/* * Copyright 2015 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.core.ext.TreeLogger; import com.google.gwt.dev.javac.testing.impl.JavaResourceBase; import com.google.gwt.dev.javac.testing.impl.MockJavaResource; import com.google.gwt.dev.jjs.SourceInfo; import com.google.gwt.dev.jjs.ast.JMethod; import com.google.gwt.dev.jjs.ast.JProgram; import com.google.gwt.dev.jjs.ast.JType; import com.google.gwt.thirdparty.guava.common.collect.HashMultimap; import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet; import com.google.gwt.thirdparty.guava.common.collect.Multimap; /** * Test for {@link ImplicitUpcastAnalyzer}. */ public class ImplicitUpcastAnalyzerTest extends OptimizerTestBase { // TODO(rluble): populate with unit tests for all upcast scenarios. // Currently only upcasts due to overriding are tested here. public void testOverrides() throws Exception { final MockJavaResource A = JavaResourceBase.createMockJavaResource("test.A", "package test;", "public class A {", " public A m() { return new B(); } ", "}"); final MockJavaResource I = JavaResourceBase.createMockJavaResource("test.I", "package test;", "public interface I {", " public A m(); ", "}"); final MockJavaResource B = JavaResourceBase.createMockJavaResource("test.B", "package test;", "public class B extends A implements I {", " public A m() { return new B(); } ", "}"); final MockJavaResource C = JavaResourceBase.createMockJavaResource("test.C", "package test;", "public class C implements I {", " public A m() { return new A(); } ", "}"); addAll(A, I, B, C); Result result = optimize("void", "new A().m(); new B().m();"); Multimap<JType, JType> upcastTypesByType = computeImplicitUpcasts(result.getOptimizedProgram()); JType classA = result.findClass("A"); JType classB = result.findClass("B"); assertMapsToAll(upcastTypesByType, classB, classA); } public void testTightening() throws Exception { final MockJavaResource A = JavaResourceBase.createMockJavaResource("test.A", "package test;", "public class A {", " public A m() { return new B(); } ", "}"); final MockJavaResource I = JavaResourceBase.createMockJavaResource("test.I", "package test;", "public interface I {", " public A m(); ", "}"); final MockJavaResource B = JavaResourceBase.createMockJavaResource("test.B", "package test;", "public class B extends A implements I {", " public A m() { return new B(); } ", "}"); final MockJavaResource C = JavaResourceBase.createMockJavaResource("test.C", "package test;", "public class C implements I {", " public A m() { return new A(); } ", "}"); addAll(A, I, B, C); // Variable a will be typed by a non null analysis type. Result result = optimize("void", "A a = new A(); a = new B(); a.m();"); Multimap<JType, JType> upcastTypesByType = computeImplicitUpcasts(result.getOptimizedProgram()); JType classA = result.findClass("A"); JType classB = result.findClass("B"); assertMapsToAll(upcastTypesByType, classB, classA); } private void assertMapsToAll(Multimap<JType, JType> upcastTypesByType, JType fromType, JType... toTypes) { assertEquals(ImmutableSet.copyOf(toTypes), upcastTypesByType.get(fromType)); } private Multimap<JType, JType> computeImplicitUpcasts(JProgram program) { final Multimap<JType, JType> upcastTypesByType = HashMultimap.create(); ImplicitUpcastAnalyzer implicitUpcastAnalyzer = new ImplicitUpcastAnalyzer(program) { @Override protected void processImplicitUpcast(JType fromType, JType destType, SourceInfo info) { upcastTypesByType.put(fromType.getUnderlyingType(), destType.getUnderlyingType()); } }; implicitUpcastAnalyzer.accept(program); return upcastTypesByType; } @Override protected boolean doOptimizeMethod(TreeLogger logger, JProgram program, JMethod method) { program.addEntryMethod(findMainMethod(program)); TypeTightener.exec(program); return false; } }