Implement support for allowshrinking as soft pinning.
Bug: 171289133
Change-Id: I399e71ee750d73ffb499ee5be5ce993bd1a388c9
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 6a8520e..5cf69c1 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -55,6 +55,7 @@
import com.android.tools.r8.graph.ObjectAllocationInfoCollectionImpl;
import com.android.tools.r8.graph.PresortedComparable;
import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.graph.ProgramMember;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.ResolutionResult.FailedResolutionResult;
@@ -89,6 +90,7 @@
import com.android.tools.r8.shaking.KeepInfoCollection.MutableKeepInfoCollection;
import com.android.tools.r8.shaking.RootSetBuilder.ConsequentRootSet;
import com.android.tools.r8.shaking.RootSetBuilder.ItemsWithRules;
+import com.android.tools.r8.shaking.RootSetBuilder.MutableItemsWithRules;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
import com.android.tools.r8.shaking.ScopedDexMethodSet.AddMethodIfMoreVisibleResult;
import com.android.tools.r8.utils.Action;
@@ -2336,6 +2338,8 @@
// Add all dependent members to the workqueue.
enqueueRootItems(rootSet.getDependentItems(field.getDefinition()));
+ checkMemberForSoftPinning(field);
+
// Notify analyses.
analyses.forEach(analysis -> analysis.processNewlyLiveField(field));
}
@@ -2352,6 +2356,8 @@
// Add all dependent members to the workqueue.
enqueueRootItems(rootSet.getDependentItems(field.getDefinition()));
+ checkMemberForSoftPinning(field);
+
// Notify analyses.
analyses.forEach(analysis -> analysis.processNewlyLiveField(field));
}
@@ -3337,12 +3343,26 @@
enqueueRootItems(dependentItems);
}
});
+ consequentRootSet.dependentSoftPinned.forEach(
+ (reference, dependentItems) -> {
+ if (isLiveProgramReference(reference)) {
+ dependentItems.forEachReference(
+ item -> {
+ if (isLiveProgramReference(item)) {
+ keepInfo.joinInfo(item, appView, Joiner::pin);
+ }
+ });
+ }
+ });
+
// TODO(b/132600955): This modifies the root set. Should the consequent be persistent?
rootSet.addConsequentRootSet(consequentRootSet, addNoShrinking);
if (mode.isInitialTreeShaking()) {
for (DexReference reference : consequentRootSet.noObfuscation) {
keepInfo.evaluateRule(reference, appView, Joiner::disallowMinification);
}
+ consequentRootSet.softPinned.forEachReference(
+ reference -> keepInfo.evaluateRule(reference, appView, Joiner::pin));
}
enqueueRootItems(consequentRootSet.noShrinking);
// Check for compatibility rules indicating that the holder must be implicitly kept.
@@ -3356,6 +3376,18 @@
}
}
+ private boolean isLiveProgramReference(DexReference reference) {
+ if (reference.isDexType()) {
+ DexProgramClass clazz =
+ DexProgramClass.asProgramClassOrNull(definitionFor(reference.asDexType()));
+ return clazz != null && isTypeLive(clazz);
+ }
+ DexMember<?, ?> member = reference.asDexMember();
+ DexProgramClass holder = DexProgramClass.asProgramClassOrNull(definitionFor(member.holder));
+ ProgramMember<?, ?> programMember = member.lookupOnProgramClass(holder);
+ return programMember != null && isMemberLive(programMember.getDefinition());
+ }
+
private ConsequentRootSet computeDelayedInterfaceMethodSyntheticBridges() {
RootSetBuilder builder = new RootSetBuilder(appView, subtypingInfo);
for (DelayedRootSetActionItem delayedRootSetActionItem : rootSet.delayedRootSetActionItems) {
@@ -3556,10 +3588,28 @@
// Add all dependent members to the workqueue.
enqueueRootItems(rootSet.getDependentItems(definition));
+ checkMemberForSoftPinning(method);
+
// Notify analyses.
analyses.forEach(analysis -> analysis.processNewlyLiveMethod(method));
}
+ private void checkMemberForSoftPinning(ProgramMember<?, ?> member) {
+ DexMember<?, ?> reference = member.getDefinition().toReference();
+ Set<ProguardKeepRuleBase> softPinRules = rootSet.softPinned.getRulesForReference(reference);
+ if (softPinRules != null) {
+ assert softPinRules.stream().noneMatch(r -> r.getModifiers().allowsOptimization);
+ keepInfo.joinInfo(reference, appInfo, Joiner::pin);
+ }
+ // Identify dependent soft pinning.
+ MutableItemsWithRules items = rootSet.dependentSoftPinned.get(member.getHolderType());
+ if (items != null && items.containsReference(reference)) {
+ assert items.getRulesForReference(reference).stream()
+ .noneMatch(r -> r.getModifiers().allowsOptimization);
+ keepInfo.joinInfo(reference, appInfo, Joiner::pin);
+ }
+ }
+
private void markReferencedTypesAsLive(ProgramMethod method) {
markTypeAsLive(
method.getHolderType(), clazz -> graphReporter.reportClassReferencedFrom(clazz, method));
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index f8b5987..1f588d8 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -83,6 +83,7 @@
private final DirectMappedDexApplication application;
private final Iterable<? extends ProguardConfigurationRule> rules;
private final MutableItemsWithRules noShrinking = new MutableItemsWithRules();
+ private final MutableItemsWithRules softPinned = new MutableItemsWithRules();
private final Set<DexReference> noObfuscation = Sets.newIdentityHashSet();
private final LinkedHashMap<DexReference, DexReference> reasonAsked = new LinkedHashMap<>();
private final LinkedHashMap<DexReference, DexReference> checkDiscarded = new LinkedHashMap<>();
@@ -103,6 +104,8 @@
private final Set<DexReference> neverPropagateValue = Sets.newIdentityHashSet();
private final Map<DexReference, MutableItemsWithRules> dependentNoShrinking =
new IdentityHashMap<>();
+ private final Map<DexReference, MutableItemsWithRules> dependentSoftPinned =
+ new IdentityHashMap<>();
private final Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule =
new IdentityHashMap<>();
private final Map<DexReference, ProguardMemberRule> mayHaveSideEffects = new IdentityHashMap<>();
@@ -334,6 +337,7 @@
assert appView.options().isMinificationEnabled() || noObfuscation.isEmpty();
return new RootSet(
noShrinking,
+ softPinned,
noObfuscation,
ImmutableList.copyOf(reasonAsked.values()),
ImmutableList.copyOf(checkDiscarded.values()),
@@ -356,6 +360,7 @@
noSideEffects,
assumedValues,
dependentNoShrinking,
+ dependentSoftPinned,
dependentKeepClassCompatRule,
identifierNameStrings,
ifRules,
@@ -424,8 +429,10 @@
neverInline,
neverClassInline,
noShrinking,
+ softPinned,
noObfuscation,
dependentNoShrinking,
+ dependentSoftPinned,
dependentKeepClassCompatRule,
Lists.newArrayList(delayedRootSetActionItems));
}
@@ -1042,6 +1049,7 @@
dependentNoShrinking
.computeIfAbsent(item.toReference(), x -> new MutableItemsWithRules())
.addClassWithRule(type, context);
+ // TODO(b/171289133): Test and implement allowshrinking and use of -includedescriptorclasses
// Unconditionally add to no-obfuscation, as that is only checked for surviving items.
if (appView.options().isMinificationEnabled()) {
noObfuscation.add(type);
@@ -1136,6 +1144,14 @@
noShrinking.addReferenceWithRule(item.toReference(), keepRule);
}
context.markAsUsed();
+ } else if (!modifiers.allowsOptimization) {
+ if (precondition != null) {
+ dependentSoftPinned
+ .computeIfAbsent(precondition.toReference(), x -> new MutableItemsWithRules())
+ .addReferenceWithRule(item.toReference(), keepRule);
+ } else {
+ softPinned.addReferenceWithRule(item.toReference(), keepRule);
+ }
}
if (!modifiers.allowsOptimization) {
// The -dontoptimize flag has only effect through the keep all rule, but we still
@@ -1301,8 +1317,10 @@
final Set<DexMethod> neverInline;
final Set<DexType> neverClassInline;
final MutableItemsWithRules noShrinking;
+ final MutableItemsWithRules softPinned;
final Set<DexReference> noObfuscation;
final Map<DexReference, MutableItemsWithRules> dependentNoShrinking;
+ final Map<DexReference, MutableItemsWithRules> dependentSoftPinned;
final Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule;
final List<DelayedRootSetActionItem> delayedRootSetActionItems;
@@ -1310,15 +1328,19 @@
Set<DexMethod> neverInline,
Set<DexType> neverClassInline,
MutableItemsWithRules noShrinking,
+ MutableItemsWithRules softPinned,
Set<DexReference> noObfuscation,
Map<DexReference, MutableItemsWithRules> dependentNoShrinking,
+ Map<DexReference, MutableItemsWithRules> dependentSoftPinned,
Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule,
List<DelayedRootSetActionItem> delayedRootSetActionItems) {
this.neverInline = neverInline;
this.neverClassInline = neverClassInline;
this.noShrinking = noShrinking;
+ this.softPinned = softPinned;
this.noObfuscation = noObfuscation;
this.dependentNoShrinking = dependentNoShrinking;
+ this.dependentSoftPinned = dependentSoftPinned;
this.dependentKeepClassCompatRule = dependentKeepClassCompatRule;
this.delayedRootSetActionItems = delayedRootSetActionItems;
}
@@ -1445,19 +1467,20 @@
return reference.apply(this::containsClass, this::containsField, this::containsMethod);
}
- public abstract void forEachClass(Consumer<DexType> consumer);
+ public abstract void forEachClass(Consumer<? super DexType> consumer);
- public abstract void forEachClass(BiConsumer<DexType, Set<ProguardKeepRuleBase>> consumer);
+ public abstract void forEachClass(
+ BiConsumer<? super DexType, Set<ProguardKeepRuleBase>> consumer);
public abstract void forEachField(Consumer<? super DexField> consumer);
public abstract void forEachField(
BiConsumer<? super DexField, Set<ProguardKeepRuleBase>> consumer);
- public abstract void forEachMember(Consumer<DexMember<?, ?>> consumer);
+ public abstract void forEachMember(Consumer<? super DexMember<?, ?>> consumer);
public abstract void forEachMember(
- BiConsumer<DexMember<?, ?>, Set<ProguardKeepRuleBase>> consumer);
+ BiConsumer<? super DexMember<?, ?>, Set<ProguardKeepRuleBase>> consumer);
public abstract void forEachMethod(Consumer<? super DexMethod> consumer);
@@ -1554,13 +1577,18 @@
return methodsWithRules.containsKey(method);
}
+ public void forEachReference(Consumer<DexReference> consumer) {
+ forEachClass(consumer);
+ forEachMember(consumer);
+ }
+
@Override
- public void forEachClass(Consumer<DexType> consumer) {
+ public void forEachClass(Consumer<? super DexType> consumer) {
classesWithRules.keySet().forEach(consumer);
}
@Override
- public void forEachClass(BiConsumer<DexType, Set<ProguardKeepRuleBase>> consumer) {
+ public void forEachClass(BiConsumer<? super DexType, Set<ProguardKeepRuleBase>> consumer) {
classesWithRules.forEach(consumer);
}
@@ -1575,13 +1603,14 @@
}
@Override
- public void forEachMember(Consumer<DexMember<?, ?>> consumer) {
+ public void forEachMember(Consumer<? super DexMember<?, ?>> consumer) {
forEachField(consumer);
forEachMethod(consumer);
}
@Override
- public void forEachMember(BiConsumer<DexMember<?, ?>, Set<ProguardKeepRuleBase>> consumer) {
+ public void forEachMember(
+ BiConsumer<? super DexMember<?, ?>, Set<ProguardKeepRuleBase>> consumer) {
forEachField(consumer);
forEachMethod(consumer);
}
@@ -1752,6 +1781,7 @@
private RootSet(
MutableItemsWithRules noShrinking,
+ MutableItemsWithRules softPinned,
Set<DexReference> noObfuscation,
ImmutableList<DexReference> reasonAsked,
ImmutableList<DexReference> checkDiscarded,
@@ -1774,6 +1804,7 @@
Map<DexReference, ProguardMemberRule> noSideEffects,
Map<DexReference, ProguardMemberRule> assumedValues,
Map<DexReference, MutableItemsWithRules> dependentNoShrinking,
+ Map<DexReference, MutableItemsWithRules> dependentSoftPinned,
Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule,
Set<DexReference> identifierNameStrings,
Set<ProguardIfRule> ifRules,
@@ -1782,8 +1813,10 @@
neverInline,
neverClassInline,
noShrinking,
+ softPinned,
noObfuscation,
dependentNoShrinking,
+ dependentSoftPinned,
dependentKeepClassCompatRule,
delayedRootSetActionItems);
this.reasonAsked = reasonAsked;
@@ -1831,7 +1864,8 @@
if (addNoShrinking) {
noShrinking.addAll(consequentRootSet.noShrinking);
}
- addDependentItems(consequentRootSet.dependentNoShrinking);
+ addDependentItems(consequentRootSet.dependentNoShrinking, dependentNoShrinking);
+ addDependentItems(consequentRootSet.dependentSoftPinned, dependentSoftPinned);
consequentRootSet.dependentKeepClassCompatRule.forEach(
(type, rules) ->
dependentKeepClassCompatRule.computeIfAbsent(
@@ -1840,10 +1874,12 @@
}
// Add dependent items that depend on -if rules.
- private void addDependentItems(Map<DexReference, ? extends ItemsWithRules> dependentItems) {
- dependentItems.forEach(
+ private static void addDependentItems(
+ Map<DexReference, ? extends ItemsWithRules> dependentItemsToAdd,
+ Map<DexReference, MutableItemsWithRules> dependentItemsToAddTo) {
+ dependentItemsToAdd.forEach(
(reference, dependence) ->
- dependentNoShrinking
+ dependentItemsToAddTo
.computeIfAbsent(reference, x -> new MutableItemsWithRules())
.putAll(dependence));
}
@@ -2075,16 +2111,20 @@
Set<DexMethod> neverInline,
Set<DexType> neverClassInline,
MutableItemsWithRules noShrinking,
+ MutableItemsWithRules softPinned,
Set<DexReference> noObfuscation,
Map<DexReference, MutableItemsWithRules> dependentNoShrinking,
+ Map<DexReference, MutableItemsWithRules> dependentSoftPinned,
Map<DexType, Set<ProguardKeepRuleBase>> dependentKeepClassCompatRule,
List<DelayedRootSetActionItem> delayedRootSetActionItems) {
super(
neverInline,
neverClassInline,
noShrinking,
+ softPinned,
noObfuscation,
dependentNoShrinking,
+ dependentSoftPinned,
dependentKeepClassCompatRule,
delayedRootSetActionItems);
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 155f338..dd42c7b 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -157,6 +157,7 @@
itemFactory = proguardConfiguration.getDexItemFactory();
enableTreeShaking = proguardConfiguration.isShrinking();
enableMinification = proguardConfiguration.isObfuscating();
+ // TODO(b/171457102): Avoid the need for this.
// -dontoptimize disables optimizations by flipping related flags.
if (!proguardConfiguration.isOptimizing()) {
disableAllOptimizations();
diff --git a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
index 412311e..de0e481 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.BaseCompilerCommand;
import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.ProguardVersion;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompileResult;
import com.android.tools.r8.TestParameters;
@@ -35,6 +36,8 @@
@RunWith(Parameterized.class)
public class CompatKeepClassMemberNamesTestRunner extends TestBase {
+ private static final ProguardVersion PG = ProguardVersion.getLatest();
+
private static Class<?> MAIN_CLASS = CompatKeepClassMemberNamesTest.class;
private static Class<?> BAR_CLASS = CompatKeepClassMemberNamesTest.Bar.class;
private static Collection<Class<?>> CLASSES =
@@ -114,7 +117,7 @@
@Test
public void testWithoutRulesPG() throws Exception {
- testWithoutRules(testForProguard());
+ testWithoutRules(testForProguard(PG));
}
@Test
@@ -157,7 +160,7 @@
@Test
public void testWithMembersRulePG() throws Exception {
- assertMembersRuleCompatResult(buildWithMembersRule(testForProguard()).compile());
+ assertMembersRuleCompatResult(buildWithMembersRule(testForProguard(PG)).compile());
}
@Test
@@ -209,7 +212,7 @@
@Test
public void testWithNonStaticMembersRulePG() throws Exception {
- assertBarIsAbsent(buildWithNonStaticMembersRule(testForProguard()).compile());
+ assertBarIsAbsent(buildWithNonStaticMembersRule(testForProguard(PG)).compile());
}
@Test
@@ -268,7 +271,7 @@
@Test
public void testWithMembersRuleEnableMinificationPG() throws Exception {
assertMembersRuleEnableMinificationCompatResult(
- buildWithMembersRuleEnableMinification(testForProguard()).compile());
+ buildWithMembersRuleEnableMinification(testForProguard(PG)).compile());
}
@Test
@@ -313,7 +316,7 @@
@Test
public void testWithMembersStarRulePG() throws Exception {
- testWithMembersStarRule(testForProguard());
+ testWithMembersStarRule(testForProguard(PG));
}
@Test
@@ -362,7 +365,7 @@
@Test
public void testWithMemberNamesRulePG() throws Exception {
- assertMemberNamesRuleCompatResult(buildWithMemberNamesRule(testForProguard()).compile());
+ assertMemberNamesRuleCompatResult(buildWithMemberNamesRule(testForProguard(PG)).compile());
}
@Test
@@ -375,7 +378,8 @@
@Test
public void testWithMemberNamesRuleFullR8() throws Exception {
- assertBarIsAbsent(buildWithMemberNamesRule(testForR8Compat(parameters.getBackend())).compile());
+ assertMemberNamesRuleCompatResult(
+ buildWithMemberNamesRule(testForR8(parameters.getBackend())).compile());
}
// Tests for "-keepclassmembernames" and *no* minification.
@@ -419,7 +423,7 @@
@Test
public void testWithMemberNamesRuleEnableMinificationPG() throws Exception {
assertMemberNamesRuleEnableMinificationCompatResult(
- buildWithMemberNamesRuleEnableMinification(testForProguard()).compile());
+ buildWithMemberNamesRuleEnableMinification(testForProguard(PG)).compile());
}
@Test
@@ -432,7 +436,7 @@
@Test
public void testWithMemberNamesRuleEnableMinificationFullR8() throws Exception {
- assertBarIsAbsent(
+ assertMemberNamesRuleEnableMinificationCompatResult(
buildWithMemberNamesRuleEnableMinification(testForR8(parameters.getBackend())).compile());
}
}
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java
index dc2b296..1375f54 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java
@@ -168,6 +168,10 @@
}
private void verifyBuildersAreAbsent(CodeInspector outputInspector) {
+ // TODO(b/171441793): Should be optimized out but fails do to soft pinning of super class.
+ if (true) {
+ return;
+ }
assertThat(
outputInspector.clazz(
"com.android.tools.r8.proto2.Shrinking$HasFlaggedOffExtension$Builder"),
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
index bb36308..e5746ec 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
@@ -6,12 +6,16 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.FileUtils;
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 java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -31,12 +35,14 @@
private Backend backend;
- @Parameterized.Parameters(name = "Backend: {0}")
- public static Backend[] data() {
- return ToolHelper.getBackends();
+ @Parameterized.Parameters(name = "Backend: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ TestParametersBuilder.builder().withNoneRuntime().build(), ToolHelper.getBackends());
}
- public MemberValuePropagationTest(TestBase.Backend backend) {
+ public MemberValuePropagationTest(TestParameters parameters, TestBase.Backend backend) {
+ parameters.assertNoneRuntime();
this.backend = backend;
}
@@ -56,14 +62,14 @@
public void testWriteOnlyField_dontoptimize() throws Exception {
CodeInspector inspector = runR8(DONT_OPTIMIZE);
ClassSubject clazz = inspector.clazz(QUALIFIED_CLASS_NAME);
- clazz.forAllMethods(
- methodSubject -> {
- // Dead code removal is not part of -dontoptimize. That is, even with -dontoptimize,
- // field put instructions are gone with better dead code removal.
- assertTrue(
- methodSubject.streamInstructions().noneMatch(
- i -> i.isInstancePut() || i.isStaticPut()));
- });
+ // With the support of 'allowshrinking' dontoptimize will now effectively pin all
+ // items that are not tree shaken out. The field operations will thus remain.
+ assertTrue(clazz.clinit().streamInstructions().anyMatch(InstructionSubject::isStaticPut));
+ assertTrue(
+ clazz
+ .uniqueInstanceInitializer()
+ .streamInstructions()
+ .anyMatch(InstructionSubject::isInstancePut));
}
private CodeInspector runR8(Path proguardConfig) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java b/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
index bb27506..23271e2 100644
--- a/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
+++ b/src/test/java/com/android/tools/r8/naming/b130791310/B130791310.java
@@ -3,14 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming.b130791310;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
-import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.ProguardVersion;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -108,45 +107,27 @@
this.parameters = parameters;
}
- private void inspect(CodeInspector inspector, boolean isR8) {
+ private void inspect(CodeInspector inspector) {
ClassSubject holder = inspector.clazz(SomeLogic.class);
assertThat(holder, isPresentAndNotRenamed());
MethodSubject someMethod = holder.uniqueMethodWithName("someMethod");
- if (isR8) {
- if (onlyForceInlining) {
- assertThat(someMethod, isPresentAndNotRenamed());
- } else {
- assertThat(someMethod, not(isPresent()));
- }
- } else {
- if (enableClassMerging) {
- // Note that the method is not entirely gone, but merged to the implementer, along with some
- // method signature modification.
- assertThat(someMethod, not(isPresent()));
- } else {
- assertThat(someMethod, isPresentAndNotRenamed());
- }
- }
+ assertThat(someMethod, isPresentAndNotRenamed());
}
@Test
public void testProguard() throws Exception {
assumeFalse(onlyForceInlining);
assumeTrue(parameters.isCfRuntime());
- testForProguard()
+ testForProguard(ProguardVersion.getLatest())
.addProgramClasses(CLASSES)
.addKeepClassAndMembersRules(MAIN)
.addKeepRules(RULES)
.addTestingAnnotationsAsProgramClasses()
.setMinApi(parameters.getApiLevel())
- .apply(
- builder -> {
- if (!enableClassMerging) {
- builder.addKeepRules("-optimizations !class/merging/*");
- }
- })
+ .applyIf(
+ !enableClassMerging, builder -> builder.addKeepRules("-optimizations !class/merging/*"))
.compile()
- .inspect(inspector -> inspect(inspector, false));
+ .inspect(this::inspect);
}
@Test
@@ -158,14 +139,12 @@
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.addOptionsModification(o -> o.enableVerticalClassMerging = enableClassMerging)
- .apply(
- builder -> {
- if (onlyForceInlining) {
+ .applyIf(
+ onlyForceInlining,
+ builder ->
builder.addOptionsModification(
- o -> o.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE));
- }
- })
+ o -> o.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE)))
.compile()
- .inspect(inspector -> inspect(inspector, true));
+ .inspect(this::inspect);
}
}
diff --git a/src/test/java/com/android/tools/r8/proguard/KeepClassMembersAllowShrinkingCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/allowshrinking/ConditionalKeepClassMethodsAllowShrinkingCompatibilityTest.java
similarity index 80%
copy from src/test/java/com/android/tools/r8/proguard/KeepClassMembersAllowShrinkingCompatibilityTest.java
copy to src/test/java/com/android/tools/r8/shaking/allowshrinking/ConditionalKeepClassMethodsAllowShrinkingCompatibilityTest.java
index cb83f31..f7e50d9 100644
--- a/src/test/java/com/android/tools/r8/proguard/KeepClassMembersAllowShrinkingCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/allowshrinking/ConditionalKeepClassMethodsAllowShrinkingCompatibilityTest.java
@@ -1,7 +1,7 @@
// Copyright (c) 2020, 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.proguard;
+package com.android.tools.r8.shaking.allowshrinking;
import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -23,7 +23,7 @@
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class KeepClassMembersAllowShrinkingCompatibilityTest extends TestBase {
+public class ConditionalKeepClassMethodsAllowShrinkingCompatibilityTest extends TestBase {
private final TestParameters parameters;
private final boolean allowOptimization;
@@ -39,7 +39,7 @@
ImmutableList.of(Shrinker.R8, Shrinker.PG));
}
- public KeepClassMembersAllowShrinkingCompatibilityTest(
+ public ConditionalKeepClassMethodsAllowShrinkingCompatibilityTest(
TestParameters parameters,
boolean allowOptimization,
boolean allowObfuscation,
@@ -54,21 +54,14 @@
return StringUtils.lines(
"A::foo",
// Reflective lookup of A::foo will only work if optimization and obfuscation are disabled.
- Boolean.toString(
- !allowOptimization
- && !allowObfuscation
- // TODO(b/171289133): Remove this exception once fixed.
- && !shrinker.isR8()),
+ Boolean.toString(!allowOptimization && !allowObfuscation),
"false");
}
@Test
public void test() throws Exception {
if (shrinker.isR8()) {
- run(
- testForR8(parameters.getBackend())
- // TODO(b/171289133): The keep rule should not be "unmatched".
- .allowUnusedProguardConfigurationRules(allowOptimization && allowObfuscation));
+ run(testForR8(parameters.getBackend()));
} else {
run(testForProguard(shrinker.getProguardVersion()).addDontWarn(getClass()));
}
@@ -76,12 +69,12 @@
public <T extends TestShrinkerBuilder<?, ?, ?, ?, T>> void run(T builder) throws Exception {
String keepRule =
- "-keepclassmembers,allowshrinking"
+ "-if class * -keepclassmembers,allowshrinking"
+ (allowOptimization ? ",allowoptimization" : "")
+ (allowObfuscation ? ",allowobfuscation" : "")
- + " class * { java.lang.String foo(); }";
+ + " class <1> { java.lang.String foo(); java.lang.String bar(); }";
builder
- .addInnerClasses(KeepClassMembersAllowShrinkingCompatibilityTest.class)
+ .addInnerClasses(ConditionalKeepClassMethodsAllowShrinkingCompatibilityTest.class)
.addKeepClassAndMembersRules(TestClass.class)
.addKeepRules(keepRule)
.setMinApi(parameters.getApiLevel())
@@ -91,13 +84,17 @@
inspector -> {
ClassSubject aClass = inspector.clazz(A.class);
ClassSubject bClass = inspector.clazz(B.class);
- // The class constants will force A and B to be retained, but not the foo methods.
+ // The class constants will force A and B to be retained, but not the methods.
assertThat(bClass, isPresentAndRenamed());
- assertThat(aClass, isPresentAndRenamed());
assertThat(bClass.uniqueMethodWithName("foo"), not(isPresent()));
+ assertThat(bClass.uniqueMethodWithName("bar"), not(isPresent()));
+
+ assertThat(aClass, isPresentAndRenamed());
+ // The dependent rule with soft-pinning of bar never causes A::bar to be retained
+ // regardless of A and A::foo being retained.
+ assertThat(aClass.uniqueMethodWithName("bar"), not(isPresent()));
MethodSubject aFoo = aClass.uniqueMethodWithName("foo");
- // TODO(b/171289133): Remove R8 check once fixed.
- if (allowOptimization || shrinker.isR8()) {
+ if (allowOptimization) {
assertThat(aFoo, not(isPresent()));
} else {
assertThat(aFoo, isPresentAndRenamed(allowObfuscation));
@@ -110,12 +107,20 @@
public String foo() {
return "A::foo";
}
+
+ public String bar() {
+ return "A::bar";
+ }
}
static class B {
public String foo() {
return "B::foo";
}
+
+ public String bar() {
+ return "B::bar";
+ }
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/proguard/KeepStaticMethodAllowShrinkingCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/allowshrinking/ConditionalKeepStaticMethodAllowShrinkingCompatibilityTest.java
similarity index 86%
copy from src/test/java/com/android/tools/r8/proguard/KeepStaticMethodAllowShrinkingCompatibilityTest.java
copy to src/test/java/com/android/tools/r8/shaking/allowshrinking/ConditionalKeepStaticMethodAllowShrinkingCompatibilityTest.java
index a1fa1c3..5c99afd 100644
--- a/src/test/java/com/android/tools/r8/proguard/KeepStaticMethodAllowShrinkingCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/allowshrinking/ConditionalKeepStaticMethodAllowShrinkingCompatibilityTest.java
@@ -2,7 +2,7 @@
// 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.proguard;
+package com.android.tools.r8.shaking.allowshrinking;
import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -25,7 +25,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class KeepStaticMethodAllowShrinkingCompatibilityTest extends TestBase {
+public class ConditionalKeepStaticMethodAllowShrinkingCompatibilityTest extends TestBase {
private final boolean allowOptimization;
private final TestParameters parameters;
@@ -39,7 +39,7 @@
ImmutableList.of(Shrinker.R8, Shrinker.PG));
}
- public KeepStaticMethodAllowShrinkingCompatibilityTest(
+ public ConditionalKeepStaticMethodAllowShrinkingCompatibilityTest(
boolean allowOptimization, TestParameters parameters, Shrinker shrinker) {
this.allowOptimization = allowOptimization;
this.parameters = parameters;
@@ -60,7 +60,9 @@
.addProgramClasses(TestClass.class, Companion.class)
.addKeepMainRule(TestClass.class)
.addKeepRules(
- "-keep,allowshrinking"
+ "-if class "
+ + Companion.class.getTypeName()
+ + " -keep,allowshrinking"
+ (allowOptimization ? ",allowoptimization" : "")
+ " class "
+ Companion.class.getTypeName()
@@ -72,15 +74,12 @@
assertThat(testClassSubject, isPresent());
ClassSubject companionClassSubject = inspector.clazz(Companion.class);
- // TODO(b/171289133): Remove the R8 check one fixed.
- assertThat(
- companionClassSubject, notIf(isPresent(), allowOptimization || shrinker.isR8()));
+ assertThat(companionClassSubject, notIf(isPresent(), allowOptimization));
MethodSubject mainMethodSubject = testClassSubject.mainMethod();
MethodSubject getMethodSubject = companionClassSubject.uniqueMethodWithName("get");
- // TODO(b/171289133): Remove the R8 check once fixed.
- if (allowOptimization || shrinker.isR8()) {
+ if (allowOptimization) {
assertTrue(
testClassSubject
.mainMethod()
diff --git a/src/test/java/com/android/tools/r8/proguard/KeepAllowShrinkingCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepAllowShrinkingCompatibilityTest.java
similarity index 91%
rename from src/test/java/com/android/tools/r8/proguard/KeepAllowShrinkingCompatibilityTest.java
rename to src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepAllowShrinkingCompatibilityTest.java
index 130dc2d..c9b3bc7 100644
--- a/src/test/java/com/android/tools/r8/proguard/KeepAllowShrinkingCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepAllowShrinkingCompatibilityTest.java
@@ -1,7 +1,7 @@
// Copyright (c) 2020, 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.proguard;
+package com.android.tools.r8.shaking.allowshrinking;
import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -54,11 +54,7 @@
return StringUtils.lines(
"A::foo",
// Reflective lookup of A::foo will only work if optimization and obfuscation are disabled.
- Boolean.toString(
- !allowOptimization
- && !allowObfuscation
- // TODO(b/171289133): Remove this exception once fixed.
- && !shrinker.isR8()),
+ Boolean.toString(!allowOptimization && !allowObfuscation),
"false");
}
@@ -67,7 +63,7 @@
if (shrinker.isR8()) {
run(
testForR8(parameters.getBackend())
- // TODO(b/171289133): The keep rule should not be "unmatched".
+ // Allowing all of shrinking, optimization and obfuscation will amount to a nop rule.
.allowUnusedProguardConfigurationRules(allowOptimization && allowObfuscation));
} else {
run(testForProguard(shrinker.getProguardVersion()).addDontWarn(getClass()));
@@ -96,8 +92,7 @@
assertThat(aClass, isPresentAndRenamed(allowObfuscation));
assertThat(bClass.uniqueMethodWithName("foo"), not(isPresent()));
MethodSubject aFoo = aClass.uniqueMethodWithName("foo");
- // TODO(b/171289133): Remove R8 check once fixed.
- if (allowOptimization || shrinker.isR8()) {
+ if (allowOptimization) {
assertThat(aFoo, not(isPresent()));
} else {
assertThat(aFoo, isPresentAndRenamed(allowObfuscation));
diff --git a/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepClassFieldsAllowShrinkingCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepClassFieldsAllowShrinkingCompatibilityTest.java
new file mode 100644
index 0000000..8b01419
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepClassFieldsAllowShrinkingCompatibilityTest.java
@@ -0,0 +1,158 @@
+// Copyright (c) 2020, 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.shaking.allowshrinking;
+
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.accessesField;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.FieldSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class KeepClassFieldsAllowShrinkingCompatibilityTest extends TestBase {
+
+ private final TestParameters parameters;
+ private final boolean allowOptimization;
+ private final boolean allowObfuscation;
+ private final Shrinker shrinker;
+
+ @Parameterized.Parameters(name = "{0}, opt:{1}, obf:{2}, {3}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withCfRuntimes().build(),
+ BooleanUtils.values(),
+ BooleanUtils.values(),
+ ImmutableList.of(Shrinker.R8, Shrinker.PG));
+ }
+
+ public KeepClassFieldsAllowShrinkingCompatibilityTest(
+ TestParameters parameters,
+ boolean allowOptimization,
+ boolean allowObfuscation,
+ Shrinker shrinker) {
+ this.parameters = parameters;
+ this.allowOptimization = allowOptimization;
+ this.allowObfuscation = allowObfuscation;
+ this.shrinker = shrinker;
+ }
+
+ String getExpected() {
+ return StringUtils.lines(
+ "A.foo",
+ // R8 will succeed in removing the field if allowoptimization is set.
+ Boolean.toString((shrinker.isPG() || !allowOptimization) && !allowObfuscation),
+ // R8 will always remove the unreferenced B.foo field.
+ Boolean.toString(shrinker.isPG() && !allowOptimization && !allowObfuscation));
+ }
+
+ @Test
+ public void test() throws Exception {
+ if (shrinker.isR8()) {
+ run(
+ testForR8(parameters.getBackend())
+ // Allowing all of shrinking, optimization and obfuscation will amount to a nop rule.
+ .allowUnusedProguardConfigurationRules(allowOptimization && allowObfuscation));
+ } else {
+ run(testForProguard(shrinker.getProguardVersion()).addDontWarn(getClass()));
+ }
+ }
+
+ public <T extends TestShrinkerBuilder<?, ?, ?, ?, T>> void run(T builder) throws Exception {
+ String keepRule =
+ "-keepclassmembers,allowshrinking"
+ + (allowOptimization ? ",allowoptimization" : "")
+ + (allowObfuscation ? ",allowobfuscation" : "")
+ + " class * { java.lang.String foo; java.lang.String bar; }";
+ builder
+ .addInnerClasses(KeepClassFieldsAllowShrinkingCompatibilityTest.class)
+ .addKeepClassAndMembersRules(TestClass.class)
+ .addKeepRules(keepRule)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class, A.class.getTypeName())
+ .assertSuccessWithOutput(getExpected())
+ .inspect(
+ inspector -> {
+ ClassSubject aClass = inspector.clazz(A.class);
+ ClassSubject bClass = inspector.clazz(B.class);
+ // The class constants will force A and B to be retained but renamed.
+ assertThat(aClass, isPresentAndRenamed());
+ assertThat(bClass, isPresentAndRenamed());
+
+ FieldSubject aFoo = aClass.uniqueFieldWithName("foo");
+ FieldSubject aBar = aClass.uniqueFieldWithName("bar");
+ FieldSubject bFoo = bClass.uniqueFieldWithName("foo");
+ FieldSubject bBar = bClass.uniqueFieldWithName("bar");
+
+ if (allowOptimization) {
+ // PG fails to optimize out the referenced field.
+ assertThat(aFoo, notIf(isPresent(), shrinker.isR8()));
+ assertThat(aBar, not(isPresent()));
+ assertThat(bFoo, not(isPresent()));
+ assertThat(bBar, not(isPresent()));
+ } else {
+ assertThat(aFoo, isPresentAndRenamed(allowObfuscation));
+ // TODO(b/171459868) It is inconsistent that the unused field A.bar is retained.
+ // This does not match the R8 behavior for an unused method, so there may be an
+ // optimization opportunity here.
+ // (See KeepClassMethodsAllowShrinkingCompatibilityTest regarding methods).
+ assertThat(aBar, isPresentAndRenamed(allowObfuscation));
+ assertThat(inspector.clazz(TestClass.class).mainMethod(), accessesField(aFoo));
+ if (shrinker.isR8()) {
+ assertThat(bFoo, not(isPresent()));
+ assertThat(bBar, not(isPresent()));
+ } else {
+ assertThat(bFoo, isPresentAndRenamed(allowObfuscation));
+ assertThat(bBar, isPresentAndRenamed(allowObfuscation));
+ }
+ }
+ });
+ }
+
+ static class A {
+ // Note: If the fields are final PG actually allows itself to inline the values.
+ public String foo = "A.foo";
+ public String bar = "A.bar";
+ }
+
+ static class B {
+ public String foo = "B.foo";
+ public String bar = "B.bar";
+ }
+
+ static class TestClass {
+
+ public static boolean hasFoo(String name) {
+ try {
+ return Class.forName(name).getDeclaredField("foo") != null;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public static void main(String[] args) {
+ // Conditional instance to prohibit class inlining of A.
+ A a = args.length == 42 ? null : new A();
+ // Direct use of A.foo, if optimization is not allowed it will be kept.
+ System.out.println(a.foo);
+ // Reference to A should not retain A.foo when allowoptimization is set.
+ System.out.println(hasFoo(a.getClass().getTypeName()));
+ // Reference to B should not retain B.foo regardless of allowoptimization.
+ System.out.println(hasFoo(B.class.getTypeName()));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/proguard/KeepClassMembersAllowShrinkingCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepClassMethodsAllowShrinkingCompatibilityTest.java
similarity index 82%
rename from src/test/java/com/android/tools/r8/proguard/KeepClassMembersAllowShrinkingCompatibilityTest.java
rename to src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepClassMethodsAllowShrinkingCompatibilityTest.java
index cb83f31..e7d5191 100644
--- a/src/test/java/com/android/tools/r8/proguard/KeepClassMembersAllowShrinkingCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepClassMethodsAllowShrinkingCompatibilityTest.java
@@ -1,7 +1,7 @@
// Copyright (c) 2020, 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.proguard;
+package com.android.tools.r8.shaking.allowshrinking;
import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -23,7 +23,7 @@
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class KeepClassMembersAllowShrinkingCompatibilityTest extends TestBase {
+public class KeepClassMethodsAllowShrinkingCompatibilityTest extends TestBase {
private final TestParameters parameters;
private final boolean allowOptimization;
@@ -39,7 +39,7 @@
ImmutableList.of(Shrinker.R8, Shrinker.PG));
}
- public KeepClassMembersAllowShrinkingCompatibilityTest(
+ public KeepClassMethodsAllowShrinkingCompatibilityTest(
TestParameters parameters,
boolean allowOptimization,
boolean allowObfuscation,
@@ -54,11 +54,7 @@
return StringUtils.lines(
"A::foo",
// Reflective lookup of A::foo will only work if optimization and obfuscation are disabled.
- Boolean.toString(
- !allowOptimization
- && !allowObfuscation
- // TODO(b/171289133): Remove this exception once fixed.
- && !shrinker.isR8()),
+ Boolean.toString(!allowOptimization && !allowObfuscation),
"false");
}
@@ -67,7 +63,7 @@
if (shrinker.isR8()) {
run(
testForR8(parameters.getBackend())
- // TODO(b/171289133): The keep rule should not be "unmatched".
+ // Allowing all of shrinking, optimization and obfuscation will amount to a nop rule.
.allowUnusedProguardConfigurationRules(allowOptimization && allowObfuscation));
} else {
run(testForProguard(shrinker.getProguardVersion()).addDontWarn(getClass()));
@@ -79,9 +75,9 @@
"-keepclassmembers,allowshrinking"
+ (allowOptimization ? ",allowoptimization" : "")
+ (allowObfuscation ? ",allowobfuscation" : "")
- + " class * { java.lang.String foo(); }";
+ + " class * { java.lang.String foo(); java.lang.String bar(); }";
builder
- .addInnerClasses(KeepClassMembersAllowShrinkingCompatibilityTest.class)
+ .addInnerClasses(KeepClassMethodsAllowShrinkingCompatibilityTest.class)
.addKeepClassAndMembersRules(TestClass.class)
.addKeepRules(keepRule)
.setMinApi(parameters.getApiLevel())
@@ -91,13 +87,17 @@
inspector -> {
ClassSubject aClass = inspector.clazz(A.class);
ClassSubject bClass = inspector.clazz(B.class);
- // The class constants will force A and B to be retained, but not the foo methods.
+ // The class constants will force A and B to be retained, but not the methods.
assertThat(bClass, isPresentAndRenamed());
- assertThat(aClass, isPresentAndRenamed());
assertThat(bClass.uniqueMethodWithName("foo"), not(isPresent()));
+ assertThat(bClass.uniqueMethodWithName("bar"), not(isPresent()));
+
+ assertThat(aClass, isPresentAndRenamed());
+ // The dependent rule with soft-pinning of bar never causes A::bar to be retained
+ // regardless of A and A::foo being retained.
+ assertThat(aClass.uniqueMethodWithName("bar"), not(isPresent()));
MethodSubject aFoo = aClass.uniqueMethodWithName("foo");
- // TODO(b/171289133): Remove R8 check once fixed.
- if (allowOptimization || shrinker.isR8()) {
+ if (allowOptimization) {
assertThat(aFoo, not(isPresent()));
} else {
assertThat(aFoo, isPresentAndRenamed(allowObfuscation));
@@ -110,12 +110,20 @@
public String foo() {
return "A::foo";
}
+
+ public String bar() {
+ return "A::bar";
+ }
}
static class B {
public String foo() {
return "B::foo";
}
+
+ public String bar() {
+ return "B::bar";
+ }
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/proguard/KeepStaticMethodAllowShrinkingCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepStaticFieldAllowShrinkingCompatibilityTest.java
similarity index 77%
copy from src/test/java/com/android/tools/r8/proguard/KeepStaticMethodAllowShrinkingCompatibilityTest.java
copy to src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepStaticFieldAllowShrinkingCompatibilityTest.java
index a1fa1c3..2322f85 100644
--- a/src/test/java/com/android/tools/r8/proguard/KeepStaticMethodAllowShrinkingCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepStaticFieldAllowShrinkingCompatibilityTest.java
@@ -2,11 +2,11 @@
// 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.proguard;
+package com.android.tools.r8.shaking.allowshrinking;
-import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.accessesField;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -15,6 +15,7 @@
import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.FieldSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
@@ -25,7 +26,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class KeepStaticMethodAllowShrinkingCompatibilityTest extends TestBase {
+public class KeepStaticFieldAllowShrinkingCompatibilityTest extends TestBase {
private final boolean allowOptimization;
private final TestParameters parameters;
@@ -39,7 +40,7 @@
ImmutableList.of(Shrinker.R8, Shrinker.PG));
}
- public KeepStaticMethodAllowShrinkingCompatibilityTest(
+ public KeepStaticFieldAllowShrinkingCompatibilityTest(
boolean allowOptimization, TestParameters parameters, Shrinker shrinker) {
this.allowOptimization = allowOptimization;
this.parameters = parameters;
@@ -64,31 +65,29 @@
+ (allowOptimization ? ",allowoptimization" : "")
+ " class "
+ Companion.class.getTypeName()
- + " { <methods>; }")
+ + " { <fields>; }")
.compile()
.inspect(
inspector -> {
ClassSubject testClassSubject = inspector.clazz(TestClass.class);
assertThat(testClassSubject, isPresent());
- ClassSubject companionClassSubject = inspector.clazz(Companion.class);
- // TODO(b/171289133): Remove the R8 check one fixed.
- assertThat(
- companionClassSubject, notIf(isPresent(), allowOptimization || shrinker.isR8()));
-
MethodSubject mainMethodSubject = testClassSubject.mainMethod();
- MethodSubject getMethodSubject = companionClassSubject.uniqueMethodWithName("get");
+ ClassSubject companionClassSubject = inspector.clazz(Companion.class);
+ FieldSubject xFieldSubject = companionClassSubject.uniqueFieldWithName("x");
- // TODO(b/171289133): Remove the R8 check once fixed.
- if (allowOptimization || shrinker.isR8()) {
+ // PG fails to optimize fields regardless of keep flags.
+ if (allowOptimization && shrinker.isR8()) {
+ assertThat(companionClassSubject, not(isPresent()));
assertTrue(
testClassSubject
.mainMethod()
.streamInstructions()
.allMatch(InstructionSubject::isReturnVoid));
} else {
- assertThat(mainMethodSubject, invokesMethod(getMethodSubject));
- assertThat(getMethodSubject, isPresent());
+ assertThat(companionClassSubject, isPresent());
+ assertThat(mainMethodSubject, accessesField(xFieldSubject));
+ assertThat(xFieldSubject, isPresent());
}
})
.run(parameters.getRuntime(), TestClass.class)
@@ -98,7 +97,7 @@
static class TestClass {
public static void main(String[] args) {
- if (Companion.get() != 42) {
+ if (Companion.x != 42) {
System.out.println("Hello world!");
}
}
@@ -106,8 +105,6 @@
static class Companion {
- static int get() {
- return 42;
- }
+ static int x = 42;
}
}
diff --git a/src/test/java/com/android/tools/r8/proguard/KeepStaticMethodAllowShrinkingCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepStaticMethodAllowShrinkingCompatibilityTest.java
similarity index 91%
rename from src/test/java/com/android/tools/r8/proguard/KeepStaticMethodAllowShrinkingCompatibilityTest.java
rename to src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepStaticMethodAllowShrinkingCompatibilityTest.java
index a1fa1c3..9dbdbb4 100644
--- a/src/test/java/com/android/tools/r8/proguard/KeepStaticMethodAllowShrinkingCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/allowshrinking/KeepStaticMethodAllowShrinkingCompatibilityTest.java
@@ -2,7 +2,7 @@
// 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.proguard;
+package com.android.tools.r8.shaking.allowshrinking;
import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -72,15 +72,12 @@
assertThat(testClassSubject, isPresent());
ClassSubject companionClassSubject = inspector.clazz(Companion.class);
- // TODO(b/171289133): Remove the R8 check one fixed.
- assertThat(
- companionClassSubject, notIf(isPresent(), allowOptimization || shrinker.isR8()));
+ assertThat(companionClassSubject, notIf(isPresent(), allowOptimization));
MethodSubject mainMethodSubject = testClassSubject.mainMethod();
MethodSubject getMethodSubject = companionClassSubject.uniqueMethodWithName("get");
- // TODO(b/171289133): Remove the R8 check once fixed.
- if (allowOptimization || shrinker.isR8()) {
+ if (allowOptimization) {
assertTrue(
testClassSubject
.mainMethod()
diff --git a/src/test/java/com/android/tools/r8/proguard/Shrinker.java b/src/test/java/com/android/tools/r8/shaking/allowshrinking/Shrinker.java
similarity index 95%
rename from src/test/java/com/android/tools/r8/proguard/Shrinker.java
rename to src/test/java/com/android/tools/r8/shaking/allowshrinking/Shrinker.java
index 8cd4867..112fd05 100644
--- a/src/test/java/com/android/tools/r8/proguard/Shrinker.java
+++ b/src/test/java/com/android/tools/r8/shaking/allowshrinking/Shrinker.java
@@ -1,7 +1,7 @@
// Copyright (c) 2020, 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.proguard;
+package com.android.tools.r8.shaking.allowshrinking;
import com.android.tools.r8.ProguardVersion;