/* * Copyright 2014 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.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.truth.Truth.assertThat; import static com.google.javascript.jscomp.CompilerTestCase.LINE_JOINER; import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; import com.google.javascript.jscomp.CompilerOptions.LanguageMode; import com.google.javascript.jscomp.SyntacticScopeCreator.RedeclarationHandler; import com.google.javascript.rhino.Node; import junit.framework.TestCase; /** * Tests for {@link Es6SyntacticScopeCreator}. * * @author moz@google.com (Michael Zhou) */ public final class Es6SyntacticScopeCreatorTest extends TestCase { private Compiler compiler; private Es6SyntacticScopeCreator scopeCreator; private Multiset<String> redeclarations; private class RecordingRedeclarationHandler implements RedeclarationHandler { @Override public void onRedeclaration(Scope s, String name, Node n, CompilerInput input) { redeclarations.add(name); } } private Node getRoot(String js) { Node root = compiler.parseTestCode(js); assertThat(compiler.getErrors()).isEmpty(); return root; } /** * Helper to create a top-level scope from a JavaScript string */ private Scope getScope(String js) { return scopeCreator.createScope(getRoot(js), null); } @Override protected void setUp() { compiler = new Compiler(); CompilerOptions options = new CompilerOptions(); options.setLanguageIn(LanguageMode.ECMASCRIPT_2015); compiler.initOptions(options); redeclarations = HashMultiset.create(); RedeclarationHandler handler = new RecordingRedeclarationHandler(); scopeCreator = new Es6SyntacticScopeCreator(compiler, handler); } public void testVarRedeclaration1() { getScope("var x; var x"); assertThat(redeclarations).hasCount("x", 1); } public void testVarRedeclaration2() { getScope("var x; var x; var x;"); assertThat(redeclarations).hasCount("x", 2); } public void testVarRedeclaration3() { String js = "var x; if (true) { var x; } var x;"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node block = root .getFirstChild() // VAR .getNext() // IF .getLastChild(); // BLOCK checkState(block.isNormalBlock(), block); scopeCreator.createScope(block, globalScope); assertThat(redeclarations).hasCount("x", 2); } public void testVarRedeclaration4() { String js = "var x; if (true) { var x; var x; }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node block = root .getFirstChild() // VAR .getNext() // IF .getLastChild(); // BLOCK checkState(block.isNormalBlock(), block); scopeCreator.createScope(block, globalScope); assertThat(redeclarations).hasCount("x", 2); } public void testVarRedeclaration5() { String js = "if (true) { var x; var x; }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node block = root .getFirstChild() // IF .getLastChild(); // BLOCK checkState(block.isNormalBlock(), block); scopeCreator.createScope(block, globalScope); assertThat(redeclarations).hasCount("x", 1); } public void testLetRedeclaration1() { getScope("let x; let x"); assertThat(redeclarations).hasCount("x", 1); } public void testLetRedeclaration2() { getScope("let x; let x; let x;"); assertThat(redeclarations).hasCount("x", 2); } public void testLetRedeclaration3() { String js = "let x; if (true) { let x; } let x;"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node block = root .getFirstChild() // VAR .getNext() // IF .getLastChild(); // BLOCK checkState(block.isNormalBlock(), block); scopeCreator.createScope(block, globalScope); assertThat(redeclarations).hasCount("x", 1); } public void testLetRedeclaration4() { String js = "let x; if (true) { let x; let x; }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node block = root .getFirstChild() // VAR .getNext() // IF .getLastChild(); // BLOCK checkState(block.isNormalBlock(), block); scopeCreator.createScope(block, globalScope); assertThat(redeclarations).hasCount("x", 1); } public void testLetRedeclaration5() { String js = "if (true) { let x; let x; }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node block = root .getFirstChild() // IF .getLastChild(); // BLOCK checkState(block.isNormalBlock(), block); scopeCreator.createScope(block, globalScope); assertThat(redeclarations).hasCount("x", 1); } public void testArrayDestructuring() { Scope scope = getScope("var [x, y] = foo();"); assertTrue(scope.isDeclared("x", false)); assertTrue(scope.isDeclared("y", false)); } public void testNestedArrayDestructuring() { Scope scope = getScope("var [x, [y,z]] = foo();"); assertTrue(scope.isDeclared("x", false)); assertTrue(scope.isDeclared("y", false)); assertTrue(scope.isDeclared("z", false)); } public void testArrayDestructuringWithName() { Scope scope = getScope("var a = 1, [x, y] = foo();"); assertTrue(scope.isDeclared("a", false)); assertTrue(scope.isDeclared("x", false)); assertTrue(scope.isDeclared("y", false)); } public void testArrayDestructuringLet() { String js = "" + "function foo() {\n" + " var [a, b] = getVars();" + " if (true) {" + " let [x, y] = getLets();" + " }" + "}"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node functionNode = root.getFirstChild(); Scope functionScope = scopeCreator.createScope(functionNode, globalScope); Node functionBlock = functionNode.getLastChild(); Scope functionBlockScope = scopeCreator.createScope(functionBlock, functionScope); assertTrue(functionBlockScope.isDeclared("a", false)); assertTrue(functionBlockScope.isDeclared("b", false)); assertFalse(functionBlockScope.isDeclared("x", false)); assertFalse(functionBlockScope.isDeclared("y", false)); Node var = functionBlock.getFirstChild(); Node ifStmt = var.getNext(); Node ifBlock = ifStmt.getLastChild(); Scope blockScope = scopeCreator.createScope(ifBlock, functionBlockScope); // a and b are declared in the parent scope. assertFalse(blockScope.isDeclared("a", false)); assertFalse(blockScope.isDeclared("b", false)); assertTrue(blockScope.isDeclared("a", true)); assertTrue(blockScope.isDeclared("b", true)); // x and y are declared in this scope. assertTrue(blockScope.isDeclared("x", false)); assertTrue(blockScope.isDeclared("y", false)); } public void testArrayDestructuringVarInBlock() { String js = "" + "function foo() {\n" + " var [a, b] = getVars();" + " if (true) {" + " var [x, y] = getMoreVars();" + " }" + "}"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node functionNode = root.getFirstChild(); Scope functionScope = scopeCreator.createScope(functionNode, globalScope); Node functionBlock = functionNode.getLastChild(); Scope functionBlockScope = scopeCreator.createScope(functionBlock, functionScope); assertTrue(functionBlockScope.isDeclared("a", false)); assertTrue(functionBlockScope.isDeclared("b", false)); assertTrue(functionBlockScope.isDeclared("x", false)); assertTrue(functionBlockScope.isDeclared("y", false)); } public void testObjectDestructuring() { String js = LINE_JOINER.join( "function foo() {", " var {a, b} = bar();", "}"); Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node functionNode = root.getFirstChild(); Scope functionScope = scopeCreator.createScope(functionNode, globalScope); Node functionBlock = functionNode.getLastChild(); Scope functionBlockScope = scopeCreator.createScope(functionBlock, functionScope); assertTrue(functionBlockScope.isDeclared("a", false)); assertTrue(functionBlockScope.isDeclared("b", false)); } public void testObjectDestructuring2() { String js = LINE_JOINER.join( "function foo() {", " var {a: b = 1} = bar();", "}"); Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node functionNode = root.getFirstChild(); Scope functionScope = scopeCreator.createScope(functionNode, globalScope); Node functionBlock = functionNode.getLastChild(); Scope functionBlockScope = scopeCreator.createScope(functionBlock, functionScope); assertFalse(functionBlockScope.isDeclared("a", false)); assertTrue(functionBlockScope.isDeclared("b", false)); } public void testObjectDestructuringComputedProp() { String js = LINE_JOINER.join( "function foo() {", " var {['s']: a} = bar();", "}"); Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node functionNode = root.getFirstChild(); Scope functionScope = scopeCreator.createScope(functionNode, globalScope); Node functionBlock = functionNode.getLastChild(); Scope functionBlockScope = scopeCreator.createScope(functionBlock, functionScope); assertTrue(functionBlockScope.isDeclared("a", false)); } public void testObjectDestructuringComputedPropParam() { String js = "function foo({['s']: a}) {}"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node functionNode = root.getFirstChild(); Scope functionScope = scopeCreator.createScope(functionNode, globalScope); assertTrue(functionScope.isDeclared("a", false)); } public void testObjectDestructuringNested() { String js = LINE_JOINER.join( "function foo() {", " var {a:{b}} = bar();", "}"); Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node functionNode = root.getFirstChild(); Scope functionScope = scopeCreator.createScope(functionNode, globalScope); Node functionBlock = functionNode.getLastChild(); Scope functionBlockScope = scopeCreator.createScope(functionBlock, functionScope); assertFalse(functionBlockScope.isDeclared("a", false)); assertTrue(functionBlockScope.isDeclared("b", false)); } public void testObjectDestructuringWithInitializer() { String js = LINE_JOINER.join( "function foo() {", " var {a=1} = bar();", "}"); Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node functionNode = root.getFirstChild(); Scope functionScope = scopeCreator.createScope(functionNode, globalScope); Node functionBlock = functionNode.getLastChild(); Scope functionBlockScope = scopeCreator.createScope(functionBlock, functionScope); assertTrue(functionBlockScope.isDeclared("a", false)); } public void testObjectDestructuringInForOfParam() { String js = "{for (let {length: x} of gen()) {}}"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node block = root.getFirstChild(); Scope blockScope = scopeCreator.createScope(block, globalScope); Node forOf = block.getFirstChild(); Scope forOfScope = scopeCreator.createScope(forOf, blockScope); assertTrue(forOfScope.isDeclared("x", false)); } public void testFunctionScope() { Scope scope = getScope("function foo() {}\n" + "var x = function bar(a1) {};" + "[function bar2() { var y; }];" + "if (true) { function z() {} }" ); assertTrue(scope.isDeclared("foo", false)); assertTrue(scope.isDeclared("x", false)); assertFalse(scope.isDeclared("z", false)); // The following should not be declared in this scope assertFalse(scope.isDeclared("a1", false)); assertFalse(scope.isDeclared("bar", false)); assertFalse(scope.isDeclared("bar2", false)); assertFalse(scope.isDeclared("y", false)); assertFalse(scope.isDeclared("", false)); } public void testClassScope() { Scope scope = getScope("class Foo {}\n" + "var x = class Bar {};" + "[class Bar2 { constructor(a1) {} static y() {} }];" + "if (true) { class Z {} }" ); assertTrue(scope.isDeclared("Foo", false)); assertTrue(scope.isDeclared("x", false)); assertFalse(scope.isDeclared("Z", false)); // The following should not be declared in this scope assertFalse(scope.isDeclared("a1", false)); assertFalse(scope.isDeclared("Bar", false)); assertFalse(scope.isDeclared("Bar2", false)); assertFalse(scope.isDeclared("y", false)); assertFalse(scope.isDeclared("", false)); } public void testScopeRootNode() { String js = "function foo() {\n" + " var x = 10;" + "}"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertEquals(root, globalScope.getRootNode()); assertFalse(globalScope.isBlockScope()); assertEquals(globalScope, globalScope.getClosestHoistScope()); assertTrue(globalScope.isHoistScope()); Node function = root.getFirstChild(); checkState(function.isFunction(), function); Scope functionScope = scopeCreator.createScope(function, globalScope); Node fooBlockNode = NodeUtil.getFunctionBody(function); Scope fooScope = scopeCreator.createScope(fooBlockNode, functionScope); assertEquals(fooBlockNode, fooScope.getRootNode()); assertTrue(fooScope.isBlockScope()); assertEquals(fooScope, fooScope.getClosestHoistScope()); assertTrue(fooScope.isHoistScope()); assertTrue(fooScope.isDeclared("x", false)); } public void testBlockScopeWithVar() { String js = "if (true) { if (true) { var x; } }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertTrue(globalScope.isDeclared("x", false)); Node firstLevelBlock = root.getFirstChild().getLastChild(); Scope firstLevelBlockScope = scopeCreator.createScope(firstLevelBlock, globalScope); assertFalse(firstLevelBlockScope.isDeclared("x", false)); Node secondLevelBlock = firstLevelBlock.getFirstChild().getLastChild(); Scope secondLevelBLockScope = scopeCreator.createScope(secondLevelBlock, firstLevelBlockScope); assertFalse(secondLevelBLockScope.isDeclared("x", false)); } public void testBlockScopeWithLet() { String js = "if (true) { if (true) { let x; } }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertFalse(globalScope.isDeclared("x", false)); Node firstLevelBlock = root.getFirstChild().getLastChild(); Scope firstLevelBlockScope = scopeCreator.createScope(firstLevelBlock, globalScope); assertFalse(firstLevelBlockScope.isDeclared("x", false)); Node secondLevelBlock = firstLevelBlock.getFirstChild().getLastChild(); Scope secondLevelBLockScope = scopeCreator.createScope(secondLevelBlock, firstLevelBlockScope); assertTrue(secondLevelBLockScope.isDeclared("x", false)); } public void testBlockScopeWithClass() { String js = "if (true) { if (true) { class X {} } }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertFalse(globalScope.isDeclared("X", false)); Node firstLevelBlock = root.getFirstChild().getLastChild(); Scope firstLevelBlockScope = scopeCreator.createScope(firstLevelBlock, globalScope); assertFalse(firstLevelBlockScope.isDeclared("X", false)); Node secondLevelBlock = firstLevelBlock.getFirstChild().getLastChild(); Scope secondLevelBLockScope = scopeCreator.createScope(secondLevelBlock, firstLevelBlockScope); assertTrue(secondLevelBLockScope.isDeclared("X", false)); } public void testForLoopScope() { String js = "for (let i = 0;;) { let x; }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertFalse(globalScope.isDeclared("i", false)); assertFalse(globalScope.isDeclared("x", false)); Node forNode = root.getFirstChild(); Scope forScope = scopeCreator.createScope(forNode, globalScope); assertTrue(forScope.isDeclared("i", false)); assertFalse(forScope.isDeclared("x", false)); Node forBlock = forNode.getLastChild(); Scope forBlockScope = scopeCreator.createScope(forBlock, forScope); assertFalse(forBlockScope.isDeclared("i", false)); assertTrue(forBlockScope.isDeclared("x", false)); } public void testForOfLoopScope() { String js = "for (let i of arr) { let x; }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertFalse(globalScope.isDeclared("i", false)); assertFalse(globalScope.isDeclared("x", false)); Node forNode = root.getFirstChild(); Scope forScope = scopeCreator.createScope(forNode, globalScope); assertTrue(forScope.isDeclared("i", false)); assertFalse(forScope.isDeclared("x", false)); Node forBlock = forNode.getLastChild(); Scope forBlockScope = scopeCreator.createScope(forBlock, forScope); assertFalse(forBlockScope.isDeclared("i", false)); assertTrue(forBlockScope.isDeclared("x", false)); } public void testFunctionArgument() { String js = "function f(x) { if (true) { let y = 3; } }"; Node root = getRoot(js); Scope global = scopeCreator.createScope(root, null); Node function = root.getLastChild(); checkState(function.isFunction(), function); Scope functionScope = scopeCreator.createScope(function, global); Node functionBlock = NodeUtil.getFunctionBody(function); Scope fBlockScope = scopeCreator.createScope(functionBlock, functionScope); assertTrue(fBlockScope.isDeclared("x", false)); assertFalse(fBlockScope.isDeclared("y", false)); Node ifBlock = functionBlock.getLastChild().getLastChild(); checkState(ifBlock.isNormalBlock(), ifBlock); Scope blockScope = scopeCreator.createScope(ifBlock, fBlockScope); assertFalse(blockScope.isDeclared("x", false)); assertTrue(blockScope.isDeclared("x", true)); assertTrue(blockScope.isDeclared("y", false)); } public void testTheArgumentsVariable() { String js = "function f() { if (true) { let arguments = 3; } }"; Node root = getRoot(js); Scope global = scopeCreator.createScope(root, null); Node function = root.getFirstChild(); checkState(function.isFunction(), function); Scope fScope = scopeCreator.createScope(function, global); Var arguments = fScope.getArgumentsVar(); assertThat(fScope.getVar("arguments")).isSameAs(arguments); Node fBlock = NodeUtil.getFunctionBody(function); Scope fBlockScope = scopeCreator.createScope(fBlock, fScope); assertThat(fBlockScope.getVar("arguments")).isSameAs(arguments); assertThat(fBlockScope.getArgumentsVar()).isSameAs(arguments); Node ifBlock = fBlock.getFirstChild().getLastChild(); Scope blockScope = scopeCreator.createScope(ifBlock, fBlockScope); assertTrue(blockScope.isDeclared("arguments", false)); assertThat(blockScope.getArgumentsVar()).isSameAs(arguments); assertThat(blockScope.getVar("arguments")).isNotEqualTo(arguments); } public void testArgumentsVariableInArrowFunction() { String js = "function outer() { var inner = () => { alert(0); } }"; Node root = getRoot(js); Scope global = scopeCreator.createScope(root, null); Node outer = root.getFirstChild(); checkState(outer.isFunction(), outer); checkState(!outer.isArrowFunction(), outer); Scope outerFunctionScope = scopeCreator.createScope(outer, global); Var arguments = outerFunctionScope.getArgumentsVar(); Node outerBody = NodeUtil.getFunctionBody(outer); Scope outerBodyScope = scopeCreator.createScope(outerBody, outerFunctionScope); Node inner = outerBody.getFirstChild() // VAR .getFirstChild() // NAME .getFirstChild(); // FUNCTION checkState(inner.isFunction(), inner); checkState(inner.isArrowFunction(), inner); Scope innerFunctionScope = scopeCreator.createScope(inner, outerBodyScope); assertThat(innerFunctionScope.getArgumentsVar()).isSameAs(arguments); } public void testIsFunctionBlockScoped() { String js = "if (true) { function f() {}; }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertFalse(globalScope.isDeclared("f", false)); Node ifBlock = root.getFirstChild().getLastChild(); Scope blockScope = scopeCreator.createScope(ifBlock, globalScope); assertTrue(blockScope.isDeclared("f", false)); } public void testIsClassBlockScoped() { String js = "if (true) { class X {}; }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertFalse(globalScope.isDeclared("X", false)); Node ifBlock = root.getFirstChild().getLastChild(); Scope blockScope = scopeCreator.createScope(ifBlock, globalScope); assertTrue(blockScope.isDeclared("X", false)); } public void testIsCatchBlockScoped() { String js = "try { var x = 2; } catch (e) { var y = 3; let z = 4; }"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertTrue(globalScope.isDeclared("x", false)); assertTrue(globalScope.isDeclared("y", false)); assertFalse(globalScope.isDeclared("z", false)); assertFalse(globalScope.isDeclared("e", false)); Node tryBlock = root.getFirstFirstChild(); Scope tryBlockScope = scopeCreator.createScope(tryBlock, globalScope); assertFalse(tryBlockScope.isDeclared("x", false)); assertFalse(tryBlockScope.isDeclared("y", false)); assertFalse(tryBlockScope.isDeclared("z", false)); assertFalse(tryBlockScope.isDeclared("e", false)); Node catchBlock = tryBlock.getNext(); Scope catchBlockScope = scopeCreator.createScope(catchBlock, tryBlockScope); assertFalse(catchBlockScope.isDeclared("x", false)); assertFalse(catchBlockScope.isDeclared("y", false)); assertTrue(catchBlockScope.isDeclared("z", false)); assertTrue(catchBlockScope.isDeclared("e", false)); } public void testVarAfterLet() { String js = LINE_JOINER.join( "function f() {", " if (a) {", " let x;", " }", " var y;", "}"); Node root = getRoot(js); Scope global = scopeCreator.createScope(root, null); Node function = root.getFirstChild(); Scope fScope = scopeCreator.createScope(function, global); Node fBlock = root.getFirstChild().getLastChild(); Scope fBlockScope = scopeCreator.createScope(fBlock, fScope); checkNotNull(fBlockScope); assertFalse(fBlockScope.isDeclared("x", false)); assertTrue(fBlockScope.isDeclared("y", false)); Node ifBlock = fBlock.getFirstChild().getLastChild(); Scope ifBlockScope = scopeCreator.createScope(ifBlock, fBlockScope); assertTrue(ifBlockScope.isDeclared("x", false)); assertFalse(ifBlockScope.isDeclared("y", false)); } public void testSimpleFunctionParam() { String js = "function f(x) {}"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); Node fNode = root.getFirstChild(); checkState(fNode.isFunction(), fNode); Scope fScope = scopeCreator.createScope(fNode, globalScope); assertTrue(fScope.isDeclared("x", false)); Node fBlock = NodeUtil.getFunctionBody(fNode); Scope fBlockScope = scopeCreator.createScope(fBlock, fScope); assertTrue(fBlockScope.isDeclared("x", false)); } public void testOnlyOneDeclaration() { String js = "function f(x) { if (!x) var x = 6; }"; Node root = getRoot(js); Node fNode = root.getFirstChild(); Scope globalScope = scopeCreator.createScope(root, null); Scope fScope = scopeCreator.createScope(fNode, globalScope); assertTrue(fScope.isDeclared("x", false)); Node fBlock = fNode.getLastChild(); Scope fBlockScope = scopeCreator.createScope(fBlock, fScope); assertTrue(fBlockScope.isDeclared("x", false)); Node ifBlock = fBlock.getFirstChild().getLastChild(); Scope ifBlockScope = scopeCreator.createScope(ifBlock, fBlockScope); assertFalse(ifBlockScope.isDeclared("x", false)); } public void testCatchInFunction() { String js = "function f(e) { try {} catch (e) {} }"; Node root = getRoot(js); Node fNode = root.getFirstChild(); Scope globalScope = scopeCreator.createScope(root, null); Scope fScope = scopeCreator.createScope(fNode, globalScope); assertTrue(fScope.isDeclared("e", false)); Node fBlock = fNode.getLastChild(); Scope fBlockScope = scopeCreator.createScope(fBlock, fScope); Node tryBlock = fBlock.getFirstFirstChild(); Scope tryScope = scopeCreator.createScope(tryBlock, fBlockScope); Node catchBlock = tryBlock.getNext(); Scope catchScope = scopeCreator.createScope(catchBlock, tryScope); assertTrue(catchScope.isDeclared("e", false)); } public void testFunctionName() { String js = "var f = function foo() {}"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertTrue(globalScope.isDeclared("f", false)); assertFalse(globalScope.isDeclared("foo", false)); Node fNode = root.getFirstChild().getFirstChild().getFirstChild(); Scope fScope = scopeCreator.createScope(fNode, globalScope); assertFalse(fScope.isDeclared("f", false)); assertTrue(fScope.isDeclared("foo", false)); } public void testClassName() { String js = "var Clazz = class Foo {}"; Node root = getRoot(js); Scope globalScope = scopeCreator.createScope(root, null); assertTrue(globalScope.isDeclared("Clazz", false)); assertFalse(globalScope.isDeclared("Foo", false)); Node classNode = root.getFirstChild().getFirstChild().getFirstChild(); Scope classScope = scopeCreator.createScope(classNode, globalScope); assertFalse(classScope.isDeclared("Clazz", false)); assertTrue(classScope.isDeclared("Foo", false)); } public void testFunctionExpressionInForLoopInitializer() { Node root = getRoot("for (function foo() {};;) {}"); Scope globalScope = scopeCreator.createScope(root, null); assertFalse(globalScope.isDeclared("foo", false)); Node forNode = root.getFirstChild(); Scope forScope = scopeCreator.createScope(forNode, globalScope); assertFalse(forScope.isDeclared("foo", false)); Node fNode = forNode.getFirstChild(); Scope fScope = scopeCreator.createScope(fNode, forScope); assertTrue(fScope.isDeclared("foo", false)); } public void testClassExpressionInForLoopInitializer() { Node root = getRoot("for (class Clazz {};;) {}"); Scope globalScope = scopeCreator.createScope(root, null); assertFalse(globalScope.isDeclared("Clazz", false)); Node forNode = root.getFirstChild(); Scope forScope = scopeCreator.createScope(forNode, globalScope); assertFalse(forScope.isDeclared("Clazz", false)); Node classNode = forNode.getFirstChild(); Scope classScope = scopeCreator.createScope(classNode, forScope); assertTrue(classScope.isDeclared("Clazz", false)); } public void testVarsInModulesNotGlobal() { Node root = getRoot("goog.module('example'); var x;"); Scope globalScope = scopeCreator.createScope(root, null); assertFalse(globalScope.isDeclared("x", false)); Node moduleBody = root.getFirstChild(); checkState(moduleBody.isModuleBody(), moduleBody); Scope moduleScope = scopeCreator.createScope(moduleBody, globalScope); assertTrue(moduleScope.isDeclared("x", false)); } }