use of com.google.javascript.rhino.Token in project closure-compiler by google.
the class Denormalize method maybeCollapseLogicalAssignShorthand.
private void maybeCollapseLogicalAssignShorthand(NodeTraversal t, Node n, Node parent) {
if (!isCollapsableLogicalAssign(n)) {
return;
}
Node op = n.getLastChild();
Token assignOp = getAssignOpFromOp(n);
if (n.getFirstChild().getString().equals(op.getFirstChild().getString())) {
op.setToken(assignOp);
Node opDetached = op.detach();
opDetached.setJSDocInfo(n.getJSDocInfo());
n.replaceWith(opDetached);
NodeUtil.addFeatureToScript(t.getCurrentScript(), Feature.LOGICAL_ASSIGNMENT, compiler);
compiler.reportChangeToEnclosingScope(parent);
}
}
use of com.google.javascript.rhino.Token in project closure-compiler by google.
the class NodeIteratorsTest method testVarMotionWithCode.
/**
* @see #testVarMotionWithCode(String, Token ...)
*/
private void testVarMotionWithCode(String code, List<Token> expectedTokens) {
List<Node> ancestors = new ArrayList<>();
// Add an empty node to the beginning of the code and start there.
Compiler compiler = new Compiler();
Node root = compiler.parseTestCode(";" + code);
for (Node n = root; n != null; n = n.getFirstChild()) {
ancestors.add(0, n);
}
FunctionlessLocalScope searchIt = new FunctionlessLocalScope(ancestors.toArray(new Node[0]));
boolean found = false;
while (searchIt.hasNext()) {
Node n = searchIt.next();
if (n.isName() && NodeUtil.isNameDeclaration(searchIt.currentParent()) && n.getString().equals("X")) {
found = true;
break;
}
}
assertWithMessage("Variable X not found! " + root.toStringTree()).that(found).isTrue();
List<Node> currentAncestors = searchIt.currentAncestors();
assertThat(currentAncestors.size()).isAtLeast(3);
Iterator<Node> moveIt = LocalVarMotion.forVar(compiler, currentAncestors.get(0), currentAncestors.get(1), currentAncestors.get(2));
List<Token> actualTokens = new ArrayList<>();
while (moveIt.hasNext()) {
actualTokens.add(moveIt.next().getToken());
}
assertThat(actualTokens).isEqualTo(expectedTokens);
}
use of com.google.javascript.rhino.Token in project closure-compiler by google.
the class InferConsts method isInferredConst.
private static boolean isInferredConst(Var v, ReferenceCollection refCollection) {
Node nameNode = v.getNameNode();
if (nameNode == null || refCollection == null || !refCollection.isAssignedOnceInLifetime()) {
return false;
}
if (v.isImplicitGoogNamespace()) {
return false;
}
Token declarationType = v.declarationType();
switch(declarationType) {
case LET:
// Check that non-destructuring let names are actually assigned at declaration.
return !nameNode.getParent().isLet() || nameNode.hasChildren();
case CONST:
case CATCH:
case CLASS:
// Parameters cannot be referenced before declaration.
case PARAM_LIST:
case // Function hoisting means no references before declaration.
FUNCTION:
return true;
case IMPORT:
// TODO(lharker): make this check smarter if we start optimizing unrewritten modules.
return false;
case VAR:
// reference.
return refCollection.firstReferenceIsAssigningDeclaration() && refCollection.isWellDefined();
default:
throw new IllegalStateException("Unrecognized declaration type " + declarationType);
}
}
use of com.google.javascript.rhino.Token in project closure-compiler by google.
the class RemoveUnusedCode method traverseNode.
/**
* Traverses everything in the current scope and marks variables that are referenced.
*
* <p>During traversal, we identify subtrees that will only be referenced if their enclosing
* variables are referenced. Instead of traversing those subtrees, we create a continuation for
* them, and traverse them lazily.
*/
private void traverseNode(Node n, Scope scope) {
Node parent = n.getParent();
Token type = n.getToken();
switch(type) {
case CATCH:
traverseCatch(n, scope);
break;
case FUNCTION:
{
VarInfo varInfo = null;
// for it instead of traversing immediately.
if (NodeUtil.isFunctionDeclaration(n)) {
varInfo = traverseNameNode(n.getFirstChild(), scope);
FunctionDeclaration functionDeclaration = new RemovableBuilder().addContinuation(new Continuation(n, scope)).buildFunctionDeclaration(n);
varInfo.addRemovable(functionDeclaration);
if (parent.isExport()) {
varInfo.setIsExplicitlyNotRemovable();
}
} else {
traverseFunction(n, scope);
}
}
break;
case ASSIGN:
traverseAssign(n, scope);
break;
case ASSIGN_BITOR:
case ASSIGN_BITXOR:
case ASSIGN_BITAND:
case ASSIGN_LSH:
case ASSIGN_RSH:
case ASSIGN_URSH:
case ASSIGN_ADD:
case ASSIGN_SUB:
case ASSIGN_MUL:
case ASSIGN_EXPONENT:
case ASSIGN_DIV:
case ASSIGN_MOD:
traverseCompoundAssign(n, scope);
break;
case INC:
case DEC:
traverseIncrementOrDecrementOp(n, scope);
break;
case CALL:
case OPTCHAIN_CALL:
traverseCall(n, scope);
break;
case SWITCH:
case BLOCK:
// This case if for if there are let and const variables in block scopes.
// Otherwise other variables will be hoisted up into the global scope and already be
// handled.
traverseChildren(n, NodeUtil.createsBlockScope(n) ? scopeCreator.createScope(n, scope) : scope);
break;
case MODULE_BODY:
traverseChildren(n, scopeCreator.createScope(n, scope));
break;
case CLASS:
traverseClass(n, scope);
break;
case CLASS_MEMBERS:
traverseClassMembers(n, scope);
break;
case ARRAY_PATTERN:
case PARAM_LIST:
traverseIndirectAssignmentList(n, scope);
break;
case OBJECT_PATTERN:
traverseObjectPattern(n, scope);
break;
case OBJECTLIT:
traverseObjectLiteral(n, scope);
break;
case FOR:
traverseVanillaFor(n, scope);
break;
case FOR_IN:
case FOR_OF:
case FOR_AWAIT_OF:
traverseEnhancedFor(n, scope);
break;
case LET:
case CONST:
case VAR:
// for-loop cases are handled by custom traversal methods.
checkState(NodeUtil.isStatement(n));
traverseDeclarationStatement(n, scope);
break;
case INSTANCEOF:
traverseInstanceof(n, scope);
break;
case NAME:
// The only cases that should reach this point are parameter declarations and references
// to names. The name node does not have children in these cases.
checkState(!n.hasChildren());
// the parameter declaration is not a read of the name
if (!parent.isParamList()) {
// var|let|const name;
// are handled at a higher level.
checkState(!NodeUtil.isNameDeclaration(parent));
// function name() {}
// class name() {}
// handled at a higher level
checkState(!((parent.isFunction() || parent.isClass()) && parent.getFirstChild() == n));
traverseNameNode(n, scope).setIsExplicitlyNotRemovable();
}
break;
case GETPROP:
case OPTCHAIN_GETPROP:
traverseNormalOrOptChainGetProp(n, scope);
break;
default:
traverseChildren(n, scope);
break;
}
}
use of com.google.javascript.rhino.Token in project closure-compiler by google.
the class CheckGlobalThis method shouldTraverse.
/**
* Since this pass reports errors only when a global {@code this} keyword
* is encountered, there is no reason to traverse non global contexts.
*/
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
if (n.isFunction()) {
// is the global "this", not an instance of Foo.
if (n.isArrowFunction()) {
return true;
}
// Don't traverse functions that are constructors or have the @this
// or @override annotation.
JSDocInfo jsDoc = NodeUtil.getBestJSDocInfo(n);
if (jsDoc != null && (jsDoc.isConstructor() || jsDoc.isInterface() || jsDoc.hasThisType() || jsDoc.isOverride())) {
return false;
}
if (jsDoc != null) {
JSTypeExpression functionType = jsDoc.getType();
if (functionType != null) {
Node functionNode = functionType.getRoot();
if (functionNode != null && functionNode.isFunction()) {
// function(this: ThisType, ...)
// `this:` is only allowed as the very first child of the
// FUNCTION node.
Node thisNode = functionNode.getFirstChild();
if (thisNode != null && thisNode.isThis()) {
// Type of `this` is specified, so no need to check further.
return false;
}
}
}
}
// Don't traverse functions unless they would normally
// be able to have a @this annotation associated with them. e.g.,
// var a = function() { }; // or
// function a() {} // or
// a.x = function() {}; // or
// var a = {x: function() {}};
Token pType = parent.getToken();
if (!(pType == Token.BLOCK || pType == Token.SCRIPT || pType == Token.NAME || pType == Token.ASSIGN || // object literal keys
pType == Token.STRING_KEY)) {
return false;
}
// Don't traverse functions that are getting lent to a prototype.
Node grandparent = parent.getParent();
if (NodeUtil.mayBeObjectLitKey(parent)) {
JSDocInfo maybeLends = grandparent.getJSDocInfo();
if (maybeLends != null && maybeLends.hasLendsName() && maybeLends.getLendsName().getRoot().getString().endsWith(".prototype")) {
return false;
}
}
}
if (parent != null && parent.isAssign()) {
Node lhs = parent.getFirstChild();
if (n == lhs) {
// assignLhsChild should not be overridden.
if (assignLhsChild == null) {
assignLhsChild = lhs;
}
} else {
// property or subproperty.
if (NodeUtil.isNormalGet(lhs)) {
if (lhs.isGetProp() && lhs.getString().equals("prototype")) {
return false;
}
Node llhs = lhs.getFirstChild();
if (llhs.isGetProp() && llhs.getString().equals("prototype")) {
return false;
}
}
}
}
return true;
}
Aggregations