com.google.javascript.jscomp.VariableVisibilityAnalysis Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.liferay.frontend.js.minifier
Show all versions of com.liferay.frontend.js.minifier
Liferay Frontend JS Minifier
/*
* 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();
}
}