This repository has been archived on 2023-06-18. You can view files and clone it, but cannot push or open issues or pull requests.
ima02/resources/defects4j-checkout-closure-1f/test/com/google/javascript/jscomp/CoalesceVariableNamesTest.java
github-classroom[bot] e42e547e48
Initial commit
2023-04-25 11:33:41 +00:00

450 lines
14 KiB
Java

/*
* Copyright 2008 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;
/**
* Unit tests for {@link CoalesceVariableNames}
*
*/
public class CoalesceVariableNamesTest extends CompilerTestCase {
// The spacing in this file is not exactly standard but it greatly helps
// picking out which variable names are merged.
private boolean usePseudoName = false;
@Override
protected int getNumRepetitions() {
return 1;
}
@Override
public void setUp() {
super.enableLineNumberCheck(true);
usePseudoName = false;
}
@Override
public CompilerPass getProcessor(final Compiler compiler) {
return new CompilerPass() {
@Override
public void process(Node externs, Node js) {
NodeTraversal.traverse(compiler, js,
new CoalesceVariableNames(compiler, usePseudoName));
}
};
}
public void testSimple() {
inFunction("var x; var y; x=1; x; y=1; y; return y",
"var x; x=1; x; x=1; x; return x");
inFunction("var x,y; x=1; x; y=1; y",
"var x ; x=1; x; x=1; x");
inFunction("var x,y; x=1; y=2; y; x");
inFunction("y=0; var x, y; y; x=0; x",
"y=0; var y ; y; y=0;y");
inFunction("var x,y; x=1; y=x; y",
"var x ; x=1; x=x; x");
inFunction("var x,y; x=1; y=x+1; y",
"var x ; x=1; x=x+1; x");
inFunction("x=1; x; y=2; y; var x; var y",
"x=1; x; x=2; x; var x");
inFunction("var x=1; var y=x+1; return y",
"var x=1; x=x+1; return x");
inFunction("var x=1; var y=0; x+=1; y");
inFunction("var x=1; x+=1; var y=0; y",
"var x=1; x+=1; x=0; x");
inFunction("var x=1; foo(bar(x+=1)); var y=0; y",
"var x=1; foo(bar(x+=1)); x=0; x");
inFunction("var y, x=1; f(x+=1, y)");
inFunction("var x; var y; y += 1, y, x = 1; x");
}
public void testMergeThreeVarNames() {
inFunction("var x,y,z; x=1; x; y=1; y; z=1; z",
"var x ; x=1; x; x=1; x; x=1; x");
}
public void testDifferentBlock() {
inFunction("if(1) { var x = 0; x } else { var y = 0; y }",
"if(1) { var x = 0; x } else { x = 0; x }");
}
public void testLoops() {
inFunction("var x; while(1) { x; x = 1; var y = 1; y }");
inFunction("var y = 1; y; while(1) { var x = 1; x }",
"var y = 1; y; while(1) { y = 1; y }");
}
public void testEscaped() {
inFunction("var x = 1; x; function f() { x }; var y = 0; y; f()");
}
public void testFor() {
inFunction("var x = 1; x; for (;;) var y; y = 1; y",
"var x = 1; x; for (;;) ; x = 1; x");
}
public void testForIn() {
// We lose some precision here, unless we have "branched-backward-dataflow".
inFunction("var x = 1, k; x; ; for (var y in k) { y }",
"var x = 1, k; x; ; for (var y in k) { y }");
inFunction("var x = 1, k; x; y = 1; for (var y in k) { y }",
"var x = 1, k; x; x = 1; for ( x in k) { x }");
}
public void testLoopInductionVar() {
inFunction(
"for(var x = 0; x < 10; x++){}" +
"for(var y = 0; y < 10; y++){}" +
"for(var z = 0; z < 10; z++){}",
"for(var x = 0; x < 10; x++){}" +
"for(x = 0; x < 10; x++){}" +
"for(x = 0; x < 10; x++){}");
inFunction(
"for(var x = 0; x < 10; x++){z}" +
"for(var y = 0, z = 0; y < 10; y++){z}",
"for(var x = 0; x < 10; x++){z}" +
"for(var x = 0, z = 0; x < 10; x++){z}");
inFunction("var x = 1; x; for (var y; y=1; ) {y}",
"var x = 1; x; for ( ; x=1; ) {x}");
inFunction("var x = 1; x; y = 1; while(y) var y; y",
"var x = 1; x; x = 1; while(x); x");
inFunction("var x = 1; x; f:var y; y=1",
"var x = 1; x; x=1");
}
public void testSwitchCase() {
inFunction("var x = 1; switch(x) { case 1: var y; case 2: } y = 1; y",
"var x = 1; switch(x) { case 1: case 2: } x = 1; x");
}
public void testDuplicatedVar() {
// Is there a shorter version without multiple declarations?
inFunction("z = 1; var x = 0; x; z; var y = 2, z = 1; y; z;",
"z = 1; var x = 0; x; z; var x = 2, z = 1; x; z;");
}
public void testTryCatch() {
inFunction("try {} catch (e) { } var x = 4; x;",
"try {} catch (e) { } var x = 4; x;");
inFunction("var x = 4; x; try {} catch (e) { }",
"var x = 4; x; try {} catch (e) { }");
}
public void testDeadAssignment() {
inFunction("var x = 6; var y; y = 4 ; x");
inFunction("var y = 3; var y; y += 4; x");
inFunction("var y = 3; var y; y ++ ; x");
inFunction("y = 3; var x; var y = 1 ; x");
}
public void testParameter() {
test("function FUNC(param) {var x = 0; x}",
"function FUNC(param) {param = 0; param}");
}
public void testParameter2() {
// Make sure two formal parameter name never merges.
test("function FUNC(x,y) {x = 0; x; y = 0; y}");
test("function FUNC(x,y,z) {x = 0; x; y = 0; z = 0; z}");
}
public void testParameter3() {
// Make sure the formal parameter declaration is consider a def.
test("function FUNC(x) {var y; y = 0; x; y}");
}
public void testParameter4() {
// Make sure that we do not merge two-arg functions because of the
// IE sort bug (see comments in computeEscaped)
test("function FUNC(x, y) {var a,b; y; a=0; a; x; b=0; b}",
"function FUNC(x, y) {var a; y; a=0; a; x; a=0; a}");
}
public void testParameter4b() {
// Merge parameters
test("function FUNC(x, y, z) {var a,b; y; a=0; a; x; b=0; b}",
"function FUNC(x, y, z) { y; y=0; y; x; x=0; x}");
}
public void testLiveRangeChangeWithinCfgNode() {
inFunction("var x, y; x = 1, y = 2, y, x");
inFunction("var x, y; x = 1,x; y");
// We lose some precisions within the node itself.
inFunction("var x; var y; y = 1, y, x = 1; x");
inFunction("var x; var y; y = 1; y, x = 1; x", "var x; x = 1; x, x = 1; x");
inFunction("var x, y; y = 1, x = 1, x, y += 1, y");
inFunction("var x, y; y = 1, x = 1, x, y ++, y");
}
public void testLiveRangeChangeWithinCfgNode2() {
inFunction("var x; var y; var a; var b;" +
"y = 1, a = 1, y, a, x = 1, b = 1; x; b");
inFunction("var x; var y; var a; var b;" +
"y = 1, a = 1, y, a, x = 1; x; b = 1; b",
"var x; var y; var a; " +
"y = 1, a = 1, y, a, x = 1; x; x = 1; x");
inFunction("var x; var y; var a; var b;" +
"y = 1, a = 1, y, x = 1; a; x; b = 1; b",
"var x; var y; var a; " +
"y = 1, a = 1, y, x = 1; a; x; x = 1; x");
}
public void testFunctionNameReuse() {
// TODO(user): Figure out why this increase code size most of the time.
// inFunction("function x() {}; x(); var y = 1; y",
// "function x() {}; x(); x = 1; x");
// inFunction("x(); var y = 1; y; function x() {}",
// "x(); x = 1; x; function x() {}");
// inFunction("x(); var y = 1; function x() {}; y",
// "x(); x = 1; function x() {}; x");
// // Can't merge because of possible escape.
// inFunction("function x() {return x}; x(); var y = 1; y",
// "function x() {return x}; x(); var y = 1; y");
//
// inFunction("var y = 1; y; x; function x() {}",
// "var y = 1; y; x; function x() {}");
// inFunction("var y = 1; y; function x() {}; x",
// "var y = 1; y; function x() {}; x");
// inFunction("var y = 1; y; function x() {}; x = 1; x",
// "var y = 1; y; function x() {}; y = 1; y");
// inFunction("var y = 1; y; x = 1; function x() {}; x",
// "var y = 1; y; y = 1; function x() {}; y");
}
public void testBug1401831() {
// Verify that we don't wrongly merge "opt_a2" and "i" without considering
// arguments[0] aliasing it.
String src = "function f(opt_a2) {" +
" var buffer;" +
" if (opt_a2) {" +
" for(var i = 0; i < arguments.length; i++) {" +
" buffer += arguments[i];" +
" }" +
" }" +
" return buffer;" +
"}";
test(src, src);
}
public void testDeterministic() {
// Make the variable interference graph a pentagon.
// a - b
// / \
// e c
// \ /
// d
// The coloring partitioning would be:
// a = { a, c }
// b = { b, d }
// e = { e }
inFunction("var a,b,c,d,e;" +
" a=1; b=1; a; b;" +
" b=1; c=1; b; c;" +
" c=1; d=1; c; d;" +
" d=1; e=1; d; e;" +
" e=1; a=1; e; a;",
"var a,b, e;" +
" a=1; b=1; a; b;" +
" b=1; a=1; b; a;" +
" a=1; b=1; a; b;" +
" b=1; e=1; b; e;" +
" e=1; a=1; e; a;");
// If we favor "d" first by declaring "d" earlier,
// the coloring partitioning would be:
// b = { b, e }
// d = { d, a }
// c = { c }
inFunction("var d,a,b,c,e;" +
" a=1; b=1; a; b;" +
" b=1; c=1; b; c;" +
" c=1; d=1; c; d;" +
" d=1; e=1; d; e;" +
" e=1; a=1; e; a;",
"var d, b,c ;" +
" d=1; b=1; d; b;" +
" b=1; c=1; b; c;" +
" c=1; d=1; c; d;" +
" d=1; b=1; d; b;" +
" b=1; d=1; b; d;");
}
// Sometimes live range can be cross even within a VAR declaration.
public void testVarLiveRangeCross() {
inFunction("var a={}; var b=a.S(); b",
"var a={}; a=a.S(); a");
inFunction("var a={}; var b=a.S(), c=b.SS(); b; c",
"var a={}; var b=a.S(), a=b.SS(); b; a");
inFunction("var a={}; var b=a.S(), c=a.SS(), d=a.SSS(); b; c; d",
"var a={}; var b=a.S(), c=a.SS(), a=a.SSS(); b; c; a");
inFunction("var a={}; var b=a.S(), c=a.SS(), d=a.SSS(); b; c; d",
"var a={}; var b=a.S(), c=a.SS(), a=a.SSS(); b; c; a");
inFunction("var a={}; d=1; d; var b=a.S(), c=a.SS(), d=a.SSS(); b; c; d");
}
public void testBug1445366() {
// An assignment might not be complete if the RHS throws an exception.
inFunction(
" var iframe = getFrame();" +
" try {" +
" var win = iframe.contentWindow;" +
" } catch (e) {" +
" } finally {" +
" if (win)" +
" this.setupWinUtil_();" +
" else" +
" this.load();" +
" }");
// Verify that we can still coalesce it if there are no handlers.
inFunction(
" var iframe = getFrame();" +
" var win = iframe.contentWindow;" +
" if (win)" +
" this.setupWinUtil_();" +
" else" +
" this.load();",
" var iframe = getFrame();" +
" iframe = iframe.contentWindow;" +
" if (iframe)" +
" this.setupWinUtil_();" +
" else" +
" this.load();");
}
public void testCannotReuseAnyParamsBug() {
testSame("function handleKeyboardShortcut(e, key, isModifierPressed) {\n" +
" if (!isModifierPressed) {\n" +
" return false;\n" +
" }\n" +
" var command;\n" +
" switch (key) {\n" +
" case 'b': // Ctrl+B\n" +
" command = COMMAND.BOLD;\n" +
" break;\n" +
" case 'i': // Ctrl+I\n" +
" command = COMMAND.ITALIC;\n" +
" break;\n" +
" case 'u': // Ctrl+U\n" +
" command = COMMAND.UNDERLINE;\n" +
" break;\n" +
" case 's': // Ctrl+S\n" +
" return true;\n" +
" }\n" +
"\n" +
" if (command) {\n" +
" this.fieldObject.execCommand(command);\n" +
" return true;\n" +
" }\n" +
"\n" +
" return false;\n" +
"};");
}
public void testForInWithAssignment() {
inFunction(
"var _f = function (commands) {" +
" var k, v, ref;" +
" for (k in ref = commands) {" +
" v = ref[k];" +
" alert(k + ':' + v);" +
" }" +
"}",
"var _f = function (commands) {" +
" var k,ref;" +
" for (k in ref = commands) {" +
" commands = ref[k];" +
" alert(k + ':' + commands);" +
" }" +
"}"
);
}
public void testUsePseduoNames() {
usePseudoName = true;
inFunction("var x = 0; print(x ); var y = 1; print( y)",
"var x_y = 0; print(x_y); x_y = 1; print(x_y)");
inFunction("var x_y = 1; var x = 0; print(x ); var y = 1;" +
"print( y); print(x_y);",
"var x_y = 1; var x_y$ = 0; print(x_y$); x_y$ = 1;" + "" +
"print(x_y$); print(x_y);");
inFunction("var x_y = 1; function f() {" +
"var x = 0; print(x ); var y = 1; print( y);" +
"print(x_y);}",
"var x_y = 1; function f() {" +
"var x_y$ = 0; print(x_y$); x_y$ = 1; print(x_y$);" +
"print(x_y);}");
inFunction("var x = 0; print(x ); var y = 1; print( y); " +
"var closure_var; function bar() { print(closure_var); }",
"var x_y = 0; print(x_y); x_y = 1; print(x_y); " +
"var closure_var; function bar() { print(closure_var); }");
}
public void testMaxVars() {
String code = "";
for (int i = 0;
i < LiveVariablesAnalysis.MAX_VARIABLES_TO_ANALYZE + 1; i++) {
code += String.format("var x%d = 0; print(x%d);", i, i);
}
inFunction(code);
}
private void inFunction(String src) {
inFunction(src, src);
}
private void inFunction(String src, String expected) {
test("function FUNC(){" + src + "}",
"function FUNC(){" + expected + "}");
}
private void test(String src) {
test(src, src);
}
}