Merge commit 'dad89985ee69f78f00d4559d230fac0ddf71d3c8' into dev-release
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index afa5f60..87925c3 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -143,6 +143,7 @@
name: "linux"
mixins: "linux"
mixins: "normal"
+ priority: 26
recipe {
properties: "tool:r8"
}
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index ab75708..f7f3305 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -99,6 +99,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -125,7 +126,7 @@
id: "linux"
acl_sets: "default"
triggering_policy: {
- max_concurrent_invocations: 3
+ max_concurrent_invocations: 6
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -138,7 +139,7 @@
id: "linux-android-4.0.4"
acl_sets: "default"
triggering_policy: {
- max_concurrent_invocations: 3
+ max_concurrent_invocations: 6
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -152,6 +153,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -164,7 +166,7 @@
id: "linux-android-4.4.4"
acl_sets: "default"
triggering_policy: {
- max_concurrent_invocations: 2
+ max_concurrent_invocations: 6
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -178,6 +180,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -190,7 +193,7 @@
id: "linux-android-5.1.1"
acl_sets: "default"
triggering_policy: {
- max_concurrent_invocations: 2
+ max_concurrent_invocations: 6
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -204,6 +207,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -216,7 +220,7 @@
id: "linux-android-6.0.1"
acl_sets: "default"
triggering_policy: {
- max_concurrent_invocations: 3
+ max_concurrent_invocations: 6
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -230,6 +234,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -242,7 +247,7 @@
id: "linux-android-7.0.0"
acl_sets: "default"
triggering_policy: {
- max_concurrent_invocations: 2
+ max_concurrent_invocations: 6
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -256,6 +261,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -268,7 +274,7 @@
id: "linux-android-8.1.0"
acl_sets: "default"
triggering_policy: {
- max_concurrent_invocations: 2
+ max_concurrent_invocations: 6
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -282,6 +288,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -295,7 +302,7 @@
id: "linux-android-9.0.0"
acl_sets: "default"
triggering_policy: {
- max_concurrent_invocations: 2
+ max_concurrent_invocations: 6
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -309,6 +316,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -321,7 +329,7 @@
id: "linux-android-10.0.0"
acl_sets: "default"
triggering_policy: {
- max_concurrent_invocations: 2
+ max_concurrent_invocations: 6
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -335,6 +343,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -366,6 +375,9 @@
job {
id: "linux-run-on-as-app"
acl_sets: "default"
+ triggering_policy: {
+ max_concurrent_invocations: 3
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -376,6 +388,9 @@
job {
id: "linux-run-on-as-app-recompilation"
acl_sets: "default"
+ triggering_policy: {
+ max_concurrent_invocations: 3
+ }
buildbucket {
server: "cr-buildbucket.appspot.com"
bucket: "luci.r8.ci"
@@ -388,6 +403,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
@@ -425,6 +441,7 @@
acl_sets: "default"
triggering_policy: {
max_batch_size: 1
+ max_concurrent_invocations: 3
}
buildbucket {
server: "cr-buildbucket.appspot.com"
diff --git a/src/library_desugar/desugar_jdk_libs.json b/src/library_desugar/desugar_jdk_libs.json
index 5bdc91e..049699a 100644
--- a/src/library_desugar/desugar_jdk_libs.json
+++ b/src/library_desugar/desugar_jdk_libs.json
@@ -2,7 +2,7 @@
"configuration_format_version": 3,
"group_id" : "com.tools.android",
"artifact_id" : "desugar_jdk_libs",
- "version": "1.0.9",
+ "version": "1.0.10",
"required_compilation_api_level": 26,
"synthesized_library_classes_package_prefix": "j$.",
"common_flags": [
@@ -84,7 +84,8 @@
},
"retarget_lib_member": {
"java.util.Date#toInstant": "java.util.DesugarDate",
- "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar"
+ "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar",
+ "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone"
},
"custom_conversion": {
"java.time.ZonedDateTime": "java.time.TimeConversions",
@@ -163,7 +164,9 @@
"java.util.Date#from": "java.util.DesugarDate",
"java.util.Date#toInstant": "java.util.DesugarDate",
"java.util.GregorianCalendar#from": "java.util.DesugarGregorianCalendar",
- "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar"
+ "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar",
+ "java.util.TimeZone#getTimeZone": "java.util.DesugarTimeZone",
+ "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone"
},
"custom_conversion": {
"java.time.ZonedDateTime": "java.time.TimeConversions",
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index c40d755..b456ecb 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -187,7 +187,7 @@
executor);
}
- AppView<?> appView = AppView.createForD8(appInfo, options, rewritePrefix);
+ AppView<?> appView = AppView.createForD8(appInfo, rewritePrefix);
IRConverter converter = new IRConverter(appView, timing, printer);
app = converter.convert(app, executor);
@@ -354,7 +354,7 @@
throws IOException, ExecutionException {
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
- IRConverter converter = new IRConverter(appInfo, options, timing, printer);
+ IRConverter converter = new IRConverter(appInfo, timing, printer);
application = converter.convert(application, executor);
if (options.printCfg) {
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index dcf33f1..bbee24d 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -312,7 +312,7 @@
// Write a header jar with the desugared APIs.
AppInfo appInfo = new AppInfo(app);
- AppView<?> appView = AppView.createForD8(appInfo, options);
+ AppView<?> appView = AppView.createForD8(appInfo);
CfApplicationWriter writer =
new CfApplicationWriter(
builder.build(),
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 42290d2..bacd375 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -50,7 +50,7 @@
DirectMappedDexApplication application =
new ApplicationReader(app, options, timing).read(executor).toDirect();
AppView<? extends AppInfoWithClassHierarchy> appView =
- AppView.createForR8(new AppInfoWithClassHierarchy(application), options);
+ AppView.createForR8(new AppInfoWithClassHierarchy(application));
appView.setAppServices(AppServices.builder(appView).build());
MainDexListBuilder.checkForAssumedLibraryTypes(appView.appInfo());
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index 4b35d17..f5059e4 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -128,7 +128,7 @@
DexApplication app = new L8TreePruner(options).prune(lazyApp, rewritePrefix);
AppInfo appInfo = new AppInfo(app);
- AppView<?> appView = AppView.createForL8(appInfo, options, rewritePrefix);
+ AppView<?> appView = AppView.createForL8(appInfo, rewritePrefix);
IRConverter converter = new IRConverter(appView, timing);
if (!options.testing.disableL8AnnotationRemoval) {
diff --git a/src/main/java/com/android/tools/r8/PrintSeeds.java b/src/main/java/com/android/tools/r8/PrintSeeds.java
index 7c2302a..3f8b70e 100644
--- a/src/main/java/com/android/tools/r8/PrintSeeds.java
+++ b/src/main/java/com/android/tools/r8/PrintSeeds.java
@@ -88,7 +88,7 @@
DirectMappedDexApplication application =
new ApplicationReader(command.getInputApp(), options, timing).read(executor).toDirect();
AppView<? extends AppInfoWithClassHierarchy> appView =
- AppView.createForR8(new AppInfoWithClassHierarchy(application), options);
+ AppView.createForR8(new AppInfoWithClassHierarchy(application));
appView.setAppServices(AppServices.builder(appView).build());
SubtypingInfo subtypingInfo = new SubtypingInfo(application.allClasses(), application);
RootSet rootSet =
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 5998450..07948a1 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -100,6 +100,7 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.io.ByteStreams;
@@ -110,7 +111,6 @@
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -209,6 +209,10 @@
try {
Marker marker = options.getMarker(Tool.R8);
assert marker != null;
+ // Get the markers from the input which are different from the one created for this
+ // compilation
+ Set<Marker> markers = new HashSet<>(options.itemFactory.extractMarkers());
+ markers.remove(marker);
if (options.isGeneratingClassFiles()) {
new CfApplicationWriter(
application, appView, options, marker, graphLense, namingLens, proguardMapSupplier)
@@ -218,7 +222,8 @@
application,
appView,
options,
- Collections.singletonList(marker),
+ // Ensure that the marker for this compilation is the first in the list.
+ ImmutableList.<Marker>builder().add(marker).addAll(markers).build(),
graphLense,
initClassLens,
namingLens,
@@ -274,7 +279,7 @@
inputApp.closeInternalArchiveProviders();
AppView<AppInfoWithClassHierarchy> appView =
- AppView.createForR8(new AppInfoWithClassHierarchy(application), options);
+ AppView.createForR8(new AppInfoWithClassHierarchy(application));
appView.setAppServices(AppServices.builder(appView).build());
// Check for potentially having pass-through of Cf-code for kotlin libraries.
@@ -606,7 +611,7 @@
// Overwrite SourceFile if specified. This step should be done after IR conversion.
timing.begin("Rename SourceFile");
- new SourceFileRewriter(appView).run();
+ new SourceFileRewriter(appViewWithLiveness).run();
timing.end();
// Collect the already pruned types before creating a new app info without liveness.
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 5d102bdf..8986801 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -235,8 +235,8 @@
proguardMapId = proguardMapSupplier.writeProguardMap();
}
- // If we do have a map then we're called from R8. In that case we have exactly one marker.
- assert proguardMapId == null || (markers != null && markers.size() == 1);
+ // If we do have a map then we're called from R8. In that case we have at least one marker.
+ assert proguardMapId == null || (markers != null && markers.size() >= 1);
if (markers != null && !markers.isEmpty()) {
if (proguardMapId != null) {
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 9763f50..245a9ab 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
import com.android.tools.r8.ir.optimize.library.LibraryMemberOptimizer;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.shaking.LibraryModeledPredicate;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
import com.android.tools.r8.utils.InternalOptions;
@@ -43,12 +44,13 @@
private T appInfo;
private AppInfoWithClassHierarchy appInfoForDesugaring;
private AppServices appServices;
- private final DexItemFactory dexItemFactory;
private final WholeProgramOptimizations wholeProgramOptimizations;
private GraphLense graphLense;
private InitClassLens initClassLens;
- private final InternalOptions options;
private RootSet rootSet;
+ // This should perferably always be obtained via AppInfoWithLiveness.
+ // Currently however the liveness may be downgraded thus loosing the computed keep info.
+ private KeepInfoCollection keepInfo = null;
private final AbstractValueFactory abstractValueFactory = new AbstractValueFactory();
private final InstanceFieldInitializationInfoFactory instanceFieldInitializationInfoFactory =
new InstanceFieldInitializationInfoFactory();
@@ -74,32 +76,19 @@
private Map<DexClass, DexValueString> sourceDebugExtensions = new IdentityHashMap<>();
private AppView(
- T appInfo, WholeProgramOptimizations wholeProgramOptimizations, InternalOptions options) {
- this(
- appInfo,
- wholeProgramOptimizations,
- options,
- appInfo == null
- ? PrefixRewritingMapper.empty()
- : options.desugaredLibraryConfiguration.createPrefixRewritingMapper(options));
- }
-
- private AppView(
T appInfo,
WholeProgramOptimizations wholeProgramOptimizations,
- InternalOptions options,
PrefixRewritingMapper mapper) {
+ assert appInfo != null;
this.appInfo = appInfo;
- this.dexItemFactory = appInfo != null ? appInfo.dexItemFactory() : null;
this.wholeProgramOptimizations = wholeProgramOptimizations;
this.graphLense = GraphLense.getIdentityLense();
this.initClassLens = InitClassLens.getDefault();
this.methodProcessingIdFactory =
- new MethodProcessingId.Factory(options.testing.methodProcessingIdConsumer);
- this.options = options;
+ new MethodProcessingId.Factory(options().testing.methodProcessingIdConsumer);
this.rewritePrefix = mapper;
- if (enableWholeProgramOptimizations() && options.callSiteOptimizationOptions().isEnabled()) {
+ if (enableWholeProgramOptimizations() && options().callSiteOptimizationOptions().isEnabled()) {
this.callSiteOptimizationInfoPropagator =
new CallSiteOptimizationInfoPropagator(withLiveness());
} else {
@@ -108,7 +97,7 @@
this.libraryMemberOptimizer = new LibraryMemberOptimizer(this);
- if (enableWholeProgramOptimizations() && options.protoShrinking().isProtoShrinkingEnabled()) {
+ if (enableWholeProgramOptimizations() && options().protoShrinking().isProtoShrinkingEnabled()) {
this.protoShrinker = new ProtoShrinker(withLiveness());
} else {
this.protoShrinker = null;
@@ -120,27 +109,34 @@
return libraryMemberOptimizer.isModeled(type);
}
- public static <T extends AppInfo> AppView<T> createForD8(T appInfo, InternalOptions options) {
- return new AppView<>(appInfo, WholeProgramOptimizations.OFF, options);
+ private static <T extends AppInfo> PrefixRewritingMapper defaultPrefixRewritingMapper(T appInfo) {
+ InternalOptions options = appInfo.options();
+ return options.desugaredLibraryConfiguration.createPrefixRewritingMapper(options);
+ }
+
+ public static <T extends AppInfo> AppView<T> createForD8(T appInfo) {
+ return new AppView<>(
+ appInfo, WholeProgramOptimizations.OFF, defaultPrefixRewritingMapper(appInfo));
}
public static <T extends AppInfo> AppView<T> createForD8(
- T appInfo, InternalOptions options, PrefixRewritingMapper mapper) {
- return new AppView<>(appInfo, WholeProgramOptimizations.OFF, options, mapper);
+ T appInfo, PrefixRewritingMapper mapper) {
+ return new AppView<>(appInfo, WholeProgramOptimizations.OFF, mapper);
}
- public static <T extends AppInfo> AppView<T> createForR8(T appInfo, InternalOptions options) {
- return new AppView<>(appInfo, WholeProgramOptimizations.ON, options);
+ public static <T extends AppInfo> AppView<T> createForR8(T appInfo) {
+ return new AppView<>(
+ appInfo, WholeProgramOptimizations.ON, defaultPrefixRewritingMapper(appInfo));
}
public static <T extends AppInfo> AppView<T> createForL8(
- T appInfo, InternalOptions options, PrefixRewritingMapper mapper) {
- return new AppView<>(appInfo, WholeProgramOptimizations.OFF, options, mapper);
+ T appInfo, PrefixRewritingMapper mapper) {
+ return new AppView<>(appInfo, WholeProgramOptimizations.OFF, mapper);
}
- public static <T extends AppInfo> AppView<T> createForRelocator(
- T appInfo, InternalOptions options) {
- return new AppView<>(appInfo, WholeProgramOptimizations.OFF, options);
+ public static <T extends AppInfo> AppView<T> createForRelocator(T appInfo) {
+ return new AppView<>(
+ appInfo, WholeProgramOptimizations.OFF, defaultPrefixRewritingMapper(appInfo));
}
public AbstractValueFactory abstractValueFactory() {
@@ -184,6 +180,9 @@
if (appInfo != previous) {
previous.markObsolete();
}
+ if (appInfo.hasLiveness()) {
+ keepInfo = appInfo.withLiveness().getKeepInfo();
+ }
@SuppressWarnings("unchecked")
AppView<U> appViewWithSpecializedAppInfo = (AppView<U>) this;
return appViewWithSpecializedAppInfo;
@@ -252,7 +251,7 @@
@Override
public DexItemFactory dexItemFactory() {
- return dexItemFactory;
+ return appInfo.dexItemFactory();
}
public boolean enableWholeProgramOptimizations() {
@@ -344,7 +343,7 @@
}
public boolean canUseInitClass() {
- return options.isShrinking() && !initClassLens.isFinal();
+ return options().isShrinking() && !initClassLens.isFinal();
}
public InitClassLens initClassLens() {
@@ -373,7 +372,7 @@
}
public InternalOptions options() {
- return options;
+ return appInfo.options();
}
public RootSet rootSet() {
@@ -385,6 +384,10 @@
this.rootSet = rootSet;
}
+ public KeepInfoCollection getKeepInfo() {
+ return keepInfo;
+ }
+
public MergedClassesCollection allMergedClasses() {
MergedClassesCollection collection = new MergedClassesCollection();
if (horizontallyMergedLambdaClasses != null) {
@@ -455,14 +458,14 @@
}
public boolean isCfByteCodePassThrough(DexEncodedMethod method) {
- if (!options.isGeneratingClassFiles()) {
+ if (!options().isGeneratingClassFiles()) {
return false;
}
if (cfByteCodePassThrough.contains(method.method)) {
return true;
}
- return options.testing.cfByteCodePassThrough != null
- && options.testing.cfByteCodePassThrough.test(method.method);
+ return options().testing.cfByteCodePassThrough != null
+ && options().testing.cfByteCodePassThrough.test(method.method);
}
public boolean hasCfByteCodePassThroughMethods() {
diff --git a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
index 1315f4a..3cd5fc5 100644
--- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -140,7 +140,7 @@
private void writeIR(ProgramMethod method, PrintStream ps) {
CfgPrinter printer = new CfgPrinter();
- IRConverter converter = new IRConverter(appInfo, options, timing, printer);
+ IRConverter converter = new IRConverter(appInfo, timing, printer);
OneTimeMethodProcessor methodProcessor =
OneTimeMethodProcessor.create(method, methodProcessingIdFactory);
methodProcessor.forEachWave(
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 5f6f83b..0809d00 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
@@ -372,8 +372,8 @@
this(appView, timing, printer, MainDexClasses.NONE);
}
- public IRConverter(AppInfo appInfo, InternalOptions options, Timing timing, CfgPrinter printer) {
- this(AppView.createForD8(appInfo, options), timing, printer, MainDexClasses.NONE);
+ public IRConverter(AppInfo appInfo, Timing timing, CfgPrinter printer) {
+ this(AppView.createForD8(appInfo), timing, printer, MainDexClasses.NONE);
}
private boolean enableTwrCloseResourceDesugaring() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index c0cdc54..fbf5a15 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -107,7 +107,7 @@
new ApplicationReader(androidApp, options, Timing.empty()).read(executor);
appInfo = new AppInfo(app);
}
- AppView<?> appView = AppView.createForD8(appInfo, options, rewritePrefix);
+ AppView<?> appView = AppView.createForD8(appInfo, rewritePrefix);
BackportedMethodRewriter.RewritableMethods rewritableMethods =
new BackportedMethodRewriter.RewritableMethods(options, appView);
rewritableMethods.visit(methods::add);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
index a1af388..d687d19 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.SemanticVersion;
import com.android.tools.r8.utils.StringDiagnostic;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -22,14 +23,7 @@
public class DesugaredLibraryConfigurationParser {
public static final int MAX_SUPPORTED_VERSION = 4;
-
- private static final String MIN_DESUGARED_LIBRARY_WITH_COMMON_FLAGS = "1.0.9";
-
- private static final String UNSUPPORTED_MESSAGE =
- "Unsupported desugared library version, please upgrade the"
- + " desugared library to at least version "
- + MIN_DESUGARED_LIBRARY_WITH_COMMON_FLAGS
- + ".";
+ public static final SemanticVersion MIN_SUPPORTED_VERSION = new SemanticVersion(1, 0, 9);
static final String CONFIGURATION_FORMAT_VERSION_KEY = "configuration_format_version";
static final String VERSION_KEY = "version";
@@ -73,15 +67,11 @@
}
private JsonElement required(JsonObject json, String key) {
- return required(
- json,
- key,
- "Invalid desugared library configuration. " + "Expected required key '" + key + "'");
- }
-
- private JsonElement required(JsonObject json, String key, String message) {
if (!json.has(key)) {
- throw reporter.fatalError(new StringDiagnostic(message, origin));
+ throw reporter.fatalError(
+ new StringDiagnostic(
+ "Invalid desugared library configuration. Expected required key '" + key + "'",
+ origin));
}
return json.get(key);
}
@@ -115,6 +105,18 @@
}
String version = required(jsonConfig, VERSION_KEY).getAsString();
+ SemanticVersion semanticVersion = SemanticVersion.parse(version);
+ if (!semanticVersion.isNewerOrEqual(MIN_SUPPORTED_VERSION)) {
+ throw reporter.fatalError(
+ new StringDiagnostic(
+ "Unsupported desugared library version: "
+ + version
+ + ", please upgrade the desugared library to at least version "
+ + MIN_SUPPORTED_VERSION
+ + ".",
+ origin));
+ }
+
String groupID = required(jsonConfig, GROUP_ID_KEY).getAsString();
String artifactID = required(jsonConfig, ARTIFACT_ID_KEY).getAsString();
String identifier = String.join(":", groupID, artifactID, version);
@@ -126,7 +128,7 @@
required(jsonConfig, REQUIRED_COMPILATION_API_LEVEL_KEY).getAsInt();
configurationBuilder.setRequiredCompilationAPILevel(
AndroidApiLevel.getAndroidApiLevel(required_compilation_api_level));
- JsonElement commonFlags = required(jsonConfig, COMMON_FLAGS_KEY, UNSUPPORTED_MESSAGE);
+ JsonElement commonFlags = required(jsonConfig, COMMON_FLAGS_KEY);
JsonElement libraryFlags = required(jsonConfig, LIBRARY_FLAGS_KEY);
JsonElement programFlags = required(jsonConfig, PROGRAM_FLAGS_KEY);
parseFlagsList(commonFlags.getAsJsonArray());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
index 7272948..b1d8880 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
@@ -322,7 +322,8 @@
return null;
}
- if (appView.options().isMinifying() && appView.rootSet().mayBeMinified(holder, appView)) {
+ if (appView.enableWholeProgramOptimizations()
+ && appView.withLiveness().appInfo().isMinificationAllowed(holder)) {
if (invokedMethod == dexItemFactory.classMethods.getName) {
return new DexItemBasedValueString(holder, ClassNameComputationInfo.getInstance(NAME));
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
index d00100a..af2dee2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -354,7 +354,8 @@
continue;
}
boolean mayBeRenamed =
- appView.options().isMinifying() && appView.rootSet().mayBeMinified(holder.type, appView);
+ appView.enableWholeProgramOptimizations()
+ && appView.withLiveness().appInfo().isMinificationAllowed(holder.type);
// b/120138731: Filter out escaping uses. In such case, the result of this optimization will
// be stored somewhere, which can lead to a regression if the corresponding class is in a deep
// package hierarchy. For local cases, it is likely a one-time computation, but make sure the
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 2ee7485..3d27387 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -130,10 +130,10 @@
static class MinificationClassNamingStrategy extends BaseMinificationNamingStrategy
implements ClassNamingStrategy {
- final AppView<?> appView;
+ final AppView<AppInfoWithLiveness> appView;
final DexItemFactory factory;
- MinificationClassNamingStrategy(AppView<?> appView) {
+ MinificationClassNamingStrategy(AppView<AppInfoWithLiveness> appView) {
super(
appView.options().getProguardConfiguration().getClassObfuscationDictionary(),
appView.options().getProguardConfiguration().hasDontUseMixedCaseClassnames());
@@ -169,7 +169,7 @@
@Override
public DexString reservedDescriptor(DexType type) {
- if (appView.rootSet().mayNotBeMinified(type, appView)) {
+ if (!appView.appInfo().isMinificationAllowed(type)) {
return type.descriptor;
}
return null;
@@ -207,11 +207,11 @@
static class MinifierMemberNamingStrategy extends BaseMinificationNamingStrategy
implements MemberNamingStrategy {
- final AppView<?> appView;
+ final AppView<AppInfoWithLiveness> appView;
private final DexItemFactory factory;
private final boolean desugaredLibraryRenaming;
- public MinifierMemberNamingStrategy(AppView<?> appView) {
+ public MinifierMemberNamingStrategy(AppView<AppInfoWithLiveness> appView) {
super(appView.options().getProguardConfiguration().getObfuscationDictionary(), false);
this.appView = appView;
this.factory = appView.dexItemFactory();
@@ -254,7 +254,7 @@
if (!allowMemberRenaming(holder)
|| holder.accessFlags.isAnnotation()
|| method.accessFlags.isConstructor()
- || appView.rootSet().mayNotBeMinified(method.method, appView)) {
+ || !appView.appInfo().isMinificationAllowed(method.method)) {
return method.method.name;
}
if (desugaredLibraryRenaming
@@ -268,7 +268,7 @@
@Override
public DexString getReservedName(DexEncodedField field, DexClass holder) {
- if (holder.isLibraryClass() || appView.rootSet().mayNotBeMinified(field.field, appView)) {
+ if (holder.isLibraryClass() || !appView.appInfo().isMinificationAllowed(field.field)) {
return field.field.name;
}
return null;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index 57f63fa..ad27200 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -203,7 +203,7 @@
if (clazz == null || !appView.options().isMinifying()) {
notMappedReferences.add(type);
} else if (appView.options().isMinifying()
- && appView.rootSet().mayNotBeMinified(type, appView)) {
+ && !appView.appInfo().isMinificationAllowed(type)) {
notMappedReferences.add(type);
}
}
@@ -392,7 +392,9 @@
private final Set<String> mappedNames;
ApplyMappingClassNamingStrategy(
- AppView<?> appView, Map<DexType, DexString> mappings, Set<String> mappedNames) {
+ AppView<AppInfoWithLiveness> appView,
+ Map<DexType, DexString> mappings,
+ Set<String> mappedNames) {
super(appView);
this.mappings = mappings;
this.mappedNames = mappedNames;
@@ -402,7 +404,7 @@
public DexString next(
DexType type, char[] packagePrefix, InternalNamingState state, Predicate<String> isUsed) {
assert !mappings.containsKey(type);
- assert appView.rootSet().mayBeMinified(type, appView);
+ assert appView.appInfo().isMinificationAllowed(type);
return super.next(
type,
packagePrefix,
@@ -427,15 +429,12 @@
if (clazz.isNotProgramClass() && mappings.containsKey(type)) {
return mappings.get(type);
}
- if (clazz.isProgramClass() && appView.rootSet().mayBeMinified(type, appView)) {
- if (mappings.containsKey(type)) {
+ if (clazz.isProgramClass()) {
+ if (appView.appInfo().isMinificationAllowed(type)) {
return mappings.get(type);
}
- return null;
- } else if (clazz.isProgramClass()
- && !appView.rootSet().mayBeMinified(type, appView)
- && mappings.containsKey(type)) {
- // TODO(b/136694827): Report a warning here since the user may find this not intuitive.
+ // TODO(b/136694827): Report a warning here if in the mapping since the user may find this
+ // non intuitive.
}
return type.descriptor;
}
@@ -453,7 +452,7 @@
private final Reporter reporter;
public ApplyMappingMemberNamingStrategy(
- AppView<?> appView, Map<DexReference, MemberNaming> mappedNames) {
+ AppView<AppInfoWithLiveness> appView, Map<DexReference, MemberNaming> mappedNames) {
super(appView);
this.mappedNames = mappedNames;
this.factory = appView.dexItemFactory();
@@ -477,7 +476,7 @@
nextName = reservedName;
} else {
assert !mappedNames.containsKey(reference);
- assert appView.rootSet().mayBeMinified(reference, appView);
+ assert appView.appInfo().isMinificationAllowed(reference);
nextName = super.next(method, internalState, isAvailable);
}
assert nextName == reference.name || !method.isInitializer();
@@ -500,7 +499,7 @@
return reservedName;
}
assert !mappedNames.containsKey(reference);
- assert appView.rootSet().mayBeMinified(reference, appView);
+ assert appView.appInfo().isMinificationAllowed(reference);
return super.next(field, internalState, isAvailable);
}
diff --git a/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java b/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java
index a5ead29..1e57331 100644
--- a/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/SourceFileRewriter.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.DexDebugEvent.SetFile;
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.ProguardConfiguration;
import java.util.Arrays;
@@ -20,9 +21,9 @@
*/
public class SourceFileRewriter {
- private final AppView<?> appView;
+ private final AppView<AppInfoWithLiveness> appView;
- public SourceFileRewriter(AppView<?> appView) {
+ public SourceFileRewriter(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
}
@@ -45,7 +46,7 @@
// of ART.
if (!hasRenameSourceFileAttribute
&& proguardConfiguration.getKeepAttributes().sourceFile
- && appView.rootSet().mayNotBeMinified(clazz.type, appView)) {
+ && !appView.appInfo().isMinificationAllowed(clazz.type)) {
continue;
}
clazz.sourceFile = defaultRenaming;
diff --git a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
index 44efffc..db4613f 100644
--- a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
@@ -165,7 +165,7 @@
boolean wasSeen = methodPoolCollection.markIfNotSeen(holder, method.method);
if (wasSeen) {
// We can't do anything further because even renaming is not allowed due to the keep rule.
- if (appView.rootSet().mayNotBeMinified(method.method, appView)) {
+ if (!appView.appInfo().isMinificationAllowed(method.method)) {
return false;
}
// TODO(b/111118390): Renaming will enable more private instance methods to be publicized.
diff --git a/src/main/java/com/android/tools/r8/relocator/Relocator.java b/src/main/java/com/android/tools/r8/relocator/Relocator.java
index 1e8420e..176e058 100644
--- a/src/main/java/com/android/tools/r8/relocator/Relocator.java
+++ b/src/main/java/com/android/tools/r8/relocator/Relocator.java
@@ -81,7 +81,7 @@
DexApplication app = new ApplicationReader(inputApp, options, timing).read(executor);
AppInfo appInfo = new AppInfo(app);
- AppView<?> appView = AppView.createForRelocator(appInfo, options);
+ AppView<?> appView = AppView.createForRelocator(appInfo);
appView.setAppServices(AppServices.builder(appView).build());
SimplePackagesRewritingMapper packageRemapper = new SimplePackagesRewritingMapper(appView);
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index af2b520..3d59b8b 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -17,7 +17,11 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.Timing;
+import com.google.common.base.Charsets;
import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -117,7 +121,7 @@
private static List<String> getStackTraceFromFile(
String stackTracePath, DiagnosticsHandler diagnostics) {
try {
- return Files.readAllLines(Paths.get(stackTracePath));
+ return Files.readAllLines(Paths.get(stackTracePath), Charsets.UTF_8);
} catch (IOException e) {
diagnostics.error(new StringDiagnostic("Could not find stack trace file: " + stackTracePath));
throw new RetraceAbortException();
@@ -196,7 +200,15 @@
return;
}
builder.setRetracedStackTraceConsumer(
- retraced -> System.out.print(StringUtils.lines(retraced)));
+ retraced -> {
+ try (PrintStream printStream = new PrintStream(System.out, true, Charsets.UTF_8.name())) {
+ for (String line : retraced) {
+ printStream.println(line);
+ }
+ } catch (UnsupportedEncodingException e) {
+ retraceDiagnosticsHandler.error(new StringDiagnostic(e.getMessage()));
+ }
+ });
run(builder.build());
}
@@ -210,7 +222,7 @@
}
private static List<String> getStackTraceFromStandardInput() {
- Scanner sc = new Scanner(System.in);
+ Scanner sc = new Scanner(new InputStreamReader(System.in, Charsets.UTF_8));
List<String> readLines = new ArrayList<>();
while (sc.hasNext()) {
readLines.add(sc.nextLine());
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java b/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
index 4973190..f1603f7 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.retrace;
import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
@@ -33,6 +34,9 @@
private static final int NO_MATCH = -1;
+ private final RegularExpressionGroup[] syntheticGroups =
+ new RegularExpressionGroup[] {new SourceFileLineNumberGroup()};
+
private final RegularExpressionGroup[] groups =
new RegularExpressionGroup[] {
new TypeNameGroup(),
@@ -130,19 +134,17 @@
String regularExpression, List<RegularExpressionGroupHandler> handlers) {
int currentIndex = 0;
int captureGroupIndex = 0;
+ regularExpression = registerSyntheticGroups(regularExpression);
while (currentIndex < regularExpression.length()) {
RegularExpressionGroup firstGroup = null;
int firstIndexFromCurrent = regularExpression.length();
for (RegularExpressionGroup group : groups) {
- int nextIndexOf = regularExpression.indexOf(group.shortName(), currentIndex);
- if (nextIndexOf > NO_MATCH && nextIndexOf < firstIndexFromCurrent) {
- // Check if previous character in the regular expression is not \\ to ensure not
- // overriding a matching on shortName.
- if (nextIndexOf > 0 && regularExpression.charAt(nextIndexOf - 1) == '\\') {
- continue;
- }
+ int firstIndex =
+ firstIndexOfGroup(
+ currentIndex, firstIndexFromCurrent, regularExpression, group.shortName());
+ if (firstIndex > NO_MATCH) {
firstGroup = group;
- firstIndexFromCurrent = nextIndexOf;
+ firstIndexFromCurrent = firstIndex;
}
}
if (firstGroup != null) {
@@ -161,6 +163,49 @@
return regularExpression;
}
+ private int firstIndexOfGroup(int startIndex, int endIndex, String expression, String shortName) {
+ int nextIndexOf = startIndex;
+ while (nextIndexOf != NO_MATCH) {
+ nextIndexOf = expression.indexOf(shortName, nextIndexOf);
+ if (nextIndexOf > NO_MATCH) {
+ if (nextIndexOf < endIndex && !isEscaped(expression, nextIndexOf)) {
+ return nextIndexOf;
+ }
+ nextIndexOf++;
+ }
+ }
+ return NO_MATCH;
+ }
+
+ private boolean isEscaped(String expression, int index) {
+ boolean escaped = false;
+ while (index > 0 && expression.charAt(--index) == '\\') {
+ escaped = !escaped;
+ }
+ return escaped;
+ }
+
+ private String registerSyntheticGroups(String regularExpression) {
+ boolean modifiedExpression;
+ do {
+ modifiedExpression = false;
+ for (RegularExpressionGroup syntheticGroup : syntheticGroups) {
+ int firstIndex =
+ firstIndexOfGroup(
+ 0, regularExpression.length(), regularExpression, syntheticGroup.shortName());
+ if (firstIndex > NO_MATCH) {
+ regularExpression =
+ regularExpression.substring(0, firstIndex)
+ + syntheticGroup.subExpression()
+ + regularExpression.substring(firstIndex + syntheticGroup.shortName().length());
+ // Loop as long as we can replace.
+ modifiedExpression = true;
+ }
+ }
+ } while (modifiedExpression);
+ return regularExpression;
+ }
+
static class RetraceString {
private final Element classContext;
@@ -387,6 +432,10 @@
abstract String subExpression();
abstract RegularExpressionGroupHandler createHandler(String captureGroup);
+
+ boolean isSynthetic() {
+ return false;
+ }
}
// TODO(b/145731185): Extend support for identifiers with strings inside back ticks.
@@ -718,6 +767,29 @@
}
}
+ private static class SourceFileLineNumberGroup extends RegularExpressionGroup {
+
+ @Override
+ String shortName() {
+ return "%S";
+ }
+
+ @Override
+ String subExpression() {
+ return "%s(?::%l)?";
+ }
+
+ @Override
+ RegularExpressionGroupHandler createHandler(String captureGroup) {
+ throw new Unreachable("Should never be called");
+ }
+
+ @Override
+ boolean isSynthetic() {
+ return true;
+ }
+ }
+
private static final String JAVA_TYPE_REGULAR_EXPRESSION =
"(" + javaIdentifierSegment + "\\.)*" + javaIdentifierSegment + "[\\[\\]]*";
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index f617c31..d3afad2 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -917,11 +917,14 @@
return this;
}
+ public boolean isMinificationAllowed(DexReference reference) {
+ return options().isMinificationEnabled()
+ && keepInfo.getInfo(reference, this).isMinificationAllowed(options());
+ }
+
public boolean isAccessModificationAllowed(DexReference reference) {
assert options().getProguardConfiguration().isAccessModificationAllowed();
- return keepInfo
- .getInfo(reference, this)
- .isAccessModificationAllowed(options().getProguardConfiguration());
+ return keepInfo.getInfo(reference, this).isAccessModificationAllowed(options());
}
public boolean isPinned(DexReference reference) {
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 e432e69..e033e78 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -92,6 +92,7 @@
import com.android.tools.r8.shaking.DelayedRootSetActionItem.InterfaceMethodSyntheticBridgeAction;
import com.android.tools.r8.shaking.EnqueuerWorklist.EnqueuerAction;
import com.android.tools.r8.shaking.GraphReporter.KeepReasonWitness;
+import com.android.tools.r8.shaking.KeepInfo.Joiner;
import com.android.tools.r8.shaking.KeepInfoCollection.MutableKeepInfoCollection;
import com.android.tools.r8.shaking.RootSetBuilder.ConsequentRootSet;
import com.android.tools.r8.shaking.RootSetBuilder.ItemsWithRules;
@@ -630,8 +631,13 @@
private void enqueueRootClass(
DexProgramClass clazz, Set<ProguardKeepRuleBase> rules, DexDefinition precondition) {
- KeepReasonWitness witness = graphReporter.reportKeepClass(precondition, rules, clazz);
keepClassWithRules(clazz, rules);
+ enqueueKeepRuleInstantiatedType(clazz, rules, precondition);
+ }
+
+ private void enqueueKeepRuleInstantiatedType(
+ DexProgramClass clazz, Set<ProguardKeepRuleBase> rules, DexDefinition precondition) {
+ KeepReasonWitness witness = graphReporter.reportKeepClass(precondition, rules, clazz);
if (clazz.isAnnotation()) {
workList.enqueueMarkAnnotationInstantiatedAction(clazz, witness);
} else if (clazz.isInterface()) {
@@ -743,11 +749,12 @@
}
private void compatEnqueueHolderIfDependentNonStaticMember(
- DexClass holder, Set<ProguardKeepRuleBase> compatRules) {
+ DexProgramClass holder, Set<ProguardKeepRuleBase> compatRules) {
if (!forceProguardCompatibility || compatRules == null) {
return;
}
- enqueueRootItem(holder, compatRules);
+ // TODO(b/120959039): This needs the set of instance member as preconditon.
+ enqueueKeepRuleInstantiatedType(holder, compatRules, null);
}
//
@@ -1583,7 +1590,7 @@
rootSet.forEachDependentInstanceConstructor(
holder, appView, this::enqueueHolderWithDependentInstanceConstructor);
- rootSet.forEachDependentStaticMember(holder, appView, this::enqueueDependentItem);
+ rootSet.forEachDependentStaticMember(holder, appView, this::enqueueDependentMember);
compatEnqueueHolderIfDependentNonStaticMember(
holder, rootSet.getDependentKeepClassCompatRule(holder.getType()));
@@ -1648,14 +1655,17 @@
}
}
- private void enqueueDependentItem(
- DexDefinition precondition, DexDefinition consequent, Set<ProguardKeepRuleBase> reasons) {
+ private void enqueueDependentMember(
+ DexDefinition precondition,
+ DexEncodedMember<?, ?> consequent,
+ Set<ProguardKeepRuleBase> reasons) {
internalEnqueueRootItem(consequent, reasons, precondition);
}
private void enqueueHolderWithDependentInstanceConstructor(
ProgramMethod instanceInitializer, Set<ProguardKeepRuleBase> reasons) {
- enqueueRootItem(instanceInitializer.getHolder(), reasons);
+ DexProgramClass holder = instanceInitializer.getHolder();
+ enqueueKeepRuleInstantiatedType(holder, reasons, instanceInitializer.getDefinition());
}
private void processAnnotations(DexProgramClass holder, DexDefinition annotatedItem) {
@@ -1828,36 +1838,36 @@
}
private void ensureFromLibraryOrThrow(DexType type, DexClass context) {
- if (!mode.isInitialTreeShaking()) {
+ if (mode.isTracingMainDex()) {
// b/72312389: android.jar contains parts of JUnit and most developers include JUnit in
// their programs. This leads to library classes extending program classes. When tracing
// main dex lists we allow this.
return;
}
- DexClass holder = appView.definitionFor(type);
- if (holder != null && !holder.isLibraryClass()) {
- if (forceProguardCompatibility) {
- // To ensure that the program works correctly we have to pin all super types and members
- // in the tree.
- appInfo.forEachSuperType(
- holder,
- (dexType, ignored) -> {
- if (holder.isProgramClass()) {
- DexProgramClass holderClass = holder.asProgramClass();
- keepInfo.keepClass(holderClass);
- rootSet.shouldNotBeMinified(holder.toReference());
- for (DexEncodedMember<?, ?> member : holder.members()) {
- keepInfo.keepMember(holderClass, member);
- DexMember<?, ?> memberReference = member.toReference();
- rootSet.shouldNotBeMinified(memberReference);
- }
- }
- });
- }
- if (dontWarnPatterns.matches(context.type)) {
- // Ignore.
- return;
- }
+ DexProgramClass holder = getProgramClassOrNull(type);
+ if (holder == null) {
+ return;
+ }
+ if (forceProguardCompatibility) {
+ // To ensure that the program works correctly we have to pin all super types and members
+ // in the tree.
+ KeepReason keepReason = KeepReason.reachableFromLiveType(context.type);
+ keepClassAndAllMembers(holder, keepReason);
+ appInfo.forEachSuperType(
+ holder,
+ (dexType, ignored) -> {
+ DexProgramClass superClass = getProgramClassOrNull(dexType);
+ if (superClass != null) {
+ keepClassAndAllMembers(superClass, keepReason);
+ }
+ });
+ }
+ if (dontWarnPatterns.matches(context.type)) {
+ // Ignore.
+ return;
+ }
+ // Only report an error during the first round of treeshaking.
+ if (mode.isInitialTreeShaking()) {
Diagnostic message =
new StringDiagnostic(
"Library class "
@@ -1873,6 +1883,25 @@
}
}
+ private void keepClassAndAllMembers(DexProgramClass clazz, KeepReason keepReason) {
+ KeepReasonWitness keepReasonWitness = graphReporter.registerClass(clazz, keepReason);
+ markClassAsInstantiatedWithCompatRule(clazz.asProgramClass(), keepReasonWitness);
+ keepInfo.keepClass(clazz);
+ rootSet.shouldNotBeMinified(clazz.toReference());
+ clazz.forEachProgramField(
+ field -> {
+ keepInfo.keepField(field);
+ rootSet.shouldNotBeMinified(field.getReference());
+ markFieldAsKept(field, keepReasonWitness);
+ });
+ clazz.forEachProgramMethod(
+ method -> {
+ keepInfo.keepMethod(method);
+ rootSet.shouldNotBeMinified(method.getReference());
+ markMethodAsKept(method, keepReasonWitness);
+ });
+ }
+
private void reportMissingClass(DexType clazz) {
assert !mode.isFinalTreeShaking()
|| appView.dexItemFactory().isPossiblyCompilerSynthesizedType(clazz)
@@ -2227,7 +2256,7 @@
private void transitionDependentItemsForInstantiatedItem(DexProgramClass clazz) {
do {
// Handle keep rules that are dependent on the class being instantiated.
- rootSet.forEachDependentNonStaticMember(clazz, appView, this::enqueueDependentItem);
+ rootSet.forEachDependentNonStaticMember(clazz, appView, this::enqueueDependentMember);
// Visit the super type.
clazz =
@@ -2639,6 +2668,24 @@
new KotlinMetadataEnqueuerExtension(
appView, enqueuerDefinitionSupplier, initialPrunedTypes));
}
+ if (mode.isInitialTreeShaking()) {
+ // This is simulating the effect of the "root set" applied rules.
+ // This is done only in the initial pass, in subsequent passes the "rules" are reapplied
+ // by iterating the instances.
+ for (DexReference reference : rootSet.noObfuscation) {
+ keepInfo.evaluateRule(reference, appInfo, Joiner::disallowMinification);
+ }
+ } else if (appView.getKeepInfo() != null) {
+ appView
+ .getKeepInfo()
+ .getRuleInstances()
+ .forEach(
+ (reference, rules) -> {
+ for (Consumer<Joiner<?, ?, ?>> rule : rules) {
+ keepInfo.evaluateRule(reference, appInfo, rule);
+ }
+ });
+ }
if (appView.options().isShrinking() || appView.options().getProguardConfiguration() == null) {
enqueueRootItems(rootSet.noShrinking);
} else {
@@ -2669,43 +2716,35 @@
}
private void keepClassWithRules(DexProgramClass clazz, Set<ProguardKeepRuleBase> rules) {
- keepInfo.joinClass(
- clazz,
- info ->
- info.pin()
- .lazyDisallowAccessModification(() -> computeDisallowAccessModification(rules)));
+ keepInfo.joinClass(clazz, info -> applyKeepRules(rules, info));
}
private void keepMethodWithRules(
DexProgramClass holder, DexEncodedMethod method, Set<ProguardKeepRuleBase> rules) {
- keepInfo.joinMethod(
- holder,
- method,
- info ->
- info.pin()
- .lazyDisallowAccessModification(() -> computeDisallowAccessModification(rules)));
+ keepInfo.joinMethod(holder, method, info -> applyKeepRules(rules, info));
}
private void keepFieldWithRules(
DexProgramClass holder, DexEncodedField field, Set<ProguardKeepRuleBase> rules) {
- keepInfo.joinField(
- holder,
- field,
- info ->
- info.pin()
- .lazyDisallowAccessModification(() -> computeDisallowAccessModification(rules)));
+ keepInfo.joinField(holder, field, info -> applyKeepRules(rules, info));
}
- private boolean computeDisallowAccessModification(Set<ProguardKeepRuleBase> rules) {
+ private void applyKeepRules(Set<ProguardKeepRuleBase> rules, KeepInfo.Joiner<?, ?, ?> joiner) {
for (ProguardKeepRuleBase rule : rules) {
ProguardKeepRuleModifiers modifiers =
(rule.isProguardIfRule() ? rule.asProguardIfRule().getSubsequentRule() : rule)
.getModifiers();
+ if (!modifiers.allowsShrinking) {
+ // TODO(b/159589281): Evaluate this interpretation.
+ joiner.pin();
+ }
+ if (!modifiers.allowsObfuscation) {
+ joiner.disallowMinification();
+ }
if (!modifiers.allowsAccessModification) {
- return true;
+ joiner.disallowAccessModification();
}
}
- return false;
}
private static class SyntheticAdditions {
@@ -3283,11 +3322,11 @@
consequentRootSet.forEachDependentInstanceConstructor(
clazz, appView, this::enqueueHolderWithDependentInstanceConstructor);
consequentRootSet.forEachDependentStaticMember(
- clazz, appView, this::enqueueDependentItem);
+ clazz, appView, this::enqueueDependentMember);
if (objectAllocationInfoCollection.isInstantiatedDirectlyOrHasInstantiatedSubtype(
clazz)) {
consequentRootSet.forEachDependentNonStaticMember(
- clazz, appView, this::enqueueDependentItem);
+ clazz, appView, this::enqueueDependentMember);
}
compatEnqueueHolderIfDependentNonStaticMember(
clazz, consequentRootSet.getDependentKeepClassCompatRule(clazz.type));
@@ -3302,13 +3341,18 @@
});
// TODO(b/132600955): This modifies the root set. Should the consequent be persistent?
rootSet.addConsequentRootSet(consequentRootSet, addNoShrinking);
+ if (mode.isInitialTreeShaking()) {
+ for (DexReference reference : consequentRootSet.noObfuscation) {
+ keepInfo.evaluateRule(reference, appView, Joiner::disallowMinification);
+ }
+ }
enqueueRootItems(consequentRootSet.noShrinking);
// Check for compatibility rules indicating that the holder must be implicitly kept.
if (forceProguardCompatibility) {
consequentRootSet.dependentKeepClassCompatRule.forEach(
(precondition, compatRules) -> {
assert precondition.isDexType();
- DexClass preconditionHolder = appView.definitionFor(precondition.asDexType());
+ DexProgramClass preconditionHolder = getProgramClassOrNull(precondition.asDexType());
compatEnqueueHolderIfDependentNonStaticMember(preconditionHolder, compatRules);
});
}
diff --git a/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java b/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java
new file mode 100644
index 0000000..18ae09e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, 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.shaking;
+
+/** Globally controlled settings that affect the default values for kept items. */
+public interface GlobalKeepInfoConfiguration {
+
+ boolean isTreeShakingEnabled();
+
+ boolean isMinificationEnabled();
+
+ boolean isAccessModificationEnabled();
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
index 761547a..a1f8424 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
@@ -4,21 +4,23 @@
package com.android.tools.r8.shaking;
import com.android.tools.r8.shaking.KeepInfo.Builder;
-import java.util.function.Supplier;
/** Keep information that can be associated with any item, i.e., class, method or field. */
public abstract class KeepInfo<B extends Builder, K extends KeepInfo> {
private final boolean pinned;
+ private final boolean allowMinification;
private final boolean allowAccessModification;
- private KeepInfo(boolean pinned, boolean allowAccessModification) {
+ private KeepInfo(boolean pinned, boolean allowMinification, boolean allowAccessModification) {
this.pinned = pinned;
+ this.allowMinification = allowMinification;
this.allowAccessModification = allowAccessModification;
}
KeepInfo(B builder) {
- this(builder.isPinned(), builder.isAccessModificationAllowed());
+ this(
+ builder.isPinned(), builder.isMinificationAllowed(), builder.isAccessModificationAllowed());
}
/** True if an item must be present in the output. */
@@ -27,6 +29,20 @@
}
/**
+ * True if an item may have its name minified/changed.
+ *
+ * <p>This method requires knowledge of the global configuration as that can override the concrete
+ * value on a given item.
+ */
+ public boolean isMinificationAllowed(GlobalKeepInfoConfiguration configuration) {
+ return configuration.isMinificationEnabled() && internalIsMinificationAllowed();
+ }
+
+ boolean internalIsMinificationAllowed() {
+ return allowMinification;
+ }
+
+ /**
* True if an item may have its access flags modified.
*
* <p>This method requires knowledge of the global access modification as that will override the
@@ -34,8 +50,8 @@
*
* @param configuration Global configuration object to determine access modification.
*/
- public boolean isAccessModificationAllowed(ProguardConfiguration configuration) {
- return configuration.isAccessModificationAllowed() && internalIsAccessModificationAllowed();
+ public boolean isAccessModificationAllowed(GlobalKeepInfoConfiguration configuration) {
+ return configuration.isAccessModificationEnabled() && internalIsAccessModificationAllowed();
}
// Internal accessor for the items access-modification bit.
@@ -69,6 +85,7 @@
private K original;
private boolean pinned;
+ private boolean allowMinification;
private boolean allowAccessModification;
Builder() {
@@ -78,17 +95,20 @@
Builder(K original) {
this.original = original;
pinned = original.isPinned();
+ allowMinification = original.internalIsMinificationAllowed();
allowAccessModification = original.internalIsAccessModificationAllowed();
}
B makeTop() {
pin();
+ disallowMinification();
disallowAccessModification();
return self();
}
B makeBottom() {
unpin();
+ allowMinification();
allowAccessModification();
return self();
}
@@ -110,6 +130,7 @@
private boolean internalIsEqualTo(K other) {
return isPinned() == other.isPinned()
+ && isMinificationAllowed() == other.internalIsMinificationAllowed()
&& isAccessModificationAllowed() == other.internalIsAccessModificationAllowed()
&& isEqualTo(other);
}
@@ -118,6 +139,10 @@
return pinned;
}
+ public boolean isMinificationAllowed() {
+ return allowMinification;
+ }
+
public boolean isAccessModificationAllowed() {
return allowAccessModification;
}
@@ -135,6 +160,19 @@
return setPinned(false);
}
+ public B setAllowMinification(boolean allowMinification) {
+ this.allowMinification = allowMinification;
+ return self();
+ }
+
+ public B allowMinification() {
+ return setAllowMinification(true);
+ }
+
+ public B disallowMinification() {
+ return setAllowMinification(false);
+ }
+
public B setAllowAccessModification(boolean allowAccessModification) {
this.allowAccessModification = allowAccessModification;
return self();
@@ -175,12 +213,13 @@
return self();
}
- // Lazy modification of access modification.
- // Only forced if access modification is still allowed.
- public J lazyDisallowAccessModification(Supplier<Boolean> lazyShouldDisallow) {
- if (builder.isAccessModificationAllowed() && lazyShouldDisallow.get()) {
- builder.disallowAccessModification();
- }
+ public J disallowMinification() {
+ builder.disallowMinification();
+ return self();
+ }
+
+ public J disallowAccessModification() {
+ builder.disallowAccessModification();
return self();
}
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
index 37c8771..53af669 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -20,8 +20,10 @@
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.KeepFieldInfo.Joiner;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
+import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@@ -43,6 +45,8 @@
return KeepFieldInfo.bottom();
}
+ abstract Map<DexReference, List<Consumer<KeepInfo.Joiner<?, ?, ?>>>> getRuleInstances();
+
/**
* Base accessor for keep info on a class.
*
@@ -127,6 +131,14 @@
return getFieldInfo(field, definitions).isPinned();
}
+ public final boolean isMinificationAllowed(
+ DexReference reference,
+ DexDefinitionSupplier definitions,
+ GlobalKeepInfoConfiguration configuration) {
+ return configuration.isMinificationEnabled()
+ && getInfo(reference, definitions).isMinificationAllowed(configuration);
+ }
+
public final boolean verifyNoneArePinned(Collection<DexType> types, AppInfo appInfo) {
for (DexType type : types) {
DexProgramClass clazz =
@@ -161,17 +173,26 @@
private final Map<DexMethod, KeepMethodInfo> keepMethodInfo;
private final Map<DexField, KeepFieldInfo> keepFieldInfo;
+ // Map of applied rules for which keys may need to be mutated.
+ private final Map<DexReference, List<Consumer<KeepInfo.Joiner<?, ?, ?>>>> ruleInstances;
+
MutableKeepInfoCollection() {
- this(new IdentityHashMap<>(), new IdentityHashMap<>(), new IdentityHashMap<>());
+ this(
+ new IdentityHashMap<>(),
+ new IdentityHashMap<>(),
+ new IdentityHashMap<>(),
+ new IdentityHashMap<>());
}
private MutableKeepInfoCollection(
Map<DexType, KeepClassInfo> keepClassInfo,
Map<DexMethod, KeepMethodInfo> keepMethodInfo,
- Map<DexField, KeepFieldInfo> keepFieldInfo) {
+ Map<DexField, KeepFieldInfo> keepFieldInfo,
+ Map<DexReference, List<Consumer<KeepInfo.Joiner<?, ?, ?>>>> ruleInstances) {
this.keepClassInfo = keepClassInfo;
this.keepMethodInfo = keepMethodInfo;
this.keepFieldInfo = keepFieldInfo;
+ this.ruleInstances = ruleInstances;
}
@Override
@@ -197,7 +218,43 @@
assert !info.isPinned() || field == newField;
newFieldInfo.put(newField, info);
});
- return new MutableKeepInfoCollection(newClassInfo, newMethodInfo, newFieldInfo);
+ Map<DexReference, List<Consumer<KeepInfo.Joiner<?, ?, ?>>>> newRuleInstances =
+ new IdentityHashMap<>(ruleInstances.size());
+ ruleInstances.forEach(
+ (reference, consumers) -> {
+ DexReference newReference;
+ if (reference.isDexType()) {
+ DexType newType = lens.lookupType(reference.asDexType());
+ if (!newType.isClassType()) {
+ assert newType.isIntType() : "Expected only enum unboxing type changes.";
+ return;
+ }
+ newReference = newType;
+ } else if (reference.isDexMethod()) {
+ newReference = lens.getRenamedMethodSignature(reference.asDexMethod());
+ } else {
+ assert reference.isDexField();
+ newReference = lens.getRenamedFieldSignature(reference.asDexField());
+ }
+ newRuleInstances.put(newReference, consumers);
+ });
+ return new MutableKeepInfoCollection(
+ newClassInfo, newMethodInfo, newFieldInfo, newRuleInstances);
+ }
+
+ @Override
+ Map<DexReference, List<Consumer<KeepInfo.Joiner<?, ?, ?>>>> getRuleInstances() {
+ return ruleInstances;
+ }
+
+ void evaluateRule(
+ DexReference reference,
+ DexDefinitionSupplier definitions,
+ Consumer<KeepInfo.Joiner<?, ?, ?>> fn) {
+ joinInfo(reference, definitions, fn);
+ if (!getInfo(reference, definitions).isBottom()) {
+ ruleInstances.computeIfAbsent(reference, k -> new ArrayList<>()).add(fn);
+ }
}
@Override
@@ -230,6 +287,34 @@
}
}
+ public void joinInfo(
+ DexReference reference,
+ DexDefinitionSupplier definitions,
+ Consumer<KeepInfo.Joiner<?, ?, ?>> fn) {
+ if (reference.isDexType()) {
+ DexType type = reference.asDexType();
+ DexProgramClass clazz = asProgramClassOrNull(definitions.definitionFor(type));
+ if (clazz != null) {
+ joinClass(clazz, fn::accept);
+ }
+ } else if (reference.isDexMethod()) {
+ DexMethod method = reference.asDexMethod();
+ DexProgramClass clazz = asProgramClassOrNull(definitions.definitionFor(method.holder));
+ DexEncodedMethod definition = method.lookupOnClass(clazz);
+ if (definition != null) {
+ joinMethod(clazz, definition, fn::accept);
+ }
+ } else {
+ assert reference.isDexField();
+ DexField field = reference.asDexField();
+ DexProgramClass clazz = asProgramClassOrNull(definitions.definitionFor(field.holder));
+ DexEncodedField definition = field.lookupOnClass(clazz);
+ if (definition != null) {
+ joinField(clazz, definition, fn::accept);
+ }
+ }
+ }
+
public void keepClass(DexProgramClass clazz) {
joinClass(clazz, KeepInfo.Joiner::top);
}
@@ -303,6 +388,10 @@
}
}
+ public void keepField(ProgramField programField) {
+ keepField(programField.getHolder(), programField.getDefinition());
+ }
+
public void keepField(DexProgramClass holder, DexEncodedField field) {
joinField(holder, field, KeepInfo.Joiner::top);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index b38d077..ec9f101 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -1368,7 +1368,7 @@
public void forEachDependentMember(
DexDefinition item,
AppView<?> appView,
- Consumer3<DexDefinition, DexDefinition, Set<ProguardKeepRuleBase>> fn) {
+ Consumer3<DexDefinition, DexEncodedMember<?, ?>, Set<ProguardKeepRuleBase>> fn) {
getDependentItems(item)
.forEachMember(
(reference, reasons) -> {
@@ -1386,7 +1386,7 @@
public void forEachDependentNonStaticMember(
DexDefinition item,
AppView<?> appView,
- Consumer3<DexDefinition, DexDefinition, Set<ProguardKeepRuleBase>> fn) {
+ Consumer3<DexDefinition, DexEncodedMember<?, ?>, Set<ProguardKeepRuleBase>> fn) {
forEachDependentMember(
item,
appView,
@@ -1400,7 +1400,7 @@
public void forEachDependentStaticMember(
DexDefinition item,
AppView<?> appView,
- Consumer3<DexDefinition, DexDefinition, Set<ProguardKeepRuleBase>> fn) {
+ Consumer3<DexDefinition, DexEncodedMember<?, ?>, Set<ProguardKeepRuleBase>> fn) {
forEachDependentMember(
item,
appView,
@@ -1903,24 +1903,6 @@
noObfuscation.add(reference);
}
- public boolean mayBeMinified(DexReference reference, AppView<?> appView) {
- return !mayNotBeMinified(reference, appView);
- }
-
- public boolean mayNotBeMinified(DexReference reference, AppView<?> appView) {
- if (reference.isDexType()) {
- return noObfuscation.contains(
- appView.graphLense().getOriginalType(reference.asDexType()));
- } else if (reference.isDexMethod()) {
- return noObfuscation.contains(
- appView.graphLense().getOriginalMethodSignature(reference.asDexMethod()));
- } else {
- assert reference.isDexField();
- return noObfuscation.contains(
- appView.graphLense().getOriginalFieldSignature(reference.asDexField()));
- }
- }
-
public boolean verifyKeptFieldsAreAccessedAndLive(AppInfoWithLiveness appInfo) {
noShrinking.forEachField(
reference -> {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 35e4614..f7353d9 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -45,6 +45,7 @@
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.Enqueuer;
+import com.android.tools.r8.shaking.GlobalKeepInfoConfiguration;
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.IROrdering.IdentityIROrdering;
@@ -77,7 +78,7 @@
import java.util.function.Predicate;
import org.objectweb.asm.Opcodes;
-public class InternalOptions {
+public class InternalOptions implements GlobalKeepInfoConfiguration {
// Set to true to run compilation in a single thread and without randomly shuffling the input.
// This makes life easier when running R8 in a debugger.
@@ -481,13 +482,33 @@
private final boolean enableMinification;
public boolean isShrinking() {
+ assert proguardConfiguration == null
+ || enableTreeShaking == proguardConfiguration.isShrinking();
return enableTreeShaking;
}
public boolean isMinifying() {
+ assert proguardConfiguration == null
+ || enableMinification == proguardConfiguration.isObfuscating();
return enableMinification;
}
+ @Override
+ public boolean isTreeShakingEnabled() {
+ return isShrinking();
+ }
+
+ @Override
+ public boolean isMinificationEnabled() {
+ return isMinifying();
+ }
+
+ @Override
+ public boolean isAccessModificationEnabled() {
+ return getProguardConfiguration() != null
+ && getProguardConfiguration().isAccessModificationAllowed();
+ }
+
public boolean keepInnerClassStructure() {
return getProguardConfiguration().getKeepAttributes().signature
|| getProguardConfiguration().getKeepAttributes().innerClasses;
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 367092b..83f8ec0 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -47,7 +47,7 @@
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.Range;
-import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
+import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.google.common.base.Suppliers;
import java.util.ArrayList;
@@ -448,7 +448,7 @@
if (appView.options().isGeneratingClassFiles()) {
return true;
}
- RootSet rootSet = appView.rootSet();
+ KeepInfoCollection keepInfo = appView.getKeepInfo();
boolean allSeenAreInstanceInitializers = true;
DexString originalName = null;
for (DexEncodedMethod method : methods) {
@@ -459,7 +459,7 @@
}
allSeenAreInstanceInitializers = false;
// If the method is pinned, we cannot minify it.
- if (rootSet.mayNotBeMinified(method.method, appView)) {
+ if (!keepInfo.isMinificationAllowed(method.method, appView, appView.options())) {
continue;
}
// With desugared library, call-backs names are reserved here.
diff --git a/src/main/java/com/android/tools/r8/utils/SemanticVersion.java b/src/main/java/com/android/tools/r8/utils/SemanticVersion.java
new file mode 100644
index 0000000..977073d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/SemanticVersion.java
@@ -0,0 +1,84 @@
+// Copyright (c) 2020, 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.utils;
+
+import java.util.Objects;
+
+public class SemanticVersion {
+
+ public static SemanticVersion parse(String version) {
+ int majorEnd = version.indexOf('.');
+ if (majorEnd <= 0) {
+ throw new IllegalArgumentException("Invalid semantic version: " + version);
+ }
+ int minorEnd = version.indexOf('.', majorEnd + 1);
+ if (minorEnd <= majorEnd) {
+ throw new IllegalArgumentException("Invalid semantic version: " + version);
+ }
+ // No current support for extensions.
+ int patchEnd = version.length();
+ int major;
+ int minor;
+ int patch;
+ try {
+ major = Integer.parseInt(version.substring(0, majorEnd));
+ minor = Integer.parseInt(version.substring(majorEnd + 1, minorEnd));
+ patch = Integer.parseInt(version.substring(minorEnd + 1, patchEnd));
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid semantic version: " + version, e);
+ }
+ return new SemanticVersion(major, minor, patch);
+ }
+
+ private final int major;
+ private final int minor;
+ private final int patch;
+
+ public SemanticVersion(int major, int minor, int patch) {
+ this.major = major;
+ this.minor = minor;
+ this.patch = patch;
+ }
+
+ public int getMajor() {
+ return major;
+ }
+
+ public int getMinor() {
+ return minor;
+ }
+
+ public int getPatch() {
+ return patch;
+ }
+
+ public boolean isNewerOrEqual(SemanticVersion other) {
+ if (major != other.major) {
+ return major > other.major;
+ }
+ if (minor != other.minor) {
+ return minor > other.minor;
+ }
+ return patch >= other.patch;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof SemanticVersion)) {
+ return false;
+ }
+ SemanticVersion other = (SemanticVersion) obj;
+ return major == other.major && minor == other.minor && patch == other.patch;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(major, minor, patch);
+ }
+
+ @Override
+ public String toString() {
+ return "" + major + "." + minor + "." + patch;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java b/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java
index 846bc6b..2c53667 100644
--- a/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java
+++ b/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
@@ -32,7 +31,7 @@
}
public D8ApiBinaryCompatibilityTests(TestParameters parameters) {
- assertEquals(NoneRuntime.getInstance(), parameters.getRuntime());
+ parameters.assertNoneRuntime();
}
@Test
diff --git a/src/test/java/com/android/tools/r8/MarkerMatcher.java b/src/test/java/com/android/tools/r8/MarkerMatcher.java
new file mode 100644
index 0000000..90aec54
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/MarkerMatcher.java
@@ -0,0 +1,181 @@
+// Copyright (c) 2020, 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+public abstract class MarkerMatcher extends TypeSafeMatcher<Marker> {
+
+ public static void assertMarkersMatch(
+ Iterable<Marker> markers, Collection<Matcher<Marker>> matchers) {
+ // Match is unordered, but we make no attempts to find the maximum match.
+ int markerCount = 0;
+ Set<Marker> matchedMarkers = new HashSet<>();
+ Set<Matcher<Marker>> matchedMatchers = new HashSet<>();
+ for (Marker marker : markers) {
+ markerCount++;
+ for (Matcher<Marker> matcher : matchers) {
+ if (matchedMatchers.contains(matcher)) {
+ continue;
+ }
+ if (matcher.matches(marker)) {
+ matchedMarkers.add(marker);
+ matchedMatchers.add(matcher);
+ break;
+ }
+ }
+ }
+ StringBuilder builder = new StringBuilder();
+ boolean failedMatching = false;
+ if (matchedMarkers.size() < markerCount) {
+ failedMatching = true;
+ builder.append("\nUnmatched markers:");
+ for (Marker marker : markers) {
+ if (!matchedMarkers.contains(marker)) {
+ builder.append("\n - ").append(marker);
+ }
+ }
+ }
+ if (matchedMatchers.size() < matchers.size()) {
+ failedMatching = true;
+ builder.append("\nUnmatched matchers:");
+ for (Matcher<Marker> matcher : matchers) {
+ if (!matchedMatchers.contains(matcher)) {
+ builder.append("\n - ").append(matcher);
+ }
+ }
+ }
+ if (failedMatching) {
+ builder.append("\nAll markers:");
+ for (Marker marker : markers) {
+ builder.append("\n - ").append(marker);
+ }
+ builder.append("\nAll matchers:");
+ for (Matcher<Marker> matcher : matchers) {
+ builder.append("\n - ").append(matcher);
+ }
+ fail(builder.toString());
+ }
+ // Double check consistency.
+ assertEquals(matchers.size(), markerCount);
+ assertEquals(markerCount, matchedMarkers.size());
+ assertEquals(markerCount, matchedMatchers.size());
+ }
+
+ public static Matcher<Marker> markerTool(Tool tool) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ return marker.getTool() == tool;
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description.appendText("tool ").appendText(tool.name());
+ }
+ };
+ }
+
+ public static Matcher<Marker> markerCompilationMode(CompilationMode compilationMode) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ return marker.getCompilationMode().equals(compilationMode.name().toLowerCase());
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description.appendText(Marker.COMPILATION_MODE + " ").appendText(compilationMode.name());
+ }
+ };
+ }
+
+ public static Matcher<Marker> markerMinApi(AndroidApiLevel level) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ return marker.getMinApi() == level.getLevel();
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description.appendText(Marker.MIN_API + " ").appendText(level.toString());
+ }
+ };
+ }
+
+ public static Matcher<Marker> markerHasChecksums(boolean value) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ return marker.getHasChecksums() == value;
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description.appendText(Marker.HAS_CHECKSUMS + " ").appendText(Boolean.toString(value));
+ }
+ };
+ }
+
+ public static Matcher<Marker> markerR8Mode(String r8Mode) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ return marker.getR8Mode().equals(r8Mode);
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description.appendText(Marker.R8_MODE + " ").appendText(r8Mode);
+ }
+ };
+ }
+
+ public static Matcher<Marker> markerDesugaredLibraryIdentifier(
+ String desugaredLibraryIdentifier) {
+ return new MarkerMatcher() {
+ @Override
+ protected boolean eval(Marker marker) {
+ if (marker.getDesugaredLibraryIdentifiers().length != 1) {
+ return false;
+ }
+ return marker.getDesugaredLibraryIdentifiers()[0].equals(desugaredLibraryIdentifier);
+ }
+
+ @Override
+ protected void explain(Description description) {
+ description
+ .appendText(Marker.DESUGARED_LIBRARY_IDENTIFIERS + " ")
+ .appendText(desugaredLibraryIdentifier);
+ }
+ };
+ }
+
+ @Override
+ protected boolean matchesSafely(Marker marker) {
+ return eval(marker);
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ explain(description.appendText("a marker "));
+ }
+
+ protected abstract boolean eval(Marker diagnostic);
+
+ protected abstract void explain(Description description);
+}
diff --git a/src/test/java/com/android/tools/r8/MarkersTest.java b/src/test/java/com/android/tools/r8/MarkersTest.java
new file mode 100644
index 0000000..cc7b81e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/MarkersTest.java
@@ -0,0 +1,88 @@
+// Copyright (c) 2020, 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;
+
+import static com.android.tools.r8.MarkerMatcher.assertMarkersMatch;
+import static com.android.tools.r8.MarkerMatcher.markerCompilationMode;
+import static com.android.tools.r8.MarkerMatcher.markerDesugaredLibraryIdentifier;
+import static com.android.tools.r8.MarkerMatcher.markerHasChecksums;
+import static com.android.tools.r8.MarkerMatcher.markerMinApi;
+import static com.android.tools.r8.MarkerMatcher.markerR8Mode;
+import static com.android.tools.r8.MarkerMatcher.markerTool;
+import static org.hamcrest.CoreMatchers.allOf;
+
+import com.android.tools.r8.dex.Marker;
+import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.util.Collection;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MarkersTest extends TestBase {
+
+ @Parameterized.Parameters(name = "{0}, compilationMode {1}, shrinkDesugaredLibrary {2}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withNoneRuntime().build(),
+ CompilationMode.values(),
+ BooleanUtils.values());
+ }
+
+ private final TestParameters parameters;
+ private final CompilationMode compilationMode;
+ private final boolean shrinkDesugaredLibrary;
+
+ public MarkersTest(
+ TestParameters parameters, CompilationMode compilationMode, boolean shrinkDesugaredLibrary) {
+ this.parameters = parameters;
+ this.compilationMode = compilationMode;
+ this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ }
+
+ @Test
+ public void testL8Marker() throws Throwable {
+ AndroidApiLevel apiLevel = AndroidApiLevel.L;
+ Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
+ L8Command.Builder builder =
+ L8Command.builder()
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .addProgramFiles(ToolHelper.getDesugarJDKLibs())
+ .setMinApiLevel(apiLevel.getLevel())
+ .setMode(compilationMode)
+ .addDesugaredLibraryConfiguration(
+ StringResource.fromFile(ToolHelper.DESUGAR_LIB_JSON_FOR_TESTING))
+ .setOutput(output, OutputMode.DexIndexed);
+ if (shrinkDesugaredLibrary) {
+ builder.addProguardConfiguration(ImmutableList.of("-keep class * { *; }"), Origin.unknown());
+ }
+ L8.run(builder.build());
+ Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(output);
+ Matcher<Marker> l8Matcher =
+ allOf(
+ markerTool(Tool.L8),
+ markerCompilationMode(compilationMode),
+ markerDesugaredLibraryIdentifier("com.tools.android:desugar_jdk_libs:1.0.10"),
+ markerHasChecksums(false));
+ Matcher<Marker> d8Matcher =
+ allOf(
+ markerTool(Tool.R8),
+ markerCompilationMode(compilationMode),
+ markerMinApi(apiLevel),
+ markerR8Mode("compatibility"));
+ Matcher<Marker> r8Matcher =
+ allOf(markerTool(Tool.D8), markerCompilationMode(compilationMode), markerMinApi(apiLevel));
+ if (shrinkDesugaredLibrary) {
+ assertMarkersMatch(markers, ImmutableList.of(l8Matcher, d8Matcher));
+ } else {
+ assertMarkersMatch(markers, ImmutableList.of(l8Matcher, r8Matcher));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java b/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java
index 954d773..ac3d89f 100644
--- a/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java
+++ b/src/test/java/com/android/tools/r8/R8ApiBinaryCompatibilityTests.java
@@ -6,7 +6,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
@@ -35,7 +34,7 @@
}
public R8ApiBinaryCompatibilityTests(TestParameters parameters) {
- assertEquals(NoneRuntime.getInstance(), parameters.getRuntime());
+ parameters.assertNoneRuntime();
}
@Test
diff --git a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
index 2daa0a9..e30b788 100644
--- a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
+++ b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
@@ -44,8 +44,7 @@
DirectMappedDexApplication application =
new ApplicationReader(input, options, timing).read(executorService).toDirect();
IRConverter converter =
- new IRConverter(
- AppView.createForR8(new AppInfoWithClassHierarchy(application), options), null);
+ new IRConverter(AppView.createForR8(new AppInfoWithClassHierarchy(application)), null);
converter.optimize();
DexProgramClass clazz = application.classes().iterator().next();
assertEquals(4, clazz.getMethodCollection().numberOfDirectMethods());
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index aeaf585..78eaabf 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -47,6 +47,7 @@
import com.android.tools.r8.shaking.EnqueuerFactory;
import com.android.tools.r8.shaking.ProguardClassFilter;
import com.android.tools.r8.shaking.ProguardClassNameList;
+import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.shaking.ProguardKeepRule;
import com.android.tools.r8.shaking.ProguardKeepRule.Builder;
@@ -66,6 +67,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.PreloadedClassFileProvider;
+import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.android.tools.r8.utils.Timing;
@@ -574,35 +576,40 @@
return newJar;
}
- protected static AppInfo computeAppInfo(AndroidApp application) {
- try {
- DexApplication dexApplication =
- new ApplicationReader(application, new InternalOptions(), Timing.empty()).read();
- return new AppInfo(dexApplication);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ private static DexApplication readApplicationForDexOutput(AndroidApp app, InternalOptions options)
+ throws Exception {
+ assert options.programConsumer == null;
+ options.programConsumer = DexIndexedConsumer.emptyConsumer();
+ return new ApplicationReader(app, options, Timing.empty()).read();
}
- protected static AppInfoWithClassHierarchy computeAppInfoWithClassHierarchy(
- AndroidApp application) {
- try {
- DexApplication dexApplication =
- new ApplicationReader(application, new InternalOptions(), Timing.empty()).read();
- return new AppInfoWithClassHierarchy(dexApplication);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ protected static AppView<AppInfo> computeAppView(AndroidApp app) throws Exception {
+ AppInfo appInfo = new AppInfo(readApplicationForDexOutput(app, new InternalOptions()));
+ return AppView.createForD8(appInfo);
+ }
+
+ protected static AppInfoWithClassHierarchy computeAppInfoWithClassHierarchy(AndroidApp app)
+ throws Exception {
+ return new AppInfoWithClassHierarchy(readApplicationForDexOutput(app, new InternalOptions()));
}
protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithSubtyping(AndroidApp app)
throws Exception {
- Timing timing = Timing.empty();
- InternalOptions options = new InternalOptions();
- DirectMappedDexApplication application =
- new ApplicationReader(app, options, timing).read().toDirect();
+ return computeAppViewWithSubtyping(
+ app,
+ factory ->
+ buildConfigForRules(
+ factory,
+ Collections.singletonList(ProguardKeepRule.defaultKeepAllRule(unused -> {}))));
+ }
+
+ private static AppView<AppInfoWithClassHierarchy> computeAppViewWithSubtyping(
+ AndroidApp app, Function<DexItemFactory, ProguardConfiguration> keepConfig) throws Exception {
+ DexItemFactory dexItemFactory = new DexItemFactory();
+ InternalOptions options = new InternalOptions(keepConfig.apply(dexItemFactory), new Reporter());
+ DexApplication dexApplication = readApplicationForDexOutput(app, options);
AppView<AppInfoWithClassHierarchy> appView =
- AppView.createForR8(new AppInfoWithClassHierarchy(application), options);
+ AppView.createForR8(new AppInfoWithClassHierarchy(dexApplication.toDirect()));
appView.setAppServices(AppServices.builder(appView).build());
return appView;
}
@@ -610,31 +617,32 @@
protected static AppView<AppInfoWithLiveness> computeAppViewWithLiveness(AndroidApp app)
throws Exception {
return computeAppViewWithLiveness(
- app, factory -> ImmutableList.of(ProguardKeepRule.defaultKeepAllRule(unused -> {})));
+ app,
+ factory ->
+ buildConfigForRules(
+ factory, ImmutableList.of(ProguardKeepRule.defaultKeepAllRule(unused -> {}))));
}
protected static AppView<AppInfoWithLiveness> computeAppViewWithLiveness(
AndroidApp app, Class<?> mainClass) throws Exception {
return computeAppViewWithLiveness(
- app, factory -> buildKeepRuleForClassAndMethods(mainClass, factory));
+ app,
+ factory ->
+ buildConfigForRules(factory, buildKeepRuleForClassAndMethods(mainClass, factory)));
}
protected static AppView<AppInfoWithLiveness> computeAppViewWithLiveness(
- AndroidApp app,
- Function<DexItemFactory, Collection<ProguardConfigurationRule>>
- proguardConfigurationRulesGenerator)
- throws Exception {
- AppView<AppInfoWithClassHierarchy> appView = computeAppViewWithSubtyping(app);
+ AndroidApp app, Function<DexItemFactory, ProguardConfiguration> keepConfig) throws Exception {
+ AppView<AppInfoWithClassHierarchy> appView = computeAppViewWithSubtyping(app, keepConfig);
// Run the tree shaker to compute an instance of AppInfoWithLiveness.
ExecutorService executor = Executors.newSingleThreadExecutor();
DirectMappedDexApplication application = appView.appInfo().app().asDirect();
SubtypingInfo subtypingInfo = new SubtypingInfo(application.allClasses(), application);
RootSet rootSet =
new RootSetBuilder(
- appView,
- subtypingInfo,
- proguardConfigurationRulesGenerator.apply(appView.appInfo().dexItemFactory()))
+ appView, subtypingInfo, application.options.getProguardConfiguration().getRules())
.run(executor);
+ appView.setRootSet(rootSet);
AppInfoWithLiveness appInfoWithLiveness =
EnqueuerFactory.createForInitialTreeShaking(appView, subtypingInfo)
.traceApplication(rootSet, ProguardClassFilter.empty(), executor, application.timing);
@@ -714,6 +722,18 @@
return Collections.singletonList(keepRuleBuilder.build());
}
+ protected static ProguardConfiguration buildConfigForRules(
+ DexItemFactory factory, Collection<ProguardConfigurationRule> rules) {
+ return buildConfigForRules(factory, new Reporter(), rules);
+ }
+
+ protected static ProguardConfiguration buildConfigForRules(
+ DexItemFactory factory, Reporter reporter, Collection<ProguardConfigurationRule> rules) {
+ ProguardConfiguration.Builder builder = ProguardConfiguration.builder(factory, reporter);
+ rules.forEach(builder::addRule);
+ return builder.build();
+ }
+
/** Returns a list containing all the data resources in the given app. */
public static List<DataEntryResource> getDataResources(AndroidApp app) throws ResourceException {
List<DataEntryResource> dataResources = new ArrayList<>();
@@ -1500,4 +1520,28 @@
public static AndroidApiLevel apiLevelWithInvokeCustomSupport() {
return AndroidApiLevel.O;
}
+
+ public Path compileToZip(
+ TestParameters parameters, Collection<Class<?>> classPath, Class<?>... compilationUnit)
+ throws Exception {
+ return compileToZip(parameters, classPath, Arrays.asList(compilationUnit));
+ }
+
+ public Path compileToZip(
+ TestParameters parameters,
+ Collection<Class<?>> classpath,
+ Collection<Class<?>> compilationUnit)
+ throws Exception {
+ if (parameters.isCfRuntime()) {
+ Path out = temp.newFolder().toPath().resolve("out.jar");
+ writeClassesToJar(out, compilationUnit);
+ return out;
+ }
+ return testForD8()
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClasses(compilationUnit)
+ .addClasspathClasses(classpath)
+ .compile()
+ .writeToZip();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java b/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java
index ed0e8f1..72a22e6 100644
--- a/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java
+++ b/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java
@@ -34,6 +34,18 @@
TestDiagnosticMessages assertErrorsCount(int count);
+ default TestDiagnosticMessages assertNoInfos() {
+ return assertInfosCount(0);
+ }
+
+ default TestDiagnosticMessages assertNoWarnings() {
+ return assertWarningsCount(0);
+ }
+
+ default TestDiagnosticMessages assertNoErrors() {
+ return assertErrorsCount(0);
+ }
+
// Match exact.
default TestDiagnosticMessages assertDiagnosticsMatch(Matcher<Diagnostic> matcher) {
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java
index d886efb..75b7336 100644
--- a/src/test/java/com/android/tools/r8/TestParameters.java
+++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import static org.junit.Assert.assertEquals;
+
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -70,4 +72,8 @@
}
return runtime.toString();
}
+
+ public void assertNoneRuntime() {
+ assertEquals(NoneRuntime.getInstance(), runtime);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/bisect/BisectTest.java b/src/test/java/com/android/tools/r8/bisect/BisectTest.java
index 28ecca3..bd1d3c4 100644
--- a/src/test/java/com/android/tools/r8/bisect/BisectTest.java
+++ b/src/test/java/com/android/tools/r8/bisect/BisectTest.java
@@ -37,10 +37,8 @@
return TestParametersBuilder.builder().withNoneRuntime().build();
}
- private final TestParameters parameters;
-
public BisectTest(TestParameters parameters) {
- this.parameters = parameters;
+ parameters.assertNoneRuntime();
}
private final String[] CLASSES = {"A", "B", "C", "D", "E", "F", "G", "H"};
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedTest.java
index b0c7ecf..df38cb2 100644
--- a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedTest.java
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedTest.java
@@ -3,25 +3,27 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.checkdiscarded;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.checkdiscarded.testclasses.Main;
import com.android.tools.r8.checkdiscarded.testclasses.UnusedClass;
import com.android.tools.r8.checkdiscarded.testclasses.UsedClass;
import com.android.tools.r8.checkdiscarded.testclasses.WillBeGone;
import com.android.tools.r8.checkdiscarded.testclasses.WillStay;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.function.Consumer;
import org.junit.Test;
@@ -32,19 +34,19 @@
@RunWith(Parameterized.class)
public class CheckDiscardedTest extends TestBase {
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withNoneRuntime().build();
+ @Parameters(name = "{0}, minify:{1}")
+ public static List<Object[]> data() {
+ return buildParameters(getTestParameters().withNoneRuntime().build(), BooleanUtils.values());
}
- private final TestParameters parameters;
+ public final boolean minify;
- public CheckDiscardedTest(TestParameters parameters) {
- this.parameters = parameters;
+ public CheckDiscardedTest(TestParameters parameters, boolean minify) {
+ assertEquals(NoneRuntime.getInstance(), parameters.getRuntime());
+ this.minify = minify;
}
private void compile(
- boolean obfuscate,
Class annotation,
boolean checkMembers,
Consumer<TestDiagnosticMessages> onCompilationFailure) {
@@ -56,7 +58,7 @@
.addProgramClasses(UnusedClass.class, UsedClass.class, Main.class)
.addKeepMainRule(Main.class)
.addKeepRules(checkDiscardRule(checkMembers, annotation))
- .minification(obfuscate)
+ .minification(minify)
.addOptionsModification(this::noInlining)
.compile();
assertNull(onCompilationFailure);
@@ -80,45 +82,44 @@
@Test
public void classesAreGone() {
- compile(false, WillBeGone.class, false, null);
- compile(true, WillBeGone.class, false, null);
+ compile(WillBeGone.class, false, null);
}
@Test
public void classesAreNotGone() {
Consumer<TestDiagnosticMessages> check =
- diagnostics -> {
- List<Diagnostic> infos = diagnostics.getInfos();
- assertEquals(2, infos.size());
- String messageUsedClass = infos.get(1).getDiagnosticMessage();
- assertThat(messageUsedClass, containsString("UsedClass was not discarded"));
- assertThat(messageUsedClass, containsString("is instantiated in"));
- String messageMain = infos.get(0).getDiagnosticMessage();
- assertThat(messageMain, containsString("Main was not discarded"));
- assertThat(messageMain, containsString("is referenced in keep rule"));
- };
- compile(false, WillStay.class, false, check);
- compile(true, WillStay.class, false, check);
+ diagnostics ->
+ diagnostics
+ .assertNoWarnings()
+ .assertErrorsMatch(diagnosticMessage(containsString("Discard checks failed")))
+ .assertInfosMatch(
+ ImmutableList.of(
+ allOf(
+ diagnosticMessage(containsString("UsedClass was not discarded")),
+ diagnosticMessage(containsString("is instantiated in"))),
+ allOf(
+ diagnosticMessage(containsString("Main was not discarded")),
+ diagnosticMessage(containsString("is referenced in keep rule")))));
+ compile(WillStay.class, false, check);
}
@Test
public void membersAreGone() {
- compile(false, WillBeGone.class, true, null);
- compile(true, WillBeGone.class, true, null);
+ compile(WillBeGone.class, true, null);
}
@Test
public void membersAreNotGone() {
Consumer<TestDiagnosticMessages> check =
- diagnostics -> {
- List<Diagnostic> infos = diagnostics.getInfos();
- assertEquals(1, infos.size());
- String message = infos.get(0).getDiagnosticMessage();
- assertThat(message, containsString("was not discarded"));
- assertThat(message, containsString("is invoked from"));
- };
- compile(false, WillStay.class, true, check);
- compile(true, WillStay.class, true, check);
+ diagnostics ->
+ diagnostics
+ .assertNoWarnings()
+ .assertErrorsMatch(diagnosticMessage(containsString("Discard checks failed")))
+ .assertInfosMatch(
+ allOf(
+ diagnosticMessage(containsString("was not discarded")),
+ diagnosticMessage(containsString("is invoked from"))));
+ compile(WillStay.class, true, check);
}
}
diff --git a/src/test/java/com/android/tools/r8/classlookup/ClasspathClassExtendsProgramClassTest.java b/src/test/java/com/android/tools/r8/classlookup/ClasspathClassExtendsProgramClassTest.java
index b409e5a..f9d6e4d 100644
--- a/src/test/java/com/android/tools/r8/classlookup/ClasspathClassExtendsProgramClassTest.java
+++ b/src/test/java/com/android/tools/r8/classlookup/ClasspathClassExtendsProgramClassTest.java
@@ -4,14 +4,11 @@
package com.android.tools.r8.classlookup;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.references.Reference;
import com.google.common.collect.ImmutableList;
-import java.nio.file.Path;
-import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -63,7 +60,12 @@
public void testReference() throws Exception {
testForRuntime(parameters)
.addProgramClasses(Main.class, ProgramClass.class)
- .addRunClasspathFiles(compileClasspath())
+ .addRunClasspathFiles(
+ compileToZip(
+ parameters,
+ ImmutableList.of(ProgramClass.class),
+ ClasspathClass.class,
+ ClasspathIndirection.class))
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("ClasspathClass::foo");
}
@@ -77,29 +79,13 @@
.addKeepMainRule(Main.class)
// Keep the method that is overridden by the classpath class.
.addKeepMethodRules(Reference.methodFromMethod(ProgramClass.class.getDeclaredMethod("foo")))
- .addRunClasspathFiles(compileClasspath())
+ .addRunClasspathFiles(
+ compileToZip(
+ parameters,
+ ImmutableList.of(ProgramClass.class),
+ ClasspathClass.class,
+ ClasspathIndirection.class))
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("ClasspathClass::foo");
}
-
- private Path compileClasspath() throws java.io.IOException, CompilationFailedException {
- return compile(
- ImmutableList.of(ClasspathClass.class, ClasspathIndirection.class),
- ImmutableList.of(ProgramClass.class));
- }
-
- private Path compile(Collection<Class<?>> compilationUnit, Collection<Class<?>> classpath)
- throws java.io.IOException, CompilationFailedException {
- if (parameters.isCfRuntime()) {
- Path out = temp.newFolder().toPath().resolve("out.jar");
- writeClassesToJar(out, compilationUnit);
- return out;
- }
- return testForD8()
- .setMinApi(parameters.getApiLevel())
- .addProgramClasses(compilationUnit)
- .addClasspathClasses(classpath)
- .compile()
- .writeToZip();
- }
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
index c27b55b..8866342 100644
--- a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
@@ -19,10 +19,9 @@
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import java.util.ArrayList;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,13 +44,14 @@
Class<?> methodToBeKept, Class<?> classToBeKept) throws Exception {
return computeAppViewWithLiveness(
buildClasses(I.class, J.class, K.class, L.class, A.class, Main.class).build(),
- factory -> {
- List<ProguardConfigurationRule> rules = new ArrayList<>();
- rules.addAll(buildKeepRuleForClassAndMethods(methodToBeKept, factory));
- rules.addAll(buildKeepRuleForClass(classToBeKept, factory));
- rules.addAll(buildKeepRuleForClassAndMethods(Main.class, factory));
- return rules;
- });
+ factory ->
+ buildConfigForRules(
+ factory,
+ ImmutableList.<ProguardConfigurationRule>builder()
+ .addAll(buildKeepRuleForClassAndMethods(methodToBeKept, factory))
+ .addAll(buildKeepRuleForClass(classToBeKept, factory))
+ .addAll(buildKeepRuleForClassAndMethods(Main.class, factory))
+ .build()));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java
index 54f3acb..6b46ee4 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.google.common.collect.ImmutableList;
@@ -33,7 +32,7 @@
private final String release;
public BackwardsCompatibleSpecificationTest(TestParameters parameters, String release) {
- assertEquals(NoneRuntime.getInstance(), parameters.getRuntime());
+ parameters.assertNoneRuntime();
this.release = release;
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibaryChecksumsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibaryChecksumsTest.java
index 3e819e2..8280f92 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibaryChecksumsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibaryChecksumsTest.java
@@ -5,7 +5,6 @@
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.CompilationMode;
@@ -16,7 +15,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -36,7 +34,7 @@
}
public DesugaredLibaryChecksumsTest(TestParameters parameters) {
- assertEquals(NoneRuntime.getInstance(), parameters.getRuntime());
+ parameters.assertNoneRuntime();
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
index 92fc7be..1141cb3 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.TestDiagnosticMessagesImpl;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
@@ -28,6 +27,7 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.SemanticVersion;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
import com.google.common.collect.ImmutableList;
@@ -51,7 +51,7 @@
}
public DesugaredLibraryConfigurationParsingTest(TestParameters parameters) {
- assertEquals(NoneRuntime.getInstance(), parameters.getRuntime());
+ parameters.assertNoneRuntime();
}
final AndroidApiLevel minApi = AndroidApiLevel.B;
@@ -73,7 +73,7 @@
DesugaredLibraryConfigurationParser.MAX_SUPPORTED_VERSION)
.put("group_id", "com.tools.android")
.put("artifact_id", "desugar_jdk_libs")
- .put("version", "0.0.0")
+ .put("version", DesugaredLibraryConfigurationParser.MIN_SUPPORTED_VERSION.toString())
.put("required_compilation_api_level", 1)
.put("synthesized_library_classes_package_prefix", "j$.")
.put("common_flags", Collections.emptyList())
@@ -141,6 +141,7 @@
"version",
"required_compilation_api_level",
"synthesized_library_classes_package_prefix",
+ "common_flags",
"program_flags",
"library_flags");
for (String key : requiredKeys) {
@@ -158,9 +159,13 @@
}
@Test
- public void testUnsupportedFormatMissingFlags() {
+ public void testUnsupportedVersion() {
LinkedHashMap<String, Object> data = template();
- data.remove("common_flags");
+ SemanticVersion minVersion = DesugaredLibraryConfigurationParser.MIN_SUPPORTED_VERSION;
+ data.put(
+ "version",
+ new SemanticVersion(minVersion.getMajor(), minVersion.getMinor(), minVersion.getPatch() - 1)
+ .toString());
runFailing(
toJson(data),
diagnostics ->
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java
index 1d66c7f..5f323bc 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DontKeepBootstrapClassesTest.java
@@ -5,11 +5,9 @@
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.Arrays;
import java.util.function.Consumer;
@@ -28,7 +26,7 @@
final AndroidApiLevel minApiLevel = AndroidApiLevel.B;
public DontKeepBootstrapClassesTest(TestParameters parameters) {
- assertEquals(NoneRuntime.getInstance(), parameters.getRuntime());
+ parameters.assertNoneRuntime();
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
index 846b65d..2225ceb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
@@ -99,7 +98,7 @@
private final AndroidApiLevel targetApi = AndroidApiLevel.Q;
public ExtractWrapperTypesTest(TestParameters parameters) {
- assertEquals(NoneRuntime.getInstance(), parameters.getRuntime());
+ parameters.assertNoneRuntime();
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
index 23d3658..6414d4b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -37,7 +37,13 @@
private final TestParameters parameters;
private final boolean shrinkDesugaredLibrary;
private static final String expectedOutput =
- StringUtils.lines("Caught java.time.format.DateTimeParseException", "true", "Hello, world");
+ StringUtils.lines(
+ "Caught java.time.format.DateTimeParseException",
+ "true",
+ "1970-01-02T10:17:36.789Z",
+ "GMT",
+ "GMT",
+ "Hello, world");
@Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
public static List<Object[]> data() {
@@ -62,13 +68,15 @@
String expectedInstanceOfTypes;
if (parameters.getApiLevel().getLevel() >= 26) {
expectedInvokeHolders =
- ImmutableSet.of("java.time.Clock", "java.time.LocalDate", "java.time.ZoneOffset");
+ ImmutableSet.of(
+ "java.time.Clock", "java.time.LocalDate", "java.time.ZoneOffset", "java.time.ZoneId");
expectedCatchGuards = ImmutableSet.of("java.time.format.DateTimeParseException");
expectedCheckCastType = ImmutableSet.of("java.time.ZoneId");
expectedInstanceOfTypes = "java.time.ZoneOffset";
} else {
expectedInvokeHolders =
- ImmutableSet.of("j$.time.Clock", "j$.time.LocalDate", "j$.time.ZoneOffset");
+ ImmutableSet.of(
+ "j$.time.Clock", "j$.time.LocalDate", "j$.time.ZoneOffset", "j$.time.ZoneId");
expectedCatchGuards = ImmutableSet.of("j$.time.format.DateTimeParseException");
expectedCheckCastType = ImmutableSet.of("j$.time.ZoneId");
expectedInstanceOfTypes = "j$.time.ZoneOffset";
@@ -166,6 +174,14 @@
System.out.println("NOT!");
}
System.out.println(java.time.ZoneOffset.getAvailableZoneIds().size() > 0);
+
+ System.out.println(
+ java.util.Date.from(new java.util.Date(123456789).toInstant()).toInstant());
+
+ java.util.TimeZone timeZone = java.util.TimeZone.getTimeZone(java.time.ZoneId.of("GMT"));
+ System.out.println(timeZone.getID());
+ System.out.println(timeZone.toZoneId().getId());
+
System.out.println("Hello, world");
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
index 04a7258..32bbe65 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/RetargetOverrideTest.java
@@ -122,6 +122,26 @@
System.out.println("43");
System.out.println(myAtomicInteger.updateAndGet(x -> x + 100));
System.out.println("145");
+
+ try {
+ MyDateNoOverride.from(myCal.toInstant());
+ System.out.println("b/159441805 fixed");
+ } catch (NoSuchMethodError e) {
+ // TODO(b/159441805): Should not throw.
+ }
+
+ try {
+ MyDateOverride.from(myCal.toInstant());
+ System.out.println("b/159441805 fixed");
+ } catch (NoSuchMethodError e) {
+ // TODO(b/159441805): Should not throw.
+ }
+
+ System.out.println(MyDateDoubleOverride.from(myCal.toInstant()).toInstant());
+ System.out.println("1970-01-02T10:17:36.788Z");
+
+ System.out.println(MyDateTrippleOverride.from(myCal.toInstant()).toInstant());
+ System.out.println("1970-01-02T10:17:36.788Z");
}
public static void polyTypes() {
@@ -212,6 +232,22 @@
public Instant toInstant() {
return super.toInstant().plusSeconds(3);
}
+
+ public static Date from(Instant instant) {
+ return new Date(123456788);
+ }
+ }
+
+ static class MyDateTrippleOverride extends MyDateDoubleOverride {
+
+ public MyDateTrippleOverride(long date) {
+ super(date);
+ }
+
+ @Override
+ public Instant toInstant() {
+ return super.toInstant().plusSeconds(6);
+ }
}
static class MyDateNoOverride extends Date {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicTimeConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicTimeConversionTest.java
deleted file mode 100644
index bb728fb..0000000
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/BasicTimeConversionTest.java
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (c) 2019, 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.desugar.desugaredlibrary.conversiontests;
-
-import static junit.framework.TestCase.assertTrue;
-
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.time.ZoneId;
-import java.util.List;
-import java.util.TimeZone;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class BasicTimeConversionTest extends DesugaredLibraryTestBase {
-
- private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
- private static final String GMT = StringUtils.lines("GMT");
-
- @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
- public static List<Object[]> data() {
- return buildParameters(
- getConversionParametersUpToExcluding(AndroidApiLevel.O), BooleanUtils.values());
- }
-
- public BasicTimeConversionTest(TestParameters parameters, boolean shrinkDesugaredLibrary) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
- this.parameters = parameters;
- }
-
- @Test
- public void testRewrittenAPICallsD8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForD8()
- .setMinApi(parameters.getApiLevel())
- .addInnerClasses(BasicTimeConversionTest.class)
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
- .inspect(this::checkAPIRewritten)
- .run(parameters.getRuntime(), Executor.class)
- .assertSuccessWithOutput(GMT);
- if (shrinkDesugaredLibrary) {
- checkKeepRules(keepRuleConsumer.get());
- }
- }
-
- private void checkKeepRules(String keepRules) {
- assertTrue(keepRules.contains("TimeConversion"));
- }
-
- @Test
- public void testRewrittenAPICallsR8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForR8(parameters.getBackend())
- .setMinApi(parameters.getApiLevel())
- .addKeepMainRule(Executor.class)
- .addInnerClasses(BasicTimeConversionTest.class)
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
- .run(parameters.getRuntime(), Executor.class)
- .assertSuccessWithOutput(GMT);
- if (shrinkDesugaredLibrary) {
- checkKeepRules(keepRuleConsumer.get());
- }
- }
-
- private void checkAPIRewritten(CodeInspector inspector) {
- MethodSubject mainMethod = inspector.clazz(Executor.class).uniqueMethodWithName("main");
- // Check the API calls are not using j$ types.
- assertTrue(
- mainMethod
- .streamInstructions()
- .anyMatch(
- instr ->
- instr.isInvokeStatic()
- && instr.getMethod().name.toString().equals("getTimeZone")
- && instr
- .getMethod()
- .proto
- .parameters
- .values[0]
- .toString()
- .equals("java.time.ZoneId")));
- assertTrue(
- mainMethod
- .streamInstructions()
- .anyMatch(
- instr ->
- instr.isInvokeVirtual()
- && instr.getMethod().name.toString().equals("toZoneId")
- && instr
- .getMethod()
- .proto
- .returnType
- .toString()
- .equals("java.time.ZoneId")));
- // Check the conversion instructions are present.
- assertTrue(
- mainMethod
- .streamInstructions()
- .anyMatch(
- instr ->
- instr.isInvokeStatic()
- && instr.getMethod().name.toString().equals("convert")
- && instr
- .getMethod()
- .proto
- .parameters
- .values[0]
- .toString()
- .equals("j$.time.ZoneId")));
- assertTrue(
- mainMethod
- .streamInstructions()
- .anyMatch(
- instr ->
- instr.isInvokeStatic()
- && instr.getMethod().name.toString().equals("convert")
- && instr
- .getMethod()
- .proto
- .parameters
- .values[0]
- .toString()
- .equals("java.time.ZoneId")));
- }
-
- static class Executor {
- public static void main(String[] args) {
- ZoneId zoneId = ZoneId.systemDefault();
- // Following is a call where java.time.ZoneId is a parameter type (getTimeZone()).
- TimeZone timeZone = TimeZone.getTimeZone(zoneId);
- // Following is a call where java.time.ZoneId is a return type (toZoneId()).
- System.out.println(timeZone.toZoneId().getId());
- }
- }
-}
diff --git a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
index 9c86160..7d22782 100644
--- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -9,7 +9,8 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.ProcessResult;
@@ -30,11 +31,24 @@
import java.nio.file.Path;
import java.util.Collections;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class TargetLookupTest extends SmaliTestBase {
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public TargetLookupTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
@Test
- public void lookupDirect() {
+ public void lookupDirect() throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
builder.addDefaultConstructor();
@@ -100,7 +114,7 @@
}
@Test
- public void lookupDirectSuper() {
+ public void lookupDirectSuper() throws Exception {
SmaliBuilder builder = new SmaliBuilder("TestSuper");
builder.addDefaultConstructor();
@@ -185,7 +199,7 @@
}
@Test
- public void lookupFieldWithDefaultInInterface() throws CompilationFailedException {
+ public void lookupFieldWithDefaultInInterface() throws Exception {
SmaliBuilder builder = new SmaliBuilder();
builder.addInterface("Interface");
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
index 5048226..ca35303 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
@@ -60,7 +60,7 @@
.read(proguardMap, executorService)
.toDirect();
InternalOptions options = new InternalOptions();
- appView = AppView.createForR8(new AppInfoWithClassHierarchy(program), options);
+ appView = AppView.createForR8(new AppInfoWithClassHierarchy(program));
appView.setAppServices(AppServices.builder(appView).build());
subtypingInfo = new SubtypingInfo(program.allClasses(), program);
}
diff --git a/src/test/java/com/android/tools/r8/internal/proto/ProtoShrinkingTestBase.java b/src/test/java/com/android/tools/r8/internal/proto/ProtoShrinkingTestBase.java
index 79ce685..23d12f6 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/ProtoShrinkingTestBase.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/ProtoShrinkingTestBase.java
@@ -115,7 +115,7 @@
continue;
}
- IRCode code = methodSubject.buildIR(dexItemFactory);
+ IRCode code = methodSubject.buildIR();
InvokeMethod invoke =
GeneratedMessageLiteShrinker.getNewMessageInfoInvoke(code, references);
assert invoke != null;
diff --git a/src/test/java/com/android/tools/r8/internal/retrace/RetraceTests.java b/src/test/java/com/android/tools/r8/internal/retrace/RetraceTests.java
index 6fea76f..c8b98d7 100644
--- a/src/test/java/com/android/tools/r8/internal/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/internal/retrace/RetraceTests.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.retrace.Retrace;
import com.android.tools.r8.retrace.RetraceCommand;
import com.android.tools.r8.retrace.stacktraces.StackTraceForTest;
+import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import junit.framework.TestCase;
@@ -32,6 +33,13 @@
return getTestParameters().withNoneRuntime().build();
}
+ private static String REMAPPER_REGEX =
+ "(?:.*?\\bat\\s+%c\\.%m\\s*\\(%S\\)\\s*)"
+ + "|(?:(?:.*?[:\"]\\s+)?%c(?::.*)?)"
+ + "|(?:.*?%t\\s+%c\\.%m\\s*\\(%a\\)\\s*)";
+ private static String FINSKY_REGEX = "(?:.*Finsky\\s+:\\s+\\[\\d+\\]\\s+%c\\.%m\\(%l\\):.*)";
+ private static String SMILEY_EMOJI = "\uD83D\uDE00";
+
public RetraceTests(TestParameters parameters) {}
@Test
@@ -41,7 +49,82 @@
@Test
public void testFinskyStackTrace() {
- runRetraceTest(new FinskyStackTrace(), "(?:.*Finsky\\s+:\\s+\\[\\d+\\]\\s+%c\\.%m\\(%l\\):.*)");
+ runRetraceTest(new FinskyStackTrace(), FINSKY_REGEX);
+ }
+
+ @Test
+ public void testCronetRemapperRegexpTest() {
+ runRetraceTest(new CronetStackTrace(), REMAPPER_REGEX);
+ }
+
+ @Test
+ public void testCronetAndFinskyStackTrace() {
+ CronetStackTrace cronetStackTrace = new CronetStackTrace();
+ FinskyStackTrace finskyStackTrace = new FinskyStackTrace();
+ runRetraceTest(
+ new StackTraceForTest() {
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ ArrayList<String> obfuscated = new ArrayList<>();
+ obfuscated.addAll(cronetStackTrace.obfuscatedStackTrace());
+ obfuscated.addAll(finskyStackTrace.obfuscatedStackTrace());
+ return obfuscated;
+ }
+
+ @Override
+ public String mapping() {
+ return cronetStackTrace.mapping();
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ ArrayList<String> retraced = new ArrayList<>();
+ retraced.addAll(cronetStackTrace.retracedStackTrace());
+ retraced.addAll(finskyStackTrace.retracedStackTrace());
+ return retraced;
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+ },
+ FINSKY_REGEX + "|" + DEFAULT_REGULAR_EXPRESSION);
+ }
+
+ @Test
+ public void testCronetAndFinskyStackTraceRemapperRegExp() {
+ CronetStackTrace cronetStackTrace = new CronetStackTrace();
+ FinskyStackTrace finskyStackTrace = new FinskyStackTrace();
+ runRetraceTest(
+ new StackTraceForTest() {
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ ArrayList<String> obfuscated = new ArrayList<>();
+ obfuscated.addAll(cronetStackTrace.obfuscatedStackTrace());
+ obfuscated.addAll(finskyStackTrace.obfuscatedStackTrace());
+ return obfuscated;
+ }
+
+ @Override
+ public String mapping() {
+ return cronetStackTrace.mapping();
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ ArrayList<String> retraced = new ArrayList<>();
+ retraced.addAll(cronetStackTrace.retracedStackTrace());
+ retraced.addAll(finskyStackTrace.retracedStackTrace());
+ return retraced;
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+ },
+ FINSKY_REGEX + "|" + REMAPPER_REGEX);
}
@Test
@@ -49,6 +132,39 @@
runRetraceTest(new VelvetStackTrace());
}
+ @Test
+ public void testNonAscii() {
+ CronetStackTrace cronetStackTrace = new CronetStackTrace();
+ runRetraceTest(
+ new StackTraceForTest() {
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ ArrayList<String> smileyObf = new ArrayList<>();
+ smileyObf.add(SMILEY_EMOJI);
+ smileyObf.addAll(cronetStackTrace.obfuscatedStackTrace());
+ return smileyObf;
+ }
+
+ @Override
+ public String mapping() {
+ return cronetStackTrace.mapping();
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ ArrayList<String> smileyObf = new ArrayList<>();
+ smileyObf.add(SMILEY_EMOJI);
+ smileyObf.addAll(cronetStackTrace.retracedStackTrace());
+ return smileyObf;
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+ });
+ }
+
private TestDiagnosticMessagesImpl runRetraceTest(StackTraceForTest stackTraceForTest) {
return runRetraceTest(stackTraceForTest, DEFAULT_REGULAR_EXPRESSION);
}
diff --git a/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java b/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java
index 586129b..04c8788 100644
--- a/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.ir;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
@@ -24,11 +26,25 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class BasicBlockIteratorTest extends SmaliTestBase {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
@Rule
public ExpectedException thrown = ExpectedException.none();
+ public BasicBlockIteratorTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
/**
* Simple test IR, which has three blocks:
*
@@ -55,7 +71,7 @@
InternalOptions options = new InternalOptions();
DexApplication dexApplication =
new ApplicationReader(application, options, Timing.empty()).read();
- AppView<?> appView = AppView.createForD8(new AppInfo(dexApplication), options);
+ AppView<?> appView = AppView.createForD8(new AppInfo(dexApplication));
// Build the code, and split the code into three blocks.
MethodSubject methodSubject = getMethodSubject(application, signature);
diff --git a/src/test/java/com/android/tools/r8/ir/InlineTest.java b/src/test/java/com/android/tools/r8/ir/InlineTest.java
index a2246c0..2bd2803 100644
--- a/src/test/java/com/android/tools/r8/ir/InlineTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InlineTest.java
@@ -6,6 +6,9 @@
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppServices;
import com.android.tools.r8.graph.AppView;
@@ -40,9 +43,22 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class InlineTest extends IrInjectionTestBase {
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public InlineTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
private TestApplication buildTestApplication(
DexApplication application,
InternalOptions options,
@@ -51,7 +67,7 @@
throws ExecutionException {
DirectMappedDexApplication directApp = application.asDirect();
AppView<AppInfoWithClassHierarchy> appView =
- AppView.createForR8(new AppInfoWithClassHierarchy(directApp), options);
+ AppView.createForR8(new AppInfoWithClassHierarchy(directApp));
appView.setAppServices(AppServices.builder(appView).build());
ExecutorService executorService = ThreadUtils.getExecutorService(options);
SubtypingInfo subtypingInfo = new SubtypingInfo(directApp.allClasses(), directApp);
@@ -73,7 +89,9 @@
Reporter reporter = new Reporter();
ProguardConfiguration proguardConfiguration =
ProguardConfiguration.builder(new DexItemFactory(), reporter).build();
- return new InternalOptions(proguardConfiguration, reporter);
+ InternalOptions options = new InternalOptions(proguardConfiguration, reporter);
+ options.programConsumer = DexIndexedConsumer.emptyConsumer();
+ return options;
}
private TestApplication codeForMethodReplaceTest(int a, int b) throws ExecutionException {
@@ -129,10 +147,10 @@
MethodSubject methodSubject = getMethodSubject(application, signature);
MethodSubject methodASubject = getMethodSubject(application, signatureA);
- IRCode codeA = methodASubject.buildIR(options.itemFactory);
+ IRCode codeA = methodASubject.buildIR();
MethodSubject methodBSubject = getMethodSubject(application, signatureB);
- IRCode codeB = methodBSubject.buildIR(options.itemFactory);
+ IRCode codeB = methodBSubject.buildIR();
return buildTestApplication(
application, options, methodSubject, ImmutableList.of(codeA, codeB));
@@ -211,7 +229,7 @@
MethodSubject methodSubject = getMethodSubject(application, signature);
MethodSubject methodASubject = getMethodSubject(application, signatureA);
- IRCode codeA = methodASubject.buildIR(options.itemFactory);
+ IRCode codeA = methodASubject.buildIR();
return buildTestApplication(application, options, methodSubject, ImmutableList.of(codeA));
}
@@ -291,13 +309,13 @@
List<IRCode> additionalCode = new ArrayList<>();
for (int i = 0; i < 3; i++) {
MethodSubject methodASubject = getMethodSubject(application, signatureA);
- IRCode codeA = methodASubject.buildIR(options.itemFactory);
+ IRCode codeA = methodASubject.buildIR();
additionalCode.add(codeA);
}
for (int i = 0; i < 3; i++) {
MethodSubject methodBSubject = getMethodSubject(application, signatureB);
- IRCode codeB = methodBSubject.buildIR(options.itemFactory);
+ IRCode codeB = methodBSubject.buildIR();
additionalCode.add(codeB);
}
@@ -421,10 +439,10 @@
MethodSubject methodSubject = getMethodSubject(application, signature);
MethodSubject methodASubject = getMethodSubject(application, signatureA);
- IRCode codeA = methodASubject.buildIR(options.itemFactory);
+ IRCode codeA = methodASubject.buildIR();
MethodSubject methodBSubject = getMethodSubject(application, signatureB);
- IRCode codeB = methodBSubject.buildIR(options.itemFactory);
+ IRCode codeB = methodBSubject.buildIR();
return buildTestApplication(
application, options, methodSubject, ImmutableList.of(codeA, codeB));
@@ -534,10 +552,10 @@
MethodSubject methodSubject = getMethodSubject(application, signature);
MethodSubject methodASubject = getMethodSubject(application, signatureA);
- IRCode codeA = methodASubject.buildIR(options.itemFactory);
+ IRCode codeA = methodASubject.buildIR();
MethodSubject methodBSubject = getMethodSubject(application, signatureB);
- IRCode codeB = methodBSubject.buildIR(options.itemFactory);
+ IRCode codeB = methodBSubject.buildIR();
return buildTestApplication(
application, options, methodSubject, ImmutableList.of(codeA, codeB));
@@ -645,10 +663,10 @@
MethodSubject methodSubject = getMethodSubject(application, signature);
MethodSubject methodASubject = getMethodSubject(application, signatureA);
- IRCode codeA = methodASubject.buildIR(options.itemFactory);
+ IRCode codeA = methodASubject.buildIR();
MethodSubject methodBSubject = getMethodSubject(application, signatureB);
- IRCode codeB = methodBSubject.buildIR(options.itemFactory);
+ IRCode codeB = methodBSubject.buildIR();
return buildTestApplication(
application, options, methodSubject, ImmutableList.of(codeA, codeB));
@@ -761,13 +779,13 @@
List<IRCode> additionalCode = new ArrayList<>();
for (int i = 0; i < 3; i++) {
MethodSubject methodASubject = getMethodSubject(application, signatureA);
- IRCode codeA = methodASubject.buildIR(options.itemFactory);
+ IRCode codeA = methodASubject.buildIR();
additionalCode.add(codeA);
}
for (int i = 0; i < 3; i++) {
MethodSubject methodBSubject = getMethodSubject(application, signatureB);
- IRCode codeB = methodBSubject.buildIR(options.itemFactory);
+ IRCode codeB = methodBSubject.buildIR();
additionalCode.add(codeB);
}
@@ -917,13 +935,13 @@
List<IRCode> additionalCode = new ArrayList<>();
for (int i = 0; i < 3; i++) {
MethodSubject methodASubject = getMethodSubject(application, signatureA);
- IRCode codeA = methodASubject.buildIR(options.itemFactory);
+ IRCode codeA = methodASubject.buildIR();
additionalCode.add(codeA);
}
for (int i = 0; i < 3; i++) {
MethodSubject methodBSubject = getMethodSubject(application, signatureB);
- IRCode codeB = methodBSubject.buildIR(options.itemFactory);
+ IRCode codeB = methodBSubject.buildIR();
additionalCode.add(codeB);
}
@@ -1160,10 +1178,10 @@
MethodSubject methodSubject = getMethodSubject(application, signature);
MethodSubject methodASubject = getMethodSubject(application, signatureA);
- IRCode codeA = methodASubject.buildIR(options.itemFactory);
+ IRCode codeA = methodASubject.buildIR();
MethodSubject methodBSubject = getMethodSubject(application, signatureB);
- IRCode codeB = methodBSubject.buildIR(options.itemFactory);
+ IRCode codeB = methodBSubject.buildIR();
return buildTestApplication(
application, options, methodSubject, ImmutableList.of(codeA, codeB));
diff --git a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
index e9d9abd..83f64ee 100644
--- a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.ValueNumberGenerator;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.smali.SmaliBuilder;
import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
@@ -34,22 +33,12 @@
protected DexApplication buildApplication(SmaliBuilder builder, InternalOptions options) {
try {
- return buildApplication(
- AndroidApp.builder().addDexProgramData(builder.compile(), Origin.unknown()).build(),
- options);
+ return new ApplicationReader(builder.build(), options, Timing.empty()).read();
} catch (IOException | RecognitionException | ExecutionException e) {
throw new RuntimeException(e);
}
}
- protected DexApplication buildApplication(AndroidApp input, InternalOptions options) {
- try {
- return new ApplicationReader(input, options, Timing.empty()).read();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
protected MethodSubject getMethodSubject(DexApplication application, MethodSignature signature) {
return getMethodSubject(
application,
@@ -89,7 +78,7 @@
this.application = appView.appInfo().app();
this.appView = appView;
this.method = method.getMethod();
- this.code = method.buildIR(appView.dexItemFactory());
+ this.code = method.buildIR();
this.additionalCode = additionalCode;
this.consumers = new AndroidAppConsumers(appView.options());
}
diff --git a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
index 7104c9a..1662269 100644
--- a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
+++ b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
@@ -8,9 +8,10 @@
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.Add;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -23,16 +24,28 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.smali.SmaliBuilder;
import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class SplitBlockTest extends IrInjectionTestBase {
- private TestApplication codeWithoutCatchHandlers() {
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public SplitBlockTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
+ private TestApplication codeWithoutCatchHandlers() throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String returnType = "int";
@@ -59,12 +72,10 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
- DexApplication application = buildApplication(builder, options);
- AppView<?> appView = AppView.createForD8(new AppInfo(application), options);
+ AppView<AppInfo> appView = computeAppView(builder.build());
// Return the processed method for inspection.
- MethodSubject methodSubject = getMethodSubject(application, signature);
+ MethodSubject methodSubject = getMethodSubject(appView.appInfo().app(), signature);
return new TestApplication(appView, methodSubject);
}
@@ -137,7 +148,8 @@
}
}
- private TestApplication codeWithCatchHandlers(boolean shouldThrow, boolean twoGuards) {
+ private TestApplication codeWithCatchHandlers(boolean shouldThrow, boolean twoGuards)
+ throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String secondGuard = twoGuards ?
@@ -175,12 +187,10 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
- DexApplication application = buildApplication(builder, options);
- AppView<?> appView = AppView.createForD8(new AppInfo(application), options);
+ AppView<?> appView = computeAppView(builder.build());
// Return the processed method for inspection.
- MethodSubject methodSubject = getMethodSubject(application, signature);
+ MethodSubject methodSubject = getMethodSubject(appView.appInfo().app(), signature);
return new TestApplication(appView, methodSubject);
}
@@ -270,7 +280,7 @@
runCatchHandlerSplitThreeTest(true, true);
}
- private TestApplication codeWithIf(boolean hitTrueBranch) {
+ private TestApplication codeWithIf(boolean hitTrueBranch) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String returnType = "int";
@@ -299,12 +309,10 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
- DexApplication application = buildApplication(builder, options);
- AppView<?> appView = AppView.createForD8(new AppInfo(application), options);
+ AppView<?> appView = computeAppView(builder.build());
// Return the processed method for inspection.
- MethodSubject methodSubject = getMethodSubject(application, signature);
+ MethodSubject methodSubject = getMethodSubject(appView.appInfo().app(), signature);
return new TestApplication(appView, methodSubject);
}
@@ -385,7 +393,7 @@
splitBeforeReturn(true);
}
- private TestApplication codeWithSwitch(boolean hitCase) {
+ private TestApplication codeWithSwitch(boolean hitCase) throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
String returnType = "int";
@@ -422,12 +430,10 @@
" return-void"
);
- InternalOptions options = new InternalOptions();
- DexApplication application = buildApplication(builder, options);
- AppView<?> appView = AppView.createForD8(new AppInfo(application), options);
+ AppView<?> appView = computeAppView(builder.build());
// Return the processed method for inspection.
- MethodSubject methodSubject = getMethodSubject(application, signature);
+ MethodSubject methodSubject = getMethodSubject(appView.appInfo().app(), signature);
return new TestApplication(appView, methodSubject);
}
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java b/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
index 80fef97..ce5cbce 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
@@ -64,7 +64,7 @@
public void buildAndCheckIR(String methodName, Consumer<IRCode> irInspector) {
CodeInspector inspector = new CodeInspector(appView.appInfo().app());
MethodSubject methodSubject = inspector.clazz(className).uniqueMethodWithName(methodName);
- irInspector.accept(methodSubject.buildIR(appView.dexItemFactory()));
+ irInspector.accept(methodSubject.buildIR());
}
@SuppressWarnings("unchecked")
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
index 5a53fb5..86f4e3d 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
@@ -134,7 +134,7 @@
timing)
.read()
.toDirect();
- return AppView.createForR8(new AppInfoWithClassHierarchy(application), options);
+ return AppView.createForR8(new AppInfoWithClassHierarchy(application));
}
private DexEncodedField uniqueFieldByName(DexProgramClass clazz, String name) {
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
index 06f2813..a4c9785 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
@@ -11,6 +11,8 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
@@ -39,8 +41,22 @@
import java.util.Map;
import java.util.function.BiConsumer;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class NullabilityTest extends NonNullTrackerTestBase {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public NullabilityTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
private void buildAndTest(
Class<?> mainClass,
MethodSignature signature,
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
index d0cf699..40c87b6 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
@@ -11,10 +11,8 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.ArrayLength;
import com.android.tools.r8.ir.code.CheckCast;
@@ -32,9 +30,7 @@
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.smali.SmaliTestBase;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Smali;
-import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
@@ -57,7 +53,6 @@
@RunWith(Parameterized.class)
public class TypeAnalysisTest extends SmaliTestBase {
- private static final InternalOptions TEST_OPTIONS = new InternalOptions();
private static final TypeElement NULL = TypeElement.getNull();
private static final TypeElement SINGLE = TypeElement.getSingle();
private static final TypeElement INT = TypeElement.getInt();
@@ -112,11 +107,8 @@
.forEach(s -> smaliStringBuilder.append(s).append(System.lineSeparator()));
byte[] content = Smali.compile(smaliStringBuilder.toString());
AndroidApp app = AndroidApp.builder().addDexProgramData(content, Origin.unknown()).build();
- DexApplication dexApplication =
- new ApplicationReader(app, TEST_OPTIONS, Timing.empty()).read().toDirect();
- inspection.accept(
- AppView.createForD8(new AppInfo(dexApplication), TEST_OPTIONS),
- new CodeInspector(dexApplication));
+ AppView<AppInfo> appView = computeAppView(app);
+ inspection.accept(appView, new CodeInspector(appView.appInfo().app()));
}
private static void forEachOutValue(IRCode irCode, BiConsumer<Value, TypeElement> consumer) {
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
index cfe27c9..06de00a 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeLatticeTest.java
@@ -60,7 +60,7 @@
.read()
.toDirect();
factory = options.itemFactory;
- appView = AppView.createForR8(new AppInfoWithClassHierarchy(application), options);
+ appView = AppView.createForR8(new AppInfoWithClassHierarchy(application));
}
private TopTypeElement top() {
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java b/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
index c838a0d..41c5ef5 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
@@ -45,7 +45,7 @@
parser.parse(
createConfigurationForTesting(
ImmutableList.of("-keep class ** { void m1(); void m5(); }")));
- return parser.getConfig().getRules();
+ return parser.getConfig();
});
this.options = appView.options();
this.executorService = ThreadUtils.getExecutorService(options);
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/StringSwitchConversionFromIfTest.java b/src/test/java/com/android/tools/r8/ir/conversion/StringSwitchConversionFromIfTest.java
index 2a700c3..294efee 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/StringSwitchConversionFromIfTest.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/StringSwitchConversionFromIfTest.java
@@ -17,8 +17,6 @@
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
@@ -75,15 +73,12 @@
for (String methodName : methodNames) {
MethodSubject methodSubject = classSubject.uniqueMethodWithName(methodName);
assertThat(methodSubject, isPresent());
-
- DexItemFactory dexItemFactory = new DexItemFactory();
- InternalOptions options = new InternalOptions(dexItemFactory, new Reporter());
- options.enableStringSwitchConversion = enableStringSwitchConversion;
-
- IRCode code = methodSubject.buildIR(options);
+ IRCode code = methodSubject.buildIR();
List<Value> hashCodeValues =
Streams.stream(code.instructions())
- .filter(instruction -> isInvokeStringHashCode(instruction, dexItemFactory))
+ .filter(
+ instruction ->
+ isInvokeStringHashCode(instruction, inspector.getFactory()))
.map(Instruction::asInvokeVirtual)
.map(Instruction::outValue)
.collect(Collectors.toList());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
index fa6597f..dc6bc19 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
@@ -134,7 +134,7 @@
InternalOptions options = new InternalOptions();
options.debug = true;
AppInfo appInfo = new AppInfo(DexApplication.builder(options, null).build());
- AppView<?> appView = AppView.createForD8(appInfo, options);
+ AppView<?> appView = AppView.createForD8(appInfo);
IRCode code =
new IRCode(
options,
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
index a9f77ce..daa21f4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
@@ -7,6 +7,8 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.code.IRCode;
@@ -25,9 +27,22 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.util.function.Consumer;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class NonNullTrackerTest extends NonNullTrackerTestBase {
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public NonNullTrackerTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
private void buildAndTest(
Class<?> testClass,
MethodSignature signature,
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
index 4820221..6b5f0cb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
@@ -5,27 +5,13 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppServices;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Timing;
public abstract class NonNullTrackerTestBase extends TestBase {
protected AppView<? extends AppInfoWithClassHierarchy> build(Class<?> mainClass)
throws Exception {
- Timing timing = Timing.empty();
- AndroidApp app = buildAndroidApp(ToolHelper.getClassAsBytes(mainClass));
- InternalOptions options = new InternalOptions();
- DirectMappedDexApplication dexApplication =
- new ApplicationReader(app, options, timing).read().toDirect();
- AppView<? extends AppInfoWithClassHierarchy> appView =
- AppView.createForR8(new AppInfoWithClassHierarchy(dexApplication), options);
- appView.setAppServices(AppServices.builder(appView).build());
- return appView;
+ return computeAppViewWithSubtyping(buildAndroidApp(ToolHelper.getClassAsBytes(mainClass)));
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
index 95557b6..7d7785f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
@@ -6,9 +6,11 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.Argument;
@@ -26,13 +28,26 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueNumberGenerator;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
import java.util.LinkedList;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
-public class TrivialGotoEliminationTest {
+@RunWith(Parameterized.class)
+public class TrivialGotoEliminationTest extends TestBase {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public TrivialGotoEliminationTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
private final IRMetadata metadata = IRMetadata.unknown();
@@ -92,10 +107,9 @@
}
@Test
- public void trivialGotoLoopAsFallthrough() {
- InternalOptions options = new InternalOptions();
- DexApplication app = DexApplication.builder(new InternalOptions(), Timing.empty()).build();
- AppView<AppInfo> appView = AppView.createForD8(new AppInfo(app), options);
+ public void trivialGotoLoopAsFallthrough() throws Exception {
+ AppView<AppInfo> appView = computeAppView(AndroidApp.builder().build());
+ InternalOptions options = appView.options();
// Setup block structure:
// block0:
// v0 <- argument
@@ -135,7 +149,7 @@
new Value(
0,
TypeElement.fromDexType(
- app.dexItemFactory.throwableType, Nullability.definitelyNotNull(), appView),
+ options.itemFactory.throwableType, Nullability.definitelyNotNull(), appView),
null);
instruction = new Argument(value, 0, false);
instruction.setPosition(position);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionMappingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionMappingTest.java
new file mode 100644
index 0000000..5e7a17d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionMappingTest.java
@@ -0,0 +1,101 @@
+// Copyright (c) 2020, 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.unusedarguments;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class UnusedArgumentsCollisionMappingTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public UnusedArgumentsCollisionMappingTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ R8TestRunResult runResult =
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .enableInliningAnnotations()
+ .addKeepAttributeLineNumberTable()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("test with unused", "test with used: foo")
+ .inspect(this::verifyArgumentsRemoved);
+ // TODO(b/140851070): Duplicate entries for different methods.
+ assertEquals(
+ 2,
+ StringUtils.splitLines(runResult.proguardMap()).stream()
+ .filter(line -> line.contains("void test(java.lang.String,java.lang.String)"))
+ .count());
+ assertEquals(
+ 0,
+ StringUtils.splitLines(runResult.proguardMap()).stream()
+ .filter(line -> line.contains("void test(java.lang.String)"))
+ .count());
+ }
+
+ private void verifyArgumentsRemoved(CodeInspector inspector) {
+ ClassSubject main = inspector.clazz(Main.class);
+ assertThat(main, isPresent());
+ List<FoundMethodSubject> foundMethodSubjects = main.allMethods();
+ assertEquals(3, foundMethodSubjects.size());
+ boolean foundZeroArgumentMethod = false;
+ boolean foundOneArgumentMethod = false;
+ for (FoundMethodSubject method : foundMethodSubjects) {
+ if (method.getFinalName().equals("main")) {
+ continue;
+ }
+ foundZeroArgumentMethod |= method.getMethod().parameters().size() == 0;
+ foundOneArgumentMethod |= method.getMethod().parameters().size() == 1;
+ }
+ assertTrue(foundZeroArgumentMethod);
+ assertTrue(foundOneArgumentMethod);
+ }
+
+ public static class Main {
+
+ @NeverInline
+ public static void test(String unused) {
+ System.out.println("test with unused");
+ }
+
+ @NeverInline
+ public static void test(String used, String unused) {
+ System.out.println("test with used: " + used);
+ }
+
+ public static void main(String[] args) {
+ test("foo");
+ test("foo", "notused");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index b4d2c3a..3c202dd 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -367,7 +367,7 @@
public void multipleLiveTempRegisters() {
InternalOptions options = new InternalOptions();
AppView<AppInfo> appInfo =
- AppView.createForD8(new AppInfo(DexApplication.builder(options, null).build()), options);
+ AppView.createForD8(new AppInfo(DexApplication.builder(options, null).build()));
TypeElement objectType =
TypeElement.fromDexType(options.itemFactory.objectType, Nullability.maybeNull(), appInfo);
CollectMovesIterator moves = new CollectMovesIterator();
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java b/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
index 2c1d228..e246335 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
@@ -57,7 +57,7 @@
public void splitOverlappingInactiveIntervalWithNoNextUse() {
InternalOptions options = new InternalOptions();
AppInfo appInfo = new AppInfo(DexApplication.builder(options, null).build());
- AppView<?> appView = AppView.createForD8(appInfo, options);
+ AppView<?> appView = AppView.createForD8(appInfo);
IRCode code = simpleCode();
MyRegisterAllocator allocator = new MyRegisterAllocator(appView, code);
// Setup live an inactive live interval with ranges [0, 10[ and [20, 30[ with only
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 26186aa..b3cbe0e 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -809,7 +809,7 @@
options.intermediate = intermediate;
DexItemFactory factory = options.itemFactory;
AppInfo appInfo = new AppInfo(DexApplication.builder(options, timing).build());
- AppView<?> appView = AppView.createForR8(appInfo, options);
+ AppView<?> appView = AppView.createForR8(appInfo);
DexApplication.Builder<?> builder = DexApplication.builder(options, timing);
for (String clazz : classes) {
DexString desc = factory.createString(DescriptorUtils.javaTypeToDescriptor(clazz));
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierTest.java b/src/test/java/com/android/tools/r8/naming/MinifierTest.java
index 1baffde..ebc3ad7 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierTest.java
@@ -36,7 +36,7 @@
@Test
public void minifierTest() throws Exception {
NamingLens naming = runMinifier(ListUtils.map(keepRulesFiles, Paths::get));
- inspection.accept(dexItemFactory, naming);
+ inspection.accept(naming);
}
@Parameters(name = "test: {0} keep: {1}")
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 385911c..e461666 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -3,83 +3,55 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
-import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppServices;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.shaking.Enqueuer;
-import com.android.tools.r8.shaking.EnqueuerFactory;
-import com.android.tools.r8.shaking.ProguardConfiguration;
-import com.android.tools.r8.shaking.RootSetBuilder;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Reporter;
-import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
import java.io.File;
-import java.io.IOException;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.function.BiConsumer;
-import org.junit.Before;
+import java.util.function.Consumer;
-public abstract class NamingTestBase {
+public abstract class NamingTestBase extends TestBase {
private final String appFileName;
protected final List<String> keepRulesFiles;
- protected final BiConsumer<DexItemFactory, NamingLens> inspection;
+ protected final Consumer<NamingLens> inspection;
- private final Timing timing;
-
- private DirectMappedDexApplication program;
- protected DexItemFactory dexItemFactory;
+ private DexItemFactory dexItemFactory = null;
protected NamingTestBase(
String test, List<String> keepRulesFiles, BiConsumer<DexItemFactory, NamingLens> inspection) {
appFileName = ToolHelper.EXAMPLES_BUILD_DIR + test + "/classes.dex";
this.keepRulesFiles = keepRulesFiles;
- this.inspection = inspection;
- this.timing = Timing.empty();
+ this.inspection = lens -> inspection.accept(dexItemFactory, lens);
}
- @Before
- public void readApp() throws IOException, ExecutionException {
- program = ToolHelper.buildApplication(ImmutableList.of(appFileName));
- dexItemFactory = program.dexItemFactory;
- }
-
- protected NamingLens runMinifier(List<Path> configPaths) throws ExecutionException {
- ProguardConfiguration configuration =
- ToolHelper.loadProguardConfiguration(dexItemFactory, configPaths);
-
- InternalOptions options = new InternalOptions(configuration, new Reporter());
- options.programConsumer = DexIndexedConsumer.emptyConsumer();
-
- ExecutorService executor = ThreadUtils.getExecutorService(1);
-
- AppView<AppInfoWithClassHierarchy> appView =
- AppView.createForR8(new AppInfoWithClassHierarchy(program), options);
- SubtypingInfo subtypingInfo = new SubtypingInfo(program.allClasses(), program);
- appView.setRootSet(
- new RootSetBuilder(appView, subtypingInfo, configuration.getRules()).run(executor));
- appView.setAppServices(AppServices.builder(appView).build());
-
- Enqueuer enqueuer = EnqueuerFactory.createForInitialTreeShaking(appView, subtypingInfo);
- appView.setAppInfo(
- enqueuer.traceApplication(
- appView.rootSet(), configuration.getDontWarnPatterns(), executor, timing));
- return new Minifier(appView.withLiveness()).run(executor, timing);
+ protected NamingLens runMinifier(List<Path> configPaths) throws Exception {
+ AppView<AppInfoWithLiveness> appView =
+ computeAppViewWithLiveness(
+ AndroidApp.builder().addProgramFile(Paths.get(appFileName)).build(),
+ factory -> ToolHelper.loadProguardConfiguration(factory, configPaths));
+ dexItemFactory = appView.dexItemFactory();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ try {
+ return new Minifier(appView).run(executor, Timing.empty());
+ } finally {
+ executor.shutdown();
+ }
}
protected static <T> Collection<Object[]> createTests(
diff --git a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
index 549b0e1..caa1ae9 100644
--- a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
@@ -44,7 +44,7 @@
@Test
public void packageNamingTest() throws Exception {
NamingLens naming = runMinifier(ListUtils.map(keepRulesFiles, Paths::get));
- inspection.accept(dexItemFactory, naming);
+ inspection.accept(naming);
}
private static final List<String> CLASSES_IN_NAMING044 = ImmutableList.of(
diff --git a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
index abd4956..4e19a05 100644
--- a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
@@ -24,7 +24,6 @@
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.Sets;
-import java.util.ArrayList;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,7 +47,8 @@
AppView<AppInfoWithLiveness> appView =
computeAppViewWithLiveness(
buildClasses(A.class, B.class, Main.class).build(),
- factory -> new ArrayList<>(buildKeepRuleForClassAndMethods(Main.class, factory)));
+ factory ->
+ buildConfigForRules(factory, buildKeepRuleForClassAndMethods(Main.class, factory)));
AppInfoWithLiveness appInfo = appView.appInfo();
DexType typeA = buildType(A.class, appInfo.dexItemFactory());
DexType typeB = buildType(B.class, appInfo.dexItemFactory());
@@ -72,7 +72,8 @@
AppView<AppInfoWithLiveness> appView =
computeAppViewWithLiveness(
buildClasses(A.class, B.class, C.class, Main.class).build(),
- factory -> new ArrayList<>(buildKeepRuleForClassAndMethods(Main.class, factory)));
+ factory ->
+ buildConfigForRules(factory, buildKeepRuleForClassAndMethods(Main.class, factory)));
AppInfoWithLiveness appInfo = appView.appInfo();
DexType typeA = buildType(A.class, appInfo.dexItemFactory());
DexType typeB = buildType(B.class, appInfo.dexItemFactory());
@@ -97,8 +98,8 @@
computeAppViewWithLiveness(
buildClasses(A.class, B.class, C.class, MainAllInstantiated.class).build(),
factory ->
- new ArrayList<>(
- buildKeepRuleForClassAndMethods(MainAllInstantiated.class, factory)));
+ buildConfigForRules(
+ factory, buildKeepRuleForClassAndMethods(MainAllInstantiated.class, factory)));
AppInfoWithLiveness appInfo = appView.appInfo();
DexType typeA = buildType(A.class, appInfo.dexItemFactory());
DexType typeC = buildType(C.class, appInfo.dexItemFactory());
diff --git a/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java b/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java
index 9489060..593670d 100644
--- a/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import java.util.ArrayList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -40,7 +39,8 @@
AppView<AppInfoWithLiveness> appView =
computeAppViewWithLiveness(
buildClasses(I.class, A.class, Main.class).build(),
- factory -> new ArrayList<>(buildKeepRuleForClassAndMethods(Main.class, factory)));
+ factory ->
+ buildConfigForRules(factory, buildKeepRuleForClassAndMethods(Main.class, factory)));
AppInfoWithLiveness appInfo = appView.appInfo();
DexType typeMain = buildType(Main.class, appInfo.dexItemFactory());
DexMethod mainMethodReference =
@@ -63,7 +63,8 @@
AppView<AppInfoWithLiveness> appView =
computeAppViewWithLiveness(
buildClasses(I.class, A.class, Main.class).build(),
- factory -> new ArrayList<>(buildKeepRuleForClassAndMethods(Main.class, factory)));
+ factory ->
+ buildConfigForRules(factory, buildKeepRuleForClassAndMethods(Main.class, factory)));
AppInfoWithLiveness appInfo = appView.appInfo();
DexType typeMain = buildType(Main.class, appInfo.dexItemFactory());
DexMethod mainMethodReference =
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
index 745ff4b..4332d86 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
@@ -82,7 +82,7 @@
rules.addAll(buildKeepRuleForClassAndMethods(methodToBeKept, factory));
rules.addAll(buildKeepRuleForClass(classToBeKept, factory));
rules.addAll(buildKeepRuleForClassAndMethods(main, factory));
- return rules;
+ return buildConfigForRules(factory, rules);
});
AppInfoWithLiveness appInfo = appView.appInfo();
DexMethod method = buildNullaryVoidMethod(initial, "foo", appInfo.dexItemFactory());
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
index e8494d6..ec3fcc1 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
@@ -15,12 +15,14 @@
import com.android.tools.r8.retrace.stacktraces.ActualRetraceBotStackTraceWithInfo;
import com.android.tools.r8.retrace.stacktraces.FoundMethodVerboseStackTrace;
import com.android.tools.r8.utils.StringUtils;
+import com.google.common.base.Charsets;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -38,6 +40,8 @@
@Rule public TemporaryFolder folder = new TemporaryFolder();
+ private static String SMILEY_EMOJI = "\uD83D\uDE00";
+
@Test
public void testPrintIdentityStackTraceFile() throws IOException {
runTest("", nonMappableStackTrace, false, nonMappableStackTrace);
@@ -125,6 +129,16 @@
assertEquals(Retrace.USAGE_MESSAGE, processResult.stdout);
}
+ @Test
+ public void testNonAscii() throws IOException {
+ runTest("", SMILEY_EMOJI, false, SMILEY_EMOJI + StringUtils.LINE_SEPARATOR);
+ }
+
+ @Test
+ public void testNonAsciiStdIn() throws IOException {
+ runTest("", SMILEY_EMOJI, true, SMILEY_EMOJI + StringUtils.LINE_SEPARATOR);
+ }
+
private final String nonMappableStackTrace =
StringUtils.lines(
"com.android.r8.R8Exception: Problem when compiling program",
@@ -164,7 +178,7 @@
Path mappingFile = folder.newFile("mapping.txt").toPath();
Files.write(mappingFile, mapping.getBytes());
File stackTraceFile = folder.newFile("stacktrace.txt");
- Files.write(stackTraceFile.toPath(), stackTrace.getBytes());
+ Files.write(stackTraceFile.toPath(), stackTrace.getBytes(StandardCharsets.UTF_8));
Collection<String> args = new ArrayList<>();
args.add(mappingFile.toString());
@@ -216,8 +230,8 @@
System.setErr(originalErr);
return new ProcessResult(
exitCode,
- outputByteStream.toString(),
- errorByteStream.toString(),
+ outputByteStream.toString(Charsets.UTF_8.name()),
+ errorByteStream.toString(Charsets.UTF_8.name()),
StringUtils.joinLines(args));
}
}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java
index bb69fc3..d8768a2 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.retrace;
+import static com.android.tools.r8.retrace.Retrace.DEFAULT_REGULAR_EXPRESSION;
import static junit.framework.TestCase.assertEquals;
import com.android.tools.r8.TestBase;
@@ -11,6 +12,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.retrace.stacktraces.InlineFileNameStackTrace;
+import com.android.tools.r8.retrace.stacktraces.RetraceAssertionErrorStackTrace;
import com.android.tools.r8.retrace.stacktraces.StackTraceForTest;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
@@ -24,9 +26,6 @@
@RunWith(Parameterized.class)
public class RetraceRegularExpressionTests extends TestBase {
- private static final String DEFAULT_REGULAR_EXPRESSION =
- "(?:.*?\\bat\\s+%c\\.%m\\s*\\(%s(?::%l)?\\)\\s*(?:~\\[.*\\])?)|(?:(?:.*?[:\"]\\s+)?%c(?::.*)?)";
-
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withNoneRuntime().build();
@@ -731,6 +730,41 @@
});
}
+ @Test
+ public void testSourceFileLineNumber() {
+ runRetraceTest(
+ DEFAULT_REGULAR_EXPRESSION.replace("%s(?::%l)?", "%S"),
+ new RetraceAssertionErrorStackTrace());
+ }
+
+ @Test
+ public void testEscaping() {
+ runRetraceTest(
+ "\\%c\\\\%c\\\\\\%c.%m\\(\\\\%S\\)\\\\\\%S",
+ new StackTraceForTest() {
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return ImmutableList.of("%c\\com.android.tools.r8.Foo\\%c.a(\\SourceFile:1)\\%S");
+ }
+
+ @Override
+ public String mapping() {
+ return "com.android.tools.r8.Bar -> com.android.tools.r8.Foo:\n"
+ + " 1:1:void m():13:13 -> a";
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return ImmutableList.of("%c\\com.android.tools.r8.Bar\\%c.m(\\Bar.java:13)\\%S");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+ });
+ }
+
private TestDiagnosticMessagesImpl runRetraceTest(
String regularExpression, StackTraceForTest stackTraceForTest) {
TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
diff --git a/src/test/java/com/android/tools/r8/shaking/LibraryClassExtendingProgramClassSuperTest.java b/src/test/java/com/android/tools/r8/shaking/LibraryClassExtendingProgramClassSuperTest.java
new file mode 100644
index 0000000..584d3ae
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/LibraryClassExtendingProgramClassSuperTest.java
@@ -0,0 +1,139 @@
+// Copyright (c) 2020, 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.shaking;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThrows;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class LibraryClassExtendingProgramClassSuperTest extends TestBase {
+
+ private final TestParameters parameters;
+ private final boolean proguardCompatibility;
+ private final boolean dontWarn;
+ private final String EXPECTED = ProgramIndirectSuper.class.getTypeName();
+
+ @Parameters(name = "{0}, proguardcompatiblity: {1}, dontwarn: {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ public LibraryClassExtendingProgramClassSuperTest(
+ TestParameters parameters, boolean proguardCompatibility, boolean dontWarn) {
+ this.parameters = parameters;
+ this.proguardCompatibility = proguardCompatibility;
+ this.dontWarn = dontWarn;
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(Main.class, ProgramDirectSuper.class, ProgramIndirectSuper.class)
+ .addRunClasspathFiles(
+ compileToZip(
+ parameters,
+ ImmutableList.of(ProgramDirectSuper.class, ProgramIndirectSuper.class),
+ LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ R8TestBuilder<? extends R8TestBuilder<?>> r8TestBuilder =
+ (proguardCompatibility
+ ? testForR8Compat(parameters.getBackend(), true)
+ : testForR8(parameters.getBackend()))
+ .addLibraryFiles(
+ parameters.isCfRuntime()
+ ? ToolHelper.getJava8RuntimeJar()
+ : ToolHelper.getAndroidJar(parameters.getApiLevel()))
+ .addLibraryClasses(LibraryClass.class)
+ .addProgramClasses(ProgramDirectSuper.class, ProgramIndirectSuper.class, Main.class)
+ .addKeepMainRule(Main.class)
+ .applyIf(dontWarn, b -> b.addKeepRules("-dontwarn " + LibraryClass.class.getTypeName()))
+ .setMinApi(parameters.getApiLevel())
+ .addRunClasspathFiles(
+ compileToZip(
+ parameters,
+ ImmutableList.of(ProgramIndirectSuper.class, ProgramDirectSuper.class),
+ LibraryClass.class));
+ if (proguardCompatibility && dontWarn) {
+ r8TestBuilder.run(parameters.getRuntime(), Main.class).assertSuccessWithOutputLines(EXPECTED);
+ } else if (proguardCompatibility) {
+ r8TestBuilder
+ .allowDiagnosticWarningMessages()
+ .compile()
+ .assertAllWarningMessagesMatch(
+ containsString(
+ LibraryClass.class.getTypeName()
+ + " extends program class "
+ + ProgramDirectSuper.class.getTypeName()))
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(ProgramIndirectSuper.class.getTypeName());
+ } else if (dontWarn) {
+ // TODO(b/159609181): This fails with an assertion error, should we not handle it the same as
+ // proguardcompat?
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ r8TestBuilder.compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics.assertErrorsMatch(
+ diagnosticMessage(
+ containsString(
+ "Failed lookup of non-missing type: "
+ + ProgramDirectSuper.class.getTypeName())))));
+ } else {
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ r8TestBuilder.compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertErrorsMatch(
+ diagnosticMessage(
+ containsString(
+ LibraryClass.class.getTypeName()
+ + " extends program class "
+ + ProgramDirectSuper.class.getTypeName())));
+ }));
+ }
+ }
+
+ public static class ProgramIndirectSuper {}
+
+ public static class ProgramDirectSuper extends ProgramIndirectSuper {}
+
+ public static class LibraryClass extends ProgramDirectSuper {
+
+ void foo() {
+ System.out.println(this.getClass().getSuperclass().getSuperclass().getName());
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ new LibraryClass().foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepInterfaceMethodTest.java
index 550957e..e6baeae 100644
--- a/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepInterfaceMethodTest.java
@@ -40,6 +40,7 @@
@Test
public void testIProguard() throws CompilationFailedException, IOException, ExecutionException {
testForProguard()
+ // TODO(b/159694276): Run the resulting code on runtime.
.addProgramClasses(I.class)
.addKeepRules(
"-keepclassmembers class " + I.class.getTypeName() + " { void foo(); }",
@@ -51,6 +52,7 @@
@Test
public void testIR8() throws CompilationFailedException, IOException, ExecutionException {
+ // TODO(b/159694276): Add compat variant of this.
testForR8(parameters.getBackend())
.addProgramClasses(I.class)
.addKeepRules("-keepclassmembers class " + I.class.getTypeName() + " { void foo(); }")
@@ -75,6 +77,7 @@
@Test
public void testAR8() throws CompilationFailedException, IOException, ExecutionException {
+ // TODO(b/159694276): Add non-compat variant of this.
testForR8Compat(parameters.getBackend())
.addProgramClasses(I.class, A.class, B.class, Main.class)
.addKeepRules("-keepclassmembers class " + I.class.getTypeName() + " { void foo(); }")
diff --git a/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
index 17cce81..f4884c3 100644
--- a/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
+++ b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
@@ -79,7 +79,7 @@
ProgramMethod method = getProgramMethod(originalApplication, methodSig);
// Get the IR pre-optimization.
- IRCode code = method.buildIR(AppView.createForD8(new AppInfo(application), options));
+ IRCode code = method.buildIR(AppView.createForD8(new AppInfo(application)));
// Find the exit block and assert that the value is a phi merging the exceptional edge
// with the normal edge.
diff --git a/src/test/java/com/android/tools/r8/utils/SemanticVersionTests.java b/src/test/java/com/android/tools/r8/utils/SemanticVersionTests.java
new file mode 100644
index 0000000..8f0dd61
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/SemanticVersionTests.java
@@ -0,0 +1,48 @@
+// Copyright (c) 2020, 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.utils;
+
+import static com.android.tools.r8.utils.SemanticVersion.parse;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.NoneRuntime;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class SemanticVersionTests extends TestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public SemanticVersionTests(TestParameters parameters) {
+ assertEquals(NoneRuntime.getInstance(), parameters.getRuntime());
+ }
+
+ @Test
+ public void test() throws Exception {
+ assertTrue(parse("1.0.1").isNewerOrEqual(parse("1.0.0")));
+ assertFalse(parse("1.0.1").isNewerOrEqual(parse("1.1.0")));
+ assertTrue(parse("1.1.0").isNewerOrEqual(parse("1.0.1")));
+ assertFalse(parse("1.1.1").isNewerOrEqual(parse("2.0.0")));
+
+ assertTrue(parse("2.0.0").isNewerOrEqual(parse("1.1.1")));
+ assertTrue(parse("42.42.42").isNewerOrEqual(parse("9.9.9")));
+ assertTrue(parse("9.42.42").isNewerOrEqual(parse("9.9.9")));
+ assertTrue(parse("9.9.42").isNewerOrEqual(parse("9.9.9")));
+
+ assertFalse(parse("1.1.1").isNewerOrEqual(parse("2.0.0")));
+ assertFalse(parse("9.9.9").isNewerOrEqual(parse("42.42.42")));
+ assertFalse(parse("9.9.9").isNewerOrEqual(parse("9.42.42")));
+ assertFalse(parse("9.9.9").isNewerOrEqual(parse("9.9.42")));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
index ed7ac4d..38dc236 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -10,12 +10,11 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.android.tools.r8.utils.InternalOptions;
public class AbsentMethodSubject extends MethodSubject {
@Override
- public IRCode buildIR(InternalOptions options) {
+ public IRCode buildIR() {
throw new Unreachable("Cannot build IR for an absent method");
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index f43c01c..76ed0e2 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -5,6 +5,7 @@
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfTryCatch;
@@ -126,6 +127,10 @@
if (optionsConsumer != null) {
optionsConsumer.accept(internalOptions);
}
+ if (internalOptions.programConsumer == null) {
+ // The inspector allows building IR for a method. An output type must be defined for that.
+ internalOptions.programConsumer = DexIndexedConsumer.emptyConsumer();
+ }
return internalOptions;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 0e504ca..1f1fe84 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.utils.codeinspector;
-import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfPosition;
import com.android.tools.r8.code.Instruction;
@@ -32,7 +31,6 @@
import com.android.tools.r8.naming.signature.GenericSignatureParser;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.LocalVariableTable.LocalVariableTableEntry;
import com.google.common.base.Predicates;
@@ -58,10 +56,9 @@
}
@Override
- public IRCode buildIR(InternalOptions options) {
- options.programConsumer = DexIndexedConsumer.emptyConsumer();
- return getProgramMethod()
- .buildIR(AppView.createForD8(new AppInfo(codeInspector.application), options));
+ public IRCode buildIR() {
+ assert codeInspector.application.options.programConsumer != null;
+ return getProgramMethod().buildIR(AppView.createForD8(new AppInfo(codeInspector.application)));
}
@Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index 72b71b0..8fc439f 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -5,12 +5,9 @@
package com.android.tools.r8.utils.codeinspector;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Reporter;
import com.google.common.collect.Streams;
import java.util.Iterator;
import java.util.function.Predicate;
@@ -18,15 +15,7 @@
public abstract class MethodSubject extends MemberSubject {
- public final IRCode buildIR() {
- return buildIR(new DexItemFactory());
- }
-
- public IRCode buildIR(DexItemFactory dexItemFactory) {
- return buildIR(new InternalOptions(dexItemFactory, new Reporter()));
- }
-
- public abstract IRCode buildIR(InternalOptions options);
+ public abstract IRCode buildIR();
public final boolean isAbsent() {
return !isPresent();