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(),