/* * 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.treeshaker.ElementReferenceMapper.MethodReferenceNode; 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 ElementReferenceMapper. * * @author Priyank Malvania */ public class ElementReferenceMapperTest extends GenerationTest { public void testMethodReference() throws IOException { String source = "class A {\n" + " private static interface B {\n" + " String bar();\n" + " }\n" + " private void baz() {\n" + " // nothing\n" + " }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementReferenceMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementReferenceMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementReferenceMap.keySet(); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A"))); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A$B"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A$B", "bar", "()Ljava/lang/String;"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "baz", "()V"))); assertFalse(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "abc", "()V"))); } public void testMethod_AnonymousClassMemberReference() throws IOException { String source = "abstract class B { public void foo() {} }\n" + "class A {\n" + " public void launch() {" + " final B b = new B() {\n" + " @Override" + " public void foo() {}\n" + " };\n" + " b.foo();\n" + " }\n" + " static { new A().launch(); }" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementReferenceMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementReferenceMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementReferenceMap.keySet(); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A"))); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("B"))); //TODO(malvania): Enable testing for unused fields when ElementUtil glitch is fixed //assertTrue(elementSet.contains(ElementReferenceMapper.stitchFieldIdentifier("A", "b"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A$1", "foo", "()V"))); } public void testMethod_InnerClassConstructorReference() throws IOException { String source = "class A {\n" + " class B {\n" + " B(int i) {}\n" + " }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementReferenceMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementReferenceMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementReferenceMap.keySet(); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A"))); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A$B"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A$B", "A$B", "(LA;I)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 testFieldsReference() 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 int abc = 9;\n" // + "}\n"; // // CompilationUnit unit = compileType("test", source); // final HashMap<String, ReferenceNode> elementReferenceMap = new HashMap<>(); // final HashMap<String, Set<String>> overrideMap = new HashMap<>(); // final Set<String> staticSet = new HashSet<>(); // ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementReferenceMap, // staticSet, overrideMap); // mapper.run(); // Set<String> elementSet = elementReferenceMap.keySet(); // // 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"))); //} public void testInitializerReference() throws IOException { String source = "class A {\n" + " static final int baz = 9;\n" + " static { System.out.println(\"foo\"); }\n" + " { System.out.println(\"bar\"); }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementReferenceMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementReferenceMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementReferenceMap.keySet(); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A"))); //TODO(malvania): Enable testing for unused fields when ElementUtil glitch is fixed //assertTrue(elementSet.contains(ElementReferenceMapper.stitchFieldIdentifier("A", "baz"))); } public void testEnumReference() throws IOException { String source = "class A {\n" + " private static void foo() {}\n" + " public enum Thing implements java.io.Serializable {\n" + " THING1(27),\n" + " THING2(89) { void bar() {} },\n" + " THING3 { void bar() { foo(); } };\n" + " private Thing(int x) {}\n" + " private Thing() {}\n" + " }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementReferenceMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementReferenceMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementReferenceMap.keySet(); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A"))); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A$Thing"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "foo", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A$Thing", "A$Thing", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A$Thing", "A$Thing", "(I)V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A$Thing$1", "bar", "()V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A$Thing$2", "bar", "()V"))); } public void testMethodInvocation() throws IOException { String source = "class A {\n" + " private static void foo(String s) {final int bro = 1;}\n" + " private static void bar(String s) {foo(\"boo\");}\n" + " static { bar(\"bro\"); }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementReferenceMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementReferenceMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementReferenceMap.keySet(); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "foo", "(Ljava/lang/String;)V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "bar", "(Ljava/lang/String;)V"))); assertTrue(((MethodReferenceNode) elementReferenceMap.get(ElementReferenceMapper .stitchMethodIdentifier("A", "bar", "(Ljava/lang/String;)V"))) .invokedMethods.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "foo", "(Ljava/lang/String;)V"))); } public void testMethodTraversal() 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 bar(String s) {foo(\"boo\");}\n" + " static { bar(\"zoo\"); }\n" + "}\n"; CompilationUnit unit = compileType("test", source); final HashMap<String, ReferenceNode> elementReferenceMap = new HashMap<>(); final HashMap<String, Set<String>> overrideMap = new HashMap<>(); final Set<String> staticSet = new HashSet<>(); ElementReferenceMapper mapper = new ElementReferenceMapper(unit, elementReferenceMap, staticSet, overrideMap); mapper.run(); Set<String> elementSet = elementReferenceMap.keySet(); assertTrue(elementSet.contains(ElementReferenceMapper.stitchClassIdentifier("A"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "abc", "(Ljava/lang/String;)V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "xyz", "(Ljava/lang/String;)V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "foo", "(Ljava/lang/String;)V"))); assertTrue(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "bar", "(Ljava/lang/String;)V"))); assertFalse(elementSet.contains(ElementReferenceMapper .stitchMethodIdentifier("A", "falseCase", "(Ljava/lang/String;)V"))); } }