Side effect analysis for invoke-direct and new-instance instructions

Bug: 110196118, 114002137
Change-Id: I75e00d55b9c1f9c8de384a95f7bb3196a3713851
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 1f6b6ea..0a19d27 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -37,7 +37,6 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
@@ -361,8 +360,29 @@
           createString("makeConcat")
       );
 
+  public final Set<DexMethod> libraryMethodsReturningReceiver =
+      ImmutableSet.<DexMethod>builder()
+          .addAll(stringBufferMethods.appendMethods)
+          .addAll(stringBuilderMethods.appendMethods)
+          .build();
+
+  // Library methods listed here are based on their original implementations. That is, we assume
+  // these cannot be overridden.
+  public final Set<DexMethod> libraryMethodsReturningNonNull =
+      ImmutableSet.of(classMethods.getName, classMethods.getSimpleName, stringMethods.valueOf);
+
+  public Set<DexMethod> libraryMethodsWithoutSideEffects =
+      ImmutableSet.of(
+          objectMethods.constructor,
+          stringBufferMethods.constructor,
+          stringBuilderMethods.constructor);
+
+  public Set<DexType> libraryTypesAssumedToBePresent =
+      ImmutableSet.of(objectType, stringBufferType, stringBuilderType);
+
   public final Set<DexType> libraryTypesWithoutStaticInitialization =
-      ImmutableSet.of(iteratorType, serializableType);
+      ImmutableSet.of(
+          iteratorType, objectType, serializableType, stringBufferType, stringBuilderType);
 
   private boolean skipNameValidationForTesting = false;
 
@@ -716,7 +736,9 @@
     public final DexMethod appendObject;
     public final DexMethod appendString;
     public final DexMethod appendStringBuffer;
-    private final Set<DexMethod> appenders;
+    public final DexMethod constructor;
+
+    private final Set<DexMethod> appendMethods;
 
     private StringBuildingMethods(DexType receiver) {
       DexType sbufType = createType(createString("Ljava/lang/StringBuffer;"));
@@ -737,29 +759,27 @@
       appendObject = createMethod(receiver, createProto(receiver, objectType), append);
       appendString = createMethod(receiver, createProto(receiver, stringType), append);
       appendStringBuffer = createMethod(receiver, createProto(receiver, sbufType), append);
+      constructor = createMethod(receiver, createProto(voidType), constructorMethodName);
 
-      appenders = new HashSet<>();
-      appenders.add(appendBoolean);
-      appenders.add(appendChar);
-      appenders.add(appendCharArray);
-      appenders.add(appendSubCharArray);
-      appenders.add(appendCharSequence);
-      appenders.add(appendSubCharSequence);
-      appenders.add(appendInt);
-      appenders.add(appendDouble);
-      appenders.add(appendFloat);
-      appenders.add(appendLong);
-      appenders.add(appendObject);
-      appenders.add(appendString);
-      appenders.add(appendStringBuffer);
+      appendMethods =
+          ImmutableSet.of(
+              appendBoolean,
+              appendChar,
+              appendCharArray,
+              appendSubCharArray,
+              appendCharSequence,
+              appendSubCharSequence,
+              appendInt,
+              appendDouble,
+              appendFloat,
+              appendLong,
+              appendObject,
+              appendString,
+              appendStringBuffer);
     }
 
-    public boolean isAppend(DexMethod method) {
-      return appenders.contains(method);
-    }
-
-    public void forEachAppendMethod(Consumer<DexMethod> consumer) {
-      appenders.forEach(consumer);
+    public boolean isAppendMethod(DexMethod method) {
+      return appendMethods.contains(method);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index 462da0d..c9ba12e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -3,12 +3,15 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
+import static com.android.tools.r8.optimize.MemberRebindingAnalysis.isMemberVisibleFromOriginalContext;
+
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.code.InvokeDirectRange;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
@@ -20,9 +23,11 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Predicate;
 import org.objectweb.asm.Opcodes;
 
 public class InvokeDirect extends InvokeMethodWithReceiver {
@@ -135,4 +140,115 @@
     return ClassInitializationAnalysis.InstructionUtils.forInvokeDirect(
         this, clazz, appView, mode, assumption);
   }
+
+  @Override
+  public boolean instructionMayHaveSideEffects(
+      AppView<? extends AppInfo> appView, DexType context) {
+    if (!appView.enableWholeProgramOptimizations()) {
+      return true;
+    }
+
+    if (appView.options().debug) {
+      return true;
+    }
+
+    // Check if it could throw a NullPointerException as a result of the receiver being null.
+    Value receiver = getReceiver();
+    if (receiver.getTypeLattice().nullability().isNullable()) {
+      return true;
+    }
+
+    // Find the target and check if the invoke may have side effects.
+    if (appView.appInfo().hasLiveness()) {
+      AppInfoWithLiveness appInfoWithLiveness = appView.appInfo().withLiveness();
+      DexEncodedMethod target = lookupSingleTarget(appInfoWithLiveness, context);
+      if (target == null) {
+        return true;
+      }
+
+      // Verify that the target method is accessible in the current context.
+      if (!isMemberVisibleFromOriginalContext(
+          appInfoWithLiveness, context, target.method.holder, target.accessFlags)) {
+        return true;
+      }
+
+      // Verify that the target method does not have side-effects. For program methods, we use
+      // optimization info, and for library methods, we use modeling.
+      DexClass clazz = appView.definitionFor(target.method.holder);
+      if (clazz == null) {
+        assert false : "Expected to be able to find the enclosing class of a method definition";
+        return true;
+      }
+
+      boolean targetMayHaveSideEffects;
+      if (clazz.isProgramClass()) {
+        targetMayHaveSideEffects =
+            target.getOptimizationInfo().mayHaveSideEffects()
+                && !appInfoWithLiveness.noSideEffects.containsKey(target.method);
+      } else {
+        targetMayHaveSideEffects =
+            !appView.dexItemFactory().libraryMethodsWithoutSideEffects.contains(target.method);
+      }
+
+      if (targetMayHaveSideEffects) {
+        return true;
+      }
+
+      // Success, the instruction does not have any side effects.
+      return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public boolean canBeDeadCode(AppView<? extends AppInfo> appView, IRCode code) {
+    DexEncodedMethod method = code.method;
+    if (instructionMayHaveSideEffects(appView, method.method.holder)) {
+      return false;
+    }
+
+    if (appView.dexItemFactory().isConstructor(getInvokedMethod())) {
+      // If it is a constructor call that initializes an uninitialized object, then the
+      // uninitialized object must be dead. This is the case if all the constructor calls cannot
+      // have side effects and the instance is dead except for the constructor calls.
+      List<Instruction> otherInitCalls = null;
+      for (Instruction user : getReceiver().uniqueUsers()) {
+        if (user == this) {
+          continue;
+        }
+        if (user.isInvokeDirect()) {
+          InvokeDirect invoke = user.asInvokeDirect();
+          if (appView.dexItemFactory().isConstructor(invoke.getInvokedMethod())
+              && invoke.getReceiver() == getReceiver()) {
+            // If another constructor call than `this` is found, then it must not have side effects.
+            if (invoke.instructionMayHaveSideEffects(appView, method.method.holder)) {
+              return false;
+            }
+            if (otherInitCalls == null) {
+              otherInitCalls = new ArrayList<>();
+            }
+            otherInitCalls.add(invoke);
+          }
+        }
+      }
+
+      // Now check that the instance is dead except for the constructor calls.
+      final List<Instruction> finalOtherInitCalls = otherInitCalls;
+      Predicate<Instruction> ignoreConstructorCalls =
+          instruction ->
+              instruction == this
+                  || (finalOtherInitCalls != null && finalOtherInitCalls.contains(instruction));
+      if (!getReceiver().isDead(appView, code, ignoreConstructorCalls)) {
+        return false;
+      }
+
+      // Verify that it is not a super-constructor call (these cannot be removed).
+      if (getReceiver() == code.getThis()) {
+        return false;
+      }
+    }
+
+    return true;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index 13263d9..44397e1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -3,12 +3,15 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
+import static com.android.tools.r8.optimize.MemberRebindingAnalysis.isMemberVisibleFromOriginalContext;
+
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfNew;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
@@ -120,6 +123,50 @@
         this, clazz, appView, mode, assumption);
   }
 
+  @Override
+  public boolean instructionMayHaveSideEffects(
+      AppView<? extends AppInfo> appView, DexType context) {
+    if (!appView.enableWholeProgramOptimizations()) {
+      return true;
+    }
+
+    if (clazz.isPrimitiveType() || clazz.isArrayType()) {
+      assert false : "Unexpected new-instance instruction with primitive or array type";
+      return true;
+    }
+
+    DexClass definition = appView.definitionFor(clazz);
+    if (definition == null || definition.accessFlags.isAbstract()) {
+      return true;
+    }
+
+    if (definition.isLibraryClass()
+        && !appView.dexItemFactory().libraryTypesAssumedToBePresent.contains(clazz)) {
+      return true;
+    }
+
+    // Verify that the instruction does not lead to an IllegalAccessError.
+    if (!isMemberVisibleFromOriginalContext(
+        appView, context, definition.type, definition.accessFlags)) {
+      return true;
+    }
+
+    // Verify that the new-instance instruction won't lead to class initialization.
+    if (definition.classInitializationMayHaveSideEffects(
+        appView,
+        // Types that are a super type of `context` are guaranteed to be initialized already.
+        type -> context.isSubtypeOf(type, appView))) {
+      return true;
+    }
+
+    return false;
+  }
+
+  @Override
+  public boolean canBeDeadCode(AppView<? extends AppInfo> appView, IRCode code) {
+    return !instructionMayHaveSideEffects(appView, code.method.method.holder);
+  }
+
   public void markNoSpilling() {
     allowSpilling = 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 9cbdd34..02b393d 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
@@ -16,6 +16,7 @@
 import com.android.tools.r8.utils.LongInterval;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringDiagnostic;
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import it.unimi.dsi.fastutil.ints.IntList;
@@ -29,6 +30,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.function.Predicate;
 
 public class Value {
 
@@ -849,10 +851,30 @@
 
   public boolean isDead(AppView<? extends AppInfo> appView, IRCode code) {
     // Totally unused values are trivially dead.
-    return !isUsed() || isDead(appView, code, new HashSet<>());
+    return !isUsed() || isDead(appView, code, Predicates.alwaysFalse());
   }
 
-  protected boolean isDead(AppView<? extends AppInfo> appView, IRCode code, Set<Value> active) {
+  public boolean isDead(
+      AppView<? extends AppInfo> appView, IRCode code, Predicate<Instruction> ignoreUser) {
+    // Totally unused values are trivially dead.
+    return !isUsed() || isDead(appView, code, ignoreUser, new HashSet<>());
+  }
+
+  /**
+   * Used to determine if a given value is dead.
+   *
+   * <p>The predicate `ignoreUser` can be used to determine if a given value is dead under the
+   * assumption that the instructions for which `ignoreUser` returns true are also dead.
+   *
+   * <p>One use case of this is when we attempt to determine if a call to {@code <init>()} can be
+   * removed: calls to {@code <init>()} can only be removed if the receiver is dead except for the
+   * constructor call.
+   */
+  protected boolean isDead(
+      AppView<? extends AppInfo> appView,
+      IRCode code,
+      Predicate<Instruction> ignoreUser,
+      Set<Value> active) {
     // Give up when the dependent set of values reach a given threshold (otherwise this fails with
     // a StackOverflowError on Art003_omnibus_opcodesTest).
     if (active.size() > 100) {
@@ -868,18 +890,21 @@
     // currently active values.
     active.add(this);
     for (Instruction instruction : uniqueUsers()) {
+      if (ignoreUser.test(instruction)) {
+        continue;
+      }
       if (!instruction.canBeDeadCode(appView, code)) {
         return false;
       }
       Value outValue = instruction.outValue();
       if (outValue != null
           && !active.contains(outValue)
-          && !outValue.isDead(appView, code, active)) {
+          && !outValue.isDead(appView, code, ignoreUser, active)) {
         return false;
       }
     }
     for (Phi phi : uniquePhiUsers()) {
-      if (!active.contains(phi) && !phi.isDead(appView, code, active)) {
+      if (!active.contains(phi) && !phi.isDead(appView, code, ignoreUser, active)) {
         return false;
       }
     }
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 af6da48..9cbe2e7 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
@@ -9,6 +9,7 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfo.ResolutionResult;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Code;
@@ -81,7 +82,6 @@
 import com.google.common.base.Predicates;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Sets;
 import com.google.common.collect.Streams;
@@ -89,7 +89,6 @@
 import java.util.BitSet;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -167,7 +166,7 @@
     this.rootSet = rootSet;
     this.printer = printer;
     this.mainDexClasses = mainDexClasses.getClasses();
-    this.codeRewriter = new CodeRewriter(appView, this, libraryMethodsReturningReceiver());
+    this.codeRewriter = new CodeRewriter(appView, this);
     this.classInitializerDefaultsOptimization =
         options.debug ? null : new ClassInitializerDefaultsOptimization(appView, this);
     this.stringConcatRewriter = new StringConcatRewriter(appView);
@@ -190,11 +189,7 @@
             ? new CovariantReturnTypeAnnotationTransformer(this, appView.dexItemFactory())
             : null;
     this.stringOptimizer = new StringOptimizer(appView);
-    this.nonNullTracker =
-        options.enableNonNullTracking
-            ? new NonNullTracker(
-                appView, libraryMethodsReturningNonNull(appView.dexItemFactory()))
-            : null;
+    this.nonNullTracker = options.enableNonNullTracking ? new NonNullTracker(appView) : null;
     if (appView.enableWholeProgramOptimizations()) {
       assert appView.appInfo().hasLiveness();
       AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
@@ -274,24 +269,6 @@
     throw new Unreachable();
   }
 
-  private Set<DexMethod> libraryMethodsReturningReceiver() {
-    Set<DexMethod> methods = new HashSet<>();
-    DexItemFactory dexItemFactory = appView.dexItemFactory();
-    dexItemFactory.stringBufferMethods.forEachAppendMethod(methods::add);
-    dexItemFactory.stringBuilderMethods.forEachAppendMethod(methods::add);
-    return methods;
-  }
-
-  // Library methods listed here are based on their original implementations. That is, we assume
-  // these cannot be overridden.
-  public static Set<DexMethod> libraryMethodsReturningNonNull(DexItemFactory factory) {
-    return ImmutableSet.of(
-        factory.stringMethods.valueOf,
-        factory.classMethods.getName,
-        factory.classMethods.getSimpleName
-    );
-  }
-
   private boolean removeLambdaDeserializationMethods() {
     if (lambdaRewriter != null) {
       return lambdaRewriter.removeLambdaDeserializationMethods(appView.appInfo().classes());
@@ -1189,6 +1166,8 @@
       boolean mayHaveSideEffects =
           // If the method is synchronized then it acquires a lock.
           method.accessFlags.isSynchronized()
+              || (appView.dexItemFactory().isConstructor(method.method)
+                  && hasNonTrivialFinalizeMethod(method.method.holder))
               || Streams.stream(code.instructions())
                   .anyMatch(
                       instruction ->
@@ -1199,6 +1178,30 @@
     }
   }
 
+  // Returns true if `method` is an initializer and the enclosing class overrides the method
+  // `void java.lang.Object.finalize()`.
+  private boolean hasNonTrivialFinalizeMethod(DexType type) {
+    DexClass clazz = appView.definitionFor(type);
+    if (clazz != null) {
+      if (clazz.isProgramClass()) {
+        ResolutionResult resolutionResult =
+            appView
+                .appInfo()
+                .resolveMethodOnClass(type, appView.dexItemFactory().objectMethods.finalize);
+        for (DexEncodedMethod target : resolutionResult.asListOfTargets()) {
+          if (target.method != appView.dexItemFactory().objectMethods.finalize) {
+            return true;
+          }
+        }
+        return false;
+      } else {
+        // Conservatively report that the library class could implement finalize().
+        return true;
+      }
+    }
+    return false;
+  }
+
   private void finalizeIR(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
     code.traceBlocks();
     if (options.isGeneratingClassFiles()) {
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 c3b080a..b322460 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
@@ -155,18 +155,13 @@
 
   private final AppView<? extends AppInfo> appView;
   private final DexItemFactory dexItemFactory;
-  private final Set<DexMethod> libraryMethodsReturningReceiver;
   private final InternalOptions options;
 
-  public CodeRewriter(
-      AppView<? extends AppInfo> appView,
-      IRConverter converter,
-      Set<DexMethod> libraryMethodsReturningReceiver) {
+  public CodeRewriter(AppView<? extends AppInfo> appView, IRConverter converter) {
     this.appView = appView;
     this.converter = converter;
     this.options = appView.options();
     this.dexItemFactory = appView.dexItemFactory();
-    this.libraryMethodsReturningReceiver = libraryMethodsReturningReceiver;
   }
 
   private static boolean removedTrivialGotos(IRCode code) {
@@ -1641,7 +1636,10 @@
             // and move it to iterator.
           }
         } else if (outValue != null && !outValue.hasLocalInfo()) {
-          if (libraryMethodsReturningReceiver.contains(invoke.getInvokedMethod())) {
+          if (appView
+              .dexItemFactory()
+              .libraryMethodsReturningReceiver
+              .contains(invoke.getInvokedMethod())) {
             if (checkArgumentType(invoke, 0)) {
               outValue.replaceUsers(invoke.arguments().get(0));
               invoke.setOutValue(null);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index aa90c7f..2bb6e8d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -17,7 +17,6 @@
 import com.android.tools.r8.ir.code.InvokeStatic;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.conversion.CallSiteInformation;
-import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
 import com.android.tools.r8.ir.optimize.Inliner.InlineeWithReason;
 import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -457,9 +456,7 @@
       assert IteratorUtils.peekNext(blockIterator) == block;
 
       // Kick off the tracker to add non-null IRs only to the inlinee blocks.
-      new NonNullTracker(
-              appView, IRConverter.libraryMethodsReturningNonNull(appView.dexItemFactory()))
-          .addNonNullInPart(code, blockIterator, inlinee.blocks::contains);
+      new NonNullTracker(appView).addNonNullInPart(code, blockIterator, inlinee.blocks::contains);
       assert !blockIterator.hasNext();
 
       // Restore the old state of the iterator.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
index 489891a..114e63c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
@@ -42,13 +42,9 @@
 public class NonNullTracker {
 
   private final AppView<? extends AppInfo> appView;
-  private final Set<DexMethod> libraryMethodsReturningNonNull;
 
-  public NonNullTracker(
-      AppView<? extends AppInfo> appView,
-      Set<DexMethod> libraryMethodsReturningNonNull) {
+  public NonNullTracker(AppView<? extends AppInfo> appView) {
     this.appView = appView;
-    this.libraryMethodsReturningNonNull = libraryMethodsReturningNonNull;
   }
 
   @VisibleForTesting
@@ -102,8 +98,10 @@
       while (iterator.hasNext()) {
         Instruction current = iterator.next();
         if (current.isInvokeMethod()
-            && libraryMethodsReturningNonNull.contains(
-                current.asInvokeMethod().getInvokedMethod())) {
+            && appView
+                .dexItemFactory()
+                .libraryMethodsReturningNonNull
+                .contains(current.asInvokeMethod().getInvokedMethod())) {
           Value knownToBeNonNullValue = current.outValue();
           // Avoid adding redundant non-null instruction.
           // Otherwise, we will have something like:
diff --git a/src/test/java/com/android/tools/r8/AssumeMayHaveSideEffects.java b/src/test/java/com/android/tools/r8/AssumeMayHaveSideEffects.java
index 181422f..260d36b 100644
--- a/src/test/java/com/android/tools/r8/AssumeMayHaveSideEffects.java
+++ b/src/test/java/com/android/tools/r8/AssumeMayHaveSideEffects.java
@@ -6,5 +6,5 @@
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Target;
 
-@Target({ElementType.METHOD})
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
 public @interface AssumeMayHaveSideEffects {}
diff --git a/src/test/java/com/android/tools/r8/KotlinTestBase.java b/src/test/java/com/android/tools/r8/KotlinTestBase.java
index 9139583..a728201 100644
--- a/src/test/java/com/android/tools/r8/KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/KotlinTestBase.java
@@ -9,6 +9,13 @@
 import java.nio.file.Paths;
 
 public abstract class KotlinTestBase extends TestBase {
+
+  public static final String checkParameterIsNotNullSignature =
+      "void kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull("
+          + "java.lang.Object, java.lang.String)";
+  public static final String throwParameterIsNotNullExceptionSignature =
+      "void kotlin.jvm.internal.Intrinsics.throwParameterIsNullException(java.lang.String)";
+
   private static final String RSRC = "kotlinR8TestResources";
 
   protected final KotlinTargetVersion targetVersion;
diff --git a/src/test/java/com/android/tools/r8/R8CompatTestBuilder.java b/src/test/java/com/android/tools/r8/R8CompatTestBuilder.java
new file mode 100644
index 0000000..43f1ffa
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/R8CompatTestBuilder.java
@@ -0,0 +1,34 @@
+// 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.R8Command.Builder;
+import com.android.tools.r8.TestBase.Backend;
+import java.nio.file.Path;
+
+public class R8CompatTestBuilder extends R8TestBuilder<R8CompatTestBuilder> {
+
+  private R8CompatTestBuilder(TestState state, Builder builder, Backend backend) {
+    super(state, builder, backend);
+  }
+
+  public static R8CompatTestBuilder create(
+      TestState state, Backend backend, boolean forceProguardCompatibility) {
+    CompatProguardCommandBuilder builder =
+        new CompatProguardCommandBuilder(forceProguardCompatibility, state.getDiagnosticsHandler());
+    return new R8CompatTestBuilder(state, builder, backend);
+  }
+
+  public R8CompatTestBuilder setProguardCompatibilityRulesOutput(
+      Path proguardCompatibilityRulesOutput) {
+    assert builder.proguardCompatibilityRulesOutput == null;
+    builder.proguardCompatibilityRulesOutput = proguardCompatibilityRulesOutput;
+    return self();
+  }
+
+  @Override
+  R8CompatTestBuilder self() {
+    return this;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/R8FullTestBuilder.java b/src/test/java/com/android/tools/r8/R8FullTestBuilder.java
new file mode 100644
index 0000000..7e41239
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/R8FullTestBuilder.java
@@ -0,0 +1,24 @@
+// 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.R8Command.Builder;
+import com.android.tools.r8.TestBase.Backend;
+
+public class R8FullTestBuilder extends R8TestBuilder<R8FullTestBuilder> {
+
+  private R8FullTestBuilder(TestState state, Builder builder, Backend backend) {
+    super(state, builder, backend);
+  }
+
+  public static R8FullTestBuilder create(TestState state, Backend backend) {
+    Builder builder = R8Command.builder(state.getDiagnosticsHandler());
+    return new R8FullTestBuilder(state, builder, backend);
+  }
+
+  @Override
+  R8FullTestBuilder self() {
+    return this;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 71d2101..47c3e99 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -1126,6 +1126,8 @@
       "958-methodhandle-stackframe"
   );
 
+  private static Map<String, List<String>> keepRules = ImmutableMap.of();
+
   private static List<String> failuresToTriage = ImmutableList.of(
       // Dex file input into a jar file, not yet supported by the test framework.
       "663-odd-dex-size",
@@ -1212,6 +1214,8 @@
     private final boolean hasMissingClasses;
     // Explicitly disable desugaring.
     private final boolean disableDesugaring;
+    // Extra keep rules to use when running with R8.
+    private final List<String> keepRules;
 
     TestSpecification(
         String name,
@@ -1230,7 +1234,8 @@
         boolean disableClassInlining,
         boolean disableUninstantiatedTypeOptimization,
         boolean hasMissingClasses,
-        boolean disableDesugaring) {
+        boolean disableDesugaring,
+        List<String> keepRules) {
       this.name = name;
       this.dexTool = dexTool;
       this.nativeLibrary = nativeLibrary;
@@ -1248,6 +1253,7 @@
       this.disableUninstantiatedTypeOptimization = disableUninstantiatedTypeOptimization;
       this.hasMissingClasses = hasMissingClasses;
       this.disableDesugaring = disableDesugaring;
+      this.keepRules = keepRules;
     }
 
     TestSpecification(
@@ -1275,8 +1281,8 @@
           true, // Disable class inlining for JCTF tests.
           false,
           false,
-          true // Disable desugaring for JCTF tests.
-      );
+          true, // Disable desugaring for JCTF tests.
+          ImmutableList.of());
     }
 
     TestSpecification(
@@ -1303,8 +1309,8 @@
           true, // Disable class inlining for JCTF tests.
           false,
           false,
-          true // Disable desugaring for JCTF tests.
-      );
+          true, // Disable desugaring for JCTF tests.
+          ImmutableList.of());
     }
 
     public File resolveFile(String name) {
@@ -1468,7 +1474,8 @@
                 requireClassInliningToBeDisabled.contains(name),
                 requireUninstantiatedTypeOptimizationToBeDisabled.contains(name),
                 hasMissingClasses.contains(name),
-                false));
+                false,
+                keepRules.getOrDefault(name, ImmutableList.of())));
       }
     }
     return data;
@@ -1537,6 +1544,7 @@
     private final boolean disableUninstantiatedTypeOptimization;
     private final boolean hasMissingClasses;
     private final boolean disableDesugaring;
+    private final List<String> keepRules;
 
     private CompilationOptions(TestSpecification spec) {
       this.disableInlining = spec.disableInlining;
@@ -1544,6 +1552,7 @@
       this.disableUninstantiatedTypeOptimization = spec.disableUninstantiatedTypeOptimization;
       this.hasMissingClasses = spec.hasMissingClasses;
       this.disableDesugaring = spec.disableDesugaring;
+      this.keepRules = spec.keepRules;
     }
 
     @Override
@@ -1715,9 +1724,11 @@
                   .setDisableMinification(true)
                   .setDisableDesugaring(compilationOptions.disableDesugaring)
                   .addProguardConfiguration(ImmutableList.of("-keepattributes *"), Origin.unknown())
+                  .addProguardConfiguration(compilationOptions.keepRules, Origin.unknown())
                   .setOutput(
                       Paths.get(resultPath),
                       cfBackend ? OutputMode.ClassFile : OutputMode.DexIndexed);
+          ToolHelper.allowTestProguardOptions(builder);
           // Add program files directly to the underlying app to avoid errors on DEX inputs.
           ToolHelper.getAppBuilder(builder).addProgramFiles(ListUtils.map(fileNames, Paths::get));
           if (cfBackend) {
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index bb3d9cd..0c441a5 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -5,7 +5,6 @@
 
 import com.android.tools.r8.R8Command.Builder;
 import com.android.tools.r8.TestBase.Backend;
-import com.android.tools.r8.TestBase.R8Mode;
 import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.CollectingGraphConsumer;
@@ -25,22 +24,13 @@
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
-public class R8TestBuilder
-    extends TestShrinkerBuilder<
-        R8Command, Builder, R8TestCompileResult, R8TestRunResult, R8TestBuilder> {
+public abstract class R8TestBuilder<T extends R8TestBuilder<T>>
+    extends TestShrinkerBuilder<R8Command, Builder, R8TestCompileResult, R8TestRunResult, T> {
 
-  private R8TestBuilder(TestState state, Builder builder, Backend backend) {
+  R8TestBuilder(TestState state, Builder builder, Backend backend) {
     super(state, builder, backend);
   }
 
-  public static R8TestBuilder create(TestState state, Backend backend, R8Mode mode) {
-    R8Command.Builder builder =
-        mode == R8Mode.Full
-            ? R8Command.builder(state.getDiagnosticsHandler())
-            : new CompatProguardCommandBuilder(true, state.getDiagnosticsHandler());
-    return new R8TestBuilder(state, builder, backend);
-  }
-
   private boolean enableInliningAnnotations = false;
   private boolean enableClassInliningAnnotations = false;
   private boolean enableMergeAnnotations = false;
@@ -54,11 +44,6 @@
   private List<String> applyMappingMaps = new ArrayList<>();
 
   @Override
-  R8TestBuilder self() {
-    return this;
-  }
-
-  @Override
   R8TestCompileResult internalCompile(
       Builder builder, Consumer<InternalOptions> optionsConsumer, Supplier<AndroidApp> app)
       throws CompilationFailedException {
@@ -117,73 +102,73 @@
   }
 
   @Override
-  public R8TestBuilder addClasspathClasses(Collection<Class<?>> classes) {
+  public T addClasspathClasses(Collection<Class<?>> classes) {
     builder.addClasspathResourceProvider(ClassFileResourceProviderFromClasses(classes));
     return self();
   }
 
   @Override
-  public R8TestBuilder addClasspathFiles(Collection<Path> files) {
+  public T addClasspathFiles(Collection<Path> files) {
     builder.addClasspathFiles(files);
     return self();
   }
 
-  public R8TestBuilder addDataResources(List<DataEntryResource> resources) {
+  public T addDataResources(List<DataEntryResource> resources) {
     resources.forEach(builder.getAppBuilder()::addDataResource);
     return self();
   }
 
   @Override
-  public R8TestBuilder addDataEntryResources(DataEntryResource... resources) {
+  public T addDataEntryResources(DataEntryResource... resources) {
     return addDataResources(Arrays.asList(resources));
   }
 
   @Override
-  public R8TestBuilder addKeepRuleFiles(List<Path> files) {
+  public T addKeepRuleFiles(List<Path> files) {
     builder.addProguardConfigurationFiles(files);
     return self();
   }
 
   @Override
-  public R8TestBuilder addKeepRules(Collection<String> rules) {
+  public T addKeepRules(Collection<String> rules) {
     // Delay adding the actual rules so that we only associate a single origin and unique lines to
     // each actual rule.
     keepRules.addAll(rules);
     return self();
   }
 
-  public R8TestBuilder addMainDexRules(Collection<String> rules) {
+  public T addMainDexRules(Collection<String> rules) {
     builder.addMainDexRules(new ArrayList<>(rules), Origin.unknown());
     return self();
   }
 
-  public R8TestBuilder addMainDexRules(String... rules) {
+  public T addMainDexRules(String... rules) {
     return addMainDexRules(Arrays.asList(rules));
   }
 
-  public R8TestBuilder addMainDexRuleFiles(List<Path> files) {
+  public T addMainDexRuleFiles(List<Path> files) {
     mainDexRulesFiles.addAll(files);
     return self();
   }
 
-  public R8TestBuilder addMainDexRuleFiles(Path... files) {
+  public T addMainDexRuleFiles(Path... files) {
     return addMainDexRuleFiles(Arrays.asList(files));
   }
 
-  public R8TestBuilder addMainDexClassRules(Class<?>... classes) {
+  public T addMainDexClassRules(Class<?>... classes) {
     for (Class<?> clazz : classes) {
       addMainDexRules("-keep class " + clazz.getTypeName());
     }
     return self();
   }
 
-  public R8TestBuilder addMainDexListClasses(Class<?>... classes) {
+  public T addMainDexListClasses(Class<?>... classes) {
     builder.addMainDexClasses(
         Arrays.stream(classes).map(Class::getTypeName).collect(Collectors.toList()));
     return self();
   }
 
-  public R8TestBuilder enableInliningAnnotations() {
+  public T enableInliningAnnotations() {
     if (!enableInliningAnnotations) {
       enableInliningAnnotations = true;
       addInternalKeepRules(
@@ -193,7 +178,7 @@
     return self();
   }
 
-  public R8TestBuilder enableClassInliningAnnotations() {
+  public T enableClassInliningAnnotations() {
     if (!enableClassInliningAnnotations) {
       enableClassInliningAnnotations = true;
       addInternalKeepRules("-neverclassinline @com.android.tools.r8.NeverClassInline class *");
@@ -201,7 +186,7 @@
     return self();
   }
 
-  public R8TestBuilder enableMergeAnnotations() {
+  public T enableMergeAnnotations() {
     if (!enableMergeAnnotations) {
       enableMergeAnnotations = true;
       addInternalKeepRules("-nevermerge @com.android.tools.r8.NeverMerge class *");
@@ -209,7 +194,7 @@
     return self();
   }
 
-  public R8TestBuilder enableMemberValuePropagationAnnotations() {
+  public T enableMemberValuePropagationAnnotations() {
     if (!enableMemberValuePropagationAnnotations) {
       enableMemberValuePropagationAnnotations = true;
       addInternalKeepRules(
@@ -218,7 +203,7 @@
     return self();
   }
 
-  public R8TestBuilder enableSideEffectAnnotations() {
+  public T enableSideEffectAnnotations() {
     if (!enableSideEffectAnnotations) {
       enableSideEffectAnnotations = true;
       addInternalKeepRules(
@@ -229,7 +214,7 @@
     return self();
   }
 
-  public R8TestBuilder assumeAllMethodsMayHaveSideEffects() {
+  public T assumeAllMethodsMayHaveSideEffects() {
     if (!enableSideEffectAnnotations) {
       enableSideEffectAnnotations = true;
       addInternalKeepRules("-assumemayhavesideeffects class * { <methods>; }");
@@ -237,7 +222,7 @@
     return self();
   }
 
-  public R8TestBuilder enableConstantArgumentAnnotations() {
+  public T enableConstantArgumentAnnotations() {
     if (!enableConstantArgumentAnnotations) {
       enableConstantArgumentAnnotations = true;
       addInternalKeepRules(
@@ -246,7 +231,7 @@
     return self();
   }
 
-  public R8TestBuilder enableUnusedArgumentAnnotations() {
+  public T enableUnusedArgumentAnnotations() {
     if (!enableUnusedArgumentAnnotations) {
       enableUnusedArgumentAnnotations = true;
       addInternalKeepRules(
@@ -255,35 +240,35 @@
     return self();
   }
 
-  public R8TestBuilder enableProguardTestOptions() {
+  public T enableProguardTestOptions() {
     builder.allowTestProguardOptions();
     return self();
   }
 
-  public R8TestBuilder enableGraphInspector() {
+  public T enableGraphInspector() {
     return enableGraphInspector(null);
   }
 
-  public R8TestBuilder enableGraphInspector(GraphConsumer subConsumer) {
+  public T enableGraphInspector(GraphConsumer subConsumer) {
     CollectingGraphConsumer consumer = new CollectingGraphConsumer(subConsumer);
     setKeptGraphConsumer(consumer);
     graphConsumer = consumer;
     return self();
   }
 
-  public R8TestBuilder setKeptGraphConsumer(GraphConsumer graphConsumer) {
+  public T setKeptGraphConsumer(GraphConsumer graphConsumer) {
     assert this.graphConsumer == null;
     builder.setKeptGraphConsumer(graphConsumer);
     return self();
   }
 
-  public R8TestBuilder setMainDexKeptGraphConsumer(GraphConsumer graphConsumer) {
+  public T setMainDexKeptGraphConsumer(GraphConsumer graphConsumer) {
     builder.setMainDexKeptGraphConsumer(graphConsumer);
     return self();
   }
 
   @Override
-  public R8TestBuilder addApplyMapping(String proguardMap) {
+  public T addApplyMapping(String proguardMap) {
     applyMappingMaps.add(proguardMap);
     return self();
   }
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index ddb9861..8cf70a9 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -81,17 +81,13 @@
     DEX
   }
 
-  public enum R8Mode {
-    Full,
-    Compat
+  public static R8FullTestBuilder testForR8(TemporaryFolder temp, Backend backend) {
+    return R8FullTestBuilder.create(new TestState(temp), backend);
   }
 
-  public static R8TestBuilder testForR8(TemporaryFolder temp, Backend backend) {
-    return R8TestBuilder.create(new TestState(temp), backend, R8Mode.Full);
-  }
-
-  public static R8TestBuilder testForR8Compat(TemporaryFolder temp, Backend backend) {
-    return R8TestBuilder.create(new TestState(temp), backend, R8Mode.Compat);
+  public static R8CompatTestBuilder testForR8Compat(
+      TemporaryFolder temp, Backend backend, boolean forceProguardCompatibility) {
+    return R8CompatTestBuilder.create(new TestState(temp), backend, forceProguardCompatibility);
   }
 
   public static ExternalR8TestBuilder testForExternalR8(TemporaryFolder temp, Backend backend) {
@@ -118,12 +114,16 @@
     return GenerateMainDexListTestBuilder.create(new TestState(temp));
   }
 
-  public R8TestBuilder testForR8(Backend backend) {
+  public R8FullTestBuilder testForR8(Backend backend) {
     return testForR8(temp, backend);
   }
 
-  public R8TestBuilder testForR8Compat(Backend backend) {
-    return testForR8Compat(temp, backend);
+  public R8CompatTestBuilder testForR8Compat(Backend backend) {
+    return testForR8Compat(backend, true);
+  }
+
+  public R8CompatTestBuilder testForR8Compat(Backend backend, boolean forceProguardCompatibility) {
+    return testForR8Compat(temp, backend, forceProguardCompatibility);
   }
 
   public ExternalR8TestBuilder testForExternalR8(Backend backend) {
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
index e99a3d4..0c64040 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/NonConstructorRelaxationTest.java
@@ -155,6 +155,7 @@
             .addProgramFiles(ToolHelper.getClassFilesForTestPackage(mainClass.getPackage()))
             .addOptionsModification(o -> o.enableVerticalClassMerging = enableVerticalClassMerging)
             .enableInliningAnnotations()
+            .enableMemberValuePropagationAnnotations()
             .noMinification()
             .addKeepRules(
                 "-keep class " + mainClass.getCanonicalName() + "{",
@@ -173,9 +174,8 @@
                 "  *** p*();",
                 "}",
                 "",
-                "-allowaccessmodification"
-            )
-        .run(mainClass);
+                "-allowaccessmodification")
+            .run(mainClass);
 
     assertEquals(
         expectedOutput,
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Base.java b/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Base.java
index 130ba9a..4f5becc 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Base.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/privateinstance/Base.java
@@ -4,9 +4,11 @@
 package com.android.tools.r8.accessrelaxation.privateinstance;
 
 import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverPropagateValue;
 
 public class Base {
 
+  @NeverPropagateValue
   @NeverInline
   private String foo() {
     return "Base::foo()";
@@ -16,6 +18,7 @@
     return foo();
   }
 
+  @NeverPropagateValue
   @NeverInline
   private String foo1() {
     return "Base::foo1()";
@@ -25,6 +28,7 @@
     return foo1();
   }
 
+  @NeverPropagateValue
   @NeverInline
   private String foo2() {
     return "Base::foo2()";
@@ -34,10 +38,10 @@
     return foo2();
   }
 
+  @NeverInline
   public void dump() {
     System.out.println(foo());
     System.out.println(foo1());
     System.out.println(foo2());
   }
-
 }
diff --git a/src/test/java/com/android/tools/r8/cf/CloserTestRunner.java b/src/test/java/com/android/tools/r8/cf/CloserTestRunner.java
index cac41cc..bce6ae0 100644
--- a/src/test/java/com/android/tools/r8/cf/CloserTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/CloserTestRunner.java
@@ -44,7 +44,7 @@
         .addProgramClasses(CloserTest.class)
         .addKeepMainRule(CloserTest.class)
         .setMode(CompilationMode.RELEASE)
-        .minification(false)
+        .noMinification()
         .noTreeShaking()
         .enableInliningAnnotations()
         .compile()
diff --git a/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java b/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java
index ebae273..75a8b55 100644
--- a/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/DebugInfoTestRunner.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.cf;
 
-import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import java.nio.file.Path;
@@ -49,7 +49,7 @@
     }
   }
 
-  private R8TestBuilder builder() {
+  private R8FullTestBuilder builder() {
     return testForR8(backend)
         .debug()
         .noTreeShaking()
diff --git a/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java b/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java
index 6ecb4de..fd3245f 100644
--- a/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java
@@ -8,7 +8,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.R8CompatTestBuilder;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -54,7 +54,7 @@
   private void test(boolean keepRule)
       throws IOException, CompilationFailedException, ExecutionException {
     Class testClass = parameters.isCfRuntime() ? TEST_CLASS_CF : TEST_CLASS_DEX;
-    R8TestBuilder builder =
+    R8CompatTestBuilder builder =
         testForR8Compat(parameters.getBackend())
             .addProgramClasses(
                 com.android.tools.r8.cf.KeepDeserializeLambdaMethodTest.class, testClass)
diff --git a/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java b/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java
index b730618..f22aa2e 100644
--- a/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/TryRangeTestRunner.java
@@ -38,13 +38,10 @@
         .addProgramClasses(TryRangeTest.class)
         .addKeepMainRule(TryRangeTest.class)
         .setMode(CompilationMode.RELEASE)
-        .minification(false)
+        .noMinification()
         .noTreeShaking()
         .enableInliningAnnotations()
-        .addOptionsModification(
-            o -> {
-              o.testing.disallowLoadStoreOptimization = true;
-            })
+        .addOptionsModification(o -> o.testing.disallowLoadStoreOptimization = true)
         .run(TryRangeTest.class)
         .assertSuccessWithOutput(StringUtils.lines("10", "7.0"));
   }
@@ -56,7 +53,7 @@
             .addProgramClasses(TryRangeTestLimitRange.class)
             .addKeepMainRule(TryRangeTestLimitRange.class)
             .setMode(CompilationMode.RELEASE)
-            .minification(false)
+            .noMinification()
             .noTreeShaking()
             .enableInliningAnnotations()
             .addOptionsModification(
diff --git a/src/test/java/com/android/tools/r8/deadcode/RemoveDeadBuildersTest.java b/src/test/java/com/android/tools/r8/deadcode/RemoveDeadBuildersTest.java
new file mode 100644
index 0000000..11422fd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/deadcode/RemoveDeadBuildersTest.java
@@ -0,0 +1,61 @@
+// 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.deadcode;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+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.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+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 RemoveDeadBuildersTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().build();
+  }
+
+  public RemoveDeadBuildersTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    CodeInspector inspector =
+        testForR8(parameters.getBackend())
+            .addProgramClasses(TestClass.class)
+            .addKeepMainRule(TestClass.class)
+            .compile()
+            .inspector();
+
+    ClassSubject classSubject = inspector.clazz(TestClass.class);
+    assertThat(classSubject, isPresent());
+
+    MethodSubject methodSubject = classSubject.mainMethod();
+    assertThat(methodSubject, isPresent());
+    assertTrue(methodSubject.streamInstructions().noneMatch(InstructionSubject::isNewInstance));
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      new StringBuffer();
+      new StringBuilder();
+    }
+  }
+}
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 66fa712..785487a 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
@@ -37,7 +37,6 @@
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
 import java.util.Map;
 import java.util.function.BiConsumer;
 import org.junit.Test;
@@ -54,8 +53,7 @@
     MethodSubject fooSubject = codeInspector.clazz(mainClass.getName()).method(signature);
     DexEncodedMethod foo = codeInspector.clazz(mainClass.getName()).method(signature).getMethod();
     IRCode irCode = fooSubject.buildIR();
-    NonNullTracker nonNullTracker = new NonNullTracker(appView, ImmutableSet.of());
-    nonNullTracker.addNonNull(irCode);
+    new NonNullTracker(appView).addNonNull(irCode);
     TypeAnalysis analysis = new TypeAnalysis(appView, foo);
     analysis.widening(foo, irCode);
     inspector.accept(appView.appInfo(), irCode);
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 69e16ba..e971cc1 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
@@ -22,7 +22,6 @@
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.google.common.collect.ImmutableSet;
 import java.util.function.Consumer;
 import org.junit.Test;
 
@@ -40,7 +39,7 @@
     IRCode irCode = fooSubject.buildIR();
     checkCountOfNonNull(irCode, 0);
 
-    NonNullTracker nonNullTracker = new NonNullTracker(appView, ImmutableSet.of());
+    NonNullTracker nonNullTracker = new NonNullTracker(appView);
 
     nonNullTracker.addNonNull(irCode);
     assertTrue(irCode.isConsistentSSA());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java
index 5a033cd..6d9142a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerTest.java
@@ -93,15 +93,16 @@
         ClassWithFinal.class
     };
     String javaOutput = runOnJava(main);
-    TestRunResult result = testForR8(backend)
-        .addProgramClasses(classes)
-        .enableInliningAnnotations()
-        .addKeepMainRule(main)
-        .addKeepRules(
-            "-dontobfuscate", "-allowaccessmodification", "-keepattributes LineNumberTable")
-        .addOptionsModification(this::configure)
-        .run(main)
-        .assertSuccessWithOutput(javaOutput);
+    TestRunResult result =
+        testForR8(backend)
+            .addProgramClasses(classes)
+            .enableInliningAnnotations()
+            .addKeepMainRule(main)
+            .addKeepRules("-allowaccessmodification", "-keepattributes LineNumberTable")
+            .addOptionsModification(this::configure)
+            .noMinification()
+            .run(main)
+            .assertSuccessWithOutput(javaOutput);
 
     CodeInspector inspector = result.inspector();
     ClassSubject clazz = inspector.clazz(main);
@@ -172,15 +173,16 @@
         ControlFlow.class,
     };
     String javaOutput = runOnJava(main);
-    TestRunResult result = testForR8(backend)
-        .addProgramClasses(classes)
-        .enableInliningAnnotations()
-        .addKeepMainRule(main)
-        .addKeepRules(
-            "-dontobfuscate", "-allowaccessmodification", "-keepattributes LineNumberTable")
-        .addOptionsModification(this::configure)
-        .run(main)
-        .assertSuccessWithOutput(javaOutput);
+    TestRunResult result =
+        testForR8(backend)
+            .addProgramClasses(classes)
+            .enableInliningAnnotations()
+            .addKeepMainRule(main)
+            .addKeepRules(
+                "-dontobfuscate", "-allowaccessmodification", "-keepattributes LineNumberTable")
+            .addOptionsModification(this::configure)
+            .run(main)
+            .assertSuccessWithOutput(javaOutput);
 
     CodeInspector inspector = result.inspector();
     ClassSubject clazz = inspector.clazz(main);
@@ -190,13 +192,12 @@
           Sets.newHashSet(
               "com.android.tools.r8.ir.optimize.classinliner.builders.Pair",
               "java.lang.StringBuilder");
-      if (backend == Backend.CF && i < 3) {
+      if (backend == Backend.CF) {
         // const-string canonicalization is disabled in CF, which helps ClassInliner identify
-        // PairBuilder as candidate. Concatenated builder calls in test #3 bother that again.
+        // PairBuilder as candidate.
         expected.add("com.android.tools.r8.ir.optimize.classinliner.builders.PairBuilder");
       }
-      assertEquals(expected,
-          collectTypes(clazz, "testSimpleBuilder" + i, "void"));
+      assertEquals(expected, collectTypes(clazz, "testSimpleBuilder" + i, "void"));
     }
 
     // Note that Pair created instances were also inlined in the following method since
@@ -223,9 +224,7 @@
 
     assertFalse(inspector.clazz(ControlFlow.class).isPresent());
 
-    assertEquals(
-        Collections.emptySet(),
-        collectTypes(clazz, "testWithMoreControlFlow", "void"));
+    assertEquals(Collections.emptySet(), collectTypes(clazz, "testWithMoreControlFlow", "void"));
 
     assertFalse(inspector.clazz(BuildersTestClass.Pos.class).isPresent());
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
index 76e9cfa..a4e1b56 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
@@ -32,7 +32,7 @@
             .setMinApi(AndroidApiLevel.M)
             .enableClassInliningAnnotations()
             .enableMergeAnnotations()
-            .minification(false)
+            .noMinification()
             .run(TestClass.class)
             .assertSuccessWithOutput(expectedOutput)
             .inspector();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldPropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldPropagationTest.java
index 9694a28..789b715 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldPropagationTest.java
@@ -31,7 +31,7 @@
             .addProgramClasses(TestClass.class, Log.class)
             .addKeepMainRule(TestClass.class)
             .enableInliningAnnotations()
-            .minification(false)
+            .noMinification()
             .run(TestClass.class)
             .assertSuccessWithOutput(expectedOutput);
 
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameInClassInitializerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameInClassInitializerTest.java
index 4472ef6..1ed8793 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameInClassInitializerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameInClassInitializerTest.java
@@ -6,8 +6,7 @@
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.R8TestBuilder;
-import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
 import com.google.common.collect.ImmutableList;
@@ -64,14 +63,12 @@
   @Test
   public void testR8_pinning() throws Exception {
     // Pinning the test class.
-    R8TestBuilder builder =
-        testForR8(parameters.getBackend())
-            .addProgramFiles(classPaths)
-            .enableInliningAnnotations()
-            .addKeepMainRule(MAIN)
-            .addKeepRules("-keep class **.GetNameClinit*")
-            .minification(enableMinification);
-    builder
+    testForR8(parameters.getBackend())
+        .addProgramFiles(classPaths)
+        .enableInliningAnnotations()
+        .addKeepMainRule(MAIN)
+        .addKeepRules("-keep class **.GetNameClinit*")
+        .minification(enableMinification)
         .setMinApi(parameters.getRuntime())
         .addOptionsModification(this::configure)
         .run(parameters.getRuntime(), MAIN)
@@ -81,20 +78,18 @@
   @Test
   public void testR8_shallow_pinning() throws Exception {
     // Pinning the test class.
-    R8TestBuilder builder =
+    R8TestCompileResult result =
         testForR8(parameters.getBackend())
             .addProgramFiles(classPaths)
             .enableInliningAnnotations()
             .addKeepMainRule(MAIN)
             .addKeepRules("-keep,allowobfuscation class **.GetNameClinit*")
-            .minification(enableMinification);
-
-    R8TestRunResult result =
-        builder
+            .minification(enableMinification)
             .setMinApi(parameters.getRuntime())
             .addOptionsModification(this::configure)
-            .run(parameters.getRuntime(), MAIN);
-    result.assertSuccessWithOutput(
-        result.inspector().clazz(GetNameClinitClass.class).getFinalName());
+            .compile();
+    result
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccessWithOutput(result.inspector().clazz(GetNameClinitClass.class).getFinalName());
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index b722683..e961c0e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -6,10 +6,10 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -121,6 +121,13 @@
     return classSubject;
   }
 
+  protected void checkClassIsRemoved(CodeInspector inspector, String className) {
+    checkClassExistsInInput(className);
+    ClassSubject classSubject = inspector.clazz(className);
+    assertNotNull(classSubject);
+    assertThat(classSubject, not(isPresent()));
+  }
+
   protected FieldSubject checkFieldIsKept(
       ClassSubject classSubject, String fieldType, String fieldName) {
     // Field must exist in the input.
@@ -137,6 +144,15 @@
     return fieldSubject;
   }
 
+  protected void checkFieldIsRemoved(
+      ClassSubject classSubject, String fieldType, String fieldName) {
+    // Field must exist in the input.
+    checkFieldPresenceInInput(classSubject.getOriginalName(), fieldType, fieldName, true);
+    FieldSubject fieldSubject = classSubject.field(fieldType, fieldName);
+    assertNotNull(fieldSubject);
+    assertThat(fieldSubject, not(isPresent()));
+  }
+
   protected void checkFieldIsAbsent(ClassSubject classSubject, String fieldType, String fieldName) {
     // Field must NOT exist in the input.
     checkFieldPresenceInInput(classSubject.getOriginalName(), fieldType, fieldName, false);
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
index 5de6fd9be..37debc5 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
@@ -3,10 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin;
 
-import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -18,11 +18,14 @@
 import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
-import java.util.Iterator;
 import java.util.function.Consumer;
 import org.junit.Test;
 
 public class KotlinUnusedSingletonTest extends AbstractR8KotlinTestBase {
+
+  private static final String printlnSignature =
+      "void java.io.PrintStream.println(java.lang.Object)";
+
   private Consumer<InternalOptions> optionsModifier =
       o -> {
         o.enableTreeShaking = true;
@@ -38,33 +41,53 @@
   public void b110196118() throws Exception {
     final String mainClassName = "unused_singleton.MainKt";
     final String moduleName = "unused_singleton.TestModule";
-    runTest("unused_singleton", mainClassName, optionsModifier, app -> {
-      CodeInspector inspector = new CodeInspector(app);
-      ClassSubject main = inspector.clazz(mainClassName);
-      assertThat(main, isPresent());
-      MethodSubject mainMethod = main.mainMethod();
-      assertThat(mainMethod, isPresent());
-      // const-string of provideGreeting() is propagated.
-      Iterator<InstructionSubject> it =
-          mainMethod.iterateInstructions(i -> i.isConstString("Hello", JumboStringMode.ALLOW));
-      assertTrue(it.hasNext());
-      // But, static call is still there, since it may trigger class initialization.
-      ClassSubject module = inspector.clazz(moduleName);
-      assertThat(main, isPresent());
-      MethodSubject provideGreetingMethod = module.uniqueMethodWithName("provideGreeting");
-      assertThat(mainMethod, invokesMethod(provideGreetingMethod));
+    runTest(
+        "unused_singleton",
+        mainClassName,
+        optionsModifier,
+        app -> {
+          CodeInspector inspector = new CodeInspector(app);
+          ClassSubject main = inspector.clazz(mainClassName);
+          assertThat(main, isPresent());
 
-      // field `INSTANCE` is shrunk.
-      FieldSubject instance = module.uniqueFieldWithName("INSTANCE");
-      assertThat(instance, not(isPresent()));
-      // TODO(b/110196118): remaining new-instance and invoke-direct <init> could be shrunk.
-      // TODO(b/110196118): then, trivial---empty---<clinit> could be shrunk.
-      MethodSubject clinit = module.clinit();
-      assertThat(clinit, isPresent());
-      // TODO(b/110196118): if the instantiation in <clinit> is gone, <init> is unreachable and can
-      // be removed by TreePruner.
-      MethodSubject init = module.init(ImmutableList.of());
-      assertThat(init, isPresent());
-    });
+          MethodSubject mainMethod = main.mainMethod();
+          assertThat(mainMethod, isPresent());
+
+          // The const-string from provideGreeting() has been propagated.
+          assertTrue(
+              mainMethod
+                  .iterateInstructions(i -> i.isConstString("Hello", JumboStringMode.ALLOW))
+                  .hasNext());
+
+          // The method provideGreeting() is no longer being invoked -- i.e., we have been able to
+          // determine that the class initialization of the enclosing class is trivial.
+          ClassSubject module = inspector.clazz(moduleName);
+          assertThat(main, isPresent());
+          assertEquals(
+              0,
+              mainMethod
+                  .streamInstructions()
+                  .filter(InstructionSubject::isInvoke)
+                  .map(i -> i.getMethod().toSourceString())
+                  .filter(
+                      invokedMethod ->
+                          !invokedMethod.equals(checkParameterIsNotNullSignature)
+                              && !invokedMethod.equals(printlnSignature)
+                              && !invokedMethod.equals(throwParameterIsNotNullExceptionSignature))
+                  .count());
+
+          // The field `INSTANCE` has been removed entirely.
+          FieldSubject instance = module.uniqueFieldWithName("INSTANCE");
+          assertThat(instance, not(isPresent()));
+
+          // The class initializer is no longer there.
+          MethodSubject clinit = module.clinit();
+          assertThat(clinit, not(isPresent()));
+
+          // Also, the instance initializer is no longer there, since it is only reachable from the
+          // class initializer.
+          MethodSubject init = module.init(ImmutableList.of());
+          assertThat(init, not(isPresent()));
+        });
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
index 85ff94c..27cc0b8 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
@@ -302,9 +302,10 @@
           ClassSubject outerClass =
               checkClassIsKept(codeInspector, testedClass.getOuterClassName());
           ClassSubject companionClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+
+          // Property field has been removed due to member value propagation.
           String propertyName = "property";
-          FieldSubject fieldSubject = checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
-          assertTrue(fieldSubject.getField().accessFlags.isStatic());
+          checkFieldIsRemoved(outerClass, JAVA_LANG_STRING, propertyName);
 
           // The getter is always inlined since it just calls into the accessor.
           MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
@@ -312,11 +313,6 @@
 
           MemberNaming.MethodSignature getterAccessor =
               testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
-          if (allowAccessModification) {
-            assertTrue(fieldSubject.getField().accessFlags.isPublic());
-          } else {
-            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-          }
           checkMethodIsKept(outerClass, getterAccessor);
         });
   }
@@ -354,23 +350,18 @@
 
   @Test
   public void testAccessorForInnerClassIsRemovedWhenNotUsed() throws Exception {
-    TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_INNER_CLASS;
-    String mainClass = addMainToClasspath(testedClass.className + "Kt",
-        "noUseOfPropertyAccessorFromInnerClass");
-    runTest("accessors", mainClass, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector, testedClass.getClassName());
+    String mainClass =
+        addMainToClasspath(
+            "accessors.PropertyAccessorForInnerClassKt", "noUseOfPropertyAccessorFromInnerClass");
+    runTest(
+        "accessors",
+        mainClass,
+        (app) -> {
+          CodeInspector codeInspector = new CodeInspector(app);
 
-      for (String propertyName : testedClass.properties.keySet()) {
-        MemberNaming.MethodSignature getterAccessor =
-            testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
-        MemberNaming.MethodSignature setterAccessor =
-            testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
-
-        checkMethodIsRemoved(classSubject, getterAccessor);
-        checkMethodIsRemoved(classSubject, setterAccessor);
-      }
-    });
+          // Class is removed because the instantiation of the inner class has no side effects.
+          checkClassIsRemoved(codeInspector, PROPERTY_ACCESS_FOR_INNER_CLASS.getClassName());
+        });
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
index 7635077..76c9ba8 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
@@ -7,7 +7,6 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
-import com.android.tools.r8.kotlin.TestKotlinClass.KotlinProperty;
 import com.android.tools.r8.kotlin.TestKotlinClass.Visibility;
 import com.android.tools.r8.naming.MemberNaming;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -15,7 +14,6 @@
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FieldSubject;
-import java.util.Map.Entry;
 import java.util.function.Consumer;
 import org.junit.Test;
 
@@ -97,292 +95,315 @@
   }
 
   @Test
-  public void testMutableProperty_getterAndSetterAreRemoveIfNotUsed() throws Exception {
+  public void testMutableProperty_classIsRemovedIfNotUsed() throws Exception {
     String mainClass = addMainToClasspath("properties/MutablePropertyKt",
         "mutableProperty_noUseOfProperties");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          MUTABLE_PROPERTY_CLASS.getClassName());
-      for (Entry<String, KotlinProperty> property : MUTABLE_PROPERTY_CLASS.properties.entrySet()) {
-        MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(property.getKey());
-        MethodSignature setter = MUTABLE_PROPERTY_CLASS.getSetterForProperty(property.getKey());
-        if (property.getValue().getVisibility() == Visibility.PRIVATE) {
-          // Private properties have no getter/setter
-          checkMethodIsAbsent(classSubject, getter);
-          checkMethodIsAbsent(classSubject, setter);
-        } else {
-          checkMethodIsRemoved(classSubject, getter);
-          checkMethodIsRemoved(classSubject, setter);
-        }
-      }
-    });
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          checkClassIsRemoved(codeInspector, MUTABLE_PROPERTY_CLASS.getClassName());
+        });
   }
 
   @Test
   public void testMutableProperty_privateIsAlwaysInlined() throws Exception {
     String mainClass = addMainToClasspath("properties/MutablePropertyKt",
         "mutableProperty_usePrivateProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          MUTABLE_PROPERTY_CLASS.getClassName());
-      String propertyName = "privateProp";
-      FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
-      if (!allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-      }
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject classSubject =
+              checkClassIsKept(codeInspector, MUTABLE_PROPERTY_CLASS.getClassName());
+          String propertyName = "privateProp";
+          FieldSubject fieldSubject =
+              checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
+          if (!allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+          }
 
-      // Private property has no getter or setter.
-      checkMethodIsAbsent(classSubject, MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName));
-      checkMethodIsAbsent(classSubject, MUTABLE_PROPERTY_CLASS.getSetterForProperty(propertyName));
-    });
+          // Private property has no getter or setter.
+          checkMethodIsAbsent(
+              classSubject, MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName));
+          checkMethodIsAbsent(
+              classSubject, MUTABLE_PROPERTY_CLASS.getSetterForProperty(propertyName));
+        });
   }
 
   @Test
   public void testMutableProperty_protectedIsAlwaysInlined() throws Exception {
     String mainClass = addMainToClasspath("properties/MutablePropertyKt",
         "mutableProperty_useProtectedProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          MUTABLE_PROPERTY_CLASS.getClassName());
-      String propertyName = "protectedProp";
-      FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject classSubject =
+              checkClassIsKept(codeInspector, MUTABLE_PROPERTY_CLASS.getClassName());
+          String propertyName = "protectedProp";
+          FieldSubject fieldSubject =
+              checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
 
-      // Protected property has private field.
-      MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-        checkMethodIsRemoved(classSubject, getter);
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-        checkMethodIsKept(classSubject, getter);
-      }
-    });
+          // Protected property has private field.
+          MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+            checkMethodIsRemoved(classSubject, getter);
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+            checkMethodIsKept(classSubject, getter);
+          }
+        });
   }
 
   @Test
   public void testMutableProperty_internalIsAlwaysInlined() throws Exception {
     String mainClass = addMainToClasspath("properties/MutablePropertyKt",
         "mutableProperty_useInternalProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          MUTABLE_PROPERTY_CLASS.getClassName());
-      String propertyName = "internalProp";
-      FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject classSubject =
+              checkClassIsKept(codeInspector, MUTABLE_PROPERTY_CLASS.getClassName());
+          String propertyName = "internalProp";
+          FieldSubject fieldSubject =
+              checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
 
-      // Internal property has private field
-      MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-        checkMethodIsRemoved(classSubject, getter);
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-        checkMethodIsKept(classSubject, getter);
-      }
-    });
+          // Internal property has private field
+          MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+            checkMethodIsRemoved(classSubject, getter);
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+            checkMethodIsKept(classSubject, getter);
+          }
+        });
   }
 
   @Test
   public void testMutableProperty_publicIsAlwaysInlined() throws Exception {
     String mainClass = addMainToClasspath("properties/MutablePropertyKt",
         "mutableProperty_usePublicProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          MUTABLE_PROPERTY_CLASS.getClassName());
-      String propertyName = "publicProp";
-      FieldSubject fieldSubject = checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject classSubject =
+              checkClassIsKept(codeInspector, MUTABLE_PROPERTY_CLASS.getClassName());
+          String propertyName = "publicProp";
+          FieldSubject fieldSubject =
+              checkFieldIsKept(classSubject, JAVA_LANG_STRING, propertyName);
 
-      // Public property has private field
-      MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-        checkMethodIsRemoved(classSubject, getter);
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-        checkMethodIsKept(classSubject, getter);
-      }
-    });
+          // Public property has private field
+          MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+            checkMethodIsRemoved(classSubject, getter);
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+            checkMethodIsKept(classSubject, getter);
+          }
+        });
   }
 
   @Test
   public void testMutableProperty_primitivePropertyIsAlwaysInlined() throws Exception {
     String mainClass = addMainToClasspath("properties/MutablePropertyKt",
         "mutableProperty_usePrimitiveProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          MUTABLE_PROPERTY_CLASS.getClassName());
-      String propertyName = "primitiveProp";
-      FieldSubject fieldSubject = checkFieldIsKept(classSubject, "int", propertyName);
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject classSubject =
+              checkClassIsKept(codeInspector, MUTABLE_PROPERTY_CLASS.getClassName());
+          String propertyName = "primitiveProp";
+          FieldSubject fieldSubject = checkFieldIsKept(classSubject, "int", propertyName);
 
-      MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
-      MethodSignature setter = MUTABLE_PROPERTY_CLASS.getSetterForProperty(propertyName);
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-        checkMethodIsRemoved(classSubject, getter);
-        checkMethodIsRemoved(classSubject, setter);
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-        checkMethodIsKept(classSubject, getter);
-        checkMethodIsKept(classSubject, setter);
-      }
-    });
+          MethodSignature getter = MUTABLE_PROPERTY_CLASS.getGetterForProperty(propertyName);
+          MethodSignature setter = MUTABLE_PROPERTY_CLASS.getSetterForProperty(propertyName);
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+            checkMethodIsRemoved(classSubject, getter);
+            checkMethodIsRemoved(classSubject, setter);
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+            checkMethodIsKept(classSubject, getter);
+            checkMethodIsKept(classSubject, setter);
+          }
+        });
   }
 
   @Test
-  public void testLateInitProperty_getterAndSetterAreRemoveIfNotUsed() throws Exception {
-    String mainClass = addMainToClasspath("properties/LateInitPropertyKt",
-        "lateInitProperty_noUseOfProperties");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          LATE_INIT_PROPERTY_CLASS.getClassName());
-      for (Entry<String, KotlinProperty> property : LATE_INIT_PROPERTY_CLASS.properties
-          .entrySet()) {
-        MethodSignature getter = LATE_INIT_PROPERTY_CLASS.getGetterForProperty(property.getKey());
-        MethodSignature setter = LATE_INIT_PROPERTY_CLASS.getSetterForProperty(property.getKey());
-        if (property.getValue().getVisibility() == Visibility.PRIVATE) {
-          // Private properties have no getter or setter.
-          checkMethodIsAbsent(classSubject, getter);
-          checkMethodIsAbsent(classSubject, setter);
-
-        } else {
-          checkMethodIsRemoved(classSubject, getter);
-          checkMethodIsRemoved(classSubject, setter);
-        }
-      }
-    });
+  public void testLateInitProperty_classIsRemovedIfNotUsed() throws Exception {
+    String mainClass =
+        addMainToClasspath("properties/LateInitPropertyKt", "lateInitProperty_noUseOfProperties");
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          checkClassIsRemoved(codeInspector, LATE_INIT_PROPERTY_CLASS.getClassName());
+        });
   }
 
   @Test
   public void testLateInitProperty_privateIsAlwaysInlined() throws Exception {
     String mainClass = addMainToClasspath(
         "properties/LateInitPropertyKt", "lateInitProperty_usePrivateLateInitProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          LATE_INIT_PROPERTY_CLASS.getClassName());
-      String propertyName = "privateLateInitProp";
-      FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
-      assertTrue("Field is absent", fieldSubject.isPresent());
-      if (!allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-      }
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject classSubject =
+              checkClassIsKept(codeInspector, LATE_INIT_PROPERTY_CLASS.getClassName());
+          String propertyName = "privateLateInitProp";
+          FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
+          assertTrue("Field is absent", fieldSubject.isPresent());
+          if (!allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+          }
 
-      // Private late init property have no getter or setter.
-      checkMethodIsAbsent(classSubject,
-          LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
-      checkMethodIsAbsent(classSubject,
-          LATE_INIT_PROPERTY_CLASS.getSetterForProperty(propertyName));
-    });
+          // Private late init property have no getter or setter.
+          checkMethodIsAbsent(
+              classSubject, LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
+          checkMethodIsAbsent(
+              classSubject, LATE_INIT_PROPERTY_CLASS.getSetterForProperty(propertyName));
+        });
   }
 
   @Test
   public void testLateInitProperty_protectedIsAlwaysInlined() throws Exception {
     String mainClass = addMainToClasspath("properties/LateInitPropertyKt",
         "lateInitProperty_useProtectedLateInitProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          LATE_INIT_PROPERTY_CLASS.getClassName());
-      String propertyName = "protectedLateInitProp";
-      FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
-      assertTrue("Field is absent", fieldSubject.isPresent());
-      if (!allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isProtected());
-      }
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject classSubject =
+              checkClassIsKept(codeInspector, LATE_INIT_PROPERTY_CLASS.getClassName());
+          String propertyName = "protectedLateInitProp";
+          FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
+          assertTrue("Field is absent", fieldSubject.isPresent());
+          if (!allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isProtected());
+          }
 
-      // Protected late init property have protected getter
-      checkMethodIsRemoved(classSubject,
-          LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
-    });
+          // Protected late init property have protected getter
+          checkMethodIsRemoved(
+              classSubject, LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
+        });
   }
 
   @Test
   public void testLateInitProperty_internalIsAlwaysInlined() throws Exception {
     String mainClass = addMainToClasspath(
         "properties/LateInitPropertyKt", "lateInitProperty_useInternalLateInitProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          LATE_INIT_PROPERTY_CLASS.getClassName());
-      String propertyName = "internalLateInitProp";
-      FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
-      assertTrue("Field is absent", fieldSubject.isPresent());
-      assertTrue(fieldSubject.getField().accessFlags.isPublic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject classSubject =
+              checkClassIsKept(codeInspector, LATE_INIT_PROPERTY_CLASS.getClassName());
+          String propertyName = "internalLateInitProp";
+          FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
+          assertTrue("Field is absent", fieldSubject.isPresent());
+          assertTrue(fieldSubject.getField().accessFlags.isPublic());
 
-      // Internal late init property have protected getter
-      checkMethodIsRemoved(classSubject,
-          LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
-    });
+          // Internal late init property have protected getter
+          checkMethodIsRemoved(
+              classSubject, LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
+        });
   }
 
   @Test
   public void testLateInitProperty_publicIsAlwaysInlined() throws Exception {
     String mainClass = addMainToClasspath(
         "properties/LateInitPropertyKt", "lateInitProperty_usePublicLateInitProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          LATE_INIT_PROPERTY_CLASS.getClassName());
-      String propertyName = "publicLateInitProp";
-      FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
-      assertTrue("Field is absent", fieldSubject.isPresent());
-      assertTrue(fieldSubject.getField().accessFlags.isPublic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject classSubject =
+              checkClassIsKept(codeInspector, LATE_INIT_PROPERTY_CLASS.getClassName());
+          String propertyName = "publicLateInitProp";
+          FieldSubject fieldSubject = classSubject.field(JAVA_LANG_STRING, propertyName);
+          assertTrue("Field is absent", fieldSubject.isPresent());
+          assertTrue(fieldSubject.getField().accessFlags.isPublic());
 
-      // Internal late init property have protected getter
-      checkMethodIsRemoved(classSubject,
-          LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
-    });
+          // Internal late init property have protected getter
+          checkMethodIsRemoved(
+              classSubject, LATE_INIT_PROPERTY_CLASS.getGetterForProperty(propertyName));
+        });
   }
 
   @Test
-  public void testUserDefinedProperty_getterAndSetterAreRemoveIfNotUsed() throws Exception {
+  public void testUserDefinedProperty_classIsRemovedIfNotUsed() throws Exception {
     String mainClass = addMainToClasspath(
         "properties/UserDefinedPropertyKt", "userDefinedProperty_noUseOfProperties");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          USER_DEFINED_PROPERTY_CLASS.getClassName());
-      for (String propertyName : USER_DEFINED_PROPERTY_CLASS.properties.keySet()) {
-        checkMethodIsRemoved(classSubject,
-            USER_DEFINED_PROPERTY_CLASS.getGetterForProperty(propertyName));
-        checkMethodIsRemoved(classSubject,
-            USER_DEFINED_PROPERTY_CLASS.getSetterForProperty(propertyName));
-      }
-    });
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          checkClassIsRemoved(codeInspector, USER_DEFINED_PROPERTY_CLASS.getClassName());
+        });
   }
 
   @Test
   public void testUserDefinedProperty_publicIsAlwaysInlined() throws Exception {
     String mainClass = addMainToClasspath(
         "properties/UserDefinedPropertyKt", "userDefinedProperty_useProperties");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject classSubject = checkClassIsKept(codeInspector,
-          USER_DEFINED_PROPERTY_CLASS.getClassName());
-      String propertyName = "durationInSeconds";
-      // The 'wrapper' property is not assigned to a backing field, it only relies on the wrapped
-      // property.
-      checkFieldIsAbsent(classSubject, "int", "durationInSeconds");
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject classSubject =
+              checkClassIsKept(codeInspector, USER_DEFINED_PROPERTY_CLASS.getClassName());
+          String propertyName = "durationInSeconds";
+          // The 'wrapper' property is not assigned to a backing field, it only relies on the
+          // wrapped property.
+          checkFieldIsAbsent(classSubject, "int", "durationInSeconds");
 
-      FieldSubject fieldSubject = checkFieldIsKept(classSubject, "int",
-          "durationInMilliSeconds");
-      MethodSignature getter = USER_DEFINED_PROPERTY_CLASS.getGetterForProperty(propertyName);
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-        checkMethodIsRemoved(classSubject, getter);
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-        checkMethodIsKept(classSubject, getter);
-      }
-    });
+          FieldSubject fieldSubject =
+              checkFieldIsKept(classSubject, "int", "durationInMilliSeconds");
+          MethodSignature getter = USER_DEFINED_PROPERTY_CLASS.getGetterForProperty(propertyName);
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+            checkMethodIsRemoved(classSubject, getter);
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+            checkMethodIsKept(classSubject, getter);
+          }
+        });
   }
 
   @Test
@@ -393,7 +414,7 @@
         PACKAGE_NAME,
         mainClass,
         disableAggressiveClassOptimizations,
-        (app) -> {
+        app -> {
           CodeInspector codeInspector = new CodeInspector(app);
           ClassSubject outerClass =
               checkClassIsKept(codeInspector, "properties.CompanionProperties");
@@ -428,7 +449,7 @@
         PACKAGE_NAME,
         mainClass,
         disableAggressiveClassOptimizations,
-        (app) -> {
+        app -> {
           CodeInspector codeInspector = new CodeInspector(app);
           ClassSubject outerClass =
               checkClassIsKept(codeInspector, "properties.CompanionProperties");
@@ -466,7 +487,7 @@
         PACKAGE_NAME,
         mainClass,
         disableAggressiveClassOptimizations,
-        (app) -> {
+        app -> {
           CodeInspector codeInspector = new CodeInspector(app);
           ClassSubject outerClass =
               checkClassIsKept(codeInspector, "properties.CompanionProperties");
@@ -501,7 +522,7 @@
         PACKAGE_NAME,
         mainClass,
         disableAggressiveClassOptimizations,
-        (app) -> {
+        app -> {
           CodeInspector codeInspector = new CodeInspector(app);
           ClassSubject outerClass =
               checkClassIsKept(codeInspector, "properties.CompanionProperties");
@@ -537,7 +558,7 @@
         PACKAGE_NAME,
         mainClass,
         disableAggressiveClassOptimizations,
-        (app) -> {
+        app -> {
           CodeInspector codeInspector = new CodeInspector(app);
           ClassSubject outerClass =
               checkClassIsKept(codeInspector, testedClass.getOuterClassName());
@@ -573,7 +594,7 @@
         PACKAGE_NAME,
         mainClass,
         disableAggressiveClassOptimizations,
-        (app) -> {
+        app -> {
           CodeInspector codeInspector = new CodeInspector(app);
           ClassSubject outerClass =
               checkClassIsKept(codeInspector, testedClass.getOuterClassName());
@@ -602,7 +623,7 @@
         PACKAGE_NAME,
         mainClass,
         disableAggressiveClassOptimizations,
-        (app) -> {
+        app -> {
           CodeInspector codeInspector = new CodeInspector(app);
           ClassSubject outerClass =
               checkClassIsKept(codeInspector, testedClass.getOuterClassName());
@@ -623,30 +644,41 @@
   }
 
   @Test
-  public void testObjectClass_primitivePropertyCannotBeInlined() throws Exception {
+  public void testObjectClass_primitivePropertyIsInlined() throws Exception {
     final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.ObjectPropertiesKt", "objectProperties_usePrimitiveProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "primitiveProp";
-      FieldSubject fieldSubject = checkFieldIsKept(objectClass, "int", propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "primitiveProp";
+          FieldSubject fieldSubject = checkFieldIsKept(objectClass, "int", propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      // Getter and setter cannot be inlined when we don't know if null check semantic is
-      // preserved.
-      checkMethodIsKept(objectClass, getter);
-      checkMethodIsKept(objectClass, setter);
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-      }
-    });
+          if (allowAccessModification) {
+            // Getter and setter is inlined because the constructor of ObjectProperties is
+            // considered trivial, which implies that the member value propagation marks the
+            // INSTANCE field as being non-null.
+            checkMethodIsRemoved(objectClass, getter);
+            checkMethodIsRemoved(objectClass, setter);
+          } else {
+            checkMethodIsKept(objectClass, getter);
+            checkMethodIsKept(objectClass, setter);
+          }
+
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+          }
+        });
   }
 
   @Test
@@ -654,80 +686,106 @@
     final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.ObjectPropertiesKt", "objectProperties_usePrivateProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "privateProp";
-      FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "privateProp";
+          FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      // A private property has no getter/setter.
-      checkMethodIsAbsent(objectClass, getter);
-      checkMethodIsAbsent(objectClass, setter);
+          // A private property has no getter/setter.
+          checkMethodIsAbsent(objectClass, getter);
+          checkMethodIsAbsent(objectClass, setter);
 
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-      }
-    });
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+          }
+        });
   }
 
   @Test
-  public void testObjectClass_internalPropertyCannotBeInlined() throws Exception {
+  public void testObjectClass_internalPropertyIsInlined() throws Exception {
     final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.ObjectPropertiesKt", "objectProperties_useInternalProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "internalProp";
-      FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "internalProp";
+          FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      // Getter and setter cannot be inlined when we don't know if null check semantic is
-      // preserved.
-      checkMethodIsKept(objectClass, getter);
-      checkMethodIsKept(objectClass, setter);
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-      }
-    });
+          if (allowAccessModification) {
+            // Getter and setter is inlined because the constructor of ObjectProperties is
+            // considered trivial, which implies that the member value propagation marks the
+            // INSTANCE field as being non-null.
+            checkMethodIsRemoved(objectClass, getter);
+            checkMethodIsRemoved(objectClass, setter);
+          } else {
+            checkMethodIsKept(objectClass, getter);
+            checkMethodIsKept(objectClass, setter);
+          }
+
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+          }
+        });
   }
 
   @Test
-  public void testObjectClass_publicPropertyCannotBeInlined() throws Exception {
+  public void testObjectClass_publicPropertyIsInlined() throws Exception {
     final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.ObjectPropertiesKt", "objectProperties_usePublicProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "publicProp";
-      FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "publicProp";
+          FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      // Getter and setter cannot be inlined when we don't know if null check semantic is
-      // preserved.
-      checkMethodIsKept(objectClass, getter);
-      checkMethodIsKept(objectClass, setter);
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-      }
-    });
+          if (allowAccessModification) {
+            // Getter and setter is inlined because the constructor of ObjectProperties is
+            // considered trivial, which implies that the member value propagation marks the
+            // INSTANCE field as being non-null.
+            checkMethodIsRemoved(objectClass, getter);
+            checkMethodIsRemoved(objectClass, setter);
+          } else {
+            checkMethodIsKept(objectClass, getter);
+            checkMethodIsKept(objectClass, setter);
+          }
+
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+          }
+        });
   }
 
   @Test
@@ -735,68 +793,80 @@
     final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.ObjectPropertiesKt", "objectProperties_useLateInitPrivateProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "privateLateInitProp";
-      FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "privateLateInitProp";
+          FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      // A private property has no getter/setter.
-      checkMethodIsAbsent(objectClass, getter);
-      checkMethodIsAbsent(objectClass, setter);
+          // A private property has no getter/setter.
+          checkMethodIsAbsent(objectClass, getter);
+          checkMethodIsAbsent(objectClass, setter);
 
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-      }
-    });
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+          }
+        });
   }
 
   @Test
-  public void testObjectClass_internalLateInitPropertyCannotBeInlined() throws Exception {
+  public void testObjectClass_internalLateInitPropertyIsInlined() throws Exception {
     final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.ObjectPropertiesKt", "objectProperties_useLateInitInternalProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "internalLateInitProp";
-      FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "internalLateInitProp";
+          FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      checkMethodIsRemoved(objectClass, getter);
-      checkMethodIsRemoved(objectClass, setter);
-      assertTrue(fieldSubject.getField().accessFlags.isPublic());
-    });
+          checkMethodIsRemoved(objectClass, getter);
+          checkMethodIsRemoved(objectClass, setter);
+          assertTrue(fieldSubject.getField().accessFlags.isPublic());
+        });
   }
 
   @Test
-  public void testObjectClass_publicLateInitPropertyCannotBeInlined() throws Exception {
+  public void testObjectClass_publicLateInitPropertyIsInlined() throws Exception {
     final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.ObjectPropertiesKt", "objectProperties_useLateInitPublicProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "publicLateInitProp";
-      FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "publicLateInitProp";
+          FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      checkMethodIsRemoved(objectClass, getter);
-      checkMethodIsRemoved(objectClass, setter);
-      assertTrue(fieldSubject.getField().accessFlags.isPublic());
-    });
+          checkMethodIsRemoved(objectClass, getter);
+          checkMethodIsRemoved(objectClass, setter);
+          assertTrue(fieldSubject.getField().accessFlags.isPublic());
+        });
   }
 
   @Test
@@ -808,7 +878,7 @@
         PACKAGE_NAME,
         mainClass,
         disableAggressiveClassOptimizations,
-        (app) -> {
+        app -> {
           CodeInspector codeInspector = new CodeInspector(app);
           ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
           String propertyName = "primitiveProp";
@@ -835,25 +905,29 @@
     final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.FilePropertiesKt", "fileProperties_usePrivateProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "privateProp";
-      FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "privateProp";
+          FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      // A private property has no getter/setter.
-      checkMethodIsAbsent(objectClass, getter);
-      checkMethodIsAbsent(objectClass, setter);
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-      }
-    });
+          // A private property has no getter/setter.
+          checkMethodIsAbsent(objectClass, getter);
+          checkMethodIsAbsent(objectClass, setter);
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+          }
+        });
   }
 
   @Test
@@ -865,7 +939,7 @@
         PACKAGE_NAME,
         mainClass,
         disableAggressiveClassOptimizations,
-        (app) -> {
+        app -> {
           CodeInspector codeInspector = new CodeInspector(app);
           ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
           String propertyName = "internalProp";
@@ -895,7 +969,7 @@
         PACKAGE_NAME,
         mainClass,
         disableAggressiveClassOptimizations,
-        (app) -> {
+        app -> {
           CodeInspector codeInspector = new CodeInspector(app);
           ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
           String propertyName = "publicProp";
@@ -904,8 +978,7 @@
 
           // We expect getter to be inlined when access (of the backing field) is relaxed to public.
           // On the other hand, the setter is considered as a regular method (because of null
-          // checks),
-          // thus we cannot say if it can be inlined or not.
+          // checks), thus we cannot say if it can be inlined or not.
           MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
 
           if (allowAccessModification) {
@@ -923,69 +996,81 @@
     final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.FilePropertiesKt", "fileProperties_useLateInitPrivateProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject fileClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "privateLateInitProp";
-      FieldSubject fieldSubject = checkFieldIsKept(fileClass, JAVA_LANG_STRING, propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject fileClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "privateLateInitProp";
+          FieldSubject fieldSubject = checkFieldIsKept(fileClass, JAVA_LANG_STRING, propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      // A private property has no getter/setter.
-      checkMethodIsAbsent(fileClass, getter);
-      checkMethodIsAbsent(fileClass, setter);
-      if (allowAccessModification) {
-        assertTrue(fieldSubject.getField().accessFlags.isPublic());
-      } else {
-        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
-      }
-    });
+          // A private property has no getter/setter.
+          checkMethodIsAbsent(fileClass, getter);
+          checkMethodIsAbsent(fileClass, setter);
+          if (allowAccessModification) {
+            assertTrue(fieldSubject.getField().accessFlags.isPublic());
+          } else {
+            assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+          }
+        });
   }
 
   @Test
-  public void testFileLevel_internalLateInitPropertyCannotBeInlined() throws Exception {
+  public void testFileLevel_internalLateInitPropertyIsInlined() throws Exception {
     final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.FilePropertiesKt", "fileProperties_useLateInitInternalProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "internalLateInitProp";
-      FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
-      assertTrue(fieldSubject.getField().accessFlags.isPublic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "internalLateInitProp";
+          FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
+          assertTrue(fieldSubject.getField().accessFlags.isPublic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      // Field is public and getter/setter is only called from one place so we expect to always
-      // inline it.
-      checkMethodIsRemoved(objectClass, getter);
-      checkMethodIsRemoved(objectClass, setter);
-    });
+          // Field is public and getter/setter is only called from one place so we expect to always
+          // inline it.
+          checkMethodIsRemoved(objectClass, getter);
+          checkMethodIsRemoved(objectClass, setter);
+        });
   }
 
   @Test
-  public void testFileLevel_publicLateInitPropertyCannotBeInlined() throws Exception {
+  public void testFileLevel_publicLateInitPropertyIsInlined() throws Exception {
     final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
     String mainClass = addMainToClasspath(
         "properties.FilePropertiesKt", "fileProperties_useLateInitPublicProp");
-    runTest(PACKAGE_NAME, mainClass, disableAggressiveClassOptimizations, (app) -> {
-      CodeInspector codeInspector = new CodeInspector(app);
-      ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
-      String propertyName = "publicLateInitProp";
-      FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
-      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+    runTest(
+        PACKAGE_NAME,
+        mainClass,
+        disableAggressiveClassOptimizations,
+        app -> {
+          CodeInspector codeInspector = new CodeInspector(app);
+          ClassSubject objectClass = checkClassIsKept(codeInspector, testedClass.getClassName());
+          String propertyName = "publicLateInitProp";
+          FieldSubject fieldSubject = checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
+          assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
-      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+          MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+          MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
 
-      checkMethodIsRemoved(objectClass, getter);
-      checkMethodIsRemoved(objectClass, setter);
-      assertTrue(fieldSubject.getField().accessFlags.isPublic());
-    });
+          checkMethodIsRemoved(objectClass, getter);
+          checkMethodIsRemoved(objectClass, setter);
+          assertTrue(fieldSubject.getField().accessFlags.isPublic());
+        });
   }
 
 }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
index dd62cac..5df74fa 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -333,8 +333,8 @@
         .addOptionsModification(optionsConsumer)
         .assumeAllMethodsMayHaveSideEffects()
         .setMinApi(minSdk)
-        .minification(false)
-        .treeShaking(false)
+        .noMinification()
+        .noTreeShaking()
         .setMainDexListConsumer((string, handler) -> r8MainDexListOutput.content = string)
         .compile()
         .writeToZip(out);
diff --git a/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java b/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
index 0acd733..cd80843 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
@@ -8,7 +8,7 @@
 
 import com.android.tools.r8.GenerateMainDexList;
 import com.android.tools.r8.GenerateMainDexListCommand;
-import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.errors.Unreachable;
@@ -83,7 +83,7 @@
   }
 
   public void runTestWithR8(GraphConsumer consumer, String rule) throws Exception {
-    R8TestBuilder builder =
+    R8FullTestBuilder builder =
         testForR8(Backend.DEX)
             .noTreeShaking()
             .noMinification()
@@ -133,9 +133,9 @@
         StringUtils.lines(
             "com.android.tools.r8.maindexlist.whyareyoukeeping.MainDexClass",
             "|- is instantiated in:",
-            "|  void com.android.tools.r8.maindexlist.whyareyoukeeping.HelloWorldMain.main(java.lang.String[])",
+            "|  void " + HelloWorldMain.class.getTypeName() + ".main(java.lang.String[])",
             "|- is referenced in keep rule:",
-            "|  -keep class com.android.tools.r8.maindexlist.whyareyoukeeping.HelloWorldMain {",
+            "|  -keep class " + HelloWorldMain.class.getTypeName() + " {",
             "|    public static void main(java.lang.String[]);",
             "|  }");
     assertEquals(expected, runTest(MainDexClass.class));
diff --git a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
index 8c2dafc..1809ada 100644
--- a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
@@ -102,6 +102,13 @@
         "-neverinline class " + adaptresourcefilenames.B.Inner.class.getName() + " {",
         "  public void method();",
         "}",
+        "-assumemayhavesideeffects class " + adaptresourcefilenames.pkg.C.class.getName() + " {",
+        "  void <init>();",
+        "}",
+        "-assumemayhavesideeffects class " + adaptresourcefilenames.pkg.innerpkg.D.class.getName(),
+        "{",
+        "  void <init>();",
+        "}",
         "-neverclassinline class *");
   }
 
diff --git a/src/test/java/com/android/tools/r8/naming/AvoidRTest.java b/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
index 2d48d5c..2eda1cd 100644
--- a/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
@@ -9,7 +9,7 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.jasmin.JasminTestBase;
@@ -44,7 +44,7 @@
     Set<String> expectedNames = ImmutableSet.of("P", "Q", "S", "T");
 
     JasminBuilder jasminBuilder = new JasminBuilder();
-    R8TestBuilder builder = testForR8(backend);
+    R8FullTestBuilder builder = testForR8(backend);
     for (int i = 0; i < 4; i++) {
       jasminBuilder.addClass("TopLevel" + Integer.toString(i));
     }
@@ -76,7 +76,7 @@
   @Test
   public void test_withoutPackageHierarchy() throws Exception {
     JasminBuilder jasminBuilder = new JasminBuilder();
-    R8TestBuilder builder = testForR8(backend);
+    R8FullTestBuilder builder = testForR8(backend);
     for (int i = 0; i < 26 * 2; i++) {
       jasminBuilder.addClass("TestClass" + Integer.toString(i));
     }
@@ -96,7 +96,7 @@
   }
 
   private void test_withPackageHierarchy(String keepRule) throws Exception {
-    R8TestBuilder builder = testForR8(backend);
+    R8FullTestBuilder builder = testForR8(backend);
     JasminBuilder jasminBuilder = new JasminBuilder();
     for (int i = 0; i < 26 * 2; i++) {
       jasminBuilder.addClass("TopLevel" + Integer.toString(i));
diff --git a/src/test/java/com/android/tools/r8/naming/CovariantReturnTypeTest.java b/src/test/java/com/android/tools/r8/naming/CovariantReturnTypeTest.java
index 314acdc..740c906 100644
--- a/src/test/java/com/android/tools/r8/naming/CovariantReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/naming/CovariantReturnTypeTest.java
@@ -63,7 +63,7 @@
             .addKeepMainRule("package.TestClass")
             .addKeepRules("-keepconstantarguments class * { *; }")
             .enableConstantArgumentAnnotations()
-            .treeShaking(false)
+            .noTreeShaking()
             .compile()
             .inspector();
 
diff --git a/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java b/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
index 9ade2f9..3088fdf 100644
--- a/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
@@ -56,7 +56,7 @@
         .assertSuccess();
   }
 
-  private void test(R8TestBuilder builder) throws Exception {
+  private void test(R8TestBuilder<?> builder) throws Exception {
     builder
         .addKeepRules("-dontoptimize")
         .addKeepRules("-keepattributes InnerClasses,EnclosingMethod,Signature")
diff --git a/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java b/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
index 47f0b1d..c02e401 100644
--- a/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
+++ b/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
@@ -4,19 +4,13 @@
 
 package com.android.tools.r8.regress.b69825683;
 
+import static org.hamcrest.CoreMatchers.startsWith;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ClassFileConsumer;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
-import com.google.common.collect.ImmutableList;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -37,27 +31,29 @@
 
   @Test
   public void outerConstructsInner() throws Exception {
-    Class mainClass = com.android.tools.r8.regress.b69825683.outerconstructsinner.Outer.class;
-    R8Command.Builder builder = R8Command.builder();
-    builder.addProgramFiles(ToolHelper.getClassFilesForTestPackage(mainClass.getPackage()));
-    builder.addProguardConfiguration(ImmutableList.of(
-        "-keep class " + mainClass.getCanonicalName() + " {",
-        "  public static void main(java.lang.String[]);",
-        "}",
-        "-dontobfuscate"),
-        Origin.unknown());
-    if (backend == Backend.DEX) {
-      builder
-          .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
-          .addLibraryFiles(ToolHelper.getDefaultAndroidJar());
-    } else {
-      assert backend == Backend.CF;
-      builder
-          .setProgramConsumer(ClassFileConsumer.emptyConsumer())
-          .addLibraryFiles(ToolHelper.getJava8RuntimeJar());
-    }
-    AndroidApp app = ToolHelper.runR8(builder.build(), o -> o.enableClassInlining = false);
-    CodeInspector inspector = new CodeInspector(app);
+    Class<?> inner = com.android.tools.r8.regress.b69825683.outerconstructsinner.Outer.Inner.class;
+    Class<?> outer = com.android.tools.r8.regress.b69825683.outerconstructsinner.Outer.class;
+
+    String innerName = inner.getCanonicalName();
+    int index = innerName.lastIndexOf('.');
+    innerName = innerName.substring(0, index) + "$" + innerName.substring(index + 1);
+
+    CodeInspector inspector =
+        testForR8(backend)
+            .addProgramFiles(ToolHelper.getClassFilesForTestPackage(outer.getPackage()))
+            .addKeepMainRule(outer)
+            .enableSideEffectAnnotations()
+            .addKeepRules(
+                "-assumemayhavesideeffects class " + inner.getTypeName() + " {",
+                "  synthetic void <init>(...);",
+                "}")
+            .addOptionsModification(options -> options.enableClassInlining = false)
+            .noMinification()
+            .run(outer)
+            // Run code to check that the constructor with synthetic class as argument is present.
+            .assertSuccessWithOutputThatMatches(startsWith(innerName))
+            .inspector();
+
     List<FoundClassSubject> classes = inspector.allClasses();
 
     // Check that the synthetic class is still present.
@@ -67,41 +63,23 @@
             .map(FoundClassSubject::getOriginalName)
             .filter(name  -> name.endsWith("$1"))
             .count());
-
-    // Run code to check that the constructor with synthetic class as argument is present.
-    Class innerClass =
-        com.android.tools.r8.regress.b69825683.outerconstructsinner.Outer.Inner.class;
-    String innerName = innerClass.getCanonicalName();
-    int index = innerName.lastIndexOf('.');
-    innerName = innerName.substring(0, index) + "$" + innerName.substring(index + 1);
-    assertTrue(
-        (backend == Backend.DEX ? runOnArt(app, mainClass) : runOnJava(app, mainClass))
-            .startsWith(innerName));
   }
 
   @Test
   public void innerConstructsOuter() throws Exception {
-    Class mainClass = com.android.tools.r8.regress.b69825683.innerconstructsouter.Outer.class;
-    R8Command.Builder builder = R8Command.builder();
-    builder.addProgramFiles(ToolHelper.getClassFilesForTestPackage(mainClass.getPackage()));
-    builder.addProguardConfiguration(ImmutableList.of(
-        "-keep class " + mainClass.getCanonicalName() + " {",
-        "  public static void main(java.lang.String[]);",
-        "}",
-        "-dontobfuscate"),
-        Origin.unknown());
-    if (backend == Backend.DEX) {
-      builder
-          .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
-          .addLibraryFiles(ToolHelper.getDefaultAndroidJar());
-    } else {
-      assert backend == Backend.CF;
-      builder
-          .setProgramConsumer(ClassFileConsumer.emptyConsumer())
-          .addLibraryFiles(ToolHelper.getJava8RuntimeJar());
-    }
-    AndroidApp app = ToolHelper.runR8(builder.build(), o -> o.enableClassInlining = false);
-    CodeInspector inspector = new CodeInspector(app);
+    Class<?> clazz = com.android.tools.r8.regress.b69825683.innerconstructsouter.Outer.class;
+    CodeInspector inspector =
+        testForR8(backend)
+            .addProgramFiles(ToolHelper.getClassFilesForTestPackage(clazz.getPackage()))
+            .addKeepMainRule(clazz)
+            .enableInliningAnnotations()
+            .noMinification()
+            .addOptionsModification(o -> o.enableClassInlining = false)
+            // Run code to check that the constructor with synthetic class as argument is present.
+            .run(clazz)
+            .assertSuccessWithOutputThatMatches(startsWith(clazz.getTypeName()))
+            .inspector();
+
     List<FoundClassSubject> classes = inspector.allClasses();
 
     // Check that the synthetic class is still present.
@@ -111,10 +89,5 @@
             .map(FoundClassSubject::getOriginalName)
             .filter(name  -> name.endsWith("$1"))
             .count());
-
-    // Run code to check that the constructor with synthetic class as argument is present.
-    assertTrue(
-        (backend == Backend.DEX ? runOnArt(app, mainClass) : runOnJava(app, mainClass))
-            .startsWith(mainClass.getCanonicalName()));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/regress/b69825683/innerconstructsouter/Outer.java b/src/test/java/com/android/tools/r8/regress/b69825683/innerconstructsouter/Outer.java
index 8241c18..78d9d05 100644
--- a/src/test/java/com/android/tools/r8/regress/b69825683/innerconstructsouter/Outer.java
+++ b/src/test/java/com/android/tools/r8/regress/b69825683/innerconstructsouter/Outer.java
@@ -4,18 +4,22 @@
 
 package com.android.tools.r8.regress.b69825683.innerconstructsouter;
 
+import com.android.tools.r8.NeverInline;
+
 public class Outer {
 
   private Outer() {
   }
 
   public static class Inner {
+
+    @NeverInline
     public Outer build() {
       return new Outer();
     }
   }
 
-  public static void main(String args[]) {
+  public static void main(String[] args) {
     Inner builder = new Inner();
     builder.build();
     for (java.lang.reflect.Constructor m : Outer.class.getDeclaredConstructors()) {
diff --git a/src/test/java/com/android/tools/r8/regress/b69825683/outerconstructsinner/Outer.java b/src/test/java/com/android/tools/r8/regress/b69825683/outerconstructsinner/Outer.java
index 79bccc5..3222964 100644
--- a/src/test/java/com/android/tools/r8/regress/b69825683/outerconstructsinner/Outer.java
+++ b/src/test/java/com/android/tools/r8/regress/b69825683/outerconstructsinner/Outer.java
@@ -4,16 +4,19 @@
 
 package com.android.tools.r8.regress.b69825683.outerconstructsinner;
 
+import com.android.tools.r8.AssumeMayHaveSideEffects;
+
 public class Outer {
 
+  @AssumeMayHaveSideEffects
   public Outer() {
     new Inner();
   }
 
   public class Inner {
 
-    private Inner() {
-    }
+    @AssumeMayHaveSideEffects
+    private Inner() {}
   }
 
   public static void main(String args[]) {
diff --git a/src/test/java/com/android/tools/r8/rewrite/logarguments/LogArgumentsTest.java b/src/test/java/com/android/tools/r8/rewrite/logarguments/LogArgumentsTest.java
index ed40bbd..a5ad00a 100644
--- a/src/test/java/com/android/tools/r8/rewrite/logarguments/LogArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/logarguments/LogArgumentsTest.java
@@ -36,8 +36,8 @@
             .addOptionsModification(
                 options -> options.logArgumentsFilter = ImmutableList.of(qualifiedMethodName))
             .assumeAllMethodsMayHaveSideEffects()
-            .minification(false)
-            .treeShaking(false)
+            .noMinification()
+            .noTreeShaking()
             .run(TestStatic.class)
             .getStdOut();
     assertEquals(7, occourences(qualifiedMethodName, result));
@@ -57,8 +57,8 @@
             .addOptionsModification(
                 options -> options.logArgumentsFilter = ImmutableList.of(qualifiedMethodName))
             .assumeAllMethodsMayHaveSideEffects()
-            .minification(false)
-            .treeShaking(false)
+            .noMinification()
+            .noTreeShaking()
             .run(TestInstance.class)
             .getStdOut();
     assertEquals(7, occourences(qualifiedMethodName, result));
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
index 9290085..9398f79 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnFieldsTest.java
@@ -4,8 +4,9 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
+import com.android.tools.r8.AssumeMayHaveSideEffects;
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
@@ -22,6 +23,15 @@
 @RunWith(Parameterized.class)
 public class AnnotationsOnFieldsTest extends TestBase {
 
+  private static final List<Class<?>> CLASSES =
+      ImmutableList.of(
+          FieldAnnotation.class,
+          StaticFieldAnnotation.class,
+          FieldAnnotationUse.class,
+          StaticFieldAnnotationUse.class,
+          TestClass.class,
+          MainClass.class);
+
   private final Backend backend;
 
   @Parameterized.Parameters(name = "Backend: {0}")
@@ -33,28 +43,22 @@
     this.backend = backend;
   }
 
-  List<Class<?>> CLASSES = ImmutableList.of(
-      FieldAnnotation.class,
-      StaticFieldAnnotation.class,
-      FieldAnnotationUse.class,
-      StaticFieldAnnotationUse.class,
-      TestClass.class,
-      MainClass.class
-  );
-
   @Test
   public void test() throws Exception {
     testForR8Compat(backend)
         .enableClassInliningAnnotations()
         .addProgramClasses(CLASSES)
         .addKeepMainRule(MainClass.class)
-        .addKeepRules("-keep @interface **.*Annotation { *; }")
-        .addKeepRules("-keepclassmembers class * { @**.*Annotation <fields>; }")
-        .addKeepRules("-keepattributes *Annotation*")
+        .addKeepRules(
+            "-keep @interface **.*Annotation { *; }",
+            "-keepclassmembers class * { @**.*Annotation <fields>; }",
+            "-keepattributes *Annotation*")
+        .enableSideEffectAnnotations()
         .compile()
         .inspect(
             inspector -> {
               ClassSubject clazz = inspector.clazz(TestClass.class);
+              assertThat(clazz, isPresent());
               assertThat(clazz, isRenamed());
 
               FieldSubject field = clazz.uniqueFieldWithName("field");
@@ -92,6 +96,9 @@
 @NeverClassInline
 class TestClass {
 
+  @AssumeMayHaveSideEffects
+  public TestClass() {}
+
   @StaticFieldAnnotation(clazz = StaticFieldAnnotationUse.class)
   static int staticField;
 
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
index 76fd865..6863b0e 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.shaking.forceproguardcompatibility;
 
+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.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -446,14 +448,10 @@
     testAtomicFieldUpdaters(false, true);
   }
 
-  public void testKeepAttributes(boolean forceProguardCompatibility,
-      boolean innerClasses, boolean enclosingMethod) throws Exception {
-    CompatProguardCommandBuilder builder =
-        new CompatProguardCommandBuilder(forceProguardCompatibility);
-    Class mainClass = TestKeepAttributes.class;
-    builder.addProgramFiles(ToolHelper.getClassFilesForTestPackage(mainClass.getPackage()));
-    ImmutableList.Builder<String> proguardConfigurationBuilder = ImmutableList.builder();
-    String keepAttributes = "";
+  public void testKeepAttributes(
+      boolean forceProguardCompatibility, boolean innerClasses, boolean enclosingMethod)
+      throws Exception {
+    String keepRules = "";
     if (innerClasses || enclosingMethod) {
       List<String> attributes = new ArrayList<>();
       if (innerClasses) {
@@ -462,45 +460,42 @@
       if (enclosingMethod) {
         attributes.add(ProguardKeepAttributes.ENCLOSING_METHOD);
       }
-      keepAttributes = "-keepattributes " + String.join(",", attributes);
+      keepRules = "-keepattributes " + String.join(",", attributes);
     }
-    proguardConfigurationBuilder.add(
-        "-keep class " + mainClass.getCanonicalName() + " {",
-        "  <init>();",  // Add <init>() so it does not become a compatibility rule below.
-        "  public static void main(java.lang.String[]);",
-        "}",
-        keepAttributes);
-    List<String> proguardConfig = proguardConfigurationBuilder.build();
-    builder.addProguardConfiguration(proguardConfig, Origin.unknown());
     Path proguardCompatibilityRules = temp.newFile().toPath();
-    builder.setProguardCompatibilityRulesOutput(proguardCompatibilityRules);
+    CodeInspector inspector;
 
-    AndroidApp app;
-    builder.setProgramConsumer(emptyConsumer(backend)).addLibraryFiles(runtimeJar(backend));
     try {
-      app = ToolHelper.runR8(builder.build(), o -> o.enableClassInlining = false);
+      inspector =
+          testForR8Compat(backend, forceProguardCompatibility)
+              .addProgramFiles(
+                  ToolHelper.getClassFilesForTestPackage(TestKeepAttributes.class.getPackage()))
+              .addKeepRules(
+                  "-keep class " + TestKeepAttributes.class.getTypeName() + " {",
+                  "  <init>();", // Add <init>() so it does not become a compatibility rule below.
+                  "  public static void main(java.lang.String[]);",
+                  "}",
+                  keepRules)
+              .addOptionsModification(options -> options.enableClassInlining = false)
+              .enableSideEffectAnnotations()
+              .setProguardCompatibilityRulesOutput(proguardCompatibilityRules)
+              .compile()
+              .run(TestKeepAttributes.class)
+              .assertSuccessWithOutput(innerClasses || enclosingMethod ? "1" : "0")
+              .inspector();
     } catch (CompilationFailedException e) {
       assertTrue(!forceProguardCompatibility && (!innerClasses || !enclosingMethod));
       return;
     }
-    CodeInspector inspector = new CodeInspector(app);
-    assertTrue(inspector.clazz(getJavacGeneratedClassName(mainClass)).isPresent());
-    String result;
-    if (backend == Backend.DEX) {
-      result = runOnArt(app, mainClass);
-    } else {
-      assert backend == Backend.CF;
-      result = runOnJava(app, mainClass);
-    }
-    assertEquals(innerClasses || enclosingMethod ? "1" : "0", result);
+
+    assertThat(inspector.clazz(getJavacGeneratedClassName(TestKeepAttributes.class)), isPresent());
 
     // Check the Proguard compatibility configuration generated.
     ProguardConfigurationParser parser =
         new ProguardConfigurationParser(new DexItemFactory(), new Reporter());
     parser.parse(proguardCompatibilityRules);
-    System.out.println(proguardCompatibilityRules);
     ProguardConfiguration configuration = parser.getConfigRawForTesting();
-    assertEquals(0, configuration.getRules().size());
+    assertTrue(configuration.getRules().isEmpty());
     if (innerClasses ^ enclosingMethod) {
       assertTrue(configuration.getKeepAttributes().innerClasses);
       assertTrue(configuration.getKeepAttributes().enclosingMethod);
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepattributes/TestKeepAttributes.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepattributes/TestKeepAttributes.java
index b5ac462..f7c8fd6 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepattributes/TestKeepAttributes.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/keepattributes/TestKeepAttributes.java
@@ -4,14 +4,20 @@
 
 package com.android.tools.r8.shaking.forceproguardcompatibility.keepattributes;
 
+import com.android.tools.r8.AssumeMayHaveSideEffects;
+
 public class TestKeepAttributes {
   public static class InnerClass {
 
+    @AssumeMayHaveSideEffects
+    InnerClass() {}
   }
 
-  public static void methodWithMemberClass() {
+  private static void methodWithMemberClass() {
     class MemberClass {
 
+      @AssumeMayHaveSideEffects
+      private MemberClass() {}
     }
 
     new MemberClass();
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java
index e1b071f..28f456d 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedReturnTypeTest.java
@@ -10,6 +10,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThat;
 
+import com.android.tools.r8.AssumeMayHaveSideEffects;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
@@ -25,6 +26,7 @@
       System.out.print(method().getClass().getName());
     }
 
+    @AssumeMayHaveSideEffects
     public static A method() {
       return new B();
     }
@@ -53,6 +55,7 @@
 
     static class SuperTestClass {
 
+      @AssumeMayHaveSideEffects
       public static A method() {
         return new B();
       }
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java
index d10f029..70cc711 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/MergedTypeBaseTest.java
@@ -98,6 +98,7 @@
             getAdditionalKeepRules())
         .addOptionsModification(this::configure)
         .enableClassInliningAnnotations()
+        .enableSideEffectAnnotations()
         .run(getTestClass())
         .assertSuccessWithOutput(expected)
         .inspect(this::inspect);
diff --git a/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java b/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java
index 1d6b5b0..1a8b97d 100644
--- a/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java
@@ -8,7 +8,7 @@
 import static org.hamcrest.CoreMatchers.not;
 import static org.junit.Assert.assertThat;
 
-import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -46,10 +46,11 @@
   @Test
   public void b120675359_devirtualized() throws Exception {
     Path flagToKeepTestRunner = Paths.get(ToolHelper.EXAMPLES_DIR, M_I_PKG, "keep-rules.txt");
-    R8TestBuilder builder = testForR8(backend)
-        .addProgramFiles(MOCKITO_INTERFACE_JAR)
-        .addKeepRuleFiles(flagToKeepTestRunner)
-        .minification(minify);
+    R8FullTestBuilder builder =
+        testForR8(backend)
+            .addProgramFiles(MOCKITO_INTERFACE_JAR)
+            .addKeepRuleFiles(flagToKeepTestRunner)
+            .minification(minify);
     CodeInspector inspector = builder.compile().inspector();
     ClassSubject itf = inspector.clazz(M_I);
     assertThat(itf, isPresent());
@@ -61,10 +62,11 @@
   public void b120675359_conditional_keep() throws Exception {
     Path flagToKeepInterfaceConditionally =
         Paths.get(ToolHelper.EXAMPLES_DIR, M_I_PKG, "keep-rules-conditional-on-mock.txt");
-    R8TestBuilder builder = testForR8(backend)
-        .addProgramFiles(MOCKITO_INTERFACE_JAR)
-        .addKeepRuleFiles(flagToKeepInterfaceConditionally)
-        .minification(minify);
+    R8FullTestBuilder builder =
+        testForR8(backend)
+            .addProgramFiles(MOCKITO_INTERFACE_JAR)
+            .addKeepRuleFiles(flagToKeepInterfaceConditionally)
+            .minification(minify);
     CodeInspector inspector = builder.compile().inspector();
     ClassSubject itf = inspector.clazz(M_I);
     assertThat(itf, isPresent());
diff --git a/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java b/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java
index c9efc35..f62d2d9 100644
--- a/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/reflection/ReflectiveNewInstanceTest.java
@@ -42,7 +42,10 @@
         StringUtils.lines("Success", "Success", "Success", "Success", "Success");
 
     if (parameters.getBackend() == Backend.CF) {
-      testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
+      testForJvm()
+          .addTestClasspath()
+          .run(parameters.getRuntime(), TestClass.class)
+          .assertSuccessWithOutput(expectedOutput);
     }
 
     String expectedOutputAfterR8 =
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index 5d524af..8111405 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -5,8 +5,8 @@
 package com.android.tools.r8.smali;
 
 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.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.code.Const4;
@@ -26,11 +26,9 @@
 import com.android.tools.r8.code.ReturnObject;
 import com.android.tools.r8.code.ReturnVoid;
 import com.android.tools.r8.code.ReturnWide;
-import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
 import com.android.tools.r8.utils.AndroidApp;
@@ -39,20 +37,40 @@
 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.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.function.Consumer;
-import java.util.stream.Collectors;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class OutlineTest extends SmaliTestBase {
 
-  private Consumer<InternalOptions> configureOptions(Consumer<OutlineOptions> optionsConsumer) {
+  private static final String stringBuilderAppendSignature =
+      "Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;";
+  private static final String stringBuilderAppendDoubleSignature =
+      "Ljava/lang/StringBuilder;->append(D)Ljava/lang/StringBuilder;";
+  private static final String stringBuilderAppendIntSignature =
+      "Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;";
+  private static final String stringBuilderAppendLongSignature =
+      "Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;";
+  private static final String stringBuilderToStringSignature =
+      "Ljava/lang/StringBuilder;->toString()Ljava/lang/String;";
+
+  private Consumer<InternalOptions> configureOptions(Consumer<InternalOptions> optionsConsumer) {
+    return options -> {
+      // Disable inlining to make sure that code looks as expected.
+      options.enableInlining = false;
+      // Also apply outline options.
+      optionsConsumer.accept(options);
+    };
+  }
+
+  private Consumer<InternalOptions> configureOutlineOptions(
+      Consumer<OutlineOptions> optionsConsumer) {
     return options -> {
       // Disable inlining to make sure that code looks as expected.
       options.enableInlining = false;
@@ -61,22 +79,6 @@
     };
   }
 
-  DexEncodedMethod getInvokedMethod(DexApplication application, InvokeStatic invoke) {
-    CodeInspector inspector = new CodeInspector(application);
-    ClassSubject clazz = inspector.clazz(invoke.getMethod().holder.toSourceString());
-    assertTrue(clazz.isPresent());
-    DexMethod invokedMethod = invoke.getMethod();
-    invokedMethod.proto.returnType.toSourceString();
-    MethodSubject method = clazz.method(
-        invokedMethod.proto.returnType.toSourceString(),
-        invokedMethod.name.toString(),
-        Arrays.stream(invokedMethod.proto.parameters.values)
-            .map(DexType::toSourceString)
-            .collect(Collectors.toList()));
-    assertTrue(method.isPresent());
-    return method.getMethod();
-  }
-
   private String firstOutlineMethodName() {
     return OutlineOptions.CLASS_NAME + '.' + OutlineOptions.METHOD_PREFIX + "0";
   }
@@ -92,44 +94,46 @@
 
     String returnType = "java.lang.String";
     List<String> parameters = Collections.singletonList("java.lang.StringBuilder");
-    MethodSignature signature = builder.addStaticMethod(
-        returnType,
-        DEFAULT_METHOD_NAME,
-        parameters,
-        2,
-        "    move-object         v0, p0",
-        "    const-string        v1, \"Test\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v0",
-        "    return-object       v0"
-    );
+    MethodSignature signature =
+        builder.addStaticMethod(
+            returnType,
+            DEFAULT_METHOD_NAME,
+            parameters,
+            2,
+            "    move-object         v0, p0",
+            "    const-string        v1, \"Test\"",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v0",
+            "    return-object       v0");
 
     builder.addMainMethod(
         2,
         "    sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
         "    new-instance        v1, Ljava/lang/StringBuilder;",
         "    invoke-direct       { v1 }, Ljava/lang/StringBuilder;-><init>()V",
-        "    invoke-static       { v1 }, LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
+        "    invoke-static       { v1 },"
+            + " LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
         "    move-result-object  v1",
         "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+        "    return-void");
 
     for (int i = 2; i < 6; i++) {
       final int j = i;
-      Consumer<InternalOptions> options = configureOptions(outline -> {
-        outline.threshold = 1;
-        outline.minSize = j;
-        outline.maxSize = j;
-      });
+      Consumer<InternalOptions> options =
+          configureOutlineOptions(
+              outline -> {
+                outline.threshold = 1;
+                outline.minSize = j;
+                outline.maxSize = j;
+              });
 
       AndroidApp originalApplication = buildApplication(builder);
       AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -156,47 +160,49 @@
 
     String returnType = "java.lang.String";
     List<String> parameters = Collections.singletonList("java.lang.StringBuilder");
-    MethodSignature signature = builder.addStaticMethod(
-        returnType,
-        DEFAULT_METHOD_NAME,
-        parameters,
-        2,
-        "    move-object         v0, p0",
-        "    const-string        v1, \"Test1\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    const-string        v1, \"Test2\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    const-string        v1, \"Test3\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    const-string        v1, \"Test4\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v0",
-        "    return-object       v0"
-    );
+    MethodSignature signature =
+        builder.addStaticMethod(
+            returnType,
+            DEFAULT_METHOD_NAME,
+            parameters,
+            2,
+            "    move-object         v0, p0",
+            "    const-string        v1, \"Test1\"",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    const-string        v1, \"Test2\"",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    const-string        v1, \"Test3\"",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    const-string        v1, \"Test4\"",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v0",
+            "    return-object       v0");
 
     builder.addMainMethod(
         2,
         "    sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
         "    new-instance        v1, Ljava/lang/StringBuilder;",
         "    invoke-direct       { v1 }, Ljava/lang/StringBuilder;-><init>()V",
-        "    invoke-static       { v1 }, LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
+        "    invoke-static       { v1 },"
+            + " LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
         "    move-result-object  v1",
         "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+        "    return-void");
 
     for (int i = 2; i < 6; i++) {
       final int finalI = i;
-      Consumer<InternalOptions> options = configureOptions(outline -> {
-        outline.threshold = 1;
-        outline.minSize = finalI;
-        outline.maxSize = finalI;
-      });
+      Consumer<InternalOptions> options =
+          configureOutlineOptions(
+              outline -> {
+                outline.threshold = 1;
+                outline.minSize = finalI;
+                outline.maxSize = finalI;
+              });
 
       AndroidApp originalApplication = buildApplication(builder);
       AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -229,24 +235,24 @@
     // Method with const instructions after the outline.
     String returnType = "int";
     List<String> parameters = Collections.singletonList("java.lang.StringBuilder");
-    MethodSignature signature = builder.addStaticMethod(
-        returnType,
-        DEFAULT_METHOD_NAME,
-        parameters,
-        2,
-        "    move-object         v0, p0",
-        "    const-string        v1, \"Test\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v0",
-        "    const               v0, 0",
-        "    const               v1, 1",
-        "    add-int             v1, v1, v0",
-        "    return              v1"
-    );
+    MethodSignature signature =
+        builder.addStaticMethod(
+            returnType,
+            DEFAULT_METHOD_NAME,
+            parameters,
+            2,
+            "    move-object         v0, p0",
+            "    const-string        v1, \"Test\"",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v0",
+            "    const               v0, 0",
+            "    const               v1, 1",
+            "    add-int             v1, v1, v0",
+            "    return              v1");
 
     builder.addMainMethod(
         2,
@@ -259,9 +265,7 @@
         "    return-void"
     );
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-    });
+    Consumer<InternalOptions> options = configureOutlineOptions(outline -> outline.threshold = 1);
     AndroidApp originalApplication = buildApplication(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
     assertEquals(2, getNumberOfProgramClasses(processedApplication));
@@ -288,28 +292,28 @@
     String returnType = "java.lang.String";
     List<String> parameters = ImmutableList.of(
         "java.lang.StringBuilder", "java.lang.String", "java.lang.String");
-    MethodSignature signature = builder.addStaticMethod(
-        returnType,
-        DEFAULT_METHOD_NAME,
-        parameters,
-        2,
-        "    invoke-virtual      { p0, p1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  p0",
-        "    const-string        v0, \"Test1\"",
-        "    invoke-virtual      { p0, v0 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  p0",
-        "    invoke-virtual      { p0, p2 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  p0",
-        "    const-string        v1, \"Test2\"",
-        "    invoke-virtual      { p0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  p0",
-        "    const-string        v1, \"Test3\"",
-        "    invoke-virtual      { p0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  p0",
-        "    invoke-virtual      { p0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v1",
-        "    return-object  v1"
-    );
+    MethodSignature signature =
+        builder.addStaticMethod(
+            returnType,
+            DEFAULT_METHOD_NAME,
+            parameters,
+            2,
+            "    invoke-virtual      { p0, p1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  p0",
+            "    const-string        v0, \"Test1\"",
+            "    invoke-virtual      { p0, v0 }, " + stringBuilderAppendSignature,
+            "    move-result-object  p0",
+            "    invoke-virtual      { p0, p2 }, " + stringBuilderAppendSignature,
+            "    move-result-object  p0",
+            "    const-string        v1, \"Test2\"",
+            "    invoke-virtual      { p0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  p0",
+            "    const-string        v1, \"Test3\"",
+            "    invoke-virtual      { p0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  p0",
+            "    invoke-virtual      { p0 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v1",
+            "    return-object  v1");
 
     builder.addMainMethod(
         4,
@@ -318,15 +322,13 @@
         "    invoke-direct       { v1 }, Ljava/lang/StringBuilder;-><init>()V",
         "    const-string        v2, \"TestX\"",
         "    const-string        v3, \"TestY\"",
-        "    invoke-static       { v1, v2, v3 }, LTest;->method(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+        "    invoke-static       { v1, v2, v3 },"
+            + " LTest;->method(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
         "    move-result-object  v1",
         "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+        "    return-void");
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-    });
+    Consumer<InternalOptions> options = configureOutlineOptions(outline -> outline.threshold = 1);
     AndroidApp originalApplication = buildApplication(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
     assertEquals(2, getNumberOfProgramClasses(processedApplication));
@@ -352,44 +354,46 @@
 
     String returnType = "java.lang.String";
     List<String> parameters = Collections.singletonList("java.lang.StringBuilder");
-    MethodSignature signature = builder.addStaticMethod(
-        returnType,
-        DEFAULT_METHOD_NAME,
-        parameters,
-        3,
-        "    move-object         v0, p0",
-        "    const-wide          v1, 0x7fffffff00000000L",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v0",
-        "    return-object       v0"
-    );
+    MethodSignature signature =
+        builder.addStaticMethod(
+            returnType,
+            DEFAULT_METHOD_NAME,
+            parameters,
+            3,
+            "    move-object         v0, p0",
+            "    const-wide          v1, 0x7fffffff00000000L",
+            "    invoke-virtual      { v0, v1, v2 }, " + stringBuilderAppendLongSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1, v2 }, " + stringBuilderAppendLongSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1, v2 }, " + stringBuilderAppendLongSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1, v2 }, " + stringBuilderAppendLongSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v0",
+            "    return-object       v0");
 
     builder.addMainMethod(
         2,
         "    sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
         "    new-instance        v1, Ljava/lang/StringBuilder;",
         "    invoke-direct       { v1 }, Ljava/lang/StringBuilder;-><init>()V",
-        "    invoke-static       { v1 }, LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
+        "    invoke-static       { v1 },"
+            + " LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
         "    move-result-object  v1",
         "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+        "    return-void");
 
     for (int i = 2; i < 4; i++) {
       final int finalI = i;
-      Consumer<InternalOptions> options = configureOptions(outline -> {
-        outline.threshold = 1;
-        outline.minSize = finalI;
-        outline.maxSize = finalI;
-      });
+      Consumer<InternalOptions> options =
+          configureOutlineOptions(
+              outline -> {
+                outline.threshold = 1;
+                outline.minSize = finalI;
+                outline.maxSize = finalI;
+              });
 
       AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
       AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -428,44 +432,46 @@
 
     String returnType = "java.lang.String";
     List<String> parameters = Collections.singletonList("java.lang.StringBuilder");
-    MethodSignature signature = builder.addStaticMethod(
-        returnType,
-        DEFAULT_METHOD_NAME,
-        parameters,
-        3,
-        "    move-object         v0, p0",
-        "    const-wide          v1, 0x3ff0000000000000L",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/lang/StringBuilder;->append(D)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/lang/StringBuilder;->append(D)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/lang/StringBuilder;->append(D)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/lang/StringBuilder;->append(D)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v0",
-        "    return-object       v0"
-    );
+    MethodSignature signature =
+        builder.addStaticMethod(
+            returnType,
+            DEFAULT_METHOD_NAME,
+            parameters,
+            3,
+            "    move-object         v0, p0",
+            "    const-wide          v1, 0x3ff0000000000000L",
+            "    invoke-virtual      { v0, v1, v2 }, " + stringBuilderAppendDoubleSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1, v2 }, " + stringBuilderAppendDoubleSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1, v2 }, " + stringBuilderAppendDoubleSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1, v2 }, " + stringBuilderAppendDoubleSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v0",
+            "    return-object       v0");
 
     builder.addMainMethod(
         2,
         "    sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
         "    new-instance        v1, Ljava/lang/StringBuilder;",
         "    invoke-direct       { v1 }, Ljava/lang/StringBuilder;-><init>()V",
-        "    invoke-static       { v1 }, LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
+        "    invoke-static       { v1 },"
+            + " LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
         "    move-result-object  v1",
         "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+        "    return-void");
 
     for (int i = 2; i < 4; i++) {
       final int finalI = i;
-      Consumer<InternalOptions> options = configureOptions(outline -> {
-        outline.threshold = 1;
-        outline.minSize = finalI;
-        outline.maxSize = finalI;
-      });
+      Consumer<InternalOptions> options =
+          configureOutlineOptions(
+              outline -> {
+                outline.threshold = 1;
+                outline.minSize = finalI;
+                outline.maxSize = finalI;
+              });
 
       AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
       AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -504,40 +510,41 @@
 
     String returnType = "void";
     List<String> parameters = ImmutableList.of("java.lang.StringBuilder", "int");
-    MethodSignature signature = builder.addStaticMethod(
+    builder.addStaticMethod(
         returnType,
         DEFAULT_METHOD_NAME,
         parameters,
         1,
-        "    invoke-virtual      { p0, p1 }, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;",
+        "    invoke-virtual      { p0, p1 }, " + stringBuilderAppendIntSignature,
         "    move-result-object  v0",
-        "    invoke-virtual      { p0, p1 }, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;",
+        "    invoke-virtual      { p0, p1 }, " + stringBuilderAppendIntSignature,
         "    move-result-object  v0",
-        "    return-void"
-    );
+        "    return-void");
 
-    MethodSignature mainSignature = builder.addMainMethod(
-        2,
-        "    new-instance        v0, Ljava/lang/StringBuilder;",
-        "    invoke-direct       { v0 }, Ljava/lang/StringBuilder;-><init>()V",
-        "    const/4             v1, 0x1",
-        "    invoke-static       { v0, v1 }, LTest;->method(Ljava/lang/StringBuilder;I)V",
-        "    const/4             v1, 0x2",
-        "    invoke-static       { v0, v1 }, LTest;->method(Ljava/lang/StringBuilder;I)V",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v1",
-        "    sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
-        "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+    MethodSignature mainSignature =
+        builder.addMainMethod(
+            2,
+            "    new-instance        v0, Ljava/lang/StringBuilder;",
+            "    invoke-direct       { v0 }, Ljava/lang/StringBuilder;-><init>()V",
+            "    const/4             v1, 0x1",
+            "    invoke-static       { v0, v1 }, LTest;->method(Ljava/lang/StringBuilder;I)V",
+            "    const/4             v1, 0x2",
+            "    invoke-static       { v0, v1 }, LTest;->method(Ljava/lang/StringBuilder;I)V",
+            "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v1",
+            "    sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
+            "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
+            "    return-void");
 
     for (int i = 2; i < 6; i++) {
       final int finalI = i;
-      Consumer<InternalOptions> options = configureOptions(outline -> {
-        outline.threshold = 1;
-        outline.minSize = finalI;
-        outline.maxSize = finalI;
-      });
+      Consumer<InternalOptions> options =
+          configureOutlineOptions(
+              outline -> {
+                outline.threshold = 1;
+                outline.minSize = finalI;
+                outline.maxSize = finalI;
+              });
 
       AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
       AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -577,50 +584,50 @@
   public void constructor() throws Exception {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
-    MethodSignature signature1 = builder.addStaticMethod(
-        "java.lang.String",
-        "method1",
-        Collections.emptyList(),
-        3,
-        "    new-instance        v0, Ljava/lang/StringBuilder;",
-        "    invoke-direct       { v0 }, Ljava/lang/StringBuilder;-><init>()V",
-        "    const-string        v1, \"Test1\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v0",
-        "    return-object       v0"
-    );
+    MethodSignature signature1 =
+        builder.addStaticMethod(
+            "java.lang.String",
+            "method1",
+            Collections.emptyList(),
+            3,
+            "    new-instance        v0, Ljava/lang/StringBuilder;",
+            "    invoke-direct       { v0 }, Ljava/lang/StringBuilder;-><init>()V",
+            "    const-string        v1, \"Test1\"",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v0",
+            "    return-object       v0");
 
-    MethodSignature signature2 = builder.addStaticMethod(
-        "java.lang.String",
-        "method2",
-        Collections.emptyList(),
-        3,
-        "    const/4             v1, 7",
-        "    new-instance        v0, Ljava/lang/StringBuilder;",
-        "    invoke-direct       { v0, v1 }, Ljava/lang/StringBuilder;-><init>(I)V",
-        "    const-string        v1, \"Test2\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v0",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v0",
-        "    return-object       v0"
-    );
+    MethodSignature signature2 =
+        builder.addStaticMethod(
+            "java.lang.String",
+            "method2",
+            Collections.emptyList(),
+            3,
+            "    const/4             v1, 7",
+            "    new-instance        v0, Ljava/lang/StringBuilder;",
+            "    invoke-direct       { v0, v1 }, Ljava/lang/StringBuilder;-><init>(I)V",
+            "    const-string        v1, \"Test2\"",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v0",
+            "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v0",
+            "    return-object       v0");
 
-    MethodSignature mainSignature = builder.addMainMethod(
+    builder.addMainMethod(
         2,
         "    sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
         "    invoke-static       {}, LTest;->method1()Ljava/lang/String;",
@@ -629,14 +636,15 @@
         "    invoke-static       {}, LTest;->method2()Ljava/lang/String;",
         "    move-result-object  v1",
         "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+        "    return-void");
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 7;
-      outline.maxSize = 7;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 1;
+              outline.minSize = 7;
+              outline.maxSize = 7;
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -663,46 +671,48 @@
   public void constructorDontSplitNewInstanceAndInit() throws Exception {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
-    MethodSignature signature = builder.addStaticMethod(
-        "java.lang.String",
-        DEFAULT_METHOD_NAME,
-        ImmutableList.of("java.lang.StringBuilder"),
-        2,
-        "    const-string        v0, \"Test1\"",
-        "    invoke-virtual      { p0, v0 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  p0",
-        "    invoke-virtual      { p0, v0 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  p0",
-        "    new-instance        v1, Ljava/lang/StringBuilder;",
-        "    invoke-direct       { v1 }, Ljava/lang/StringBuilder;-><init>()V",
-        "    const-string        v0, \"Test2\"",
-        "    invoke-virtual      { v1, v0 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v1",
-        "    invoke-virtual      { v1, v0 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
-        "    move-result-object  v1",
-        "    invoke-virtual      { v1 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v0",
-        "    return-object       v0"
-    );
+    MethodSignature signature =
+        builder.addStaticMethod(
+            "java.lang.String",
+            DEFAULT_METHOD_NAME,
+            ImmutableList.of("java.lang.StringBuilder"),
+            2,
+            "    const-string        v0, \"Test1\"",
+            "    invoke-virtual      { p0, v0 }, " + stringBuilderAppendSignature,
+            "    move-result-object  p0",
+            "    invoke-virtual      { p0, v0 }, " + stringBuilderAppendSignature,
+            "    move-result-object  p0",
+            "    new-instance        v1, Ljava/lang/StringBuilder;",
+            "    invoke-direct       { v1 }, Ljava/lang/StringBuilder;-><init>()V",
+            "    const-string        v0, \"Test2\"",
+            "    invoke-virtual      { v1, v0 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v1",
+            "    invoke-virtual      { v1, v0 }, " + stringBuilderAppendSignature,
+            "    move-result-object  v1",
+            "    invoke-virtual      { v1 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v0",
+            "    return-object       v0");
 
-    MethodSignature mainSignature = builder.addMainMethod(
+    builder.addMainMethod(
         2,
         "    sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
         "    new-instance        v1, Ljava/lang/StringBuilder;",
         "    invoke-direct       { v1 }, Ljava/lang/StringBuilder;-><init>()V",
-        "    invoke-static       { v1 }, LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
+        "    invoke-static       { v1 },"
+            + " LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
         "    move-result-object  v1",
         "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+        "    return-void");
 
     for (int i = 2; i < 8; i++) {
       final int finalI = i;
-      Consumer<InternalOptions> options = configureOptions(outline -> {
-        outline.threshold = 1;
-        outline.minSize = finalI;
-        outline.maxSize = finalI;
-      });
+      Consumer<InternalOptions> options =
+          configureOutlineOptions(
+              outline -> {
+                outline.threshold = 1;
+                outline.minSize = finalI;
+                outline.maxSize = finalI;
+              });
 
       AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
       AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -740,32 +750,33 @@
   public void outlineWithoutArguments() throws Exception {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
-    MethodSignature signature1 = builder.addStaticMethod(
-        "java.lang.String",
-        DEFAULT_METHOD_NAME,
-        Collections.emptyList(),
-        1,
-        "    new-instance        v0, Ljava/lang/StringBuilder;",
-        "    invoke-direct       { v0 }, Ljava/lang/StringBuilder;-><init>()V",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    move-result-object  v0",
-        "    return-object       v0"
-    );
+    MethodSignature signature1 =
+        builder.addStaticMethod(
+            "java.lang.String",
+            DEFAULT_METHOD_NAME,
+            Collections.emptyList(),
+            1,
+            "    new-instance        v0, Ljava/lang/StringBuilder;",
+            "    invoke-direct       { v0 }, Ljava/lang/StringBuilder;-><init>()V",
+            "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
+            "    move-result-object  v0",
+            "    return-object       v0");
 
-    MethodSignature mainSignature = builder.addMainMethod(
+    builder.addMainMethod(
         2,
         "    sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
         "    invoke-static       {}, LTest;->method()Ljava/lang/String;",
         "    move-result-object  v1",
         "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+        "    return-void");
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 3;
-      outline.maxSize = 3;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 1;
+              outline.minSize = 3;
+              outline.maxSize = 3;
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -791,37 +802,35 @@
     // The naming of the methods in this test is important. The method name that don't use the
     // output from StringBuilder.toString must sort before the method name that does.
     String returnType1 = "void";
-    MethodSignature signature1 = builder.addStaticMethod(
+    builder.addStaticMethod(
         returnType1,
         "method1",
         parameters,
         2,
         "    move-object         v0, p0",
         "    const-string        v1, \"Test\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+        "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
         "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+        "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
         "    move-result-object  v0",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
-        "    return-void"
-    );
+        "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
+        "    return-void");
 
     String returnType2 = "java.lang.String";
-    MethodSignature signature2 = builder.addStaticMethod(
+    builder.addStaticMethod(
         returnType2,
         "method2",
         parameters,
         2,
         "    move-object         v0, p0",
         "    const-string        v1, \"Test\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+        "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
         "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+        "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
         "    move-result-object  v0",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
+        "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
         "    move-result-object  v0",
-        "    return-object       v0"
-    );
+        "    return-object       v0");
 
     builder.addMainMethod(
         3,
@@ -829,17 +838,19 @@
         "    new-instance        v1, Ljava/lang/StringBuilder;",
         "    invoke-direct       { v1 }, Ljava/lang/StringBuilder;-><init>()V",
         "    invoke-static       { v1 }, LTest;->method1(Ljava/lang/StringBuilder;)V",
-        "    invoke-static       { v1 }, LTest;->method2(Ljava/lang/StringBuilder;)Ljava/lang/String;",
+        "    invoke-static       { v1 },"
+            + " LTest;->method2(Ljava/lang/StringBuilder;)Ljava/lang/String;",
         "    move-result-object  v2",
         "    invoke-virtual      { v0, v2 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+        "    return-void");
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 3;
-      outline.maxSize = 3;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 1;
+              outline.minSize = 3;
+              outline.maxSize = 3;
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -876,42 +887,43 @@
 
     String returnType = "java.lang.String";
     List<String> parameters = Collections.singletonList("java.lang.StringBuilder");
-    MethodSignature signature = builder.addStaticMethod(
+    builder.addStaticMethod(
         returnType,
         DEFAULT_METHOD_NAME,
         parameters,
         2,
         "    move-object         v0, p0",
         "    const-string        v1, \"Test\"",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+        "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
         "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+        "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
         "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+        "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
         "    move-result-object  v0",
-        "    invoke-virtual      { v0, v1 }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+        "    invoke-virtual      { v0, v1 }, " + stringBuilderAppendSignature,
         "    move-result-object  v0",
-        "    invoke-virtual      { v0 }, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
+        "    invoke-virtual      { v0 }, " + stringBuilderToStringSignature,
         "    move-result-object  v0",
-        "    return-object       v0"
-    );
+        "    return-object       v0");
 
     builder.addMainMethod(
         2,
         "    sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;",
         "    new-instance        v1, Ljava/lang/StringBuilder;",
         "    invoke-direct       { v1 }, Ljava/lang/StringBuilder;-><init>()V",
-        "    invoke-static       { v1 }, LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
+        "    invoke-static       { v1 },"
+            + " LTest;->method(Ljava/lang/StringBuilder;)Ljava/lang/String;",
         "    move-result-object  v1",
         "    invoke-virtual      { v0, v1 }, Ljava/io/PrintStream;->print(Ljava/lang/String;)V",
-        "    return-void"
-    );
+        "    return-void");
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 3;
-      outline.maxSize = 3;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 1;
+              outline.minSize = 3;
+              outline.maxSize = 3;
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -927,11 +939,13 @@
     }
 
     // Process the application several times. No more outlining as threshold has been raised.
-    options = configureOptions(outline -> {
-      outline.threshold = 2;
-      outline.minSize = 3;
-      outline.maxSize = 3;
-    });
+    options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 2;
+              outline.minSize = 3;
+              outline.maxSize = 3;
+            });
     for (int i = 0; i < count; i++) {
       // Build a new application with the Outliner class.
       originalApplication = processedApplication;
@@ -972,11 +986,13 @@
         "    return-void"
     );
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 5;
-      outline.maxSize = 5;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 1;
+              outline.minSize = 5;
+              outline.maxSize = 5;
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1036,11 +1052,13 @@
         "    return-void"
     );
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 5;
-      outline.maxSize = 5;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 1;
+              outline.minSize = 5;
+              outline.maxSize = 5;
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1086,11 +1104,13 @@
         "    return-void"
     );
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 4;
-      outline.maxSize = 4;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 1;
+              outline.minSize = 4;
+              outline.maxSize = 4;
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1161,11 +1181,13 @@
         "    return-void"
     );
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 4;
-      outline.maxSize = 4;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 1;
+              outline.minSize = 4;
+              outline.maxSize = 4;
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1237,11 +1259,13 @@
         "    return-void"
     );
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 3;  // Outline add, sub and mul.
-      outline.maxSize = 3;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 1;
+              outline.minSize = 3; // Outline add, sub and mul.
+              outline.maxSize = 3;
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1290,11 +1314,27 @@
         "    return-void"
     );
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 3;
-      outline.maxSize = 3;
-    });
+    Consumer<InternalOptions> options =
+        configureOptions(
+            opts -> {
+              opts.outline.threshold = 1;
+              opts.outline.minSize = 3;
+              opts.outline.maxSize = 3;
+
+              // Do not allow dead code elimination of the new-instance and invoke-direct
+              // instructions.
+              // This can be achieved by not assuming that StringBuilder is present.
+              DexItemFactory dexItemFactory = opts.itemFactory;
+              dexItemFactory.libraryTypesAssumedToBePresent =
+                  new HashSet<>(dexItemFactory.libraryTypesAssumedToBePresent);
+              dexItemFactory.libraryTypesAssumedToBePresent.remove(
+                  dexItemFactory.stringBuilderType);
+              // ... and not assuming that StringBuilder.<init>() cannot have side effects.
+              dexItemFactory.libraryMethodsWithoutSideEffects =
+                  new HashSet<>(dexItemFactory.libraryMethodsWithoutSideEffects);
+              dexItemFactory.libraryMethodsWithoutSideEffects.remove(
+                  dexItemFactory.stringBuilderMethods.constructor);
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1336,11 +1376,22 @@
         "    return-void"
     );
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 1;
-      outline.minSize = 3;
-      outline.maxSize = 3;
-    });
+    Consumer<InternalOptions> options =
+        configureOptions(
+            opts -> {
+              opts.outline.threshold = 1;
+              opts.outline.minSize = 3;
+              opts.outline.maxSize = 3;
+
+              // Do not allow dead code elimination of the new-instance instructions. This can be
+              // achieved
+              // by not assuming that StringBuilder is present.
+              DexItemFactory dexItemFactory = opts.itemFactory;
+              opts.itemFactory.libraryTypesAssumedToBePresent =
+                  new HashSet<>(dexItemFactory.libraryTypesAssumedToBePresent);
+              dexItemFactory.libraryTypesAssumedToBePresent.remove(
+                  dexItemFactory.stringBuilderType);
+            });
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1375,22 +1426,26 @@
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x01  # 1",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \" http://schemas.google.com/g/2005#work\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x02  # 2",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#other\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x03  # 3",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#primary\"",
         "    const/4             v2, 0x04  # 4",
         "    invoke-static       { v2 }, Ljava/lang/Byte;->valueOf(B)Ljava/lang/Byte;",
         "    move-result-object  v2",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    sput-object         v0, LA;->A:Ljava/util/Hashtable;",
         "    invoke-static       { v0 }, LA;->a(Ljava/util/Hashtable;)Ljava/util/Hashtable;",
         "    move-result-object  v0",
@@ -1401,37 +1456,44 @@
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x02  # 2",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#mobile\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x01  # 1",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#pager\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x06  # 6",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#work\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x03  # 3",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#home_fax\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x05  # 5",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#work_fax\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x04  # 4",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#other\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x07  # 7",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    sput-object         v0, LA;->C:Ljava/util/Hashtable;",
         "    invoke-static       { v0 }, LA;->a(Ljava/util/Hashtable;)Ljava/util/Hashtable;",
         "    move-result-object  v0",
@@ -1442,17 +1504,20 @@
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x01  # 1",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#work\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x02  # 2",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#other\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x03  # 3",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    sput-object         v0, LA;->E:Ljava/util/Hashtable;",
         "    invoke-static       { v0 }, LA;->a(Ljava/util/Hashtable;)Ljava/util/Hashtable;",
         "    move-result-object  v0",
@@ -1463,17 +1528,20 @@
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x01  # 1",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#work\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x02  # 2",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#other\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x03  # 3",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    sput-object         v0, LA;->G:Ljava/util/Hashtable;",
         "    invoke-static       { v0 }, LA;->a(Ljava/util/Hashtable;)Ljava/util/Hashtable;",
         "    move-result-object  v0",
@@ -1484,12 +1552,14 @@
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x01  # 1",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#other\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x02  # 2",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    sput-object         v0, LA;->I:Ljava/util/Hashtable;",
         "    invoke-static       { v0 }, LA;->a(Ljava/util/Hashtable;)Ljava/util/Hashtable;",
         "    move-result-object  v0",
@@ -1500,52 +1570,57 @@
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x02  # 2",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#MSN\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x03  # 3",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#YAHOO\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x04  # 4",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#SKYPE\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x05  # 5",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#QQ\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x06  # 6",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#GOOGLE_TALK\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/4             v3, 0x07  # 7",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#ICQ\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/16            v3, 0x0008  # 8",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    const-string        v1, \"http://schemas.google.com/g/2005#JABBER\"",
         "    new-instance        v2, Ljava/lang/Byte;",
         "    const/16            v3, 0x0009  # 9",
         "    invoke-direct       { v2, v3 }, Ljava/lang/Byte;-><init>(B)V",
-        "    invoke-virtual      { v0, v1, v2 }, Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+        "    invoke-virtual      { v0, v1, v2 },"
+            + " Ljava/util/Hashtable;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
         "    sput-object         v0, LA;->K:Ljava/util/Hashtable;",
         "    invoke-static       { v0 }, LA;->a(Ljava/util/Hashtable;)Ljava/util/Hashtable;",
         "    move-result-object  v0",
         "    sput-object         v0, LA;->L:Ljava/util/Hashtable;",
-        "    return-void"
-    );
+        "    return-void");
 
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 2;
-    });
+    Consumer<InternalOptions> options = configureOutlineOptions(outline -> outline.threshold = 2);
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1617,11 +1692,13 @@
     );
 
     // Outline 2 times two instructions.
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 2;
-      outline.minSize = 2;
-      outline.maxSize = 2;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 2;
+              outline.minSize = 2;
+              outline.maxSize = 2;
+            });
 
     AndroidApp originalApplication = buildApplication(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1690,11 +1767,13 @@
     );
 
     // Outline 2 times two instructions.
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 2;
-      outline.minSize = 2;
-      outline.maxSize = 2;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 2;
+              outline.minSize = 2;
+              outline.maxSize = 2;
+            });
 
     AndroidApp originalApplication = buildApplication(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1762,11 +1841,13 @@
     );
 
     // Outline 2 times two instructions.
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 2;
-      outline.minSize = 2;
-      outline.maxSize = 2;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 2;
+              outline.minSize = 2;
+              outline.maxSize = 2;
+            });
 
     AndroidApp originalApplication = buildApplication(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);
@@ -1834,11 +1915,13 @@
     );
 
     // Outline 2 times two instructions.
-    Consumer<InternalOptions> options = configureOptions(outline -> {
-      outline.threshold = 2;
-      outline.minSize = 2;
-      outline.maxSize = 2;
-    });
+    Consumer<InternalOptions> options =
+        configureOutlineOptions(
+            outline -> {
+              outline.threshold = 2;
+              outline.minSize = 2;
+              outline.maxSize = 2;
+            });
 
     AndroidApp originalApplication = buildApplication(builder);
     AndroidApp processedApplication = processApplication(originalApplication, options);