Update LineNumberOptimizer to always insert positions for overloads

Bug: b/221015863
Bug: b/251677184
Change-Id: Ie9268c22589d32f71a223cc28bcdf7eef9e13b6f
diff --git a/src/main/java/com/android/tools/r8/utils/positions/ClassFilePositionToMappedRangeMapper.java b/src/main/java/com/android/tools/r8/utils/positions/ClassFilePositionToMappedRangeMapper.java
index cd6efb7..dd60a3e 100644
--- a/src/main/java/com/android/tools/r8/utils/positions/ClassFilePositionToMappedRangeMapper.java
+++ b/src/main/java/com/android/tools/r8/utils/positions/ClassFilePositionToMappedRangeMapper.java
@@ -11,8 +11,10 @@
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.Position.SyntheticPosition;
 import com.android.tools.r8.utils.Pair;
 import java.util.ArrayList;
 import java.util.List;
@@ -34,7 +36,7 @@
       int pcEncodingCutoff) {
     return appView.options().getTestingOptions().usePcEncodingInCfForTesting
         ? getPcEncodedPositions(method, positionRemapper)
-        : getMappedPositionsRemapped(method, positionRemapper);
+        : getMappedPositionsRemapped(method, positionRemapper, hasOverloads);
   }
 
   @Override
@@ -43,15 +45,17 @@
   }
 
   private List<MappedPosition> getMappedPositionsRemapped(
-      ProgramMethod method, PositionRemapper positionRemapper) {
+      ProgramMethod method, PositionRemapper positionRemapper, boolean hasOverloads) {
     List<MappedPosition> mappedPositions = new ArrayList<>();
     // Do the actual processing for each method.
     CfCode oldCode = method.getDefinition().getCode().asCfCode();
     List<CfInstruction> oldInstructions = oldCode.getInstructions();
     List<CfInstruction> newInstructions = new ArrayList<>(oldInstructions.size());
+    boolean seenPosition = false;
     for (CfInstruction oldInstruction : oldInstructions) {
       CfInstruction newInstruction;
       if (oldInstruction.isPosition()) {
+        seenPosition = true;
         CfPosition cfPosition = oldInstruction.asPosition();
         newInstruction =
             new CfPosition(
@@ -62,6 +66,24 @@
       }
       newInstructions.add(newInstruction);
     }
+    if (!seenPosition && hasOverloads) {
+      // If a method with overloads does not have an actual position then map it to the implicit
+      // preamble position.
+      DexMethod reference = method.getReference();
+      DexMethod original = appView.graphLens().getOriginalMethodSignature(reference);
+      CfPosition preamblePositionForOverload =
+          new CfPosition(
+              new CfLabel(),
+              remapAndAdd(
+                  SyntheticPosition.builder().setMethod(original).setLine(0).build(),
+                  positionRemapper,
+                  mappedPositions));
+      List<CfInstruction> shiftedPositions = new ArrayList<>(oldInstructions.size() + 2);
+      shiftedPositions.add(preamblePositionForOverload);
+      shiftedPositions.add(preamblePositionForOverload.getLabel());
+      shiftedPositions.addAll(newInstructions);
+      newInstructions = shiftedPositions;
+    }
     method.setCode(
         new CfCode(
             method.getHolderType(),
diff --git a/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java
index 993ca5f..c1e6850 100644
--- a/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java
@@ -118,13 +118,21 @@
 
         for (ProgramMethod method : methods) {
           DexEncodedMethod definition = method.getDefinition();
+          DexMethod methodReference = method.getReference();
+          if (methodName == method.getName()
+              && appView.graphLens().getOriginalMethodSignature(methodReference) == methodReference
+              && !mustHaveResidualDebugInfo(appView.options(), definition)
+              && !definition.isD8R8Synthesized()
+              && methods.size() <= 1) {
+            continue;
+          }
           positionRemapper.setCurrentMethod(definition);
           List<MappedPosition> mappedPositions;
           int pcEncodingCutoff =
               methods.size() == 1 ? representation.getDexPcEncodingCutoff(method) : -1;
           boolean canUseDexPc = pcEncodingCutoff > 0;
           if (definition.getCode() != null
-              && mustHaveResidualDebugInfo(appView.options(), definition)
+              && (definition.getCode().isCfCode() || definition.getCode().isDexCode())
               && !appView.isCfByteCodePassThrough(definition)) {
             mappedPositions =
                 positionToMappedRangeMapper.getMappedPositions(
@@ -229,14 +237,9 @@
       DexEncodedMethod definition = programMethod.getDefinition();
       DexMethod method = programMethod.getReference();
       DexString renamedName = appView.getNamingLens().lookupName(method);
-      if (renamedName != method.name
-          || appView.graphLens().getOriginalMethodSignature(method) != method
-          || mustHaveResidualDebugInfo(appView.options(), definition)
-          || definition.isD8R8Synthesized()) {
-        methodsByRenamedName
-            .computeIfAbsent(renamedName, key -> new ArrayList<>())
-            .add(programMethod);
-      }
+      methodsByRenamedName
+          .computeIfAbsent(renamedName, key -> new ArrayList<>())
+          .add(programMethod);
     }
     return methodsByRenamedName;
   }
diff --git a/src/test/examples/shaking1/print-mapping-dex.ref b/src/test/examples/shaking1/print-mapping-dex.ref
index 3635115..bb72965 100644
--- a/src/test/examples/shaking1/print-mapping-dex.ref
+++ b/src/test/examples/shaking1/print-mapping-dex.ref
@@ -1,6 +1,7 @@
 shaking1.Shaking -> shaking1.Shaking:
 shaking1.Used -> a.a:
     0:2:void <init>(java.lang.String):12:12 -> <init>
+    0:2:java.lang.String aMethodThatIsNotUsedButKept():0:0 -> aMethodThatIsNotUsedButKept
     3:5:void <init>(java.lang.String):13:13 -> <init>
     0:6:void main(java.lang.String[]):8:8 -> main
     7:21:void main(java.lang.String[]):9:9 -> main
diff --git a/src/test/java/com/android/tools/r8/debuginfo/OverloadWithNoLineNumberTest.java b/src/test/java/com/android/tools/r8/debuginfo/OverloadWithNoLineNumberTest.java
index 47f6e4b..7a519a6 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/OverloadWithNoLineNumberTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/OverloadWithNoLineNumberTest.java
@@ -4,17 +4,20 @@
 
 package com.android.tools.r8.debuginfo;
 
-import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.debuginfo.testclasses.SimpleCallChainClassWithOverloads;
-import com.android.tools.r8.naming.retrace.StackTrace;
-import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.ProguardMappingSupplier;
+import com.android.tools.r8.retrace.Retrace;
+import com.android.tools.r8.retrace.RetraceCommand;
 import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.stream.Collectors;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -35,68 +38,43 @@
 
   @Test
   public void testR8() throws Exception {
-    testForR8(parameters.getBackend())
-        .addProgramClassFileData(
-            transformer(SimpleCallChainClassWithOverloads.class)
-                .removeLineNumberTable(MethodPredicate.onName("test"))
-                .transform())
-        .setMinApi(parameters.getApiLevel())
-        .addKeepMainRule(SimpleCallChainClassWithOverloads.class)
-        .addKeepClassAndMembersRules(SimpleCallChainClassWithOverloads.class)
-        .addKeepAttributeLineNumberTable()
-        .run(parameters.getRuntime(), SimpleCallChainClassWithOverloads.class)
-        .assertFailureWithErrorThatThrows(RuntimeException.class)
-        .inspectStackTrace(
-            (stackTrace, inspector) -> {
-              StackTraceLine mainLine =
-                  StackTraceLine.builder()
-                      .setClassName(typeName(SimpleCallChainClassWithOverloads.class))
-                      .setMethodName("main")
-                      .setFileName(SOURCE_FILE_NAME)
-                      .setLineNumber(10)
-                      .build();
-              if (parameters.isCfRuntime()
-                  || parameters.getDexRuntimeVersion().isOlderThan(Version.V8_1_0)) {
-                StackTraceLine testStackTraceLine =
-                    StackTraceLine.builder()
-                        .setClassName(typeName(SimpleCallChainClassWithOverloads.class))
-                        .setMethodName("test")
-                        .setFileName(SOURCE_FILE_NAME)
-                        .build();
-                assertThat(
-                    stackTrace,
-                    isSame(
-                        StackTrace.builder()
-                            // TODO(b/251677184): Stack trace lines should still be distinguishable
-                            //  even if there are no original line numbers to map back two.
-                            .add(testStackTraceLine)
-                            .add(testStackTraceLine)
-                            .add(mainLine)
-                            .build()));
-              } else {
-                assertThat(
-                    stackTrace,
-                    isSame(
-                        StackTrace.builder()
-                            // TODO(b/251677184): Strange that we are able to distinguish when using
-                            //  pc mapping.
-                            .add(
-                                StackTraceLine.builder()
-                                    .setClassName(typeName(SimpleCallChainClassWithOverloads.class))
-                                    .setMethodName("test")
-                                    .setFileName(SOURCE_FILE_NAME)
-                                    .setLineNumber(11)
-                                    .build())
-                            .add(
-                                StackTraceLine.builder()
-                                    .setClassName(typeName(SimpleCallChainClassWithOverloads.class))
-                                    .setMethodName("test")
-                                    .setFileName(SOURCE_FILE_NAME)
-                                    .setLineNumber(4)
-                                    .build())
-                            .add(mainLine)
-                            .build()));
-              }
-            });
+    R8TestRunResult result =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(
+                transformer(SimpleCallChainClassWithOverloads.class)
+                    .removeLineNumberTable(MethodPredicate.onName("test"))
+                    .transform())
+            .setMinApi(parameters.getApiLevel())
+            .addKeepMainRule(SimpleCallChainClassWithOverloads.class)
+            .addKeepClassAndMembersRules(SimpleCallChainClassWithOverloads.class)
+            .addKeepAttributeLineNumberTable()
+            .run(parameters.getRuntime(), SimpleCallChainClassWithOverloads.class)
+            .assertFailureWithErrorThatThrows(RuntimeException.class);
+    Retrace.run(
+        RetraceCommand.builder()
+            .setMappingSupplier(
+                ProguardMappingSupplier.builder()
+                    .setProguardMapProducer(ProguardMapProducer.fromString(result.proguardMap()))
+                    .build())
+            .setStackTrace(
+                result.getOriginalStackTrace().getStackTraceLines().stream()
+                    .map(line -> line.originalLine)
+                    .collect(Collectors.toList()))
+            .setRetracedStackTraceConsumer(
+                retraced -> {
+                  String className = typeName(SimpleCallChainClassWithOverloads.class);
+                  assertEquals(
+                      StringUtils.joinLines(
+                          "\tat " + className + ".void test(long)(" + SOURCE_FILE_NAME + ":0)",
+                          "\tat " + className + ".void test()(" + SOURCE_FILE_NAME + ":0)",
+                          "\tat "
+                              + className
+                              + ".void main(java.lang.String[])("
+                              + SOURCE_FILE_NAME
+                              + ":10)"),
+                      StringUtils.joinLines(retraced));
+                })
+            .setVerbose(true)
+            .build());
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java b/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
index fc1e432..9e361e6 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/VerticalClassMergingRetraceTest.java
@@ -130,7 +130,6 @@
     // at com.android.tools.r8.naming.retraceproguard.MainApp.main(MainApp.java:7)
     //
     // We should instead translate to:
-    // at com.android.tools.r8.naming.retraceproguard.ResourceWrapper.foo(ResourceWrapper.java:1)
     // at com.android.tools.r8.naming.retraceproguard.ResourceWrapper.foo(ResourceWrapper.java:0)
     // at com.android.tools.r8.naming.retraceproguard.MainApp.main(MainApp.java:7)
     // since the synthetic bridge belongs to ResourceWrapper.foo.
@@ -140,12 +139,7 @@
     runTest(
         ImmutableList.of(),
         (StackTrace actualStackTrace, StackTrace retracedStackTrace) -> {
-          StackTrace reprocessedStackTrace =
-              mode == CompilationMode.DEBUG
-                  ? retracedStackTrace
-                  : retracedStackTrace.filter(this::filterSynthesizedBridgeMethod);
-          assertThat(
-              reprocessedStackTrace, isSameExceptForFileNameAndLineNumber(expectedStackTrace));
+          assertThat(retracedStackTrace, isSameExceptForFileNameAndLineNumber(expectedStackTrace));
           assertEquals(
               expectedActualStackTraceHeight(), actualStackTrace.getStackTraceLines().size());
         });
diff --git a/src/test/java/com/android/tools/r8/retrace/OverloadsWithoutLineNumberTest.java b/src/test/java/com/android/tools/r8/retrace/OverloadsWithoutLineNumberTest.java
index 3aa2f49..2ba06ba 100644
--- a/src/test/java/com/android/tools/r8/retrace/OverloadsWithoutLineNumberTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/OverloadsWithoutLineNumberTest.java
@@ -63,21 +63,11 @@
             .setRetracedStackTraceConsumer(box::set)
             .setVerbose(true);
     Retrace.run(builder.build());
-    // TODO(b/221015863): This should ideally be:
-    // at " + typeName(ClassWithOverload.class) + ".test(int)(OverloadsWithoutLineNumberTest.java)
-    if (parameters.canUseNativeDexPC()) {
-      assertEquals(
-          "\tat "
-              + typeName(ClassWithOverload.class)
-              + ".test(OverloadsWithoutLineNumberTest.java:0)",
-          box.get().get(1));
-    } else {
-      assertEquals(
-          "\tat "
-              + typeName(ClassWithOverload.class)
-              + ".test(OverloadsWithoutLineNumberTest.java)",
-          box.get().get(1));
-    }
+    assertEquals(
+        "\tat "
+            + typeName(ClassWithOverload.class)
+            + ".void test(int)(OverloadsWithoutLineNumberTest.java:0)",
+        box.get().get(1));
   }
 
   public static class ClassWithOverload {
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java
index 9d9d7a4..367e1b6 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java
@@ -36,7 +36,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.function.Supplier;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -157,7 +156,6 @@
     return rewrittenR8Jar;
   }
 
-  @Ignore("b/251677184: Failing since update to target 11")
   @Test
   public void testR8RetraceAndComposition() throws Exception {
     Path rewrittenR8Jar = getRewrittenR8Jar();