161 lines
5.3 KiB
Java
161 lines
5.3 KiB
Java
|
/*
|
||
|
* Copyright 2011 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;
|
||
|
|
||
|
/**
|
||
|
* @author johnlenz@google.com (John Lenz)
|
||
|
*/
|
||
|
public class RemoveUnusedClassPropertiesTest extends CompilerTestCase {
|
||
|
|
||
|
private static final String EXTERNS =
|
||
|
"var window;\n" +
|
||
|
"function alert(a) {}\n" +
|
||
|
"var EXT = {};" +
|
||
|
"EXT.ext;";
|
||
|
|
||
|
public RemoveUnusedClassPropertiesTest() {
|
||
|
super(EXTERNS);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected CompilerPass getProcessor(Compiler compiler) {
|
||
|
return new RemoveUnusedClassProperties(compiler);
|
||
|
}
|
||
|
|
||
|
public void testSimple1() {
|
||
|
// A property defined on "this" can be removed
|
||
|
test("this.a = 2", "2");
|
||
|
test("x = (this.a = 2)", "x = 2");
|
||
|
testSame("this.a = 2; x = this.a;");
|
||
|
}
|
||
|
|
||
|
public void testSimple2() {
|
||
|
// A property defined on "this" can be removed, even when defined
|
||
|
// as part of an expression
|
||
|
test("this.a = 2, f()", "2, f()");
|
||
|
test("x = (this.a = 2, f())", "x = (2, f())");
|
||
|
test("x = (f(), this.a = 2)", "x = (f(), 2)");
|
||
|
}
|
||
|
|
||
|
public void testSimple3() {
|
||
|
// A property defined on an object other than "this" can not be removed.
|
||
|
testSame("y.a = 2");
|
||
|
// but doesn't prevent the removal of the definition on 'this'.
|
||
|
test("y.a = 2; this.a = 2", "y.a = 2; 2");
|
||
|
// Some use of the property "a" prevents the removal.
|
||
|
testSame("y.a = 2; this.a = 1; alert(x.a)");
|
||
|
}
|
||
|
|
||
|
public void testObjLit() {
|
||
|
// A property defined on an object other than "this" can not be removed.
|
||
|
testSame("({a:2})");
|
||
|
// but doesn't prevent the removal of the definition on 'this'.
|
||
|
test("({a:0}); this.a = 1;", "({a:0});1");
|
||
|
// Some use of the property "a" prevents the removal.
|
||
|
testSame("x = ({a:0}); this.a = 1; alert(x.a)");
|
||
|
}
|
||
|
|
||
|
public void testExtern() {
|
||
|
// A property defined in the externs is can not be removed.
|
||
|
testSame("this.ext = 2");
|
||
|
}
|
||
|
|
||
|
public void testExport() {
|
||
|
// An exported property can not be removed.
|
||
|
testSame("this.ext = 2; window['export'] = this.ext;");
|
||
|
testSame("function f() { this.ext = 2; } window['export'] = this.ext;");
|
||
|
}
|
||
|
|
||
|
|
||
|
public void testAssignOp1() {
|
||
|
// Properties defined using a compound assignment can be removed if the
|
||
|
// result of the assignment expression is not immediately used.
|
||
|
test("this.x += 2", "2");
|
||
|
testSame("x = (this.x += 2)");
|
||
|
testSame("this.x += 2; x = this.x;");
|
||
|
// But, of course, a later use prevents its removal.
|
||
|
testSame("this.x += 2; x.x;");
|
||
|
}
|
||
|
|
||
|
public void testAssignOp2() {
|
||
|
// Properties defined using a compound assignment can be removed if the
|
||
|
// result of the assignment expression is not immediately used.
|
||
|
test("this.a += 2, f()", "2, f()");
|
||
|
test("x = (this.a += 2, f())", "x = (2, f())");
|
||
|
testSame("x = (f(), this.a += 2)");
|
||
|
}
|
||
|
|
||
|
public void testInc1() {
|
||
|
// Increments and Decrements are handled similarly to compound assignments
|
||
|
// but need a placeholder value when replaced.
|
||
|
test("this.x++", "0");
|
||
|
testSame("x = (this.x++)");
|
||
|
testSame("this.x++; x = this.x;");
|
||
|
|
||
|
test("--this.x", "0");
|
||
|
testSame("x = (--this.x)");
|
||
|
testSame("--this.x; x = this.x;");
|
||
|
}
|
||
|
|
||
|
public void testInc2() {
|
||
|
// Increments and Decrements are handled similarly to compound assignments
|
||
|
// but need a placeholder value when replaced.
|
||
|
test("this.a++, f()", "0, f()");
|
||
|
test("x = (this.a++, f())", "x = (0, f())");
|
||
|
testSame("x = (f(), this.a++)");
|
||
|
|
||
|
test("--this.a, f()", "0, f()");
|
||
|
test("x = (--this.a, f())", "x = (0, f())");
|
||
|
testSame("x = (f(), --this.a)");
|
||
|
}
|
||
|
|
||
|
public void testJSCompiler_renameProperty() {
|
||
|
// JSCompiler_renameProperty introduces a use of the property
|
||
|
testSame("this.a = 2; x[JSCompiler_renameProperty('a')]");
|
||
|
testSame("this.a = 2; JSCompiler_renameProperty('a')");
|
||
|
}
|
||
|
|
||
|
public void testForIn() {
|
||
|
// This is the basic assumption that this pass makes:
|
||
|
// it can remove properties even when the object is used in a FOR-IN loop
|
||
|
test("this.y = 1;for (var a in x) { alert(x[a]) }",
|
||
|
"1;for (var a in x) { alert(x[a]) }");
|
||
|
}
|
||
|
|
||
|
public void testObjectKeys() {
|
||
|
// This is the basic assumption that this pass makes:
|
||
|
// it can remove properties even when the object are referenced
|
||
|
test("this.y = 1;alert(Object.keys(this))",
|
||
|
"1;alert(Object.keys(this))");
|
||
|
}
|
||
|
|
||
|
public void testIssue730() {
|
||
|
// Partial removal of properties can causes problems if the object is
|
||
|
// sealed.
|
||
|
// TODO(johnlenz): should we not allow partial removals?
|
||
|
test(
|
||
|
"function A() {this.foo = 0;}\n" +
|
||
|
"function B() {this.a = new A();}\n" +
|
||
|
"B.prototype.dostuff = function() {this.a.foo++;alert('hi');}\n" +
|
||
|
"new B().dostuff();\n",
|
||
|
"function A(){0}" +
|
||
|
"function B(){this.a=new A}" +
|
||
|
"B.prototype.dostuff=function(){this.a.foo++;alert(\"hi\")};" +
|
||
|
"new B().dostuff();");
|
||
|
}
|
||
|
}
|