| /* |
| * Copyright 2010 Google Inc. |
| * |
| * 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.gwt.dev.jjs.impl; |
| |
| import com.google.gwt.dev.jjs.ast.JMethod; |
| import com.google.gwt.dev.jjs.ast.JProgram; |
| import com.google.gwt.dev.jjs.ast.js.JsniMethodBody; |
| |
| public class PrunerTest extends OptimizerTestBase { |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| runDeadCodeElimination = true; |
| } |
| |
| public void testSmoke() throws Exception { |
| addSnippetClassDecl("static int foo(int i) { return i; }"); |
| |
| addSnippetClassDecl("static void unusedMethod() { }"); |
| addSnippetClassDecl("static void usedMethod() { }"); |
| addSnippetClassDecl("static class UnusedClass { }"); |
| addSnippetClassDecl("static class UninstantiatedClass { int field; void method() {} }"); |
| addSnippetClassDecl("static UninstantiatedClass uninstantiatedField;"); |
| addSnippetClassDecl("static int unusedField;"); |
| addSnippetClassDecl("static int unreadField;"); |
| addSnippetClassDecl("static int unassignedField;"); |
| addSnippetClassDecl("static UninstantiatedClass returnUninstantiatedClass() { return null; }"); |
| addSnippetClassDecl( |
| "interface UsedInterface {", |
| " int unusedConstant = 2;", |
| " int usedConstant = 3;", |
| " void method2();", |
| "}"); |
| addSnippetClassDecl("static class UsedClass implements UsedInterface {", |
| " int field2;", |
| " public void method2() { field2 = usedConstant; }", |
| " UsedClass(UninstantiatedClass c) { }", |
| " UsedClass(UninstantiatedClass c1, UninstantiatedClass c2) { }", |
| "}"); |
| addSnippetClassDecl( |
| "static native void usedNativeMethod(UninstantiatedClass c, UsedClass c2)", |
| "/*-{", |
| " c.@test.EntryPoint.UninstantiatedClass::field = 2;", |
| " c.@test.EntryPoint.UninstantiatedClass::method();", |
| " c2.@test.EntryPoint.UsedClass::field2++;", |
| " c2.@test.EntryPoint.UsedClass::method2();", |
| "}-*/;"); |
| addSnippetClassDecl( |
| "static native void unusedNativeMethod()", |
| "/*-{", |
| "}-*/;"); |
| addSnippetClassDecl("static void methodWithUninstantiatedParam(UninstantiatedClass c) { }"); |
| addSnippetClassDecl("interface UnusedInterface { void foo(); }"); |
| |
| Result result; |
| (result = optimize("void", |
| "usedMethod();", |
| "unreadField = 1;", // should be pruned because it's not read. |
| "foo(unassignedField);", |
| "returnUninstantiatedClass();", |
| "usedNativeMethod(null, null);", |
| "foo(uninstantiatedField.field);", |
| "uninstantiatedField.method();", |
| "methodWithUninstantiatedParam(null);", |
| "new UsedClass(null);", |
| "new UsedClass(returnUninstantiatedClass(), returnUninstantiatedClass());", |
| "UninstantiatedClass localUninstantiated = null;" |
| )).intoString( |
| "EntryPoint.usedMethod();", |
| "EntryPoint.foo(EntryPoint.unassignedField);", |
| "EntryPoint.returnUninstantiatedClass();", |
| "EntryPoint.usedNativeMethod(null, null);", |
| "EntryPoint.foo(null.nullField);", |
| "null.nullMethod();", |
| "EntryPoint.methodWithUninstantiatedParam();", |
| "new EntryPoint$UsedClass();", |
| "new EntryPoint$UsedClass((EntryPoint.returnUninstantiatedClass(), EntryPoint.returnUninstantiatedClass()));" |
| ); |
| |
| assertNotNull(result.findMethod("usedMethod")); |
| // We do not assign to the field, but we use its default value. |
| // Shouldn't be pruned. |
| assertNotNull(result.findField("unassignedField")); |
| assertNotNull(result.findMethod("usedNativeMethod")); |
| assertNotNull(result.findMethod("returnUninstantiatedClass")); |
| assertNotNull(result.findMethod("methodWithUninstantiatedParam")); |
| assertNotNull(result.findClass("EntryPoint$UsedClass")); |
| assertNotNull(result.findClass("EntryPoint$UsedInterface")); |
| |
| assertNull(result.findMethod("unusedMethod")); |
| assertNull(result.findField("unusedField")); |
| assertNull(result.findField("unreadField")); |
| assertNull(result.findClass("EntryPoint$UnusedClass")); |
| assertNull(result.findMethod("unusedNativeMethod")); |
| assertNull(result.findField("uninstantiatedField")); |
| assertNull(result.findClass("EntryPoint$UnusedInterface")); |
| |
| // Class is never instantiated. Should be pruned. |
| assertNull(result.findClass("UninstantiatedClass")); |
| |
| assertEquals( |
| "public static <null> returnUninstantiatedClass(){\n" + |
| " return null;\n" + |
| "}", |
| result.findMethod("returnUninstantiatedClass").toSource()); |
| |
| assertEquals( |
| "public static void methodWithUninstantiatedParam(){\n" + |
| "}", |
| result.findMethod("methodWithUninstantiatedParam").toSource()); |
| |
| assertEquals( |
| "[final <null> nullField, int field2]", |
| ((JsniMethodBody) result.findMethod("usedNativeMethod").getBody()). |
| getJsniFieldRefs().toString()); |
| assertEquals( |
| "[public final <null> nullMethod(), public void method2()]", |
| ((JsniMethodBody) result.findMethod("usedNativeMethod").getBody()). |
| getJsniMethodRefs().toString()); |
| |
| assertEquals( |
| "interface EntryPoint$UsedInterface {\n" + |
| " private static final void $clinit(){\n" + |
| " Object.$clinit();\n" + |
| " }\n" + |
| "\n" + |
| "}", |
| result.findClass("EntryPoint$UsedInterface").toSource()); |
| } |
| |
| @Override |
| protected boolean optimizeMethod(JProgram program, JMethod method) { |
| program.addEntryMethod(findMainMethod(program)); |
| return Pruner.exec(program, true).didChange(); |
| } |
| } |