Java tutorial
/* * Copyright 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.template.soy.passes; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSortedSet; import com.google.template.soy.passes.FindTransitiveDepTemplatesVisitor.TransitiveDepTemplatesInfo; import com.google.template.soy.soytree.SoyFileNode; import com.google.template.soy.soytree.SoyFileSetNode; import com.google.template.soy.soytree.TemplateNode; import com.google.template.soy.soytree.TemplateRegistry; import com.google.template.soy.soytree.defn.TemplateParam; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Visitor for finding the injected params used by a given template. * * <p> Important: Do not use outside of Soy code (treat as superpackage-private). * * <p> {@link #exec} should be called on a {@code TemplateNode}. * * <p> If you need to call this visitor for multiple templates in the same tree (without modifying * the tree), it's more efficient to reuse the same instance of this visitor because we memoize * results from previous calls to exec. * */ public class FindIjParamsVisitor { /** * Return value for {@code FindIjParamsVisitor}. */ public static class IjParamsInfo { /** Sorted set of inject params (i.e. the keys of the multimap below). */ public final ImmutableSortedSet<String> ijParamSet; /** Multimap from injected param key to transitive callees that use the param. */ public final ImmutableMultimap<String, TemplateNode> ijParamToCalleesMultimap; /** * @param ijParamToCalleesMultimap Multimap from injected param key to transitive callees that * use the param. */ public IjParamsInfo(ImmutableMultimap<String, TemplateNode> ijParamToCalleesMultimap) { this.ijParamToCalleesMultimap = ijParamToCalleesMultimap; this.ijParamSet = ImmutableSortedSet.copyOf(ijParamToCalleesMultimap.keySet()); } } // ----------------------------------------------------------------------------------------------- // FindIjParamsVisitor body. /** The FindTransitiveDepTemplatesVisitor to use. */ private final FindTransitiveDepTemplatesVisitor findTransitiveDepTemplatesVisitor; /** Map from TransitiveDepTemplatesInfo to IjParamsInfo, containing memoized results that were * computed in previous calls to exec. */ private final Map<TransitiveDepTemplatesInfo, IjParamsInfo> depsInfoToIjParamsInfoMap; /** Map from template to set of ij params used locally in that template, containing memoized * results that were found in previous calls to exec. */ private final Map<TemplateNode, Set<String>> templateToLocalIjParamsMap; /** * @param templateRegistry Map from template name to TemplateNode to use during the pass. */ public FindIjParamsVisitor(TemplateRegistry templateRegistry) { this.findTransitiveDepTemplatesVisitor = new FindTransitiveDepTemplatesVisitor(templateRegistry); depsInfoToIjParamsInfoMap = new HashMap<>(); templateToLocalIjParamsMap = new HashMap<>(); } /** * Computes injected params info for a template. * * <p> Note: This method is not thread-safe. If you need to get injected params info in a * thread-safe manner, then please use {@link #execOnAllTemplates}() in a thread-safe manner. */ public IjParamsInfo exec(TemplateNode rootTemplate) { TransitiveDepTemplatesInfo depsInfo = findTransitiveDepTemplatesVisitor.exec(rootTemplate); if (!depsInfoToIjParamsInfoMap.containsKey(depsInfo)) { ImmutableMultimap.Builder<String, TemplateNode> ijParamToCalleesMultimapBuilder = ImmutableMultimap .builder(); for (TemplateNode template : depsInfo.depTemplateSet) { if (!templateToLocalIjParamsMap.containsKey(template)) { templateToLocalIjParamsMap.put(template, IjDataQueries.getAllIjs(template)); } for (String localIjParam : templateToLocalIjParamsMap.get(template)) { ijParamToCalleesMultimapBuilder.put(localIjParam, template); } for (TemplateParam injectedParam : template.getInjectedParams()) { ijParamToCalleesMultimapBuilder.put(injectedParam.name(), template); } } IjParamsInfo ijParamsInfo = new IjParamsInfo(ijParamToCalleesMultimapBuilder.build()); depsInfoToIjParamsInfoMap.put(depsInfo, ijParamsInfo); } return depsInfoToIjParamsInfoMap.get(depsInfo); } /** * Precomputes injected params info for all templates. * * <p> Note: This method is not thread-safe. If you need to get injected params info in a * thread-safe manner, be sure to call this method only once and then use the precomputed map. * * @param soyTree The full Soy tree. * @return A map from template node to injected params info for all templates. The returned map * is deeply immutable ({@code IjParamsInfo} is immutable). */ public ImmutableMap<TemplateNode, IjParamsInfo> execOnAllTemplates(SoyFileSetNode soyTree) { ImmutableMap.Builder<TemplateNode, IjParamsInfo> resultMapBuilder = ImmutableMap.builder(); for (SoyFileNode soyFile : soyTree.getChildren()) { for (TemplateNode template : soyFile.getChildren()) { resultMapBuilder.put(template, exec(template)); } } return resultMapBuilder.build(); } }