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/MaybeReachingVariableUseTest.java
github-classroom[bot] e42e547e48
Initial commit
2023-04-25 11:33:41 +00:00

173 lines
5.6 KiB
Java

/*
* Copyright 2009 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.common.collect.Lists;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.rhino.Node;
import junit.framework.TestCase;
import java.util.Collection;
import java.util.List;
/**
* Tests for {@link MaybeReachingVariableUse}.
*
*/
public class MaybeReachingVariableUseTest extends TestCase {
private MaybeReachingVariableUse useDef = null;
private Node def = null;
private List<Node> uses = null;
/*
* The test cases consist of a short code snippet that has an instruction
* labeled with D and one or more with label starting with U. When assertMatch
* is called, the test suite verifies that all the uses with label starting
* with U is reachable to the definition label at D.
*/
public void testStraightLine() {
assertMatch("D:var x=1; U: x");
assertMatch("var x; D:x=1; U: x");
assertNotMatch("D:var x=1; x = 2; U: x");
assertMatch("var x=1; D:x=2; U: x");
assertNotMatch("U:x; D:var x = 1");
assertMatch("D: var x = 1; var y = 2; y; U:x");
}
public void testIf() {
assertMatch("var x; if(a){ D:x=1 }else { x=2 }; U:x");
assertMatch("var x; if(a){ x=1 }else { D:x=2 }; U:x");
assertMatch("D:var x=1; if(a){ U1: x }else { U2: x };");
}
public void testLoops() {
assertMatch("var x=0; while(a){ D:x=1 }; U:x");
assertMatch("var x=0; for(;;) { D:x=1 }; U:x");
assertMatch("D:var x=1; while(a) { U:x }");
assertMatch("D:var x=1; for(;;) { U:x }");
}
public void testConditional() {
assertMatch("var x=0; var y; D:(x=1)&&y; U:x");
assertMatch("var x=0; var y; D:y&&(x=1); U:x");
assertMatch("var x=0; var y=0; D:(x=1)&&(y=0); U:x");
assertMatch("var x=0; var y=0; D:(y=0)&&(x=1); U:x");
assertNotMatch("D: var x=0; var y=0; (x=1)&&(y=0); U:x");
assertMatch("D: var x=0; var y=0; (y=1)&&((y=2)||(x=1)); U:x");
assertMatch("D: var x=0; var y=0; (y=0)&&(x=1); U:x");
}
public void testUseAndDefInSameInstruction() {
assertNotMatch("D:var x=0; U:x=1,x");
assertMatch("D:var x=0; U:x,x=1");
}
public void testAssignmentInExpressions() {
assertMatch("var x=0; D:foo(bar(x=1)); U:x");
assertMatch("var x=0; D:foo(bar + (x = 1)); U:x");
}
public void testHook() {
assertMatch("var x=0; D:foo() ? x=1 : bar(); U:x");
assertMatch("var x=0; D:foo() ? x=1 : x=2; U:x");
}
public void testAssignmentOps() {
assertNotMatch("D: var x = 0; U: x = 100");
assertMatch("D: var x = 0; U: x += 100");
assertMatch("D: var x = 0; U: x -= 100");
}
public void testInc() {
assertMatch("D: var x = 0; U:x++");
assertMatch("var x = 0; D:x++; U:x");
}
public void testForIn() {
// Uses within FOR-IN header are hard to test. They are covered
// by the tests in the flow sensitive inliner.
assertNotMatch("D: var x = [], foo; U: for (x in foo) { }");
assertNotMatch("D: var x = [], foo; for (x in foo) { U:x }");
assertMatch("var x = [], foo; D: for (x in foo) { U:x }");
}
public void testTryCatch() {
assertMatch(
"D: var x = 1; " +
"try { U: var y = foo() + x; } catch (e) {} " +
"U: var z = x;");
}
/**
* The def of x at D: may be used by the read of x at U:.
*/
private void assertMatch(String src) {
computeUseDef(src);
Collection<Node> result = useDef.getUses("x", def);
assertTrue(result.size() == uses.size());
assertTrue(result.containsAll(uses));
}
/**
* The def of x at D: is not used by the read of x at U:.
*/
private void assertNotMatch(String src) {
computeUseDef(src);
assertFalse(useDef.getUses("x", def).contains(uses));
}
/**
* Computes reaching use on given source.
*/
private void computeUseDef(String src) {
Compiler compiler = new Compiler();
src = "function _FUNCTION(param1, param2){" + src + "}";
Node n = compiler.parseTestCode(src).getFirstChild();
assertEquals(0, compiler.getErrorCount());
Scope scope = new SyntacticScopeCreator(compiler).createScope(n, null);
ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, true);
cfa.process(null, n);
ControlFlowGraph<Node> cfg = cfa.getCfg();
useDef = new MaybeReachingVariableUse(cfg, scope, compiler);
useDef.analyze();
def = null;
uses = Lists.newArrayList();
new NodeTraversal(compiler,new LabelFinder()).traverse(n);
assertNotNull("Code should have an instruction labeled D", def);
assertFalse("Code should have an instruction labeled starting withing U",
uses.isEmpty());
}
/**
* Finds the D: and U: label and store which node they point to.
*/
private class LabelFinder extends AbstractPostOrderCallback {
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.isLabel()) {
if (n.getFirstChild().getString().equals("D")) {
def = n.getLastChild();
} else if (n.getFirstChild().getString().startsWith("U")) {
uses.add(n.getLastChild());
}
}
}
}
}