Search in sources :

Example 21 with JSTypeExpression

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;
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) Node(com.google.javascript.rhino.Node) Parameter(com.google.javascript.rhino.jstype.FunctionType.Parameter) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) FunctionParamBuilder(com.google.javascript.rhino.jstype.FunctionParamBuilder)

Example 22 with JSTypeExpression

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());
    }
}
Also used : Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) JSDocInfo(com.google.javascript.rhino.JSDocInfo) MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition)

Example 23 with JSTypeExpression

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;
}
Also used : Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) JSDocInfo(com.google.javascript.rhino.JSDocInfo)

Example 24 with JSTypeExpression

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);
        }
    }
}
Also used : Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) FeatureSet(com.google.javascript.jscomp.parsing.parser.FeatureSet) JSDocInfo(com.google.javascript.rhino.JSDocInfo) MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition)

Example 25 with JSTypeExpression

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);
    }
}
Also used : Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) JSDocInfo(com.google.javascript.rhino.JSDocInfo)

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