|  | // 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; | 
|  |  | 
|  | import com.android.tools.r8.keepanno.annotations.KeepForApi; | 
|  | import com.android.tools.r8.references.MethodReference; | 
|  | import com.android.tools.r8.utils.BooleanUtils; | 
|  | import com.android.tools.r8.utils.Reporter; | 
|  |  | 
|  | @KeepForApi | 
|  | public class AssertionsConfiguration { | 
|  |  | 
|  | private enum AssertionTransformation { | 
|  | ENABLE, | 
|  | DISABLE, | 
|  | PASSTHROUGH | 
|  | } | 
|  |  | 
|  | public enum AssertionTransformationScope { | 
|  | ALL, | 
|  | PACKAGE, | 
|  | CLASS | 
|  | } | 
|  |  | 
|  | private final AssertionTransformation transformation; | 
|  | private final MethodReference assertionHandler; | 
|  | private final AssertionTransformationScope scope; | 
|  | private final String value; | 
|  |  | 
|  | AssertionsConfiguration( | 
|  | AssertionTransformation transformation, | 
|  | MethodReference assertionHandler, | 
|  | AssertionTransformationScope scope, | 
|  | String value) { | 
|  | this.transformation = transformation; | 
|  | this.assertionHandler = assertionHandler; | 
|  | this.scope = scope; | 
|  | this.value = value; | 
|  | assert BooleanUtils.xor(transformation != null, assertionHandler != null); | 
|  | } | 
|  |  | 
|  | public boolean isCompileTimeEnabled() { | 
|  | return transformation == AssertionTransformation.ENABLE; | 
|  | } | 
|  |  | 
|  | public boolean isCompileTimeDisabled() { | 
|  | return transformation == AssertionTransformation.DISABLE; | 
|  | } | 
|  |  | 
|  | public boolean isPassthrough() { | 
|  | return transformation == AssertionTransformation.PASSTHROUGH; | 
|  | } | 
|  |  | 
|  | public boolean isAssertionHandler() { | 
|  | return assertionHandler != null; | 
|  | } | 
|  |  | 
|  | public MethodReference getAssertionHandler() { | 
|  | return assertionHandler; | 
|  | } | 
|  |  | 
|  | public AssertionTransformationScope getScope() { | 
|  | return scope; | 
|  | } | 
|  |  | 
|  | public String getValue() { | 
|  | return value; | 
|  | } | 
|  |  | 
|  | static AssertionsConfiguration.Builder builder(Reporter reporter) { | 
|  | return new AssertionsConfiguration.Builder(reporter); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Builder for constructing a <code>{@link AssertionsConfiguration}</code>. | 
|  | * | 
|  | * <p>A builder is obtained by calling {@link | 
|  | * BaseCompilerCommand.Builder#addAssertionsConfiguration}. | 
|  | */ | 
|  | @KeepForApi | 
|  | public static class Builder { | 
|  | Reporter reporter; | 
|  | private AssertionTransformation transformation; | 
|  | private MethodReference assertionHandler; | 
|  | private AssertionTransformationScope scope; | 
|  | private String value; | 
|  |  | 
|  | private Builder(Reporter reporter) { | 
|  | this.reporter = reporter; | 
|  | } | 
|  |  | 
|  | private AssertionsConfiguration.Builder setTransformation( | 
|  | AssertionTransformation transformation) { | 
|  | this.transformation = transformation; | 
|  | this.assertionHandler = null; | 
|  | return this; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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 setCompileTimeEnable() { | 
|  | setTransformation(AssertionTransformation.ENABLE); | 
|  | return this; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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 setCompileTimeDisable() { | 
|  | setTransformation(AssertionTransformation.DISABLE); | 
|  | return this; | 
|  | } | 
|  |  | 
|  | /** Passthrough of the javac generated assertion code in all packages and classes. */ | 
|  | public AssertionsConfiguration.Builder setPassthrough() { | 
|  | setTransformation(AssertionTransformation.PASSTHROUGH); | 
|  | return this; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Rewrite the throwing of <code>java.lang.AssertionError</code> to call the supplied method | 
|  | * <code>assertionHandler</code>. The method must be a reference to a static method taking one | 
|  | * argument. The type of the argument should be <code>java.lang.Throwable</code> as kotlinc will | 
|  | * generate code where the assertion error is thrown as <code>java.lang.Throwable</code>. If all | 
|  | * code is generated by javac then the type of the argument can be <code> | 
|  | * java.lang.AssertionError</code>. After the assertion handler as been called, the code | 
|  | * continues as if assertions where disabled. | 
|  | */ | 
|  | public AssertionsConfiguration.Builder setAssertionHandler(MethodReference assertionHandler) { | 
|  | this.transformation = null; | 
|  | this.assertionHandler = assertionHandler; | 
|  | return this; | 
|  | } | 
|  |  | 
|  | public AssertionsConfiguration.Builder setScopeAll() { | 
|  | this.scope = AssertionTransformationScope.ALL; | 
|  | this.value = null; | 
|  | return this; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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 the transformation is 'enable' this corresponds to passing <code> | 
|  | * -enableassertions:packageName...</code> or <code>-ea:packageName...</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 setScopePackage(String packageName) { | 
|  | this.scope = AssertionTransformationScope.PACKAGE; | 
|  | this.value = packageName; | 
|  | return this; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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 setScopeClass(String className) { | 
|  | this.scope = AssertionTransformationScope.CLASS; | 
|  | this.value = className; | 
|  | return this; | 
|  | } | 
|  |  | 
|  | /** Build and return the {@link AssertionsConfiguration}. */ | 
|  | @SuppressWarnings("InlineMeSuggester") | 
|  | public AssertionsConfiguration build() { | 
|  | if (transformation == null && assertionHandler == null) { | 
|  | reporter.error( | 
|  | "No transformation or assertion handler specified for building AssertionConfiguration"); | 
|  | } | 
|  | if (scope == null) { | 
|  | reporter.error("No scope specified for building AssertionConfiguration"); | 
|  | } | 
|  | if (scope == AssertionTransformationScope.PACKAGE && value == null) { | 
|  | reporter.error("No package name specified for building AssertionConfiguration"); | 
|  | } | 
|  | if (scope == AssertionTransformationScope.CLASS && value == null) { | 
|  | reporter.error("No class name specified for building AssertionConfiguration"); | 
|  | } | 
|  | return new AssertionsConfiguration(transformation, assertionHandler, 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.setCompileTimeEnable().setScopeAll().build()) | 
|  | *     ... | 
|  | *     .build(); | 
|  | * </pre> | 
|  | */ | 
|  | public static AssertionsConfiguration compileTimeEnableAllAssertions( | 
|  | AssertionsConfiguration.Builder builder) { | 
|  | return builder.setCompileTimeEnable().setScopeAll().build(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @deprecated As of version 3.3, replaced by {@link #compileTimeEnableAllAssertions(Builder)} | 
|  | */ | 
|  | @Deprecated | 
|  | @SuppressWarnings("InlineMeSuggester") | 
|  | public static AssertionsConfiguration enableAllAssertions( | 
|  | AssertionsConfiguration.Builder builder) { | 
|  | return compileTimeEnableAllAssertions(builder); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * 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::compileTimeDisableAllAssertions) | 
|  | *     ... | 
|  | *     .build(); | 
|  | * </pre> | 
|  | * | 
|  | * which is a shorthand for: | 
|  | * | 
|  | * <pre> | 
|  | *   D8Command command = D8Command.builder() | 
|  | *     .addAssertionsConfiguration( | 
|  | *         builder -> builder.setCompileTimeDisabled().setScopeAll().build()) | 
|  | *     ... | 
|  | *     .build(); | 
|  | * </pre> | 
|  | */ | 
|  | public static AssertionsConfiguration compileTimeDisableAllAssertions( | 
|  | AssertionsConfiguration.Builder builder) { | 
|  | return builder.setCompileTimeDisable().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(); | 
|  | } | 
|  | } | 
|  | } |