Change the API for assertion configuration
* The AssertionConfiguration.Builder only builds one item
* Split the transformation and scope on the the builder API
* For multiple configuration items addAssertionsConfiguration
has to be called multiple times
Bug: 139898386
Change-Id: Ife488d59b856e86ea06240cbd9e13b4507f0bc73
diff --git a/src/main/java/com/android/tools/r8/AssertionsConfiguration.java b/src/main/java/com/android/tools/r8/AssertionsConfiguration.java
index 15acd6f..7199b77 100644
--- a/src/main/java/com/android/tools/r8/AssertionsConfiguration.java
+++ b/src/main/java/com/android/tools/r8/AssertionsConfiguration.java
@@ -4,8 +4,7 @@
package com.android.tools.r8;
-import java.util.ArrayList;
-import java.util.List;
+import com.android.tools.r8.utils.Reporter;
@Keep
public class AssertionsConfiguration {
@@ -24,55 +23,37 @@
PASSTHROUGH
}
- public enum ConfigurationType {
+ public enum AssertionTransformationScope {
ALL,
PACKAGE,
CLASS
}
- public static class ConfigurationEntry {
- private final AssertionTransformation transformation;
- private final ConfigurationType type;
- private final String value;
+ private final AssertionTransformation transformation;
+ private final AssertionTransformationScope scope;
+ private final String value;
- private ConfigurationEntry(
- AssertionTransformation transformation, ConfigurationType type, String value) {
- assert value != null || type == ConfigurationType.ALL;
- this.transformation = transformation;
- this.type = type;
- this.value = value;
- }
-
- public AssertionTransformation getTransformation() {
- return transformation;
- }
-
- public ConfigurationType getType() {
- return type;
- }
-
- public String getValue() {
- return value;
- }
+ AssertionsConfiguration(
+ AssertionTransformation transformation, AssertionTransformationScope scope, String value) {
+ this.transformation = transformation;
+ this.scope = scope;
+ this.value = value;
}
- // Methods which need to be public.
- public static class InternalAssertionConfiguration {
-
- public static List<ConfigurationEntry> getConfiguration(AssertionsConfiguration configuration) {
- return configuration.entries;
- }
+ public AssertionTransformation getTransformation() {
+ return transformation;
}
- private final List<ConfigurationEntry> entries;
-
- private AssertionsConfiguration(List<ConfigurationEntry> entries) {
- this.entries = entries;
+ public AssertionTransformationScope getScope() {
+ return scope;
}
- static AssertionsConfiguration.Builder builder(AssertionsConfiguration previous) {
- return new AssertionsConfiguration.Builder(
- previous != null ? previous.entries : new ArrayList<>());
+ public String getValue() {
+ return value;
+ }
+
+ static AssertionsConfiguration.Builder builder(Reporter reporter) {
+ return new AssertionsConfiguration.Builder(reporter);
}
/**
@@ -83,33 +64,19 @@
*/
@Keep
public static class Builder {
- private final List<ConfigurationEntry> entries;
+ Reporter reporter;
+ private AssertionTransformation transformation;
+ private AssertionTransformationScope scope;
+ private String value;
- private Builder(List<ConfigurationEntry> previousEntries) {
- assert previousEntries != null;
- this.entries = previousEntries;
- }
-
- private void addEntry(
- AssertionTransformation transformation, ConfigurationType type, String value) {
- entries.add(new ConfigurationEntry(transformation, type, value));
+ private Builder(Reporter reporter) {
+ this.reporter = reporter;
}
/** Set how to handle javac generated assertion code. */
public AssertionsConfiguration.Builder setTransformation(
AssertionTransformation transformation) {
- addEntry(transformation, ConfigurationType.ALL, null);
- return this;
- }
-
- AssertionsConfiguration.Builder setDefault(AssertionTransformation transformation) {
- // Add the default by inserting a transform all entry at the beginning of the list, if there
- // isn't already one.
- ConfigurationEntry defaultEntry =
- new ConfigurationEntry(transformation, ConfigurationType.ALL, null);
- if (entries.size() == 0 || entries.get(0).type != ConfigurationType.ALL) {
- entries.listIterator().add(defaultEntry);
- }
+ this.transformation = transformation;
return this;
}
@@ -117,7 +84,7 @@
* Unconditionally enable javac generated assertion code in all packages and classes. This
* corresponds to passing <code>-enableassertions</code> or <code>-ea</code> to the java CLI.
*/
- public AssertionsConfiguration.Builder enable() {
+ public AssertionsConfiguration.Builder setEnable() {
setTransformation(AssertionTransformation.ENABLE);
return this;
}
@@ -126,86 +93,145 @@
* Disable the javac generated assertion code in all packages and classes. This corresponds to
* passing <code>-disableassertions</code> or <code>-da</code> to the java CLI.
*/
- public AssertionsConfiguration.Builder disable() {
+ public AssertionsConfiguration.Builder setDisable() {
setTransformation(AssertionTransformation.DISABLE);
return this;
}
/** Passthrough of the javac generated assertion code in all packages and classes. */
- public AssertionsConfiguration.Builder passthrough() {
+ public AssertionsConfiguration.Builder setPassthrough() {
setTransformation(AssertionTransformation.PASSTHROUGH);
return this;
}
- /** Set how to handle javac generated assertion code in package and all subpackages. */
- public AssertionsConfiguration.Builder setTransformationForPackage(
- String packageName, AssertionTransformation transformation) {
- addEntry(transformation, ConfigurationType.PACKAGE, packageName);
+ public AssertionsConfiguration.Builder setScopeAll() {
+ this.scope = AssertionTransformationScope.ALL;
+ this.value = null;
return this;
}
/**
- * Unconditionally enable javac generated assertion code in package <code>packageName</code> and
- * all subpackages. This corresponds to passing <code>-enableassertions:packageName...</code> or
- * <code>-ea:packageName...</code> to the java CLI.
+ * Apply the specified transformation in package <code>packageName</code> and all subpackages.
+ * If <code>packageName</code> is the empty string, this specifies that the transformation is
+ * applied ion the unnamed package.
*
- * <p>If <code>packageName</code> is the empty string, assertions are enabled in the unnamed
- * package, which corresponds to passing <code>-enableassertions:...</code> or <code>-ea:...
- * </code> to the java CLI.
- */
- public AssertionsConfiguration.Builder enableForPackage(String packageName) {
- return setTransformationForPackage(packageName, AssertionTransformation.ENABLE);
- }
-
- /**
- * Disable the javac generated assertion code in package <code>packageName</code> and all
- * subpackages. This corresponds to passing <code>-disableassertions:packageName...</code> or
- * <code>-da:packageName...</code> to the java CLI.
+ * <p>If the transformation is 'enable' this corresponds to passing <code>
+ * -enableassertions:packageName...</code> or <code>-ea:packageName...</code> to the java CLI.
*
- * <p>If <code>packageName</code> is the empty string assertions are disabled in the unnamed
- * package, which corresponds to passing <code>-disableassertions:...</code> or <code>-da:...
- * </code> to the java CLI.
+ * <p>If the transformation is 'disable' this corresponds to passing <code>
+ * -disableassertions:packageName...</code> or <code>-da:packageName...</code> to the java CLI.
*/
- public AssertionsConfiguration.Builder disableForPackage(String packageName) {
- return setTransformationForPackage(packageName, AssertionTransformation.DISABLE);
- }
-
- public AssertionsConfiguration.Builder passthroughForPackage(String packageName) {
- return setTransformationForPackage(packageName, AssertionTransformation.PASSTHROUGH);
- }
-
- /** Set how to handle javac generated assertion code in class. */
- public AssertionsConfiguration.Builder setTransformationForClass(
- String className, AssertionTransformation transformation) {
- addEntry(transformation, ConfigurationType.CLASS, className);
+ public AssertionsConfiguration.Builder setScopePackage(String packageName) {
+ this.scope = AssertionTransformationScope.PACKAGE;
+ this.value = packageName;
return this;
}
/**
- * Unconditionally enable javac generated assertion in class <code>className</code>. This
- * corresponds to passing <code> -enableassertions:className</code> or <code>-ea:className
- * </code> to the java CLI.
+ * Apply the specified transformation in class <code>className</code>.
+ *
+ * <p>If the transformation is 'enable' this corresponds to passing <code>
+ * -enableassertions:className</code> or <code>-ea:className...</code> to the java CLI.
+ *
+ * <p>If the transformation is 'disable' this corresponds to passing <code>
+ * -disableassertions:className</code> or <code>-da:className</code> to the java CLI.
*/
- public AssertionsConfiguration.Builder enableForClass(String className) {
- return setTransformationForClass(className, AssertionTransformation.ENABLE);
- }
-
- /**
- * Disable the javac generated assertion code in class <code>className</code>. This corresponds
- * to passing <code> -disableassertions:className</code> or <code>-da:className</code> to the
- * java CLI.
- */
- public AssertionsConfiguration.Builder disableForClass(String className) {
- return setTransformationForClass(className, AssertionTransformation.DISABLE);
- }
-
- public AssertionsConfiguration.Builder passthroughForClass(String className) {
- return setTransformationForClass(className, AssertionTransformation.PASSTHROUGH);
+ public AssertionsConfiguration.Builder setScopeClass(String className) {
+ this.scope = AssertionTransformationScope.CLASS;
+ this.value = className;
+ return this;
}
/** Build and return the {@link AssertionsConfiguration}. */
public AssertionsConfiguration build() {
- return new AssertionsConfiguration(entries);
+ if (transformation == null) {
+ reporter.error("No transformation specified for building AccertionConfiguration");
+ }
+ if (scope == null) {
+ reporter.error("No scope specified for building AccertionConfiguration");
+ }
+ if (scope == AssertionTransformationScope.PACKAGE && value == null) {
+ reporter.error("No package name specified for building AccertionConfiguration");
+ }
+ if (scope == AssertionTransformationScope.CLASS && value == null) {
+ reporter.error("No class name specified for building AccertionConfiguration");
+ }
+ return new AssertionsConfiguration(transformation, scope, value);
+ }
+
+ /**
+ * Static helper to build an <code>AssertionConfiguration</code> which unconditionally enables
+ * javac generated assertion code in all packages and classes. To be used like this:
+ *
+ * <pre>
+ * D8Command command = D8Command.builder()
+ * .addAssertionsConfiguration(AssertionsConfiguration.Builder::enableAllAssertions)
+ * ...
+ * .build();
+ * </pre>
+ *
+ * which is a shorthand for:
+ *
+ * <pre>
+ * D8Command command = D8Command.builder()
+ * .addAssertionsConfiguration(builder -> builder.setEnabled().setScopeAll().build())
+ * ...
+ * .build();
+ * </pre>
+ */
+ public static AssertionsConfiguration enableAllAssertions(
+ AssertionsConfiguration.Builder builder) {
+ return builder.setEnable().setScopeAll().build();
+ }
+
+ /**
+ * Static helper to build an <code>AssertionConfiguration</code> which unconditionally disables
+ * javac generated assertion code in all packages and classes. To be used like this:
+ *
+ * <pre>
+ * D8Command command = D8Command.builder()
+ * .addAssertionsConfiguration(AssertionsConfiguration.Builder::disableAllAssertions)
+ * ...
+ * .build();
+ * </pre>
+ *
+ * which is a shorthand for:
+ *
+ * <pre>
+ * D8Command command = D8Command.builder()
+ * .addAssertionsConfiguration(builder -> builder.setDisabled().setScopeAll().build())
+ * ...
+ * .build();
+ * </pre>
+ */
+ public static AssertionsConfiguration disableAllAssertions(
+ AssertionsConfiguration.Builder builder) {
+ return builder.setDisable().setScopeAll().build();
+ }
+
+ /**
+ * Static helper to build an <code>AssertionConfiguration</code> which will passthrough javac
+ * generated assertion code in all packages and classes. To be used like this:
+ *
+ * <pre>
+ * D8Command command = D8Command.builder()
+ * .addAssertionsConfiguration(AssertionsConfiguration.Builder::passthroughAllAssertions)
+ * ...
+ * .build();
+ * </pre>
+ *
+ * which is a shorthand for:
+ *
+ * <pre>
+ * D8Command command = D8Command.builder()
+ * .addAssertionsConfiguration(builder -> builder.setPassthrough().setScopeAll().build())
+ * ...
+ * .build();
+ * </pre>
+ */
+ public static AssertionsConfiguration passthroughAllAssertions(
+ AssertionsConfiguration.Builder builder) {
+ return builder.setPassthrough().setScopeAll().build();
}
}
}
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index 2b94a54..fd2ecb3 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
-import com.android.tools.r8.AssertionsConfiguration.AssertionTransformation;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexItemFactory;
@@ -40,7 +39,7 @@
private final boolean includeClassesChecksum;
private final boolean optimizeMultidexForLinearAlloc;
private final BiPredicate<String, Long> dexClassChecksumFilter;
- private final AssertionsConfiguration assertionsConfiguration;
+ private final List<AssertionsConfiguration> assertionsConfiguration;
BaseCompilerCommand(boolean printHelp, boolean printVersion) {
super(printHelp, printVersion);
@@ -53,7 +52,7 @@
includeClassesChecksum = false;
optimizeMultidexForLinearAlloc = false;
dexClassChecksumFilter = (name, checksum) -> true;
- assertionsConfiguration = null;
+ assertionsConfiguration = new ArrayList<>();
}
BaseCompilerCommand(
@@ -67,7 +66,7 @@
boolean optimizeMultidexForLinearAlloc,
boolean includeClassesChecksum,
BiPredicate<String, Long> dexClassChecksumFilter,
- AssertionsConfiguration assertionsConfiguration) {
+ List<AssertionsConfiguration> assertionsConfiguration) {
super(app);
assert minApiLevel > 0;
assert mode != null;
@@ -135,11 +134,8 @@
return optimizeMultidexForLinearAlloc;
}
- AssertionsConfiguration getAssertionsConfiguration(
- AssertionTransformation defaultTransformation) {
- return AssertionsConfiguration.builder(assertionsConfiguration)
- .setDefault(defaultTransformation)
- .build();
+ public List<AssertionsConfiguration> getAssertionsConfiguration() {
+ return assertionsConfiguration;
}
Reporter getReporter() {
@@ -171,7 +167,7 @@
private boolean lookupLibraryBeforeProgram = true;
private boolean optimizeMultidexForLinearAlloc = false;
private BiPredicate<String, Long> dexClassChecksumFilter = (name, checksum) -> true;
- private AssertionsConfiguration assertionsConfiguration;
+ private List<AssertionsConfiguration> assertionsConfiguration = new ArrayList<>();
abstract CompilationMode defaultCompilationMode();
@@ -490,20 +486,19 @@
return includeClassesChecksum;
}
+ List<AssertionsConfiguration> getAssertionsConfiguration() {
+ return assertionsConfiguration;
+ }
+
/** Configure compile time assertion enabling through a {@link AssertionsConfiguration}. */
public B addAssertionsConfiguration(
Function<AssertionsConfiguration.Builder, AssertionsConfiguration>
assertionsConfigurationGenerator) {
- assertionsConfiguration =
- assertionsConfigurationGenerator.apply(
- AssertionsConfiguration.builder(assertionsConfiguration));
+ assertionsConfiguration.add(
+ assertionsConfigurationGenerator.apply(AssertionsConfiguration.builder(getReporter())));
return self();
}
- public AssertionsConfiguration getAssertionsConfiguration() {
- return assertionsConfiguration;
- }
-
@Override
void validate() {
Reporter reporter = getReporter();
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index d3ec378..cf5e6c8 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -159,7 +159,7 @@
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
- if (!AssertionsRewriter.isPassthroughAll(options.assertionsConfiguration)) {
+ if (AssertionsRewriter.isEnabled(options)) {
// Run analysis to mark all <clinit> methods having the javac generated assertion
// enabling code.
ClassInitializerAssertionEnablingAnalysis analysis =
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 2401aa5..b76e6a7 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -10,11 +10,13 @@
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.List;
import java.util.function.BiPredicate;
/**
@@ -287,7 +289,7 @@
DesugarGraphConsumer desugarGraphConsumer,
StringConsumer desugaredLibraryKeepRuleConsumer,
DesugaredLibraryConfiguration libraryConfiguration,
- AssertionsConfiguration assertionsConfiguration,
+ List<AssertionsConfiguration> assertionsConfiguration,
DexItemFactory factory) {
super(
inputApp,
@@ -361,10 +363,11 @@
internal.desugaredLibraryConfiguration = libraryConfiguration;
internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
+ // Default is to remove all javac generated assertion code when generating dex.
assert internal.assertionsConfiguration == null;
- // Default, when no configuration is provided, is to remove all javac generated assertion
- // code when generating dex.
- internal.assertionsConfiguration = getAssertionsConfiguration(AssertionTransformation.DISABLE);
+ internal.assertionsConfiguration =
+ new AssertionConfigurationWithDefault(
+ AssertionTransformation.DISABLE, getAssertionsConfiguration());
return internal;
}
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 4a587aa..1ddd338 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -10,10 +10,12 @@
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
+import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
@@ -92,7 +94,7 @@
false,
false,
(name, checksum) -> true,
- AssertionsConfiguration.builder(null).build());
+ ImmutableList.of());
this.d8Command = d8Command;
this.r8Command = r8Command;
this.libraryConfiguration = libraryConfiguration;
@@ -171,10 +173,11 @@
// TODO(134732760): This is still work in progress.
internal.desugaredLibraryConfiguration = libraryConfiguration;
+ // Default is to remove all javac generated assertion code when generating dex.
assert internal.assertionsConfiguration == null;
- // Default, when no configuration is provided, is to remove all javac generated assertion
- // code when generating dex.
- internal.assertionsConfiguration = getAssertionsConfiguration(AssertionTransformation.DISABLE);
+ internal.assertionsConfiguration =
+ new AssertionConfigurationWithDefault(
+ AssertionTransformation.DISABLE, getAssertionsConfiguration());
return internal;
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 8c26650..dbe1572 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -807,7 +807,7 @@
if (appView.options().enableInitializedClassesInInstanceMethodsAnalysis) {
enqueuer.registerAnalysis(new InitializedClassesInInstanceMethodsAnalysis(appView));
}
- if (!AssertionsRewriter.isPassthroughAll(appView.options().assertionsConfiguration)) {
+ if (AssertionsRewriter.isEnabled(appView.options())) {
enqueuer.registerAnalysis(
new ClassInitializerAssertionEnablingAnalysis(
appView.dexItemFactory(), OptimizationFeedbackSimple.getInstance()));
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 265fa38..187e095 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.shaking.ProguardConfigurationSourceStrings;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -720,7 +721,7 @@
StringConsumer desugaredLibraryKeepRuleConsumer,
DesugaredLibraryConfiguration libraryConfiguration,
FeatureSplitConfiguration featureSplitConfiguration,
- AssertionsConfiguration assertionsConfiguration) {
+ List<AssertionsConfiguration> assertionsConfiguration) {
super(
inputApp,
mode,
@@ -870,14 +871,14 @@
internal.syntheticProguardRulesConsumer = syntheticProguardRulesConsumer;
+ // Default is to remove all javac generated assertion code when generating dex.
assert internal.assertionsConfiguration == null;
- // Default, when no configuration is provided, is to remove all javac generated assertion
- // code when generating dex and leave it when generating class files.
internal.assertionsConfiguration =
- getAssertionsConfiguration(
- internal.isGeneratingClassFiles()
+ new AssertionConfigurationWithDefault(
+ getProgramConsumer() instanceof ClassFileConsumer
? AssertionTransformation.PASSTHROUGH
- : AssertionTransformation.DISABLE);
+ : AssertionTransformation.DISABLE,
+ getAssertionsConfiguration());
// When generating class files the build is "intermediate" and we cannot pollute the namespace
// with the a hard-coded outline class. Doing so would prohibit subsequent merging of two
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
index 2292b0a..a344095 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/AssertionsRewriter.java
@@ -6,9 +6,6 @@
import com.android.tools.r8.AssertionsConfiguration;
import com.android.tools.r8.AssertionsConfiguration.AssertionTransformation;
-import com.android.tools.r8.AssertionsConfiguration.ConfigurationEntry;
-import com.android.tools.r8.AssertionsConfiguration.ConfigurationType;
-import com.android.tools.r8.AssertionsConfiguration.InternalAssertionConfiguration;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
@@ -21,7 +18,9 @@
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.StaticPut;
+import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThrowingCharIterator;
import java.io.UTFDataFormatException;
import java.util.List;
@@ -31,21 +30,21 @@
private static class ConfigurationEntryWithDexString {
- private ConfigurationEntry entry;
+ private AssertionsConfiguration entry;
private final DexString value;
private ConfigurationEntryWithDexString(
- ConfigurationEntry entry, DexItemFactory dexItemFactory) {
- this.entry = entry;
- switch (entry.getType()) {
+ AssertionsConfiguration configuration, DexItemFactory dexItemFactory) {
+ this.entry = configuration;
+ switch (configuration.getScope()) {
case PACKAGE:
- if (entry.getValue().length() == 0) {
+ if (configuration.getValue().length() == 0) {
value = dexItemFactory.createString("");
} else {
value =
dexItemFactory.createString(
"L"
- + entry
+ + configuration
.getValue()
.replace(
DescriptorUtils.JAVA_PACKAGE_SEPARATOR,
@@ -57,7 +56,7 @@
value =
dexItemFactory.createString(
"L"
- + entry
+ + configuration
.getValue()
.replace(
DescriptorUtils.JAVA_PACKAGE_SEPARATOR,
@@ -75,39 +74,38 @@
private final AppView<?> appView;
private final DexItemFactory dexItemFactory;
+ private final AssertionTransformation defaultTransformation;
private final List<ConfigurationEntryWithDexString> configuration;
private final boolean enabled;
public AssertionsRewriter(AppView<?> appView) {
this.appView = appView;
this.dexItemFactory = appView.dexItemFactory();
- if (appView.options().assertionsConfiguration == null) {
- this.configuration = null;
- this.enabled = false;
- } else {
- List<ConfigurationEntry> configuration =
- InternalAssertionConfiguration
- .getConfiguration(appView.options().assertionsConfiguration);
- this.configuration =
- configuration.stream()
- .map(entry -> new ConfigurationEntryWithDexString(entry, appView.dexItemFactory()))
- .collect(Collectors.toList());
- this.enabled = !isPassthroughAll(appView.options().assertionsConfiguration);
+ this.enabled = isEnabled(appView.options());
+ if (!enabled) {
+ defaultTransformation = null;
+ configuration = null;
+ return;
}
+ // Convert the assertion transformation to the representation used for this rewriter.
+ this.defaultTransformation = appView.options().assertionsConfiguration.defautlTransformation;
+ this.configuration =
+ appView.options().assertionsConfiguration.assertionsConfigurations.stream()
+ .map(entry -> new ConfigurationEntryWithDexString(entry, appView.dexItemFactory()))
+ .collect(Collectors.toList());
}
- public static boolean isPassthroughAll(AssertionsConfiguration assertionsConfiguration) {
- List<ConfigurationEntry> configuration =
- InternalAssertionConfiguration.getConfiguration(assertionsConfiguration);
- return configuration.size() == 1
- && configuration.get(0).getTransformation() == AssertionTransformation.PASSTHROUGH
- && configuration.get(0).getType() == ConfigurationType.ALL;
+ // Static method used by other analyses to see if additional analysis is required to support
+ // this rewriting.
+ public static boolean isEnabled(InternalOptions options) {
+ AssertionConfigurationWithDefault configuration = options.assertionsConfiguration;
+ return configuration != null && !configuration.isPassthroughAll();
}
private AssertionTransformation getTransformationForMethod(DexEncodedMethod method) {
- AssertionTransformation transformation = null;
+ AssertionTransformation transformation = defaultTransformation;
for (ConfigurationEntryWithDexString entry : configuration) {
- switch (entry.entry.getType()) {
+ switch (entry.entry.getScope()) {
case ALL:
transformation = entry.entry.getTransformation();
break;
@@ -132,7 +130,7 @@
throw new Unreachable();
}
}
- assert transformation != null; // Default transformation are always added.
+ assert transformation != null;
return transformation;
}
diff --git a/src/main/java/com/android/tools/r8/utils/AssertionConfigurationWithDefault.java b/src/main/java/com/android/tools/r8/utils/AssertionConfigurationWithDefault.java
new file mode 100644
index 0000000..7dc7b33
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/AssertionConfigurationWithDefault.java
@@ -0,0 +1,34 @@
+// 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 com.android.tools.r8.AssertionsConfiguration;
+import com.android.tools.r8.AssertionsConfiguration.AssertionTransformation;
+import com.android.tools.r8.AssertionsConfiguration.AssertionTransformationScope;
+import java.util.List;
+
+public class AssertionConfigurationWithDefault {
+
+ public final AssertionTransformation defautlTransformation;
+ public final List<AssertionsConfiguration> assertionsConfigurations;
+
+ public AssertionConfigurationWithDefault(
+ AssertionTransformation defautlTransformation,
+ List<AssertionsConfiguration> assertionsConfigurations) {
+ this.defautlTransformation = defautlTransformation;
+ assert assertionsConfigurations != null;
+ this.assertionsConfigurations = assertionsConfigurations;
+ }
+
+ public boolean isPassthroughAll() {
+ if (assertionsConfigurations.size() == 0) {
+ return defautlTransformation == AssertionTransformation.PASSTHROUGH;
+ }
+ return assertionsConfigurations.size() == 1
+ && assertionsConfigurations.get(0).getScope() == AssertionTransformationScope.ALL
+ && assertionsConfigurations.get(0).getTransformation()
+ == AssertionTransformation.PASSTHROUGH;
+ }
+}
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 cf2844f..114715a 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -5,7 +5,6 @@
import static com.google.common.base.Predicates.not;
-import com.android.tools.r8.AssertionsConfiguration;
import com.android.tools.r8.ClassFileConsumer;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.DataResourceConsumer;
@@ -437,7 +436,7 @@
public boolean ignoreMissingClasses = false;
// EXPERIMENTAL flag to get behaviour as close to Proguard as possible.
public boolean forceProguardCompatibility = false;
- public AssertionsConfiguration assertionsConfiguration = null;
+ public AssertionConfigurationWithDefault assertionsConfiguration = null;
public boolean configurationDebugging = false;
// Don't convert Code objects to IRCode.
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionsConfigurationTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionsConfigurationTest.java
index ce9f1c5..2d79d48 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionsConfigurationTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionsConfigurationTest.java
@@ -10,9 +10,12 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.AssertionsConfiguration;
+import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ThrowableConsumer;
import com.android.tools.r8.rewrite.assertions.testclasses.TestClassForInnerClass;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ThrowingConsumer;
@@ -21,7 +24,6 @@
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.google.common.collect.ImmutableList;
import java.util.List;
-import java.util.function.Function;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -65,15 +67,14 @@
}
private void runD8Test(
- Function<AssertionsConfiguration.Builder, AssertionsConfiguration>
- assertionsConfigurationBuilder,
+ ThrowableConsumer<D8TestBuilder> builderConsumer,
ThrowingConsumer<CodeInspector, RuntimeException> inspector,
List<String> outputLines)
throws Exception {
testForD8()
.addProgramClasses(testClasses)
.setMinApi(parameters.getApiLevel())
- .addAssertionsConfiguration(assertionsConfigurationBuilder)
+ .apply(builderConsumer)
.compile()
.inspect(inspector)
.run(parameters.getRuntime(), TestClass.class)
@@ -81,17 +82,15 @@
}
public void runR8Test(
- Function<AssertionsConfiguration.Builder, AssertionsConfiguration>
- assertionsConfigurationBuilder,
+ ThrowableConsumer<R8FullTestBuilder> builderConsumer,
ThrowingConsumer<CodeInspector, RuntimeException> inspector,
List<String> outputLines)
throws Exception {
- runR8Test(assertionsConfigurationBuilder, inspector, outputLines, false);
+ runR8Test(builderConsumer, inspector, outputLines, false);
}
public void runR8Test(
- Function<AssertionsConfiguration.Builder, AssertionsConfiguration>
- assertionsConfigurationBuilder,
+ ThrowableConsumer<R8FullTestBuilder> builderConsumer,
ThrowingConsumer<CodeInspector, RuntimeException> inspector,
List<String> outputLines,
boolean enableJvmAssertions)
@@ -102,7 +101,7 @@
.addKeepMainRule(TestClass.class)
.addKeepClassAndMembersRules(class1, class2, subpackageClass1, subpackageClass2)
.setMinApi(parameters.getApiLevel())
- .addAssertionsConfiguration(assertionsConfigurationBuilder)
+ .apply(builderConsumer)
.compile()
.inspect(inspector)
.enableRuntimeAssertions(enableJvmAssertions)
@@ -110,18 +109,6 @@
.assertSuccessWithOutput(StringUtils.lines(outputLines));
}
- private AssertionsConfiguration enableAllAssertions(AssertionsConfiguration.Builder builder) {
- return builder.enable().build();
- }
-
- private AssertionsConfiguration disableAllAssertions(AssertionsConfiguration.Builder builder) {
- return builder.disable().build();
- }
-
- private AssertionsConfiguration leaveAllAssertions(AssertionsConfiguration.Builder builder) {
- return builder.passthrough().build();
- }
-
private List<String> allAssertionsExpectedLines() {
return ImmutableList.of(
"AssertionError in testclasses.Class1",
@@ -218,29 +205,53 @@
Assume.assumeTrue(parameters.isDexRuntime());
// Leaving assertions in or disabling them on Dalvik/Art means no assertions.
runD8Test(
- this::leaveAllAssertions, this::checkAssertionCodeLeft, noAllAssertionsExpectedLines());
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::passthroughAllAssertions),
+ this::checkAssertionCodeLeft,
+ noAllAssertionsExpectedLines());
runR8Test(
- this::leaveAllAssertions, this::checkAssertionCodeLeft, noAllAssertionsExpectedLines());
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::passthroughAllAssertions),
+ this::checkAssertionCodeLeft,
+ noAllAssertionsExpectedLines());
runD8Test(
- this::disableAllAssertions,
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::disableAllAssertions),
this::checkAssertionCodeRemoved,
noAllAssertionsExpectedLines());
runR8Test(
- this::disableAllAssertions,
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::disableAllAssertions),
this::checkAssertionCodeRemoved,
noAllAssertionsExpectedLines());
// Compile time enabling assertions gives assertions on Dalvik/Art.
runD8Test(
- this::enableAllAssertions, this::checkAssertionCodeEnabled, allAssertionsExpectedLines());
- runR8Test(
- this::enableAllAssertions, this::checkAssertionCodeEnabled, allAssertionsExpectedLines());
- // Enabling for the package should enable all.
- runD8Test(
- builder -> builder.enableForPackage(packageName).build(),
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::enableAllAssertions),
this::checkAssertionCodeEnabled,
allAssertionsExpectedLines());
runR8Test(
- builder -> builder.enableForPackage(packageName).build(),
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::enableAllAssertions),
+ this::checkAssertionCodeEnabled,
+ allAssertionsExpectedLines());
+ // Enabling for the package should enable all.
+ runD8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ b -> b.setEnable().setScopePackage(packageName).build()),
+ this::checkAssertionCodeEnabled,
+ allAssertionsExpectedLines());
+ runR8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ b -> b.setEnable().setScopePackage(packageName).build()),
this::checkAssertionCodeEnabled,
allAssertionsExpectedLines());
}
@@ -250,23 +261,42 @@
Assume.assumeTrue(parameters.isCfRuntime());
// Leaving assertion code means assertions are controlled by the -ea flag.
runR8Test(
- this::leaveAllAssertions, this::checkAssertionCodeLeft, noAllAssertionsExpectedLines());
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::passthroughAllAssertions),
+ this::checkAssertionCodeLeft,
+ noAllAssertionsExpectedLines());
runR8Test(
- this::leaveAllAssertions, this::checkAssertionCodeLeft, allAssertionsExpectedLines(), true);
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::passthroughAllAssertions),
+ this::checkAssertionCodeLeft,
+ allAssertionsExpectedLines(),
+ true);
// Compile time enabling or disabling assertions means the -ea flag has no effect.
runR8Test(
- this::enableAllAssertions, this::checkAssertionCodeEnabled, allAssertionsExpectedLines());
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::enableAllAssertions),
+ this::checkAssertionCodeEnabled,
+ allAssertionsExpectedLines());
runR8Test(
- this::enableAllAssertions,
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::enableAllAssertions),
this::checkAssertionCodeEnabled,
allAssertionsExpectedLines(),
true);
runR8Test(
- this::disableAllAssertions,
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::disableAllAssertions),
this::checkAssertionCodeRemoved,
noAllAssertionsExpectedLines());
runR8Test(
- this::disableAllAssertions,
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::disableAllAssertions),
this::checkAssertionCodeRemoved,
noAllAssertionsExpectedLines(),
true);
@@ -276,7 +306,9 @@
public void testEnableForPackageForDex() throws Exception {
Assume.assumeTrue(parameters.isDexRuntime());
runD8Test(
- builder -> builder.enableForPackage(subPackageName).build(),
+ builder ->
+ builder.addAssertionsConfiguration(
+ b -> b.setEnable().setScopePackage(subPackageName).build()),
inspector -> {
checkAssertionCodeEnabled(inspector, subpackageClass1);
checkAssertionCodeEnabled(inspector, subpackageClass2);
@@ -286,7 +318,9 @@
"AssertionError in testclasses.subpackage.Class2",
"DONE"));
runR8Test(
- builder -> builder.enableForPackage(subPackageName).build(),
+ builder ->
+ builder.addAssertionsConfiguration(
+ b -> b.setEnable().setScopePackage(subPackageName).build()),
inspector -> {
checkAssertionCodeEnabled(inspector, subpackageClass1);
checkAssertionCodeEnabled(inspector, subpackageClass2);
@@ -303,12 +337,13 @@
runD8Test(
builder ->
builder
- .enableForClass(class1.getCanonicalName())
- .enableForClass(subpackageClass2.getCanonicalName())
- .build(),
+ .addAssertionsConfiguration(
+ b -> b.setEnable().setScopeClass(class1.getCanonicalName()).build())
+ .addAssertionsConfiguration(
+ b -> b.setEnable().setScopeClass(subpackageClass2.getCanonicalName()).build()),
inspector -> {
- // checkAssertionCodeEnabled(inspector, class1);
- // checkAssertionCodeEnabled(inspector, subpackageClass2);
+ checkAssertionCodeEnabled(inspector, class1);
+ checkAssertionCodeEnabled(inspector, subpackageClass2);
},
ImmutableList.of(
"AssertionError in testclasses.Class1",
@@ -317,9 +352,10 @@
runR8Test(
builder ->
builder
- .enableForClass(class1.getCanonicalName())
- .enableForClass(subpackageClass2.getCanonicalName())
- .build(),
+ .addAssertionsConfiguration(
+ b -> b.setEnable().setScopeClass(class1.getCanonicalName()).build())
+ .addAssertionsConfiguration(
+ b -> b.setEnable().setScopeClass(subpackageClass2.getCanonicalName()).build()),
inspector -> {
checkAssertionCodeEnabled(inspector, class1);
checkAssertionCodeEnabled(inspector, subpackageClass2);
@@ -336,10 +372,11 @@
runD8Test(
builder ->
builder
- .enableForPackage(packageName)
- .disableForClass(class2.getCanonicalName())
- .disableForClass(subpackageClass1.getCanonicalName())
- .build(),
+ .addAssertionsConfiguration(b -> b.setEnable().setScopePackage(packageName).build())
+ .addAssertionsConfiguration(
+ b -> b.setDisable().setScopeClass(class2.getCanonicalName()).build())
+ .addAssertionsConfiguration(
+ b -> b.setDisable().setScopeClass(subpackageClass1.getCanonicalName()).build()),
inspector -> {
checkAssertionCodeEnabled(inspector, class1);
checkAssertionCodeRemoved(inspector, class2);
@@ -353,10 +390,11 @@
runR8Test(
builder ->
builder
- .enableForPackage(packageName)
- .disableForClass(class2.getCanonicalName())
- .disableForClass(subpackageClass1.getCanonicalName())
- .build(),
+ .addAssertionsConfiguration(b -> b.setEnable().setScopePackage(packageName).build())
+ .addAssertionsConfiguration(
+ b -> b.setDisable().setScopeClass(class2.getCanonicalName()).build())
+ .addAssertionsConfiguration(
+ b -> b.setDisable().setScopeClass(subpackageClass1.getCanonicalName()).build()),
inspector -> {
checkAssertionCodeEnabled(inspector, class1);
checkAssertionCodeRemoved(inspector, class2);
@@ -379,7 +417,7 @@
classInUnnamedPackage("Class1"),
classInUnnamedPackage("Class2"))
.setMinApi(parameters.getApiLevel())
- .addAssertionsConfiguration(builder -> builder.enableForPackage("").build())
+ .addAssertionsConfiguration(builder -> builder.setEnable().setScopePackage("").build())
.compile()
.inspect(
inspector -> {
@@ -427,7 +465,10 @@
.setMinApi(parameters.getApiLevel())
.addAssertionsConfiguration(
builder ->
- builder.enableForClass(TestClassForInnerClass.class.getCanonicalName()).build())
+ builder
+ .setEnable()
+ .setScopeClass(TestClassForInnerClass.class.getCanonicalName())
+ .build())
.compile()
.inspect(
inspector -> {
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
index 27e53ba..bbcc8e2 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
@@ -199,7 +199,8 @@
.debug()
.noTreeShaking()
.noMinification()
- .addAssertionsConfiguration(builder -> builder.setTransformation(transformation).build())
+ .addAssertionsConfiguration(
+ builder -> builder.setTransformation(transformation).setScopeAll().build())
.compile();
}
@@ -337,7 +338,8 @@
.addProgramClasses(ClassWithAssertions.class)
.debug()
.setMinApi(AndroidApiLevel.B)
- .addAssertionsConfiguration(builder -> builder.setTransformation(transformation).build())
+ .addAssertionsConfiguration(
+ builder -> builder.setTransformation(transformation).setScopeAll().build())
.compile();
}
@@ -357,7 +359,8 @@
.addProgramFiles(program)
.debug()
.setMinApi(AndroidApiLevel.B)
- .addAssertionsConfiguration(builder -> builder.setTransformation(transformation).build())
+ .addAssertionsConfiguration(
+ builder -> builder.setTransformation(transformation).setScopeAll().build())
.compile();
}