Skip to content

Commit

Permalink
Make sure we never create a scope rooted at a node which can't be a s…
Browse files Browse the repository at this point in the history
…cope root.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=152698151
  • Loading branch information
tbreisacher authored and brad4d committed Apr 10, 2017
1 parent 7d0ea79 commit 8315486
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 15 deletions.
14 changes: 9 additions & 5 deletions src/com/google/javascript/jscomp/NodeUtil.java
Expand Up @@ -2543,14 +2543,18 @@ public boolean apply(Node n) {
} }
}; };


static boolean createsScope(Node n) {
return createsBlockScope(n) || n.isFunction() || n.isModuleBody()
// The ROOT nodes that are the root of the externs tree or main JS tree do not
// create scopes. The parent of those two, which is the root of the entire AST and
// therefore has no parent, is the only ROOT node that creates a scope.
|| (n.isRoot() && n.getParent() == null);
}

static final Predicate<Node> createsScope = new Predicate<Node>() { static final Predicate<Node> createsScope = new Predicate<Node>() {
@Override @Override
public boolean apply(Node n) { public boolean apply(Node n) {
return createsBlockScope(n) || n.isFunction() || n.isModuleBody() return createsScope(n);
// The ROOT nodes that are the root of the externs tree or main JS tree do not
// create scopes. The parent of those two, which is the root of the entire AST and
// therefore has no parent, is the only ROOT node that creates a scope.
|| (n.isRoot() && n.getParent() == null);
} }
}; };


Expand Down
16 changes: 14 additions & 2 deletions src/com/google/javascript/jscomp/Scope.java
Expand Up @@ -47,7 +47,13 @@ public class Scope implements StaticScope {
*/ */
Scope(Scope parent, Node rootNode) { Scope(Scope parent, Node rootNode) {
Preconditions.checkNotNull(parent); Preconditions.checkNotNull(parent);
Preconditions.checkNotNull(rootNode); // TODO(tbreisacher): Can we tighten this to just NodeUtil.createsScope?
Preconditions.checkState(
NodeUtil.createsScope(rootNode)
|| rootNode.isScript()
|| rootNode.isRoot()
|| rootNode.isNormalBlock(),
rootNode);
Preconditions.checkArgument( Preconditions.checkArgument(
rootNode != parent.rootNode, "rootNode should not be the parent's root node", rootNode); rootNode != parent.rootNode, "rootNode should not be the parent's root node", rootNode);


Expand All @@ -57,7 +63,13 @@ public class Scope implements StaticScope {
} }


protected Scope(Node rootNode) { protected Scope(Node rootNode) {
Preconditions.checkNotNull(rootNode); // TODO(tbreisacher): Can we tighten this to just NodeUtil.createsScope?
Preconditions.checkState(
NodeUtil.createsScope(rootNode)
|| rootNode.isScript()
|| rootNode.isRoot()
|| rootNode.isNormalBlock(),
rootNode);
this.parent = null; this.parent = null;
this.rootNode = rootNode; this.rootNode = rootNode;
this.depth = 0; this.depth = 0;
Expand Down
16 changes: 8 additions & 8 deletions test/com/google/javascript/jscomp/MemoizedScopeCreatorTest.java
Expand Up @@ -30,30 +30,30 @@
public final class MemoizedScopeCreatorTest extends TestCase { public final class MemoizedScopeCreatorTest extends TestCase {


public void testMemoization() throws Exception { public void testMemoization() throws Exception {
Node trueNode = new Node(Token.TRUE); Node block1 = new Node(Token.BLOCK);
Node falseNode = new Node(Token.FALSE); Node block2 = new Node(Token.BLOCK);
// Wow, is there really a circular dependency between JSCompiler and // Wow, is there really a circular dependency between JSCompiler and
// SyntacticScopeCreator? // SyntacticScopeCreator?
Compiler compiler = new Compiler(); Compiler compiler = new Compiler();
compiler.initOptions(new CompilerOptions()); compiler.initOptions(new CompilerOptions());
ScopeCreator creator = new MemoizedScopeCreator( ScopeCreator creator = new MemoizedScopeCreator(
SyntacticScopeCreator.makeTyped(compiler)); SyntacticScopeCreator.makeTyped(compiler));
Scope scopeA = creator.createScope(trueNode, null); Scope scopeA = creator.createScope(block1, null);
assertSame(scopeA, creator.createScope(trueNode, null)); assertSame(scopeA, creator.createScope(block1, null));
assertNotSame(scopeA, creator.createScope(falseNode, null)); assertNotSame(scopeA, creator.createScope(block2, null));
} }


public void testPreconditionCheck() throws Exception { public void testPreconditionCheck() throws Exception {
Compiler compiler = new Compiler(); Compiler compiler = new Compiler();
compiler.initOptions(new CompilerOptions()); compiler.initOptions(new CompilerOptions());
Node trueNode = new Node(Token.TRUE); Node block = new Node(Token.BLOCK);
ScopeCreator creator = new MemoizedScopeCreator( ScopeCreator creator = new MemoizedScopeCreator(
SyntacticScopeCreator.makeTyped(compiler)); SyntacticScopeCreator.makeTyped(compiler));
Scope scopeA = creator.createScope(trueNode, null); Scope scopeA = creator.createScope(block, null);


boolean handled = false; boolean handled = false;
try { try {
creator.createScope(trueNode, scopeA); creator.createScope(block, scopeA);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
handled = true; handled = true;
} }
Expand Down

0 comments on commit 8315486

Please sign in to comment.