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.
}