All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.VariableVisibilityAnalysis Maven / Gradle / Ivy

There is a newer version: 9.0.8
Show newest version
/*
 * Copyright 2010 The Closure Compiler Authors.
 *
 * 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.javascript.jscomp;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.javascript.rhino.Node;
import java.util.HashMap;
import java.util.Map;

/**
 * An analysis pass that determines the visibility of variables -- that is,
 * whether a variable is truly local, a local captured by an inner scope, a
 * parameter, or a global variable.
 *
 * SideEffectsAnalysis uses this class to partition a potentially infinite
 * number of concrete storage locations into a (small) finite number of
 * abstract storage locations based on a variable's storage visibility.
 *
 * @author [email protected] (Devin Coughlin)
 */
class VariableVisibilityAnalysis implements CompilerPass {

  enum VariableVisibility {

    /** Local variable, not captured by closure */
    LOCAL,

    /** Local variable captured by a closure */
    CAPTURED_LOCAL,

    /**
     * Formal parameter declaration variable
     *
     * Parameters are different than local variables because they can be
     * aliased by elements of the arguments object.
     */
    PARAMETER,

    /** A global variable */
    GLOBAL
  }

  private final AbstractCompiler compiler;

  /** Maps the declaring name node for a variable to that variable's visibility. */
  private final Map visibilityByDeclaringNameNode;

  public VariableVisibilityAnalysis(AbstractCompiler compiler) {
    this.compiler = compiler;

    visibilityByDeclaringNameNode = new HashMap<>();
  }

  /**
   * Returns the visibility of of a variable, given that variable's declaring
   * name node.
   *
   * The name node's parent must be one of:
   * 
   *    Token.VAR (for a variable declaration)
   *    Token.FUNCTION (for a function declaration)
   *    Token.PARAM_LIST (for a function formal parameter)
   * 
* * The returned visibility will be one of: *
   *    LOCAL_VARIABLE : the variable is a local variable used only in its
   *        declared scope
   *    CAPTURED_LOCAL_VARIABLE : A local variable that is used in a capturing
   *        closure
   *     PARAMETER_VARIABLE : the variable is a formal parameter
   *     GLOBAL_VARIABLE : the variable is declared in the global scope
   *  
* * @param declaringNameNode The name node for a declaration. */ public VariableVisibility getVariableVisibility(Node declaringNameNode) { Node parent = declaringNameNode.getParent(); checkArgument(parent.isVar() || parent.isFunction() || parent.isParamList()); return visibilityByDeclaringNameNode.get(declaringNameNode); } /** * Determines the visibility class for each variable in root. */ @Override public void process(Node externs, Node root) { ReferenceCollectingCallback callback = new ReferenceCollectingCallback(compiler, ReferenceCollectingCallback.DO_NOTHING_BEHAVIOR, new Es6SyntacticScopeCreator(compiler)); callback.process(root); for (Var variable : callback.getAllSymbols()) { ReferenceCollection referenceCollection = callback.getReferences(variable); VariableVisibility visibility; if (variableIsParameter(variable)) { visibility = VariableVisibility.PARAMETER; } else if (variable.isLocal()) { if (referenceCollection.isEscaped()) { visibility = VariableVisibility.CAPTURED_LOCAL; } else { visibility = VariableVisibility.LOCAL; } } else if (variable.isGlobal()) { visibility = VariableVisibility.GLOBAL; } else { throw new IllegalStateException("Un-handled variable visibility for " + variable); } visibilityByDeclaringNameNode.put(variable.getNameNode(), visibility); } } /** * Returns true if the variable is a formal parameter. */ private static boolean variableIsParameter(Var variable) { Node variableParent = variable.getParentNode(); return variableParent != null && variableParent.isParamList(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy