/* * 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.devtools.treeshaker; import com.google.devtools.j2objc.GenerationTest; import com.google.devtools.j2objc.ast.CompilationUnit; import com.google.devtools.j2objc.util.CodeReferenceMap; import com.google.devtools.j2objc.util.CodeReferenceMap.Builder; import com.google.devtools.treeshaker.ElementReferenceMapper.ReferenceNode; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Set; /** * Unit tests for UnusedCodeTracker. * * @author Priyank Malvania */ public class UnusedCodeTrackerTest extends GenerationTest { public void testUnusedMethod() throws IOException { String source = "class A {\n" + " private static void abc(String s) {}\n" + " private static void xyz(String s) {abc(\"goo\");}\n" + " private static void foo(String s) {xyz(\"woo\");}\n" + " private static void unused(String s) {foo(\"boo\");}\n" + " static { foo(\"zoo\"); }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "foo", "(Ljava/lang/String;)V")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "xyz", "(Ljava/lang/String;)V")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "abc", "(Ljava/lang/String;)V")).reachable); assertFalse(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "unused", "(Ljava/lang/String;)V")).reachable); } //Check for assumptions: In this case, a static block's class does not get marked as true //TODO(malvania): Add static block used test public void testUnusedClass() throws IOException { String source = "class A {\n" + " public static void abc(String s) {}\n" + "}" + "class B {\n" + " static { A.abc(\"zoo\"); }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); assertTrue(elementMap.get(ElementReferenceMapper.stitchClassIdentifier("A")).reachable); assertFalse(elementMap.get(ElementReferenceMapper.stitchClassIdentifier("B")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "abc", "(Ljava/lang/String;)V")).reachable); } public void testUsedStaticNestedClasses() throws IOException { String source = "class A {\n" + " static { B.abc(\"zoo\"); }\n" + " static class B {\n" + " public static void abc(String s) {}\n" + " }\n" + " class C {\n" + " public void xyz(String s) {}\n" + " }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); assertFalse(elementMap.get(ElementReferenceMapper.stitchClassIdentifier("A")).reachable); assertTrue(elementMap.get(ElementReferenceMapper.stitchClassIdentifier("A$B")).reachable); assertFalse(elementMap.get(ElementReferenceMapper.stitchClassIdentifier("A$C")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A$B", "abc", "(Ljava/lang/String;)V")).reachable); assertFalse(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A$C", "xyz", "(Ljava/lang/String;)V")).reachable); } public void testUsedNonStaticNestedClasses() throws IOException { String source = "class A {\n" + " static { new A().new B().abc(\"zoo\"); }\n" + " class B {\n" + " public void abc(String s) {}\n" + " }\n" + " class C {\n" + " public void xyz(String s) {}\n" + " }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); assertTrue(elementMap.get(ElementReferenceMapper.stitchClassIdentifier("A")).reachable); assertTrue(elementMap.get(ElementReferenceMapper.stitchClassIdentifier("A$B")).reachable); assertFalse(elementMap.get(ElementReferenceMapper.stitchClassIdentifier("A$C")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A$B", "abc", "(Ljava/lang/String;)V")).reachable); assertFalse(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A$C", "xyz", "(Ljava/lang/String;)V")).reachable); } public void testUnusedSubclassInCodeReferenceMap() throws IOException { String source = "class A {\n" + " static { B.abc(\"zoo\"); }\n" + " static class B {\n" + " public static void abc(String s) {}\n" + " }\n" + " class C {\n" + " public void xyz(String s) {}\n" + " }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); CodeReferenceMap unusedCodeMap = tracker.buildTreeShakerMap(); assertTrue(unusedCodeMap.containsClass("A$C")); assertTrue(unusedCodeMap.containsMethod("A$C", "xyz", "(Ljava/lang/String;)V")); } //TODO(malvania): Enable testing for unused fields when ElementUtil glitch is fixed and fields // are tracked again. (See ElementReferenceMapper line 183, fields comment.) //public void testUnusedField() throws IOException { // String source = "import static java.lang.System.out;\n" // + "import static java.lang.System.in;\n" // + "class A {\n" // + " private static final int foo = 1;\n" // + " public static final String bar = \"bar\";\n" // + " static final double pi = 3.2; // in Indiana only\n" // + " final String baz = null, bah = \"123\";\n" // + " private static int abc = 9;\n" // + " private static void foo() {abc = 10;}" // + " static {foo();}" // + "}\n"; // // CompilationUnit unit = compileType("test", source); // final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); // final HashMap<String, Set<String>> overrideMap = new HashMap<>(); // final Set<String> staticSet = new HashSet<>(); // ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, // overrideMap); // mapper.run(); // Set<String> elementSet = elementMap.keySet(); // UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, // overrideMap); // tracker.markUsedElements(); // // assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A"))); // assertTrue(elementSet.contains(ElementReferenceMapper.stitchFieldIdentifier("A", "foo"))); // assertTrue(elementSet.contains(ElementReferenceMapper.stitchFieldIdentifier("A", "bar"))); // assertTrue(elementSet.contains(ElementReferenceMapper.stitchFieldIdentifier("A", "pi"))); // assertTrue(elementSet.contains(ElementReferenceMapper.stitchFieldIdentifier("A", "baz"))); // assertTrue(elementSet.contains(ElementReferenceMapper.stitchFieldIdentifier("A", "bah"))); // assertTrue(elementSet.contains(ElementReferenceMapper.stitchFieldIdentifier("A", "abc"))); // // //TODO(malvania): Add necessary checks after visiting FieldAccess to check used/unused fields //} public void testUsedStaticlyCalledConstructor() throws IOException { String source = "class A {\n" + " public A() {bar = 2;}" + " private int bar = 1;\n" + "}\n" + "class B {\n" + " public static void foo(A a) {}\n" + " static {foo(new A());}" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); CodeReferenceMap unusedCodeMap = tracker.buildTreeShakerMap(); assertFalse(unusedCodeMap.containsClass("A")); assertFalse(unusedCodeMap.containsMethod("B", "foo", "(LA;)V")); } public void testPublicFieldInUnusedClass() throws IOException { String source = "class A {\n" + " public int bar = 1;\n" + "}\n" + "class B {\n" + " private int baz = 2;\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); CodeReferenceMap unusedCodeMap = tracker.buildTreeShakerMap(); assertFalse(unusedCodeMap.containsClass("A")); assertTrue(unusedCodeMap.containsClass("B")); } public void testUnusedConstructor() throws IOException { String source = "class A {\n" + " public A() {bar = 2;}" + " public A(int i) {bar = i;}" + " private int bar = 1;\n" + "}\n" + "class B {\n" + " public static void foo() {new A();}\n" + " static {foo();}" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementMap.keySet(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); CodeReferenceMap unusedCodeMap = tracker.buildTreeShakerMap(); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "<init>", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "<init>", "(I)V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("B", "foo", "()V"))); assertFalse(unusedCodeMap.containsClass("A")); assertFalse(unusedCodeMap.containsMethod("B", "foo", "()V")); assertFalse(unusedCodeMap.containsMethod("A", "<init>", "()V")); assertTrue(unusedCodeMap.containsMethod("A", "<init>", "(I)V")); } public void testConstructorInvocation() throws IOException { String source = "class A {\n" + " public A() {this(true);}" + " public A(boolean b) {bar = 0;}" + " public A(int i) {bar = i;}" + " private int bar = 1;\n" + "}\n" + "class B {\n" + " public static void foo() {new A();}\n" + " static {foo();}" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementMap.keySet(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); CodeReferenceMap unusedCodeMap = tracker.buildTreeShakerMap(); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "<init>", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "<init>", "(Z)V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "<init>", "(I)V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("B", "foo", "()V"))); assertFalse(unusedCodeMap.containsClass("A")); assertFalse(unusedCodeMap.containsMethod("B", "foo", "()V")); assertFalse(unusedCodeMap.containsMethod("A", "<init>", "()V")); assertFalse(unusedCodeMap.containsMethod("A", "<init>", "(Z)V")); assertTrue(unusedCodeMap.containsMethod("A", "<init>", "(I)V")); } public void testSuperConstructorInvocation() throws IOException { String source = "class A {\n" + " public A() {this(true);}" + " public A(boolean b) {bar = 0;}" + " public A(int i) {bar = i;}" + " private int bar = 1;\n" + "}\n" + "class B extends A {\n" + " public B() {super(1);}\n" + " static {new B();}" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementMap.keySet(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); CodeReferenceMap unusedCodeMap = tracker.buildTreeShakerMap(); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "<init>", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "<init>", "(Z)V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "<init>", "(I)V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("B", "<init>", "()V"))); assertFalse(unusedCodeMap.containsClass("A")); assertFalse(unusedCodeMap.containsMethod("B", "<init>", "()V")); assertFalse(unusedCodeMap.containsMethod("A", "<init>", "(I)V")); assertTrue(unusedCodeMap.containsMethod("A", "<init>", "(Z)V")); assertTrue(unusedCodeMap.containsMethod("A", "<init>", "()V")); } public void testChainedMethodCalls() throws IOException { String source = "class A {\n" + " public static void foo() {}\n" + " public static void launch() {new D().xyz().bar().abc().foo();\n" + " new E();}\n" + " static {launch();}" + "}\n" + "class B {\n" + " public static A abc() {return new A();}\n" + "}\n" + "class C {\n" + " public static B bar() {return new B();}\n" + "}\n" + "class D {\n" + " public static C xyz() {return new C();}\n" + "}\n" + "class E {\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementMap.keySet(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A"))); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("B"))); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("C"))); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("D"))); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("E"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "<init>", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("B", "<init>", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("C", "<init>", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("D", "<init>", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "foo", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("B", "abc", "()LA;"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("C", "bar", "()LB;"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("D", "xyz", "()LC;"))); } public void testUnusedMethodCallingMethods() throws IOException { String source = "class A {\n" + " private static void abc(String s) {}\n" + " private static void xyz(String s) {abc(\"goo\");}\n" + " private static void foo(String s) {xyz(\"woo\");}\n" + " private static void unused2(String s) {foo(\"boo\");}\n" + " private static void unused(String s) {unused2(\"boo\");}\n" + " static { foo(\"zoo\"); }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "foo", "(Ljava/lang/String;)V")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "xyz", "(Ljava/lang/String;)V")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "abc", "(Ljava/lang/String;)V")).reachable); assertFalse(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "unused", "(Ljava/lang/String;)V")).reachable); assertFalse(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "unused2", "(Ljava/lang/String;)V")).reachable); } public void testUnusedMethodsCycle() throws IOException { String source = "class A {\n" + " private static void abc(String s) {}\n" + " private static void xyz(String s) {abc(\"goo\");}\n" + " private static void foo(String s) {xyz(\"woo\");}\n" + " private static void unused2(String s) {unused(\"boo\");}\n" + " private static void unused(String s) {unused2(\"boo\");}\n" + " static { foo(\"zoo\"); }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "foo", "(Ljava/lang/String;)V")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "xyz", "(Ljava/lang/String;)V")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "abc", "(Ljava/lang/String;)V")).reachable); assertFalse(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "unused", "(Ljava/lang/String;)V")).reachable); assertFalse(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "unused2", "(Ljava/lang/String;)V")).reachable); } public void testInputMethodsKept() throws IOException { String source = "class A {\n" + " private static void abc(String s) {}\n" + " private static void xyz(String s) {}\n" + " private static void foo(String s) {xyz(\"woo\");}\n" + "}\n"; Builder builder = CodeReferenceMap.builder(); builder.addMethod("A", "abc", "(Ljava/lang/String;)V"); builder.addMethod("A", "xyz", "(Ljava/lang/String;)V"); CodeReferenceMap inputCodeMap = builder.build(); CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(inputCodeMap); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "abc", "(Ljava/lang/String;)V")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "xyz", "(Ljava/lang/String;)V")).reachable); assertFalse(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "foo", "(Ljava/lang/String;)V")).reachable); } public void testPublicMethodsInInputClasses() throws IOException { String source = "class A {\n" + " public static void abc(String s) {}\n" + " public static void xyz(String s) {}\n" + " private static void foo(String s) {xyz(\"woo\");}\n" + "}\n"; Builder builder = CodeReferenceMap.builder(); builder.addClass("A"); CodeReferenceMap inputCodeMap = builder.build(); CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementMap, staticSet, overrideMap); mapper.run(); UnusedCodeTracker tracker = new UnusedCodeTracker(unit.getEnv(), elementMap, staticSet, overrideMap); tracker.markUsedElements(inputCodeMap); CodeReferenceMap unusedCodeMap = tracker.buildTreeShakerMap(); assertFalse(unusedCodeMap.containsClass("A")); assertFalse(unusedCodeMap.containsMethod("A", "abc", "(Ljava/lang/String;)V")); assertFalse(unusedCodeMap.containsMethod("A", "xyz", "(Ljava/lang/String;)V")); assertTrue(unusedCodeMap.containsMethod("A", "foo", "(Ljava/lang/String;)V")); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "abc", "(Ljava/lang/String;)V")).reachable); assertTrue(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "xyz", "(Ljava/lang/String;)V")).reachable); assertFalse(elementMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "foo", "(Ljava/lang/String;)V")).reachable); } //TODO(malvania): Consult: //Any custom type in parameters must be created by calling some constructor/initializer? public void testUnusedType() throws IOException { //TODO(malvania): Add test for unused types after visiting VariableDeclarationExpression } }