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);