Search in sources :

Example 11 with StaticScope

use of com.google.javascript.rhino.StaticScope in project closure-compiler by google.

the class JSTypeRegistry method createTypeFromCommentNode.

/**
 * Creates a JSType from the nodes representing a type.
 *
 * @param n The node with type info.
 * @param sourceName The source file name.
 * @param scope A scope for doing type name lookups.
 */
public JSType createTypeFromCommentNode(Node n, String sourceName, StaticTypedScope scope) {
    switch(n.getToken()) {
        case // Record type.
        LC:
            return createRecordTypeFromNodes(n.getFirstChild(), sourceName, scope);
        case // Not nullable
        BANG:
            {
                JSType child = createTypeFromCommentNode(n.getFirstChild(), sourceName, scope);
                if (child instanceof NamedType) {
                    return ((NamedType) child).getBangType();
                }
                return child.restrictByNotNullOrUndefined();
            }
        case // Nullable or unknown
        QMARK:
            Node firstChild = n.getFirstChild();
            if (firstChild == null) {
                return getNativeType(UNKNOWN_TYPE);
            }
            return createNullableType(createTypeFromCommentNode(firstChild, sourceName, scope));
        case // Optional
        EQUALS:
            // TODO(b/117162687): stop automatically converting {string=} to {(string|undefined)]}
            return createOptionalType(createTypeFromCommentNode(n.getFirstChild(), sourceName, scope));
        case // Var args
        ITER_REST:
            return createTypeFromCommentNode(n.getFirstChild(), sourceName, scope);
        case // The AllType
        STAR:
            return getNativeType(ALL_TYPE);
        case // Union type
        PIPE:
            ImmutableList.Builder<JSType> builder = ImmutableList.builder();
            for (Node child = n.getFirstChild(); child != null; child = child.getNext()) {
                builder.add(createTypeFromCommentNode(child, sourceName, scope));
            }
            return createUnionType(builder.build());
        case // When the return value of a function is not specified
        EMPTY:
            return getNativeType(UNKNOWN_TYPE);
        case // Only allowed in the return value of a function.
        VOID:
            return getNativeType(VOID_TYPE);
        case TYPEOF:
            {
                String name = n.getFirstChild().getString();
                // TODO(sdh): require var to be const?
                QualifiedName qname = QualifiedName.of(name);
                String root = qname.getRoot();
                StaticScope declarationScope = scope.getTopmostScopeOfEventualDeclaration(root);
                StaticSlot rootSlot = scope.getSlot(root);
                JSType type = scope.lookupQualifiedName(qname);
                if (type == null || type.isUnknownType() || rootSlot.getScope() != declarationScope) {
                    // eventually resolve if necessary.
                    return NamedType.builder(this, "typeof " + name).setScope(scope).setResolutionKind(ResolutionKind.TYPEOF).setErrorReportingLocationFrom(n).build();
                }
                if (type.isLiteralObject()) {
                    JSType scopeType = type;
                    type = NamedType.builder(this, "typeof " + name).setResolutionKind(ResolutionKind.NONE).setReferencedType(scopeType).build();
                }
                return type;
            }
        case STRINGLIT:
            {
                JSType nominalType = getType(scope, n.getString(), sourceName, n.getLineno(), n.getCharno());
                ImmutableList<JSType> templateArgs = parseTemplateArgs(nominalType, n, sourceName, scope);
                // Handle forward declared types
                if (nominalType.isNamedType() && !nominalType.isResolved()) {
                    if (templateArgs != null) {
                        nominalType = nominalType.toMaybeNamedType().toBuilder().setTemplateTypes(templateArgs).build();
                    }
                    return addNullabilityBasedOnParseContext(n, nominalType, scope);
                }
                if (!(nominalType instanceof ObjectType) || isNonNullableName(scope, n.getString())) {
                    return nominalType;
                }
                if (templateArgs == null || !nominalType.isRawTypeOfTemplatizedType() || nominalType.isUnknownType()) {
                    // given isRawTypeOfTemplatizedType, but in some contexts is not.
                    return addNullabilityBasedOnParseContext(n, nominalType, scope);
                }
                return addNullabilityBasedOnParseContext(n, createTemplatizedType((ObjectType) nominalType, templateArgs), scope);
            }
        case FUNCTION:
            JSType thisType = null;
            boolean isConstructor = false;
            Node current = n.getFirstChild();
            if (current.isThis() || current.isNew()) {
                Node contextNode = current.getFirstChild();
                JSType candidateThisType = createTypeFromCommentNode(contextNode, sourceName, scope);
                // and 'this' access should raise warnings.
                if (candidateThisType.isNullType() || candidateThisType.isVoidType()) {
                    thisType = candidateThisType;
                } else if (current.isThis()) {
                    thisType = candidateThisType.restrictByNotNullOrUndefined();
                } else if (current.isNew()) {
                    thisType = ObjectType.cast(candidateThisType.restrictByNotNullOrUndefined());
                    if (thisType == null) {
                        reporter.warning(Msg.JSDOC_FUNCTION_NEWNOTOBJECT.format(), sourceName, contextNode.getLineno(), contextNode.getCharno());
                    }
                }
                isConstructor = current.getToken() == Token.NEW;
                current = current.getNext();
            }
            FunctionParamBuilder paramBuilder = new FunctionParamBuilder(this);
            if (current.getToken() == Token.PARAM_LIST) {
                for (Node arg = current.getFirstChild(); arg != null; arg = arg.getNext()) {
                    if (arg.getToken() == Token.ITER_REST) {
                        if (!arg.hasChildren()) {
                            paramBuilder.addVarArgs(getNativeType(UNKNOWN_TYPE));
                        } else {
                            paramBuilder.addVarArgs(createTypeFromCommentNode(arg.getFirstChild(), sourceName, scope));
                        }
                    } else {
                        JSType type = createTypeFromCommentNode(arg, sourceName, scope);
                        if (arg.getToken() == Token.EQUALS) {
                            boolean addSuccess = paramBuilder.addOptionalParams(type);
                            if (!addSuccess) {
                                reporter.warning(Msg.JSDOC_FUNCTION_VARARGS.format(), sourceName, arg.getLineno(), arg.getCharno());
                            }
                        } else {
                            paramBuilder.addRequiredParams(type);
                        }
                    }
                }
                current = current.getNext();
            }
            JSType returnType = createTypeFromCommentNode(current, sourceName, scope);
            return FunctionType.builder(this).withParameters(paramBuilder.build()).withReturnType(returnType).withTypeOfThis(thisType).withKind(isConstructor ? FunctionType.Kind.CONSTRUCTOR : FunctionType.Kind.ORDINARY).build();
        default:
            throw new IllegalStateException("Unexpected node in type expression: " + n);
    }
}
Also used : ImmutableList(com.google.common.collect.ImmutableList) Node(com.google.javascript.rhino.Node) QualifiedName(com.google.javascript.rhino.QualifiedName) StaticScope(com.google.javascript.rhino.StaticScope) StaticSlot(com.google.javascript.rhino.StaticSlot)

Aggregations

StaticScope (com.google.javascript.rhino.StaticScope)11 Node (com.google.javascript.rhino.Node)4 Test (org.junit.Test)4 StaticSlot (com.google.javascript.rhino.StaticSlot)2 NodeSubject.assertNode (com.google.javascript.rhino.testing.NodeSubject.assertNode)2 ImmutableList (com.google.common.collect.ImmutableList)1 QualifiedName (com.google.javascript.rhino.QualifiedName)1