com.google.template.soy.sharedpasses.FindIjParamsVisitor.java Source code

Java tutorial

Introduction

Here is the source code for com.google.template.soy.sharedpasses.FindIjParamsVisitor.java

Source

/*
 * 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.sharedpasses;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.template.soy.error.ErrorReporter;
import com.google.template.soy.sharedpasses.FindTransitiveDepTemplatesVisitor.TransitiveDepTemplatesInfo;
import com.google.template.soy.soytree.SoyFileNode;
import com.google.template.soy.soytree.SoyFileSetNode;
import com.google.template.soy.soytree.SoytreeUtils;
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;

import javax.annotation.Nullable;

/**
 * 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;

    private final ErrorReporter errorReporter;

    /**
     * @param templateRegistry Map from template name to TemplateNode to use during the pass.
     * @param errorReporter For reporting errors.
     */
    public FindIjParamsVisitor(@Nullable TemplateRegistry templateRegistry, ErrorReporter errorReporter) {
        this.errorReporter = errorReporter;
        this.findTransitiveDepTemplatesVisitor = new FindTransitiveDepTemplatesVisitor(templateRegistry,
                errorReporter);
        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)) {
                    FindIjParamsInExprHelperVisitor helperVisitor = new FindIjParamsInExprHelperVisitor(
                            errorReporter);
                    SoytreeUtils.execOnAllV2Exprs(template, helperVisitor, errorReporter);
                    Set<String> localIjParams = helperVisitor.getResult();
                    templateToLocalIjParamsMap.put(template, localIjParams);
                }

                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();
    }

}