Merge "Fixing super calls to default interface methods in desugaring."
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 48497c3..f525565 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -8,14 +8,18 @@
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.shaking.Enqueuer;
+import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.MainDexListBuilder;
+import com.android.tools.r8.shaking.ReasonPrinter;
 import com.android.tools.r8.shaking.RootSetBuilder;
 import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
+import com.android.tools.r8.shaking.TreePruner;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
 import java.io.IOException;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
@@ -37,9 +41,11 @@
     AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
     RootSet mainDexRootSet =
         new RootSetBuilder(application, appInfo, options.mainDexKeepRules, options).run(executor);
-    Set<DexType> mainDexBaseClasses =
-        new Enqueuer(appInfo, options).traceMainDex(mainDexRootSet, timing);
-    Set<DexType> mainDexClasses = new MainDexListBuilder(mainDexBaseClasses, application).run();
+    Enqueuer enqueuer = new Enqueuer(appInfo, options, true);
+    AppInfoWithLiveness mainDexAppInfo = enqueuer.traceMainDex(mainDexRootSet, timing);
+    // LiveTypes is the result.
+    Set<DexType> mainDexClasses =
+        new MainDexListBuilder(new HashSet<>(mainDexAppInfo.liveTypes), application).run();
 
     List<String> result = mainDexClasses.stream()
         .map(c -> c.toSourceString().replace('.', '/') + ".class")
@@ -50,6 +56,15 @@
       options.mainDexListConsumer.accept(String.join("\n", result), options.reporter);
     }
 
+    // Print -whyareyoukeeping results if any.
+    if (mainDexRootSet.reasonAsked.size() > 0) {
+      // Print reasons on the application after pruning, so that we reflect the actual result.
+      TreePruner pruner = new TreePruner(application, appInfo.withLiveness(), options);
+      application = pruner.run();
+      ReasonPrinter reasonPrinter = enqueuer.getReasonPrinter(mainDexRootSet.reasonAsked);
+      reasonPrinter.run(application);
+    }
+
     return result;
   }
 
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 21cab49..d062d13 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -37,6 +37,7 @@
 import com.android.tools.r8.shaking.AnnotationRemover;
 import com.android.tools.r8.shaking.DiscardedChecker;
 import com.android.tools.r8.shaking.Enqueuer;
+import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.MainDexListBuilder;
 import com.android.tools.r8.shaking.ProguardClassFilter;
 import com.android.tools.r8.shaking.ProguardConfiguration;
@@ -285,7 +286,8 @@
                 .run(executorService);
         ProtoLiteExtension protoLiteExtension =
             options.forceProguardCompatibility ? null : new ProtoLiteExtension(appInfo);
-        Enqueuer enqueuer = new Enqueuer(appInfo, options, compatibility, protoLiteExtension);
+        Enqueuer enqueuer = new Enqueuer(appInfo, options, options.forceProguardCompatibility,
+            compatibility, protoLiteExtension);
         appInfo = enqueuer.traceApplication(rootSet, timing);
         if (options.proguardConfiguration.isPrintSeeds()) {
           ByteArrayOutputStream bytes = new ByteArrayOutputStream();
@@ -391,12 +393,15 @@
 
       if (!options.mainDexKeepRules.isEmpty()) {
         appInfo = new AppInfoWithSubtyping(application);
-        Enqueuer enqueuer = new Enqueuer(appInfo, options);
+        Enqueuer enqueuer = new Enqueuer(appInfo, options, true);
         // Lets find classes which may have code executed before secondary dex files installation.
         RootSet mainDexRootSet =
             new RootSetBuilder(application, appInfo, options.mainDexKeepRules, options)
                 .run(executorService);
-        Set<DexType> mainDexBaseClasses = enqueuer.traceMainDex(mainDexRootSet, timing);
+        AppInfoWithLiveness mainDexAppInfo = enqueuer.traceMainDex(mainDexRootSet, timing);
+
+        // LiveTypes is the result.
+        Set<DexType> mainDexBaseClasses = new HashSet<>(mainDexAppInfo.liveTypes);
 
         // Calculate the automatic main dex list according to legacy multidex constraints.
         // Add those classes to an eventual manual list of classes.
@@ -410,7 +415,7 @@
       if (options.enableTreeShaking || options.enableMinification) {
         timing.begin("Post optimization code stripping");
         try {
-          Enqueuer enqueuer = new Enqueuer(appInfo, options);
+          Enqueuer enqueuer = new Enqueuer(appInfo, options, options.forceProguardCompatibility);
           appInfo = enqueuer.traceApplication(rootSet, timing);
           if (options.enableTreeShaking) {
             TreePruner pruner = new TreePruner(application, appInfo.withLiveness(), options);
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 6a78145..6f062cf 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "v1.2.3-dev";
+  public static final String LABEL = "v1.2.4-dev";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 30d0dbe..9d3c7a9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -482,6 +482,10 @@
     return createType(createString(descriptor));
   }
 
+  synchronized public DexType lookupType(DexString descriptor) {
+    return types.get(descriptor);
+  }
+
   public DexType createArrayType(int nesting, DexType baseType) {
     assert nesting > 0;
     return createType(Strings.repeat("[", nesting) + baseType.toDescriptorString());
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index b733faf..0b43509 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -85,6 +85,8 @@
  * field descriptions for details.
  */
 public class Enqueuer {
+
+  private final boolean forceProguardCompatibility;
   private boolean tracingMainDex = false;
 
   private final AppInfoWithSubtyping appInfo;
@@ -195,16 +197,19 @@
    */
   private final ProguardConfiguration.Builder compatibility;
 
-  public Enqueuer(AppInfoWithSubtyping appInfo, InternalOptions options) {
-    this(appInfo, options, null, null);
+  public Enqueuer(AppInfoWithSubtyping appInfo, InternalOptions options,
+      boolean forceProguardCompatibility) {
+    this(appInfo, options, forceProguardCompatibility, null, null);
   }
 
   public Enqueuer(AppInfoWithSubtyping appInfo, InternalOptions options,
+      boolean forceProguardCompatibility,
       ProguardConfiguration.Builder compatibility, ProtoLiteExtension protoLiteExtension) {
     this.appInfo = appInfo;
     this.compatibility = compatibility;
     this.options = options;
     this.protoLiteExtension = protoLiteExtension;
+    this.forceProguardCompatibility = forceProguardCompatibility;
   }
 
   private void enqueueRootItems(Map<DexItem, ProguardKeepRule> items) {
@@ -218,7 +223,7 @@
     if (item instanceof DexClass) {
       DexClass clazz = (DexClass) item;
       workList.add(Action.markInstantiated(clazz, reason));
-      if (options.forceProguardCompatibility && clazz.hasDefaultInitializer()) {
+      if (forceProguardCompatibility && clazz.hasDefaultInitializer()) {
         ProguardKeepRule rule = ProguardConfigurationUtils.buildDefaultInitializerKeepRule(clazz);
         proguardCompatibilityWorkList.add(Action.markMethodLive(
             clazz.getDefaultInitializer(), KeepReason.dueToProguardCompatibilityKeepRule(rule)));
@@ -275,7 +280,7 @@
     @Override
     public boolean registerInvokeVirtual(DexMethod method) {
       if (appInfo.dexItemFactory.classMethods.isReflectiveMemberLookup(method)) {
-        if (options.forceProguardCompatibility) {
+        if (forceProguardCompatibility) {
           // TODO(b/76181966): whether or not add this rule in normal mode.
           if (identifierNameStrings.add(method) && compatibility != null) {
             compatibility.addRule(buildIdentifierNameStringRule(method));
@@ -309,7 +314,7 @@
     public boolean registerInvokeStatic(DexMethod method) {
       if (method == appInfo.dexItemFactory.classMethods.forName
           || appInfo.dexItemFactory.atomicFieldUpdaterMethods.isFieldUpdater(method)) {
-        if (options.forceProguardCompatibility) {
+        if (forceProguardCompatibility) {
           // TODO(b/76181966): whether or not add this rule in normal mode.
           if (identifierNameStrings.add(method) && compatibility != null) {
             compatibility.addRule(buildIdentifierNameStringRule(method));
@@ -431,7 +436,7 @@
     }
 
     private boolean registerConstClassOrCheckCast(DexType type) {
-      if (options.forceProguardCompatibility) {
+      if (forceProguardCompatibility) {
         DexType baseType = type.toBaseType(appInfo.dexItemFactory);
         if (baseType.isClassType()) {
           DexClass baseClass = appInfo.definitionFor(baseType);
@@ -507,7 +512,7 @@
         annotations.forEach(this::handleAnnotationOfLiveType);
       }
 
-      if (options.forceProguardCompatibility) {
+      if (forceProguardCompatibility) {
         // Add all dependent members to the workqueue.
         enqueueRootItems(rootSet.getDependentItems(type));
       } else {
@@ -581,7 +586,7 @@
       Diagnostic message = new StringDiagnostic("Library class " + context.toSourceString()
           + (holder.isInterface() ? " implements " : " extends ")
           + "program class " + type.toSourceString());
-      if (options.forceProguardCompatibility) {
+      if (forceProguardCompatibility) {
         options.reporter.warning(message);
       } else {
         options.reporter.error(message);
@@ -613,7 +618,7 @@
       Log.verbose(getClass(), "Method `%s` is targeted.", encodedMethod.method);
     }
     targetedMethods.add(encodedMethod, reason);
-    if (options.forceProguardCompatibility) {
+    if (forceProguardCompatibility) {
       // Keep targeted default methods in compatibility mode. The tree pruner will otherwise make
       // these methods abstract, whereas Proguard does not (seem to) touch their code.
       DexClass clazz = appInfo.definitionFor(encodedMethod.method.holder);
@@ -1022,15 +1027,14 @@
         reachability, instantiatedTypes.getReasons());
   }
 
-  public Set<DexType> traceMainDex(RootSet rootSet, Timing timing) {
+  public AppInfoWithLiveness traceMainDex(RootSet rootSet, Timing timing) {
     this.tracingMainDex = true;
     this.rootSet = rootSet;
     // Translate the result of root-set computation into enqueuer actions.
     enqueueRootItems(rootSet.noShrinking);
     AppInfoWithLiveness appInfo = trace(timing);
     options.reporter.failIfPendingErrors();
-    // LiveTypes is the result, just make a copy because further work will modify its content.
-    return new HashSet<>(appInfo.liveTypes);
+    return appInfo;
   }
 
   public AppInfoWithLiveness traceApplication(RootSet rootSet, Timing timing) {
diff --git a/src/test/examples/multidex005/ReflectionReference.java b/src/test/examples/multidex005/ReflectionReference.java
new file mode 100644
index 0000000..791e7d2
--- /dev/null
+++ b/src/test/examples/multidex005/ReflectionReference.java
@@ -0,0 +1,18 @@
+// 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 multidex005;
+
+public class ReflectionReference {
+  Class directlyReferencedClass;
+
+  public ReflectionReference() throws ClassNotFoundException {
+    directlyReferencedClass = Class.forName("multidex005.ClassReference");
+  }
+
+  public Object noReference() throws ClassNotFoundException {
+    return Class.forName("multidex005.IndirectlyReferenced");
+  }
+
+}
diff --git a/src/test/examples/multidex005/main-dex-rules-7.txt b/src/test/examples/multidex005/main-dex-rules-7.txt
new file mode 100644
index 0000000..84120e0
--- /dev/null
+++ b/src/test/examples/multidex005/main-dex-rules-7.txt
@@ -0,0 +1,7 @@
+# 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.
+
+-keep public class *.ReflectionReference {
+  <init>();
+}
diff --git a/src/test/examples/multidex005/ref-list-7.txt b/src/test/examples/multidex005/ref-list-7.txt
new file mode 100644
index 0000000..5f01577
--- /dev/null
+++ b/src/test/examples/multidex005/ref-list-7.txt
@@ -0,0 +1,9 @@
+Lmultidex005/ClassReference;
+Lmultidex005/DirectlyReferenced;
+Lmultidex005/Interface1;
+Lmultidex005/Interface2;
+Lmultidex005/Interface3;
+Lmultidex005/ReflectionReference;
+Lmultidex005/SuperClass;
+Lmultidex005/SuperInterface;
+Lmultidex005/SuperSuperClass;
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
index 2e8645c..bb2628a 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -125,6 +125,11 @@
   }
 
   @Test
+  public void traceMainDexList005_7() throws Throwable {
+    doTest5(7);
+  }
+
+  @Test
   public void traceMainDexList006() throws Throwable {
     doTest(
         "traceMainDexList006",
@@ -137,7 +142,7 @@
 
   private void doTest5(int variant) throws Throwable {
     doTest(
-        "traceMainDexList003",
+        "traceMainDexList005",
         "multidex005",
         EXAMPLE_BUILD_DIR,
         Paths.get(EXAMPLE_SRC_DIR, "multidex005", "main-dex-rules-" + variant + ".txt"),
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index 1c3a9e0..5b1e7e3 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -76,7 +76,7 @@
 
     RootSet rootSet = new RootSetBuilder(program, appInfo, configuration.getRules(), options)
         .run(ThreadUtils.getExecutorService(options));
-    Enqueuer enqueuer = new Enqueuer(appInfo, options);
+    Enqueuer enqueuer = new Enqueuer(appInfo, options, options.forceProguardCompatibility);
     appInfo = enqueuer.traceApplication(rootSet, timing);
     return new Minifier(appInfo.withLiveness(), rootSet, options).run(timing);
   }
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
index 80bba31..c483267 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
@@ -106,7 +106,8 @@
     RootSet rootSet = new RootSetBuilder(application, appInfoWithSubtyping,
         buildKeepRuleForClass(Main.class, application.dexItemFactory), options).run(
         Executors.newSingleThreadExecutor());
-    appInfo = new Enqueuer(appInfoWithSubtyping, options).traceApplication(rootSet, timing);
+    appInfo = new Enqueuer(appInfoWithSubtyping, options, options.forceProguardCompatibility)
+        .traceApplication(rootSet, timing);
     // We do not run the tree pruner to ensure that the hierarchy is as designed and not modified
     // due to liveness.
   }