Search in sources :

Example 11 with QualifiedName

use of com.google.javascript.jscomp.newtypes.QualifiedName in project closure-compiler by google.

the class NewTypeInference method analyzeInFwd.

private EnvTypePair analyzeInFwd(Node expr, TypeEnv inEnv, JSType specializedType) {
    Node lhs = expr.getFirstChild();
    Node rhs = expr.getLastChild();
    JSType reqObjType = pickReqObjType(expr);
    EnvTypePair pair;
    pair = analyzeExprFwd(lhs, inEnv, NUMBER_OR_STRING);
    if (!pair.type.isSubtypeOf(NUMBER_OR_STRING)) {
        warnInvalidOperand(lhs, Token.IN, NUMBER_OR_STRING, pair.type);
    }
    pair = analyzeExprFwd(rhs, pair.env, reqObjType);
    if (!pair.type.isSubtypeOf(TOP_OBJECT)) {
        warnInvalidOperand(rhs, Token.IN, "Object", pair.type);
        pair.type = BOOLEAN;
        return pair;
    }
    if (pair.type.isStruct()) {
        warnings.add(JSError.make(rhs, IN_USED_WITH_STRUCT));
        pair.type = BOOLEAN;
        return pair;
    }
    JSType resultType = BOOLEAN;
    if (lhs.isString()) {
        QualifiedName pname = new QualifiedName(lhs.getString());
        if (specializedType.isTrueOrTruthy()) {
            pair = analyzeExprFwd(rhs, inEnv, reqObjType, reqObjType.withPropertyRequired(pname.getLeftmostName()));
            resultType = TRUE_TYPE;
        } else if (specializedType.isFalseOrFalsy()) {
            pair = analyzeExprFwd(rhs, inEnv, reqObjType);
            // If the rhs is a loose object, we won't warn about missing
            // properties, despite removing the type here.
            // The only way to have that warning would be to keep track of props
            // that a loose object *cannot* have; but the implementation cost
            // is probably not worth it.
            pair = analyzeExprFwd(rhs, inEnv, reqObjType, pair.type.withoutProperty(pname));
            resultType = FALSE_TYPE;
        }
    }
    pair.type = resultType;
    return pair;
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) QualifiedName(com.google.javascript.jscomp.newtypes.QualifiedName)

Example 12 with QualifiedName

use of com.google.javascript.jscomp.newtypes.QualifiedName in project closure-compiler by google.

the class NewTypeInference method changeTypeIfFunctionNamespace.

private JSType changeTypeIfFunctionNamespace(NTIScope fnScope, JSType fnType) {
    NTIScope enclosingScope = fnScope.getParent();
    Node fnNameNode = NodeUtil.getNameNode(fnScope.getRoot());
    JSType namespaceType = null;
    if (fnNameNode == null) {
        return fnType;
    }
    if (fnNameNode.isName()) {
        String fnName = fnNameNode.getString();
        if (enclosingScope.isFunctionNamespace(fnName)) {
            namespaceType = enclosingScope.getDeclaredTypeOf(fnName);
        }
    } else if (fnNameNode.isQualifiedName()) {
        QualifiedName qname = QualifiedName.fromNode(fnNameNode);
        JSType rootNs = enclosingScope.getDeclaredTypeOf(qname.getLeftmostName());
        if (rootNs != null && rootNs.isSubtypeOf(TOP_OBJECT)) {
            namespaceType = rootNs.getProp(qname.getAllButLeftmost());
        }
    }
    if (namespaceType != null && namespaceType.isNamespace()) {
        // with the new function summary.
        return namespaceType.withFunction(fnType.getFunTypeIfSingletonObj(), commonTypes.getFunctionType());
    }
    return fnType;
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) QualifiedName(com.google.javascript.jscomp.newtypes.QualifiedName)

Example 13 with QualifiedName

use of com.google.javascript.jscomp.newtypes.QualifiedName in project closure-compiler by google.

the class NewTypeInference method analyzePropAccessFwd.

private EnvTypePair analyzePropAccessFwd(Node receiver, String pname, TypeEnv inEnv, JSType requiredType, JSType specializedType) {
    QualifiedName propQname = new QualifiedName(pname);
    Node propAccessNode = receiver.getParent();
    EnvTypePair pair;
    JSType reqObjType = pickReqObjType(propAccessNode);
    JSType recvReqType;
    JSType recvSpecType;
    // First, analyze the receiver object.
    if ((NodeUtil.isPropertyTest(compiler, propAccessNode) && !specializedType.isFalseOrFalsy()) || (NodeUtil.isPropertyAbsenceTest(propAccessNode) && !specializedType.isTrueOrTruthy()) || // else branch of "if (!x.prop)" is a property test.
    specializedType.isTrueOrTruthy()) {
        recvReqType = reqObjType;
        pair = analyzeExprFwd(receiver, inEnv, recvReqType);
        JSType subtypeWithProp = pair.type.findSubtypeWithProp(propQname);
        if (subtypeWithProp.isBottom()) {
            recvSpecType = reqObjType;
        } else {
            recvSpecType = subtypeWithProp;
        }
        if (specializedType.isTrueOrTruthy()) {
            // This handles cases like: if (x.prop1 && x.prop1.prop2) { ... }
            // In the THEN branch, the only thing we know about x.prop1 is that it
            // has a truthy property, so x.prop1 should be a loose object to avoid
            // spurious warnings.
            recvSpecType = recvSpecType.withLoose().withProperty(propQname, specializedType);
        } else {
            recvSpecType = recvSpecType.withProperty(propQname, specializedType);
        }
    } else if (specializedType.isFalseOrFalsy()) {
        recvReqType = recvSpecType = reqObjType;
    } else {
        recvReqType = reqObjType.withProperty(propQname, requiredType);
        recvSpecType = reqObjType.withProperty(propQname, specializedType);
    }
    pair = analyzeExprFwd(receiver, inEnv, recvReqType, recvSpecType);
    pair = mayWarnAboutNullableReferenceAndTighten(receiver, pair.type, recvSpecType, pair.env);
    JSType recvType = pair.type.autobox();
    if (recvType.isUnknown() || recvType.isTrueOrTruthy()) {
        mayWarnAboutInexistentProp(propAccessNode, recvType, propQname);
        return new EnvTypePair(pair.env, requiredType);
    }
    if (mayWarnAboutNonObject(receiver, recvType, specializedType)) {
        return new EnvTypePair(pair.env, requiredType);
    }
    FunctionType ft = recvType.getFunTypeIfSingletonObj();
    if (ft != null && (pname.equals("call") || pname.equals("apply"))) {
        if (ft.isAbstract()) {
            // We don't check if the parent of the property access is a call node.
            // This catches calls that are a few nodes away, and also warns on .call/.apply
            // accesses that do not result in calls (these should be very rare).
            String funName = receiver.isQualifiedName() ? receiver.getQualifiedName() : "";
            warnings.add(JSError.make(propAccessNode, ABSTRACT_SUPER_METHOD_NOT_CALLABLE, funName));
        }
        return new EnvTypePair(pair.env, pname.equals("call") ? commonTypes.fromFunctionType(ft.transformByCallProperty()) : commonTypes.fromFunctionType(ft.transformByApplyProperty()));
    }
    if (this.convention.isSuperClassReference(pname)) {
        if (ft != null && ft.isUniqueConstructor()) {
            JSType result = ft.getSuperPrototype();
            pair.type = firstNonNull(result, UNDEFINED);
            return pair;
        }
    }
    if (propAccessNode.isGetProp() && mayWarnAboutDictPropAccess(receiver, recvType)) {
        return new EnvTypePair(pair.env, requiredType);
    }
    if (recvType.isTop()) {
        recvType = TOP_OBJECT;
    }
    if (propAccessNode.getParent().isDelProp() && recvType.hasConstantProp(propQname)) {
        warnings.add(JSError.make(propAccessNode.getParent(), CONST_PROPERTY_DELETED, pname));
    }
    // Then, analyze the property access.
    QualifiedName getterPname = new QualifiedName(commonTypes.createGetterPropName(pname));
    if (recvType.hasProp(getterPname)) {
        return new EnvTypePair(pair.env, recvType.getProp(getterPname));
    }
    JSType resultType = recvType.getProp(propQname);
    if (resultType != null && resultType.isBottom()) {
        warnings.add(JSError.make(propAccessNode, BOTTOM_PROP, pname, recvType.toString()));
        return new EnvTypePair(pair.env, UNKNOWN);
    }
    if (!propAccessNode.getParent().isExprResult() && !specializedType.isTrueOrTruthy() && !specializedType.isFalseOrFalsy() && !recvType.mayBeDict() && !mayWarnAboutInexistentProp(propAccessNode, recvType, propQname) && recvType.hasProp(propQname) && !resultType.isSubtypeOf(requiredType) && tightenPropertyTypeAndDontWarn(receiver.isName() ? receiver.getString() : null, propAccessNode, recvType, recvType.getDeclaredProp(propQname), resultType, requiredType)) {
        // Tighten the inferred type and don't warn.
        // See analyzeNameFwd for explanation about types as lower/upper bounds.
        resultType = resultType.specialize(requiredType);
        LValueResultFwd lvr = analyzeLValueFwd(propAccessNode, inEnv, resultType);
        TypeEnv updatedEnv = updateLvalueTypeInEnv(lvr.env, propAccessNode, lvr.ptr, resultType);
        return new EnvTypePair(updatedEnv, resultType);
    }
    // We've already warned about missing props, and never want to return null.
    if (resultType == null) {
        resultType = UNKNOWN;
    }
    // Any potential type mismatch will be caught by the context
    return new EnvTypePair(pair.env, resultType);
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) QualifiedName(com.google.javascript.jscomp.newtypes.QualifiedName) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 14 with QualifiedName

use of com.google.javascript.jscomp.newtypes.QualifiedName in project closure-compiler by google.

the class NewTypeInference method analyzeObjLitBwd.

private EnvTypePair analyzeObjLitBwd(Node objLit, TypeEnv outEnv, JSType requiredType) {
    if (NodeUtil.isEnumDecl(objLit.getParent())) {
        return analyzeEnumObjLitBwd(objLit, outEnv, requiredType);
    }
    TypeEnv env = outEnv;
    JSType result = pickReqObjType(objLit);
    for (Node prop = objLit.getLastChild(); prop != null; prop = prop.getPrevious()) {
        if (prop.isGetterDef() || prop.isSetterDef()) {
            env = analyzeExprBwd(prop.getFirstChild(), env).env;
        } else if (prop.isComputedProp() && !prop.getFirstChild().isString()) {
            env = analyzeExprBwd(prop, env).env;
        } else {
            QualifiedName pname = new QualifiedName(NodeUtil.getObjectLitKeyName(prop));
            JSType jsdocType = (JSType) prop.getTypeI();
            JSType reqPtype;
            if (jsdocType != null) {
                reqPtype = jsdocType;
            } else if (requiredType.mayHaveProp(pname)) {
                reqPtype = requiredType.getProp(pname);
            } else {
                reqPtype = UNKNOWN;
            }
            EnvTypePair pair = analyzeExprBwd(prop, env, reqPtype);
            result = result.withProperty(pname, pair.type);
            env = pair.env;
        }
    }
    return new EnvTypePair(env, result);
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) QualifiedName(com.google.javascript.jscomp.newtypes.QualifiedName) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 15 with QualifiedName

use of com.google.javascript.jscomp.newtypes.QualifiedName in project closure-compiler by google.

the class NTIScope method addFunNamespace.

void addFunNamespace(Node qnameNode) {
    if (qnameNode.isName()) {
        String varName = qnameNode.getString();
        checkArgument(isDefinedLocally(varName, false));
        checkState(!this.localNamespaces.containsKey(varName));
        NTIScope s = checkNotNull(this.localFunDefs.get(varName));
        this.localNamespaces.put(varName, new FunctionNamespace(this.commonTypes, varName, s, qnameNode));
    } else {
        checkArgument(!isNamespace(qnameNode));
        QualifiedName qname = QualifiedName.fromNode(qnameNode);
        Namespace ns = getNamespace(qname.getLeftmostName());
        NTIScope s = (NTIScope) ns.getDeclaration(qname).getFunctionScope();
        ns.addNamespace(qname.getAllButLeftmost(), new FunctionNamespace(this.commonTypes, qname.toString(), s, qnameNode));
    }
}
Also used : FunctionNamespace(com.google.javascript.jscomp.newtypes.FunctionNamespace) QualifiedName(com.google.javascript.jscomp.newtypes.QualifiedName) Namespace(com.google.javascript.jscomp.newtypes.Namespace) FunctionNamespace(com.google.javascript.jscomp.newtypes.FunctionNamespace)

Aggregations

QualifiedName (com.google.javascript.jscomp.newtypes.QualifiedName)23 JSType (com.google.javascript.jscomp.newtypes.JSType)18 Node (com.google.javascript.rhino.Node)15 DiGraphNode (com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)14 TypeEnv (com.google.javascript.jscomp.newtypes.TypeEnv)7 DeclaredFunctionType (com.google.javascript.jscomp.newtypes.DeclaredFunctionType)6 FunctionNamespace (com.google.javascript.jscomp.newtypes.FunctionNamespace)5 FunctionType (com.google.javascript.jscomp.newtypes.FunctionType)5 Namespace (com.google.javascript.jscomp.newtypes.Namespace)5 Declaration (com.google.javascript.jscomp.newtypes.Declaration)3 ImmutableList (com.google.common.collect.ImmutableList)1 ObjectLiteralCast (com.google.javascript.jscomp.CodingConvention.ObjectLiteralCast)1 EnumType (com.google.javascript.jscomp.newtypes.EnumType)1 RawNominalType (com.google.javascript.jscomp.newtypes.RawNominalType)1 JSDocInfo (com.google.javascript.rhino.JSDocInfo)1