Merge commit '2bc4198a912b1e155340f4054984ca26fd27bb31' into dev-release
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
index 8af5714..c1107e6 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -319,6 +319,10 @@
       "third_party",
       "binary_compatibility_tests",
       "compiler_api_tests.tar.gz.sha1").toFile())
+  val dagger = ThirdPartyDependency(
+    "dagger",
+    Paths.get("third_party", "dagger", "2.41", "dagger-2.41.jar").toFile(),
+    Paths.get("third_party", "dagger", "2.41.tar.gz.sha1").toFile())
   val ddmLib = ThirdPartyDependency(
     "ddmlib",
     Paths.get("third_party", "ddmlib", "ddmlib.jar").toFile(),
@@ -338,6 +342,11 @@
     Paths.get("third_party", "openjdk", "openjdk-rt-1.8.tar.gz.sha1").toFile()
   )
   val jdks = getJdks()
+  val jdk11Test = ThirdPartyDependency(
+    "jdk-11-test",
+    Paths.get("third_party", "openjdk", "jdk-11-test", "Makefile").toFile(),
+    Paths.get("third_party", "openjdk", "jdk-11-test.tar.gz.sha1").toFile()
+  )
   val jdwpTests = ThirdPartyDependency(
     "jdwp-tests",
     Paths.get("third_party", "jdwp-tests", "apache-harmony-jdwp-tests-host.jar").toFile(),
diff --git a/d8_r8/library_desugar/build.gradle.kts b/d8_r8/library_desugar/build.gradle.kts
new file mode 100644
index 0000000..7483d80
--- /dev/null
+++ b/d8_r8/library_desugar/build.gradle.kts
@@ -0,0 +1,34 @@
+// Copyright (c) 2023, 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.
+
+// import java.nio.file.Paths
+// import net.ltgt.gradle.errorprone.errorprone
+
+plugins {
+  `kotlin-dsl`
+  id("dependencies-plugin")
+}
+
+java {
+  sourceSets.main.configure {
+    java.srcDir(getRoot().resolveAll("src", "library_desugar", "java"))
+    output.resourcesDir = getRoot().resolveAll("build", "classes", "library_desugar_conversions")
+  }
+  sourceCompatibility = JavaVersion.VERSION_1_8
+  targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+dependencies {
+}
+
+tasks {
+  withType<JavaCompile> {
+    options.setFork(true)
+    options.forkOptions.memoryMaximumSize = "3g"
+    options.forkOptions.jvmArgs = listOf(
+      "-Xss256m",
+      // Set the bootclass path so compilation is consistent with 1.8 target compatibility.
+      "-Xbootclasspath/a:third_party/openjdk/openjdk-rt-1.8/rt.jar")
+  }
+}
\ No newline at end of file
diff --git a/d8_r8/library_desugar/gradle.properties b/d8_r8/library_desugar/gradle.properties
new file mode 100644
index 0000000..1de43f9
--- /dev/null
+++ b/d8_r8/library_desugar/gradle.properties
@@ -0,0 +1,17 @@
+# Copyright (c) 2023, 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.
+
+org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8
+kotlin.daemon.jvmargs=-Xmx3g -Dkotlin.js.compiler.legacy.force_enabled=true
+systemProp.file.encoding=UTF-8
+
+# Enable new incremental compilation
+kotlin.incremental.useClasspathSnapshot=true
+
+org.gradle.parallel=true
+org.gradle.caching=true
+
+# Do not download any jdks or detect them. We provide them.
+org.gradle.java.installations.auto-detect=false
+org.gradle.java.installations.auto-download=false
diff --git a/d8_r8/library_desugar/settings.gradle.kts b/d8_r8/library_desugar/settings.gradle.kts
new file mode 100644
index 0000000..e60eee4
--- /dev/null
+++ b/d8_r8/library_desugar/settings.gradle.kts
@@ -0,0 +1,5 @@
+// Copyright (c) 2023, 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.
+
+rootProject.name = "library_desugar"
diff --git a/d8_r8/settings.gradle.kts b/d8_r8/settings.gradle.kts
index 9907334..77ad2e0 100644
--- a/d8_r8/settings.gradle.kts
+++ b/d8_r8/settings.gradle.kts
@@ -54,6 +54,7 @@
 // We need to include src/main as a composite-build otherwise our test-modules
 // will compete with the test to compile the source files.
 includeBuild(root.resolve("main"))
+includeBuild(root.resolve("library_desugar"))
 includeBuild(root.resolve("test"))
 
 // Include r8lib as standalone to have a nice separation between source artifacts and r8 compiled
diff --git a/d8_r8/test_modules/tests_java_8/build.gradle.kts b/d8_r8/test_modules/tests_java_8/build.gradle.kts
index f7e52e5..669b394 100644
--- a/d8_r8/test_modules/tests_java_8/build.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/build.gradle.kts
@@ -55,7 +55,12 @@
 
 val thirdPartyRuntimeDependenciesTask = ensureThirdPartyDependencies(
   "runtimeDeps",
-  listOf(ThirdPartyDeps.compilerApi, ThirdPartyDeps.jacoco, ThirdPartyDeps.java8Runtime)
+  listOf(
+    ThirdPartyDeps.compilerApi,
+    ThirdPartyDeps.dagger,
+    ThirdPartyDeps.jacoco,
+    ThirdPartyDeps.java8Runtime,
+    ThirdPartyDeps.jdk11Test)
     + ThirdPartyDeps.androidJars
     + ThirdPartyDeps.androidVMs
     + ThirdPartyDeps.jdks
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeUtils.java b/src/main/java/com/android/tools/r8/graph/DexTypeUtils.java
index 62531ba..625b127 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeUtils.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeUtils.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.utils.AndroidApiLevelUtils;
 import com.google.common.collect.Iterables;
 
 public class DexTypeUtils {
@@ -15,7 +16,7 @@
       AppView<? extends AppInfoWithClassHierarchy> appView, Iterable<DexType> types) {
     TypeElement join =
         TypeElement.join(Iterables.transform(types, type -> type.toTypeElement(appView)), appView);
-    return toDexType(appView, join);
+    return findApiSafeUpperBound(appView, toDexType(appView, join));
   }
 
   public static DexType toDexType(
@@ -39,4 +40,23 @@
     }
     return dexItemFactory.objectType;
   }
+
+  public static DexType findApiSafeUpperBound(
+      AppView<? extends AppInfoWithClassHierarchy> appView, DexType type) {
+    DexItemFactory factory = appView.dexItemFactory();
+    if (type.toBaseType(factory).isPrimitiveType()) {
+      return type;
+    }
+    DexClass clazz = appView.definitionFor(type.isArrayType() ? type.toBaseType(factory) : type);
+    if (clazz == null) {
+      assert false : "We should not have found an upper bound if the hierarchy is missing";
+      return type;
+    }
+    if (!clazz.isLibraryClass()
+        || AndroidApiLevelUtils.isApiSafeForReference(clazz.asLibraryClass(), appView)) {
+      return type;
+    }
+    // Always just return the object type since this is safe for all api versions.
+    return factory.objectType;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/AbstractGenerateFiles.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/AbstractGenerateFiles.java
index e5ad61c..f1092d4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/AbstractGenerateFiles.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/AbstractGenerateFiles.java
@@ -99,6 +99,7 @@
 
   abstract AndroidApiLevel run() throws Exception;
 
+  // TODO(b/289365156): Move this out.
   private static String getFallBackAndroidJarPath(AndroidApiLevel apiLevel) {
     String jar =
         apiLevel == AndroidApiLevel.MASTER
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
index 2323d03..809fd77 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -517,11 +517,19 @@
   void write(ChainableStringConsumer consumer) {
     consumer.accept(originalName).accept(" -> ").accept(renamedName).accept(":\n");
 
+    String spacing = "    ";
+
     // Print all additional mapping information.
     additionalMappingInfo.forEach(info -> consumer.accept("# " + info.serialize()).accept("\n"));
 
     // Print field member namings.
-    forAllFieldNamingSorted(m -> consumer.accept("    ").accept(m.toString()).accept("\n"));
+    forAllFieldNamingSorted(
+        fieldMember -> {
+          consumer.accept(spacing).accept(fieldMember.toString()).accept("\n");
+          for (MappingInformation info : fieldMember.getAdditionalMappingInformation()) {
+            consumer.accept(spacing + "  # ").accept(info.serialize()).accept("\n");
+          }
+        });
 
     // Sort MappedRanges by sequence number to restore construction order (original Proguard-map
     // input).
@@ -531,9 +539,9 @@
     }
     mappedRangesSorted.sort(Comparator.comparingInt(range -> range.sequenceNumber));
     for (MappedRange range : mappedRangesSorted) {
-      consumer.accept("    ").accept(range.toString()).accept("\n");
+      consumer.accept(spacing).accept(range.toString()).accept("\n");
       for (MappingInformation info : range.getAdditionalMappingInformation()) {
-        consumer.accept("      # ").accept(info.serialize()).accept("\n");
+        consumer.accept(spacing + "  # ").accept(info.serialize()).accept("\n");
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
index e4fc96d..8be5e9a 100644
--- a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
+++ b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
@@ -865,38 +865,40 @@
         assert verifyAllOutlineCallSitesAreEqualTo(outlineCallSite, computedMappedRangeForOutlines);
         ComputedMappedRangeForOutline computedMappedRangeForOutline =
             ListUtils.first(computedMappedRangeForOutlines);
-          Int2IntSortedMap newPositionMap =
-              new Int2IntLinkedOpenHashMap(outlineCallSite.getPositions().size());
-          visitOutlineMappedPositions(
-              outlineCallSite,
-              computedMappedRangeForOutline.current.getOriginalSignature(),
-              positionInfo -> {
-                int newIndex = firstAvailableRange.getAndIncrement();
-                Range newMinifiedRange = new Range(newIndex, newIndex);
-                MappedRange outerMostOutlineCallsiteFrame =
-                    ListUtils.last(positionInfo.mappedRanges());
-                for (MappedRange inlineMappedRangeInOutlinePosition : positionInfo.mappedRanges()) {
-                  if (inlineMappedRangeInOutlinePosition != outerMostOutlineCallsiteFrame) {
-                    composedRanges.add(
-                        inlineMappedRangeInOutlinePosition.withMinifiedRange(newMinifiedRange));
-                  }
-                }
+        Int2IntSortedMap newPositionMap =
+            new Int2IntLinkedOpenHashMap(outlineCallSite.getPositions().size());
+        visitOutlineMappedPositions(
+            outlineCallSite,
+            computedMappedRangeForOutline.current.getOriginalSignature(),
+            positionInfo -> {
+              int newIndex = firstAvailableRange.getAndIncrement();
+              Range newMinifiedRange = new Range(newIndex, newIndex);
+              boolean isCaller = false;
+              for (MappedRange existingMappedRange : positionInfo.mappedRanges()) {
                 int originalPosition =
-                    outerMostOutlineCallsiteFrame.getOriginalLineNumber(
+                    existingMappedRange.getOriginalLineNumber(
                         positionInfo.outlineCallsitePosition());
-                boolean hasInlineFrames = positionInfo.mappedRanges().size() > 1;
-                composedRanges.add(
+                Range newOriginalRange =
+                    isCaller
+                        ? new Range(originalPosition)
+                        : new Range(originalPosition, originalPosition);
+                MappedRange newMappedRange =
                     new MappedRange(
                         newMinifiedRange,
-                        lastComposedRange.signature,
-                        hasInlineFrames
-                            ? new Range(originalPosition)
-                            : new Range(originalPosition, originalPosition),
-                        lastComposedRange.getRenamedName()));
-                newPositionMap.put(positionInfo.outlinePosition(), newIndex);
-                outlineCallSite.setPositionsInternal(newPositionMap);
-              });
-        }
+                        existingMappedRange.getOriginalSignature(),
+                        newOriginalRange,
+                        lastComposedRange.getRenamedName());
+                if (!existingMappedRange.getAdditionalMappingInformation().isEmpty()) {
+                  newMappedRange.setAdditionalMappingInformationInternal(
+                      existingMappedRange.getAdditionalMappingInformation());
+                }
+                composedRanges.add(newMappedRange);
+                isCaller = true;
+              }
+              newPositionMap.put(positionInfo.outlinePosition(), newIndex);
+            });
+        outlineCallSite.setPositionsInternal(newPositionMap);
+      }
     }
 
     private boolean verifyAllOutlineCallSitesAreEqualTo(
diff --git a/src/main/java/com/android/tools/r8/retrace/IllegalClassNameLookupException.java b/src/main/java/com/android/tools/r8/retrace/IllegalClassNameLookupException.java
index 702ed59..97d77be 100644
--- a/src/main/java/com/android/tools/r8/retrace/IllegalClassNameLookupException.java
+++ b/src/main/java/com/android/tools/r8/retrace/IllegalClassNameLookupException.java
@@ -4,6 +4,9 @@
 
 package com.android.tools.r8.retrace;
 
+import com.android.tools.r8.Keep;
+
+@Keep
 public class IllegalClassNameLookupException extends RuntimeException {
 
   private final String typeName;
diff --git a/src/main/java/com/android/tools/r8/retrace/MappingSupplierAsync.java b/src/main/java/com/android/tools/r8/retrace/MappingSupplierAsync.java
index 9ffa613..ba04547 100644
--- a/src/main/java/com/android/tools/r8/retrace/MappingSupplierAsync.java
+++ b/src/main/java/com/android/tools/r8/retrace/MappingSupplierAsync.java
@@ -5,7 +5,9 @@
 package com.android.tools.r8.retrace;
 
 import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.Keep;
 
+@Keep
 public interface MappingSupplierAsync<T extends MappingSupplierAsync<T>>
     extends MappingSupplierBase<T> {
 
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
index 98ed799..eaa21d3 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
@@ -85,7 +85,7 @@
               memberNamings,
               memberNaming -> memberNaming.getResidualSignature().equals(fieldSignature));
     }
-    return memberNamings;
+    return memberNamings.isEmpty() ? null : memberNamings;
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
index ac45d92..c7f09b8 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
@@ -95,7 +95,9 @@
 
   @Override
   public boolean isEmpty() {
-    return memberNamings == null || memberNamings.isEmpty();
+    return memberNamings == null
+        || memberNamings.isEmpty()
+        || (memberNamings.size() == 1 && memberNamings.get(0).getSecond() == null);
   }
 
   public static class ElementImpl implements RetraceFieldElement {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 41c295f..03a8229 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1718,8 +1718,9 @@
       // Allow 4 instructions when using LIR regardless of backend.
       if (options.testing.useLir) {
         // TODO(b/288226522): We should reevaluate this for size and other inputs as it regresses
-        //  compared to DEX code with limit 5. This is set to 4 to avoid discard errors in chrome.
-        return 4;
+        //  compared to DEX code with limit 5 for tivi. This is set to 5 to avoid discard errors
+        //  in chrome. Using 5 also improves size for chrome compared to a lower value.
+        return 5;
       }
       // Allow 3 instructions when generating to class files.
       if (options.isGeneratingClassFiles()) {
diff --git a/src/main/java/com/android/tools/r8/utils/RetracerForCodePrinting.java b/src/main/java/com/android/tools/r8/utils/RetracerForCodePrinting.java
index fe301df..1b772b7 100644
--- a/src/main/java/com/android/tools/r8/utils/RetracerForCodePrinting.java
+++ b/src/main/java/com/android/tools/r8/utils/RetracerForCodePrinting.java
@@ -11,8 +11,10 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.IndexedDexItem;
 import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.references.FieldReference;
 import com.android.tools.r8.retrace.RetraceClassElement;
 import com.android.tools.r8.retrace.RetraceElement;
+import com.android.tools.r8.retrace.RetraceFieldResult;
 import com.android.tools.r8.retrace.RetraceMethodResult;
 import com.android.tools.r8.retrace.RetraceResult;
 import com.android.tools.r8.retrace.RetracedFieldReference;
@@ -117,8 +119,16 @@
     if (retracer == null) {
       return noRetraceString.apply(field);
     }
+    FieldReference fieldReference = field.asFieldReference();
+    RetraceFieldResult retraceFieldResult = retracer.retraceField(fieldReference);
+    if (retraceFieldResult.isEmpty()) {
+      retraceFieldResult =
+          retracer
+              .retraceClass(fieldReference.getHolderClass())
+              .lookupField(fieldReference.getFieldName());
+    }
     return joinAmbiguousResults(
-        retracer.retraceField(field.asFieldReference()),
+        retraceFieldResult,
         element -> {
           if (element.isUnknown()) {
             return unknownToString.apply(element.getField());
diff --git a/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java b/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java
index 487ac5f..c3780fb 100644
--- a/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java
@@ -193,7 +193,9 @@
             DexField originalField = appView.graphLens().getOriginalFieldSignature(dexField);
             DexField residualField =
                 appView.getNamingLens().lookupField(dexField, appView.dexItemFactory());
-            if (residualField.name != originalField.name || originalField.holder != originalType) {
+            if (residualField.name != originalField.name
+                || residualField.getType() != originalField.getType()
+                || originalField.holder != originalType) {
               FieldSignature originalSignature =
                   FieldSignature.fromDexField(originalField, originalField.holder != originalType);
               FieldSignature residualSignature = FieldSignature.fromDexField(residualField);
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index a81451f..842b6a8 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -19,21 +19,17 @@
 import com.android.tools.r8.AssertionsConfiguration.AssertionTransformationScope;
 import com.android.tools.r8.D8CommandParser.OrderedClassFileResourceProvider;
 import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.dex.Marker;
 import com.android.tools.r8.dex.Marker.Tool;
 import com.android.tools.r8.origin.EmbeddedOrigin;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.profile.startup.profile.StartupProfile;
-import com.android.tools.r8.profile.startup.profile.StartupProfileRule;
 import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.startup.StartupProfileProvider;
-import com.android.tools.r8.startup.diagnostic.MissingStartupProfileItemsDiagnostic;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.ExtractMarkerUtils;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.ZipUtils;
 import com.google.common.collect.ImmutableList;
@@ -699,7 +695,7 @@
     D8Command d8Command =
         parse(
             "--desugared-lib",
-            "src/library_desugar/desugar_jdk_libs.json",
+            LibraryDesugaringSpecification.JDK11.getSpecification().toString(),
             "--lib",
             ToolHelper.getAndroidJar(AndroidApiLevel.R).toString());
     InternalOptions options = getOptionsWithLoadedDesugaredLibraryConfiguration(d8Command, false);
@@ -712,7 +708,7 @@
     D8Command d8Command =
         parse(
             "--desugared-lib",
-            "src/library_desugar/desugar_jdk_libs.json",
+            LibraryDesugaringSpecification.JDK11.getSpecification().toString(),
             "--lib",
             ToolHelper.getAndroidJar(AndroidApiLevel.R).toString(),
             "--desugared-lib-pg-conf-output",
@@ -728,7 +724,7 @@
       parse(
           diagnostics,
           "--desugared-lib",
-          "src/library_desugar/desugar_jdk_libs.json",
+          LibraryDesugaringSpecification.JDK11.getSpecification().toString(),
           "--desugared-lib-pg-conf-output");
       fail("Expected parse error");
     } catch (CompilationFailedException e) {
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index a98ad79..d22f197 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.AssertionsConfiguration.AssertionTransformationScope;
 import com.android.tools.r8.ProgramResource.Kind;
 import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.dex.Marker;
 import com.android.tools.r8.dex.Marker.Tool;
 import com.android.tools.r8.origin.EmbeddedOrigin;
@@ -860,7 +861,7 @@
     R8Command r8Command =
         parse(
             "--desugared-lib",
-            "src/library_desugar/desugar_jdk_libs.json",
+            LibraryDesugaringSpecification.JDK11.getSpecification().toString(),
             "--lib",
             ToolHelper.getAndroidJar(AndroidApiLevel.R).toString());
     InternalOptions options = getOptionsWithLoadedDesugaredLibraryConfiguration(r8Command, false);
@@ -873,7 +874,7 @@
     R8Command r8Command =
         parse(
             "--desugared-lib",
-            "src/library_desugar/desugar_jdk_libs.json",
+            LibraryDesugaringSpecification.JDK11.getSpecification().toString(),
             "--lib",
             ToolHelper.getAndroidJar(AndroidApiLevel.R).toString(),
             "--desugared-lib-pg-conf-output",
@@ -889,7 +890,7 @@
       parse(
           diagnostics,
           "--desugared-lib",
-          "src/library_desugar/desugar_jdk_libs.json",
+          LibraryDesugaringSpecification.JDK11.getSpecification().toString(),
           "--desugared-lib-pg-conf-output");
       fail("Expected parse error");
     } catch (CompilationFailedException e) {
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 8ffd594..1151357 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -111,8 +111,8 @@
     return Paths.get(current).getParent().toString() + "/";
   }
 
-  public static final String SOURCE_DIR = "src/main/java/";
-  public static final String RESOURCES_DIR = "src/main/resources/";
+  public static final String SOURCE_DIR = getProjectRoot() + "src/main/java/";
+  public static final String LIBRARY_DESUGAR_SOURCE_DIR = getProjectRoot() + "src/library_desugar/";
   public static final String BUILD_DIR = getProjectRoot() + "build/";
   public static final String TEST_MODULE_DIR = getProjectRoot() + "d8_r8/test_modules/";
   public static final String GENERATED_TEST_BUILD_DIR = BUILD_DIR + "generated/test/";
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkDependency.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkDependency.java
index 26e9029..ceb6152 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkDependency.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkDependency.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.benchmarks;
 
+import com.android.tools.r8.ToolHelper;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Locale;
@@ -11,12 +12,12 @@
 
   public static BenchmarkDependency getRuntimeJarJava8() {
     return new BenchmarkDependency(
-        "java8rtjar", "openjdk-rt-1.8", Paths.get("third_party", "openjdk"));
+        "java8rtjar", "openjdk-rt-1.8", Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk"));
   }
 
   public static BenchmarkDependency getAndroidJar30() {
     return new BenchmarkDependency(
-        "android30jar", "lib-v30", Paths.get("third_party", "android_jar"));
+        "android30jar", "lib-v30", Paths.get(ToolHelper.THIRD_PARTY_DIR, "android_jar"));
   }
 
   // Nice name of the dependency. Must be a valid dart identifier.
diff --git a/src/test/java/com/android/tools/r8/benchmarks/desugaredlib/LegacyDesugaredLibraryBenchmark.java b/src/test/java/com/android/tools/r8/benchmarks/desugaredlib/LegacyDesugaredLibraryBenchmark.java
index a047c5a..0e86477 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/desugaredlib/LegacyDesugaredLibraryBenchmark.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/desugaredlib/LegacyDesugaredLibraryBenchmark.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.benchmarks.BenchmarkBase;
 import com.android.tools.r8.benchmarks.BenchmarkConfig;
 import com.android.tools.r8.benchmarks.BenchmarkDependency;
@@ -26,7 +27,9 @@
   private static final BenchmarkDependency androidJar = BenchmarkDependency.getAndroidJar30();
   private static final BenchmarkDependency legacyConf =
       new BenchmarkDependency(
-          "legacyConf", "desugar_jdk_libs_legacy", Paths.get("third_party", "openjdk"));
+          "legacyConf",
+          "desugar_jdk_libs_legacy",
+          Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk"));
 
   public LegacyDesugaredLibraryBenchmark(BenchmarkConfig config, TestParameters parameters) {
     super(config, parameters);
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClInitMergeSuperTypeApiLevelTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClInitMergeSuperTypeApiLevelTest.java
new file mode 100644
index 0000000..27890cf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClInitMergeSuperTypeApiLevelTest.java
@@ -0,0 +1,128 @@
+// Copyright (c) 2023, 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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/** This is a regression test for b/289361079. */
+@RunWith(Parameterized.class)
+public class ClInitMergeSuperTypeApiLevelTest extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  private TypeReference getMergeReferenceForApiLevel() {
+    boolean canUseExecutable =
+        parameters.isDexRuntime()
+            && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.O);
+    return Reference.typeFromTypeName(typeName(canUseExecutable ? Executable.class : Object.class));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        // Emulate a standard AGP setup where we compile with a new android jar on boot classpath.
+        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.LATEST))
+        .addInnerClasses(getClass())
+        .setMinApi(parameters)
+        .addKeepClassAndMembersRules(Main.class)
+        .addHorizontallyMergedClassesInspector(
+            inspector -> inspector.assertClassesMerged(A.class, B.class))
+        .enableInliningAnnotations()
+        .compile()
+        .inspect(
+            inspector -> {
+              ClassSubject clazz = inspector.clazz(A.class);
+              assertThat(clazz, isPresent());
+              MethodSubject init = clazz.uniqueInstanceInitializer();
+              assertThat(init, isPresent());
+              TypeReference mergeTypeRef = getMergeReferenceForApiLevel();
+              assertEquals(mergeTypeRef, init.getParameter(0).getTypeReference());
+              assertTrue(
+                  clazz.allFields().stream()
+                      .anyMatch(f -> mergeTypeRef.equals(f.getFinalReference().getFieldType())));
+            })
+        .run(parameters.getRuntime(), Main.class)
+        // The test succeeds for some unknown reason.
+        .assertSuccessWithOutputLines(typeName(Main.class));
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) throws Exception {
+      if (System.currentTimeMillis() > 0) {
+        System.out.println(
+            new A(Main.class.getDeclaredConstructor()).newInstance().getClass().getName());
+      } else {
+        System.out.println(
+            new B(Main.class.getDeclaredMethod("main", String[].class))
+                .newInstance()
+                .getClass()
+                .getName());
+      }
+    }
+  }
+
+  public abstract static class Factory {
+
+    abstract Object newInstance() throws Exception;
+  }
+
+  public static class A extends Factory {
+
+    public final Constructor<?> constructor;
+
+    public A(Constructor<?> constructor) {
+      this.constructor = constructor;
+    }
+
+    @Override
+    @NeverInline
+    Object newInstance() throws Exception {
+      return constructor.newInstance();
+    }
+  }
+
+  public static class B extends Factory {
+
+    public final Method method;
+
+    public B(Method method) {
+      this.method = method;
+    }
+
+    @Override
+    @NeverInline
+    Object newInstance() throws Exception {
+      return method.invoke(null);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/GuavaMultiSetSpliteratorTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/GuavaMultiSetSpliteratorTest.java
index 5e75ab4..a8fd859 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/GuavaMultiSetSpliteratorTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/GuavaMultiSetSpliteratorTest.java
@@ -63,6 +63,7 @@
       Assume.assumeTrue(parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L));
     }
     testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        // TODO(b/289363570): Guava should not rely on dagger.
         .addProgramFiles(DaggerUtils.getGuavaFromDagger())
         .addInnerClasses(getClass())
         .addOptionsModification(opt -> opt.ignoreMissingClasses = true)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
index 202d752..ce9ae53 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
@@ -41,7 +41,8 @@
 @RunWith(Parameterized.class)
 public class LintFilesTest extends DesugaredLibraryTestBase {
 
-  private static final String ANDROID_JAR_34 = "third_party/android_jar/lib-v34/android.jar";
+  private static final String ANDROID_JAR_34 =
+      ToolHelper.THIRD_PARTY_DIR + "android_jar/lib-v34/android.jar";
 
   private final LibraryDesugaringSpecification libraryDesugaringSpecification;
 
@@ -170,7 +171,12 @@
         new String[] {
           libraryDesugaringSpecification.getSpecification().toString(),
           jdkLibJar.toString(),
-          directory.toString()
+          directory.toString(),
+          // TODO(b/289365156): Should probably not be hardcoded on U.
+          ToolHelper.THIRD_PARTY_DIR
+              + "android_jar/lib-v"
+              + AndroidApiLevel.U.getLevel()
+              + "/android.jar"
         });
     InternalOptions options = new InternalOptions(new DexItemFactory(), new Reporter());
     DesugaredLibrarySpecification desugaredLibrarySpecification =
@@ -213,7 +219,12 @@
           "--generate-api-docs",
           libraryDesugaringSpecification.getSpecification().toString(),
           jdkLibJar.toString(),
-          directory2.toString()
+          directory2.toString(),
+          // TODO(b/289365156): Should probably not be hardcoded on U.
+          ToolHelper.THIRD_PARTY_DIR
+              + "android_jar/lib-v"
+              + AndroidApiLevel.U.getLevel()
+              + "/android.jar"
         });
     List<String> html = Files.readAllLines(directory2.resolve("apis.html"));
     // The doc has the same content than the lint data that is tested above, this is just a sanity
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonDesugaredLibraryTestUtils.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonDesugaredLibraryTestUtils.java
index b07f7b9..655e117 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonDesugaredLibraryTestUtils.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonDesugaredLibraryTestUtils.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary.gson;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
 import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import java.io.IOException;
@@ -14,8 +15,12 @@
 public abstract class GsonDesugaredLibraryTestUtils {
 
   static final Path GSON_CONFIGURATION =
-      Paths.get("src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/gson.cfg");
-  static final Path GSON_2_8_1_JAR = Paths.get("third_party/iosched_2019/gson-2.8.1.jar");
+      ToolHelper.getSourceFileForTestClass(GsonDesugaredLibraryTestUtils.class)
+          .getParent()
+          .resolve("gson.cfg");
+  // TODO(b/289363570): GSON should not rely on Iosched.
+  static final Path GSON_2_8_1_JAR =
+      Paths.get(ToolHelper.THIRD_PARTY_DIR, "iosched_2019/gson-2.8.1.jar");
 
   static String uniqueName(
       TemporaryFolder temp,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TestLibraryDesugaringSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TestLibraryDesugaringSpecification.java
index f909be9..6eabf06 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TestLibraryDesugaringSpecification.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TestLibraryDesugaringSpecification.java
@@ -33,9 +33,10 @@
   private static final String EXTENSION_STRING = "build/libs/java_base_extension.jar";
 
   private static final Path JDK_11_JAVA_BASE_EXTENSION_FILES_DIR =
-      Paths.get("third_party/openjdk/jdk-11-test/lib/testlibrary/bootlib/java.base");
+      Paths.get(
+          ToolHelper.THIRD_PARTY_DIR, "openjdk/jdk-11-test/lib/testlibrary/bootlib/java.base");
   private static final Path JDK_11_TESTLIBRARY_FILES_DIR =
-      Paths.get("third_party/openjdk/jdk-11-test/lib/testlibrary/jdk");
+      Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk/jdk-11-test/lib/testlibrary/jdk");
 
   public static Path EXTENSION_PATH;
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
index 7f89255..b82ba3e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
@@ -181,7 +181,7 @@
     this(
         name,
         ImmutableSet.of(desugarJdkLibs, ToolHelper.getDesugarLibConversions(legacy)),
-        Paths.get("src/library_desugar/" + specificationPath),
+        Paths.get(ToolHelper.LIBRARY_DESUGAR_SOURCE_DIR + specificationPath),
         ImmutableSet.of(ToolHelper.getAndroidJar(androidJarLevel)),
         descriptor,
         "");
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineCallSiteInlinedTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineCallSiteInlinedTest.java
index 2e55faf..df61bf9 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineCallSiteInlinedTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineCallSiteInlinedTest.java
@@ -55,52 +55,48 @@
           "com.android.tools.r8.D8Command -> com.android.tools.r8.D8Command:",
           "# {'id':'sourceFile','fileName':'SourceFile'}",
           "    1:724:foo.internal.MapConsumer lambda$bar$0(foo.StringConsumer):0:723"
-              + " -> lambda$bar$0$com-android-tools-r8-D8Command",
+              + " -> lambda$bar$0$new",
           "    1:724:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):0"
-              + " -> lambda$bar$0$com-android-tools-r8-D8Command",
+              + " lambda$bar$0$new(foo.StringConsumer):0"
+              + " -> lambda$bar$0$new",
           "      # {'id':'com.android.tools.r8.synthesized'}");
   private static final String mappingResult =
       StringUtils.unixLines(
           "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
           "com.android.tools.r8.D8Command -> com.android.tools.r8.D8Command:",
           "# {'id':'sourceFile','fileName':'D8Command.java'}",
-          // TODO(b/288117378): This 1:1 range corresponds to position 0 in the residual of R8. This
-          //  should probably not have the `getParseFlagsInformation` inline frame.
           "    1:1:java.util.List getParseFlagsInformation():592:592 -> getParseFlagsInformation",
+          // The following two frames is the preamble it is mapping to position 0. There is no
+          // positional information in mappingFoo, so the right thing here is to use the original
+          // signature from mappingBar/residual signature from mappingFoo.
           "    1:1:foo.internal.MapConsumer lambda$bar$0(foo.StringConsumer):0:0 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
+              + " lambda$bar$0$new",
           "    1:1:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):0:0 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
+              + " lambda$bar$0$new(foo.StringConsumer):0:0 -> lambda$bar$0$new",
           "    # {'id':'com.android.tools.r8.synthesized'}",
-          "    2:2:foo.MapConsumer lambda$bar$0(foo.StringConsumer):0:0 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
+          // This frame is the outline position in mappingFoo.
+          "    2:2:foo.MapConsumer lambda$bar$0(foo.StringConsumer):0:0 -> lambda$bar$0$new",
           "    # {'id':'com.android.tools.r8.residualsignature',"
               + "'signature':'(Lfoo/StringConsumer;)Lfoo/internal/MapConsumer;'}",
           "    # {'id':'com.android.tools.r8.outlineCallsite',"
               + "'positions':{'23':725,'24':726,'25':727},"
               + "'outline':'Lfoo/SomeClass;outline(JJJ)V'}",
           "    2:2:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):0:0 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
-          "    3:724:foo.internal.MapConsumer lambda$bar$0(foo.StringConsumer) ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
-          "    3:724:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):0:0 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
-          "    725:725:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):720:720 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
-          "    726:726:foo.PGMapConsumer foo.PGMapConsumer.builder():52:52 -> lambda$bar$0",
-          "    726:726:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):720 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
-          "    727:727:void foo.PGMapConsumer.<init>():55:55 -> lambda$bar$0",
-          "    727:727:foo.PGMapConsumer foo.PGMapConsumer.builder():52 -> lambda$bar$0",
-          "    727:727:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):720 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command");
+              + " lambda$bar$0$new(foo.StringConsumer):0:0 -> lambda$bar$0$new",
+          // This is the tail before any synthetic outline positions where the only information
+          // is in mappingBar.
+          "    3:724:foo.internal.MapConsumer lambda$bar$0(foo.StringConsumer) -> lambda$bar$0$new",
+          "    3:724:foo.internal.MapConsumer lambda$bar$0$new(foo.StringConsumer):0:0 "
+              + "-> lambda$bar$0$new",
+          // The remaining positions are the synthetic outline positions needed for correct
+          // retracing.
+          "    725:725:foo.MapConsumer lambda$bar$0(foo.StringConsumer):720:720 "
+              + "-> lambda$bar$0$new",
+          "    726:726:foo.PGMapConsumer foo.PGMapConsumer.builder():52:52 -> lambda$bar$0$new",
+          "    726:726:foo.MapConsumer lambda$bar$0(foo.StringConsumer):720 -> lambda$bar$0$new",
+          "    727:727:void foo.PGMapConsumer.<init>():55:55 -> lambda$bar$0$new",
+          "    727:727:foo.PGMapConsumer foo.PGMapConsumer.builder():52 -> lambda$bar$0$new",
+          "    727:727:foo.MapConsumer lambda$bar$0(foo.StringConsumer):720 -> lambda$bar$0$new");
 
   @Test
   public void testCompose() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlinePositionRangeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlinePositionRangeTest.java
new file mode 100644
index 0000000..753f3d7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlinePositionRangeTest.java
@@ -0,0 +1,76 @@
+// Copyright (c) 2023, 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.mappingcompose;
+
+import static com.android.tools.r8.mappingcompose.ComposeTestHelpers.doubleToSingleQuote;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MappingComposer;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/** This is a regression test for b/280564959. */
+@RunWith(Parameterized.class)
+public class ComposeOutlinePositionRangeTest extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  private static final String mappingFoo =
+      StringUtils.unixLines(
+          "# { id: 'com.android.tools.r8.mapping', version: '2.2' }",
+          "outline.Class -> a:",
+          "    1:2:int outline():11:12 -> a",
+          "    # { 'id':'com.android.tools.r8.outline' }",
+          "outline.Callsite -> x:",
+          "    1:1:int outlineCaller(int):0:0 -> s",
+          "    # { 'id':'com.android.tools.r8.outlineCallsite',"
+              + "'positions': { '1': 10, '2': 11 },"
+              + "'outline':'La;a()I' }",
+          "    10:11:int some.inlinee(int):23:24 -> s",
+          "    10:11:int outlineCaller(int):1337 -> s");
+  private static final String mappingBar =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "a -> b:",
+          "    4:5:int a():1:2 -> m",
+          "x -> y:",
+          "    42:42:int s(int):1:1 -> o");
+  private static final String mappingResult =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "outline.Callsite -> y:",
+          "    42:42:int outlineCaller(int):0:0 -> o",
+          "    # {'id':'com.android.tools.r8.outlineCallsite',"
+              + "'positions':{'4':43,'5':44},"
+              + "'outline':'Lb;m()I'}",
+          "    43:43:int some.inlinee(int):23:23 -> o",
+          "    43:43:int outlineCaller(int):1337 -> o",
+          "    44:44:int some.inlinee(int):24:24 -> o",
+          "    44:44:int outlineCaller(int):1337 -> o",
+          "outline.Class -> b:",
+          "    4:5:int outline():11:12 -> m",
+          "    # {'id':'com.android.tools.r8.outline'}");
+
+  @Test
+  public void testCompose() throws Exception {
+    ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromStringWithPreamble(mappingFoo);
+    ClassNameMapper mappingForBar = ClassNameMapper.mapperFromStringWithPreamble(mappingBar);
+    String composed = MappingComposer.compose(mappingForFoo, mappingForBar);
+    assertEquals(mappingResult, doubleToSingleQuote(composed));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java
index 48bfdfd..98ba4d5 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java
@@ -62,7 +62,7 @@
               + "'positions':{'4':43,'5':44},"
               + "'outline':'Lc;m()I'}",
           "    43:43:int outlineCaller(int):23:23 -> o",
-          "    44:44:int foo.bar.baz.outlineCaller(int):98:98 -> s",
+          "    44:44:int foo.bar.baz.outlineCaller(int):98:98 -> o",
           "    44:44:int outlineCaller(int):24 -> o",
           "outline.Class -> c:",
           "    4:5:int some.inlinee():75:76 -> m",
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineWithIdRangeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineWithIdRangeTest.java
index 20b1cb8..e79ad2c 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineWithIdRangeTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineWithIdRangeTest.java
@@ -66,7 +66,7 @@
               + "'positions':{'1':9,'2':10},"
               + "'outline':'Lpackage/new_internal/X;b(JJJ)J'}",
           "    8:8:void foo():38:38 -> b",
-          "    9:9:void inlineeInOutline():1337:1337 -> a",
+          "    9:9:void inlineeInOutline():1337:1337 -> b",
           "    9:9:void foo():42 -> b",
           "    10:10:void foo():44:44 -> b",
           "package.Class$$ExternalSyntheticOutline0 -> package.new_internal.X:",
diff --git a/src/test/java/com/android/tools/r8/naming/FieldMinificationResidualSignatureTest.java b/src/test/java/com/android/tools/r8/naming/FieldMinificationResidualSignatureTest.java
new file mode 100644
index 0000000..6466424
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/FieldMinificationResidualSignatureTest.java
@@ -0,0 +1,98 @@
+// Copyright (c) 2023, 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.naming;
+
+import static com.android.tools.r8.CollectorsUtils.toSingle;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessagesImpl;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.FieldReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.Retracer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.Box;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class FieldMinificationResidualSignatureTest extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withSystemRuntime().build();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    Box<FieldReference> minifiedMainField = new Box<>();
+    Box<FieldReference> minifiedBField = new Box<>();
+    String proguardMap =
+        testForR8(parameters.getBackend())
+            .addInnerClasses(getClass())
+            .setMinApi(AndroidApiLevel.B)
+            .addKeepMainRule(Main.class)
+            .addKeepAllClassesRuleWithAllowObfuscation()
+            .compile()
+            .inspect(
+                inspector -> {
+                  minifiedMainField.set(
+                      inspector.clazz(Main.class).allFields().get(0).getFinalReference());
+                  minifiedBField.set(
+                      inspector.clazz(B.class).allFields().get(0).getFinalReference());
+                })
+            .run(parameters.getRuntime(), Main.class)
+            .assertSuccessWithOutputLines("Hello World!")
+            .proguardMap();
+    Retracer retracer =
+        Retracer.createDefault(
+            ProguardMapProducer.fromString(proguardMap), new TestDiagnosticMessagesImpl());
+    assertEquals(
+        Reference.fieldFromField(Main.class.getDeclaredField("a")),
+        retracer.retraceField(minifiedMainField.get()).stream()
+            .map(rfe -> rfe.getField().asKnown().getFieldReference())
+            .collect(toSingle()));
+    assertEquals(
+        Reference.fieldFromField(B.class.getDeclaredField("worldContainer")),
+        retracer.retraceField(minifiedBField.get()).stream()
+            .map(rfe -> rfe.getField().asKnown().getFieldReference())
+            .collect(toSingle()));
+  }
+
+  public static class Main {
+
+    private static final Container a = new Container("Hello ");
+
+    public static void main(String[] args) {
+      System.out.println(a.getMessage() + B.worldContainer.getMessage());
+    }
+  }
+
+  public static class Container {
+
+    private final String message;
+
+    public Container(String message) {
+      this.message = message;
+    }
+
+    public String getMessage() {
+      return message;
+    }
+  }
+
+  public static class B {
+
+    public static final Container worldContainer = new Container("World!");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
index 9dc47ba..f49e491 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
@@ -204,7 +204,7 @@
 
     FieldSubject anX = lookupAnX(inspector);
     FieldSubject anArrayOfX = lookupAnArrayOfX(inspector);
-    FieldSubject aFieldsOfX =lookupAFieldsOfX(inspector);
+    FieldSubject aFieldsOfX = lookupAFieldsOfX(inspector);
     FieldSubject aFieldsOfXInner = clazz.field("Fields$Inner", "aFieldsOfXInner");
 
     // Check that all fields have been renamed
diff --git a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
index 81a977b..045cc76 100644
--- a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
@@ -13,9 +13,11 @@
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.DataEntryResource;
+import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.StreamUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -54,66 +56,72 @@
   @Test
   public void test() throws IOException, CompilationFailedException, ExecutionException {
     Path path = temp.newFile("out.zip").toPath();
-    testForR8(parameters.getBackend())
-        .addInnerClasses(ScriptEngineTest.class)
-        .addKeepMainRule(TestClass.class)
-        .applyIf(
-            parameters.isDexRuntime(),
-            testBuilder ->
-                testBuilder.addOptionsModification(
-                    options ->
-                        options
-                            .getOpenClosedInterfacesOptions()
-                            .suppressAllOpenInterfacesDueToMissingClasses()))
-        .setMinApi(parameters)
-        .addDataEntryResources(
-            DataEntryResource.fromBytes(
-                StringUtils.lines(MyScriptEngine1FactoryImpl.class.getTypeName()).getBytes(),
-                "META-INF/services/" + ScriptEngineFactory.class.getTypeName(),
-                Origin.unknown()))
-        .addDataEntryResources(
-            DataEntryResource.fromBytes(
-                StringUtils.lines(MyScriptEngine2FactoryImpl.class.getTypeName()).getBytes(),
-                "META-INF/services/" + ScriptEngineFactory.class.getTypeName(),
-                Origin.unknown()))
-        .apply(
-            b -> {
-              if (parameters.isDexRuntime()) {
-                addRhinoForAndroid(b);
-                b.allowDiagnosticWarningMessages();
-              }
-            })
-        // TODO(b/136633154): This should work both with and without -dontobfuscate.
-        .addDontObfuscate()
-        // TODO(b/136633154): This should work both with and without -dontshrink.
-        .noTreeShaking()
-        .compile()
-        .applyIf(
-            parameters.isDexRuntime(),
-            result ->
-                result.assertAllWarningMessagesMatch(
-                    anyOf(
-                        containsString("Missing class "),
-                        containsString(
-                            "it is required for default or static interface methods desugaring"),
-                        allOf(
-                            containsString("Unverifiable code in `"),
-                            containsString("org.mozilla.javascript.tools.")),
-                        equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))))
-        .writeToZip(path)
-        .run(parameters.getRuntime(), TestClass.class)
-        // TODO(b/136633154): This should provide 2 script engines on both runtimes. The use of
-        //  the rhino-android library on Android will add the Rhino script engine, and the JVM
-        //  comes with "Oracle Nashorn" included.
-        .assertSuccessWithOutput(
-            parameters.isCfRuntime()
-                // No default JS engine starting from JDK-14 where Nashorn was removed,
-                // see b/227162584.
-                ? (parameters.isCfRuntime()
-                        && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14)
-                    ? StringUtils.lines("MyEngine1", "MyEngine2")
-                    : StringUtils.lines("MyEngine1", "MyEngine2", "Oracle Nashorn"))
-                : StringUtils.lines("Mozilla Rhino", "MyEngine1", "MyEngine2"));
+    R8TestRunResult runResult =
+        testForR8(parameters.getBackend())
+            .addInnerClasses(ScriptEngineTest.class)
+            .addKeepMainRule(TestClass.class)
+            .applyIf(
+                parameters.isDexRuntime(),
+                testBuilder ->
+                    testBuilder.addOptionsModification(
+                        options ->
+                            options
+                                .getOpenClosedInterfacesOptions()
+                                .suppressAllOpenInterfacesDueToMissingClasses()))
+            .setMinApi(parameters)
+            .addDataEntryResources(
+                DataEntryResource.fromBytes(
+                    StringUtils.lines(MyScriptEngine1FactoryImpl.class.getTypeName()).getBytes(),
+                    "META-INF/services/" + ScriptEngineFactory.class.getTypeName(),
+                    Origin.unknown()))
+            .addDataEntryResources(
+                DataEntryResource.fromBytes(
+                    StringUtils.lines(MyScriptEngine2FactoryImpl.class.getTypeName()).getBytes(),
+                    "META-INF/services/" + ScriptEngineFactory.class.getTypeName(),
+                    Origin.unknown()))
+            .apply(
+                b -> {
+                  if (parameters.isDexRuntime()) {
+                    addRhinoForAndroid(b);
+                    b.allowDiagnosticWarningMessages();
+                  }
+                })
+            // TODO(b/136633154): This should work both with and without -dontobfuscate.
+            .addDontObfuscate()
+            // TODO(b/136633154): This should work both with and without -dontshrink.
+            .noTreeShaking()
+            .compile()
+            .applyIf(
+                parameters.isDexRuntime(),
+                result ->
+                    result.assertAllWarningMessagesMatch(
+                        anyOf(
+                            containsString("Missing class "),
+                            containsString(
+                                "it is required for default or static interface methods"
+                                    + " desugaring"),
+                            allOf(
+                                containsString("Unverifiable code in `"),
+                                containsString("org.mozilla.javascript.tools.")),
+                            equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))))
+            .writeToZip(path)
+            .run(parameters.getRuntime(), TestClass.class);
+    if (parameters.isDexRuntimeVersion(Version.V7_0_0)) {
+      // TODO(b/290592800): sun.misc.Service is defined on bootclasspath for android 7.
+      runResult.assertFailureWithErrorThatThrows(IllegalAccessError.class);
+    } else {
+      // TODO(b/136633154): This should provide 2 script engines on both runtimes. The use of
+      //  the rhino-android library on Android will add the Rhino script engine, and the JVM
+      //  comes with "Oracle Nashorn" included.
+      runResult.assertSuccessWithOutput(
+          parameters.isCfRuntime()
+              // No default JS engine starting from JDK-14 where Nashorn was removed,
+              // see b/227162584.
+              ? (parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK14)
+                  ? StringUtils.lines("MyEngine1", "MyEngine2")
+                  : StringUtils.lines("MyEngine1", "MyEngine2", "Oracle Nashorn"))
+              : StringUtils.lines("Mozilla Rhino", "MyEngine1", "MyEngine2"));
+    }
 
     // TODO(b/136633154): On the JVM this should always be there as the service loading is in
     //  the library. On Android we should be able to rewrite the code and not have it.
diff --git a/src/test/java/com/android/tools/r8/utils/DaggerUtils.java b/src/test/java/com/android/tools/r8/utils/DaggerUtils.java
index 80fad3d..685c0e7 100644
--- a/src/test/java/com/android/tools/r8/utils/DaggerUtils.java
+++ b/src/test/java/com/android/tools/r8/utils/DaggerUtils.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.ToolHelper;
 import com.google.common.collect.ImmutableList;
 import com.google.common.io.ByteStreams;
 import java.nio.file.Path;
@@ -20,7 +21,7 @@
 
 public class DaggerUtils {
 
-  private static final Path DAGGER_ROOT = Paths.get("third_party", "dagger", "2.41");
+  private static final Path DAGGER_ROOT = Paths.get(ToolHelper.THIRD_PARTY_DIR, "dagger", "2.41");
 
   private static final String GUAVA = "guava-31.0.1-jre.jar";
   private static final List<Path> DAGGER_COMPILER =
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
index abc83be..c9aeccb 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
@@ -57,6 +57,13 @@
       return signature;
     }
 
+    // First check if we have residual signature information.
+
+    MemberNaming memberNaming = clazz.getNaming().lookup(signature);
+    if (memberNaming != null) {
+      return memberNaming.getOriginalSignature().asFieldSignature();
+    }
+
     // Map the type to the original name. This is needed as the in the Proguard map the
     // names on the left side are the original names. E.g.
     //
@@ -70,9 +77,9 @@
     String fieldType = originalType != null ? originalType : obfuscatedType;
     FieldSignature lookupSignature = new FieldSignature(signature.name, fieldType);
 
-    MemberNaming memberNaming = clazz.getNaming().lookup(lookupSignature);
+    memberNaming = clazz.getNaming().lookup(lookupSignature);
     return memberNaming != null
-        ? (FieldSignature) memberNaming.getOriginalSignature()
+        ? memberNaming.getOriginalSignature().asFieldSignature()
         : lookupSignature;
   }
 
@@ -148,7 +155,7 @@
   public FieldReference getFinalReference() {
     return Reference.field(
         Reference.classFromDescriptor(getField().getHolderType().toDescriptorString()),
-        getOriginalName(),
+        getFinalName(),
         Reference.typeFromDescriptor(getField().getType().toDescriptorString()));
   }
 
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java
index 5761b99..efa2c30 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/TypeSubject.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.references.TypeReference;
 
 public class TypeSubject extends Subject {
 
@@ -21,6 +22,10 @@
     return dexType.getTypeName();
   }
 
+  public TypeReference getTypeReference() {
+    return dexType.asTypeReference();
+  }
+
   @Override
   public boolean isPresent() {
     return true;