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);
}
}
}
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());
}
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;
}
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();
}
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);
}
Aggregations