305 lines
9.7 KiB
Java
305 lines
9.7 KiB
Java
|
/*
|
||
|
* Copyright 2007 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;
|
||
|
|
||
|
public class InlineSimpleMethodsTest extends CompilerTestCase {
|
||
|
|
||
|
public InlineSimpleMethodsTest() {
|
||
|
super("", false);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void setUp() throws Exception {
|
||
|
super.setUp();
|
||
|
super.enableLineNumberCheck(true);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected CompilerPass getProcessor(Compiler compiler) {
|
||
|
return new InlineSimpleMethods(compiler);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Helper for tests that expects definitions to remain unchanged, such
|
||
|
* that {@code definitions+js} is converted to {@code definitions+expected}.
|
||
|
*/
|
||
|
private void testWithPrefix(String definitions, String js, String expected) {
|
||
|
test(definitions + js, definitions + expected);
|
||
|
}
|
||
|
|
||
|
public void testSimpleInline1() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){return this.baz};",
|
||
|
"var x=(new Foo).bar();var y=(new Foo).bar();",
|
||
|
"var x=(new Foo).baz;var y=(new Foo).baz");
|
||
|
}
|
||
|
|
||
|
public void testSimpleInline2() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype={bar:function(){return this.baz}};",
|
||
|
"var x=(new Foo).bar();var y=(new Foo).bar();",
|
||
|
"var x=(new Foo).baz;var y=(new Foo).baz");
|
||
|
}
|
||
|
|
||
|
public void testSimpleGetterInline1() {
|
||
|
// TODO(johnlenz): Support this case.
|
||
|
testSame("function Foo(){}" +
|
||
|
"Foo.prototype={get bar(){return this.baz}};" +
|
||
|
"var x=(new Foo).bar;var y=(new Foo).bar");
|
||
|
// Verify we are not confusing calling the result of an ES5 getter
|
||
|
// with call the getter.
|
||
|
testSame("function Foo(){}" +
|
||
|
"Foo.prototype={get bar(){return this.baz}};" +
|
||
|
"var x=(new Foo).bar();var y=(new Foo).bar()");
|
||
|
}
|
||
|
|
||
|
public void testSimpleSetterInline1() {
|
||
|
// Verify 'get' and 'set' are not confused.
|
||
|
testSame("function Foo(){}" +
|
||
|
"Foo.prototype={set bar(a){return this.baz}};" +
|
||
|
"var x=(new Foo).bar;var y=(new Foo).bar");
|
||
|
testSame("function Foo(){}" +
|
||
|
"Foo.prototype={set bar(a){return this.baz}};" +
|
||
|
"var x=(new Foo).bar();var y=(new Foo).bar()");
|
||
|
}
|
||
|
|
||
|
public void testSelfInline() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){return this.baz};",
|
||
|
"Foo.prototype.meth=function(){this.bar();}",
|
||
|
"Foo.prototype.meth=function(){this.baz}");
|
||
|
}
|
||
|
|
||
|
public void testCallWithArgs() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){return this.baz};",
|
||
|
"var x=(new Foo).bar(3,new Foo)",
|
||
|
"var x=(new Foo).bar(3,new Foo)");
|
||
|
}
|
||
|
|
||
|
public void testCallWithConstArgs() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(a){return this.baz};",
|
||
|
"var x=(new Foo).bar(3, 4)",
|
||
|
"var x=(new Foo).baz");
|
||
|
}
|
||
|
|
||
|
public void testNestedProperties() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){return this.baz.ooka};",
|
||
|
"(new Foo).bar()",
|
||
|
"(new Foo).baz.ooka");
|
||
|
}
|
||
|
|
||
|
public void testSkipComplexMethods() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){return this.baz};" +
|
||
|
"Foo.prototype.condy=function(){return this.baz?this.baz:1};",
|
||
|
"var x=(new Foo).argy()",
|
||
|
"var x=(new Foo).argy()");
|
||
|
}
|
||
|
|
||
|
public void testSkipConflictingMethods() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){return this.baz};" +
|
||
|
"Foo.prototype.bar=function(){return this.bazz};",
|
||
|
"var x=(new Foo).bar()",
|
||
|
"var x=(new Foo).bar()");
|
||
|
}
|
||
|
|
||
|
public void testSameNamesDifferentDefinitions() {
|
||
|
testWithPrefix("function A(){}" +
|
||
|
"A.prototype.g=function(){return this.a};" +
|
||
|
"function B(){}" +
|
||
|
"B.prototype.g=function(){return this.b};",
|
||
|
"var x=(new A).g();" +
|
||
|
"var y=(new B).g();" +
|
||
|
"var a=new A;" +
|
||
|
"var ag=a.g();",
|
||
|
"var x=(new A).g();" +
|
||
|
"var y=(new B).g();" +
|
||
|
"var a=new A;" +
|
||
|
"var ag=a.g()");
|
||
|
}
|
||
|
|
||
|
public void testSameNamesSameDefinitions() {
|
||
|
testWithPrefix("function A(){}" +
|
||
|
"A.prototype.g=function(){return this.a};" +
|
||
|
"function B(){}" +
|
||
|
"B.prototype.g=function(){return this.a};",
|
||
|
"var x=(new A).g();" +
|
||
|
"var y=(new B).g();" +
|
||
|
"var a=new A;" +
|
||
|
"var ag=a.g();",
|
||
|
"var x=(new A).a;" +
|
||
|
"var y=(new B).a;" +
|
||
|
"var a=new A;" +
|
||
|
"var ag=a.a");
|
||
|
}
|
||
|
|
||
|
public void testConfusingNames() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){return this.baz};",
|
||
|
"function bar(){var bar=function(){};bar()}",
|
||
|
"function bar(){var bar=function(){};bar()}");
|
||
|
}
|
||
|
|
||
|
public void testConstantInline() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){return 3};",
|
||
|
"var f=new Foo;var x=f.bar()",
|
||
|
"var f=new Foo;var x=3");
|
||
|
}
|
||
|
|
||
|
public void testConstantArrayInline() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){return[3,4]};",
|
||
|
"var f=new Foo;var x=f.bar()",
|
||
|
"var f=new Foo;var x=[3,4]");
|
||
|
}
|
||
|
|
||
|
public void testConstantInlineWithSideEffects() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){return 3};",
|
||
|
"var x=(new Foo).bar()",
|
||
|
"var x=(new Foo).bar()");
|
||
|
}
|
||
|
|
||
|
public void testEmptyMethodInline() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(a){};",
|
||
|
"var x=new Foo; x.bar();",
|
||
|
"var x=new Foo");
|
||
|
}
|
||
|
|
||
|
public void testEmptyMethodInlineWithSideEffects() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){};",
|
||
|
"(new Foo).bar();var y=new Foo;y.bar(new Foo)",
|
||
|
"(new Foo).bar();var y=new Foo;y.bar(new Foo)");
|
||
|
}
|
||
|
|
||
|
public void testEmptyMethodInlineInAssign1() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){};",
|
||
|
"var x=new Foo;var y=x.bar()",
|
||
|
"var x=new Foo;var y=void 0");
|
||
|
}
|
||
|
|
||
|
public void testEmptyMethodInlineInAssign2() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){};",
|
||
|
"var x=new Foo;var y=x.bar().toString()",
|
||
|
"var x=new Foo;var y=(void 0).toString()");
|
||
|
}
|
||
|
|
||
|
public void testNormalMethod() {
|
||
|
testWithPrefix("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(){var x=1};",
|
||
|
"var x=new Foo;x.bar()",
|
||
|
"var x=new Foo;x.bar()");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineOfExternMethods1() {
|
||
|
testSame("var external={};external.charAt;",
|
||
|
"external.charAt()", (DiagnosticType) null);
|
||
|
}
|
||
|
|
||
|
public void testNoInlineOfExternMethods2() {
|
||
|
testSame("var external={};external.charAt=function(){};",
|
||
|
"external.charAt()", (DiagnosticType) null);
|
||
|
}
|
||
|
|
||
|
public void testNoInlineOfExternMethods3() {
|
||
|
testSame("var external={};external.bar=function(){};",
|
||
|
"function Foo(){}Foo.prototype.bar=function(){};(new Foo).bar()",
|
||
|
(DiagnosticType) null);
|
||
|
}
|
||
|
|
||
|
public void testNoInlineOfDangerousProperty() {
|
||
|
testSame("function Foo(){this.bar=3}" +
|
||
|
"Foo.prototype.bar=function(){};" +
|
||
|
"var x=new Foo;var y=x.bar()");
|
||
|
}
|
||
|
|
||
|
// Don't warn about argument naming conventions (this is done in another pass)
|
||
|
// opt_ parameters must not be followed by non-optional parameters.
|
||
|
// var_args must be last
|
||
|
public void testNoWarn() {
|
||
|
testSame("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(opt_a,b){var x=1};" +
|
||
|
"var x=new Foo;x.bar()");
|
||
|
|
||
|
testSame("function Foo(){}" +
|
||
|
"Foo.prototype.bar=function(var_args,b){var x=1};" +
|
||
|
"var x=new Foo;x.bar()");
|
||
|
}
|
||
|
|
||
|
public void testObjectLit() {
|
||
|
testSame("Foo.prototype.bar=function(){return this.baz_};" +
|
||
|
"var blah={bar:function(){}};" +
|
||
|
"(new Foo).bar()");
|
||
|
}
|
||
|
|
||
|
public void testObjectLit2() {
|
||
|
testSame("var blah={bar:function(){}};" +
|
||
|
"(new Foo).bar()");
|
||
|
}
|
||
|
|
||
|
public void testObjectLitExtern() {
|
||
|
String externs = "window.bridge={_sip:function(){}};";
|
||
|
testSame(externs, "window.bridge._sip()", null);
|
||
|
}
|
||
|
|
||
|
public void testExternFunction() {
|
||
|
String externs = "function emptyFunction() {}";
|
||
|
testSame(externs,
|
||
|
"function Foo(){this.empty=emptyFunction}" +
|
||
|
"(new Foo).empty()", null);
|
||
|
}
|
||
|
|
||
|
public void testIssue2508576_1() {
|
||
|
// Method defined by an extern should be left alone.
|
||
|
String externs = "function alert(a) {}";
|
||
|
testSame(externs, "({a:alert,b:alert}).a(\"a\")", null);
|
||
|
}
|
||
|
|
||
|
public void testIssue2508576_2() {
|
||
|
// Anonymous object definition with a side-effect should be left alone.
|
||
|
testSame("({a:function(){},b:x()}).a(\"a\")");
|
||
|
}
|
||
|
|
||
|
public void testIssue2508576_3() {
|
||
|
// Anonymous object definition without side-effect should be removed.
|
||
|
test("({a:function(){},b:alert}).a(\"a\")", "");
|
||
|
}
|
||
|
|
||
|
public void testAnonymousGet() {
|
||
|
// Anonymous object definition without side-effect should be removed.
|
||
|
testSame("({get a(){return function(){}},b:alert}).a(\"a\")");
|
||
|
testSame("({get a(){},b:alert}).a(\"a\")");
|
||
|
testSame("({get a(){},b:alert}).a");
|
||
|
}
|
||
|
|
||
|
public void testAnonymousSet() {
|
||
|
// Anonymous object definition without side-effect should be removed.
|
||
|
testSame("({set a(b){return function(){}},b:alert}).a(\"a\")");
|
||
|
testSame("({set a(b){},b:alert}).a(\"a\")");
|
||
|
testSame("({set a(b){},b:alert}).a");
|
||
|
}
|
||
|
}
|