274 lines
10 KiB
Java
274 lines
10 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;
|
||
|
|
||
|
/**
|
||
|
* Unit tests for {@link ShadowVariables}.
|
||
|
*
|
||
|
*
|
||
|
*/
|
||
|
public class ShadowVariablesTest extends CompilerTestCase{
|
||
|
// Use pseudo names to make test easier to read.
|
||
|
private boolean generatePseudoNames = false;
|
||
|
@Override
|
||
|
protected CompilerPass getProcessor(Compiler compiler) {
|
||
|
return new RenameVars(
|
||
|
compiler, "", false, false,
|
||
|
generatePseudoNames, true, null, null, null);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected int getNumRepetitions() {
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void setUp() throws Exception {
|
||
|
super.setUp();
|
||
|
generatePseudoNames = false;
|
||
|
}
|
||
|
|
||
|
public void testShadowSimple1() {
|
||
|
test("function foo(x) { return function (y) {} }",
|
||
|
"function b(a) { return function (a) {} }");
|
||
|
|
||
|
generatePseudoNames = true;
|
||
|
|
||
|
test("function foo ( x ) { return function ( y ) {} }",
|
||
|
"function $foo$$($x$$) { return function ($x$$) {} }");
|
||
|
|
||
|
}
|
||
|
|
||
|
public void testShadowSimple2() {
|
||
|
test("function foo(x,y) { return function (y,z) {} }",
|
||
|
"function c(a,b) { return function (a,b) {} }");
|
||
|
|
||
|
generatePseudoNames = true;
|
||
|
|
||
|
test("function foo ( x , y ) { return function ( y , z ) {} }",
|
||
|
"function $foo$$($x$$,$y$$) { return function ($x$$,$y$$) {} }");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If we have a choice, pick out the most used variable to shadow.
|
||
|
*/
|
||
|
public void testShadowMostUsedVar() {
|
||
|
generatePseudoNames = true;
|
||
|
test("function foo () {var x ; var y ; y ; y ; y ; x ;" +
|
||
|
" return function ( k ) {} }",
|
||
|
|
||
|
"function $foo$$() {var $x$$; var $y$$; $y$$;$y$$;$y$$;$x$$;" +
|
||
|
" return function ($y$$) {} }");
|
||
|
}
|
||
|
|
||
|
public void testNoShadowReferencedVariables() {
|
||
|
generatePseudoNames = true;
|
||
|
test("function f1 () { var x ; x ; x ; x ;" +
|
||
|
" return function f2 ( y ) {" +
|
||
|
" return function f3 () { x } }}",
|
||
|
"function $f1$$() { var $x$$;$x$$;$x$$;$x$$;" +
|
||
|
" return function $f2$$($y$$) {" +
|
||
|
" return function $f3$$() {$x$$} }}");
|
||
|
}
|
||
|
|
||
|
public void testNoShadowGlobalVariables() {
|
||
|
generatePseudoNames = true;
|
||
|
test("var x ; x ; function foo () { return function ( y ) {}}",
|
||
|
"var $x$$; $x$$; function $foo$$() { return function ($y$$) {}}");
|
||
|
}
|
||
|
|
||
|
public void testShadowBleedInFunctionName() {
|
||
|
generatePseudoNames = true;
|
||
|
test("function foo () { function b ( y ) { y } b ; b ;}",
|
||
|
"function $foo$$() { function $b$$($b$$) {$b$$} $b$$; $b$$;}");
|
||
|
}
|
||
|
|
||
|
public void testNoShadowLessPopularName() {
|
||
|
generatePseudoNames = true;
|
||
|
// We make sure that y doesn't pick x as a shadow and remains to be renamed
|
||
|
// to 'a'.
|
||
|
// If we do shadow y with whatever x renames to (say b) we will
|
||
|
// get 4 b's and 7 a's while currently we get 3 b's and 8 a's.
|
||
|
// I believe this arrangement will always be better for gzipping.
|
||
|
test("function f1 ( x ) {" +
|
||
|
" function f2 ( y ) {} x ; x ;}" +
|
||
|
"function f3 ( i ) {" +
|
||
|
" var k ; var j ; j ; j ; j ; j ; j ; j ;}",
|
||
|
|
||
|
"function $f1$$($x$$) {" +
|
||
|
" function $f2$$($y$$) {} $x$$;$x$$;}" +
|
||
|
"function $f3$$($i$$) {" +
|
||
|
" var $k$$; var $j$$;$j$$;$j$$;$j$$;$j$$;$j$$;$j$$;}");
|
||
|
}
|
||
|
|
||
|
public void testShadowFunctionName() {
|
||
|
generatePseudoNames = true;
|
||
|
test("var g = function() {" +
|
||
|
" var x ; return function(){function y (){}}}",
|
||
|
"var $g$$ = function() {" +
|
||
|
" var $x$$; return function(){function $x$$(){}}}");
|
||
|
}
|
||
|
|
||
|
public void testShadowLotsOfScopes1() {
|
||
|
generatePseudoNames = true;
|
||
|
test("var g = function( x ) { return function() { return function() {" +
|
||
|
" return function() { var y }}}}",
|
||
|
"var $g$$ = function($x$$) { return function() { return function() {" +
|
||
|
" return function() { var $x$$ }}}}");
|
||
|
}
|
||
|
|
||
|
public void testShadowLotsOfScopes2() {
|
||
|
generatePseudoNames = true;
|
||
|
// 'y' doesn't have a candidate to shadow due to upward referencing.
|
||
|
test("var g = function( x ) { return function( y ) " +
|
||
|
" {return function() {return function() { x }}}}",
|
||
|
"var $g$$ = function($x$$) { return function($y$$) " +
|
||
|
" {return function() {return function() { $x$$ }}}}");
|
||
|
|
||
|
test("var g = function( x ) { return function() " +
|
||
|
" {return function( y ) {return function() { x }}}}",
|
||
|
"var $g$$ = function($x$$) { return function() " +
|
||
|
" {return function($y$$) {return function() { $x$$ }}}}");
|
||
|
|
||
|
test("var g = function( x ) { return function() " +
|
||
|
" {return function() {return function( y ) { x }}}}",
|
||
|
"var $g$$ = function($x$$) { return function() " +
|
||
|
" {return function() {return function($y$$) { $x$$ }}}}");
|
||
|
}
|
||
|
|
||
|
public void testShadowLotsOfScopes3() {
|
||
|
generatePseudoNames = true;
|
||
|
// 'y' doesn't have a candidate to shadow due to upward referencing.
|
||
|
test("var g = function( x ) { return function() " +
|
||
|
" {return function() {return function() { x }; var y }}}",
|
||
|
"var $g$$ = function($x$$) { return function() " +
|
||
|
" {return function() {return function() { $x$$ }; var $y$$}}}");
|
||
|
test("var g = function( x ) { return function() " +
|
||
|
" {return function() {return function() { x }}; var y }}",
|
||
|
"var $g$$ = function($x$$) { return function() " +
|
||
|
" {return function() {return function() { $x$$ }}; var $y$$}}");
|
||
|
test("var g = function( x ) { return function() " +
|
||
|
" {return function() {return function() { x }}}; var y }",
|
||
|
"var $g$$ = function($x$$) { return function() " +
|
||
|
" {return function() {return function() { $x$$ }}}; var $y$$}");
|
||
|
}
|
||
|
|
||
|
public void testShadowLotsOfScopes4() {
|
||
|
// Make sure we do get the optimal shadowing scheme where
|
||
|
test("var g = function(x) { return function() { return function() {" +
|
||
|
" return function(){return function(){};var m};var n};var o}}",
|
||
|
"var b = function(a) { return function() { return function() {" +
|
||
|
" return function(){return function(){};var a};var a};var a}}");
|
||
|
}
|
||
|
|
||
|
public void testShadowLotsOfScopes5() {
|
||
|
generatePseudoNames = true;
|
||
|
test("var g = function( x ) {" +
|
||
|
" return function() { return function() {" +
|
||
|
" return function() { return function() {" +
|
||
|
" x }; o };var n };var o };var p }",
|
||
|
"var $g$$ = function($x$$) {" +
|
||
|
" return function() { return function() {" +
|
||
|
" return function() { return function() {" +
|
||
|
" $x$$};$o$$};var $p$$};var $o$$};var $p$$}");
|
||
|
|
||
|
test("var g = function( x ) {" +
|
||
|
" return function() { return function() {" +
|
||
|
" return function() { return function() {" +
|
||
|
" x }; p };var n };var o };var p }",
|
||
|
"var $g$$ = function($x$$) {" +
|
||
|
" return function() { return function() {" +
|
||
|
" return function() { return function() {" +
|
||
|
" $x$$};$p$$};var $o$$};var $o$$};var $p$$}");
|
||
|
}
|
||
|
|
||
|
public void testShadowWithShadowAlready() {
|
||
|
test("var g = function(x) { return function() { return function() {" +
|
||
|
" return function(){return function(){x}};var p};var o};var p}",
|
||
|
"var c = function(b) { return function() { return function() {" +
|
||
|
" return function(){return function(){b}};var a};var a};var a}");
|
||
|
|
||
|
test("var g = function(x) { return function() { return function() {" +
|
||
|
" return function(){return function(){x};p};var p};var o};var p}",
|
||
|
"var c = function(b) { return function() { return function() {" +
|
||
|
" return function(){return function(){b};a};var a};var a};var a}");
|
||
|
}
|
||
|
|
||
|
public void testShadowBug1() {
|
||
|
generatePseudoNames = true;
|
||
|
test("function f ( x ) { return function( y ) {" +
|
||
|
" return function( x ) { x + y ; }}}",
|
||
|
"function $f$$($x$$) { return function($y$$) {" +
|
||
|
" return function($x$$) { $x$$ + $y$$; }}}");
|
||
|
}
|
||
|
|
||
|
public void testOptimal() {
|
||
|
// A test for a case that wasn't optimal in a single pass algorithm.
|
||
|
test("function f(x) { function g(y) { function h(x) {}}}",
|
||
|
"function c(a) { function b(a) { function b(a) {}}}");
|
||
|
}
|
||
|
|
||
|
public void testSharingAcrossInnerScopes() {
|
||
|
test("function f() {var f=function g(){g()}; var x=function y(){y()}}",
|
||
|
"function c() {var d=function a(){a()}; var e=function b(){b()}}");
|
||
|
test("function f(x) { return x ? function(y){} : function(z) {} }",
|
||
|
"function b(a) { return a ? function(a){} : function(a) {} }");
|
||
|
}
|
||
|
|
||
|
public void testExportedLocal1() {
|
||
|
test("function f(a) { a();a();a(); return function($super){} }",
|
||
|
"function b(a) { a();a();a(); return function($super){} }");
|
||
|
}
|
||
|
|
||
|
public void testExportedLocal2() {
|
||
|
test("function f($super) { $super();$super(); return function(a){} }",
|
||
|
"function a($super) { $super();$super(); return function(b){} }");
|
||
|
}
|
||
|
|
||
|
public void testBug4172539() {
|
||
|
// All the planets must line up. When we look at the 2nd inner function,
|
||
|
// y can shadow x, also m can shadow x as well. Now all that is left for
|
||
|
// n to shadow is 'y'. Now because y has already shadowed x, the pseudo
|
||
|
// name maps has already updated y gets $x$$. This mean n will be updated
|
||
|
// with "$x$$" in the name map which is incorrect. That is the reason
|
||
|
// why we can't update the pseudo name map on-the-fly.
|
||
|
|
||
|
generatePseudoNames = true;
|
||
|
test("function f(x) {" +
|
||
|
" x;x;x;" +
|
||
|
" return function (y) { y; x };" +
|
||
|
" return function (y) {" +
|
||
|
" y;" +
|
||
|
" return function (m, n) {" +
|
||
|
" m;m;m;" +
|
||
|
" };" +
|
||
|
" };" +
|
||
|
"}",
|
||
|
|
||
|
"function $f$$($x$$) {" +
|
||
|
" $x$$;$x$$;$x$$;" +
|
||
|
" return function ($y$$) { $y$$; $x$$ };" +
|
||
|
" return function ($x$$) {" +
|
||
|
" $x$$;" +
|
||
|
" return function ($x$$, $y$$) {" +
|
||
|
" $x$$;$x$$;$x$$;" +
|
||
|
" };" +
|
||
|
" };" +
|
||
|
"}");
|
||
|
}
|
||
|
}
|