Update parameter metadata for companion classes
Extend the MethodParameters attribute and the parameter annotations
when moving the default method to the static companion class.
Bug: 189743726
Change-Id: I2e43dfc2d8ba9b16aaceeda649bf658b37eedec8
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
index e1a64b1..651a484 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
@@ -7,6 +7,9 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.graph.DexValue.DexValueArray;
+import com.android.tools.r8.graph.DexValue.DexValueInt;
+import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.structural.StructuralItem;
@@ -199,6 +202,43 @@
return new DexAnnotationSet(rewritten);
}
+ public DexAnnotationSet methodParametersWithFakeThisArguments(DexItemFactory factory) {
+ DexAnnotation[] newAnnotations = null;
+ for (int i = 0; i < annotations.length; i++) {
+ DexAnnotation annotation = annotations[i];
+ if (annotation.annotation.type == factory.annotationMethodParameters) {
+ assert annotation.visibility == DexAnnotation.VISIBILITY_SYSTEM;
+ assert annotation.annotation.elements.length == 2;
+ assert annotation.annotation.elements[0].name.toString().equals("names");
+ assert annotation.annotation.elements[1].name.toString().equals("accessFlags");
+ DexValueArray names = annotation.annotation.elements[0].value.asDexValueArray();
+ DexValueArray accessFlags = annotation.annotation.elements[1].value.asDexValueArray();
+ assert names != null && accessFlags != null;
+ assert names.getValues().length == accessFlags.getValues().length;
+ if (newAnnotations == null) {
+ newAnnotations = new DexAnnotation[annotations.length];
+ System.arraycopy(annotations, 0, newAnnotations, 0, i);
+ }
+ DexValue[] newNames = new DexValue[names.getValues().length + 1];
+ newNames[0] =
+ new DexValueString(
+ factory.createString(DexCode.FAKE_THIS_PREFIX + DexCode.FAKE_THIS_SUFFIX));
+ System.arraycopy(names.getValues(), 0, newNames, 1, names.getValues().length);
+ DexValue[] newAccessFlags = new DexValue[accessFlags.getValues().length + 1];
+ newAccessFlags[0] = DexValueInt.create(0);
+ System.arraycopy(
+ accessFlags.getValues(), 0, newAccessFlags, 1, accessFlags.getValues().length);
+ newAnnotations[i] =
+ DexAnnotation.createMethodParametersAnnotation(newNames, newAccessFlags, factory);
+ } else {
+ if (newAnnotations != null) {
+ newAnnotations[i] = annotation;
+ }
+ }
+ }
+ return newAnnotations == null ? this : new DexAnnotationSet(newAnnotations);
+ }
+
@Override
public String toString() {
return Arrays.toString(annotations);
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index e4f7973..be89c66 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -38,8 +38,8 @@
// DexCode corresponds to code item in dalvik/dex-format.html
public class DexCode extends Code implements StructuralItem<DexCode> {
- static final String FAKE_THIS_PREFIX = "_";
- static final String FAKE_THIS_SUFFIX = "this";
+ public static final String FAKE_THIS_PREFIX = "_";
+ public static final String FAKE_THIS_SUFFIX = "this";
public final int registerSize;
public final int incomingRegisterSize;
diff --git a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
index 7628702..dee2c8d 100644
--- a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
+++ b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
@@ -187,6 +187,17 @@
return new ParameterAnnotationsList(values, parameterCount - values.length);
}
+ public ParameterAnnotationsList withFakeThisParameter() {
+ // If there are no parameter annotations there is no need to add one for the this parameter.
+ if (isEmpty()) {
+ return this;
+ }
+ DexAnnotationSet[] newValues = new DexAnnotationSet[size() + 1];
+ System.arraycopy(values, 0, newValues, 1, size());
+ newValues[0] = DexAnnotationSet.empty();
+ return new ParameterAnnotationsList(newValues, 0);
+ }
+
/**
* Return a new ParameterAnnotationsList that keeps only the annotations matched by {@code
* filter}.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index 2174002..0eebbdb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -256,8 +256,12 @@
methodBuilder
.setAccessFlags(newFlags)
.setGenericSignature(MethodTypeSignature.noSignature())
- .setAnnotations(virtual.annotations())
- .setParameterAnnotationsList(virtual.getParameterAnnotations())
+ .setAnnotations(
+ virtual
+ .annotations()
+ .methodParametersWithFakeThisArguments(appView.dexItemFactory()))
+ .setParameterAnnotationsList(
+ virtual.getParameterAnnotations().withFakeThisParameter())
.setCode(ignored -> virtual.getCode())
.setOnBuildConsumer(
implMethod -> {
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java
index 27dcc8c..43373b9 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java
@@ -5,12 +5,9 @@
import static com.android.tools.r8.TestRuntime.getCheckedInJdk;
import static com.android.tools.r8.TestRuntime.getCheckedInJdk11;
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestCompileResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
@@ -57,6 +54,22 @@
private final String EXPECTED =
StringUtils.lines(
"0", "1", "a: 1", "2", "a: 1", "b: 2", "0", "1", "a: 1", "2", "a: 1", "b: 2");
+ private final String EXPECTED_DESUGARED =
+ StringUtils.lines(
+ "1",
+ "2",
+ "_this: 0",
+ "a: 1",
+ "3",
+ "_this: 0",
+ "a: 1",
+ "b: 2",
+ "0",
+ "1",
+ "a: 1",
+ "2",
+ "a: 1",
+ "b: 2");
@Test
public void testJvm() throws Exception {
@@ -86,17 +99,6 @@
.addProgramFiles(interfaceDesugared)
.setMinApi(parameters.getApiLevel())
.compile()
- // TODO(b/189743726): These warnings should not be there.
- .applyIf(
- parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring(),
- TestCompileResult::assertNoInfoMessages,
- r ->
- r.assertAtLeastOneInfoMessage()
- .assertAllInfoMessagesMatch(
- anyOf(
- containsString(
- "Invalid parameter counts in MethodParameter attributes"),
- containsString("Methods with invalid MethodParameter attributes"))))
.writeToZip();
Path programDesugared =
@@ -112,26 +114,11 @@
.addProgramFiles(programDesugared)
.setMinApi(parameters.getApiLevel())
.compile()
- // TODO(b/189743726): These warnings should not be there.
- .applyIf(
- parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring(),
- TestCompileResult::assertNoInfoMessages,
- r ->
- r.assertAtLeastOneInfoMessage()
- .assertAllInfoMessagesMatch(
- anyOf(
- containsString(
- "Invalid parameter counts in MethodParameter attributes"),
- containsString("Methods with invalid MethodParameter attributes"))))
.run(parameters.getRuntime(), TestRunner.class)
.applyIf(
parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring(),
r -> r.assertSuccessWithOutput(EXPECTED),
- // TODO(b/189743726): Should not fail at runtime (but will have different parameter
- // count for non-static methods when desugared).
- r ->
- r.assertFailureWithErrorThatMatches(
- containsString("Wrong number of parameters in MethodParameters attribute")));
+ r -> r.assertSuccessWithOutput(EXPECTED_DESUGARED));
}
static class A implements I {}