Handle parameter type changes in Proguard -if rules

Bug: 110141157
Change-Id: I22b607fa459444752e17249c9c876027caf2ae52
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
index 0a2e4f9..a84afb2 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
@@ -259,9 +259,7 @@
           break;
         }
         for (int i = 0; i < parameters.length; i++) {
-          // TODO(b/110141157): The names of the parameter types may have changed as a result of
-          // vertical class merging. We should use the original type names.
-          if (!arguments.get(i).matches(parameters[i])) {
+          if (!matches(arguments.get(i), parameters[i], appView)) {
             return false;
           }
         }
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
index 32fd8da..6205f85 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
@@ -59,7 +59,6 @@
 }
 
 // TODO(b/110141157):
-// - Add tests where the parameter type of a kept method changes.
 // - Add tests where the type of a kept field changes.
 // - Add tests where fields and methods get renamed due to naming conflicts.
 // - Add tests where the type in a implements/extends clause has changed.
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedParameterTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedParameterTypeTest.java
new file mode 100644
index 0000000..4533cef
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedParameterTypeTest.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.shaking.ifrule.verticalclassmerging;
+
+public class MergedParameterTypeTest extends MergedTypeBaseTest {
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      method(new B());
+    }
+
+    public static void method(A obj) {
+      System.out.print(obj.getClass().getTypeName());
+    }
+  }
+
+  public MergedParameterTypeTest(Backend backend, boolean enableVerticalClassMerging) {
+    super(backend, enableVerticalClassMerging);
+  }
+
+  @Override
+  public Class<?> getTestClass() {
+    return TestClass.class;
+  }
+
+  @Override
+  public String getConditionForProguardIfRule() {
+    return "-if class **$TestClass { void method(**$A); }";
+  }
+
+  @Override
+  public String getExpectedStdout() {
+    return B.class.getTypeName();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java
index f5c8411..9f90bb1 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java
@@ -4,47 +4,12 @@
 
 package com.android.tools.r8.shaking.ifrule.verticalclassmerging;
 
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ir.optimize.Inliner.Reason;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import java.util.Collection;
-import java.util.List;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class MergedReturnTypeTest extends TestBase {
-
-  private static final List<Class> CLASSES =
-      ImmutableList.of(A.class, B.class, C.class, TestClass.class);
-
-  static class A {}
-
-  static class B extends A {
-
-    @Override
-    public String toString() {
-      return "B";
-    }
-  }
-
-  static class C {}
+public class MergedReturnTypeTest extends MergedTypeBaseTest {
 
   static class TestClass {
 
     public static void main(String[] args) {
-      System.out.print(method());
+      System.out.print(method().getClass().getTypeName());
     }
 
     public static A method() {
@@ -52,48 +17,22 @@
     }
   }
 
-  private final Backend backend;
-  private final boolean enableVerticalClassMerging;
-
   public MergedReturnTypeTest(Backend backend, boolean enableVerticalClassMerging) {
-    this.backend = backend;
-    this.enableVerticalClassMerging = enableVerticalClassMerging;
+    super(backend, enableVerticalClassMerging);
   }
 
-  @Parameters(name = "Backend: {0}, vertical class merging: {1}")
-  public static Collection<Object[]> data() {
-    // We don't run this on Proguard, as Proguard does not merge A into B.
-    return ImmutableList.of(
-        new Object[] {Backend.DEX, true},
-        new Object[] {Backend.DEX, false},
-        new Object[] {Backend.CF, true},
-        new Object[] {Backend.CF, false});
+  @Override
+  public Class<?> getTestClass() {
+    return TestClass.class;
   }
 
-  @Test
-  public void testIfRule() throws Exception {
-    String expected = "B";
-    assertEquals(expected, runOnJava(TestClass.class));
-
-    String config =
-        StringUtils.joinLines(
-            "-keep class **$TestClass {",
-            "  public static void main(java.lang.String[]);",
-            "}",
-            "-if class **$TestClass { public static **$A method(); }",
-            "-keep class **$C");
-    AndroidApp output = compileWithR8(readClasses(CLASSES), config, this::configure, backend);
-    assertEquals(expected, runOnVM(output, TestClass.class, backend));
-
-    CodeInspector inspector = new CodeInspector(output);
-    assertThat(inspector.clazz(C.class), isPresent());
+  @Override
+  public String getConditionForProguardIfRule() {
+    return "-if class **$TestClass { **$A method(); }";
   }
 
-  private void configure(InternalOptions options) {
-    options.enableMinification = false;
-    options.enableVerticalClassMerging = enableVerticalClassMerging;
-
-    // TODO(b/110148109): Allow ordinary method inlining when -if rules work with inlining.
-    options.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE);
+  @Override
+  public String getExpectedStdout() {
+    return B.class.getTypeName();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java
new file mode 100644
index 0000000..853394f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java
@@ -0,0 +1,87 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.shaking.ifrule.verticalclassmerging;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ir.optimize.Inliner.Reason;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public abstract class MergedTypeBaseTest extends TestBase {
+
+  private final List<Class> CLASSES = ImmutableList.of(A.class, B.class, C.class, getTestClass());
+
+  static class A {}
+
+  static class B extends A {}
+
+  static class C {}
+
+  private final Backend backend;
+  private final boolean enableVerticalClassMerging;
+
+  public MergedTypeBaseTest(Backend backend, boolean enableVerticalClassMerging) {
+    this.backend = backend;
+    this.enableVerticalClassMerging = enableVerticalClassMerging;
+  }
+
+  @Parameters(name = "Backend: {0}, vertical class merging: {1}")
+  public static Collection<Object[]> data() {
+    // We don't run this on Proguard, as Proguard does not merge A into B.
+    return ImmutableList.of(
+        new Object[] {Backend.DEX, true},
+        new Object[] {Backend.DEX, false},
+        new Object[] {Backend.CF, true},
+        new Object[] {Backend.CF, false});
+  }
+
+  public abstract Class<?> getTestClass();
+
+  public abstract String getConditionForProguardIfRule();
+
+  public abstract String getExpectedStdout();
+
+  @Test
+  public void testIfRule() throws Exception {
+    String expected = getExpectedStdout();
+    assertEquals(expected, runOnJava(getTestClass()));
+
+    String config =
+        StringUtils.joinLines(
+            "-keep class " + getTestClass().getTypeName() + " {",
+            "  public static void main(java.lang.String[]);",
+            "}",
+            getConditionForProguardIfRule(),
+            "-keep class " + C.class.getTypeName());
+    AndroidApp output = compileWithR8(readClasses(CLASSES), config, this::configure, backend);
+    assertEquals(expected, runOnVM(output, getTestClass(), backend));
+
+    CodeInspector inspector = new CodeInspector(output);
+    assertThat(inspector.clazz(MergedReturnTypeTest.C.class), isPresent());
+  }
+
+  private void configure(InternalOptions options) {
+    options.enableMinification = false;
+    options.enableVerticalClassMerging = enableVerticalClassMerging;
+
+    // TODO(b/110148109): Allow ordinary method inlining when -if rules work with inlining.
+    options.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE);
+  }
+}