Simple tests for normalizing parameter type lists

Bug: 195112263
Change-Id: I5e4fd353fd25583d94f6970c8fbdce403e4d71fa
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptMethodTest.java
similarity index 63%
copy from src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
copy to src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptMethodTest.java
index c78ced4..d8fa10c 100644
--- a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptMethodTest.java
@@ -5,16 +5,16 @@
 package com.android.tools.r8.optimize.proto;
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.MethodMatchers.hasParameters;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -22,7 +22,7 @@
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class NormalizeTest extends TestBase {
+public class ProtoNormalizationWithKeptMethodTest extends TestBase {
 
   @Parameter(0)
   public TestParameters parameters;
@@ -37,6 +37,7 @@
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
         .addKeepMainRule(Main.class)
+        .addKeepRules("-keep class " + Main.class.getTypeName() + " { void foo(...); }")
         .addOptionsModification(
             options -> options.testing.enableExperimentalProtoNormalization = true)
         .enableInliningAnnotations()
@@ -47,40 +48,50 @@
         .compile()
         .inspect(
             inspector -> {
-              ClassSubject aClassSubject = inspector.clazz(A.class);
-              assertThat(aClassSubject, isPresent());
-
-              ClassSubject bClassSubject = inspector.clazz(B.class);
-              assertThat(bClassSubject, isPresent());
+              TypeSubject aTypeSubject = inspector.clazz(A.class).asTypeSubject();
+              TypeSubject bTypeSubject = inspector.clazz(B.class).asTypeSubject();
 
               MethodSubject fooMethodSubject =
                   inspector.clazz(Main.class).uniqueMethodWithName("foo");
               assertThat(fooMethodSubject, isPresent());
+              assertThat(fooMethodSubject, hasParameters(bTypeSubject, aTypeSubject));
 
-              String expectedMethodSignature =
-                  "void "
-                      + fooMethodSubject.getFinalName()
-                      + "("
-                      + aClassSubject.getFinalName()
-                      + ", "
-                      + bClassSubject.getFinalName()
-                      + ")";
-              assertEquals(
-                  expectedMethodSignature,
-                  fooMethodSubject.getProgramMethod().getMethodSignature().toString());
+              // TODO(b/195112263): Share parameter type lists with Main.foo(B, A) by rewriting to
+              //  bar(B, A) and baz(B, A).
+              for (String methodName : new String[] {"bar", "baz"}) {
+                MethodSubject methodSubject =
+                    inspector.clazz(Main.class).uniqueMethodWithName(methodName);
+                assertThat(methodSubject, isPresent());
+                assertThat(methodSubject, hasParameters(aTypeSubject, bTypeSubject));
+              }
             })
         .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutputLines("A", "B");
+        .assertSuccessWithOutputLines("A", "B", "A", "B", "A", "B");
   }
 
   static class Main {
 
     public static void main(String[] args) {
       foo(new B(), new A());
+      bar(new B(), new A());
+      baz(new A(), new B());
+    }
+
+    // @Keep
+    @NeverInline
+    static void foo(B b, A a) {
+      System.out.println(a);
+      System.out.println(b);
     }
 
     @NeverInline
-    static void foo(B b, A a) {
+    static void bar(B b, A a) {
+      System.out.println(a);
+      System.out.println(b);
+    }
+
+    @NeverInline
+    static void baz(A a, B b) {
       System.out.println(a);
       System.out.println(b);
     }
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptVirtualMethodTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptVirtualMethodTest.java
new file mode 100644
index 0000000..e9655ba
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithKeptVirtualMethodTest.java
@@ -0,0 +1,118 @@
+// Copyright (c) 2022, 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.optimize.proto;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.MethodMatchers.hasParameters;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ProtoNormalizationWithKeptVirtualMethodTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepClassAndMembersRules(Main.class)
+        .addKeepRules("-keepclassmembers class " + A.class.getTypeName() + " { void foo(...); }")
+        .addOptionsModification(
+            options -> options.testing.enableExperimentalProtoNormalization = true)
+        .enableInliningAnnotations()
+        .enableNoVerticalClassMergingAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject aClassSubject = inspector.clazz(A.class);
+              assertThat(aClassSubject, isPresent());
+
+              ClassSubject bClassSubject = inspector.clazz(B.class);
+              assertThat(bClassSubject, isPresent());
+
+              TypeSubject aTypeSubject = aClassSubject.asTypeSubject();
+              TypeSubject bTypeSubject = bClassSubject.asTypeSubject();
+
+              // A.foo(B, A) is kept.
+              MethodSubject fooMethodSubject = aClassSubject.uniqueMethodWithName("foo");
+              assertThat(fooMethodSubject, isPresent());
+              assertThat(fooMethodSubject, hasParameters(bTypeSubject, aTypeSubject));
+
+              // B.foo(B, A) overrides kept method.
+              MethodSubject otherFooMethodSubject = bClassSubject.uniqueMethodWithName("foo");
+              assertThat(otherFooMethodSubject, isPresent());
+              assertThat(otherFooMethodSubject, hasParameters(bTypeSubject, aTypeSubject));
+            })
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("A", "B", "A", "B");
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      A a = new A();
+      B b = new B();
+      a.foo(b, a);
+      b.foo(b, a);
+      extra(a, b);
+    }
+
+    // @Keep to ensure that the program has parameter lists (A, B) and (B, A), or we will not
+    // optimize in the first place.
+    static void extra(A a, B b) {}
+  }
+
+  @NoVerticalClassMerging
+  static class A {
+
+    // @Keep
+    @NeverInline
+    public void foo(B b, A a) {
+      System.out.println(a);
+      System.out.println(b);
+    }
+
+    @Override
+    public String toString() {
+      return "A";
+    }
+  }
+
+  static class B extends A {
+
+    @NeverInline
+    @Override
+    public void foo(B b, A a) {
+      System.out.println(a);
+      System.out.println(b);
+    }
+
+    @Override
+    public String toString() {
+      return "B";
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
new file mode 100644
index 0000000..e4d6bee
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
@@ -0,0 +1,112 @@
+// Copyright (c) 2022, 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.optimize.proto;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.MethodMatchers.hasParameters;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ProtoNormalizationWithVirtualMethodCollisionTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .addOptionsModification(
+            options -> options.testing.enableExperimentalProtoNormalization = true)
+        .enableInliningAnnotations()
+        .enableNoVerticalClassMergingAnnotations()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject aClassSubject = inspector.clazz(A.class);
+              assertThat(aClassSubject, isPresent());
+
+              ClassSubject bClassSubject = inspector.clazz(B.class);
+              assertThat(bClassSubject, isPresent());
+
+              TypeSubject aTypeSubject = aClassSubject.asTypeSubject();
+              TypeSubject bTypeSubject = bClassSubject.asTypeSubject();
+
+              MethodSubject fooMethodSubject = aClassSubject.uniqueMethodWithName("foo");
+              assertThat(fooMethodSubject, isPresent());
+              assertThat(fooMethodSubject, hasParameters(aTypeSubject, bTypeSubject));
+
+              // TODO(b/173398086): Rewriting B.foo(B, A) to B.foo(A, B) would lead to B.foo()
+              //  starting to override A.foo(A, B). B.foo(B, A) could either be rewritten to
+              //  B.foo$1(A, B) if B.foo(B, A) is not related by overriding to a kept method, or an
+              //  extra unused argument could be appended.
+              MethodSubject otherFooMethodSubject = bClassSubject.uniqueMethodWithName("foo");
+              assertThat(otherFooMethodSubject, isPresent());
+              assertThat(otherFooMethodSubject, hasParameters(bTypeSubject, aTypeSubject));
+            })
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("A", "B", "A", "B");
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      A a = new A();
+      B b = new B();
+      a.foo(a, b);
+      b.foo(b, a);
+    }
+  }
+
+  @NoVerticalClassMerging
+  static class A {
+
+    @NeverInline
+    public void foo(A a, B b) {
+      System.out.println(a);
+      System.out.println(b);
+    }
+
+    @Override
+    public String toString() {
+      return "A";
+    }
+  }
+
+  static class B extends A {
+
+    @NeverInline
+    public void foo(B b, A a) {
+      System.out.println(a);
+      System.out.println(b);
+    }
+
+    @Override
+    public String toString() {
+      return "B";
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithoutSharingTest.java
similarity index 73%
rename from src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
rename to src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithoutSharingTest.java
index c78ced4..e468af8 100644
--- a/src/test/java/com/android/tools/r8/optimize/proto/NormalizeTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithoutSharingTest.java
@@ -5,16 +5,16 @@
 package com.android.tools.r8.optimize.proto;
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.MethodMatchers.hasParameters;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -22,7 +22,7 @@
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class NormalizeTest extends TestBase {
+public class ProtoNormalizationWithoutSharingTest extends TestBase {
 
   @Parameter(0)
   public TestParameters parameters;
@@ -47,27 +47,14 @@
         .compile()
         .inspect(
             inspector -> {
-              ClassSubject aClassSubject = inspector.clazz(A.class);
-              assertThat(aClassSubject, isPresent());
+              TypeSubject aTypeSubject = inspector.clazz(A.class).asTypeSubject();
+              TypeSubject bTypeSubject = inspector.clazz(B.class).asTypeSubject();
 
-              ClassSubject bClassSubject = inspector.clazz(B.class);
-              assertThat(bClassSubject, isPresent());
-
+              // TODO(b/173398086): Should not be normalized as there is no sharing of protos.
               MethodSubject fooMethodSubject =
                   inspector.clazz(Main.class).uniqueMethodWithName("foo");
               assertThat(fooMethodSubject, isPresent());
-
-              String expectedMethodSignature =
-                  "void "
-                      + fooMethodSubject.getFinalName()
-                      + "("
-                      + aClassSubject.getFinalName()
-                      + ", "
-                      + bClassSubject.getFinalName()
-                      + ")";
-              assertEquals(
-                  expectedMethodSignature,
-                  fooMethodSubject.getProgramMethod().getMethodSignature().toString());
+              assertThat(fooMethodSubject, hasParameters(aTypeSubject, bTypeSubject));
             })
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("A", "B");
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
index 4ffcdb4..9be6468 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -77,6 +77,16 @@
   }
 
   @Override
+  public TypeSubject getParameter(int index) {
+    throw new Unreachable("Cannot get the parameter for an absent method");
+  }
+
+  @Override
+  public List<TypeSubject> getParameters() {
+    throw new Unreachable("Cannot get the parameters for an absent method");
+  }
+
+  @Override
   public ProgramMethod getProgramMethod() {
     return null;
   }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index 04f0d52..30b3fb0 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -171,6 +171,10 @@
     return null;
   }
 
+  public TypeSubject asTypeSubject() {
+    return null;
+  }
+
   @Override
   public abstract ClassAccessFlags getAccessFlags();
 
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index 0d62343..cdc420e 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -289,6 +289,11 @@
   }
 
   @Override
+  public TypeSubject asTypeSubject() {
+    return new TypeSubject(codeInspector, dexClass.getType());
+  }
+
+  @Override
   public boolean isAbstract() {
     return dexClass.accessFlags.isAbstract();
   }
@@ -504,10 +509,6 @@
     return dexClass.toSourceString();
   }
 
-  public TypeSubject asTypeSubject() {
-    return new TypeSubject(codeInspector, getDexProgramClass().type);
-  }
-
   @Override
   public KmClassSubject getKmClass() {
     AnnotationSubject annotationSubject = annotation(METADATA_TYPE);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index a41ab17..b99b090 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -124,6 +124,18 @@
   }
 
   @Override
+  public TypeSubject getParameter(int index) {
+    return new TypeSubject(codeInspector, getMethod().getParameter(index));
+  }
+
+  @Override
+  public List<TypeSubject> getParameters() {
+    return getMethod().getParameters().stream()
+        .map(parameter -> new TypeSubject(codeInspector, parameter))
+        .collect(Collectors.toList());
+  }
+
+  @Override
   public ProgramMethod getProgramMethod() {
     return new ProgramMethod(clazz.getDexProgramClass(), getMethod());
   }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodMatchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodMatchers.java
new file mode 100644
index 0000000..8d7e78b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodMatchers.java
@@ -0,0 +1,54 @@
+// Copyright (c) 2022, 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.utils.codeinspector;
+
+import static junit.framework.TestCase.assertEquals;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+public class MethodMatchers {
+
+  public static Matcher<MethodSubject> hasParameters(TypeSubject... expectedParameters) {
+    return hasParameters(Arrays.asList(expectedParameters));
+  }
+
+  public static Matcher<MethodSubject> hasParameters(List<TypeSubject> expectedParameters) {
+    return new TypeSafeMatcher<MethodSubject>() {
+      @Override
+      protected boolean matchesSafely(MethodSubject methodSubject) {
+        if (!methodSubject.isPresent()) {
+          return false;
+        }
+        if (methodSubject.getParameters().size() != expectedParameters.size()) {
+          return false;
+        }
+        for (int i = 0; i < expectedParameters.size(); i++) {
+          TypeSubject actualParameter = methodSubject.getParameter(i);
+          TypeSubject expectedParameter = expectedParameters.get(i);
+          assertEquals(expectedParameter, actualParameter);
+        }
+        return true;
+      }
+
+      @Override
+      public void describeTo(Description description) {
+        description.appendText(
+            "has parameters ("
+                + StringUtils.join(", ", expectedParameters, TypeSubject::getTypeName)
+                + ")");
+      }
+
+      @Override
+      public void describeMismatchSafely(final MethodSubject subject, Description description) {
+        description.appendText("method did not");
+      }
+    };
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index 594b17a..3b7fe05 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.google.common.collect.Streams;
 import java.util.Iterator;
+import java.util.List;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
@@ -51,6 +52,10 @@
 
   public abstract DexEncodedMethod getMethod();
 
+  public abstract TypeSubject getParameter(int index);
+
+  public abstract List<TypeSubject> getParameters();
+
   public abstract ProgramMethod getProgramMethod();
 
   public Iterator<InstructionSubject> iterateInstructions() {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java
index 357c777..5761b99 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2022, 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.
 
@@ -17,6 +17,10 @@
     this.dexType = dexType;
   }
 
+  public String getTypeName() {
+    return dexType.getTypeName();
+  }
+
   @Override
   public boolean isPresent() {
     return true;