From 450abbd3f1b3a0ea444cc2bbf1d81e626d77909c Mon Sep 17 00:00:00 2001 From: Jesse Costello-Good Date: Tue, 24 Oct 2023 17:05:56 -0700 Subject: [PATCH] Internal PiperOrigin-RevId: 576331619 --- .../soy/passes/SoyElementCompositionPass.java | 11 ++--- .../template/soy/soytree/SoyTreeUtils.java | 42 +++++++++++++++++++ .../google/template/soy/types/RecordType.java | 15 +++++-- .../soy/types/TemplateBindingUtil.java | 6 +-- .../template/soy/types/TemplateType.java | 10 ++++- 5 files changed, 70 insertions(+), 14 deletions(-) diff --git a/java/src/com/google/template/soy/passes/SoyElementCompositionPass.java b/java/src/com/google/template/soy/passes/SoyElementCompositionPass.java index c338113a11..2366ef6845 100644 --- a/java/src/com/google/template/soy/passes/SoyElementCompositionPass.java +++ b/java/src/com/google/template/soy/passes/SoyElementCompositionPass.java @@ -270,7 +270,7 @@ private void process(TemplateNode template, HtmlTagNode tagNode, IdGenerator nod call.setHtmlContext(HtmlContext.HTML_PCDATA); tagNode.getParent().replaceChild(tagNode, call); - ImmutableMap parameterMap = templateType.getParameterMap(); + ImmutableMap parameterMap = templateType.getParameterMap(); Set seenAttr = new HashSet<>(); tagNode.getChildren().stream() @@ -340,7 +340,7 @@ private void maybeConsumeAttribute( CallBasicNode call, IdGenerator nodeIdGen, Set seenAttr, - Map parameterMap, + Map parameterMap, Map attrs, @Nullable CallParamContentNode attributesNode, Optional conditional) { @@ -445,7 +445,7 @@ private CallParamNode consumeAttribute( HtmlAttributeNode attr, IdGenerator nodeIdGen, Set seenAttr, - Map parameterMap, + Map parameterMap, Map attrs, CallParamContentNode attributesNode, CallBasicNode call, @@ -501,7 +501,7 @@ private CallParamNode consumeAttribute( new CommandTagAttribute( Identifier.create("kind", unknown), QuoteStyle.SINGLE, - getKind(parameterMap.get(paramName)), + getKind(parameterMap.get(paramName).getType()), unknown, unknown), errorReporter); @@ -529,7 +529,8 @@ private CallParamNode consumeAttribute( "$__internal_call_" + paramName + nodeIdGen.genId(), unknown, parameterMap.containsKey(paramName) - ? SanitizedContentKind.fromAttributeValue(getKind(parameterMap.get(paramName))) + ? SanitizedContentKind.fromAttributeValue( + getKind(parameterMap.get(paramName).getType())) .get() : SanitizedContentKind.TEXT); call.getParent().addChild(call.getParent().getChildIndex(call), letContentNode); diff --git a/java/src/com/google/template/soy/soytree/SoyTreeUtils.java b/java/src/com/google/template/soy/soytree/SoyTreeUtils.java index 39808e3b0c..6de37559f5 100644 --- a/java/src/com/google/template/soy/soytree/SoyTreeUtils.java +++ b/java/src/com/google/template/soy/soytree/SoyTreeUtils.java @@ -21,6 +21,7 @@ import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; @@ -651,4 +652,45 @@ public static Stream allTypeNodes(SoyNode root) { } }); } + + public static ExprNodeToHolderIndex buildExprNodeToHolderIndex(SoyNode root) { + return new ExprNodeToHolderIndex(root); + } + + /** Index mapping an expression node to the soy node that holds it. */ + public static class ExprNodeToHolderIndex { + + private final ImmutableMap index; + + ExprNodeToHolderIndex(SoyNode root) { + ImmutableMap.Builder index = ImmutableMap.builder(); + allNodesOfType(root, ExprHolderNode.class) + .forEach( + holder -> { + for (ExprRootNode exprRoot : holder.getExprList()) { + index.put(exprRoot, holder); + } + }); + this.index = index.buildOrThrow(); + } + + ExprHolderNode getHolder(ExprRootNode root) { + return Preconditions.checkNotNull(index.get(root)); + } + + public ExprHolderNode getHolder(ExprNode node) { + while (node.getParent() != null) { + node = node.getParent(); + } + return getHolder((ExprRootNode) node); + } + + @Nullable + public ExprHolderNode getNullableHolder(ExprNode node) { + while (node.getParent() != null) { + node = node.getParent(); + } + return index.get((ExprRootNode) node); + } + } } diff --git a/java/src/com/google/template/soy/types/RecordType.java b/java/src/com/google/template/soy/types/RecordType.java index ccb32f2d75..2e974c883f 100644 --- a/java/src/com/google/template/soy/types/RecordType.java +++ b/java/src/com/google/template/soy/types/RecordType.java @@ -26,6 +26,7 @@ import java.util.NavigableMap; import java.util.Objects; import java.util.stream.Collectors; +import javax.annotation.Nullable; /** * Dict type - classic dictionary type with string keys. Only works with field (dot) access. @@ -56,13 +57,12 @@ public static Member memberOf(String name, boolean optional, SoyType type) { } private final ImmutableList members; - private final ImmutableMap memberIndex; + private final ImmutableMap memberIndex; private RecordType(Iterable members) { this.members = ImmutableList.copyOf(members); this.memberIndex = - Streams.stream(members) - .collect(ImmutableMap.toImmutableMap(Member::name, Member::checkedType)); + Streams.stream(members).collect(ImmutableMap.toImmutableMap(Member::name, m -> m)); } /** @@ -111,10 +111,17 @@ public ImmutableList getMembers() { return members; } - public SoyType getMemberType(String fieldName) { + @Nullable + public Member getMember(String fieldName) { return memberIndex.get(fieldName); } + @Nullable + public SoyType getMemberType(String fieldName) { + Member member = memberIndex.get(fieldName); + return member != null ? member.checkedType() : null; + } + public Iterable getMemberNames() { return members.stream().map(Member::name).collect(Collectors.toList()); } diff --git a/java/src/com/google/template/soy/types/TemplateBindingUtil.java b/java/src/com/google/template/soy/types/TemplateBindingUtil.java index 916d839594..2a2ae91eba 100644 --- a/java/src/com/google/template/soy/types/TemplateBindingUtil.java +++ b/java/src/com/google/template/soy/types/TemplateBindingUtil.java @@ -79,7 +79,7 @@ private static SoyType bindParametersToTemplate( boolean reportedErrors = false; TemplateType.Builder builder = base.toBuilder(); for (RecordType.Member member : parameters.getMembers()) { - if (!base.getParameterMap().containsKey(member.name())) { + if (base.getParameter(member.name()) == null) { if (member.name().equals(TemplateType.EXTRA_ROOT_ELEMENT_ATTRIBUTES) && base.getAllowExtraAttributes()) { builder.setAllowExtraAttributes(false); @@ -91,12 +91,12 @@ private static SoyType bindParametersToTemplate( reportedErrors = true; continue; } - if (!base.getParameterMap().get(member.name()).isAssignableFromLoose(member.checkedType())) { + if (!base.getParameter(member.name()).getType().isAssignableFromLoose(member.checkedType())) { errorReporter.report( PARAMETER_TYPE_MISMATCH, member.name(), base, - base.getParameterMap().get(member.name()), + base.getParameter(member.name()).getType(), member.checkedType()); reportedErrors = true; } diff --git a/java/src/com/google/template/soy/types/TemplateType.java b/java/src/com/google/template/soy/types/TemplateType.java index 74c9e67931..55f34a9a08 100644 --- a/java/src/com/google/template/soy/types/TemplateType.java +++ b/java/src/com/google/template/soy/types/TemplateType.java @@ -118,8 +118,14 @@ public ImmutableList getActualParameters() { return builder.build(); } - public final ImmutableMap getParameterMap() { - return getParameters().stream().collect(toImmutableMap(Parameter::getName, Parameter::getType)); + @Memoized + public ImmutableMap getParameterMap() { + return getParameters().stream().collect(toImmutableMap(Parameter::getName, p -> p)); + } + + @Nullable + public final Parameter getParameter(String name) { + return getParameterMap().get(name); } public abstract ImmutableList getDataAllCallSituations();