Search in sources :

Example 86 with JSTypeExpression

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

the class CheckJSDoc method validateDefaultValue.

/**
 * Check that a parameter with a default value is marked as optional.
 * TODO(bradfordcsmith): This is redundant. We shouldn't require it.
 */
private void validateDefaultValue(Node n) {
    if (n.isDefaultValue() && n.getParent().isParamList()) {
        Node targetNode = n.getFirstChild();
        JSDocInfo info = targetNode.getJSDocInfo();
        if (info == null) {
            return;
        }
        JSTypeExpression typeExpr = info.getType();
        if (typeExpr == null) {
            return;
        }
        Node typeNode = typeExpr.getRoot();
        if (typeNode.getToken() != Token.EQUALS) {
            report(typeNode, DEFAULT_PARAM_MUST_BE_MARKED_OPTIONAL);
        }
    }
}
Also used : Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) JSDocInfo(com.google.javascript.rhino.JSDocInfo)

Example 87 with JSTypeExpression

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

the class CheckMissingOverrideTypes method visitPropDeclaration.

private void visitPropDeclaration(Node n) {
    JSDocInfo jsDoc = this.getOverrideJSDoc(n);
    if (jsDoc == null || jsDoc.containsTypeDeclaration()) {
        // type related annotation exists in overridden property
        return;
    }
    Node func = NodeUtil.getEnclosingFunction(n);
    if (func != null) {
        // TODO(b/197000111): Delete this when override fixer can handle instance properties.
        return;
    }
    Node owner = n.getFirstChild();
    if (!owner.isThis()) {
        // e.g. `/** @override */ this.x;`
        return;
    }
    ObjectType ownerType = ObjectType.cast(owner.getJSType());
    if (ownerType == null) {
        return;
    }
    JSType propType = ownerType.getPropertyType(n.getString());
    if (propType == null) {
        return;
    }
    JSDocInfo.Builder builder = JSDocInfo.Builder.maybeCopyFrom(jsDoc);
    builder.recordType(new JSTypeExpression(typeToTypeAst(propType), JSDOC_FILE_NAME));
    reportMissingOverrideTypes(n, builder.build());
}
Also used : ObjectType(com.google.javascript.rhino.jstype.ObjectType) JSType(com.google.javascript.rhino.jstype.JSType) Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) JSDocInfo(com.google.javascript.rhino.JSDocInfo)

Example 88 with JSTypeExpression

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

the class JsDocInfoParser method parseInlineTypeDoc.

/**
 * Parse a description as a {@code @type}.
 */
public JSDocInfo parseInlineTypeDoc() {
    skipEOLs();
    JsDocToken token = next();
    int lineno = stream.getLineno();
    int startCharno = stream.getCharno();
    Node typeAst = parseParamTypeExpression(token);
    recordTypeNode(lineno, startCharno, typeAst, token == JsDocToken.LEFT_CURLY);
    JSTypeExpression expr = createJSTypeExpression(typeAst);
    if (expr != null) {
        jsdocBuilder.recordType(expr);
        jsdocBuilder.recordInlineType();
        return retrieveAndResetParsedJSDocInfo();
    }
    return null;
}
Also used : Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression)

Example 89 with JSTypeExpression

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

the class JsDocInfoParser method parseAnnotation.

private JsDocToken parseAnnotation(JsDocToken token, List<ExtendedTypeInfo> extendedTypes) {
    // JSTypes are represented as Rhino AST nodes, and then resolved later.
    JSTypeExpression type;
    int lineno = stream.getLineno();
    int charno = stream.getCharno();
    String annotationName = stream.getString();
    Annotation annotation = annotations.get(annotationName);
    if (annotation == null || annotationName.isEmpty()) {
        addParserWarning(Msg.BAD_JSDOC_TAG, annotationName);
    } else {
        // Mark the beginning of the annotation.
        jsdocBuilder.markAnnotation(annotationName, lineno, charno);
        switch(annotation) {
            case NG_INJECT:
                if (jsdocBuilder.isNgInjectRecorded()) {
                    addParserWarning(Msg.JSDOC_NGINJECT_EXTRA);
                } else {
                    jsdocBuilder.recordNgInject(true);
                }
                return eatUntilEOLIfNotAnnotation();
            case ABSTRACT:
                if (!jsdocBuilder.recordAbstract()) {
                    addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE);
                }
                return eatUntilEOLIfNotAnnotation();
            case AUTHOR:
                if (jsdocBuilder.shouldParseDocumentation()) {
                    ExtractionInfo authorInfo = extractSingleLineBlock();
                    String author = authorInfo.string;
                    if (author.isEmpty()) {
                        addParserWarning(Msg.JSDOC_AUTHORMISSING);
                    } else {
                        jsdocBuilder.recordAuthor(author);
                    }
                    token = authorInfo.token;
                } else {
                    token = eatUntilEOLIfNotAnnotation();
                }
                return token;
            case UNRESTRICTED:
                if (!jsdocBuilder.recordUnrestricted()) {
                    addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE);
                }
                return eatUntilEOLIfNotAnnotation();
            case STRUCT:
                if (!jsdocBuilder.recordStruct()) {
                    addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE);
                }
                return eatUntilEOLIfNotAnnotation();
            case DICT:
                if (!jsdocBuilder.recordDict()) {
                    addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE);
                }
                return eatUntilEOLIfNotAnnotation();
            case COLLAPSIBLE_OR_BREAK_MY_CODE:
                if (!jsdocBuilder.recordCollapsibleOrBreakMyCode()) {
                    addParserWarning(Msg.JSDOC_COLLAPSIBLEORBREAKMYCODE);
                }
                return eatUntilEOLIfNotAnnotation();
            case CONSTRUCTOR:
                if (!jsdocBuilder.recordConstructor()) {
                    if (jsdocBuilder.isInterfaceRecorded()) {
                        addTypeWarning(Msg.JSDOC_INTERFACE_CONSTRUCTOR);
                    } else {
                        addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE);
                    }
                }
                return eatUntilEOLIfNotAnnotation();
            case RECORD:
                if (!jsdocBuilder.recordImplicitMatch()) {
                    addTypeWarning(Msg.JSDOC_RECORD);
                }
                return eatUntilEOLIfNotAnnotation();
            case DEPRECATED:
                if (!jsdocBuilder.recordDeprecated()) {
                    addParserWarning(Msg.JSDOC_DEPRECATED);
                }
                // Find the reason/description, if any.
                ExtractionInfo reasonInfo = extractMultilineTextualBlock(token);
                String reason = reasonInfo.string;
                if (reason.length() > 0) {
                    jsdocBuilder.recordDeprecationReason(reason);
                }
                token = reasonInfo.token;
                return token;
            case INTERFACE:
                if (!jsdocBuilder.recordInterface()) {
                    if (jsdocBuilder.isConstructorRecorded()) {
                        addTypeWarning(Msg.JSDOC_INTERFACE_CONSTRUCTOR);
                    } else {
                        addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE);
                    }
                }
                return eatUntilEOLIfNotAnnotation();
            case DESC:
                if (jsdocBuilder.isDescriptionRecorded()) {
                    addParserWarning(Msg.JSDOC_DESC_EXTRA);
                    return eatUntilEOLIfNotAnnotation();
                } else {
                    ExtractionInfo descriptionInfo = extractMultilineTextualBlock(token);
                    String description = descriptionInfo.string;
                    jsdocBuilder.recordDescription(description);
                    token = descriptionInfo.token;
                    return token;
                }
            case TS_TYPE:
                {
                    ExtractionInfo tsTypeInfo = extractMultilineTextualBlock(token);
                    String tsType = tsTypeInfo.string;
                    jsdocBuilder.recordTsType(tsType);
                    token = tsTypeInfo.token;
                    return token;
                }
            case FILE_OVERVIEW:
                String fileOverview = "";
                if (jsdocBuilder.shouldParseDocumentation() && !lookAheadForAnnotation()) {
                    ExtractionInfo fileOverviewInfo = extractMultilineTextualBlock(token, getWhitespaceOption(WhitespaceOption.TRIM), false);
                    fileOverview = fileOverviewInfo.string;
                    token = fileOverviewInfo.token;
                } else {
                    token = eatUntilEOLIfNotAnnotation();
                }
                if (!jsdocBuilder.recordFileOverview(fileOverview)) {
                    addParserWarning(Msg.JSDOC_FILEOVERVIEW_EXTRA);
                }
                return token;
            case LICENSE:
            case PRESERVE:
                // Always use PRESERVE for @license and @preserve blocks.
                ExtractionInfo preserveInfo = extractMultilineTextualBlock(token, WhitespaceOption.PRESERVE, true);
                String preserve = preserveInfo.string;
                if (preserve.length() > 0) {
                    this.setLicenseTextMonotonic(preserve);
                }
                token = preserveInfo.token;
                return token;
            case ENHANCE:
                ExtractionInfo enhanceInfo = extractSingleLineBlock();
                String enhance = enhanceInfo.string;
                token = enhanceInfo.token;
                jsdocBuilder.recordEnhance(enhance);
                return token;
            case ENUM:
                token = next();
                lineno = stream.getLineno();
                charno = stream.getCharno();
                type = null;
                if (token != JsDocToken.EOL && token != JsDocToken.EOC) {
                    Node typeNode = parseAndRecordTypeNode(token);
                    if (typeNode != null && typeNode.isStringLit()) {
                        String typeName = typeNode.getString();
                        if (!primitiveTypes.contains(typeName)) {
                            typeNode = wrapNode(Token.BANG, typeNode);
                        }
                    }
                    type = createJSTypeExpression(typeNode);
                } else {
                    restoreLookAhead(token);
                }
                if (type == null) {
                    type = createJSTypeExpression(newStringNode("number"));
                }
                if (!jsdocBuilder.recordEnumParameterType(type)) {
                    addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE, lineno, charno);
                }
                return eatUntilEOLIfNotAnnotation();
            case EXTERNS:
                if (!jsdocBuilder.recordExterns()) {
                    addParserWarning(Msg.JSDOC_EXTERNS);
                }
                return eatUntilEOLIfNotAnnotation();
            case TYPE_SUMMARY:
                if (!jsdocBuilder.recordTypeSummary()) {
                    addParserWarning(Msg.JSDOC_TYPESUMMARY);
                }
                return eatUntilEOLIfNotAnnotation();
            case EXTENDS:
            case IMPLEMENTS:
                skipEOLs();
                token = next();
                lineno = stream.getLineno();
                charno = stream.getCharno();
                boolean matchingRc = false;
                if (token == JsDocToken.LEFT_CURLY) {
                    token = next();
                    matchingRc = true;
                }
                if (token == JsDocToken.STRING) {
                    Node typeNode = parseAndRecordTypeNameNode(token, lineno, charno, matchingRc);
                    lineno = stream.getLineno();
                    charno = stream.getCharno();
                    typeNode = wrapNode(Token.BANG, typeNode);
                    type = createJSTypeExpression(typeNode);
                    if (annotation == Annotation.EXTENDS) {
                        // record the extended type, check later
                        extendedTypes.add(new ExtendedTypeInfo(type, stream.getLineno(), stream.getCharno()));
                    } else {
                        checkState(annotation == Annotation.IMPLEMENTS);
                        if (!jsdocBuilder.recordImplementedInterface(type)) {
                            addTypeWarning(Msg.JSDOC_IMPLEMENTS_DUPLICATE, lineno, charno);
                        }
                    }
                    token = next();
                    if (matchingRc) {
                        if (token != JsDocToken.RIGHT_CURLY) {
                            addTypeWarning(Msg.JSDOC_MISSING_RC);
                        } else {
                            token = next();
                        }
                    } else if (token != JsDocToken.EOL && token != JsDocToken.EOF && token != JsDocToken.EOC) {
                        addTypeWarning(Msg.END_ANNOTATION_EXPECTED);
                    }
                } else if (token == JsDocToken.BANG || token == JsDocToken.QMARK) {
                    addTypeWarning(Msg.JSDOC_IMPLEMENTS_EXTRAQUALIFIER, lineno, charno);
                } else {
                    addTypeWarning(Msg.NO_TYPE_NAME, lineno, charno);
                }
                token = eatUntilEOLIfNotAnnotation(token);
                return token;
            case HIDDEN:
                if (!jsdocBuilder.recordHiddenness()) {
                    addParserWarning(Msg.JSDOC_HIDDEN);
                }
                return eatUntilEOLIfNotAnnotation();
            case LENDS:
                skipEOLs();
                matchingRc = false;
                if (match(JsDocToken.LEFT_CURLY)) {
                    token = next();
                    matchingRc = true;
                }
                if (match(JsDocToken.STRING)) {
                    JSTypeExpression lendsExpression = createJSTypeExpression(parseNameExpression(next()));
                    if (!jsdocBuilder.recordLends(lendsExpression)) {
                        addTypeWarning(Msg.JSDOC_LENDS_INCOMPATIBLE);
                    }
                } else {
                    addTypeWarning(Msg.JSDOC_LENDS_MISSING);
                }
                if (matchingRc && !match(JsDocToken.RIGHT_CURLY)) {
                    addTypeWarning(Msg.JSDOC_MISSING_RC);
                }
                return eatUntilEOLIfNotAnnotation();
            case MEANING:
                ExtractionInfo meaningInfo = extractMultilineTextualBlock(token);
                String meaning = meaningInfo.string;
                token = meaningInfo.token;
                if (!jsdocBuilder.recordMeaning(meaning)) {
                    addParserWarning(Msg.JSDOC_MEANING_EXTRA);
                }
                return token;
            case ALTERNATE_MESSAGE_ID:
                ExtractionInfo alternateMessageIdInfo = extractSingleLineBlock();
                String alternateMessageId = alternateMessageIdInfo.string;
                token = alternateMessageIdInfo.token;
                if (!jsdocBuilder.recordAlternateMessageId(alternateMessageId)) {
                    addParserWarning(Msg.JSDOC_ALTERNATEMESSAGEID_EXTRA);
                }
                return token;
            case CLOSURE_PRIMITIVE:
                skipEOLs();
                return parseClosurePrimitiveTag(next());
            case NO_COMPILE:
                if (!jsdocBuilder.recordNoCompile()) {
                    addParserWarning(Msg.JSDOC_NOCOMPILE);
                }
                return eatUntilEOLIfNotAnnotation();
            case NO_COLLAPSE:
                if (!jsdocBuilder.recordNoCollapse()) {
                    addParserWarning(Msg.JSDOC_NOCOLLAPSE);
                }
                return eatUntilEOLIfNotAnnotation();
            case NO_INLINE:
                if (!jsdocBuilder.recordNoInline()) {
                    addParserWarning(Msg.JSDOC_NOINLINE);
                }
                return eatUntilEOLIfNotAnnotation();
            case PROVIDE_GOOG:
                if (!jsdocBuilder.recordProvideGoog()) {
                    addParserWarning(Msg.JSDOC_PROVIDE_GOOG);
                }
                return eatUntilEOLIfNotAnnotation();
            case PURE_OR_BREAK_MY_CODE:
                if (!jsdocBuilder.recordPureOrBreakMyCode()) {
                    addParserWarning(Msg.JSDOC_PUREORBREAKMYCODE);
                }
                return eatUntilEOLIfNotAnnotation();
            case NOT_IMPLEMENTED:
                return eatUntilEOLIfNotAnnotation();
            case INHERIT_DOC:
            case OVERRIDE:
                if (!jsdocBuilder.recordOverride()) {
                    addTypeWarning(Msg.JSDOC_OVERRIDE);
                }
                return eatUntilEOLIfNotAnnotation();
            case POLYMER:
                if (jsdocBuilder.isPolymerRecorded()) {
                    addParserWarning(Msg.JSDOC_POLYMER_EXTRA);
                } else {
                    jsdocBuilder.recordPolymer();
                }
                return eatUntilEOLIfNotAnnotation();
            case POLYMER_BEHAVIOR:
                if (jsdocBuilder.isPolymerBehaviorRecorded()) {
                    addParserWarning(Msg.JSDOC_POLYMERBEHAVIOR_EXTRA);
                } else {
                    jsdocBuilder.recordPolymerBehavior();
                }
                return eatUntilEOLIfNotAnnotation();
            case CUSTOM_ELEMENT:
                if (jsdocBuilder.isCustomElementRecorded()) {
                    addParserWarning(Msg.JSDOC_CUSTOMELEMENT_EXTRA);
                } else {
                    jsdocBuilder.recordCustomElement();
                }
                return eatUntilEOLIfNotAnnotation();
            case MIXIN_CLASS:
                if (jsdocBuilder.isMixinClassRecorded()) {
                    addParserWarning(Msg.JSDOC_MIXINCLASS_EXTRA);
                } else {
                    jsdocBuilder.recordMixinClass();
                }
                return eatUntilEOLIfNotAnnotation();
            case MIXIN_FUNCTION:
                if (jsdocBuilder.isMixinFunctionRecorded()) {
                    addParserWarning(Msg.JSDOC_MIXINFUNCTION_EXTRA);
                } else {
                    jsdocBuilder.recordMixinFunction();
                }
                return eatUntilEOLIfNotAnnotation();
            case THROWS:
                {
                    lineno = stream.getLineno();
                    charno = stream.getCharno();
                    if (!lookAheadForAnnotation()) {
                        ExtractionInfo throwsInfo = extractMultilineTextualBlock(token);
                        String throwsAnnotation = throwsInfo.string;
                        throwsAnnotation = throwsAnnotation.trim();
                        if (throwsAnnotation.length() > 0) {
                            jsdocBuilder.recordThrowsAnnotation(throwsAnnotation);
                        }
                        token = throwsInfo.token;
                    }
                    return token;
                }
            case PARAM:
                skipEOLs();
                token = next();
                lineno = stream.getLineno();
                charno = stream.getCharno();
                type = null;
                boolean hasParamType = false;
                if (token == JsDocToken.LEFT_CURLY) {
                    type = createJSTypeExpression(parseAndRecordParamTypeNode(token));
                    if (type == null) {
                        // recovering parsing
                        return eatUntilEOLIfNotAnnotation();
                    }
                    skipEOLs();
                    token = next();
                    lineno = stream.getLineno();
                    charno = stream.getCharno();
                    hasParamType = true;
                }
                String name = null;
                boolean isBracketedParam = JsDocToken.LEFT_SQUARE == token;
                if (isBracketedParam) {
                    token = next();
                }
                if (JsDocToken.STRING != token) {
                    addTypeWarning(Msg.MISSING_VARIABLE_NAME, lineno, charno);
                } else {
                    if (!hasParamType) {
                        addMissingTypeWarning(stream.getLineno(), stream.getCharno());
                    }
                    name = stream.getString();
                    if (isBracketedParam) {
                        token = next();
                        // system.
                        if (JsDocToken.EQUALS == token) {
                            token = next();
                            if (JsDocToken.STRING == token) {
                                token = next();
                            }
                        }
                        if (JsDocToken.RIGHT_SQUARE != token) {
                            reportTypeSyntaxWarning(Msg.JSDOC_MISSING_RB);
                        } else if (type != null) {
                            // Make the type expression optional, if it isn't
                            // already.
                            type = JSTypeExpression.makeOptionalArg(type);
                        }
                    }
                    // See https://github.com/google/closure-compiler/issues/499
                    if (!TokenStream.isJSIdentifier(name)) {
                        addParserWarning(Msg.INVALID_VARIABLE_NAME, name, lineno, charno);
                        name = null;
                    } else if (!jsdocBuilder.recordParameter(name, type)) {
                        if (jsdocBuilder.hasParameter(name)) {
                            addTypeWarning(Msg.DUP_VARIABLE_NAME, name, lineno, charno);
                        } else {
                            addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE, name, lineno, charno);
                        }
                    }
                }
                if (name == null) {
                    token = eatUntilEOLIfNotAnnotation(token);
                    return token;
                }
                jsdocBuilder.markName(name, templateNode, lineno, charno);
                // Find the parameter's description (if applicable).
                if (jsdocBuilder.shouldParseDocumentation() && token != JsDocToken.ANNOTATION) {
                    ExtractionInfo paramDescriptionInfo = extractMultilineTextualBlock(token);
                    String paramDescription = paramDescriptionInfo.string;
                    if (paramDescription.length() > 0) {
                        jsdocBuilder.recordParameterDescription(name, paramDescription);
                    }
                    token = paramDescriptionInfo.token;
                } else if (token != JsDocToken.EOC && token != JsDocToken.EOF) {
                    token = eatUntilEOLIfNotAnnotation();
                }
                return token;
            case NO_SIDE_EFFECTS:
                if (!jsdocBuilder.recordNoSideEffects()) {
                    addParserWarning(Msg.JSDOC_NOSIDEEFFECTS);
                }
                return eatUntilEOLIfNotAnnotation();
            case MODIFIES:
                token = parseModifiesTag(next());
                return token;
            case IMPLICIT_CAST:
                if (!jsdocBuilder.recordImplicitCast()) {
                    addTypeWarning(Msg.JSDOC_IMPLICITCAST);
                }
                return eatUntilEOLIfNotAnnotation();
            case SEE:
                if (jsdocBuilder.shouldParseDocumentation()) {
                    ExtractionInfo referenceInfo = extractSingleLineBlock();
                    String reference = referenceInfo.string;
                    if (reference.isEmpty()) {
                        addParserWarning(Msg.JSDOC_SEEMISSING);
                    } else {
                        jsdocBuilder.recordReference(reference);
                    }
                    token = referenceInfo.token;
                } else {
                    token = eatUntilEOLIfNotAnnotation();
                }
                return token;
            case SUPPRESS:
                token = parseSuppressTag(next());
                return token;
            case TEMPLATE:
                {
                    // Attempt to parse a template bound type.
                    JSTypeExpression boundTypeExpression = null;
                    if (match(JsDocToken.LEFT_CURLY)) {
                        addParserWarning(Msg.JSDOC_TEMPLATE_BOUNDEDGENERICS_USED, lineno, charno);
                        Node boundTypeNode = parseTypeExpressionAnnotation(next());
                        if (boundTypeNode != null) {
                            boundTypeExpression = createJSTypeExpression(boundTypeNode);
                        }
                    }
                    // Collect any names of template types.
                    List<String> templateNames = new ArrayList<>();
                    if (!match(JsDocToken.COLON)) {
                        // Parse a list of comma separated names.
                        do {
                            @Nullable Node nameNode = parseNameExpression(next());
                            @Nullable String templateName = (nameNode == null) ? null : nameNode.getString();
                            if (validTemplateTypeName(templateName)) {
                                templateNames.add(templateName);
                            }
                        } while (eatIfMatch(JsDocToken.COMMA));
                    }
                    // Look for some TTL. Always use TRIM for template TTL expressions.
                    @Nullable Node ttlAst = null;
                    if (match(JsDocToken.COLON)) {
                        // TODO(nickreid): Fix `extractMultilineTextualBlock` so the result includes the
                        // current token. At present, it reads the stream directly and bypasses any previously
                        // read tokens.
                        ExtractionInfo ttlExtraction = extractMultilineTextualBlock(current(), WhitespaceOption.TRIM, false);
                        token = ttlExtraction.token;
                        ttlAst = parseTtlAst(ttlExtraction, lineno, charno);
                    } else {
                        token = eatUntilEOLIfNotAnnotation(current());
                    }
                    // Validate the number of declared template names, which depends on bounds and TTL.
                    switch(templateNames.size()) {
                        case 0:
                            addTypeWarning(Msg.JSDOC_TEMPLATE_NAME_MISSING, lineno, charno);
                            // There's nothing we can connect a bound or TTL to.
                            return token;
                        case 1:
                            break;
                        default:
                            if (boundTypeExpression != null || ttlAst != null) {
                                addTypeWarning(Msg.JSDOC_TEMPLATE_MULTIPLEDECLARATION, lineno, charno);
                            }
                            break;
                    }
                    if (boundTypeExpression != null && ttlAst != null) {
                        addTypeWarning(Msg.JSDOC_TEMPLATE_BOUNDSWITHTTL, lineno, charno);
                        // It's undecidable what the user intent was.
                        return token;
                    }
                    // Based on the form form of the declaration, record the information in the JsDocInfo.
                    if (ttlAst != null) {
                        if (!jsdocBuilder.recordTypeTransformation(templateNames.get(0), ttlAst)) {
                            addTypeWarning(Msg.JSDOC_TEMPLATE_NAME_REDECLARATION, lineno, charno);
                        }
                    } else if (boundTypeExpression != null) {
                        if (!jsdocBuilder.recordTemplateTypeName(templateNames.get(0), boundTypeExpression)) {
                            addTypeWarning(Msg.JSDOC_TEMPLATE_NAME_REDECLARATION, lineno, charno);
                        }
                    } else {
                        for (String templateName : templateNames) {
                            if (!jsdocBuilder.recordTemplateTypeName(templateName)) {
                                addTypeWarning(Msg.JSDOC_TEMPLATE_NAME_REDECLARATION, lineno, charno);
                            }
                        }
                    }
                    return token;
                }
            case IDGENERATOR:
                token = parseIdGeneratorTag(next());
                return token;
            case JSX:
            case JSX_FRAGMENT:
            case SOY_MODULE:
            case SOY_TEMPLATE:
                return eatUntilEOLIfNotAnnotation();
            case WIZACTION:
                if (!jsdocBuilder.recordWizaction()) {
                    addParserWarning(Msg.JSDOC_WIZACTION);
                }
                return eatUntilEOLIfNotAnnotation();
            case VERSION:
                ExtractionInfo versionInfo = extractSingleLineBlock();
                String version = versionInfo.string;
                if (version.isEmpty()) {
                    addParserWarning(Msg.JSDOC_VERSIONMISSING);
                } else {
                    if (!jsdocBuilder.recordVersion(version)) {
                        addParserWarning(Msg.JSDOC_EXTRAVERSION);
                    }
                }
                token = versionInfo.token;
                return token;
            case CONSTANT:
            case FINAL:
            case DEFINE:
            case EXPORT:
            case RETURN:
            case PACKAGE:
            case PRIVATE:
            case PROTECTED:
            case PUBLIC:
            case THIS:
            case TYPE:
            case TYPEDEF:
                lineno = stream.getLineno();
                charno = stream.getCharno();
                Node typeNode = null;
                boolean hasType = lookAheadForType();
                boolean isAlternateTypeAnnotation = annotation == Annotation.PACKAGE || annotation == Annotation.PRIVATE || annotation == Annotation.PROTECTED || annotation == Annotation.PUBLIC || annotation == Annotation.CONSTANT || annotation == Annotation.FINAL || annotation == Annotation.EXPORT;
                boolean canSkipTypeAnnotation = isAlternateTypeAnnotation || annotation == Annotation.RETURN;
                type = null;
                if (annotation == Annotation.RETURN && !hasType) {
                    addMissingTypeWarning(stream.getLineno(), stream.getCharno());
                }
                if (hasType || !canSkipTypeAnnotation) {
                    skipEOLs();
                    token = next();
                    typeNode = parseAndRecordTypeNode(token);
                    if (annotation == Annotation.THIS) {
                        typeNode = wrapNode(Token.BANG, typeNode);
                    }
                    type = createJSTypeExpression(typeNode);
                }
                // The error was reported during recursive descent
                // recovering parsing
                boolean hasError = type == null && !canSkipTypeAnnotation;
                if (!hasError) {
                    // but should be mostly OK.
                    if (((type != null && isAlternateTypeAnnotation) || annotation == Annotation.TYPE) && !jsdocBuilder.recordType(type)) {
                        addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE, lineno, charno);
                    }
                    boolean isAnnotationNext = lookAheadForAnnotation();
                    switch(annotation) {
                        case CONSTANT:
                            if (!jsdocBuilder.recordConstancy()) {
                                addParserWarning(Msg.JSDOC_CONST);
                            }
                            break;
                        case FINAL:
                            if (!jsdocBuilder.recordFinality()) {
                                addTypeWarning(Msg.JSDOC_FINAL);
                            }
                            break;
                        case DEFINE:
                            if (!jsdocBuilder.recordDefineType(type)) {
                                addParserWarning(Msg.JSDOC_DEFINE, lineno, charno);
                            }
                            if (!isAnnotationNext) {
                                return recordDescription(token);
                            }
                            break;
                        case EXPORT:
                            if (!jsdocBuilder.recordExport()) {
                                addParserWarning(Msg.JSDOC_EXPORT, lineno, charno);
                            }
                            if (!isAnnotationNext) {
                                return recordDescription(token);
                            }
                            break;
                        case PRIVATE:
                            if (!jsdocBuilder.recordVisibility(Visibility.PRIVATE)) {
                                addParserWarning(Msg.JSDOC_EXTRA_VISIBILITY, lineno, charno);
                            }
                            if (!isAnnotationNext) {
                                return recordDescription(token);
                            }
                            break;
                        case PACKAGE:
                            if (!jsdocBuilder.recordVisibility(Visibility.PACKAGE)) {
                                addParserWarning(Msg.JSDOC_EXTRA_VISIBILITY, lineno, charno);
                            }
                            if (!isAnnotationNext) {
                                return recordDescription(token);
                            }
                            break;
                        case PROTECTED:
                            if (!jsdocBuilder.recordVisibility(Visibility.PROTECTED)) {
                                addParserWarning(Msg.JSDOC_EXTRA_VISIBILITY, lineno, charno);
                            }
                            if (!isAnnotationNext) {
                                return recordDescription(token);
                            }
                            break;
                        case PUBLIC:
                            if (!jsdocBuilder.recordVisibility(Visibility.PUBLIC)) {
                                addParserWarning(Msg.JSDOC_EXTRA_VISIBILITY, lineno, charno);
                            }
                            if (!isAnnotationNext) {
                                return recordDescription(token);
                            }
                            break;
                        case RETURN:
                            if (type == null) {
                                type = createJSTypeExpression(newNode(Token.QMARK));
                            }
                            if (!jsdocBuilder.recordReturnType(type)) {
                                addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE, lineno, charno);
                                break;
                            }
                            // Find the return's description (if applicable).
                            if (jsdocBuilder.shouldParseDocumentation() && !isAnnotationNext) {
                                ExtractionInfo returnDescriptionInfo = extractMultilineTextualBlock(token);
                                String returnDescription = returnDescriptionInfo.string;
                                if (returnDescription.length() > 0) {
                                    jsdocBuilder.recordReturnDescription(returnDescription);
                                }
                                token = returnDescriptionInfo.token;
                            } else {
                                token = eatUntilEOLIfNotAnnotation();
                            }
                            return token;
                        case THIS:
                            if (!jsdocBuilder.recordThisType(type)) {
                                addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE, lineno, charno);
                            }
                            break;
                        case TYPEDEF:
                            if (!jsdocBuilder.recordTypedef(type)) {
                                addTypeWarning(Msg.JSDOC_INCOMPAT_TYPE, lineno, charno);
                            }
                            break;
                        default:
                            break;
                    }
                }
                return eatUntilEOLIfNotAnnotation();
        }
    }
    return next();
}
Also used : Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) ArrayList(java.util.ArrayList) List(java.util.List)

Example 90 with JSTypeExpression

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

the class JsdocUtil method getJSDocForName.

static JSDocInfo getJSDocForName(Var decl, JSDocInfo oldJSDoc) {
    if (decl == null) {
        return null;
    }
    JSTypeExpression expr = NodeUtil.getDeclaredTypeExpression(decl.getNameNode());
    if (expr == null) {
        return null;
    }
    Node typeAst = expr.getRoot();
    switch(typeAst.getToken()) {
        case EQUALS:
            Node typeRoot = typeAst.getFirstChild().cloneTree();
            if (!decl.isDefaultParam()) {
                typeRoot = new Node(Token.PIPE, typeRoot, IR.string("undefined"));
            }
            typeAst = typeRoot;
            break;
        case ITER_REST:
            {
                Node newType = new Node(Token.BANG);
                Node array = IR.string("Array");
                newType.addChildToBack(array);
                Node block = new Node(Token.BLOCK, typeAst.getFirstChild().cloneTree());
                array.addChildToBack(block);
                typeAst = newType;
                break;
            }
        default:
            break;
    }
    return getConstJSDoc(oldJSDoc, typeAst);
}
Also used : Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression)

Aggregations

JSTypeExpression (com.google.javascript.rhino.JSTypeExpression)101 Node (com.google.javascript.rhino.Node)67 JSDocInfo (com.google.javascript.rhino.JSDocInfo)58 Test (org.junit.Test)26 JSDocInfoBuilder (com.google.javascript.rhino.JSDocInfoBuilder)18 MemberDefinition (com.google.javascript.jscomp.PolymerPass.MemberDefinition)9 JSType (com.google.javascript.rhino.jstype.JSType)9 ArrayList (java.util.ArrayList)8 TypeDeclarationNode (com.google.javascript.rhino.Node.TypeDeclarationNode)7 Map (java.util.Map)6 NodeSubject.assertNode (com.google.javascript.jscomp.testing.NodeSubject.assertNode)4 HashMap (java.util.HashMap)4 HashSet (java.util.HashSet)4 ImmutableList (com.google.common.collect.ImmutableList)3 ImmutableMap (com.google.common.collect.ImmutableMap)3 Visibility (com.google.javascript.rhino.JSDocInfo.Visibility)3 LinkedHashMap (java.util.LinkedHashMap)3 ImmutableSet (com.google.common.collect.ImmutableSet)2 Name (com.google.javascript.jscomp.GlobalNamespace.Name)2 Ref (com.google.javascript.jscomp.GlobalNamespace.Ref)2