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