use of com.google.template.soy.soytree.TemplateBasicNode 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;
}
use of com.google.template.soy.soytree.TemplateBasicNode in project closure-templates by google.
the class CheckDelegatesVisitor method visitCallBasicNode.
@Override
protected void visitCallBasicNode(CallBasicNode node) {
String calleeName = node.getCalleeName();
// Check that the callee name is not a delegate template name.
if (templateRegistry.getDelTemplateSelector().hasDelTemplateNamed(calleeName)) {
errorReporter.report(node.getSourceLocation(), CALL_TO_DELTEMPLATE, calleeName);
}
// Check that the callee is either not in a delegate package or in the same delegate package.
TemplateBasicNode callee = templateRegistry.getBasicTemplate(calleeName);
if (callee != null) {
String calleeDelPackageName = callee.getDelPackageName();
if (calleeDelPackageName != null && !calleeDelPackageName.equals(currDelPackageName)) {
errorReporter.report(node.getSourceLocation(), CROSS_PACKAGE_DELCALL, currTemplateNameForUserMsgs, callee.getTemplateName());
}
}
}
use of com.google.template.soy.soytree.TemplateBasicNode 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());
}
}
}
use of com.google.template.soy.soytree.TemplateBasicNode in project closure-templates by google.
the class Inferences method cloneTemplates.
/**
* Clones a template, changing the name.
*
* @return A copy of tn, differing semantically only in name and auto-generated IDs. The new
* templates will be available via {@link #lookupTemplates} with the given name.
*/
public List<TemplateNode> cloneTemplates(String baseName, String derivedName, CallNode callNode) {
if (!lookupTemplates(derivedName).isEmpty()) {
throw new AssertionError(derivedName + " already has templates: " + lookupTemplates(derivedName));
}
ImmutableList.Builder<TemplateNode> b = ImmutableList.builder();
for (TemplateNode tn : lookupTemplates(baseName)) {
if (SoyTreeUtils.hasHtmlNodes(tn)) {
throw SoyAutoescapeException.createWithNode("Non-strict template '" + baseName + "' contains HTML nodes but does not specify the kind. " + "This is no longer allowed, please migrate the template to strict and " + "specify a content kind by adding a kind attribute", callNode);
}
SoyFileHeaderInfo soyFileHeaderInfo = tn.getSoyFileHeaderInfo();
// We trivially clone the template with new ids, this ensures that all the varrefs have proper
// vardefns assigned. Then we manually recopy to a new template in order to modify the name.
// TODO(lukes): we should add direct support for swapping template names to TemplateNode
// or just eliminate usecases for this method.
TemplateNode trivialClonedTemplate = SoyTreeUtils.cloneWithNewIds(tn, idGen);
int cloneId = trivialClonedTemplate.getId();
// We need to use the unnamespaced name in the command text since we'll be inserting this
// template into a file node that already has a namespace declaration.
TemplateNode clone;
if (tn instanceof TemplateBasicNode) {
String derivedPartialName = (tn.getPartialTemplateName() != null) ? derivedName.substring(soyFileHeaderInfo.namespace.length()) : null;
clone = new TemplateBasicNodeBuilder(soyFileHeaderInfo, ErrorReporter.exploding()).setId(cloneId).setSourceLocation(tn.getSourceLocation()).setCmdTextInfo(derivedName, derivedPartialName, tn.getVisibility(), tn.getAutoescapeMode(), tn.getContentKind(), tn.getRequiredCssNamespaces()).addParams(trivialClonedTemplate.getAllParams()).build();
if (!(derivedName.equals(clone.getTemplateName()) && Objects.equals(derivedPartialName, clone.getPartialTemplateName()))) {
throw new AssertionError();
}
} else if (tn instanceof TemplateDelegateNode) {
TemplateDelegateNode tdn = (TemplateDelegateNode) tn;
clone = new TemplateDelegateNodeBuilder(soyFileHeaderInfo, ErrorReporter.exploding()).setId(cloneId).setSourceLocation(tn.getSourceLocation()).setCmdTextInfo(derivedName, tdn.getDelTemplateVariant(), tdn.getDelPriority(), tn.getAutoescapeMode(), tn.getContentKind(), tn.getRequiredCssNamespaces()).addParams(trivialClonedTemplate.getAllParams()).build();
if (!(derivedName.equals(((TemplateDelegateNode) clone).getDelTemplateName()))) {
throw new AssertionError();
}
} else {
throw new AssertionError("Unknown template node type: " + tn.getClass());
}
clone.addChildren(trivialClonedTemplate.getChildren());
// Reassign all the local variable data which isn't maintained by the cloning process above.
clone.setMaxLocalVariableTableSize(tn.getMaxLocalVariableTableSize());
Iterator<TemplateParam> tnIterator = tn.getAllParams().iterator();
Iterator<TemplateParam> cloneIterator = clone.getAllParams().iterator();
while (tnIterator.hasNext()) {
cloneIterator.next().setLocalVariableIndex(tnIterator.next().localVariableIndex());
}
b.add(clone);
}
ImmutableList<TemplateNode> clones = b.build();
templatesByName.putAll(derivedName, clones);
return clones;
}
use of com.google.template.soy.soytree.TemplateBasicNode in project closure-templates by google.
the class GenPyCallExprVisitor method visitCallBasicNode.
/**
* Visits basic call nodes and builds the call expression. If the callee is in the file, it can be
* accessed directly, but if it's in another file, the module name must be prefixed.
*
* @param node The basic call node.
* @return The call Python expression.
*/
@Override
protected PyExpr visitCallBasicNode(CallBasicNode node) {
String calleeName = node.getCalleeName();
// Build the Python expr text for the callee.
String calleeExprText;
TemplateBasicNode template = getTemplateIfInSameFile(node);
if (template != null) {
// If in the same module no namespace is required.
calleeExprText = getLocalTemplateName(template);
} else {
// If in another module, the module name is required along with the function name.
int secondToLastDotIndex = calleeName.lastIndexOf('.', calleeName.lastIndexOf('.') - 1);
calleeExprText = calleeName.substring(secondToLastDotIndex + 1);
}
String callExprText = calleeExprText + "(" + genObjToPass(node) + ", ijData)";
return escapeCall(callExprText, node.getEscapingDirectives());
}
Aggregations