Move generation of examples into another build/generated

Bug: b/270105162
Change-Id: Iceb105a1b4cbad6ec68d4d868837ba3cabe6d625
diff --git a/build.gradle b/build.gradle
index 7485331b..90167e9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -251,6 +251,7 @@
 
     examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
     examplesAndroidOCompile files("third_party/android_jar/lib-v26/android.jar")
+    examplesAndroidOCompile files("third_party/examplesAndroidOLegacy")
 
     examplesAndroidPCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
     // Import Guava for @Nullable annotation
@@ -313,6 +314,7 @@
                 "dagger/2.41",
                 "dart-sdk",
                 "ddmlib",
+                "examplesAndroidOLegacy",
                 "gradle/gradle",
                 "google/google-java-format/1.14.0",
                 "google-java-format",
@@ -1298,29 +1300,14 @@
 task buildExampleAndroidOJars {
     dependsOn downloadDeps
     def examplesDir = file("src/test/examplesAndroidO")
-    // NOTE: we want to enable a scenario when test needs to reference some
-    // classes generated by legacy (1.6) Java compiler to test some specific
-    // behaviour. To do so we compile all the java files located in sub-directory
-    // called 'legacy' with Java 1.6, then compile the rest of the files with
-    // Java 1.8 and a reference to previously generated 1.6 classes.
-
-    // Compiling all classes in dirs 'legacy' with old Java version.
-    task "compile_examplesAndroidO_Legacy"(type: JavaCompile) {
-        source = fileTree(dir: examplesDir, include: '**/legacy/**/*.java')
-        destinationDir = file("build/test/examplesAndroidOLegacy/classes")
-        classpath = sourceSets.main.compileClasspath
-        sourceCompatibility = JavaVersion.VERSION_1_6
-        targetCompatibility = JavaVersion.VERSION_1_6
-        options.compilerArgs += ["-Xlint:-options", "-parameters"]
-    }
     // Compiling the rest of the files as Java 1.8 code.
     task "compile_examplesAndroidO"(type: JavaCompile) {
-        dependsOn "compile_examplesAndroidO_Legacy"
         source = fileTree(dir: examplesDir, include: '**/*.java', exclude: '**/legacy/**/*.java')
         destinationDir = file("build/test/examplesAndroidO/classes")
         classpath = sourceSets.main.compileClasspath
         classpath += files("build/test/examplesAndroidOLegacy/classes")
-	classpath += files("third_party/android_jar/lib-v26/android.jar")
+        classpath += files("third_party/android_jar/lib-v26/android.jar")
+        classpath += files("third_party/examplesAndroidOLegacy")
         sourceCompatibility = JavaVersion.VERSION_1_8
         targetCompatibility = JavaVersion.VERSION_1_8
         options.compilerArgs += ["-Xlint:-options", "-parameters"]
@@ -1333,7 +1320,7 @@
                     dependsOn: "compile_examplesAndroidO") {
                 main = name + ".TestGenerator"
                 classpath = files(destinationDir, sourceSets.main.compileClasspath)
-                args destinationDir
+                args destinationDir, destinationDir
             }
         } else {
             task "generate_examplesAndroidO_${name}" () {}
@@ -1378,7 +1365,7 @@
                     dependsOn: "compile_examplesAndroidP") {
                 main = name + ".TestGenerator"
                 classpath = files(destinationDir, sourceSets.main.compileClasspath)
-                args destinationDir
+                args destinationDir, destinationDir
             }
         } else {
             task "generate_examplesAndroidP_${name}" () {}
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
index c0d6e1f..2a369cd 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -11,6 +11,7 @@
 import org.gradle.api.Project
 import org.gradle.api.Task
 import org.gradle.api.file.ConfigurableFileCollection
+import org.gradle.api.file.DuplicatesStrategy
 import org.gradle.api.plugins.JavaPluginExtension
 import org.gradle.api.tasks.JavaExec
 import org.gradle.api.tasks.SourceSet
@@ -116,6 +117,7 @@
     // The TEST_SOURCE_SET_NAME is the source set defined by writing java { sourcesets.test { ... }}
     .getByName(SourceSet.TEST_SOURCE_SET_NAME)
   val destinationDir = getRoot().resolveAll("build", "test", name)
+  val generateDir = getRoot().resolveAll("build", "generated", name)
   val classesOutput = destinationDir.resolve("classes")
   testSourceSet.java.destinationDirectory.set(classesOutput)
   testSourceSet.resources.destinationDirectory.set(destinationDir)
@@ -128,24 +130,35 @@
         arrayOf("compileTestJava", "debuginfo-all", "debuginfo-none").forEach { taskName ->
           if (!project.getTasksByName(taskName, false).isEmpty()) {
             var generationTask : Task? = null
-            val taskSpecificClassesOutput = getOutputName(classesOutput.toString(), taskName)
+            val compileOutput = getOutputName(classesOutput.toString(), taskName)
             if (exampleDir.resolve("TestGenerator.java").isFile) {
+              val generatedOutput = Paths.get(
+                getOutputName(generateDir.toString(), taskName), exampleDir.name).toString()
               generationTask = tasks.register<JavaExec>(
                 "generate-$name-${exampleDir.name}-$taskName") {
                 dependsOn(taskName)
                 mainClass.set("${exampleDir.name}.TestGenerator")
-                classpath = files(taskSpecificClassesOutput, testSourceSet.compileClasspath)
-                args(taskSpecificClassesOutput)
+                classpath = files(compileOutput, testSourceSet.compileClasspath)
+                args(compileOutput, generatedOutput)
+                outputs.dirs(generatedOutput)
               }.get()
             }
             jarTasks.add(tasks.register<Jar>("jar-$name-${exampleDir.name}-$taskName") {
               dependsOn(taskName)
-              if (generationTask != null) {
-                dependsOn(generationTask)
-              }
               archiveFileName.set("${getOutputName(exampleDir.name, taskName)}.jar")
               destinationDirectory.set(destinationDir)
-              from(taskSpecificClassesOutput) {
+              duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+              if (generationTask != null) {
+                // If a generation task exists, we first take the generated output and add to the
+                // current jar. Running with DuplicatesStrategy.EXCLUDE ensure that we do not
+                // overwrite with the non-generated file.
+                dependsOn(generationTask)
+                from(generationTask.outputs.files.singleFile.parentFile) {
+                  include("${exampleDir.name}/**/*.class")
+                  exclude("**/TestGenerator*")
+                }
+              }
+              from(compileOutput) {
                 include("${exampleDir.name}/**/*.class")
                 exclude("**/TestGenerator*")
               }
diff --git a/src/test/examplesAndroidO/invokecustom/TestGenerator.java b/src/test/examplesAndroidO/invokecustom/TestGenerator.java
index a4cd89a..4879521 100644
--- a/src/test/examplesAndroidO/invokecustom/TestGenerator.java
+++ b/src/test/examplesAndroidO/invokecustom/TestGenerator.java
@@ -13,6 +13,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
@@ -26,19 +27,24 @@
 public class TestGenerator {
 
   private final Path classNamePath;
+  private final Path outputClassNamePath;
 
   public static void main(String[] args) throws IOException {
-    assert args.length == 1;
-    TestGenerator testGenerator = new TestGenerator(Paths.get(args[0],
-        TestGenerator.class.getPackage().getName(), InvokeCustom.class.getSimpleName() + ".class"));
+    assert args.length == 2;
+    String fileName = InvokeCustom.class.getSimpleName() + ".class";
+    Path inputFile = Paths.get(args[0], TestGenerator.class.getPackage().getName(), fileName);
+    Path outputFile = Paths.get(args[1], fileName);
+    TestGenerator testGenerator = new TestGenerator(inputFile, outputFile);
     testGenerator.generateTests();
   }
 
-  public TestGenerator(Path classNamePath) {
+  public TestGenerator(Path classNamePath, Path outputClassNamePath) {
     this.classNamePath = classNamePath;
+    this.outputClassNamePath = outputClassNamePath;
   }
 
   private void generateTests() throws IOException {
+    Files.createDirectories(outputClassNamePath.getParent());
     try (InputStream input = Files.newInputStream(classNamePath)) {
       ClassReader cr = new ClassReader(input);
       ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -63,7 +69,8 @@
               super.visitEnd();
             }
           }, 0);
-      try (OutputStream output = Files.newOutputStream(classNamePath)) {
+      try (OutputStream output =
+          Files.newOutputStream(outputClassNamePath, StandardOpenOption.CREATE)) {
         output.write(cw.toByteArray());
       }
     }
diff --git a/src/test/examplesAndroidO/invokecustom2/TestGenerator.java b/src/test/examplesAndroidO/invokecustom2/TestGenerator.java
index 377084e..2a4eba4 100644
--- a/src/test/examplesAndroidO/invokecustom2/TestGenerator.java
+++ b/src/test/examplesAndroidO/invokecustom2/TestGenerator.java
@@ -14,6 +14,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
@@ -25,19 +26,24 @@
 public class TestGenerator {
 
   private final Path classNamePath;
+  private final Path outputClassNamePath;
 
   public static void main(String[] args) throws IOException {
-    assert args.length == 1;
-    TestGenerator testGenerator = new TestGenerator(Paths.get(args[0],
-        TestGenerator.class.getPackage().getName(), InvokeCustom.class.getSimpleName() + ".class"));
+    assert args.length == 2;
+    String fileName = invokecustom.InvokeCustom.class.getSimpleName() + ".class";
+    Path inputFile = Paths.get(args[0], TestGenerator.class.getPackage().getName(), fileName);
+    Path outputFile = Paths.get(args[1], fileName);
+    TestGenerator testGenerator = new TestGenerator(inputFile, outputFile);
     testGenerator.generateTests();
   }
 
-  public TestGenerator(Path classNamePath) {
+  public TestGenerator(Path classNamePath, Path outputClassNamePath) {
     this.classNamePath = classNamePath;
+    this.outputClassNamePath = outputClassNamePath;
   }
 
   private void generateTests() throws IOException {
+    Files.createDirectories(outputClassNamePath.getParent());
     try (InputStream input = Files.newInputStream(classNamePath)) {
       ClassReader cr = new ClassReader(input);
       ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -58,7 +64,8 @@
               super.visitEnd();
             }
           }, 0);
-      try (OutputStream output = Files.newOutputStream(classNamePath)) {
+      try (OutputStream output =
+          Files.newOutputStream(outputClassNamePath, StandardOpenOption.CREATE)) {
         output.write(cw.toByteArray());
       }
     }
diff --git a/src/test/examplesAndroidO/stringconcat/TestGenerator.java b/src/test/examplesAndroidO/stringconcat/TestGenerator.java
index 72bdfbf..4755c4d 100644
--- a/src/test/examplesAndroidO/stringconcat/TestGenerator.java
+++ b/src/test/examplesAndroidO/stringconcat/TestGenerator.java
@@ -12,6 +12,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.List;
 import org.objectweb.asm.ClassReader;
@@ -40,13 +41,16 @@
       false);
 
   public static void main(String[] args) throws IOException {
-    assert args.length == 1;
-    generateTests(Paths.get(args[0],
-        TestGenerator.class.getPackage().getName(),
-        StringConcat.class.getSimpleName() + ".class"));
+    assert args.length == 2;
+    String fileName = StringConcat.class.getSimpleName() + ".class";
+    Path inputFile = Paths.get(args[0], TestGenerator.class.getPackage().getName(), fileName);
+    Path outputFile = Paths.get(args[1], fileName);
+    generateTests(inputFile, outputFile);
   }
 
-  private static void generateTests(Path classNamePath) throws IOException {
+  private static void generateTests(Path classNamePath, Path outputClassNamePath)
+      throws IOException {
+    Files.createDirectories(outputClassNamePath.getParent());
     try (InputStream input = Files.newInputStream(classNamePath)) {
       ClassReader cr = new ClassReader(input);
       ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -221,7 +225,8 @@
               };
             }
           }, 0);
-      try (OutputStream output = Files.newOutputStream(classNamePath)) {
+      try (OutputStream output =
+          Files.newOutputStream(outputClassNamePath, StandardOpenOption.CREATE)) {
         output.write(cw.toByteArray());
       }
     }
diff --git a/src/test/examplesAndroidP/invokecustom/TestGenerator.java b/src/test/examplesAndroidP/invokecustom/TestGenerator.java
index b08441c..ef5f8de 100644
--- a/src/test/examplesAndroidP/invokecustom/TestGenerator.java
+++ b/src/test/examplesAndroidP/invokecustom/TestGenerator.java
@@ -13,6 +13,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
@@ -24,19 +25,24 @@
 public class TestGenerator {
 
   private final Path classNamePath;
+  private final Path outputClassNamePath;
 
   public static void main(String[] args) throws IOException {
-    assert args.length == 1;
-    TestGenerator testGenerator = new TestGenerator(Paths.get(args[0],
-        TestGenerator.class.getPackage().getName(), InvokeCustom.class.getSimpleName() + ".class"));
+    assert args.length == 2;
+    String fileName = InvokeCustom.class.getSimpleName() + ".class";
+    Path inputFile = Paths.get(args[0], TestGenerator.class.getPackage().getName(), fileName);
+    Path outputFile = Paths.get(args[1], fileName);
+    TestGenerator testGenerator = new TestGenerator(inputFile, outputFile);
     testGenerator.generateTests();
   }
 
-  public TestGenerator(Path classNamePath) {
+  public TestGenerator(Path classNamePath, Path outputClassNamePath) {
     this.classNamePath = classNamePath;
+    this.outputClassNamePath = outputClassNamePath;
   }
 
   private void generateTests() throws IOException {
+    Files.createDirectories(outputClassNamePath.getParent());
     try (InputStream inputStream = Files.newInputStream(classNamePath)) {
       ClassReader cr = new ClassReader(inputStream);
       ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -52,7 +58,8 @@
               super.visitEnd();
             }
           }, 0);
-      try (OutputStream output = Files.newOutputStream(classNamePath)) {
+      try (OutputStream output =
+          Files.newOutputStream(outputClassNamePath, StandardOpenOption.CREATE)) {
         output.write(cw.toByteArray());
       }
     }
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index dd3311b..d3a155f 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -33,6 +33,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -130,14 +131,22 @@
     }
 
     private List<String> collectClassFiles(Path testJarFile) {
-      List<String> result = new ArrayList<>();
+      Map<String, String> result = new HashMap<>();
       // Collect Java 8 classes.
-      visitFiles(getClassesRoot(testJarFile), path -> result.add(path.toString()));
+      visitFiles(
+          getClassesRoot(testJarFile),
+          path -> result.put(path.toFile().getName(), path.toString()));
+      // Collect generated classes, overwrite non-generated files.
+      visitFiles(
+          getGeneratedRoot(testJarFile),
+          path -> result.put(path.toFile().getName(), path.toString()));
       // Collect legacy classes.
       visitFiles(
-          getLegacyClassesRoot(testJarFile, packageName), path -> result.add(path.toString()));
-      Collections.sort(result);
-      return result;
+          getLegacyClassesRoot(testJarFile, packageName),
+          path -> result.put(path.toFile().getName(), path.toString()));
+      List<String> files = new ArrayList<>(result.values());
+      Collections.sort(files);
+      return files;
     }
 
     Path getClassesRoot(Path testJarFile) {
@@ -145,6 +154,12 @@
       return parent.resolve(Paths.get("classes", packageName));
     }
 
+    Path getGeneratedRoot(Path testJarFile) {
+      String sourceSet = testJarFile.getParent().toFile().getName();
+      Path parent = testJarFile.getParent().getParent().getParent();
+      return parent.resolve(Paths.get("generated", sourceSet, packageName));
+    }
+
     AndroidApp compileClassFilesInIntermediate(
         Path testJarFile, List<String> inputFiles, Path outputPath, OutputMode outputMode)
         throws Throwable {