Add a test for adding lambdas to baseline profile

Bug: b/265729283
Change-Id: I375e37883e20078b03cdfd398448500ab5d470d4
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/SyntheticLambdaClassProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/SyntheticLambdaClassProfileRewritingTest.java
new file mode 100644
index 0000000..3e9ef1c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/SyntheticLambdaClassProfileRewritingTest.java
@@ -0,0 +1,97 @@
+// 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.profile.art.completeness;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.onlyIf;
+import static org.hamcrest.MatcherAssert.assertThat;
+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.profile.art.model.ExternalArtProfile;
+import com.android.tools.r8.profile.art.model.ExternalArtProfileMethodRule;
+import com.android.tools.r8.profile.art.utils.ArtProfileTestingUtils;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+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 SyntheticLambdaClassProfileRewritingTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .apply(
+            testBuilder ->
+                ArtProfileTestingUtils.addArtProfileForRewriting(
+                    getArtProfile(), this::inspectResidualArtProfile, testBuilder))
+        .noHorizontalClassMergingOfSynthetics()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .inspect(this::inspect)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("Hello, world!");
+  }
+
+  private ExternalArtProfile getArtProfile() {
+    return ExternalArtProfile.builder()
+        .addRule(
+            ExternalArtProfileMethodRule.builder()
+                .setMethodReference(MethodReferenceUtils.mainMethod(Main.class))
+                .build())
+        .build();
+  }
+
+  private void inspect(CodeInspector inspector) {
+    // Verify that two lambdas were synthesized when compiling to dex.
+    assertThat(
+        inspector.clazz(SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 0)),
+        onlyIf(parameters.isDexRuntime(), isPresent()));
+    assertThat(
+        inspector.clazz(SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 1)),
+        onlyIf(parameters.isDexRuntime(), isPresent()));
+  }
+
+  private void inspectResidualArtProfile(ExternalArtProfile residualArtProfile) {
+    if (parameters.isCfRuntime()) {
+      assertEquals(getArtProfile(), residualArtProfile);
+    } else {
+      assert parameters.isDexRuntime();
+      // TODO(b/265729283): Since Main.main() is in the art profile, so should the two synthetic
+      //  lambdas be.
+      assertEquals(getArtProfile(), residualArtProfile);
+    }
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      Runnable lambda =
+          System.currentTimeMillis() > 0
+              ? () -> System.out.println("Hello, world!")
+              : () -> {
+                throw new RuntimeException();
+              };
+      lambda.run();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfile.java b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfile.java
new file mode 100644
index 0000000..1c82f55
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfile.java
@@ -0,0 +1,69 @@
+// 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.profile.art.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * Represents an ART baseline profile (for testing).
+ *
+ * <p>This is similar to {@link com.android.tools.r8.profile.art.ArtProfile}, but unlike ArtProfile,
+ * this ExternalArtProfile is backed by {@link com.android.tools.r8.references.Reference}, and not
+ * {@link com.android.tools.r8.graph.DexItem}, so that no {@link
+ * com.android.tools.r8.graph.DexItemFactory} is needed to create an ExternalArtProfile.
+ */
+public class ExternalArtProfile {
+
+  private final List<ExternalArtProfileRule> rules;
+
+  ExternalArtProfile(List<ExternalArtProfileRule> rules) {
+    this.rules = rules;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public void forEach(
+      Consumer<ExternalArtProfileClassRule> classRuleConsumer,
+      Consumer<ExternalArtProfileMethodRule> methodRuleConsumer) {
+    for (ExternalArtProfileRule rule : rules) {
+      rule.accept(classRuleConsumer, methodRuleConsumer);
+    }
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    if (obj == null || getClass() != obj.getClass()) {
+      return false;
+    }
+    ExternalArtProfile profile = (ExternalArtProfile) obj;
+    return rules.equals(profile.rules);
+  }
+
+  @Override
+  public int hashCode() {
+    return rules.hashCode();
+  }
+
+  public static class Builder {
+
+    private final List<ExternalArtProfileRule> rules = new ArrayList<>();
+
+    public Builder addRule(ExternalArtProfileRule rule) {
+      rules.add(rule);
+      return this;
+    }
+
+    public ExternalArtProfile build() {
+      return new ExternalArtProfile(rules);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileClassRule.java b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileClassRule.java
new file mode 100644
index 0000000..84cc34b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileClassRule.java
@@ -0,0 +1,68 @@
+// 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.profile.art.model;
+
+import com.android.tools.r8.references.ClassReference;
+import java.util.function.Consumer;
+
+/**
+ * Represents a class rule from an ART baseline profile, backed by {@link ClassReference}. Class
+ * rules currently contain no other information than the class reference.
+ */
+public class ExternalArtProfileClassRule extends ExternalArtProfileRule {
+
+  private final ClassReference classReference;
+
+  ExternalArtProfileClassRule(ClassReference classReference) {
+    assert classReference != null;
+    this.classReference = classReference;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  @Override
+  public void accept(
+      Consumer<ExternalArtProfileClassRule> classRuleConsumer,
+      Consumer<ExternalArtProfileMethodRule> methodRuleConsumer) {
+    classRuleConsumer.accept(this);
+  }
+
+  public ClassReference getClassReference() {
+    return classReference;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    if (obj == null || getClass() != obj.getClass()) {
+      return false;
+    }
+    ExternalArtProfileClassRule methodRule = (ExternalArtProfileClassRule) obj;
+    return classReference.equals(methodRule.classReference);
+  }
+
+  @Override
+  public int hashCode() {
+    return classReference.hashCode();
+  }
+
+  public static class Builder {
+
+    private ClassReference classReference;
+
+    public Builder setClassReference(ClassReference classReference) {
+      this.classReference = classReference;
+      return this;
+    }
+
+    public ExternalArtProfileClassRule build() {
+      return new ExternalArtProfileClassRule(classReference);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileMethodRule.java b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileMethodRule.java
new file mode 100644
index 0000000..fae6dbe
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileMethodRule.java
@@ -0,0 +1,77 @@
+// 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.profile.art.model;
+
+import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfo;
+import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfoImpl;
+import com.android.tools.r8.references.MethodReference;
+import java.util.function.Consumer;
+
+/** Represents a method rule from an ART baseline profile, backed by {@link MethodReference}. */
+public class ExternalArtProfileMethodRule extends ExternalArtProfileRule {
+
+  private final MethodReference methodReference;
+  private final ArtProfileMethodRuleInfo methodRuleInfo;
+
+  ExternalArtProfileMethodRule(
+      MethodReference methodReference, ArtProfileMethodRuleInfo methodRuleInfo) {
+    assert methodReference != null;
+    assert methodRuleInfo != null;
+    this.methodReference = methodReference;
+    this.methodRuleInfo = methodRuleInfo;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  @Override
+  public void accept(
+      Consumer<ExternalArtProfileClassRule> classRuleConsumer,
+      Consumer<ExternalArtProfileMethodRule> methodRuleConsumer) {
+    methodRuleConsumer.accept(this);
+  }
+
+  public MethodReference getMethodReference() {
+    return methodReference;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    if (obj == null || getClass() != obj.getClass()) {
+      return false;
+    }
+    ExternalArtProfileMethodRule methodRule = (ExternalArtProfileMethodRule) obj;
+    return methodReference.equals(methodRule.methodReference);
+  }
+
+  @Override
+  public int hashCode() {
+    return methodReference.hashCode();
+  }
+
+  public static class Builder {
+
+    private MethodReference methodReference;
+    private ArtProfileMethodRuleInfo methodRuleInfo = ArtProfileMethodRuleInfoImpl.empty();
+
+    public Builder setMethodReference(MethodReference methodReference) {
+      this.methodReference = methodReference;
+      return this;
+    }
+
+    public Builder setMethodRuleInfo(ArtProfileMethodRuleInfo methodRuleInfo) {
+      this.methodRuleInfo = methodRuleInfo;
+      return this;
+    }
+
+    public ExternalArtProfileMethodRule build() {
+      return new ExternalArtProfileMethodRule(methodReference, methodRuleInfo);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileRule.java b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileRule.java
new file mode 100644
index 0000000..bd3c99e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileRule.java
@@ -0,0 +1,14 @@
+// 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.profile.art.model;
+
+import java.util.function.Consumer;
+
+public abstract class ExternalArtProfileRule {
+
+  public abstract void accept(
+      Consumer<ExternalArtProfileClassRule> classRuleConsumer,
+      Consumer<ExternalArtProfileMethodRule> methodRuleConsumer);
+}
diff --git a/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileTestingUtils.java b/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileTestingUtils.java
new file mode 100644
index 0000000..0fa755b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileTestingUtils.java
@@ -0,0 +1,95 @@
+// 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.profile.art.utils;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.profile.art.ArtProfileBuilder;
+import com.android.tools.r8.profile.art.ArtProfileClassRuleInfo;
+import com.android.tools.r8.profile.art.ArtProfileConsumer;
+import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfo;
+import com.android.tools.r8.profile.art.ArtProfileProvider;
+import com.android.tools.r8.profile.art.ArtProfileRuleConsumer;
+import com.android.tools.r8.profile.art.model.ExternalArtProfile;
+import com.android.tools.r8.profile.art.model.ExternalArtProfileClassRule;
+import com.android.tools.r8.profile.art.model.ExternalArtProfileMethodRule;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
+import java.util.function.Consumer;
+
+public class ArtProfileTestingUtils {
+
+  /**
+   * Adds the given {@param artProfile} as an ART profile for rewriting. The residual ART profile
+   * will be forwarded to the given test inspector, {@param residualArtProfileInspector}.
+   */
+  public static void addArtProfileForRewriting(
+      ExternalArtProfile artProfile,
+      Consumer<ExternalArtProfile> residualArtProfileInspector,
+      R8TestBuilder<?> testBuilder) {
+    // Provider for passing the original ART profile to the compilation.
+    ArtProfileProvider artProfileProvider =
+        new ArtProfileProvider() {
+
+          @Override
+          public void getArtProfile(ArtProfileBuilder profileBuilder) {
+            artProfile.forEach(
+                classRule ->
+                    profileBuilder.addClassRule(
+                        classRuleBuilder ->
+                            classRuleBuilder.setClassReference(classRule.getClassReference())),
+                methodRule ->
+                    profileBuilder.addMethodRule(
+                        methodRuleBuilder ->
+                            methodRuleBuilder.setMethodReference(methodRule.getMethodReference())));
+          }
+
+          @Override
+          public Origin getOrigin() {
+            return Origin.unknown();
+          }
+        };
+
+    // Consumer for accepting the residual ART profile from the compilation.
+    ArtProfileConsumer residualArtProfileConsumer =
+        new ArtProfileConsumer() {
+
+          final ExternalArtProfile.Builder residualArtProfileBuilder = ExternalArtProfile.builder();
+
+          @Override
+          public ArtProfileRuleConsumer getRuleConsumer() {
+            return new ArtProfileRuleConsumer() {
+
+              @Override
+              public void acceptClassRule(
+                  ClassReference classReference, ArtProfileClassRuleInfo classRuleInfo) {
+                residualArtProfileBuilder.addRule(
+                    ExternalArtProfileClassRule.builder()
+                        .setClassReference(classReference)
+                        .build());
+              }
+
+              @Override
+              public void acceptMethodRule(
+                  MethodReference methodReference, ArtProfileMethodRuleInfo methodRuleInfo) {
+                residualArtProfileBuilder.addRule(
+                    ExternalArtProfileMethodRule.builder()
+                        .setMethodReference(methodReference)
+                        .setMethodRuleInfo(methodRuleInfo)
+                        .build());
+              }
+            };
+          }
+
+          @Override
+          public void finished(DiagnosticsHandler handler) {
+            residualArtProfileInspector.accept(residualArtProfileBuilder.build());
+          }
+        };
+
+    testBuilder.addArtProfileForRewriting(artProfileProvider, residualArtProfileConsumer);
+  }
+}