Version 1.6.62
Cherry-pick: Ensure that the marker for identifier name strings is set correctly
Manually resolved conflicts in:
src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
CL: https://r8-review.googlesource.com/c/r8/+/47869
Bug: 148021799
Change-Id: I08953afecad297ead6c7f97d3f4f44c84eaef999
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 034b2f8..a68d18d 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.6.61";
+ public static final String LABEL = "1.6.62";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 90c2a58..2a01243 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -50,6 +50,7 @@
import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MutableCallSiteOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.UpdatableMethodOptimizationInfo;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.ir.synthetic.CfEmulateInterfaceSyntheticSourceCodeProvider;
@@ -1158,15 +1159,18 @@
public void copyMetadata(DexEncodedMethod from) {
checkIfObsolete();
- // Record that the current method uses identifier name string if the inlinee did so.
- if (from.getOptimizationInfo().useIdentifierNameString()) {
- getMutableOptimizationInfo().markUseIdentifierNameString();
- }
if (from.classFileVersion > classFileVersion) {
upgradeClassFileVersion(from.getClassFileVersion());
}
}
+ public void copyMetadata(DexEncodedMethod from, OptimizationFeedback feedback) {
+ if (from.getOptimizationInfo().useIdentifierNameString()) {
+ feedback.markUseIdentifierNameString(this);
+ }
+ copyMetadata(from);
+ }
+
private static Builder builder(DexEncodedMethod from) {
return new Builder(from);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
index 62a9bb5..a01d2dd 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
@@ -166,7 +166,6 @@
new NewArrayEmpty(newObjectsValue, sizeValue, appView.dexItemFactory().objectArrayType));
// Populate the `objects` array.
- boolean hasIntroducedIdentifierNameString = false;
for (int i = 0; i < objects.size(); i++) {
Value indexValue = instructionIterator.insertConstIntInstruction(code, appView.options(), i);
Instruction materializingInstruction = objects.get(i).buildIR(appView, code);
@@ -174,20 +173,12 @@
instructionIterator.add(
new ArrayPut(
MemberType.OBJECT, newObjectsValue, indexValue, materializingInstruction.outValue()));
-
- if (materializingInstruction.isDexItemBasedConstString()) {
- hasIntroducedIdentifierNameString = true;
- }
}
// Pass the newly created `objects` array to RawMessageInfo.<init>(...) or
// GeneratedMessageLite.newMessageInfo().
setObjectsValueForMessageInfoConstructionInvoke(
newMessageInfoInvoke, newObjectsValue, references);
-
- if (hasIntroducedIdentifierNameString) {
- method.getMutableOptimizationInfo().markUseIdentifierNameString();
- }
}
public static InvokeMethod getNewMessageInfoInvoke(IRCode code, ProtoReferences references) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
index a8b0e60..8af9977 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
@@ -606,9 +606,6 @@
public void add(com.android.tools.r8.ir.code.Instruction instr, Instruction dex) {
assert !instr.isGoto();
- assert isBuildingForComparison()
- || !instr.isDexItemBasedConstString()
- || ir.method.getOptimizationInfo().useIdentifierNameString();
add(instr, new FixedSizeInfo(instr, dex));
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 883fb9f..ff09969 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -1158,7 +1158,6 @@
public void addDexItemBasedConstString(
int dest, DexReference item, NameComputationInfo<?> nameComputationInfo) {
- assert method.getOptimizationInfo().useIdentifierNameString();
TypeLatticeElement typeLattice =
TypeLatticeElement.stringClassType(appView, definitelyNotNull());
ThrowingInfo throwingInfo = throwingInfoForConstStrings();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 7dffe9d..fe31d86 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -51,6 +51,7 @@
import com.android.tools.r8.ir.desugar.D8NestBasedAccessDesugaring;
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor;
import com.android.tools.r8.ir.desugar.LambdaRewriter;
import com.android.tools.r8.ir.desugar.StringConcatRewriter;
import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
@@ -109,6 +110,7 @@
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -413,12 +415,13 @@
private void desugarInterfaceMethods(
Builder<?> builder,
- InterfaceMethodRewriter.Flavor includeAllResources,
+ OptimizationFeedback feedback,
+ Flavor includeAllResources,
ExecutorService executorService)
throws ExecutionException {
if (interfaceMethodRewriter != null) {
interfaceMethodRewriter.desugarInterfaceMethods(
- builder, includeAllResources, executorService);
+ builder, feedback, includeAllResources, executorService);
}
}
@@ -456,7 +459,7 @@
desugarNestBasedAccess(builder, executor);
synthesizeLambdaClasses(builder, executor);
- desugarInterfaceMethods(builder, ExcludeDexResources, executor);
+ desugarInterfaceMethods(builder, simpleOptimizationFeedback, ExcludeDexResources, executor);
synthesizeTwrCloseResourceUtilityClass(builder, executor);
synthesizeJava8UtilityClass(builder, executor);
processCovariantReturnTypeAnnotations(builder);
@@ -714,7 +717,8 @@
synthesizeLambdaClasses(builder, executorService);
printPhase("Interface method desugaring");
- desugarInterfaceMethods(builder, IncludeAllResources, executorService);
+ desugarInterfaceMethods(builder, feedback, IncludeAllResources, executorService);
+ feedback.updateVisibleOptimizationInfo();
printPhase("Twr close resource utility class synthesis");
synthesizeTwrCloseResourceUtilityClass(builder, executorService);
@@ -1433,22 +1437,6 @@
codeRewriter.workaroundNumberConversionRegisterAllocationBug(code);
}
- // Either marked by IdentifierNameStringMarker or name reflection, or propagated from inlinee,
- // Then, make it visible to IdentifierMinifier.
- // Note that we place this at the end of IR processing because inlinee can be inlined by
- // Inliner, ClassInliner, or future optimizations that use the inlining machinery.
- if (method.getOptimizationInfo().useIdentifierNameString()) {
- // If it is optimized, e.g., moved to default values of static fields or even removed by dead
- // code remover, we can save future computation in IdentifierMinifier.
- if (Streams.stream(code.instructionIterator())
- .anyMatch(Instruction::isDexItemBasedConstString)) {
- feedback.markUseIdentifierNameString(method);
- }
- } else {
- assert Streams.stream(code.instructionIterator())
- .noneMatch(Instruction::isDexItemBasedConstString);
- }
-
printMethod(code, "Optimized IR (SSA)", previous);
finalizeIR(method, code, feedback);
}
@@ -1575,6 +1563,17 @@
}
}
+ public void collectIdentifierNameStringUse(
+ DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
+ Iterator<Instruction> iterator = code.instructionIterator();
+ while (iterator.hasNext()) {
+ if (iterator.next().isDexItemBasedConstString()) {
+ feedback.markUseIdentifierNameString(method);
+ break;
+ }
+ }
+ }
+
private void computeReturnValueOnlyDependsOnArguments(
OptimizationFeedback feedback, DexEncodedMethod method, IRCode code) {
if (!options.enableDeterminismAnalysis) {
@@ -1612,6 +1611,7 @@
}
private void finalizeIR(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
+ collectIdentifierNameStringUse(method, code, feedback);
code.traceBlocks();
if (options.isGeneratingClassFiles()) {
finalizeToCf(method, code, feedback);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 0cb8a52..40b3bfb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -37,6 +37,7 @@
import com.android.tools.r8.ir.code.InvokeSuper;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.DefaultMethodsHelper.Collection;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.position.MethodPosition;
@@ -956,6 +957,7 @@
*/
public void desugarInterfaceMethods(
Builder<?> builder,
+ OptimizationFeedback feedback,
Flavor flavour,
ExecutorService executorService)
throws ExecutionException {
@@ -973,7 +975,8 @@
// make original default methods abstract, remove bridge methods, create dispatch
// classes if needed.
AppInfo appInfo = appView.appInfo();
- for (Entry<DexType, DexProgramClass> entry : processInterfaces(builder, flavour).entrySet()) {
+ for (Entry<DexType, DexProgramClass> entry :
+ processInterfaces(builder, feedback, flavour).entrySet()) {
// Don't need to optimize synthesized class since all of its methods
// are just moved from interfaces and don't need to be re-processed.
DexProgramClass synthesizedClass = entry.getValue();
@@ -1003,9 +1006,10 @@
&& clazz.isInterface() == mustBeInterface;
}
- private Map<DexType, DexProgramClass> processInterfaces(Builder<?> builder, Flavor flavour) {
+ private Map<DexType, DexProgramClass> processInterfaces(
+ Builder<?> builder, OptimizationFeedback feedback, Flavor flavour) {
NestedGraphLense.Builder graphLensBuilder = GraphLense.builder();
- InterfaceProcessor processor = new InterfaceProcessor(appView, this);
+ InterfaceProcessor processor = new InterfaceProcessor(appView, this, feedback);
for (DexProgramClass clazz : builder.getProgramClasses()) {
if (shouldProcess(clazz, flavour, true)) {
processor.process(clazz.asProgramClass(), graphLensBuilder);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 8b8ef05..f3257e2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.ir.code.Invoke.Type;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.origin.SynthesizedOrigin;
@@ -51,13 +52,16 @@
private final AppView<?> appView;
private final InterfaceMethodRewriter rewriter;
+ private final OptimizationFeedback feedback;
// All created companion and dispatch classes indexed by interface type.
final Map<DexType, DexProgramClass> syntheticClasses = new IdentityHashMap<>();
- InterfaceProcessor(AppView<?> appView, InterfaceMethodRewriter rewriter) {
+ InterfaceProcessor(
+ AppView<?> appView, InterfaceMethodRewriter rewriter, OptimizationFeedback feedback) {
this.appView = appView;
this.rewriter = rewriter;
+ this.feedback = feedback;
}
void process(DexProgramClass iface, NestedGraphLense.Builder graphLensBuilder) {
@@ -91,6 +95,7 @@
code, companionMethod.getArity(), appView);
DexEncodedMethod implMethod = new DexEncodedMethod(
companionMethod, newFlags, virtual.annotations, virtual.parameterAnnotationsList, code);
+ implMethod.copyMetadata(virtual, feedback);
virtual.setDefaultInterfaceMethodImplementation(implMethod);
companionMethods.add(implMethod);
graphLensBuilder.move(virtual.method, implMethod.method);
@@ -123,8 +128,16 @@
: "Static interface method " + direct.toSourceString() + " is expected to "
+ "either be public or private in " + iface.origin;
DexMethod companionMethod = rewriter.staticAsMethodOfCompanionClass(oldMethod);
- companionMethods.add(new DexEncodedMethod(companionMethod, newFlags,
- direct.annotations, direct.parameterAnnotationsList, direct.getCode()));
+ Code code = direct.getCode();
+ DexEncodedMethod implMethod =
+ new DexEncodedMethod(
+ companionMethod,
+ newFlags,
+ direct.annotations,
+ direct.parameterAnnotationsList,
+ direct.getCode());
+ implMethod.copyMetadata(direct, feedback);
+ companionMethods.add(implMethod);
graphLensBuilder.move(oldMethod, companionMethod);
} else {
if (originalFlags.isPrivate()) {
@@ -142,8 +155,15 @@
}
DexEncodedMethod.setDebugInfoWithFakeThisParameter(
code, companionMethod.getArity(), appView);
- companionMethods.add(new DexEncodedMethod(companionMethod,
- newFlags, direct.annotations, direct.parameterAnnotationsList, code));
+ DexEncodedMethod implMethod =
+ new DexEncodedMethod(
+ companionMethod,
+ newFlags,
+ direct.annotations,
+ direct.parameterAnnotationsList,
+ code);
+ implMethod.copyMetadata(direct, feedback);
+ companionMethods.add(implMethod);
graphLensBuilder.move(oldMethod, companionMethod);
} else {
// Since there are no interface constructors at this point,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 6644b26..fce06fa 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -170,9 +170,6 @@
code.origin));
return null;
}
- if (replacement.isDexItemBasedConstString()) {
- code.method.getMutableOptimizationInfo().markUseIdentifierNameString();
- }
return replacement;
}
@@ -386,9 +383,6 @@
if (replacement != null) {
affectedValues.addAll(current.outValue().affectedValues());
iterator.replaceCurrentInstruction(replacement);
- if (replacement.isDexItemBasedConstString()) {
- code.method.getMutableOptimizationInfo().markUseIdentifierNameString();
- }
feedback.markFieldAsPropagated(target);
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
index 15eda31..081b58e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -287,7 +287,6 @@
return;
}
Set<Value> affectedValues = Sets.newIdentityHashSet();
- boolean markUseIdentifierNameString = false;
InstructionListIterator it = code.instructionListIterator();
while (it.hasNext()) {
Instruction instr = it.next();
@@ -434,7 +433,6 @@
} else if (deferred != null) {
affectedValues.addAll(invoke.outValue().affectedValues());
it.replaceCurrentInstruction(deferred);
- markUseIdentifierNameString = true;
logHistogramOfNames(deferred);
}
}
@@ -443,9 +441,6 @@
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
- if (markUseIdentifierNameString) {
- code.method.getMutableOptimizationInfo().markUseIdentifierNameString();
- }
}
private void logNameComputation(ClassNameMapping kind) {
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
index 725c68c..5a36a50 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
@@ -188,7 +188,6 @@
InstancePut instancePut = instruction.asInstancePut();
iterator.replaceCurrentInstruction(new InstancePut(field, instancePut.object(), newIn));
}
- method.getMutableOptimizationInfo().markUseIdentifierNameString();
return iterator;
}
@@ -328,7 +327,6 @@
iterator.replaceCurrentInstruction(
Invoke.create(
invoke.getType(), invokedMethod, invokedMethod.proto, invoke.outValue(), newIns));
- method.getMutableOptimizationInfo().markUseIdentifierNameString();
}
return iterator;
}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultInterfaceWithIdentifierNameString.java b/src/test/java/com/android/tools/r8/desugar/DefaultInterfaceWithIdentifierNameString.java
new file mode 100644
index 0000000..5c0c8c3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultInterfaceWithIdentifierNameString.java
@@ -0,0 +1,110 @@
+// Copyright (c) 2020, 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.desugar;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DefaultInterfaceWithIdentifierNameString extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ // Test expect that default interface method desugaring is enabled.
+ return getTestParameters()
+ .withDexRuntimes()
+ .withApiLevelsEndingAtExcluding(AndroidApiLevel.N)
+ .build();
+ }
+
+ public DefaultInterfaceWithIdentifierNameString(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ private boolean isInvokeClassForName(InstructionSubject instruction) {
+ if (!instruction.isInvokeStatic()) {
+ return false;
+ }
+ return ((InvokeInstructionSubject) instruction)
+ .invokedMethod()
+ .name
+ .toString()
+ .equals("forName");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(A.class);
+ assertThat(classSubject, isRenamed());
+ ClassSubject companionClassSubject = inspector.companionClassFor(I.class);
+ assertThat(companionClassSubject, isRenamed());
+ companionClassSubject
+ .allMethods()
+ .forEach(
+ method -> assertTrue(method.streamInstructions().anyMatch(this::isInvokeClassForName)));
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(DefaultInterfaceWithIdentifierNameString.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableInliningAnnotations()
+ .enableMergeAnnotations()
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("new A", "new A", "DONE");
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) throws Exception {
+ I.newInstance().antoherInstance();
+ System.out.println("DONE");
+ }
+ }
+
+ @NeverMerge
+ interface I {
+ @NeverInline
+ static I newInstance() throws Exception {
+ return (I)
+ Class.forName("com.android.tools.r8.desugar.DefaultInterfaceWithIdentifierNameString$A")
+ .newInstance();
+ }
+
+ @NeverInline
+ default I antoherInstance() throws Exception {
+ return (I)
+ Class.forName("com.android.tools.r8.desugar.DefaultInterfaceWithIdentifierNameString$A")
+ .newInstance();
+ }
+ }
+
+ static class A implements I {
+ A() {
+ System.out.println("new A");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index 2bc1dd4..27b30f9 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexValueArray;
import com.android.tools.r8.graph.DexValue.DexValueString;
+import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.ClassNamingForNameMapper;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -245,7 +246,7 @@
return rewriter.getSignature();
}
- public ClassSubject clazz(Class clazz) {
+ public ClassSubject clazz(Class<?> clazz) {
return clazz(Reference.classFromClass(clazz));
}
@@ -278,6 +279,12 @@
return new FoundClassSubject(this, clazz, naming);
}
+ public ClassSubject companionClassFor(Class<?> clazz) {
+ return clazz(
+ Reference.classFromTypeName(
+ clazz.getTypeName() + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX));
+ }
+
public void forAllClasses(Consumer<FoundClassSubject> inspection) {
forAll(
application.classes(),