Ensure a SourceFile attribute for synthesized code

For now use a fixed value if the synthetic code did not explicitly
add a SourceFile attribute.

Bug: 187491007
Bug: 187672208
Change-Id: I0bbe123d7dca72dcf0a7546e831a384b43752c16
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 2d0e429..ce36598 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -177,6 +177,10 @@
     return sourceFile;
   }
 
+  public void setSourceFile(DexString sourceFile) {
+    this.sourceFile = sourceFile;
+  }
+
   public Iterable<DexEncodedField> fields() {
     return fields(Predicates.alwaysTrue());
   }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
index de86111..a63a1e7 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
 import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
@@ -321,6 +322,13 @@
     return true;
   }
 
+  private static void ensureSourceFile(
+      DexProgramClass externalSyntheticClass, DexString syntheticSourceFileName) {
+    if (externalSyntheticClass.getSourceFile() == null) {
+      externalSyntheticClass.setSourceFile(syntheticSourceFileName);
+    }
+  }
+
   private static DexApplication buildLensAndProgram(
       AppView<?> appView,
       Map<DexType, EquivalenceGroup<SyntheticMethodDefinition>> syntheticMethodGroups,
@@ -415,6 +423,11 @@
       application = builder.build();
     }
 
+    DexString syntheticSourceFileName =
+        appView.enableWholeProgramOptimizations()
+            ? appView.dexItemFactory().createString("R8$$SyntheticClass")
+            : appView.dexItemFactory().createString("D8$$SyntheticClass");
+
     // Add the synthesized from after repackaging which changed class definitions.
     final DexApplication appForLookup = application;
     syntheticClassGroups.forEach(
@@ -422,6 +435,7 @@
           DexProgramClass externalSyntheticClass = appForLookup.programDefinitionFor(syntheticType);
           assert externalSyntheticClass != null
               : "Expected definition for " + syntheticType.getTypeName();
+          ensureSourceFile(externalSyntheticClass, syntheticSourceFileName);
           SyntheticProgramClassDefinition representative = syntheticGroup.getRepresentative();
           addFinalSyntheticClass.accept(
               externalSyntheticClass,
@@ -433,6 +447,7 @@
     syntheticMethodGroups.forEach(
         (syntheticType, syntheticGroup) -> {
           DexProgramClass externalSyntheticClass = appForLookup.programDefinitionFor(syntheticType);
+          ensureSourceFile(externalSyntheticClass, syntheticSourceFileName);
           SyntheticMethodDefinition representative = syntheticGroup.getRepresentative();
           assert externalSyntheticClass.getMethodCollection().size() == 1;
           assert externalSyntheticClass.getMethodCollection().hasDirectMethods();
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
index 3a923e0..640796d 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/LambdaInStacktraceTest.java
@@ -3,11 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.lambdas;
 
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 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.utils.StringUtils;
 import java.util.ArrayList;
 import java.util.List;
@@ -35,6 +37,17 @@
       StringUtils.lines(
           "getStacktraceWithFileNames(" + fileName + ")",
           "lambda$main$0(" + fileName + ")",
+          "call(D8$$SyntheticClass)",
+          "main(" + fileName + ")",
+          "getStacktraceWithFileNames(" + fileName + ")",
+          "lambda$main$1(" + fileName + ")",
+          "call(D8$$SyntheticClass)",
+          "main(" + fileName + ")");
+
+  static final String EXPECTED_D8_ANDROID_O =
+      StringUtils.lines(
+          "getStacktraceWithFileNames(" + fileName + ")",
+          "lambda$main$0(" + fileName + ")",
           "call(NULL)",
           "main(" + fileName + ")",
           "getStacktraceWithFileNames(" + fileName + ")",
@@ -43,6 +56,7 @@
           "main(" + fileName + ")");
 
   private final TestParameters parameters;
+  private final boolean isAndroidOOrLater;
   private final boolean isDalvik;
 
   @Parameterized.Parameters(name = "{0}")
@@ -53,6 +67,9 @@
   public LambdaInStacktraceTest(TestParameters parameters) {
     this.parameters = parameters;
     isDalvik = parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isDalvik();
+    isAndroidOOrLater =
+        parameters.isDexRuntime()
+            && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V8_1_0);
   }
 
   @Test
@@ -71,7 +88,26 @@
         .addInnerClasses(LambdaInStacktraceTest.class)
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), TestRunner.class, Boolean.toString(isDalvik))
-        .assertSuccessWithOutput(EXPECTED_D8);
+        .assertSuccessWithOutput(isAndroidOOrLater ? EXPECTED_D8_ANDROID_O : EXPECTED_D8);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    assumeTrue(parameters.getRuntime().isDex());
+    String stdout =
+        testForR8(parameters.getBackend())
+            .addInnerClasses(LambdaInStacktraceTest.class)
+            .setMinApi(parameters.getApiLevel())
+            .addKeepMainRule(TestRunner.class)
+            .addKeepAttributeSourceFile()
+            .addKeepRules("-renamesourcefileattribute SourceFile")
+            .noTreeShaking()
+            .run(parameters.getRuntime(), TestRunner.class, Boolean.toString(isDalvik))
+            .assertSuccess()
+            .getStdOut();
+    assertTrue(
+        StringUtils.splitLines(stdout).stream()
+            .allMatch(s -> s.contains(isAndroidOOrLater ? "NULL" : "SourceFile")));
   }
 
   static class TestRunner {