/* * Copyright 2006 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 com.google.javascript.rhino.Node; /** * Tests for {@link NameAnalyzer} * */ public class NameAnalyzerTest extends CompilerTestCase { private static String kExterns = "var window, top;" + "var document;" + "var Function;" + "var Array;" + "var externfoo; methods.externfoo;"; public NameAnalyzerTest() { super(kExterns); } @Override protected void setUp() { super.enableNormalize(); super.enableLineNumberCheck(true); } @Override protected int getNumRepetitions() { // pass reaches steady state after 1 iteration. return 1; } public void testRemoveVarDeclaration1() { test("var foo = 3;", ""); } public void testRemoveVarDeclaration2() { test("var foo = 3, bar = 4; externfoo = foo;", "var foo = 3; externfoo = foo;"); } public void testRemoveVarDeclaration3() { test("var a = f(), b = 1, c = 2; b; c", "f();var b = 1, c = 2; b; c"); } public void testRemoveVarDeclaration4() { test("var a = 0, b = f(), c = 2; a; c", "var a = 0;f();var c = 2; a; c"); } public void testRemoveVarDeclaration5() { test("var a = 0, b = 1, c = f(); a; b", "var a = 0, b = 1; f(); a; b"); } public void testRemoveVarDeclaration6() { test("var a = 0, b = a = 1; a", "var a = 0; a = 1; a"); } public void testRemoveVarDeclaration7() { test("var a = 0, b = a = 1", ""); } public void testRemoveVarDeclaration8() { test("var a;var b = 0, c = a = b = 1", ""); } public void testRemoveDeclaration1() { test("var a;var b = 0, c = a = b = 1", ""); } public void testRemoveDeclaration2() { test("var a,b,c; c = a = b = 1", ""); } public void testRemoveDeclaration3() { test("var a,b,c; c = a = b = {}; a.x = 1;", ""); } public void testRemoveDeclaration4() { testSame("var a,b,c; c = a = b = {}; a.x = 1;alert(c.x);"); } public void testRemoveDeclaration5() { test("var a,b,c; c = a = b = null; use(b)", "var b;b=null;use(b)"); } public void testRemoveDeclaration6() { test("var a,b,c; c = a = b = 'str';use(b)", "var b;b='str';use(b)"); } public void testRemoveDeclaration7() { test("var a,b,c; c = a = b = true;use(b)", "var b;b=true;use(b)"); } public void testRemoveFunction1() { test("var foo = function(){};", ""); } public void testRemoveFunction2() { test("var foo; foo = function(){};", ""); } public void testRemoveFunction3() { test("var foo = {}; foo.bar = function() {};", ""); } public void testRemoveFunction4() { test("var a = {}; a.b = {}; a.b.c = function() {};", ""); } public void testReferredToByWindow() { testSame("var foo = {}; foo.bar = function() {}; window['fooz'] = foo.bar"); } public void testExtern() { testSame("externfoo = 5"); } public void testRemoveNamedFunction() { test("function foo(){}", ""); } public void testRemoveRecursiveFunction1() { test("function f(){f()}", ""); } public void testRemoveRecursiveFunction2() { test("var f = function (){f()}", ""); } public void testRemoveRecursiveFunction2a() { test("var f = function g(){g()}", ""); } public void testRemoveRecursiveFunction3() { test("var f;f = function (){f()}", ""); } public void testRemoveRecursiveFunction4() { // don't removed if name definition doesn't exist. testSame("f = function (){f()}"); } public void testRemoveRecursiveFunction5() { test("function g(){f()}function f(){g()}", ""); } public void testRemoveRecursiveFunction6() { test("var f=function(){g()};function g(){f()}", ""); } public void testRemoveRecursiveFunction7() { test("var g = function(){f()};var f = function(){g()}", ""); } public void testRemoveRecursiveFunction8() { test("var o = {};o.f = function(){o.f()}", ""); } public void testRemoveRecursiveFunction9() { testSame("var o = {};o.f = function(){o.f()};o.f()"); } public void testSideEffectClassification1() { test("foo();", "foo();"); } public void testSideEffectClassification2() { test("var a = foo();", "foo();"); } public void testSideEffectClassification3() { testSame("var a = foo();window['b']=a;"); } public void testSideEffectClassification4() { testSame("function sef(){} sef();"); } public void testSideEffectClassification5() { testSame("function nsef(){} var a = nsef();window['b']=a;"); } public void testSideEffectClassification6() { test("function sef(){} sef();", "function sef(){} sef();"); } public void testSideEffectClassification7() { testSame("function sef(){} var a = sef();window['b']=a;"); } public void testNoSideEffectAnnotation1() { test("function f(){} var a = f();", "function f(){} f()"); } public void testNoSideEffectAnnotation2() { test("/**@nosideeffects*/function f(){}", "var a = f();", "", null, null); } public void testNoSideEffectAnnotation3() { test("var f = function(){}; var a = f();", "var f = function(){}; f();"); } public void testNoSideEffectAnnotation4() { test("var f = /**@nosideeffects*/function(){};", "var a = f();", "", null, null); } public void testNoSideEffectAnnotation5() { test("var f; f = function(){}; var a = f();", "var f; f = function(){}; f();"); } public void testNoSideEffectAnnotation6() { test("var f; f = /**@nosideeffects*/function(){};", "var a = f();", "", null, null); } public void testNoSideEffectAnnotation7() { test("var f;" + "f = /**@nosideeffects*/function(){};", "f = function(){};" + "var a = f();", "f = function(){}; f();", null, null); } public void testNoSideEffectAnnotation8() { test("var f;" + "f = function(){};" + "f = /**@nosideeffects*/function(){};", "var a = f();", "f();", null, null); } public void testNoSideEffectAnnotation9() { test("var f;" + "f = /**@nosideeffects*/function(){};" + "f = /**@nosideeffects*/function(){};", "var a = f();", "", null, null); test("var f; f = /**@nosideeffects*/function(){};", "var a = f();", "", null, null); } public void testNoSideEffectAnnotation10() { test("var o = {}; o.f = function(){}; var a = o.f();", "var o = {}; o.f = function(){}; o.f();"); } public void testNoSideEffectAnnotation11() { test("var o = {}; o.f = /**@nosideeffects*/function(){};", "var a = o.f();", "", null, null); } public void testNoSideEffectAnnotation12() { test("function c(){} var a = new c", "function c(){} new c"); } public void testNoSideEffectAnnotation13() { test("/**@nosideeffects*/function c(){}", "var a = new c", "", null, null); } public void testNoSideEffectAnnotation14() { String common = "function c(){};" + "c.prototype.f = /**@nosideeffects*/function(){};"; test(common, "var o = new c; var a = o.f()", "new c", null, null); } public void testNoSideEffectAnnotation15() { test("function c(){}; c.prototype.f = function(){}; var a = (new c).f()", "function c(){}; c.prototype.f = function(){}; (new c).f()"); } public void testNoSideEffectAnnotation16() { test("/**@nosideeffects*/function c(){}" + "c.prototype.f = /**@nosideeffects*/function(){};", "var a = (new c).f()", "", null, null); } public void testFunctionPrototype() { testSame("var a = 5; Function.prototype.foo = function() {return a;}"); } public void testTopLevelClass1() { test("var Point = function() {}; Point.prototype.foo = function() {}", ""); } public void testTopLevelClass2() { testSame("var Point = {}; Point.prototype.foo = function() {};" + "externfoo = new Point()"); } public void testTopLevelClass3() { test("function Point() {this.me_ = Point}", ""); } public void testTopLevelClass4() { test("function f(){} function A(){} A.prototype = {x: function() {}}; f();", "function f(){} f();"); } public void testTopLevelClass5() { testSame("function f(){} function A(){}" + "A.prototype = {x: function() { f(); }}; new A();"); } public void testTopLevelClass6() { testSame("function f(){} function A(){}" + "A.prototype = {x: function() { f(); }}; new A().x();"); } public void testTopLevelClass7() { test("A.prototype.foo = function(){}; function A() {}", ""); } public void testNamespacedClass1() { test("var foo = {};foo.bar = {};foo.bar.prototype.baz = {}", ""); } public void testNamespacedClass2() { testSame("var foo = {};foo.bar = {};foo.bar.prototype.baz = {};" + "window.z = new foo.bar()"); } public void testNamespacedClass3() { test("var a = {}; a.b = function() {}; a.b.prototype = {x: function() {}};", ""); } public void testNamespacedClass4() { testSame("function f(){} var a = {}; a.b = function() {};" + "a.b.prototype = {x: function() { f(); }}; new a.b();"); } public void testNamespacedClass5() { testSame("function f(){} var a = {}; a.b = function() {};" + "a.b.prototype = {x: function() { f(); }}; new a.b().x();"); } public void testAssignmentToThisPrototype() { testSame("Function.prototype.inherits = function(parentCtor) {" + " function tempCtor() {};" + " tempCtor.prototype = parentCtor.prototype;" + " this.superClass_ = parentCtor.prototype;" + " this.prototype = new tempCtor();" + " this.prototype.constructor = this;" + "};"); } public void testAssignmentToCallResultPrototype() { testSame("function f() { return function(){}; } f().prototype = {};"); } public void testAssignmentToExternPrototype() { testSame("externfoo.prototype = {};"); } public void testAssignmentToUnknownPrototype() { testSame( "/** @suppress {duplicate} */ var window;" + "window['a'].prototype = {};"); } public void testBug2099540() { testSame( "/** @suppress {duplicate} */ var document;\n" + "/** @suppress {duplicate} */ var window;\n" + "var klass;\n" + "window[klass].prototype = " + "document.createElement(tagName)['__proto__'];"); } public void testOtherGlobal() { testSame("goog.global.foo = bar(); function bar(){}"); } public void testExternName1() { testSame("top.z = bar(); function bar(){}"); } public void testExternName2() { testSame("top['z'] = bar(); function bar(){}"); } public void testInherits1() { test("var a = {}; var b = {}; b.inherits(a)", ""); } public void testInherits2() { test("var a = {}; var b = {}; var goog = {}; goog.inherits(b, a)", ""); } public void testInherits3() { testSame("var a = {}; this.b = {}; b.inherits(a);"); } public void testInherits4() { testSame("var a = {}; this.b = {}; var goog = {}; goog.inherits(b, a);"); } public void testInherits5() { test("this.a = {}; var b = {}; b.inherits(a);", "this.a = {}"); } public void testInherits6() { test("this.a = {}; var b = {}; var goog = {}; goog.inherits(b, a);", "this.a = {}"); } public void testInherits7() { testSame("var a = {}; this.b = {}; var goog = {};" + " goog.inherits = function() {}; goog.inherits(b, a);"); } public void testInherits8() { // Make sure that exceptions aren't thrown if inherits() is used as // an R-value test("this.a = {}; var b = {}; var c = b.inherits(a);", "this.a = {};"); } public void testMixin1() { testSame("var goog = {}; goog.mixin = function() {};" + "Function.prototype.mixin = function(base) {" + " goog.mixin(this.prototype, base); " + "};"); } public void testMixin2() { testSame("var a = {}; this.b = {}; var goog = {};" + " goog.mixin = function() {}; goog.mixin(b.prototype, a.prototype);"); } public void testMixin3() { test("this.a = {}; var b = {}; var goog = {};" + " goog.mixin = function() {}; goog.mixin(b.prototype, a.prototype);", "this.a = {};"); } public void testMixin4() { testSame("this.a = {}; var b = {}; var goog = {};" + "goog.mixin = function() {};" + "goog.mixin(b.prototype, a.prototype);" + "new b()"); } public void testMixin5() { test("this.a = {}; var b = {}; var c = {}; var goog = {};" + "goog.mixin = function() {};" + "goog.mixin(b.prototype, a.prototype);" + "goog.mixin(c.prototype, a.prototype);" + "new b()", "this.a = {}; var b = {}; var goog = {};" + "goog.mixin = function() {};" + "goog.mixin(b.prototype, a.prototype);" + "new b()"); } public void testMixin6() { testSame("this.a = {}; var b = {}; var c = {}; var goog = {};" + "goog.mixin = function() {};" + "goog.mixin(c.prototype, a.prototype) + " + "goog.mixin(b.prototype, a.prototype);" + "new b()"); } public void testMixin7() { test("this.a = {}; var b = {}; var c = {}; var goog = {};" + "goog.mixin = function() {};" + "var d = goog.mixin(c.prototype, a.prototype) + " + "goog.mixin(b.prototype, a.prototype);" + "new b()", "this.a = {}; var b = {}; var goog = {};" + "goog.mixin = function() {};" + "goog.mixin(b.prototype, a.prototype);" + "new b()"); } public void testConstants1() { testSame("var bar = function(){}; var EXP_FOO = true; if (EXP_FOO) bar();"); } public void testConstants2() { test("var bar = function(){}; var EXP_FOO = true; var EXP_BAR = true;" + "if (EXP_FOO) bar();", "var bar = function(){}; var EXP_FOO = true; if (EXP_FOO) bar();"); } public void testExpressions1() { test("var foo={}; foo.A='A'; foo.AB=foo.A+'B'; foo.ABC=foo.AB+'C'", ""); } public void testExpressions2() { testSame("var foo={}; foo.A='A'; foo.AB=foo.A+'B'; this.ABC=foo.AB+'C'"); } public void testExpressions3() { testSame("var foo = 2; window.bar(foo + 3)"); } public void testSetCreatingReference() { testSame("var foo; var bar = function(){foo=6;}; bar();"); } public void testAnonymous1() { testSame("function foo() {}; function bar() {}; foo(function() {bar()})"); } public void testAnonymous2() { test("var foo;(function(){foo=6;})()", "(function(){})()"); } public void testAnonymous3() { testSame("var foo; (function(){ if(!foo)foo=6; })()"); } public void testAnonymous4() { testSame("var foo; (function(){ foo=6; })(); externfoo=foo;"); } public void testAnonymous5() { testSame("var foo;" + "(function(){ foo=function(){ bar() }; function bar(){} })();" + "foo();"); } public void testAnonymous6() { testSame("function foo(){}" + "function bar(){}" + "foo(function(){externfoo = bar});"); } public void testAnonymous7() { testSame("var foo;" + "(function (){ function bar(){ externfoo = foo; } bar(); })();"); } public void testAnonymous8() { testSame("var foo;" + "(function (){ var g=function(){ externfoo = foo; }; g(); })();"); } public void testAnonymous9() { testSame("function foo(){}" + "function bar(){}" + "foo(function(){ function baz(){ externfoo = bar; } baz(); });"); } public void testFunctions1() { testSame("var foo = null; function baz() {}" + "function bar() {foo=baz();} bar();"); } public void testFunctions2() { testSame("var foo; foo = function() {var a = bar()};" + "var bar = function(){}; foo();"); } public void testGetElem1() { testSame("var foo = {}; foo.bar = {}; foo.bar.baz = {a: 5, b: 10};" + "var fn = function() {window[foo.bar.baz.a] = 5;}; fn()"); } public void testGetElem2() { testSame("var foo = {}; foo.bar = {}; foo.bar.baz = {a: 5, b: 10};" + "var fn = function() {this[foo.bar.baz.a] = 5;}; fn()"); } public void testGetElem3() { testSame("var foo = {'i': 0, 'j': 1}; foo['k'] = 2; top.foo = foo;"); } public void testIf1() { test("var foo = {};if(e)foo.bar=function(){};", "if(e);"); } public void testIf2() { test("var e = false;var foo = {};if(e)foo.bar=function(){};", "var e = false;if(e);"); } public void testIf3() { test("var e = false;var foo = {};if(e + 1)foo.bar=function(){};", "var e = false;if(e + 1);"); } public void testIf4() { test("var e = false, f;var foo = {};if(f=e)foo.bar=function(){};", "var e = false;if(e);"); } public void testIf4a() { // TODO(johnlenz): fix this. testSame("var e = [], f;if(f=e);f[0] = 1;"); } public void testIf4b() { // TODO(johnlenz): fix this. test("var e = [], f;if(e=f);f[0] = 1;", "var f;if(f);f[0] = 1;"); } public void testIf4c() { test("var e = [], f;if(f=e);e[0] = 1;", "var e = [];if(e);e[0] = 1;"); } public void testIf5() { test("var e = false, f;var foo = {};if(f = e + 1)foo.bar=function(){};", "var e = false;if(e + 1);"); } public void testIfElse() { test("var foo = {};if(e)foo.bar=function(){};else foo.bar=function(){};", "if(e);else;"); } public void testWhile() { test("var foo = {};while(e)foo.bar=function(){};", "while(e);"); } public void testFor() { test("var foo = {};for(e in x)foo.bar=function(){};", "for(e in x);"); } public void testDo() { test("var cond = false;do {var a = 1} while (cond)", "var cond = false;do {} while (cond)"); } public void testSetterInForStruct1() { test("var j = 0; for (var i = 1; i = 0; j++);", "var j = 0; for (; 0; j++);"); } public void testSetterInForStruct2() { test("var Class = function() {}; " + "for (var i = 1; Class.prototype.property_ = 0; i++);", "for (var i = 1; 0; i++);"); } public void testSetterInForStruct3() { test("var j = 0; for (var i = 1 + f() + g() + h(); i = 0; j++);", "var j = 0; f(); g(); h(); for (; 0; j++);"); } public void testSetterInForStruct4() { test("var i = 0;var j = 0; for (i = 1 + f() + g() + h(); i = 0; j++);", "var j = 0; f(); g(); h(); for (; 0; j++);"); } public void testSetterInForStruct5() { test("var i = 0, j = 0; for (i = f(), j = g(); 0;);", "for (f(), g(); 0;);"); } public void testSetterInForStruct6() { test("var i = 0, j = 0, k = 0; for (i = f(), j = g(), k = h(); i = 0;);", "for (f(), g(), h(); 0;);"); } public void testSetterInForStruct7() { test("var i = 0, j = 0, k = 0; for (i = 1, j = 2, k = 3; i = 0;);", "for (1, 2, 3; 0;);"); } public void testSetterInForStruct8() { test("var i = 0, j = 0, k = 0; for (i = 1, j = i, k = 2; i = 0;);", "var i = 0; for(i = 1, i , 2; i = 0;);"); } public void testSetterInForStruct9() { test("var Class = function() {}; " + "for (var i = 1; Class.property_ = 0; i++);", "for (var i = 1; 0; i++);"); } public void testSetterInForStruct10() { test("var Class = function() {}; " + "for (var i = 1; Class.property_ = 0; i = 2);", "for (; 0;);"); } public void testSetterInForStruct11() { test("var Class = function() {}; " + "for (;Class.property_ = 0;);", "for (;0;);"); } public void testSetterInForStruct12() { test("var a = 1; var Class = function() {}; " + "for (;Class.property_ = a;);", "var a = 1; for (; a;);"); } public void testSetterInForStruct13() { test("var a = 1; var Class = function() {}; " + "for (Class.property_ = a; 0 ;);", "for (; 0;);"); } public void testSetterInForStruct14() { test("var a = 1; var Class = function() {}; " + "for (; 0; Class.property_ = a);", "for (; 0;);"); } public void testSetterInForStruct15() { test("var Class = function() {}; " + "for (var i = 1; 0; Class.prototype.property_ = 0);", "for (; 0; 0);"); } public void testSetterInForStruct16() { test("var Class = function() {}; " + "for (var i = 1; i = 0; Class.prototype.property_ = 0);", "for (; 0; 0);"); } public void testSetterInForIn1() { test("var foo = {}; var bar; for(e in bar = foo.a);", "var foo = {}; for(e in foo.a);"); } public void testSetterInForIn2() { testSame("var foo = {}; var bar; for(e in bar = foo.a); bar"); } public void testSetterInForIn3() { testSame("var foo = {}; var bar; for(e in bar = foo.a); bar.b = 3"); } public void testSetterInForIn4() { testSame("var foo = {}; var bar; for (e in bar = foo.a); bar.b = 3; foo.a"); } public void testSetterInForIn5() { // TODO(user) Fix issue similar to b/2316773: bar should be preserved // but isn't due to missing references between e and foo.a test("var foo = {}; var bar; for (e in foo.a) { bar = e } bar.b = 3; foo.a", "var foo={};for(e in foo.a);foo.a"); } public void testSetterInForIn6() { testSame("var foo = {};for(e in foo);"); } public void testSetterInIfPredicate() { // TODO(user) Make NameAnalyzer smarter so it can remove "Class". testSame("var a = 1;" + "var Class = function() {}; " + "if (Class.property_ = a);"); } public void testSetterInWhilePredicate() { test("var a = 1;" + "var Class = function() {}; " + "while (Class.property_ = a);", "var a = 1; for (;a;) {}"); } public void testSetterInDoWhilePredicate() { // TODO(user) Make NameAnalyzer smarter so it can remove "Class". testSame("var a = 1;" + "var Class = function() {}; " + "do {} while(Class.property_ = a);"); } public void testSetterInSwitchInput() { // TODO(user) Make NameAnalyzer smarter so it can remove "Class". testSame("var a = 1;" + "var Class = function() {}; " + "switch (Class.property_ = a) {" + " default:" + "}"); } public void testComplexAssigns() { // Complex assigns are not removed by the current pass. testSame("var x = 0; x += 3; x *= 5;"); } public void testNestedAssigns1() { test("var x = 0; var y = x = 3; window.alert(y);", "var y = 3; window.alert(y);"); } public void testNestedAssigns2() { testSame("var x = 0; var y = x = {}; x.b = 3; window.alert(y);"); } public void testComplexNestedAssigns1() { // TODO(nicksantos): Make NameAnalyzer smarter, so that we can eliminate y. testSame("var x = 0; var y = 2; y += x = 3; window.alert(x);"); } public void testComplexNestedAssigns2() { test("var x = 0; var y = 2; y += x = 3; window.alert(y);", "var y = 2; y += 3; window.alert(y);"); } public void testComplexNestedAssigns3() { test("var x = 0; var y = x += 3; window.alert(x);", "var x = 0; x += 3; window.alert(x);"); } public void testComplexNestedAssigns4() { testSame("var x = 0; var y = x += 3; window.alert(y);"); } public void testUnintendedUseOfInheritsInLocalScope1() { testSame("goog.mixin = function() {}; " + "(function() { var x = {}; var y = {}; goog.mixin(x, y); })();"); } public void testUnintendedUseOfInheritsInLocalScope2() { testSame("goog.mixin = function() {}; " + "var x = {}; var y = {}; (function() { goog.mixin(x, y); })();"); } public void testUnintendedUseOfInheritsInLocalScope3() { testSame("goog.mixin = function() {}; " + "var x = {}; var y = {}; (function() { goog.mixin(x, y); })(); " + "window.alert(x);"); } public void testUnintendedUseOfInheritsInLocalScope4() { // Ensures that the "goog$mixin" variable doesn't get stripped out, // even when it's only used in a local scope. testSame("var goog$mixin = function() {}; " + "(function() { var x = {}; var y = {}; goog$mixin(x, y); })();"); } public void testPrototypePropertySetInLocalScope1() { testSame("(function() { var x = function(){}; x.prototype.bar = 3; })();"); } public void testPrototypePropertySetInLocalScope2() { testSame("var x = function(){}; (function() { x.prototype.bar = 3; })();"); } public void testPrototypePropertySetInLocalScope3() { test("var x = function(){ x.prototype.bar = 3; };", ""); } public void testPrototypePropertySetInLocalScope4() { test("var x = {}; x.foo = function(){ x.foo.prototype.bar = 3; };", ""); } public void testPrototypePropertySetInLocalScope5() { test("var x = {}; x.prototype.foo = 3;", ""); } public void testPrototypePropertySetInLocalScope6() { testSame("var x = {}; x.prototype.foo = 3; bar(x.prototype.foo)"); } public void testPrototypePropertySetInLocalScope7() { testSame("var x = {}; x.foo = 3; bar(x.foo)"); } public void testRValueReference1() { testSame("var a = 1; a"); } public void testRValueReference2() { testSame("var a = 1; 1+a"); } public void testRValueReference3() { testSame("var x = {}; x.prototype.foo = 3; var a = x.prototype.foo; 1+a"); } public void testRValueReference4() { testSame("var x = {}; x.prototype.foo = 3; x.prototype.foo"); } public void testRValueReference5() { testSame("var x = {}; x.prototype.foo = 3; 1+x.prototype.foo"); } public void testRValueReference6() { testSame("var x = {}; var idx = 2; x[idx]"); } public void testUnhandledTopNode() { testSame("function Foo() {}; Foo.prototype.isBar = function() {};" + "function Bar() {}; Bar.prototype.isFoo = function() {};" + "var foo = new Foo(); var bar = new Bar();" + // The boolean AND here is currently unhandled by this pass, but // it should not cause it to blow up. "var cond = foo.isBar() && bar.isFoo();" + "if (cond) {window.alert('hello');}"); } public void testPropertyDefinedInGlobalScope() { testSame("function Foo() {}; var x = new Foo(); x.cssClass = 'bar';" + "window.alert(x);"); } public void testConditionallyDefinedFunction1() { testSame("var g; externfoo.x || (externfoo.x = function() { g; })"); } public void testConditionallyDefinedFunction2() { testSame("var g; 1 || (externfoo.x = function() { g; })"); } public void testConditionallyDefinedFunction3() { testSame("var a = {};" + "rand() % 2 || (a.f = function() { externfoo = 1; } || alert());"); } public void testGetElemOnThis() { testSame("var a = 3; this['foo'] = a;"); testSame("this['foo'] = 3;"); } public void testRemoveInstanceOfOnly() { test("function Foo() {}; Foo.prototype.isBar = function() {};" + "var x; if (x instanceof Foo) { window.alert(x); }", ";var x; if (false) { window.alert(x); }"); } public void testRemoveLocalScopedInstanceOfOnly() { test("function Foo() {}; function Bar(x) { this.z = x instanceof Foo; };" + "externfoo.x = new Bar({});", ";function Bar(x) { this.z = false }; externfoo.x = new Bar({});"); } public void testRemoveInstanceOfWithReferencedMethod() { test("function Foo() {}; Foo.prototype.isBar = function() {};" + "var x; if (x instanceof Foo) { window.alert(x.isBar()); }", ";var x; if (false) { window.alert(x.isBar()); }"); } public void testDoNotChangeReferencedInstanceOf() { testSame("function Foo() {}; Foo.prototype.isBar = function() {};" + "var x = new Foo(); if (x instanceof Foo) { window.alert(x); }"); } public void testDoNotChangeReferencedLocalScopedInstanceOf() { testSame("function Foo() {}; externfoo.x = new Foo();" + "function Bar() { if (x instanceof Foo) { window.alert(x); } };" + "externfoo.y = new Bar();"); } public void testDoNotChangeLocalScopeReferencedInstanceOf() { testSame("function Foo() {}; Foo.prototype.isBar = function() {};" + "function Bar() { this.z = new Foo(); }; externfoo.x = new Bar();" + "if (x instanceof Foo) { window.alert(x); }"); } public void testDoNotChangeLocalScopeReferencedLocalScopedInstanceOf() { testSame("function Foo() {}; Foo.prototype.isBar = function() {};" + "function Bar() { this.z = new Foo(); };" + "Bar.prototype.func = function(x) {" + "if (x instanceof Foo) { window.alert(x); }" + "}; new Bar().func();"); } public void testDoNotChangeLocalScopeReferencedLocalScopedInstanceOf2() { test( "function Foo() {}" + "var createAxis = function(f) { return window.passThru(f); };" + "var axis = createAxis(function(test) {" + " return test instanceof Foo;" + "});", "var createAxis = function(f) { return window.passThru(f); };" + "createAxis(function(test) {" + " return false;" + "});"); } public void testDoNotChangeInstanceOfGetElem() { testSame("var goog = {};" + "function f(obj, name) {" + " if (obj instanceof goog[name]) {" + " return name;" + " }" + "}" + "window['f'] = f;"); } public void testWeirdnessOnLeftSideOfPrototype() { // This checks a bug where 'x' was removed, but the function referencing // it was not, causing problems. testSame("var x = 3; " + "(function() { this.bar = 3; }).z = function() {" + " return x;" + "};"); } public void testShortCircuit1() { test("var a = b() || 1", "b()"); } public void testShortCircuit2() { test("var a = 1 || c()", "1 || c()"); } public void testShortCircuit3() { test("var a = b() || c()", "b() || c()"); } public void testShortCircuit4() { test("var a = b() || 3 || c()", "b() || 3 || c()"); } public void testShortCircuit5() { test("var a = b() && 1", "b()"); } public void testShortCircuit6() { test("var a = 1 && c()", "1 && c()"); } public void testShortCircuit7() { test("var a = b() && c()", "b() && c()"); } public void testShortCircuit8() { test("var a = b() && 3 && c()", "b() && 3 && c()"); } public void testRhsReference1() { testSame("var a = 1; a"); } public void testRhsReference2() { testSame("var a = 1; a || b()"); } public void testRhsReference3() { testSame("var a = 1; 1 || a"); } public void testRhsReference4() { test("var a = 1; var b = a || foo()", "var a = 1; a || foo()"); } public void testRhsReference5() { test("var a = 1, b = 5; a; foo(b)", "var a = 1, b = 5; a; foo(b)"); } public void testRhsAssign1() { test("var foo, bar; foo || (bar = 1)", "var foo; foo || 1"); } public void testRhsAssign2() { test("var foo, bar, baz; foo || (baz = bar = 1)", "var foo; foo || 1"); } public void testRhsAssign3() { testSame("var foo = null; foo || (foo = 1)"); } public void testRhsAssign4() { test("var foo = null; foo = (foo || 1)", ""); } public void testRhsAssign5() { test("var a = 3, foo, bar; foo || (bar = a)", "var a = 3, foo; foo || a"); } public void testRhsAssign6() { test("function Foo(){} var foo = null;" + "var f = function () {foo || (foo = new Foo()); return foo}", ""); } public void testRhsAssign7() { testSame("function Foo(){} var foo = null;" + "var f = function () {foo || (foo = new Foo())}; f()"); } public void testRhsAssign8() { testSame("function Foo(){} var foo = null;" + "var f = function () {(foo = new Foo()) || g()}; f()"); } public void testRhsAssign9() { test("function Foo(){} var foo = null;" + "var f = function () {1 + (foo = new Foo()); return foo}", ""); } public void testAssignWithOr1() { testSame("var foo = null;" + "var f = window.a || function () {return foo}; f()"); } public void testAssignWithOr2() { test("var foo = null;" + "var f = window.a || function () {return foo};", "var foo = null"); // why is this left? } public void testAssignWithAnd1() { testSame("var foo = null;" + "var f = window.a && function () {return foo}; f()"); } public void testAssignWithAnd2() { test("var foo = null;" + "var f = window.a && function () {return foo};", "var foo = null;"); // why is this left? } public void testAssignWithHook1() { testSame("function Foo(){} var foo = null;" + "var f = window.a ? " + " function () {return new Foo()} : function () {return foo}; f()"); } public void testAssignWithHook2() { test("function Foo(){} var foo = null;" + "var f = window.a ? " + " function () {return new Foo()} : function () {return foo};", ""); } public void testAssignWithHook2a() { test("function Foo(){} var foo = null;" + "var f; f = window.a ? " + " function () {return new Foo()} : function () {return foo};", ""); } public void testAssignWithHook3() { testSame("function Foo(){} var foo = null; var f = {};" + "f.b = window.a ? " + " function () {return new Foo()} : function () {return foo}; f.b()"); } public void testAssignWithHook4() { test("function Foo(){} var foo = null; var f = {};" + "f.b = window.a ? " + " function () {return new Foo()} : function () {return foo};", ""); } public void testAssignWithHook5() { testSame("function Foo(){} var foo = null; var f = {};" + "f.b = window.a ? function () {return new Foo()} :" + " window.b ? function () {return foo} :" + " function() { return Foo }; f.b()"); } public void testAssignWithHook6() { test("function Foo(){} var foo = null; var f = {};" + "f.b = window.a ? function () {return new Foo()} :" + " window.b ? function () {return foo} :" + " function() { return Foo };", ""); } public void testAssignWithHook7() { testSame("function Foo(){} var foo = null;" + "var f = window.a ? new Foo() : foo;" + "f()"); } public void testAssignWithHook8() { test("function Foo(){} var foo = null;" + "var f = window.a ? new Foo() : foo;", "function Foo(){}" + "window.a && new Foo()"); } public void testAssignWithHook9() { test("function Foo(){} var foo = null; var f = {};" + "f.b = window.a ? new Foo() : foo;", "function Foo(){} window.a && new Foo()"); } public void testAssign1() { test("function Foo(){} var foo = null; var f = {};" + "f.b = window.a;", ""); } public void testAssign2() { test("function Foo(){} var foo = null; var f = {};" + "f.b = window;", ""); } public void testAssign3() { test("var f = {};" + "f.b = window;", ""); } public void testAssign4() { test("function Foo(){} var foo = null; var f = {};" + "f.b = new Foo();", "function Foo(){} new Foo()"); } public void testAssign5() { test("function Foo(){} var foo = null; var f = {};" + "f.b = foo;", ""); } public void testNestedAssign1() { test("var a, b = a = 1, c = 2", ""); } public void testNestedAssign2() { test("var a, b = a = 1; foo(b)", "var b = 1; foo(b)"); } public void testNestedAssign3() { test("var a, b = a = 1; a = b = 2; foo(b)", "var b = 1; b = 2; foo(b)"); } public void testNestedAssign4() { test("var a, b = a = 1; b = a = 2; foo(b)", "var b = 1; b = 2; foo(b)"); } public void testNestedAssign5() { test("var a, b = a = 1; b = a = 2", ""); } public void testNestedAssign15() { test("var a, b, c; c = b = a = 2", ""); } public void testNestedAssign6() { testSame("var a, b, c; a = b = c = 1; foo(a, b, c)"); } public void testNestedAssign7() { testSame("var a = 0; a = i[j] = 1; b(a, i[j])"); } public void testNestedAssign8() { testSame("function f(){" + "this.lockedToken_ = this.lastToken_ = " + "SETPROP_value(this.hiddenInput_, a)}f()"); } public void testRefChain1() { test("var a = 1; var b = a; var c = b; var d = c", ""); } public void testRefChain2() { test("var a = 1; var b = a; var c = b; var d = c || f()", "var a = 1; var b = a; var c = b; c || f()"); } public void testRefChain3() { test("var a = 1; var b = a; var c = b; var d = c + f()", "f()"); } public void testRefChain4() { test("var a = 1; var b = a; var c = b; var d = f() || c", "f()"); } public void testRefChain5() { test("var a = 1; var b = a; var c = b; var d = f() ? g() : c", "f() && g()"); } public void testRefChain6() { test("var a = 1; var b = a; var c = b; var d = c ? f() : g()", "var a = 1; var b = a; var c = b; c ? f() : g()"); } public void testRefChain7() { test("var a = 1; var b = a; var c = b; var d = (b + f()) ? g() : c", "var a = 1; var b = a; (b+f()) && g()"); } public void testRefChain8() { test("var a = 1; var b = a; var c = b; var d = f()[b] ? g() : 0", "var a = 1; var b = a; f()[b] && g()"); } public void testRefChain9() { test("var a = 1; var b = a; var c = 5; var d = f()[b+c] ? g() : 0", "var a = 1; var b = a; var c = 5; f()[b+c] && g()"); } public void testRefChain10() { test("var a = 1; var b = a; var c = b; var d = f()[b] ? g() : 0", "var a = 1; var b = a; f()[b] && g()"); } public void testRefChain11() { test("var a = 1; var b = a; var d = f()[b] ? g() : 0", "var a = 1; var b = a; f()[b] && g()"); } public void testRefChain12() { testSame("var a = 1; var b = a; f()[b] ? g() : 0"); } public void testRefChain13() { test("function f(){}var a = 1; var b = a; var d = f()[b] ? g() : 0", "function f(){}var a = 1; var b = a; f()[b] && g()"); } public void testRefChain14() { testSame("function f(){}var a = 1; var b = a; f()[b] ? g() : 0"); } public void testRefChain15() { test("function f(){}var a = 1, b = a; var c = f(); var d = c[b] ? g() : 0", "function f(){}var a = 1, b = a; var c = f(); c[b] && g()"); } public void testRefChain16() { testSame("function f(){}var a = 1; var b = a; var c = f(); c[b] ? g() : 0"); } public void testRefChain17() { test("function f(){}var a = 1; var b = a; var c = f(); var d = c[b]", "function f(){} f()"); } public void testRefChain18() { testSame("var a = 1; f()[a] && g()"); } public void testRefChain19() { test("var a = 1; var b = [a]; var c = b; b[f()] ? g() : 0", "var a=1; var b=[a]; b[f()] ? g() : 0"); } public void testRefChain20() { test("var a = 1; var b = [a]; var c = b; var d = b[f()] ? g() : 0", "var a=1; var b=[a]; b[f()]&&g()"); } public void testRefChain21() { testSame("var a = 1; var b = 2; var c = a + b; f(c)"); } public void testRefChain22() { test("var a = 2; var b = a = 4; f(a)", "var a = 2; a = 4; f(a)"); } public void testRefChain23() { test("var a = {}; var b = a[1] || f()", "var a = {}; a[1] || f()"); } /** * Expressions that cannot be attributed to any enclosing dependency * scope should be treated as global references. * @bug 1739062 */ public void testAssignmentWithComplexLhs() { testSame("function f() { return this; }" + "var o = {'key': 'val'};" + "f().x_ = o['key'];"); } public void testAssignmentWithComplexLhs2() { testSame("function f() { return this; }" + "var o = {'key': 'val'};" + "f().foo = function() {" + " o" + "};"); } public void testAssignmentWithComplexLhs3() { String source = "var o = {'key': 'val'};" + "function init_() {" + " this.x = o['key']" + "}"; test(source, ""); testSame(source + ";init_()"); } public void testAssignmentWithComplexLhs4() { testSame("function f() { return this; }" + "var o = {'key': 'val'};" + "f().foo = function() {" + " this.x = o['key']" + "};"); } /** * Do not "prototype" property of variables that are not being * tracked (because they are local). * @bug 1809442 */ public void testNoRemovePrototypeDefinitionsOutsideGlobalScope1() { testSame("function f(arg){}" + "" + "(function(){" + " var O = {};" + " O.prototype = 'foo';" + " f(O);" + "})()"); } public void testNoRemovePrototypeDefinitionsOutsideGlobalScope2() { testSame("function f(arg){}" + "(function h(){" + " var L = {};" + " L.prototype = 'foo';" + " f(L);" + "})()"); } public void testNoRemovePrototypeDefinitionsOutsideGlobalScope4() { testSame("function f(arg){}" + "function g(){" + " var N = {};" + " N.prototype = 'foo';" + " f(N);" + "}" + "g()"); } public void testNoRemovePrototypeDefinitionsOutsideGlobalScope5() { // function body not removed due to @bug 1898561 testSame("function g(){ var R = {}; R.prototype = 'foo' } g()"); } public void testRemovePrototypeDefinitionsInGlobalScope1() { testSame("function f(arg){}" + "var M = {};" + "M.prototype = 'foo';" + "f(M);"); } public void testRemovePrototypeDefinitionsInGlobalScope2() { test("var Q = {}; Q.prototype = 'foo'", ""); } public void testRemoveLabeledStatment() { test("LBL: var x = 1;", "LBL: {}"); } public void testRemoveLabeledStatment2() { test("var x; LBL: x = f() + g()", "LBL: { f() ; g()}"); } public void testRemoveLabeledStatment3() { test("var x; LBL: x = 1;", "LBL: {}"); } public void testRemoveLabeledStatment4() { test("var a; LBL: a = f()", "LBL: f()"); } public void testPreservePropertyMutationsToAlias1() { // Test for issue b/2316773 - property get case // Since a is referenced, property mutations via a's alias b must // be preserved. testSame("var a = {}; var b = a; b.x = 1; a"); } public void testPreservePropertyMutationsToAlias2() { // Test for issue b/2316773 - property get case, don't keep 'c' test("var a = {}; var b = a; var c = a; b.x = 1; a", "var a = {}; var b = a; b.x = 1; a"); } public void testPreservePropertyMutationsToAlias3() { // Test for issue b/2316773 - property get case, chain testSame("var a = {}; var b = a; var c = b; c.x = 1; a"); } public void testPreservePropertyMutationsToAlias4() { // Test for issue b/2316773 - element get case testSame("var a = {}; var b = a; b['x'] = 1; a"); } public void testPreservePropertyMutationsToAlias5() { // From issue b/2316773 description testSame("function testCall(o){}" + "var DATA = {'prop': 'foo','attr': {}};" + "var SUBDATA = DATA['attr'];" + "SUBDATA['subprop'] = 'bar';" + "testCall(DATA);"); } public void testPreservePropertyMutationsToAlias6() { // Longer GETELEM chain testSame("function testCall(o){}" + "var DATA = {'prop': 'foo','attr': {}};" + "var SUBDATA = DATA['attr'];" + "var SUBSUBDATA = SUBDATA['subprop'];" + "SUBSUBDATA['subsubprop'] = 'bar';" + "testCall(DATA);"); } public void testPreservePropertyMutationsToAlias7() { // Make sure that the base class does not depend on the derived class. test("var a = {}; var b = {}; b.x = 0;" + "var goog = {}; goog.inherits(b, a); a", "var a = {}; a"); } public void testPreservePropertyMutationsToAlias8() { // Make sure that the derived classes don't end up depending on each other. test("var a = {};" + "var b = {}; b.x = 0;" + "var c = {}; c.y = 0;" + "var goog = {}; goog.inherits(b, a); goog.inherits(c, a); c", "var a = {}; var c = {}; c.y = 0;" + "var goog = {}; goog.inherits(c, a); c"); } public void testPreservePropertyMutationsToAlias9() { testSame("var a = {b: {}};" + "var c = a.b; c.d = 3;" + "a.d = 3; a.d;"); } public void testRemoveAlias() { test("var a = {b: {}};" + "var c = a.b;" + "a.d = 3; a.d;", "var a = {b: {}}; a.d = 3; a.d;"); } public void testSingletonGetter1() { test("function Foo() {} goog.addSingletonGetter(Foo);", ""); } public void testSingletonGetter2() { test("function Foo() {} goog$addSingletonGetter(Foo);", ""); } public void testSingletonGetter3() { // addSingletonGetter adds a getInstance method to a class. testSame("function Foo() {} goog$addSingletonGetter(Foo);" + "this.x = Foo.getInstance();"); } public void testNoRemoveWindowPropertyAlias1() { testSame( "var self_ = window.gbar;\n" + "self_.qs = function() {};"); } public void testNoRemoveWindowPropertyAlias2() { testSame( "var self_ = window;\n" + "self_.qs = function() {};"); } public void testNoRemoveWindowPropertyAlias3() { testSame( "var self_ = window;\n" + "self_['qs'] = function() {};"); } public void testNoRemoveWindowPropertyAlias4() { // TODO(johnlenz): fix this. "self_" should remain. test( "var self_ = window['gbar'] || {};\n" + "self_.qs = function() {};", ""); } public void testNoRemoveWindowPropertyAlias4a() { // TODO(johnlenz): fix this. "self_" should remain. test( "var self_; self_ = window.gbar || {};\n" + "self_.qs = function() {};", ""); } public void testNoRemoveWindowPropertyAlias5() { // TODO(johnlenz): fix this. "self_" should remain. test( "var self_ = window || {};\n" + "self_['qs'] = function() {};", ""); } public void testNoRemoveWindowPropertyAlias5a() { // TODO(johnlenz): fix this. test( "var self_; self_ = window || {};\n" + "self_['qs'] = function() {};", ""); } public void testNoRemoveWindowPropertyAlias6() { testSame( "var self_ = (window.gbar = window.gbar || {});\n" + "self_.qs = function() {};"); } public void testNoRemoveWindowPropertyAlias6a() { testSame( "var self_; self_ = (window.gbar = window.gbar || {});\n" + "self_.qs = function() {};"); } public void testNoRemoveWindowPropertyAlias7() { testSame( "var self_ = (window = window || {});\n" + "self_['qs'] = function() {};"); } public void testNoRemoveWindowPropertyAlias7a() { testSame( "var self_; self_ = (window = window || {});\n" + "self_['qs'] = function() {};"); } public void testNoRemoveAlias0() { testSame( "var x = {}; function f() { return x; }; " + "f().style.display = 'block';" + "alert(x.style)"); } public void testNoRemoveAlias1() { testSame( "var x = {}; function f() { return x; };" + "var map = f();\n" + "map.style.display = 'block';" + "alert(x.style)"); } public void testNoRemoveAlias2() { testSame( "var x = {};" + "var map = (function () { return x; })();\n" + "map.style = 'block';" + "alert(x.style)"); } public void testNoRemoveAlias3() { testSame( "var x = {}; function f() { return x; };" + "var map = {}\n" + "map[1] = f();\n" + "map[1].style.display = 'block';"); } public void testNoRemoveAliasOfExternal0() { testSame( "document.getElementById('foo').style.display = 'block';"); } public void testNoRemoveAliasOfExternal1() { testSame( "var map = document.getElementById('foo');\n" + "map.style.display = 'block';"); } public void testNoRemoveAliasOfExternal2() { testSame( "var map = {}\n" + "map[1] = document.getElementById('foo');\n" + "map[1].style.display = 'block';"); } public void testNoRemoveThrowReference1() { testSame( "var e = {}\n" + "throw e;"); } public void testNoRemoveThrowReference2() { testSame( "function e() {}\n" + "throw new e();"); } public void testClassDefinedInObjectLit1() { test( "var data = {Foo: function() {}};" + "data.Foo.prototype.toString = function() {};", ""); } public void testClassDefinedInObjectLit2() { test( "var data = {}; data.bar = {Foo: function() {}};" + "data.bar.Foo.prototype.toString = function() {};", ""); } public void testClassDefinedInObjectLit3() { test( "var data = {bar: {Foo: function() {}}};" + "data.bar.Foo.prototype.toString = function() {};", ""); } public void testClassDefinedInObjectLit4() { test( "var data = {};" + "data.baz = {bar: {Foo: function() {}}};" + "data.baz.bar.Foo.prototype.toString = function() {};", ""); } public void testVarReferencedInClassDefinedInObjectLit1() { testSame( "var ref = 3;" + "var data = {Foo: function() { this.x = ref; }};" + "window.Foo = data.Foo;"); } public void testVarReferencedInClassDefinedInObjectLit2() { testSame( "var ref = 3;" + "var data = {Foo: function() { this.x = ref; }," + " Bar: function() {}};" + "window.Bar = data.Bar;"); } public void testArrayExt() { testSame( "Array.prototype.foo = function() { return 1 };" + "var y = [];" + "switch (y.foo()) {" + "}"); } public void testArrayAliasExt() { testSame( "Array$X = Array;" + "Array$X.prototype.foo = function() { return 1 };" + "function Array$X() {}" + "var y = [];" + "switch (y.foo()) {" + "}"); } public void testExternalAliasInstanceof1() { test( "Array$X = Array;" + "function Array$X() {}" + "var y = [];" + "if (y instanceof Array) {}", "var y = [];" + "if (y instanceof Array) {}" ); } public void testExternalAliasInstanceof2() { testSame( "Array$X = Array;" + "function Array$X() {}" + "var y = [];" + "if (y instanceof Array$X) {}"); } public void testExternalAliasInstanceof3() { testSame( "var b = Array;" + "var y = [];" + "if (y instanceof b) {}"); } public void testAliasInstanceof4() { testSame( "function Foo() {};" + "var b = Foo;" + "var y = new Foo();" + "if (y instanceof b) {}"); } public void testAliasInstanceof5() { // TODO(johnlenz): fix this. "b" should remain. test( "function Foo() {}" + "function Bar() {}" + "var b = x ? Foo : Bar;" + "var y = new Foo();" + "if (y instanceof b) {}", "function Foo() {}" + "var y = new Foo;" + "if (false){}"); } // We cannot leave x.a.prototype there because it will // fail sanity var check. public void testBrokenNamespaceWithPrototypeAssignment() { test("var x = {}; x.a.prototype = 1", ""); } public void testRemovePrototypeAliases() { test( "function g() {}" + "function F() {} F.prototype.bar = g;" + "window.g = g;", "function g() {}" + "window.g = g;"); } public void testIssue284() { test( "var goog = {};" + "goog.inherits = function(x, y) {};" + "var ns = {};" + "/** @constructor */" + "ns.PageSelectionModel = function() {};" + "/** @constructor */" + "ns.PageSelectionModel.FooEvent = function() {};" + "/** @constructor */" + "ns.PageSelectionModel.SelectEvent = function() {};" + "goog.inherits(ns.PageSelectionModel.ChangeEvent," + " ns.PageSelectionModel.FooEvent);", ""); } public void testIssue838a() { testSame("var z = window['z'] || (window['z'] = {});\n" + "z['hello'] = 'Hello';\n" + "z['world'] = 'World';"); } public void testIssue838b() { testSame( "var z;" + "window['z'] = z || (z = {});\n" + "z['hello'] = 'Hello';\n" + "z['world'] = 'World';"); } public void testIssue874a() { testSame( "var a = a || {};\n" + "var b = a;\n" + "b.View = b.View || {}\n" + "var c = b.View;\n" + "c.Editor = function f(d, e) {\n" + " return d + e\n" + "};\n" + "window.ImageEditor.View.Editor = a.View.Editor;"); } public void testIssue874b() { testSame( "var b;\n" + "var c = b = {};\n" + "c.Editor = function f(d, e) {\n" + " return d + e\n" + "};\n" + "window['Editor'] = b.Editor;"); } public void testIssue874c() { testSame( "var b, c;\n" + "c = b = {};\n" + "c.Editor = function f(d, e) {\n" + " return d + e\n" + "};\n" + "window['Editor'] = b.Editor;"); } public void testIssue874d() { testSame( "var b = {}, c;\n" + "c = b;\n" + "c.Editor = function f(d, e) {\n" + " return d + e\n" + "};\n" + "window['Editor'] = b.Editor;"); } public void testIssue874e() { testSame( "var a;\n" + "var b = a || (a = {});\n" + "var c = b.View || (b.View = {});\n" + "c.Editor = function f(d, e) {\n" + " return d + e\n" + "};\n" + "window.ImageEditor.View.Editor = a.View.Editor;"); } public void testBug6575051() { testSame( "var hackhack = window['__o_o_o__'] = window['__o_o_o__'] || {};\n" + "window['__o_o_o__']['va'] = 1;\n" + "hackhack['Vb'] = 1;"); } @Override protected CompilerPass getProcessor(Compiler compiler) { return new MarkNoSideEffectCallsAndNameAnalyzerRunner(compiler); } private class MarkNoSideEffectCallsAndNameAnalyzerRunner implements CompilerPass { MarkNoSideEffectCalls markNoSideEffectCalls; NameAnalyzer analyzer; MarkNoSideEffectCallsAndNameAnalyzerRunner(Compiler compiler) { this.markNoSideEffectCalls = new MarkNoSideEffectCalls(compiler); this.analyzer = new NameAnalyzer(compiler, true); } @Override public void process(Node externs, Node root) { markNoSideEffectCalls.process(externs, root); analyzer.process(externs, root); } } }