use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class FunctionTypeBuilder method inferParameterTypes.
/**
* Infer the parameter types from the list of parameter names and the JSDoc info.
*/
FunctionTypeBuilder inferParameterTypes(@Nullable Node paramsParent, @Nullable JSDocInfo info) {
if (paramsParent == null) {
if (info == null) {
return this;
} else {
return inferParameterTypes(info);
}
}
// arguments
final Iterator<Parameter> oldParameters;
Parameter oldParameterType = null;
if (parameters != null) {
oldParameters = parameters.iterator();
oldParameterType = oldParameters.hasNext() ? oldParameters.next() : null;
} else {
oldParameters = Collections.emptyIterator();
}
FunctionParamBuilder builder = new FunctionParamBuilder(typeRegistry);
boolean warnedAboutArgList = false;
Set<String> allJsDocParams = (info == null) ? new HashSet<>() : new HashSet<>(info.getParameterNames());
boolean isVarArgs = false;
int paramIndex = 0;
for (Node param = paramsParent.getFirstChild(); param != null; param = param.getNext()) {
boolean isOptionalParam = false;
final Node paramLhs;
if (param.isRest()) {
isVarArgs = true;
paramLhs = param.getOnlyChild();
} else if (param.isDefaultValue()) {
// The first child is the actual positional parameter
paramLhs = checkNotNull(param.getFirstChild(), param);
isOptionalParam = true;
} else {
isVarArgs = isVarArgsParameterByConvention(param);
isOptionalParam = isOptionalParameterByConvention(param);
paramLhs = param;
}
String paramName = null;
if (paramLhs.isName()) {
paramName = paramLhs.getString();
} else {
checkState(paramLhs.isDestructuringPattern());
// third JSDoc parameter.
if (info != null) {
paramName = info.getParameterNameAt(paramIndex);
}
}
allJsDocParams.remove(paramName);
// type from JSDocInfo
JSType parameterType = null;
if (info != null && info.hasParameterType(paramName)) {
JSTypeExpression parameterTypeExpression = info.getParameterType(paramName);
parameterType = parameterTypeExpression.evaluate(templateScope, typeRegistry);
isOptionalParam = isOptionalParam || parameterTypeExpression.isOptionalArg();
isVarArgs = isVarArgs || parameterTypeExpression.isVarArgs();
} else if (paramLhs.getJSDocInfo() != null && paramLhs.getJSDocInfo().hasType()) {
JSTypeExpression parameterTypeExpression = paramLhs.getJSDocInfo().getType();
parameterType = parameterTypeExpression.evaluate(templateScope, typeRegistry);
isOptionalParam = parameterTypeExpression.isOptionalArg();
isVarArgs = parameterTypeExpression.isVarArgs();
} else if (oldParameterType != null && oldParameterType.getJSType() != null) {
parameterType = oldParameterType.getJSType();
isOptionalParam = oldParameterType.isOptional();
isVarArgs = oldParameterType.isVariadic();
} else {
parameterType = typeRegistry.getNativeType(UNKNOWN_TYPE);
}
warnedAboutArgList |= addParameter(builder, parameterType, warnedAboutArgList, isOptionalParam, isVarArgs);
oldParameterType = oldParameters.hasNext() ? oldParameters.next() : null;
paramIndex++;
}
// Copy over any old parameters that aren't in the param list.
if (!isVarArgs) {
while (oldParameterType != null && !isVarArgs) {
builder.newParameterFrom(oldParameterType);
oldParameterType = oldParameters.hasNext() ? oldParameters.next() : null;
}
}
for (String inexistentName : allJsDocParams) {
reportWarning(INEXISTENT_PARAM, inexistentName, formatFnName());
}
parameters = builder.build();
return this;
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class PolymerClassRewriter method addTypesToFunctions.
/**
* Adds an @this annotation to all functions in the objLit.
*/
private void addTypesToFunctions(Node objLit, String thisType, PolymerClassDefinition.DefinitionType defType) {
checkState(objLit.isObjectLit());
for (Node keyNode = objLit.getFirstChild(); keyNode != null; keyNode = keyNode.getNext()) {
Node value = keyNode.getLastChild();
if (value != null && value.isFunction()) {
JSDocInfo.Builder fnDoc = JSDocInfo.Builder.maybeCopyFrom(keyNode.getJSDocInfo());
fnDoc.recordThisType(new JSTypeExpression(new Node(Token.BANG, IR.string(thisType)).srcrefTree(keyNode), VIRTUAL_FILE));
keyNode.setJSDocInfo(fnDoc.build());
}
}
// Add @this and @return to default property values.
for (MemberDefinition property : PolymerPassStaticUtils.extractProperties(objLit, defType, compiler, /**
* constructor=
*/
null)) {
if (!property.value.isObjectLit()) {
continue;
}
Node defaultValue = NodeUtil.getFirstPropMatchingKey(property.value, "value");
if (defaultValue == null || !defaultValue.isFunction()) {
continue;
}
Node defaultValueKey = defaultValue.getParent();
JSDocInfo.Builder fnDoc = JSDocInfo.Builder.maybeCopyFrom(defaultValueKey.getJSDocInfo());
fnDoc.recordThisType(new JSTypeExpression(new Node(Token.BANG, IR.string(thisType)).srcrefTree(defaultValueKey), VIRTUAL_FILE));
fnDoc.recordReturnType(PolymerPassStaticUtils.getTypeFromProperty(property, compiler));
defaultValueKey.setJSDocInfo(fnDoc.build());
}
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class PolymerClassRewriter method getConstructorDoc.
/**
* @return The proper constructor doc for the Polymer call.
*/
private JSDocInfo.Builder getConstructorDoc(final PolymerClassDefinition cls) {
JSDocInfo.Builder constructorDoc = JSDocInfo.Builder.maybeCopyFrom(cls.constructor.info);
constructorDoc.recordConstructor();
JSTypeExpression baseType = new JSTypeExpression(new Node(Token.BANG, IR.string(PolymerPassStaticUtils.getPolymerElementType(cls))).srcrefTree(cls.definition), VIRTUAL_FILE);
constructorDoc.recordBaseType(baseType);
String interfaceName = cls.getInterfaceName(compiler.getUniqueNameIdSupplier());
JSTypeExpression interfaceType = new JSTypeExpression(new Node(Token.BANG, IR.string(interfaceName)).srcrefTree(cls.definition), VIRTUAL_FILE);
constructorDoc.recordImplementedInterface(interfaceType);
return constructorDoc;
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class PolymerClassRewriter method rewritePolymerCall.
/**
* Rewrites a given call to Polymer({}) to a set of declarations and assignments which can be
* understood by the compiler.
*
* @param cls The extracted {@link PolymerClassDefinition} for the Polymer element created by this
* call.
* @param traversal Nodetraversal used here to identify the scope in which Polymer exists
*/
void rewritePolymerCall(final PolymerClassDefinition cls, NodeTraversal traversal) {
Node callParent = cls.definition.getParent();
// Determine whether we are in a Polymer({}) call at the top level versus in an assignment.
Node exprRoot = callParent.isExprResult() ? callParent : callParent.getParent();
checkState(NodeUtil.isStatementParent(exprRoot.getParent()), exprRoot.getParent());
Node objLit = checkNotNull(cls.descriptor);
// Add {@code @lends} to the object literal.
JSDocInfo.Builder objLitDoc = JSDocInfo.builder().parseDocumentation();
JSTypeExpression jsTypeExpression = new JSTypeExpression(IR.string(cls.target.getQualifiedName() + ".prototype").srcref(exprRoot), exprRoot.getSourceFileName());
objLitDoc.recordLends(jsTypeExpression);
objLit.setJSDocInfo(objLitDoc.build());
addTypesToFunctions(objLit, cls.target.getQualifiedName(), cls.defType);
PolymerPassStaticUtils.switchDollarSignPropsToBrackets(objLit, compiler);
PolymerPassStaticUtils.quoteListenerAndHostAttributeKeys(objLit, compiler);
for (MemberDefinition prop : cls.props) {
if (prop.value.isObjectLit()) {
PolymerPassStaticUtils.switchDollarSignPropsToBrackets(prop.value, compiler);
}
}
// The propsAndBehaviorBlock holds code generated for the Polymer's properties and behaviors
Node propsAndBehaviorBlock = IR.block();
JSDocInfo.Builder constructorDoc = this.getConstructorDoc(cls);
// Remove the original constructor JS docs from the objlit.
Node ctorKey = cls.constructor.value.getParent();
if (ctorKey != null) {
ctorKey.setJSDocInfo(null);
}
// Check for a conflicting definition of PolymerElement
if (!traversal.inGlobalScope()) {
Var polymerElement = traversal.getScope().getVar("PolymerElement");
if (polymerElement != null && !polymerElement.getScope().isGlobal()) {
Node nameNode = polymerElement.getNameNode();
compiler.report(JSError.make(cls.constructor.value, POLYMER_ELEMENT_CONFLICT, nameNode.getSourceFileName(), Integer.toString(nameNode.getLineno()), Integer.toString(nameNode.getCharno())));
}
}
Node declarationCode = generateDeclarationCode(exprRoot, cls, constructorDoc, traversal);
String basePath = cls.target.getQualifiedName() + ".prototype.";
appendBehaviorPropertiesToBlock(cls, propsAndBehaviorBlock, basePath, /*isExternsBlock*/
false);
appendPropertiesToBlock(cls.props, propsAndBehaviorBlock, basePath, /* isExternsBlock= */
false);
appendBehaviorMembersToBlock(cls, propsAndBehaviorBlock);
ImmutableList<MemberDefinition> readOnlyPropsAll = parseReadOnlyProperties(cls, propsAndBehaviorBlock);
ImmutableList<MemberDefinition> attributeReflectedPropsAll = parseAttributeReflectedProperties(cls);
createExportsAndExterns(cls, readOnlyPropsAll, attributeReflectedPropsAll);
removePropertyDocs(objLit, cls.defType);
Node propsAndBehaviorCode = propsAndBehaviorBlock.removeChildren();
Node parent = exprRoot.getParent();
// exported.
if (!traversal.inGlobalScope() && cls.hasGeneratedLhs && !cls.target.isGetProp()) {
Node enclosingNode = NodeUtil.getEnclosingNode(parent, node -> node.isScript() || node.isModuleBody() || isIIFE(node) || isFunctionArgInGoogLoadModule(node));
// For module, IIFE and goog.LoadModule enclosed Polymer calls, the declaration code and the
// code generated from properties and behavior have to be hoisted in different places within
// the AST. We want to insert the generated declarations to global scope, and insert the
// propsAndbehaviorCode in the same scope. Hence, dealing with them separately.
insertGeneratedDeclarationCodeToGlobalScope(enclosingNode, declarationCode);
if (propsAndBehaviorCode != null) {
insertGeneratedPropsAndBehaviorCode(enclosingNode, propsAndBehaviorCode);
}
} else {
Node beforeRoot = exprRoot.getPrevious();
if (beforeRoot == null) {
if (propsAndBehaviorCode != null) {
parent.addChildrenToFront(propsAndBehaviorCode);
}
parent.addChildToFront(declarationCode);
} else {
if (propsAndBehaviorCode != null) {
parent.addChildrenAfter(propsAndBehaviorCode, beforeRoot);
}
declarationCode.insertAfter(beforeRoot);
}
compiler.reportChangeToEnclosingScope(parent);
}
if (propsAndBehaviorCode != null) {
compiler.reportChangeToEnclosingScope(propsAndBehaviorCode);
}
// we might need to update the FeatureSet.
if (cls.features != null) {
Node scriptNode = NodeUtil.getEnclosingScript(parent);
FeatureSet oldFeatures = (FeatureSet) scriptNode.getProp(Node.FEATURE_SET);
FeatureSet newFeatures = oldFeatures.union(cls.features);
if (!newFeatures.equals(oldFeatures)) {
scriptNode.putProp(Node.FEATURE_SET, newFeatures);
compiler.reportChangeToChangeScope(scriptNode);
}
}
if (NodeUtil.isNameDeclaration(exprRoot)) {
Node assignExpr = varToAssign(exprRoot);
exprRoot.replaceWith(assignExpr);
compiler.reportChangeToEnclosingScope(assignExpr);
}
// with the class members.
if (polymerVersion > 1 && propertyRenamingEnabled && cls.descriptor != null) {
Node props = NodeUtil.getFirstPropMatchingKey(cls.descriptor, "properties");
if (props != null && props.isObjectLit()) {
addPropertiesConfigObjectReflection(cls, props);
}
}
}
use of com.google.javascript.rhino.JSTypeExpression in project closure-compiler by google.
the class PolymerClassRewriter method createVarsInExternsBlock.
/**
* For a JSDoc like @type {{ propertyName : string }}, collects all such "propertyName"s, and
* generates extern vars with an attached {{propertyName: ?}} JsDoc. This is to prevent renaming
* of vars in source code with the same names as propertyNames.
*
* <p>If we do not preserve the property names, then 540 targets get broken on TGP testing. This
* indicates that those targets probably accidentally relied on properties not being renamed, and
* we did not find it important to clean up all those targets' JS source.
*/
private void createVarsInExternsBlock(Node block, ImmutableSet<String> propertyNames, JSTypeExpression propType, MemberDefinition prop) {
for (String propName : propertyNames) {
String varName = "PolymerDummyVar" + compiler.getUniqueNameIdSupplier().get();
Node n = Node.newString(Token.NAME, varName);
Node var = new Node(Token.VAR);
var.addChildToBack(n);
// Forming @type {{ propertyName : ? }}
JSTypeExpression newType = createNewTypeExpressionForExtern(propName, propType.getSourceName(), prop);
JSDocInfo.Builder oldInfoBuilder = JSDocInfo.Builder.maybeCopyFrom(prop.info);
JSDocInfo info = oldInfoBuilder.build();
JSDocInfo.Builder newInfo = JSDocInfo.Builder.copyFromWithNewType(info, newType);
var.setJSDocInfo(newInfo.build());
block.addChildToBack(var);
}
}
Aggregations