Account for inlined frames in outlines

Fixes: 201397823
Fixes: 204643407
Change-Id: Ic4b74d7c3c0dab6461873fb14bfbe5e0a0451d74
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index f49bdd1..16af327 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -534,7 +534,6 @@
                 lastPosition = currentPosition;
               }
             }
-            Range originalRange = new Range(firstPosition.originalLine, lastPosition.originalLine);
             Range obfuscatedRange;
             if (method.getCode().isDexCode()
                 && method.getCode().asDexCode().getDebugInfo()
@@ -547,34 +546,15 @@
             }
             ClassNaming.Builder classNamingBuilder = onDemandClassNamingBuilder.get();
             MappedRange lastMappedRange =
-                classNamingBuilder.addMappedRange(
+                getMappedRangesForPosition(
+                    appView.options().dexItemFactory(),
+                    getOriginalMethodSignature,
+                    classNamingBuilder,
+                    firstPosition.method,
+                    obfuscatedName,
                     obfuscatedRange,
-                    getOriginalMethodSignature.apply(firstPosition.method),
-                    originalRange,
-                    obfuscatedName);
-            Position caller = firstPosition.caller;
-            int inlineFramesCount = 0;
-            while (caller != null) {
-              inlineFramesCount += 1;
-              lastMappedRange =
-                  classNamingBuilder.addMappedRange(
-                      obfuscatedRange,
-                      getOriginalMethodSignature.apply(caller.getMethod()),
-                      new Range(Math.max(caller.getLine(), 0)), // Prevent against "no-position".
-                      obfuscatedName);
-              if (caller.isRemoveInnerFramesIfThrowingNpe()) {
-                lastMappedRange.addMappingInformation(
-                    RewriteFrameMappingInformation.builder()
-                        .addCondition(
-                            ThrowsCondition.create(
-                                Reference.classFromDescriptor(
-                                    appView.options().dexItemFactory().npeDescriptor.toString())))
-                        .addRewriteAction(RemoveInnerFramesAction.create(inlineFramesCount))
-                        .build(),
-                    Unreachable::raise);
-              }
-              caller = caller.getCallerPosition();
-            }
+                    new Range(firstPosition.originalLine, lastPosition.originalLine),
+                    firstPosition.caller);
             for (MappingInformation info : methodMappingInfo) {
               lastMappedRange.addMappingInformation(info, Unreachable::raise);
             }
@@ -593,12 +573,15 @@
                           positionRemapper.createRemappedPosition(position).getSecond().getLine();
                     }
                     positionMap.put((int) line, placeHolderLineToBeFixed);
-                    // TODO(b/204643407): Iterate over caller positions recursively.
-                    classNamingBuilder.addMappedRange(
+                    getMappedRangesForPosition(
+                        appView.options().dexItemFactory(),
+                        getOriginalMethodSignature,
+                        classNamingBuilder,
+                        position.getMethod(),
+                        obfuscatedName,
                         new Range(placeHolderLineToBeFixed, placeHolderLineToBeFixed),
-                        getOriginalMethodSignature.apply(position.getMethod()),
                         new Range(position.getLine(), position.getLine()),
-                        obfuscatedName);
+                        position.getCallerPosition());
                   });
               outlinesToFix
                   .computeIfAbsent(
@@ -623,6 +606,45 @@
     return classNameMapperBuilder.build();
   }
 
+  private static MappedRange getMappedRangesForPosition(
+      DexItemFactory factory,
+      Function<DexMethod, MethodSignature> getOriginalMethodSignature,
+      Builder classNamingBuilder,
+      DexMethod method,
+      String obfuscatedName,
+      Range obfuscatedRange,
+      Range originalLine,
+      Position caller) {
+    MappedRange lastMappedRange =
+        classNamingBuilder.addMappedRange(
+            obfuscatedRange,
+            getOriginalMethodSignature.apply(method),
+            originalLine,
+            obfuscatedName);
+    int inlineFramesCount = 0;
+    while (caller != null) {
+      inlineFramesCount += 1;
+      lastMappedRange =
+          classNamingBuilder.addMappedRange(
+              obfuscatedRange,
+              getOriginalMethodSignature.apply(caller.getMethod()),
+              new Range(Math.max(caller.getLine(), 0)), // Prevent against "no-position".
+              obfuscatedName);
+      if (caller.isRemoveInnerFramesIfThrowingNpe()) {
+        lastMappedRange.addMappingInformation(
+            RewriteFrameMappingInformation.builder()
+                .addCondition(
+                    ThrowsCondition.create(
+                        Reference.classFromDescriptor(factory.npeDescriptor.toString())))
+                .addRewriteAction(RemoveInnerFramesAction.create(inlineFramesCount))
+                .build(),
+            Unreachable::raise);
+      }
+      caller = caller.getCallerPosition();
+    }
+    return lastMappedRange;
+  }
+
   private static boolean verifyMethodsAreKeptDirectlyOrIndirectly(
       AppView<?> appView, List<DexEncodedMethod> methods) {
     if (appView.options().isGeneratingClassFiles() || !appView.appInfo().hasClassHierarchy()) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineWithInlineMappingInformationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineWithInlineMappingInformationTest.java
index 6f343e9..fddf01c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineWithInlineMappingInformationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineWithInlineMappingInformationTest.java
@@ -4,7 +4,6 @@
 package com.android.tools.r8.ir.optimize.outliner;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoHorizontalClassMerging;
@@ -90,12 +89,7 @@
               // and one for
               //   new ArrayStoreException("Foo")
               assertEquals(5, inspector.allClasses().size());
-              if (throwInFirstOutline ^ throwOnFirstCall) {
-                // TODO(b/204643407): Should always be equal.
-                assertNotEquals(expectedStackTrace, stackTrace);
-              } else {
-                assertEquals(expectedStackTrace, stackTrace);
-              }
+              assertEquals(expectedStackTrace, stackTrace);
             });
   }