Ensure that the marker for identifier name strings is set correctly
This refactors the bookkeeping of wether identifier name strings are
used in a method to mainly be handled in the IR converter, and not
individual optimizations moving code around.
As the interface defugaring creating of companion classes happens
after IR conversion this still need it own handling.
Bug: 148021799
Change-Id: Ia5bb9f86f023d992e3ef8fe3823186c49a74b4a9
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 ff31e35..7b529da 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -47,6 +47,7 @@
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
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.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.UpdatableMethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
@@ -1237,15 +1238,18 @@
public void copyMetadata(DexEncodedMethod from) {
checkIfObsolete();
setKotlinMemberInfo(from.kotlinMemberInfo);
- // 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 syntheticBuilder(DexEncodedMethod from) {
return new Builder(from, true);
}
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 31b6588..cc7307f 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
@@ -163,7 +163,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);
@@ -171,20 +170,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 4bddbef..4dbdde6 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
@@ -1166,7 +1166,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 b3a62b7..4f84235 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
@@ -43,6 +43,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;
@@ -101,10 +102,10 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Sets;
-import com.google.common.collect.Streams;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -419,12 +420,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);
}
}
@@ -460,7 +462,7 @@
desugarNestBasedAccess(builder, executor);
synthesizeLambdaClasses(builder, executor);
- desugarInterfaceMethods(builder, ExcludeDexResources, executor);
+ desugarInterfaceMethods(builder, simpleOptimizationFeedback, ExcludeDexResources, executor);
synthesizeTwrCloseResourceUtilityClass(builder, executor);
synthesizeJava8UtilityClass(builder, executor);
processCovariantReturnTypeAnnotations(builder);
@@ -707,7 +709,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);
@@ -1529,20 +1532,10 @@
timing.end();
}
- // 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);
+ // IR processing should not need to handle identifier name strings, so after the first round
+ // there should be no information for that.
+ if (methodProcessor.isPrimary()) {
+ assert !method.getOptimizationInfo().useIdentifierNameString();
}
printMethod(code, "Optimized IR (SSA)", previous);
@@ -1552,6 +1545,17 @@
return timing;
}
+ 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;
+ }
+ }
+ }
+
// Compute optimization info summary for the current method unless it is pinned
// (in that case we should not be making any assumptions about the behavior of the method).
public void collectOptimizationInfo(
@@ -1568,6 +1572,7 @@
public void finalizeIR(
DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
+ 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 09cd2aa..21b182e 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
@@ -38,6 +38,7 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.DefaultMethodsHelper.Collection;
import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLense;
+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;
@@ -913,6 +914,7 @@
*/
public void desugarInterfaceMethods(
Builder<?> builder,
+ OptimizationFeedback feedback,
Flavor flavour,
ExecutorService executorService)
throws ExecutionException {
@@ -930,7 +932,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();
@@ -960,9 +963,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 = InterfaceProcessorNestedGraphLense.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, 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 ccb0f3c..ef9b9c9 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
@@ -31,6 +31,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;
@@ -56,13 +57,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) {
@@ -95,6 +99,7 @@
code, companionMethod.getArity(), appView);
DexEncodedMethod implMethod = new DexEncodedMethod(
companionMethod, newFlags, virtual.annotations, virtual.parameterAnnotationsList, code, true);
+ implMethod.copyMetadata(virtual, feedback);
virtual.setDefaultInterfaceMethodImplementation(implMethod);
companionMethods.add(implMethod);
graphLensBuilder.move(virtual.method, implMethod.method);
@@ -127,8 +132,17 @@
: "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(),true));
+ Code code = direct.getCode();
+ DexEncodedMethod implMethod =
+ new DexEncodedMethod(
+ companionMethod,
+ newFlags,
+ direct.annotations,
+ direct.parameterAnnotationsList,
+ direct.getCode(),
+ true);
+ implMethod.copyMetadata(direct, feedback);
+ companionMethods.add(implMethod);
graphLensBuilder.move(oldMethod, companionMethod);
} else {
if (originalFlags.isPrivate()) {
@@ -146,8 +160,16 @@
}
DexEncodedMethod.setDebugInfoWithFakeThisParameter(
code, companionMethod.getArity(), appView);
- companionMethods.add(new DexEncodedMethod(companionMethod,
- newFlags, direct.annotations, direct.parameterAnnotationsList, code,true));
+ DexEncodedMethod implMethod =
+ new DexEncodedMethod(
+ companionMethod,
+ newFlags,
+ direct.annotations,
+ direct.parameterAnnotationsList,
+ code,
+ true);
+ 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 5413b56..722625f 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
@@ -160,9 +160,6 @@
code.origin));
return null;
}
- if (replacement.isDexItemBasedConstString()) {
- code.method.getMutableOptimizationInfo().markUseIdentifierNameString();
- }
return replacement;
}
@@ -352,9 +349,6 @@
} else {
iterator.replaceCurrentInstruction(replacement);
}
- if (replacement.isDexItemBasedConstString()) {
- code.method.getMutableOptimizationInfo().markUseIdentifierNameString();
- }
feedback.markFieldAsPropagated(target);
}
}
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 41e1264..072f762 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
@@ -305,7 +305,6 @@
return;
}
Set<Value> affectedValues = Sets.newIdentityHashSet();
- boolean markUseIdentifierNameString = false;
InstructionListIterator it = code.instructionListIterator();
while (it.hasNext()) {
Instruction instr = it.next();
@@ -452,7 +451,6 @@
} else if (deferred != null) {
affectedValues.addAll(invoke.outValue().affectedValues());
it.replaceCurrentInstruction(deferred);
- markUseIdentifierNameString = true;
logHistogramOfNames(deferred);
}
}
@@ -461,9 +459,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 de60241..47d6431 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
@@ -195,7 +195,6 @@
InstancePut instancePut = instruction.asInstancePut();
iterator.replaceCurrentInstruction(new InstancePut(field, instancePut.object(), newIn));
}
- method.getMutableOptimizationInfo().markUseIdentifierNameString();
return iterator;
}
@@ -335,7 +334,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..211050e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultInterfaceWithIdentifierNameString.java
@@ -0,0 +1,112 @@
+// 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()
+ .enableNeverClassInliningAnnotations()
+ .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();
+ }
+ }
+
+ @NeverClassInline
+ 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 51af112..5e1e668 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;
@@ -251,7 +252,7 @@
return rewriter.getSignature();
}
- public ClassSubject clazz(Class clazz) {
+ public ClassSubject clazz(Class<?> clazz) {
return clazz(Reference.classFromClass(clazz));
}
@@ -284,6 +285,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(),