Search in sources :

Example 1 with TemplateParam

use of com.google.template.soy.soytree.defn.TemplateParam in project closure-templates by google.

the class GenJsCodeVisitor method genParamsRecordType.

// -----------------------------------------------------------------------------------------------
// Helpers
/**
 * Generate the JSDoc for the opt_data parameter.
 */
private String genParamsRecordType(TemplateNode node) {
    Set<String> paramNames = new HashSet<>();
    // Generate members for explicit params.
    Map<String, String> record = new LinkedHashMap<>();
    for (TemplateParam param : node.getParams()) {
        JsType jsType = getJsType(param.type());
        record.put(genParamAlias(param.name()), jsType.typeExprForRecordMember(/* isOptional= */
        !param.isRequired()));
        for (GoogRequire require : jsType.getGoogRequires()) {
            jsCodeBuilder.addGoogRequire(require);
        }
        paramNames.add(param.name());
    }
    // Do the same for indirect params, if we can find them.
    // If there's a conflict between the explicitly-declared type, and the type
    // inferred from the indirect params, then the explicit type wins.
    // Also note that indirect param types may not be inferrable if the target
    // is not in the current compilation file set.
    IndirectParamsInfo ipi = new FindIndirectParamsVisitor(templateRegistry).exec(node);
    // types in JS allow additional undeclared fields to be present.
    if (!ipi.mayHaveIndirectParamsInExternalCalls && !ipi.mayHaveIndirectParamsInExternalDelCalls) {
        for (String indirectParamName : ipi.indirectParamTypes.keySet()) {
            if (paramNames.contains(indirectParamName)) {
                continue;
            }
            Collection<SoyType> paramTypes = ipi.indirectParamTypes.get(indirectParamName);
            SoyType combinedType = SoyTypes.computeLowestCommonType(typeRegistry, paramTypes);
            // Note that Union folds duplicate types and flattens unions, so if
            // the combinedType is already a union this will do the right thing.
            // TODO: detect cases where nullable is not needed (requires flow
            // analysis to determine if the template is always called.)
            SoyType indirectParamType = typeRegistry.getOrCreateUnionType(combinedType, NullType.getInstance());
            JsType jsType = getJsType(indirectParamType);
            // NOTE: we do not add goog.requires for indirect types.  This is because it might introduce
            // strict deps errors.  This should be fine though since the transitive soy template that
            // actually has the param will add them.
            record.put(genParamAlias(indirectParamName), jsType.typeExprForRecordMember(/* isOptional= */
            true));
        }
    }
    StringBuilder sb = new StringBuilder();
    sb.append("{\n *  ");
    Joiner.on(",\n *  ").withKeyValueSeparator(": ").appendTo(sb, record);
    // trailing comma in record is important in case the last record member is the
    // unknown type
    sb.append(",\n * }");
    return sb.toString();
}
Also used : LinkedHashMap(java.util.LinkedHashMap) IndirectParamsInfo(com.google.template.soy.passes.FindIndirectParamsVisitor.IndirectParamsInfo) GoogRequire(com.google.template.soy.jssrc.dsl.GoogRequire) SoyType(com.google.template.soy.types.SoyType) TemplateParam(com.google.template.soy.soytree.defn.TemplateParam) HashSet(java.util.HashSet) FindIndirectParamsVisitor(com.google.template.soy.passes.FindIndirectParamsVisitor)

Example 2 with TemplateParam

use of com.google.template.soy.soytree.defn.TemplateParam in project closure-templates by google.

the class GenJsCodeVisitor method genParamTypeChecks.

/**
 * Generate code to verify the runtime types of the input params. Also typecasts the input
 * parameters and assigns them to local variables for use in the template.
 *
 * @param node the template node.
 */
@CheckReturnValue
protected CodeChunk genParamTypeChecks(TemplateNode node) {
    ImmutableList.Builder<CodeChunk> declarations = ImmutableList.builder();
    for (TemplateParam param : node.getAllParams()) {
        if (param.declLoc() != TemplateParam.DeclLoc.HEADER) {
            continue;
        }
        String paramName = param.name();
        SoyType paramType = param.type();
        CodeChunk.Generator generator = templateTranslationContext.codeGenerator();
        CodeChunk.WithValue paramChunk = TranslateExprNodeVisitor.genCodeForParamAccess(paramName, param.isInjected());
        JsType jsType = getJsType(paramType);
        // The opt_param.name value that will be type-tested.
        String paramAlias = genParamAlias(paramName);
        CodeChunk.WithValue coerced = jsType.getValueCoercion(paramChunk, generator);
        if (coerced != null) {
            // since we have coercion logic, dump into a temporary
            paramChunk = generator.declarationBuilder().setRhs(coerced).build().ref();
        }
        // The param value to assign
        CodeChunk.WithValue value;
        Optional<CodeChunk.WithValue> typeAssertion = jsType.getTypeAssertion(paramChunk, generator);
        // The type-cast expression.
        if (typeAssertion.isPresent()) {
            value = SOY_ASSERTS_ASSERT_TYPE.call(typeAssertion.get(), stringLiteral(paramName), paramChunk, stringLiteral(jsType.typeExpr()));
        } else {
            value = paramChunk;
        }
        VariableDeclaration.Builder declarationBuilder = VariableDeclaration.builder(paramAlias).setRhs(value).setGoogRequires(jsType.getGoogRequires());
        declarationBuilder.setJsDoc("/** @type {" + jsType.typeExpr() + "} */");
        VariableDeclaration declaration = declarationBuilder.build();
        declarations.add(declaration);
        templateTranslationContext.soyToJsVariableMappings().put(paramName, id(paramAlias));
    }
    return CodeChunk.statements(declarations.build());
}
Also used : ImmutableList(com.google.common.collect.ImmutableList) CodeChunk(com.google.template.soy.jssrc.dsl.CodeChunk) SoyType(com.google.template.soy.types.SoyType) VariableDeclaration(com.google.template.soy.jssrc.dsl.VariableDeclaration) TemplateParam(com.google.template.soy.soytree.defn.TemplateParam) CheckReturnValue(javax.annotation.CheckReturnValue)

Example 3 with TemplateParam

use of com.google.template.soy.soytree.defn.TemplateParam in project closure-templates by google.

the class GenerateParseInfoVisitor method visitSoyFileNode.

@Override
protected void visitSoyFileNode(SoyFileNode node) {
    if (node.getSoyFileKind() != SoyFileKind.SRC) {
        // don't generate code for deps
        return;
    }
    String javaClassName = soyFileToJavaClassNameMap.get(node);
    // Collect the following:
    // + all the public basic templates (non-private, non-delegate) in a map from the
    // upper-underscore template name to the template's node,
    // + all the param keys from all templates (including private),
    // + for each param key, the list of templates that list it directly.
    // + for any params whose type is a proto, get the proto name and Java class name.
    LinkedHashMap<String, TemplateNode> publicBasicTemplateMap = Maps.newLinkedHashMap();
    List<String> deltemplates = new ArrayList<>();
    Set<String> allParamKeys = Sets.newHashSet();
    SetMultimap<String, TemplateNode> paramKeyToTemplatesMultimap = LinkedHashMultimap.create();
    SortedSet<String> protoTypes = Sets.newTreeSet();
    for (TemplateNode template : node.getChildren()) {
        if (template.getVisibility() == Visibility.PUBLIC && template instanceof TemplateBasicNode) {
            publicBasicTemplateMap.put(convertToUpperUnderscore(template.getPartialTemplateName().substring(1)), template);
        }
        if (template instanceof TemplateDelegateNode) {
            deltemplates.add("\"" + template.getTemplateName() + "\"");
        }
        for (TemplateParam param : template.getAllParams()) {
            if (!param.isInjected()) {
                allParamKeys.add(param.name());
                paramKeyToTemplatesMultimap.put(param.name(), template);
            }
            if (param instanceof HeaderParam) {
                SoyType paramType = ((HeaderParam) param).type();
                findProtoTypesRecurse(paramType, protoTypes);
            }
        }
        // Field access nodes need special handling to ensure that extension references are handled.
        for (FieldAccessNode fieldAccess : SoyTreeUtils.getAllNodesOfType(template, FieldAccessNode.class)) {
            SoyType baseType = fieldAccess.getBaseExprChild().getType();
            if (baseType.getKind() == SoyType.Kind.PROTO) {
                FieldDescriptor desc = ((SoyProtoType) baseType).getFieldDescriptor(fieldAccess.getFieldName());
                if (desc.isExtension()) {
                    protoTypes.add(ProtoUtils.getTofuExtensionImport(desc));
                }
            }
        }
        // Add enums
        for (GlobalNode global : SoyTreeUtils.getAllNodesOfType(template, GlobalNode.class)) {
            if (global.isResolved() && global.getType().getKind() == SoyType.Kind.PROTO_ENUM) {
                protoTypes.add(((SoyProtoEnumType) global.getType()).getDescriptorExpression());
            }
        }
        // Add proto init
        for (ProtoInitNode protoInit : SoyTreeUtils.getAllNodesOfType(template, ProtoInitNode.class)) {
            if (protoInit.getType().getKind() == SoyType.Kind.PROTO) {
                protoTypes.add(((SoyProtoType) protoInit.getType()).getDescriptorExpression());
            }
        }
    }
    // allParamKeysMap is a map from upper-underscore key to original key.
    SortedMap<String, String> allParamKeysMap = Maps.newTreeMap();
    for (String key : allParamKeys) {
        String upperUnderscoreKey = convertToUpperUnderscore(key);
        // stage of the compiler.
        while (allParamKeysMap.containsKey(upperUnderscoreKey)) {
            upperUnderscoreKey = upperUnderscoreKey + "_";
        }
        allParamKeysMap.put(upperUnderscoreKey, key);
        // Updates the convertedIdents here, since we might have changed the value by adding
        // prepending underscores. Without this, the generated SoyTemplateInfo still use the
        // old mapping and will fail.
        convertedIdents.put(key, upperUnderscoreKey);
    }
    ilb = new IndentedLinesBuilder(2);
    // ------ Header. ------
    ilb.appendLine("// This file was automatically generated from ", node.getFileName(), ".");
    ilb.appendLine("// Please don't edit this file by hand.");
    ilb.appendLine();
    ilb.appendLine("package ", javaPackage, ";");
    ilb.appendLine();
    ilb.appendLine("import com.google.common.collect.ImmutableList;");
    ilb.appendLine("import com.google.common.collect.ImmutableMap;");
    ilb.appendLine("import com.google.common.collect.ImmutableSortedSet;");
    if (!protoTypes.isEmpty()) {
        ilb.appendLine("import com.google.protobuf.Descriptors.GenericDescriptor;");
    }
    ilb.appendLine("import com.google.template.soy.parseinfo.SoyFileInfo;");
    ilb.appendLine("import com.google.template.soy.parseinfo.SoyTemplateInfo;");
    // ------ Class start. ------
    ilb.appendLine();
    ilb.appendLine();
    appendJavadoc(ilb, "Soy parse info for " + node.getFileName() + ".", true, false);
    ilb.appendLine("public final class ", javaClassName, " extends SoyFileInfo {");
    ilb.increaseIndent();
    // ------ Constant for namespace. ------
    ilb.appendLine();
    ilb.appendLine();
    ilb.appendLine("/** This Soy file's namespace. */");
    ilb.appendLine("public static final String __NAMESPACE__ = \"", node.getNamespace(), "\";");
    // ------ Proto types map. ------
    if (!protoTypes.isEmpty()) {
        ilb.appendLine();
        ilb.appendLine();
        ilb.appendLine("/** Protocol buffer types used by these templates. */");
        ilb.appendLine("@Override public ImmutableList<GenericDescriptor> getProtoDescriptors() {");
        ilb.increaseIndent();
        // Note we use fully-qualified names instead of imports to avoid potential collisions.
        List<String> defaultInstances = Lists.newArrayList();
        defaultInstances.addAll(protoTypes);
        appendListOrSetHelper(ilb, "return ImmutableList.<GenericDescriptor>of", defaultInstances);
        ilb.appendLineEnd(";");
        ilb.decreaseIndent();
        ilb.appendLine("}");
    }
    // ------ Template names. ------
    ilb.appendLine();
    ilb.appendLine();
    ilb.appendLine("public static final class TemplateName {");
    ilb.increaseIndent();
    ilb.appendLine("private TemplateName() {}");
    ilb.appendLine();
    for (Entry<String, TemplateNode> templateEntry : publicBasicTemplateMap.entrySet()) {
        StringBuilder javadocSb = new StringBuilder();
        javadocSb.append("The full template name of the ").append(templateEntry.getValue().getPartialTemplateName()).append(" template.");
        appendJavadoc(ilb, javadocSb.toString(), false, true);
        ilb.appendLine("public static final String ", templateEntry.getKey(), " = \"", templateEntry.getValue().getTemplateName(), "\";");
    }
    ilb.decreaseIndent();
    ilb.appendLine("}");
    // ------ Params. ------
    ilb.appendLine();
    ilb.appendLine();
    ilb.appendLine("/**");
    ilb.appendLine(" * Param names from all templates in this Soy file.");
    ilb.appendLine(" */");
    ilb.appendLine("public static final class Param {");
    ilb.increaseIndent();
    ilb.appendLine("private Param() {}");
    ilb.appendLine();
    for (Map.Entry<String, String> paramEntry : allParamKeysMap.entrySet()) {
        String upperUnderscoreKey = paramEntry.getKey();
        String key = paramEntry.getValue();
        StringBuilder javadocSb = new StringBuilder();
        javadocSb.append("Listed by ");
        boolean isFirst = true;
        for (TemplateNode template : paramKeyToTemplatesMultimap.get(key)) {
            if (isFirst) {
                isFirst = false;
            } else {
                javadocSb.append(", ");
            }
            javadocSb.append(buildTemplateNameForJavadoc(node, template));
        }
        javadocSb.append('.');
        appendJavadoc(ilb, javadocSb.toString(), false, true);
        ilb.appendLine("public static final String ", upperUnderscoreKey, " = \"", key, "\";");
    }
    ilb.decreaseIndent();
    ilb.appendLine("}");
    // ------ Templates. ------
    for (TemplateNode template : publicBasicTemplateMap.values()) {
        visit(template);
    }
    // ------ Constructor. ------
    ilb.appendLine();
    ilb.appendLine();
    ilb.appendLine("private ", javaClassName, "() {");
    ilb.increaseIndent();
    ilb.appendLine("super(");
    ilb.increaseIndent(2);
    ilb.appendLine("\"", node.getFileName(), "\",");
    ilb.appendLine("\"", node.getNamespace(), "\",");
    // Templates.
    List<String> itemSnippets = Lists.newArrayList();
    itemSnippets.addAll(publicBasicTemplateMap.keySet());
    appendImmutableList(ilb, "<SoyTemplateInfo>", itemSnippets);
    ilb.appendLineEnd(",");
    // CSS names.
    SortedMap<String, CssTagsPrefixPresence> cssNameMap = new CollectCssNamesVisitor().exec(node);
    ImmutableMap.Builder<String, String> cssTagPrefixes = ImmutableMap.builder();
    for (Map.Entry<String, CssTagsPrefixPresence> entry : cssNameMap.entrySet()) {
        cssTagPrefixes.put("\"" + entry.getKey() + "\"", "CssTagsPrefixPresence." + entry.getValue().name());
    }
    appendImmutableMap(ilb, "<String, CssTagsPrefixPresence>", cssTagPrefixes.build());
    ilb.appendLineEnd(",");
    appendImmutableList(ilb, "<String>", deltemplates);
    ilb.appendLineEnd(");");
    ilb.decreaseIndent(2);
    ilb.decreaseIndent();
    ilb.appendLine("}");
    // ------ Singleton instance and its getter. ------
    ilb.appendLine();
    ilb.appendLine();
    ilb.appendLine("private static final ", javaClassName, " __INSTANCE__ =");
    ilb.increaseIndent(2);
    ilb.appendLine("new ", javaClassName, "();");
    ilb.decreaseIndent(2);
    ilb.appendLine();
    ilb.appendLine("public static ", javaClassName, " getInstance() {");
    ilb.increaseIndent();
    ilb.appendLine("return __INSTANCE__;");
    ilb.decreaseIndent();
    ilb.appendLine("}");
    // ------ Class end. ------
    ilb.appendLine();
    ilb.decreaseIndent();
    ilb.appendLine("}");
    generatedFiles.put(javaClassName + ".java", ilb.toString());
    ilb = null;
}
Also used : TemplateBasicNode(com.google.template.soy.soytree.TemplateBasicNode) HeaderParam(com.google.template.soy.soytree.defn.HeaderParam) IndentedLinesBuilder(com.google.template.soy.base.internal.IndentedLinesBuilder) ArrayList(java.util.ArrayList) FieldDescriptor(com.google.protobuf.Descriptors.FieldDescriptor) ProtoInitNode(com.google.template.soy.exprtree.ProtoInitNode) TemplateParam(com.google.template.soy.soytree.defn.TemplateParam) TemplateNode(com.google.template.soy.soytree.TemplateNode) TemplateDelegateNode(com.google.template.soy.soytree.TemplateDelegateNode) FieldAccessNode(com.google.template.soy.exprtree.FieldAccessNode) SoyProtoType(com.google.template.soy.types.SoyProtoType) ImmutableMap(com.google.common.collect.ImmutableMap) SoyType(com.google.template.soy.types.SoyType) GlobalNode(com.google.template.soy.exprtree.GlobalNode) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) SortedMap(java.util.SortedMap) LinkedHashMap(java.util.LinkedHashMap) CssTagsPrefixPresence(com.google.template.soy.parseinfo.SoyFileInfo.CssTagsPrefixPresence)

Example 4 with TemplateParam

use of com.google.template.soy.soytree.defn.TemplateParam in project closure-templates by google.

the class GenerateParseInfoVisitor method visitTemplateNode.

@Override
protected void visitTemplateNode(TemplateNode node) {
    // Don't generate anything for private or delegate templates.
    if (node.getVisibility() != Visibility.PUBLIC || node instanceof TemplateDelegateNode) {
        return;
    }
    // First build list of all transitive params (direct and indirect).
    LinkedHashMap<String, TemplateParam> transitiveParamMap = Maps.newLinkedHashMap();
    // Direct params.
    for (TemplateParam param : node.getParams()) {
        transitiveParamMap.put(param.name(), param);
    }
    // Indirect params.
    IndirectParamsInfo indirectParamsInfo = new FindIndirectParamsVisitor(templateRegistry).exec(node);
    for (TemplateParam param : indirectParamsInfo.indirectParams.values()) {
        TemplateParam existingParam = transitiveParamMap.get(param.name());
        if (existingParam == null) {
            // Note: We don't list the description for indirect params.
            transitiveParamMap.put(param.name(), param.copyEssential());
        }
    }
    // Get info on injected params.
    IjParamsInfo ijParamsInfo = new FindIjParamsVisitor(templateRegistry).exec(node);
    // for IntelliJ
    @SuppressWarnings("ConstantConditions") String upperUnderscoreName = convertToUpperUnderscore(node.getPartialTemplateName().substring(1));
    String templateInfoClassName = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, upperUnderscoreName) + "SoyTemplateInfo";
    // ------ *SoyTemplateInfo class start. ------
    ilb.appendLine();
    ilb.appendLine();
    appendJavadoc(ilb, Optional.fromNullable(node.getSoyDocDesc()).or(""), true, false);
    ilb.appendLine("public static final class ", templateInfoClassName, " extends SoyTemplateInfo {");
    ilb.increaseIndent();
    // ------ Constants for template name. ------
    ilb.appendLine();
    ilb.appendLine("/** This template's full name. */");
    ilb.appendLine("public static final String __NAME__ = \"", node.getTemplateName(), "\";");
    ilb.appendLine("/** This template's partial name. */");
    ilb.appendLine("public static final String __PARTIAL_NAME__ = \"", node.getPartialTemplateName(), "\";");
    // ------ Param constants. ------
    boolean hasSeenFirstDirectParam = false;
    boolean hasSwitchedToIndirectParams = false;
    for (TemplateParam param : transitiveParamMap.values()) {
        if (param.desc() != null) {
            // Direct param.
            if (!hasSeenFirstDirectParam) {
                ilb.appendLine();
                hasSeenFirstDirectParam = true;
            }
            appendJavadoc(ilb, param.desc(), false, false);
        } else {
            // Indirect param.
            if (!hasSwitchedToIndirectParams) {
                ilb.appendLine();
                ilb.appendLine("// Indirect params.");
                hasSwitchedToIndirectParams = true;
            }
            // Get the list of all transitive callee names as they will appear in the generated
            // Javadoc (possibly containing both partial and full names) and sort them before
            // generating the Javadoc.
            SortedSet<String> sortedJavadocCalleeNames = Sets.newTreeSet();
            for (TemplateNode transitiveCallee : indirectParamsInfo.paramKeyToCalleesMultimap.get(param.name())) {
                String javadocCalleeName = buildTemplateNameForJavadoc(node.getParent(), transitiveCallee);
                sortedJavadocCalleeNames.add(javadocCalleeName);
            }
            // Generate the Javadoc.
            StringBuilder javadocSb = new StringBuilder();
            javadocSb.append("Listed by ");
            boolean isFirst = true;
            for (String javadocCalleeName : sortedJavadocCalleeNames) {
                if (isFirst) {
                    isFirst = false;
                } else {
                    javadocSb.append(", ");
                }
                javadocSb.append(javadocCalleeName);
            }
            javadocSb.append('.');
            appendJavadoc(ilb, javadocSb.toString(), false, true);
        }
        // The actual param field.
        ilb.appendLine("public static final String ", convertToUpperUnderscore(param.name()), " = \"", param.name(), "\";");
    }
    // ------ Constructor. ------
    ilb.appendLine();
    ilb.appendLine("private ", templateInfoClassName, "() {");
    ilb.increaseIndent();
    ilb.appendLine("super(");
    ilb.increaseIndent(2);
    ilb.appendLine("\"", node.getTemplateName(), "\",");
    if (!transitiveParamMap.isEmpty()) {
        ImmutableMap.Builder<String, String> entrySnippetPairs = ImmutableMap.builder();
        for (TemplateParam param : transitiveParamMap.values()) {
            entrySnippetPairs.put("\"" + param.name() + "\"", param.isRequired() ? "ParamRequisiteness.REQUIRED" : "ParamRequisiteness.OPTIONAL");
        }
        appendImmutableMap(ilb, "<String, ParamRequisiteness>", entrySnippetPairs.build());
        ilb.appendLineEnd(",");
    } else {
        ilb.appendLine("ImmutableMap.<String, ParamRequisiteness>of(),");
    }
    appendIjParamSet(ilb, ijParamsInfo);
    ilb.appendLineEnd(",");
    ilb.appendLine("\"", node.getAutoescapeMode().getAttributeValue(), "\");");
    ilb.decreaseIndent(2);
    ilb.decreaseIndent();
    ilb.appendLine("}");
    // ------ Singleton instance and its getter. ------
    ilb.appendLine();
    ilb.appendLine("private static final ", templateInfoClassName, " __INSTANCE__ =");
    ilb.increaseIndent(2);
    ilb.appendLine("new ", templateInfoClassName, "();");
    ilb.decreaseIndent(2);
    ilb.appendLine();
    ilb.appendLine("public static ", templateInfoClassName, " getInstance() {");
    ilb.increaseIndent();
    ilb.appendLine("return __INSTANCE__;");
    ilb.decreaseIndent();
    ilb.appendLine("}");
    // ------ *SoyTemplateInfo class end. ------
    ilb.decreaseIndent();
    ilb.appendLine("}");
    // ------ Static field with instance of *SoyTemplateInfo class. ------
    ilb.appendLine();
    ilb.appendLine("/** Same as ", templateInfoClassName, ".getInstance(). */");
    ilb.appendLine("public static final ", templateInfoClassName, " ", upperUnderscoreName, " =");
    ilb.increaseIndent(2);
    ilb.appendLine(templateInfoClassName, ".getInstance();");
    ilb.decreaseIndent(2);
}
Also used : TemplateDelegateNode(com.google.template.soy.soytree.TemplateDelegateNode) IjParamsInfo(com.google.template.soy.passes.FindIjParamsVisitor.IjParamsInfo) TemplateNode(com.google.template.soy.soytree.TemplateNode) FindIjParamsVisitor(com.google.template.soy.passes.FindIjParamsVisitor) ImmutableMap(com.google.common.collect.ImmutableMap) IndirectParamsInfo(com.google.template.soy.passes.FindIndirectParamsVisitor.IndirectParamsInfo) TemplateParam(com.google.template.soy.soytree.defn.TemplateParam) FindIndirectParamsVisitor(com.google.template.soy.passes.FindIndirectParamsVisitor)

Example 5 with TemplateParam

use of com.google.template.soy.soytree.defn.TemplateParam in project closure-templates by google.

the class CheckTemplateParamsVisitor method visitTemplateNode.

// -----------------------------------------------------------------------------------------------
// Implementations for specific nodes.
@Override
protected void visitTemplateNode(TemplateNode node) {
    if (!node.couldHaveSyntaxVersionAtLeast(SyntaxVersion.V2_0)) {
        return;
    }
    ListMultimap<String, SourceLocation> dataKeys = ArrayListMultimap.create();
    for (VarRefNode varRefNode : SoyTreeUtils.getAllNodesOfType(node, VarRefNode.class)) {
        if (varRefNode.isPossibleParam()) {
            dataKeys.put(varRefNode.getName(), varRefNode.getSourceLocation());
        }
    }
    IndirectParamsInfo ipi = new FindIndirectParamsVisitor(templateRegistry).exec(node);
    Set<String> allParamNames = new HashSet<>();
    List<TemplateParam> unusedParams = new ArrayList<>();
    for (TemplateParam param : node.getAllParams()) {
        allParamNames.add(param.name());
        if (dataKeys.containsKey(param.name())) {
            // Good: Declared and referenced in template. We remove these from dataKeys so
            // that at the end of the for-loop, dataKeys will only contain the keys that are referenced
            // but not declared in SoyDoc.
            dataKeys.removeAll(param.name());
        } else if (ipi.paramKeyToCalleesMultimap.containsKey(param.name()) || ipi.mayHaveIndirectParamsInExternalCalls || ipi.mayHaveIndirectParamsInExternalDelCalls) {
        // Good: Declared in SoyDoc and either (a) used in a call that passes all data or (b) used
        // in an external call or delcall that passes all data, which may need the param (we can't
        // verify).
        } else {
            // Bad: Declared in SoyDoc but not referenced in template.
            unusedParams.add(param);
        }
    }
    // At this point, the only keys left in dataKeys are undeclared.
    for (Entry<String, SourceLocation> undeclared : dataKeys.entries()) {
        String extraErrorMessage = SoyErrors.getDidYouMeanMessage(allParamNames, undeclared.getKey());
        errorReporter.report(undeclared.getValue(), UNDECLARED_DATA_KEY, undeclared.getKey(), extraErrorMessage);
    }
    // of the same delegate may need to use those params.
    if (node instanceof TemplateBasicNode) {
        for (TemplateParam unusedParam : unusedParams) {
            errorReporter.report(unusedParam.nameLocation(), UNUSED_PARAM, unusedParam.name());
        }
    }
}
Also used : SourceLocation(com.google.template.soy.base.SourceLocation) TemplateBasicNode(com.google.template.soy.soytree.TemplateBasicNode) ArrayList(java.util.ArrayList) VarRefNode(com.google.template.soy.exprtree.VarRefNode) IndirectParamsInfo(com.google.template.soy.passes.FindIndirectParamsVisitor.IndirectParamsInfo) TemplateParam(com.google.template.soy.soytree.defn.TemplateParam) HashSet(java.util.HashSet)

Aggregations

TemplateParam (com.google.template.soy.soytree.defn.TemplateParam)18 TemplateNode (com.google.template.soy.soytree.TemplateNode)7 IndirectParamsInfo (com.google.template.soy.passes.FindIndirectParamsVisitor.IndirectParamsInfo)4 Test (org.junit.Test)4 TemplateBasicNode (com.google.template.soy.soytree.TemplateBasicNode)3 TemplateDelegateNode (com.google.template.soy.soytree.TemplateDelegateNode)3 SoyType (com.google.template.soy.types.SoyType)3 ArrayList (java.util.ArrayList)3 HashSet (java.util.HashSet)3 ImmutableList (com.google.common.collect.ImmutableList)2 ImmutableMap (com.google.common.collect.ImmutableMap)2 SourceLocation (com.google.template.soy.base.SourceLocation)2 VarRefNode (com.google.template.soy.exprtree.VarRefNode)2 FindIndirectParamsVisitor (com.google.template.soy.passes.FindIndirectParamsVisitor)2 HeaderParam (com.google.template.soy.soytree.defn.HeaderParam)2 SoyDocParam (com.google.template.soy.soytree.defn.SoyDocParam)2 LinkedHashMap (java.util.LinkedHashMap)2 ImmutableMultimap (com.google.common.collect.ImmutableMultimap)1 FieldDescriptor (com.google.protobuf.Descriptors.FieldDescriptor)1 IndentedLinesBuilder (com.google.template.soy.base.internal.IndentedLinesBuilder)1