Prune single caller inlined methods on-the-fly
Fixes: 130721661
Fixes: 202419103
Change-Id: I1a83ada3ee6cfdc6aed60126c9ac6f056aea08dd
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 9c6d6c3..8617b7e 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -52,6 +52,7 @@
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import com.android.tools.r8.ir.optimize.AssertionsRewriter;
+import com.android.tools.r8.ir.optimize.Inliner;
import com.android.tools.r8.ir.optimize.NestReducer;
import com.android.tools.r8.ir.optimize.SwitchMapCollector;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxingCfMethods;
@@ -621,8 +622,7 @@
new BridgeHoisting(appViewWithLiveness).run();
- // TODO(b/130721661): Enable this assert.
- // assert Inliner.verifyNoMethodsInlinedDueToSingleCallSite(appView);
+ assert Inliner.verifyAllSingleCallerMethodsHaveBeenPruned(appView);
assert appView.allMergedClasses().verifyAllSourcesPruned(appViewWithLiveness);
assert appView.validateUnboxedEnumsHaveBeenPruned();
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 450bc51..209e51c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -733,6 +733,11 @@
setCode(builder.build(), appView);
}
+ public void unsetCode() {
+ checkIfObsolete();
+ code = null;
+ }
+
public boolean keepLocals(InternalOptions options) {
if (options.testing.noLocalsTableOnInput) {
return false;
@@ -908,24 +913,6 @@
return getReference().toSourceString();
}
- public DexEncodedMethod toAbstractMethod() {
- checkIfObsolete();
- // 'final' wants this to be *not* overridden, while 'abstract' wants this to be implemented in
- // a subtype, i.e., self contradict.
- assert !accessFlags.isFinal();
- // static abstract is an invalid access combination and we should never create that.
- assert !accessFlags.isStatic();
- return builder(this)
- .modifyAccessFlags(MethodAccessFlags::setAbstract)
- .setIsLibraryMethodOverrideIf(
- isNonPrivateVirtualMethod() && !isLibraryMethodOverride().isUnknown(),
- isLibraryMethodOverride())
- .unsetCode()
- .addBuildConsumer(
- method -> OptimizationFeedbackSimple.getInstance().unsetBridgeInfo(method))
- .build();
- }
-
/**
* Generates a {@link DexCode} object for the given instructions.
*/
@@ -1369,6 +1356,10 @@
return apiLevelForCode;
}
+ public void clearApiLevelForCode(AppView<?> appView) {
+ this.apiLevelForCode = AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView);
+ }
+
public void setApiLevelForCode(AndroidApiLevel apiLevel) {
assert apiLevel != null;
this.apiLevelForCode = apiLevel;
diff --git a/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java b/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
index 23bd9f7..cd5e8de 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
@@ -127,6 +127,10 @@
set(Constants.ACC_SYNCHRONIZED);
}
+ public void demoteFromSynchronized() {
+ demote(Constants.ACC_SYNCHRONIZED);
+ }
+
public void unsetSynchronized() {
unset(Constants.ACC_SYNCHRONIZED);
}
@@ -179,6 +183,14 @@
set(Constants.ACC_ABSTRACT);
}
+ public void demoteFromAbstract() {
+ demote(Constants.ACC_ABSTRACT);
+ }
+
+ public void promoteToAbstract() {
+ promote(Constants.ACC_ABSTRACT);
+ }
+
public void unsetAbstract() {
unset(Constants.ACC_ABSTRACT);
}
@@ -191,6 +203,10 @@
set(Constants.ACC_STRICT);
}
+ public void demoteFromStrict() {
+ demote(Constants.ACC_STRICT);
+ }
+
public void unsetStrict() {
unset(Constants.ACC_STRICT);
}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index c03a7b8..84ec3c5 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -3,16 +3,21 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static com.android.tools.r8.ir.optimize.info.OptimizationFeedback.getSimpleFeedback;
+
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.MethodPosition;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.AndroidApiLevel;
/** Type representing a method definition in the programs compilation unit and its holder. */
public final class ProgramMethod extends DexClassAndMethod
@@ -66,6 +71,44 @@
definition.parameterAnnotationsList.collectIndexedItems(indexedItems);
}
+ public void convertToAbstractOrThrowNullMethod(AppView<AppInfoWithLiveness> appView) {
+ if (!convertToAbstractMethodIfPossible(appView)) {
+ convertToThrowNullMethod(appView);
+ }
+ }
+
+ private boolean convertToAbstractMethodIfPossible(AppView<AppInfoWithLiveness> appView) {
+ boolean canBeAbstract =
+ (appView.options().canUseAbstractMethodOnNonAbstractClass()
+ || getHolder().isAbstract()
+ || getHolder().isInterface())
+ && !getAccessFlags().isNative()
+ && !getAccessFlags().isPrivate()
+ && !getAccessFlags().isStatic()
+ && !appView.appInfo().isFailedResolutionTarget(getReference());
+ if (canBeAbstract) {
+ MethodAccessFlags accessFlags = getAccessFlags();
+ accessFlags.demoteFromFinal();
+ accessFlags.demoteFromStrict();
+ accessFlags.demoteFromSynchronized();
+ accessFlags.promoteToAbstract();
+ getDefinition().clearApiLevelForCode(appView);
+ getDefinition().unsetCode();
+ getSimpleFeedback().unsetOptimizationInfoForAbstractMethod(this);
+ }
+ return canBeAbstract;
+ }
+
+ public void convertToThrowNullMethod(AppView<?> appView) {
+ MethodAccessFlags accessFlags = getAccessFlags();
+ accessFlags.demoteFromAbstract();
+ Code emptyThrowingCode = getDefinition().buildEmptyThrowingCode(appView.options());
+ getDefinition().setApiLevelForCode(AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView));
+ getDefinition().setCode(emptyThrowingCode, appView);
+ getSimpleFeedback().markProcessed(getDefinition(), ConstraintWithTarget.ALWAYS);
+ getSimpleFeedback().unsetOptimizationInfoForThrowNullMethod(this);
+ }
+
public void registerCodeReferences(UseRegistry<?> registry) {
Code code = getDefinition().getCode();
if (code != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java b/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java
index 92a127d..4899a50 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallSiteInformation.java
@@ -82,6 +82,12 @@
continue;
}
+ if (method.getDefinition().isDefaultInitializer()
+ && appView.hasProguardCompatibilityActions()
+ && appView.getProguardCompatibilityActions().isCompatInstantiated(method.getHolder())) {
+ continue;
+ }
+
int numberOfCallSites = node.getNumberOfCallSites();
if (numberOfCallSites == 1) {
singleCallSite.add(reference);
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 1d1a698..4fde21a 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
@@ -270,7 +270,7 @@
: null;
this.enumUnboxer = EnumUnboxer.create(appViewWithLiveness);
this.lensCodeRewriter = new LensCodeRewriter(appViewWithLiveness, enumUnboxer);
- this.inliner = new Inliner(appViewWithLiveness, lensCodeRewriter);
+ this.inliner = new Inliner(appViewWithLiveness, this, lensCodeRewriter);
this.outliner = Outliner.create(appViewWithLiveness);
this.memberValuePropagation =
options.enableValuePropagation ? new MemberValuePropagation(appViewWithLiveness) : null;
@@ -360,8 +360,7 @@
public void convert(AppView<AppInfo> appView, ExecutorService executor)
throws ExecutionException {
LambdaDeserializationMethodRemover.run(appView);
- workaroundAbstractMethodOnNonAbstractClassVerificationBug(
- executor, OptimizationFeedbackIgnore.getInstance());
+ workaroundAbstractMethodOnNonAbstractClassVerificationBug(executor);
DexApplication application = appView.appInfo().app();
D8MethodProcessor methodProcessor = new D8MethodProcessor(this, executor);
InterfaceProcessor interfaceProcessor =
@@ -603,7 +602,7 @@
}
private void workaroundAbstractMethodOnNonAbstractClassVerificationBug(
- ExecutorService executorService, OptimizationFeedback feedback) throws ExecutionException {
+ ExecutorService executorService) throws ExecutionException {
if (!options.canHaveDalvikAbstractMethodOnNonAbstractClassVerificationBug()) {
return;
}
@@ -612,13 +611,8 @@
appView.appInfo().classes(),
clazz -> {
if (!clazz.isAbstract()) {
- clazz.forEachMethod(
- method -> {
- if (method.isAbstract()) {
- method.accessFlags.unsetAbstract();
- finalizeEmptyThrowingCode(method, feedback);
- }
- });
+ clazz.forEachProgramMethodMatching(
+ DexEncodedMethod::isAbstract, method -> method.convertToThrowNullMethod(appView));
}
},
executorService);
@@ -633,8 +627,7 @@
DexApplication application = appView.appInfo().app();
computeReachabilitySensitivity(application);
- workaroundAbstractMethodOnNonAbstractClassVerificationBug(
- executorService, simpleOptimizationFeedback);
+ workaroundAbstractMethodOnNonAbstractClassVerificationBug(executorService);
// The process is in two phases in general.
// 1) Subject all DexEncodedMethods to optimization, except some optimizations that require
@@ -975,16 +968,6 @@
processMethodsConcurrently(methods, executorService);
}
- public void optimizeSynthesizedClasses(
- Collection<DexProgramClass> classes, ExecutorService executorService)
- throws ExecutionException {
- SortedProgramMethodSet methods = SortedProgramMethodSet.create();
- for (DexProgramClass clazz : classes) {
- clazz.forEachProgramMethod(methods::add);
- }
- processMethodsConcurrently(methods, executorService);
- }
-
public void optimizeSynthesizedMethod(ProgramMethod synthesizedMethod) {
if (!synthesizedMethod.getDefinition().isProcessed()) {
// Process the generated method, but don't apply any outlining.
@@ -1188,8 +1171,8 @@
+ ExceptionUtils.getMainStackTrace();
assert !method.isProcessed()
|| !appView.enableWholeProgramOptimizations()
- || !appView.appInfo().withLiveness().isNeverReprocessMethod(method.getReference())
- : "Illegal reprocessing due to -neverreprocess rule: " + context.toSourceString();
+ || !appView.appInfo().withLiveness().isNeverReprocessMethod(context)
+ : "Unexpected reprocessing of method: " + context.toSourceString();
if (typeChecker != null && !typeChecker.check(code)) {
assert appView.enableWholeProgramOptimizations();
@@ -1200,14 +1183,14 @@
+ method.toSourceString()
+ "` does not type check and will be assumed to be unreachable.");
options.reporter.warning(warning);
- finalizeEmptyThrowingCode(method, feedback);
+ context.convertToThrowNullMethod(appView);
return timing;
}
// This is the first point in time where we can assert that the types are sound. If this
// assert fails, then the types that we have inferred are unsound, or the method does not type
// check. In the latter case, the type checker should be extended to detect the issue such that
- // we will return with finalizeEmptyThrowingCode() above.
+ // we will return with a throw-null method above.
assert code.verifyTypes(appView);
assert code.isConsistentSSA();
@@ -1653,13 +1636,6 @@
}
}
- private void finalizeEmptyThrowingCode(DexEncodedMethod method, OptimizationFeedback feedback) {
- assert options.isGeneratingClassFiles() || options.isGeneratingDex();
- Code emptyThrowingCode = method.buildEmptyThrowingCode(options);
- method.setCode(emptyThrowingCode, appView);
- feedback.markProcessed(method, ConstraintWithTarget.ALWAYS);
- }
-
private void finalizeToCf(
IRCode code, OptimizationFeedback feedback, MethodConversionOptions conversionOptions) {
DexEncodedMethod method = code.method();
@@ -1984,6 +1960,7 @@
public void pruneMethod(ProgramMethod method) {
assert appView.enableWholeProgramOptimizations();
assert method.getHolder().lookupMethod(method.getReference()) == null;
+ appView.withArgumentPropagator(argumentPropagator -> argumentPropagator.pruneMethod(method));
if (inliner != null) {
inliner.pruneMethod(method);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
index a54b717..6435f37 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
@@ -82,10 +82,6 @@
methodsToRevisit.forEach(this::add);
}
- public void put(PostOptimization postOptimization) {
- put(postOptimization.methodsToRevisit());
- }
-
// Some optimizations may change methods, creating new instances of the encoded methods with a
// new signature. The compiler needs to update the set of methods that must be reprocessed
// according to the graph lens.
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostOptimization.java b/src/main/java/com/android/tools/r8/ir/conversion/PostOptimization.java
deleted file mode 100644
index 30c873d..0000000
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostOptimization.java
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.ir.conversion;
-
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
-
-/**
- * An abstraction of optimizations that require post processing of methods.
- */
-public interface PostOptimization {
-
- /** @return a set of methods that need post processing. */
- ProgramMethodSet methodsToRevisit();
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index abf7239..32df085 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.optimize;
import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
+import static com.android.tools.r8.utils.MapUtils.ignoreKey;
import static com.google.common.base.Predicates.not;
import com.android.tools.r8.androidapi.AvailableApiExceptions;
@@ -47,6 +48,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Throw;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.LensCodeRewriter;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.PostMethodProcessor;
@@ -78,10 +80,12 @@
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
public class Inliner {
protected final AppView<AppInfoWithLiveness> appView;
+ private final IRConverter converter;
private final Set<DexMethod> extraNeverInlineMethods;
private final LensCodeRewriter lensCodeRewriter;
final MainDexInfo mainDexInfo;
@@ -96,13 +100,18 @@
private final Map<DexEncodedMethod, ProgramMethod> doubleInlineeCandidates =
new IdentityHashMap<>();
+ private final Map<DexProgramClass, ProgramMethodSet> singleCallerInlinedMethods =
+ new ConcurrentHashMap<>();
+
private final AvailableApiExceptions availableApiExceptions;
public Inliner(
AppView<AppInfoWithLiveness> appView,
+ IRConverter converter,
LensCodeRewriter lensCodeRewriter) {
Kotlin.Intrinsics intrinsics = appView.dexItemFactory().kotlin.intrinsics;
this.appView = appView;
+ this.converter = converter;
this.extraNeverInlineMethods =
appView.options().kotlinOptimizationOptions().disableKotlinSpecificOptimizations
? ImmutableSet.of()
@@ -1130,7 +1139,15 @@
appView, code, inlinee.code, blockIterator, blocksToRemove, downcastClass);
if (inlinee.reason == Reason.SINGLE_CALLER) {
+ assert converter.isInWave();
feedback.markInlinedIntoSingleCallSite(singleTargetMethod);
+ if (singleCallerInlinedMethods.isEmpty()) {
+ converter.addWaveDoneAction(this::onWaveDone);
+ }
+ singleCallerInlinedMethods
+ .computeIfAbsent(
+ singleTarget.getHolder(), ignoreKey(ProgramMethodSet::createConcurrent))
+ .add(singleTarget);
}
classInitializationAnalysis.notifyCodeHasChanged();
@@ -1304,10 +1321,37 @@
singleInlineCallers.remove(method.getReference(), appView.graphLens());
}
- public static boolean verifyNoMethodsInlinedDueToSingleCallSite(AppView<?> appView) {
- for (DexProgramClass clazz : appView.appInfo().classes()) {
+ private void onWaveDone() {
+ singleCallerInlinedMethods.forEach(
+ (clazz, singleCallerInlinedMethodsForClass) -> {
+ // Convert and remove virtual single caller inlined methods to abstract or throw null.
+ singleCallerInlinedMethodsForClass.removeIf(
+ singleCallerInlinedMethod -> {
+ if (singleCallerInlinedMethod.getDefinition().belongsToVirtualPool() || true) {
+ singleCallerInlinedMethod.convertToAbstractOrThrowNullMethod(appView);
+ return true;
+ }
+ return false;
+ });
+
+ // Remove direct single caller inlined methods from the application.
+ if (!singleCallerInlinedMethodsForClass.isEmpty()) {
+ clazz
+ .getMethodCollection()
+ .removeMethods(
+ singleCallerInlinedMethodsForClass.toDefinitionSet(
+ SetUtils::newIdentityHashSet));
+ singleCallerInlinedMethodsForClass.forEach(converter::pruneMethod);
+ }
+ });
+ singleCallerInlinedMethods.clear();
+ }
+
+ public static boolean verifyAllSingleCallerMethodsHaveBeenPruned(AppView<?> appView) {
+ for (DexProgramClass clazz : appView.appInfo().classesWithDeterministicOrder()) {
for (DexEncodedMethod method : clazz.methods()) {
- assert !method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite();
+ assert !method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite() || !method.hasCode()
+ : "Method was single caller inlined: " + method.toSourceString();
}
}
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 26430a4..854a4e0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -638,9 +638,21 @@
postMethodProcessorBuilder
.getMethodsToReprocessBuilder()
.rewrittenWithLens(appView)
- .merge(dependencies)
- .merge(methodsDependingOnLibraryModelisation)
- .removeAll(treeFixerResult.getPrunedItems().getRemovedMethods());
+ .removeAll(treeFixerResult.getPrunedItems().getRemovedMethods())
+ .merge(
+ dependencies
+ .rewrittenWithLens(appView)
+ .removeAll(treeFixerResult.getPrunedItems().getRemovedMethods())
+ .removeIf(
+ appView,
+ method -> method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite()))
+ .merge(
+ methodsDependingOnLibraryModelisation
+ .rewrittenWithLens(appView)
+ .removeAll(treeFixerResult.getPrunedItems().getRemovedMethods())
+ .removeIf(
+ appView,
+ method -> method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite()));
methodsDependingOnLibraryModelisation.clear();
updateOptimizationInfos(executorService, feedback, treeFixerResult);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineCollection.java
index 16e4dab..78dc248 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineCollection.java
@@ -97,12 +97,15 @@
DexProgramClass.asProgramClassOrNull(
appView.definitionFor(rewrittenReference.getHolderType()));
ProgramMethod method = rewrittenReference.lookupOnProgramClass(holder);
- if (method != null) {
- for (Outline outline : outlinesForMethod) {
- methodsPerOutline.computeIfAbsent(outline, ignoreKey(ArrayList::new)).add(method);
- }
- } else {
+ if (method == null) {
assert false;
+ return;
+ }
+ if (method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite()) {
+ return;
+ }
+ for (Outline outline : outlinesForMethod) {
+ methodsPerOutline.computeIfAbsent(outline, ignoreKey(ArrayList::new)).add(method);
}
});
return methodsPerOutline;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 2fbaa44..c73132f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -234,7 +234,13 @@
LongLivedProgramMethodSetBuilder<?> referencedFromBuilder =
classStaticizer.referencedFrom.remove(info);
assert referencedFromBuilder != null;
- referencedFrom = referencedFromBuilder.build(appView);
+ referencedFrom =
+ referencedFromBuilder
+ .rewrittenWithLens(appView)
+ .removeIf(
+ appView,
+ method -> method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite())
+ .build(appView);
materializedReferencedFromCollections.put(info, referencedFrom);
} else {
referencedFrom = ProgramMethodSet.empty();
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index 080e691..922e198 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -213,4 +213,20 @@
reprocessingCriteriaCollection = null;
timing.end();
}
+
+ /**
+ * Called by {@link IRConverter} at the end of a wave if a method is pruned by an optimization.
+ *
+ * <p>We only prune (1) direct single caller methods and (2) isX()/asX() virtual method overrides.
+ * For (2), we always transfer the argument information for the isX()/asX() method to its parent
+ * method using {@link #transferArgumentInformation(ProgramMethod, ProgramMethod)}, which unsets
+ * the argument information for the override.
+ *
+ * <p>Therefore, we assert that we only find a method state for direct methods.
+ */
+ public void pruneMethod(ProgramMethod method) {
+ assert codeScanner != null;
+ MethodState methodState = codeScanner.getMethodStates().removeOrElse(method, null);
+ assert methodState == null || method.getDefinition().belongsToDirectPool();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
index c01508c..efa1985 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
@@ -81,7 +81,7 @@
CallSiteOptimizationInfo callSiteOptimizationInfo =
method.getDefinition().getCallSiteOptimizationInfo();
if (callSiteOptimizationInfo.isConcreteCallSiteOptimizationInfo()
- && !appView.appInfo().isNeverReprocessMethod(method.getReference())) {
+ && !appView.appInfo().isNeverReprocessMethod(method)) {
methodsToReprocessBuilder.add(method, currentGraphLens);
appView.testing().callSiteOptimizationInfoInspector.accept(method);
}
@@ -107,11 +107,14 @@
method -> {
if (graphLens.internalGetNextMethodSignature(method.getReference())
!= method.getReference()) {
- methodsToReprocessInClass.add(method);
+ if (!method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite()) {
+ methodsToReprocessInClass.add(method);
+ }
} else {
AffectedMethodUseRegistry registry =
new AffectedMethodUseRegistry(appView, method, graphLens);
if (method.registerCodeReferencesWithResult(registry)) {
+ assert !method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite();
methodsToReprocessInClass.add(method);
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 91289b7..45630fa 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -657,8 +657,9 @@
return keepUnusedArguments.contains(method);
}
- public boolean isNeverReprocessMethod(DexMethod method) {
- return neverReprocess.contains(method);
+ public boolean isNeverReprocessMethod(ProgramMethod method) {
+ return neverReprocess.contains(method.getReference())
+ || method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite();
}
public Set<DexMethod> getReprocessMethods() {
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 43d2d16..f837095 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -17,13 +17,13 @@
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.NestMemberClassAttribute;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MutableMethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback.OptimizationInfoFixer;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.logging.Log;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.IterableUtils;
@@ -283,11 +283,13 @@
return -1;
}
- private DexEncodedMethod[] reachableMethods(Iterable<DexEncodedMethod> methods, DexClass clazz) {
+ private DexEncodedMethod[] reachableMethods(
+ Iterable<DexEncodedMethod> methods, DexProgramClass clazz) {
return reachableMethods(IterableUtils.ensureUnmodifiableList(methods), clazz);
}
- private DexEncodedMethod[] reachableMethods(List<DexEncodedMethod> methods, DexClass clazz) {
+ private DexEncodedMethod[] reachableMethods(
+ List<DexEncodedMethod> methods, DexProgramClass clazz) {
AppInfoWithLiveness appInfo = appView.appInfo();
InternalOptions options = appView.options();
int firstUnreachable =
@@ -320,27 +322,11 @@
if (Log.ENABLED) {
Log.debug(getClass(), "Making method %s abstract.", method.getReference());
}
- // Final classes cannot be abstract, so we have to keep the method in that case.
- // Also some other kinds of methods cannot be abstract, so keep them around.
- boolean allowAbstract =
- (options.canUseAbstractMethodOnNonAbstractClass() || clazz.isAbstract())
- && !method.isFinal()
- && !method.accessFlags.isNative()
- && !method.accessFlags.isStrict()
- && !method.isSynchronized()
- && !method.accessFlags.isPrivate()
- && !method.isStatic()
- && !appInfo.isFailedResolutionTarget(method.getReference());
// Private methods and static methods can only be targeted yet non-live as the result of
// an invalid invoke. They will not actually be called at runtime but we have to keep them
// as non-abstract (see above) to produce the same failure mode.
- if (!allowAbstract) {
- // If the method was not marked as live and we cannot make it abstract, set the api level
- // to be min or unknown.
- method.setApiLevelForCode(AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView));
- }
- reachableMethods.add(
- allowAbstract ? method.toAbstractMethod() : method.toEmptyThrowingMethod(options));
+ new ProgramMethod(clazz, method).convertToAbstractOrThrowNullMethod(appView);
+ reachableMethods.add(method);
} else {
if (Log.ENABLED) {
Log.debug(getClass(), "Removing method %s.", method.getReference());
diff --git a/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
index 5fe5cf1..00749bb 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
@@ -7,11 +7,13 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
-import com.google.common.collect.Sets;
+import com.android.tools.r8.utils.SetUtils;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -78,6 +80,10 @@
return remove(method.getReference());
}
+ public boolean removeIf(Predicate<? super T> predicate) {
+ return backing.values().removeIf(predicate);
+ }
+
public int size() {
return backing.size();
}
@@ -88,7 +94,11 @@
public Set<DexEncodedMethod> toDefinitionSet() {
assert backing instanceof IdentityHashMap;
- Set<DexEncodedMethod> definitions = Sets.newIdentityHashSet();
+ return toDefinitionSet(SetUtils::newIdentityHashSet);
+ }
+
+ public Set<DexEncodedMethod> toDefinitionSet(IntFunction<Set<DexEncodedMethod>> factory) {
+ Set<DexEncodedMethod> definitions = factory.apply(size());
forEach(method -> definitions.add(method.getDefinition()));
return definitions;
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
index 911290b..ce4399b 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
@@ -68,7 +68,7 @@
public void addAll(Iterable<ProgramMethod> methodsToAdd, GraphLens currentGraphLens) {
assert verifyIsRewrittenWithLens(currentGraphLens);
- methodsToAdd.forEach(method -> methods.add(method.getReference()));
+ methodsToAdd.forEach(method -> add(method, currentGraphLens));
}
public void clear() {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java
index 0b58101..3882a7b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/LibraryOverrideInliningTest.java
@@ -6,16 +6,14 @@
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.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -24,17 +22,14 @@
@RunWith(Parameterized.class)
public class LibraryOverrideInliningTest extends TestBase {
- private final boolean disableInliningOfLibraryMethodOverrides;
private final TestParameters parameters;
- @Parameters(name = "{1}, disableInliningOfLibraryMethodOverrides: {0}")
- public static List<Object[]> data() {
- return buildParameters(BooleanUtils.values(), getTestParameters().withAllRuntimes().build());
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
}
- public LibraryOverrideInliningTest(
- boolean disableInliningOfLibraryMethodOverrides, TestParameters parameters) {
- this.disableInliningOfLibraryMethodOverrides = disableInliningOfLibraryMethodOverrides;
+ public LibraryOverrideInliningTest(TestParameters parameters) {
this.parameters = parameters;
}
@@ -43,12 +38,8 @@
testForR8(parameters.getBackend())
.addInnerClasses(LibraryOverrideInliningTest.class)
.addKeepMainRule(TestClass.class)
- .addOptionsModification(
- options ->
- options.disableInliningOfLibraryMethodOverrides =
- disableInliningOfLibraryMethodOverrides)
.enableNeverClassInliningAnnotations()
- .setMinApi(parameters.getRuntime())
+ .setMinApi(parameters.getApiLevel())
.compile()
.inspect(
inspector -> {
@@ -64,12 +55,7 @@
MethodSubject mainMethodSubject = testClassSubject.mainMethod();
assertThat(mainMethodSubject, isPresent());
-
- if (disableInliningOfLibraryMethodOverrides) {
- assertThat(mainMethodSubject, invokesMethod(toStringMethodSubject));
- } else {
- assertThat(mainMethodSubject, not(invokesMethod(toStringMethodSubject)));
- }
+ assertThat(mainMethodSubject, invokesMethod(toStringMethodSubject));
})
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutputLines("Hello world!");
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index 5bae6d3..105d097 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -6,8 +6,10 @@
import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72;
import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_5_0;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static com.android.tools.r8.utils.codeinspector.Matchers.onlyIf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -120,7 +122,7 @@
assertThat(
inspector.clazz(
"class_inliner_lambda_j_style.MainKt$$ExternalSyntheticLambda2"),
- isPresent());
+ isAbsent());
} else {
assertThat(
inspector.clazz("class_inliner_lambda_j_style.MainKt$testStateless$1"),
@@ -164,7 +166,7 @@
!hasKotlinCGeneratedLambdaClasses
? "class_inliner_lambda_j_style.MainKt$$ExternalSyntheticLambda2"
: "class_inliner_lambda_j_style.MainKt$testStateful$1"),
- isPresent());
+ onlyIf(hasKotlinCGeneratedLambdaClasses, 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 0f534e0..282d8d7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
@@ -10,7 +10,6 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinTargetVersion;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestParameters;
@@ -91,6 +90,11 @@
runTest(PROPERTIES_PACKAGE_NAME, mainClass, R8TestBuilder::noClassStaticizing)
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getOuterClassName());
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, testedClass.getOuterClassName());
String propertyName = "primitiveProp";
@@ -124,6 +128,11 @@
runTest(PROPERTIES_PACKAGE_NAME, mainClass, R8TestBuilder::noClassStaticizing)
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getOuterClassName());
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, testedClass.getOuterClassName());
String propertyName = "privateProp";
@@ -159,6 +168,11 @@
runTest(PROPERTIES_PACKAGE_NAME, mainClass, R8TestBuilder::noClassStaticizing)
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getOuterClassName());
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, testedClass.getOuterClassName());
String propertyName = "internalProp";
@@ -193,6 +207,11 @@
runTest(PROPERTIES_PACKAGE_NAME, mainClass, R8TestBuilder::noClassStaticizing)
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getOuterClassName());
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, testedClass.getOuterClassName());
String propertyName = "publicProp";
@@ -227,6 +246,11 @@
runTest(PROPERTIES_PACKAGE_NAME, mainClass, R8TestBuilder::noClassStaticizing)
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getOuterClassName());
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, testedClass.getOuterClassName());
String propertyName = "privateLateInitProp";
@@ -260,6 +284,11 @@
runTest(PROPERTIES_PACKAGE_NAME, mainClass)
.inspect(
inspector -> {
+ if (true) {
+ checkClassIsRemoved(inspector, testedClass.getOuterClassName());
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, testedClass.getOuterClassName());
String propertyName = "internalLateInitProp";
@@ -293,6 +322,11 @@
runTest(PROPERTIES_PACKAGE_NAME, mainClass)
.inspect(
inspector -> {
+ if (true) {
+ checkClassIsRemoved(inspector, testedClass.getOuterClassName());
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, testedClass.getOuterClassName());
String propertyName = "publicLateInitProp";
@@ -375,9 +409,7 @@
runTest("accessors", mainClass)
.inspect(
inspector -> {
- if (allowAccessModification
- && (testParameters.isCfRuntime()
- || !kotlinParameters.is(KOTLINC_1_5_0, KotlinTargetVersion.JAVA_8))) {
+ if (allowAccessModification) {
checkClassIsRemoved(inspector, testedClass.getClassName());
return;
}
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 c605951..5a60483 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
@@ -87,7 +87,7 @@
.addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL)
.addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC);
- private Consumer<InternalOptions> disableAggressiveClassOptimizations =
+ private final Consumer<InternalOptions> disableAggressiveClassOptimizations =
o -> {
o.enableClassInlining = false;
o.enableVerticalClassMerging = false;
@@ -116,13 +116,9 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
- inspector -> {
- checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName());
- });
+ inspector -> checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName()));
}
@Test
@@ -132,21 +128,20 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName());
+ return;
+ }
+
ClassSubject classSubject =
checkClassIsKept(inspector, 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());
- }
+ assertTrue(fieldSubject.getField().isPrivate());
// Private property has no getter or setter.
checkMethodIsAbsent(
@@ -163,11 +158,14 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName());
+ return;
+ }
+
ClassSubject classSubject =
checkClassIsKept(inspector, MUTABLE_PROPERTY_CLASS.getClassName());
String propertyName = "protectedProp";
@@ -176,13 +174,8 @@
// 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);
- }
+ assertTrue(fieldSubject.getField().isPrivate());
+ checkMethodIsKept(classSubject, getter);
});
}
@@ -193,11 +186,14 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName());
+ return;
+ }
+
ClassSubject classSubject =
checkClassIsKept(inspector, MUTABLE_PROPERTY_CLASS.getClassName());
String propertyName = "internalProp";
@@ -206,13 +202,8 @@
// 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);
- }
+ assertTrue(fieldSubject.getField().isPrivate());
+ checkMethodIsKept(classSubject, getter);
});
}
@@ -223,11 +214,14 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName());
+ return;
+ }
+
ClassSubject classSubject =
checkClassIsKept(inspector, MUTABLE_PROPERTY_CLASS.getClassName());
String propertyName = "publicProp";
@@ -236,13 +230,8 @@
// 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);
- }
+ assertTrue(fieldSubject.getField().isPrivate());
+ checkMethodIsKept(classSubject, getter);
});
}
@@ -256,6 +245,11 @@
testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, MUTABLE_PROPERTY_CLASS.getClassName());
+ return;
+ }
+
ClassSubject classSubject =
checkClassIsKept(inspector, MUTABLE_PROPERTY_CLASS.getClassName());
String propertyName = "primitiveProp";
@@ -263,15 +257,9 @@
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);
- checkMethodIsRemoved(classSubject, setter);
- }
+ assertTrue(fieldSubject.getField().isPrivate());
+ checkMethodIsKept(classSubject, getter);
+ checkMethodIsRemoved(classSubject, setter);
});
}
@@ -284,9 +272,7 @@
mainClass,
testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
- inspector -> {
- checkClassIsRemoved(inspector, LATE_INIT_PROPERTY_CLASS.getClassName());
- });
+ inspector -> checkClassIsRemoved(inspector, LATE_INIT_PROPERTY_CLASS.getClassName()));
}
@Test
@@ -296,19 +282,20 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, LATE_INIT_PROPERTY_CLASS.getClassName());
+ return;
+ }
+
ClassSubject classSubject =
checkClassIsKept(inspector, 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());
- }
+ assertTrue(fieldSubject.getField().isPrivate());
// Private late init property have no getter or setter.
checkMethodIsAbsent(
@@ -325,24 +312,9 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
- inspector -> {
- ClassSubject classSubject =
- checkClassIsKept(inspector, 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));
- });
+ inspector -> checkClassIsRemoved(inspector, LATE_INIT_PROPERTY_CLASS.getClassName()));
}
@Test
@@ -352,22 +324,9 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
- inspector -> {
- ClassSubject classSubject =
- checkClassIsKept(inspector, 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));
- });
+ inspector -> checkClassIsRemoved(inspector, LATE_INIT_PROPERTY_CLASS.getClassName()));
}
@Test
@@ -377,22 +336,9 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
- inspector -> {
- ClassSubject classSubject =
- checkClassIsKept(inspector, 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));
- });
+ inspector -> checkClassIsRemoved(inspector, LATE_INIT_PROPERTY_CLASS.getClassName()));
}
@Test
@@ -404,9 +350,8 @@
mainClass,
testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
- inspector -> {
- checkClassIsRemoved(inspector, USER_DEFINED_PROPERTY_CLASS.getClassName());
- });
+ inspector ->
+ checkClassIsRemoved(inspector, USER_DEFINED_PROPERTY_CLASS.getClassName()));
}
@Test
@@ -419,6 +364,11 @@
testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, USER_DEFINED_PROPERTY_CLASS.getClassName());
+ return;
+ }
+
ClassSubject classSubject =
checkClassIsKept(inspector, USER_DEFINED_PROPERTY_CLASS.getClassName());
String propertyName = "durationInSeconds";
@@ -430,13 +380,8 @@
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);
- }
+ assertTrue(fieldSubject.getField().isPrivate());
+ checkMethodIsKept(classSubject, getter);
});
}
@@ -447,22 +392,22 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName());
+
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, "properties.CompanionProperties");
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, "properties.CompanionProperties");
- checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName());
String propertyName = "primitiveProp";
FieldSubject fieldSubject = checkFieldIsKept(outerClass, "int", propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- }
+ assertTrue(fieldSubject.getField().isStatic());
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -473,34 +418,29 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName());
+
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, "properties.CompanionProperties");
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, "properties.CompanionProperties");
- checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName());
String propertyName = "privateProp";
FieldSubject fieldSubject =
checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
-
- MemberNaming.MethodSignature getter =
- COMPANION_PROPERTY_CLASS.getGetterForProperty(propertyName);
- MemberNaming.MethodSignature setter =
- COMPANION_PROPERTY_CLASS.getSetterForProperty(propertyName);
+ assertTrue(fieldSubject.getField().isStatic());
// Because the getter/setter are private, they can only be called from another method
// in the class. If this is an instance method, they will be called on 'this' which is
// known to be non-null, thus the getter/setter can be inlined if their code is small
// enough. Because the backing field is private, they will call into an accessor
- // (static) method. If access relaxation is enabled, this accessor can be removed.
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- }
+ // (static) method.
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -511,23 +451,22 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, "properties.CompanionProperties");
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, "properties.CompanionProperties");
checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName());
String propertyName = "internalProp";
FieldSubject fieldSubject =
checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- }
+ assertTrue(fieldSubject.getField().isStatic());
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -538,23 +477,23 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName());
+
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, "properties.CompanionProperties");
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, "properties.CompanionProperties");
- checkClassIsRemoved(inspector, COMPANION_PROPERTY_CLASS.getClassName());
String propertyName = "publicProp";
FieldSubject fieldSubject =
checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- }
+ assertTrue(fieldSubject.getField().isStatic());
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -566,29 +505,29 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getOuterClassName());
+ return;
+ }
+
ClassSubject outerClass =
checkClassIsKept(inspector, testedClass.getOuterClassName());
- checkClassIsRemoved(inspector, testedClass.getClassName());
String propertyName = "privateLateInitProp";
FieldSubject fieldSubject =
checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
// Because the getter/setter are private, they can only be called from another method
// in the class. If this is an instance method, they will be called on 'this' which is
// known to be non-null, thus the getter/setter can be inlined if their code is small
// enough. Because the backing field is private, they will call into an accessor
// (static) method. If access relaxation is enabled, this accessor can be removed.
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().isPublic());
- } else {
- assertTrue(fieldSubject.getField().isPrivate());
- }
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -600,19 +539,11 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
- ClassSubject outerClass =
- checkClassIsKept(inspector, testedClass.getOuterClassName());
checkClassIsRemoved(inspector, testedClass.getClassName());
- String propertyName = "internalLateInitProp";
- FieldSubject fieldSubject =
- checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
+ checkClassIsRemoved(inspector, testedClass.getOuterClassName());
});
}
@@ -624,19 +555,11 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
- ClassSubject outerClass =
- checkClassIsKept(inspector, testedClass.getOuterClassName());
checkClassIsRemoved(inspector, testedClass.getClassName());
- String propertyName = "publicLateInitProp";
- FieldSubject fieldSubject =
- checkFieldIsKept(outerClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
+ checkClassIsRemoved(inspector, testedClass.getClassName());
});
}
@@ -651,30 +574,21 @@
testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+ return;
+ }
+
ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName());
String propertyName = "primitiveProp";
FieldSubject fieldSubject = checkFieldIsKept(objectClass, "int", propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
-
- 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);
- checkMethodIsRemoved(objectClass, setter);
- }
-
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- }
+ checkMethodIsKept(objectClass, getter);
+ checkMethodIsRemoved(objectClass, setter);
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -686,16 +600,19 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+ return;
+ }
+
ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName());
String propertyName = "privateProp";
FieldSubject fieldSubject =
checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
@@ -704,11 +621,7 @@
checkMethodIsAbsent(objectClass, getter);
checkMethodIsAbsent(objectClass, setter);
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- }
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -723,31 +636,24 @@
testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+ return;
+ }
+
ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName());
String propertyName = "internalProp";
FieldSubject fieldSubject =
checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
- 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);
- checkMethodIsRemoved(objectClass, setter);
- }
+ checkMethodIsKept(objectClass, getter);
+ checkMethodIsRemoved(objectClass, setter);
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- }
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -762,31 +668,24 @@
testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+ return;
+ }
+
ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName());
String propertyName = "publicProp";
FieldSubject fieldSubject =
checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
- 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);
- checkMethodIsRemoved(objectClass, setter);
- }
+ checkMethodIsKept(objectClass, getter);
+ checkMethodIsRemoved(objectClass, setter);
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- }
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -798,16 +697,19 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+ return;
+ }
+
ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName());
String propertyName = "privateLateInitProp";
FieldSubject fieldSubject =
checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
@@ -816,11 +718,7 @@
checkMethodIsAbsent(objectClass, getter);
checkMethodIsAbsent(objectClass, setter);
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- }
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -832,24 +730,8 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
- .inspect(
- inspector -> {
- ClassSubject objectClass = checkClassIsKept(inspector, 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);
-
- checkMethodIsRemoved(objectClass, getter);
- checkMethodIsRemoved(objectClass, setter);
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- });
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
+ .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName()));
}
@Test
@@ -860,24 +742,8 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
- .inspect(
- inspector -> {
- ClassSubject objectClass = checkClassIsKept(inspector, 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);
-
- checkMethodIsRemoved(objectClass, getter);
- checkMethodIsRemoved(objectClass, setter);
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- });
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
+ .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName()));
}
@Test
@@ -891,23 +757,22 @@
testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+ return;
+ }
+
ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName());
String propertyName = "primitiveProp";
FieldSubject fieldSubject = checkFieldIsKept(objectClass, "int", propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsRemoved(objectClass, getter);
- checkMethodIsRemoved(objectClass, setter);
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsKept(objectClass, getter);
- checkMethodIsRemoved(objectClass, setter);
- }
+ assertTrue(fieldSubject.getField().isPrivate());
+ checkMethodIsKept(objectClass, getter);
+ checkMethodIsRemoved(objectClass, setter);
});
}
@@ -919,16 +784,19 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+ return;
+ }
+
ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName());
String propertyName = "privateProp";
FieldSubject fieldSubject =
checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
@@ -936,11 +804,7 @@
// 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());
- }
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -952,16 +816,19 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+ return;
+ }
+
ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName());
String propertyName = "internalProp";
FieldSubject fieldSubject =
checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
// We expect getter to be inlined when access (of the backing field) is relaxed to
// public.
@@ -969,13 +836,8 @@
// Note: the setter is considered as a regular method (because of KotlinC adding extra
// null checks), thus we cannot say if the setter would be inlined or not by R8.
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsRemoved(objectClass, getter);
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsKept(objectClass, getter);
- }
+ assertTrue(fieldSubject.getField().isPrivate());
+ checkMethodIsKept(objectClass, getter);
});
}
@@ -987,29 +849,27 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+ return;
+ }
+
ClassSubject objectClass = checkClassIsKept(inspector, testedClass.getClassName());
String propertyName = "publicProp";
FieldSubject fieldSubject =
checkFieldIsKept(objectClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
// 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.
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
- if (allowAccessModification) {
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- checkMethodIsRemoved(objectClass, getter);
- } else {
- assertTrue(fieldSubject.getField().accessFlags.isPrivate());
- checkMethodIsKept(objectClass, getter);
- }
+ assertTrue(fieldSubject.getField().isPrivate());
+ checkMethodIsKept(objectClass, getter);
});
}
@@ -1021,16 +881,19 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
.inspect(
inspector -> {
+ if (allowAccessModification) {
+ checkClassIsRemoved(inspector, testedClass.getClassName());
+ return;
+ }
+
ClassSubject fileClass = checkClassIsKept(inspector, testedClass.getClassName());
String propertyName = "privateLateInitProp";
FieldSubject fieldSubject =
checkFieldIsKept(fileClass, JAVA_LANG_STRING, propertyName);
- assertTrue(fieldSubject.getField().accessFlags.isStatic());
+ assertTrue(fieldSubject.getField().isStatic());
MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
@@ -1038,11 +901,7 @@
// 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());
- }
+ assertTrue(fieldSubject.getField().isPrivate());
});
}
@@ -1054,26 +913,8 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
- .inspect(
- inspector -> {
- ClassSubject objectClass = checkClassIsKept(inspector, 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);
-
- // 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);
- });
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
+ .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName()));
}
@Test
@@ -1084,24 +925,8 @@
runTest(
PACKAGE_NAME,
mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(disableAggressiveClassOptimizations))
- .inspect(
- inspector -> {
- ClassSubject objectClass = checkClassIsKept(inspector, 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);
-
- checkMethodIsRemoved(objectClass, getter);
- checkMethodIsRemoved(objectClass, setter);
- assertTrue(fieldSubject.getField().accessFlags.isPublic());
- });
+ testBuilder -> testBuilder.addOptionsModification(disableAggressiveClassOptimizations))
+ .inspect(inspector -> checkClassIsRemoved(inspector, testedClass.getClassName()));
}
}
diff --git a/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java b/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
index 1652222..1d25958 100644
--- a/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
@@ -9,7 +9,6 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
@@ -70,9 +69,6 @@
ClassSubject enumClass = inspector.clazz(ENUM_CLASS_NAME);
assertThat(enumClass, isPresent());
assertEquals(minify, enumClass.isRenamed());
- // TODO(b/179994975): Kotlin enum changed in 1.5.
- assertThat(
- enumClass.clinit(),
- kotlinc.is(KotlinCompilerVersion.KOTLINC_1_5_0) ? isPresent() : isAbsent());
+ assertThat(enumClass.clinit(), isAbsent());
}
}