Merge "Add bootstrapping test for testing compilation and sanity"
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index a662e1e..db0c983 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -643,6 +643,26 @@
     }
   }
 
+  public void optimizeMethodOnSynthesizedClass(DexProgramClass clazz, DexEncodedMethod method) {
+    if (!method.isProcessed()) {
+      try {
+        enterCachedClass(clazz);
+        // Process the generated method, but don't apply any outlining.
+        optimizeSynthesizedMethod(method);
+      } finally {
+        leaveCachedClass(clazz);
+      }
+    }
+  }
+
+  public void optimizeSynthesizedMethod(DexEncodedMethod method) {
+    if (!method.isProcessed()) {
+      // Process the generated method, but don't apply any outlining.
+      processMethod(method, ignoreOptimizationFeedback, x -> false, CallSiteInformation.empty(),
+          Outliner::noProcessing);
+    }
+  }
+
   private void enterCachedClass(DexProgramClass clazz) {
     DexProgramClass previous = cachedClasses.put(clazz.type, clazz);
     assert previous == null;
@@ -653,12 +673,6 @@
     assert existing == clazz;
   }
 
-  public void optimizeSynthesizedMethod(DexEncodedMethod method) {
-    // Process the generated method, but don't apply any outlining.
-    processMethod(method, ignoreOptimizationFeedback, x -> false, CallSiteInformation.empty(),
-        Outliner::noProcessing);
-  }
-
   private String logCode(InternalOptions options, DexEncodedMethod method) {
     return options.useSmaliSyntax ? method.toSmaliString(null) : method.codeToString();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 03a3818..01555da 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -128,6 +128,8 @@
   }
 
   private DexProgramClass synthesizeLambdaClass() {
+    DexMethod mainMethod = rewriter.factory
+        .createMethod(type, descriptor.erasedProto, descriptor.name);
     DexProgramClass clazz =
         new DexProgramClass(
             type,
@@ -146,8 +148,11 @@
             synthesizeStaticFields(),
             synthesizeInstanceFields(),
             synthesizeDirectMethods(),
-            synthesizeVirtualMethods(),
+            synthesizeVirtualMethods(mainMethod),
             rewriter.factory.getSkipNameValidationForTesting());
+    // Optimize main method.
+    rewriter.converter.optimizeMethodOnSynthesizedClass(
+        clazz, clazz.lookupVirtualMethod(mainMethod));
     // The method addSynthesizedFrom() may be called concurrently. To avoid a Concurrent-
     // ModificationException we must use synchronization.
     synchronized (synthesizedFrom) {
@@ -177,13 +182,11 @@
   }
 
   // Synthesize virtual methods.
-  private DexEncodedMethod[] synthesizeVirtualMethods() {
+  private DexEncodedMethod[] synthesizeVirtualMethods(DexMethod mainMethod) {
     DexEncodedMethod[] methods = new DexEncodedMethod[1 + descriptor.bridges.size()];
     int index = 0;
 
     // Synthesize main method.
-    DexMethod mainMethod = rewriter.factory
-        .createMethod(type, descriptor.erasedProto, descriptor.name);
     methods[index++] =
         new DexEncodedMethod(
             mainMethod,
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java
new file mode 100644
index 0000000..dc1c40b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java
@@ -0,0 +1,58 @@
+// Copyright (c) 2018, 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.ir.optimize.inliner;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import org.junit.Test;
+
+public class InlineSynthesizedLambdaClass extends TestBase {
+
+  @Test
+  public void test() throws Exception {
+    AndroidApp input = readClasses(Lambda.class, Lambda.Consumer.class);
+    AndroidApp output =
+        compileWithR8(
+            input,
+            String.join(
+                System.lineSeparator(),
+                keepMainProguardConfiguration(Lambda.class),
+                "-allowaccessmodification"),
+            options -> options.enableMinification = false);
+
+    // Check that everything has been inlined into main.
+    CodeInspector inspector = new CodeInspector(output);
+    assertEquals(1, inspector.allClasses().size());
+
+    ClassSubject classSubject = inspector.clazz(Lambda.class);
+    assertThat(classSubject, isPresent());
+    assertEquals(1, classSubject.allMethods().size());
+
+    // Check that the program gives the expected result.
+    assertEquals(runOnJava(Lambda.class), runOnArt(output, Lambda.class));
+  }
+}
+
+class Lambda {
+
+  interface Consumer<T> {
+    void accept(T value);
+  }
+
+  public static void main(String... args) {
+    load(s -> System.out.println(s));
+    load(s -> System.out.println(s));
+  }
+
+  public static void load(Consumer<String> c) {
+    c.accept("Hello!");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index 6331f5d..90013b0 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -17,6 +17,12 @@
 
   public abstract void forAllMethods(Consumer<FoundMethodSubject> inspection);
 
+  public final List<FoundMethodSubject> allMethods() {
+    ImmutableList.Builder<FoundMethodSubject> builder = ImmutableList.builder();
+    forAllMethods(builder::add);
+    return builder.build();
+  }
+
   public MethodSubject method(Method method) {
     List<String> parameters = new ArrayList<>();
     for (Class<?> parameterType : method.getParameterTypes()) {
diff --git a/tools/toolhelper.py b/tools/toolhelper.py
index dbf393b..1e6ebfd 100644
--- a/tools/toolhelper.py
+++ b/tools/toolhelper.py
@@ -3,6 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 import gradle
+import os
 import subprocess
 import utils
 
@@ -23,6 +24,9 @@
   if profile:
     cmd.append('-agentlib:hprof=cpu=samples,interval=1,depth=8')
   cmd.extend(['-jar', utils.R8_JAR, tool])
+  lib, args = extract_lib_from_args(args)
+  if lib:
+    cmd.extend(["--lib", lib])
   cmd.extend(args)
   utils.PrintCmd(cmd)
   return subprocess.call(cmd)
@@ -36,3 +40,15 @@
     else:
       args.append(arg)
   return build, args
+
+def extract_lib_from_args(input_args):
+  lib = None
+  args = []
+  for arg in input_args:
+    if arg == '--lib-android':
+      lib = utils.get_android_jar(26)
+    elif arg == '--lib-java':
+      lib = utils.RT_JAR
+    else:
+      args.append(arg)
+  return lib, args