Merge "Make dex segment type names UpperCamelCase."
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 8560de3..3bcf6e7 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -164,4 +164,16 @@
   public boolean hasClassInitializer() {
     return getClassInitializer() != null;
   }
+
+  public boolean hasNonTrivialClassInitializer() {
+    DexEncodedMethod clinit = getClassInitializer();
+    if (clinit == null || clinit.getCode() == null) {
+      return false;
+    }
+    if (clinit.getCode().isDexCode()) {
+      return !clinit.getCode().asDexCode().isEmptyVoidMethod();
+    }
+    // For non-dex code we don't try to check the code.
+    return true;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index f48e7db..9327fb0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.code.ReturnVoid;
 import com.android.tools.r8.code.SwitchPayload;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
@@ -135,6 +136,10 @@
     return false;
   }
 
+  boolean isEmptyVoidMethod() {
+    return instructions.length == 1 && instructions[0] instanceof ReturnVoid;
+  }
+
   @Override
   public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options) {
     DexSourceCode source = new DexSourceCode(this, encodedMethod);
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index dd29e8d2..ec21ff0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -83,6 +83,8 @@
 
   public DexString getClassMethodName = createString("getClass");
   public DexString ordinalMethodName = createString("ordinal");
+  public final DexString desiredAssertionStatusMethodName = createString("desiredAssertionStatus");
+  public final DexString assertionsDisabled = createString("$assertionsDisabled");
 
   public DexString stringDescriptor = createString("Ljava/lang/String;");
   public DexString objectDescriptor = createString("Ljava/lang/Object;");
@@ -134,6 +136,7 @@
   public ObjectMethods objectMethods = new ObjectMethods();
   public LongMethods longMethods = new LongMethods();
   public ThrowableMethods throwableMethods = new ThrowableMethods();
+  public ClassMethods classMethods = new ClassMethods();
 
   public void clearSubtypeInformation() {
     types.values().forEach(DexType::clearSubtypeInformation);
@@ -182,6 +185,17 @@
     }
   }
 
+  public class ClassMethods {
+
+    public DexMethod desiredAssertionStatus;
+
+    private ClassMethods() {
+      desiredAssertionStatus = createMethod(classDescriptor,
+          desiredAssertionStatusMethodName, booleanDescriptor, new DexString[]{});
+    }
+  }
+
+
   public class StringBuildingMethods {
 
     public DexMethod appendBoolean;
diff --git a/src/main/java/com/android/tools/r8/graph/DexString.java b/src/main/java/com/android/tools/r8/graph/DexString.java
index e70e8f0..25416d9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexString.java
+++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.naming.NamingLens;
 import java.io.UTFDataFormatException;
@@ -246,7 +247,8 @@
     // '<' SimpleName '>' should be valid. However, the art verifier only allows <init>
     // and <clinit> which is reasonable.
     if ((string.charAt(0) == '<') &&
-        (string.equals("<init>") || string.equals("<clinit>"))) {
+        (string.equals(Constants.INSTANCE_INITIALIZER_NAME) ||
+            string.equals(Constants.CLASS_INITIALIZER_NAME))) {
       return true;
     }
     for (int i = 0; i < string.length(); i++) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Argument.java b/src/main/java/com/android/tools/r8/ir/code/Argument.java
index 94f6507..d624990 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Argument.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Argument.java
@@ -21,7 +21,7 @@
   }
 
   @Override
-  public boolean canBeDeadCode(InternalOptions options) {
+  public boolean canBeDeadCode(IRCode code, InternalOptions options) {
     // Never remove argument instructions. That would change the signature of the method.
     // TODO(ager): If we can tell that a method never uses an argument we might be able to
     // rewrite the signature and call-sites.
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
index 5e1ff16..20ce7e8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayPut.java
@@ -103,7 +103,7 @@
   }
 
   @Override
-  public boolean canBeDeadCode(InternalOptions options) {
+  public boolean canBeDeadCode(IRCode code, InternalOptions options) {
     // ArrayPut has side-effects on input values.
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
index 9b565a6..3a3626e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.utils.InternalOptions;
 
 public class ConstClass extends ConstInstruction {
 
@@ -57,6 +58,16 @@
   }
 
   @Override
+  public boolean canBeDeadCode(IRCode code, InternalOptions options) {
+    // A const-class instruction can be dead code only if the resulting program is known to contain
+    // the class mentioned.
+    // The simple conservative check is for the holder of the method.
+    // TODO(sgjesse): It might be beneficial to check for program classes in the super hierarchy or
+    // interfaces implemented.
+    return code.method.method.holder == clazz;
+  }
+
+  @Override
   public boolean isConstClass() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
index ee8a279..f1a6d02 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalRead.java
@@ -50,7 +50,7 @@
   }
 
   @Override
-  public boolean canBeDeadCode(InternalOptions options) {
+  public boolean canBeDeadCode(IRCode code, InternalOptions options) {
     return false;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
index 28d6b2b..e7917c6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
@@ -61,7 +61,7 @@
   }
 
   @Override
-  public boolean canBeDeadCode(InternalOptions options) {
+  public boolean canBeDeadCode(IRCode code, InternalOptions options) {
     return false;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 3ff0624..400c30a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -355,4 +355,12 @@
   public Value createValue(MoveType moveType) {
     return createValue(moveType, null);
   }
+
+  public ConstNumber createTrue() {
+    return new ConstNumber(ConstType.INT, createValue(MoveType.SINGLE), 1);
+  }
+
+  public ConstNumber createFalse() {
+    return new ConstNumber(ConstType.INT, createValue(MoveType.SINGLE), 0);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 2e821cf..ae4fd67 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -252,7 +252,7 @@
   }
 
   /** Returns true is this instruction can be treated as dead code if its outputs are not used. */
-  public boolean canBeDeadCode(InternalOptions options) {
+  public boolean canBeDeadCode(IRCode code, InternalOptions options) {
     return !instructionInstanceCanThrow();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
index 7b1c007..ec9c12f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/JumpInstruction.java
@@ -32,7 +32,7 @@
   }
 
   @Override
-  public boolean canBeDeadCode(InternalOptions options) {
+  public boolean canBeDeadCode(IRCode code, InternalOptions options) {
     return false;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index 3e63e50..2691eed 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -57,7 +57,7 @@
   }
 
   @Override
-  public boolean canBeDeadCode(InternalOptions options) {
+  public boolean canBeDeadCode(IRCode code, InternalOptions options) {
     return !options.debug;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
index b7d05e8..63a1a0e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
@@ -80,7 +80,7 @@
   }
 
   @Override
-  public boolean canBeDeadCode(InternalOptions options) {
+  public boolean canBeDeadCode(IRCode code, InternalOptions options) {
     // Side-effects its input values.
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index 27b1e18..f208d49 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -507,7 +507,7 @@
     // currently active values.
     active.add(this);
     for (Instruction instruction : uniqueUsers()) {
-      if (!instruction.canBeDeadCode(options)) {
+      if (!instruction.canBeDeadCode(null, options)) {
         return false;
       }
       Value outValue = instruction.outValue();
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 9d8cbcf..a5e2df7 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
@@ -437,6 +437,9 @@
       assert !options.debug;
       codeRewriter.removeSwitchMaps(code);
     }
+    if (options.disableAssertions) {
+      codeRewriter.disableAssertions(code);
+    }
     if (options.inlineAccessors && inliner != null) {
       // TODO(zerny): Should we support inlining in debug mode? b/62937285
       assert !options.debug;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index f26cacd..faed53d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -680,6 +680,65 @@
     assert code.isConsistentGraph();
   }
 
+  // For supporting assert javac adds the static field $assertionsDisabled to all classes which
+  // have methods with assertions. This is used to support the Java VM -ea flag.
+  //
+  //  The class:
+  //
+  //  class A {
+  //    void m() {
+  //      assert xxx;
+  //    }
+  //  }
+  //
+  //  Is compiled into:
+  //
+  //  class A {
+  //    static boolean $assertionsDisabled;
+  //    static {
+  //      $assertionsDisabled = A.class.desiredAssertionStatus();
+  //    }
+  //
+  //    // method with "assert xxx";
+  //    void m() {
+  //      if (!$assertionsDisabled) {
+  //        if (xxx) {
+  //          throw new AssertionError(...);
+  //        }
+  //      }
+  //    }
+  //  }
+  //
+  //  With the rewriting below (and other rewritings) the resulting code is:
+  //
+  //  class A {
+  //    void m() {
+  //    }
+  //  }
+  //
+  public void disableAssertions(IRCode code) {
+    InstructionIterator iterator = code.instructionIterator();
+    while (iterator.hasNext()) {
+      Instruction current = iterator.next();
+      if (current.isInvokeMethod()) {
+        InvokeMethod invoke = current.asInvokeMethod();
+        if (invoke.getInvokedMethod() == dexItemFactory.classMethods.desiredAssertionStatus) {
+          iterator.replaceCurrentInstruction(code.createFalse());
+        }
+      } else if (current.isStaticPut()) {
+        StaticPut staticPut = current.asStaticPut();
+        if (staticPut.getField().name == dexItemFactory.assertionsDisabled) {
+          iterator.remove();
+        }
+      } else if (current.isStaticGet()) {
+        StaticGet staticGet = current.asStaticGet();
+        if (staticGet.getField().name == dexItemFactory.assertionsDisabled) {
+          iterator.replaceCurrentInstruction(code.createTrue());
+        }
+      }
+    }
+  }
+
   private boolean canBeFolded(Instruction instruction) {
     return (instruction.isBinop() && instruction.asBinop().canBeFolded()) ||
         (instruction.isUnop() && instruction.asUnop().canBeFolded());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index 0c60642..b252915 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -31,7 +31,7 @@
         // Ignore marked blocks, as they are scheduled for removal.
         continue;
       }
-      removeDeadInstructions(worklist, block, options);
+      removeDeadInstructions(worklist, code, block, options);
       removeDeadPhis(worklist, block, options);
       removeUnneededCatchHandlers(worklist, block, dominator);
     }
@@ -96,7 +96,7 @@
   }
 
   private static void removeDeadInstructions(
-      Queue<BasicBlock> worklist, BasicBlock block, InternalOptions options) {
+      Queue<BasicBlock> worklist, IRCode code, BasicBlock block, InternalOptions options) {
     InstructionListIterator iterator = block.listIterator(block.getInstructions().size());
     while (iterator.hasPrevious()) {
       Instruction current = iterator.previous();
@@ -106,8 +106,8 @@
           && current.outValue().numberOfAllUsers() == 0) {
         current.setOutValue(null);
       }
-      // Never remove instructions that can have side effects.
-      if (!current.canBeDeadCode(options)) {
+      // Never remove instructions that can have side effects, except for const-class.
+      if (!current.canBeDeadCode(code, options)) {
         continue;
       }
       Value outValue = current.outValue();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index 03f9470..febef82 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -219,7 +219,7 @@
       return true;
     }
     DexClass clazz = inliner.appInfo.definitionFor(targetHolder);
-    return (clazz != null) && (!clazz.hasClassInitializer());
+    return (clazz != null) && (!clazz.hasNonTrivialClassInitializer());
   }
 
   private synchronized boolean isDoubleInliningTarget(DexEncodedMethod candidate) {
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 abdda65..b8fa85a 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -348,10 +348,11 @@
       }
       // We also need to add the corresponding <clinit> to the set of live methods, as otherwise
       // static field initialization (and other class-load-time sideeffects) will not happen.
-      DexEncodedMethod clinit = holder.getClassInitializer();
-      if (clinit != null) {
+      if (holder.hasNonTrivialClassInitializer()) {
+        DexEncodedMethod clinit = holder.getClassInitializer();
         markDirectStaticOrConstructorMethodAsLive(clinit, KeepReason.reachableFromLiveType(type));
       }
+
       // If this type has deferred annotations, we have to process those now, too.
       Set<DexAnnotation> annotations = deferredAnnotations.remove(type);
       if (annotations != null) {
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 7b1cfe1..9a8fa82 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -74,6 +74,7 @@
   public boolean allowAccessModification = true;
   public boolean inlineAccessors = true;
   public boolean removeSwitchMaps = true;
+  public boolean disableAssertions = true;
   public final OutlineOptions outline = new OutlineOptions();
   public boolean debugKeepRules = false;
   public final AttributeRemovalOptions attributeRemoval = new AttributeRemovalOptions();
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 3f31686..e6134e7 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -87,6 +87,15 @@
   /**
    * Compile an application with R8.
    */
+  protected AndroidApp compileWithR8(Class... classes)
+      throws CompilationException, ProguardRuleParserException, ExecutionException, IOException {
+    R8Command command = ToolHelper.prepareR8CommandBuilder(readClasses(classes)).build();
+    return ToolHelper.runR8(command);
+  }
+
+  /**
+   * Compile an application with R8.
+   */
   protected AndroidApp compileWithR8(List<Class> classes)
       throws CompilationException, ProguardRuleParserException, ExecutionException, IOException {
     R8Command command = ToolHelper.prepareR8CommandBuilder(readClasses(classes)).build();
@@ -122,6 +131,15 @@
   /**
    * Compile an application with R8 using the supplied proguard configuration.
    */
+  protected AndroidApp compileWithR8(
+      List<Class> classes, String proguardConfig, Consumer<InternalOptions> optionsConsumer)
+      throws CompilationException, ProguardRuleParserException, ExecutionException, IOException {
+    return compileWithR8(readClasses(classes), proguardConfig, optionsConsumer);
+  }
+
+  /**
+   * Compile an application with R8 using the supplied proguard configuration.
+   */
   protected AndroidApp compileWithR8(List<Class> classes, Path proguardConfig)
       throws CompilationException, ProguardRuleParserException, ExecutionException, IOException {
     return compileWithR8(readClasses(classes), proguardConfig);
@@ -143,6 +161,15 @@
    * Compile an application with R8 using the supplied proguard configuration.
    */
   protected AndroidApp compileWithR8(
+      AndroidApp app, String proguardConfig, Consumer<InternalOptions> optionsConsumer)
+      throws CompilationException, ProguardRuleParserException, ExecutionException, IOException {
+    return compileWithR8(app, writeTextToTempFile(proguardConfig), optionsConsumer);
+  }
+
+  /**
+   * Compile an application with R8 using the supplied proguard configuration.
+   */
+  protected AndroidApp compileWithR8(
       AndroidApp app, Path proguardConfig, Consumer<InternalOptions> optionsConsumer)
       throws CompilationException, ProguardRuleParserException, ExecutionException, IOException {
     R8Command command =
@@ -185,6 +212,22 @@
   }
 
   /**
+   * Run application on Art with the specified main class and provided arguments.
+   */
+  protected String runOnArt(AndroidApp app, Class mainClass, String... args) throws IOException {
+    Path out = File.createTempFile("junit", ".zip", temp.getRoot()).toPath();
+    app.writeToZip(out, OutputMode.Indexed, true);
+    return ToolHelper.runArtNoVerificationErrors(
+        ImmutableList.of(out.toString()), mainClass.getCanonicalName(),
+        builder -> {
+          builder.appendArtOption("-ea");
+          for (String arg : args) {
+            builder.appendProgramArgument(arg);
+          }
+        });
+  }
+
+  /**
    * Run a single class application on Java.
    */
   protected String runOnJava(Class mainClass) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/ClassWithAssertions.java b/src/test/java/com/android/tools/r8/rewrite/assertions/ClassWithAssertions.java
new file mode 100644
index 0000000..cc56790
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/ClassWithAssertions.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2017, 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.rewrite.assertions;
+
+public class ClassWithAssertions {
+  int x = 0;
+
+  ClassWithAssertions(int x) {
+    this.x = x;
+  }
+
+  boolean condition() {
+    return x == 1;
+  }
+
+  int getX() {
+    assert condition();
+    return x;
+  }
+
+  public static void main(String[] args) {
+    new ClassWithAssertions(Integer.parseInt(args[0])).getX();
+  }
+}
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
new file mode 100644
index 0000000..3c79bd3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/RemoveAssertionsTest.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2017, 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.rewrite.assertions;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.DexInspector.ClassSubject;
+import com.android.tools.r8.utils.DexInspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class RemoveAssertionsTest extends TestBase {
+
+  @Test
+  public void test() throws Exception {
+    // Run with R8, but avoid inlining to really validate that the methods "condition"
+    // and "<clinit>" are gone.
+    Class testClass = ClassWithAssertions.class;
+    AndroidApp app = compileWithR8(
+        ImmutableList.of(testClass),
+        keepMainProguardConfiguration(testClass, true, false),
+        options -> options.inlineAccessors = false);
+    DexInspector x = new DexInspector(app);
+
+    ClassSubject clazz = x.clazz(ClassWithAssertions.class);
+    assertTrue(clazz.isPresent());
+    MethodSubject conditionMethod =
+        clazz.method(new MethodSignature("condition", "boolean", new String[]{}));
+    assertTrue(!conditionMethod.isPresent());
+    MethodSubject clinit =
+        clazz.method(new MethodSignature(Constants.CLASS_INITIALIZER_NAME, "void", new String[]{}));
+    assertTrue(!clinit.isPresent());
+  }
+}