Reland "Implicitly add necessary rules for Java reflections in any R8 mode."
PS1: same as original: https://r8-review.googlesource.com/c/r8/+/24260
PS4: rebase to a fix: https://r8-review.googlesource.com/c/r8/+/24424
PS6: fix remaining tests
PS7: not store -identifiernamestring rules for compat Proguard config
Bug: 76181966, 111619623
Change-Id: I3b5c6e99ff7626a95b655252cf2c98fd418e0e27
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
index d92de6b..8714b28 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
@@ -26,15 +26,15 @@
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.shaking.ProguardClassFilter;
+import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
import java.util.Map;
-import java.util.Set;
class IdentifierMinifier {
private final AppInfoWithLiveness appInfo;
private final ProguardClassFilter adaptClassStrings;
private final NamingLens lens;
- private final Set<DexItem> identifierNameStrings;
+ private final Object2BooleanMap<DexItem> identifierNameStrings;
IdentifierMinifier(
AppInfoWithLiveness appInfo, ProguardClassFilter adaptClassStrings, NamingLens lens) {
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
index b0f4dc0..830391a 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
@@ -35,17 +35,17 @@
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Streams;
+import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
-import java.util.Set;
import java.util.stream.Collectors;
public class IdentifierNameStringMarker {
private final AppInfo appInfo;
private final DexItemFactory dexItemFactory;
- private final Set<DexItem> identifierNameStrings;
+ private final Object2BooleanMap<DexItem> identifierNameStrings;
private final InternalOptions options;
public IdentifierNameStringMarker(AppInfoWithLiveness appInfo, InternalOptions options) {
@@ -63,7 +63,7 @@
}
private void decoupleIdentifierNameStringInField(DexEncodedField encodedField) {
- if (!identifierNameStrings.contains(encodedField.field)) {
+ if (!identifierNameStrings.containsKey(encodedField.field)) {
return;
}
if (!encodedField.accessFlags.isStatic()) {
@@ -102,22 +102,27 @@
if (instruction.isStaticPut() || instruction.isInstancePut()) {
FieldInstruction fieldPut = instruction.asFieldInstruction();
DexField field = fieldPut.getField();
- if (!identifierNameStrings.contains(field)) {
+ if (!identifierNameStrings.containsKey(field)) {
continue;
}
+ boolean isExplicitRule = identifierNameStrings.getBoolean(field);
Value in = instruction.isStaticPut()
? instruction.asStaticPut().inValue()
: instruction.asInstancePut().value();
if (!in.isConstString()) {
- warnUndeterminedIdentifierIfNecessary(
- appInfo, options, field, originHolder, instruction, null);
+ if (isExplicitRule) {
+ warnUndeterminedIdentifierIfNecessary(
+ appInfo, options, field, originHolder, instruction, null);
+ }
continue;
}
DexString original = in.getConstInstruction().asConstString().getValue();
DexItemBasedString itemBasedString = inferMemberOrTypeFromNameString(appInfo, original);
if (itemBasedString == null) {
- warnUndeterminedIdentifierIfNecessary(
- appInfo, options, field, originHolder, instruction, original);
+ if (isExplicitRule) {
+ warnUndeterminedIdentifierIfNecessary(
+ appInfo, options, field, originHolder, instruction, original);
+ }
continue;
}
// Move the cursor back to $fieldPut
@@ -163,16 +168,19 @@
} else if (instruction.isInvokeMethod()) {
InvokeMethod invoke = instruction.asInvokeMethod();
DexMethod invokedMethod = invoke.getInvokedMethod();
- if (!identifierNameStrings.contains(invokedMethod)) {
+ if (!identifierNameStrings.containsKey(invokedMethod)) {
continue;
}
+ boolean isExplicitRule = identifierNameStrings.getBoolean(invokedMethod);
List<Value> ins = invoke.arguments();
Value[] changes = new Value [ins.size()];
if (isReflectionMethod(dexItemFactory, invokedMethod)) {
DexItemBasedString itemBasedString = identifyIdentiferNameString(appInfo, invoke);
if (itemBasedString == null) {
- warnUndeterminedIdentifierIfNecessary(
- appInfo, options, invokedMethod, originHolder, instruction, null);
+ if (isExplicitRule) {
+ warnUndeterminedIdentifierIfNecessary(
+ appInfo, options, invokedMethod, originHolder, instruction, null);
+ }
continue;
}
DexType returnType = invoke.getReturnType();
@@ -217,16 +225,20 @@
for (int i = 0; i < ins.size(); i++) {
Value in = ins.get(i);
if (!in.isConstString()) {
- warnUndeterminedIdentifierIfNecessary(
- appInfo, options, invokedMethod, originHolder, instruction, null);
+ if (isExplicitRule) {
+ warnUndeterminedIdentifierIfNecessary(
+ appInfo, options, invokedMethod, originHolder, instruction, null);
+ }
continue;
}
DexString original = in.getConstInstruction().asConstString().getValue();
DexItemBasedString itemBasedString =
inferMemberOrTypeFromNameString(appInfo, original);
if (itemBasedString == null) {
- warnUndeterminedIdentifierIfNecessary(
- appInfo, options, invokedMethod, originHolder, instruction, original);
+ if (isExplicitRule) {
+ warnUndeterminedIdentifierIfNecessary(
+ appInfo, options, invokedMethod, originHolder, instruction, original);
+ }
continue;
}
// Move the cursor back to $invoke
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 bcd489e..420af47 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -5,8 +5,6 @@
import static com.android.tools.r8.naming.IdentifierNameStringUtils.identifyIdentiferNameString;
import static com.android.tools.r8.naming.IdentifierNameStringUtils.isReflectionMethod;
-import static com.android.tools.r8.naming.IdentifierNameStringUtils.warnUndeterminedIdentifierIfNecessary;
-import static com.android.tools.r8.shaking.ProguardConfigurationUtils.buildIdentifierNameStringRule;
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.dex.IndexedItemCollection;
@@ -58,6 +56,8 @@
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap;
+import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import java.util.ArrayDeque;
import java.util.Collection;
@@ -187,10 +187,9 @@
private final Queue<Action> proguardCompatibilityWorkList = Queues.newArrayDeque();
/**
- * A set of methods that need code inspection for Proguard compatibility rules.
+ * A set of methods that need code inspection for Java reflection in use.
*/
- private final Set<DexEncodedMethod> pendingProguardReflectiveCompatibility =
- Sets.newLinkedHashSet();
+ private final Set<DexEncodedMethod> pendingReflectiveUses = Sets.newLinkedHashSet();
/**
* A cache for DexMethod that have been marked reachable.
@@ -314,13 +313,10 @@
boolean registerInvokeVirtual(DexMethod method, KeepReason keepReason) {
if (appInfo.dexItemFactory.classMethods.isReflectiveMemberLookup(method)) {
- if (forceProguardCompatibility) {
- // TODO(b/76181966): whether or not add this rule in normal mode.
- if (identifierNameStrings.add(method) && compatibility != null) {
- compatibility.addRule(buildIdentifierNameStringRule(method));
- }
- pendingProguardReflectiveCompatibility.add(currentMethod);
- }
+ // Implicitly add -identifiernamestring rule for the Java reflection in use.
+ identifierNameStrings.add(method);
+ // Revisit the current method to implicitly add -keep rule for items with reflective access.
+ pendingReflectiveUses.add(currentMethod);
}
if (!registerItemWithTarget(virtualInvokes, method)) {
return false;
@@ -356,13 +352,10 @@
boolean registerInvokeStatic(DexMethod method, KeepReason keepReason) {
if (method == appInfo.dexItemFactory.classMethods.forName
|| appInfo.dexItemFactory.atomicFieldUpdaterMethods.isFieldUpdater(method)) {
- if (forceProguardCompatibility) {
- // TODO(b/76181966): whether or not add this rule in normal mode.
- if (identifierNameStrings.add(method) && compatibility != null) {
- compatibility.addRule(buildIdentifierNameStringRule(method));
- }
- pendingProguardReflectiveCompatibility.add(currentMethod);
- }
+ // Implicitly add -identifiernamestring rule for the Java reflection in use.
+ identifierNameStrings.add(method);
+ // Revisit the current method to implicitly add -keep rule for items with reflective access.
+ pendingReflectiveUses.add(currentMethod);
}
if (!registerItemWithTarget(staticInvokes, method)) {
return false;
@@ -1279,15 +1272,15 @@
}
// Continue fix-point processing while there are additional work items to ensure
- // Proguard compatibility.
+ // items that are passed to Java reflections are traced.
if (proguardCompatibilityWorkList.isEmpty()
- && pendingProguardReflectiveCompatibility.isEmpty()) {
+ && pendingReflectiveUses.isEmpty()) {
break;
}
- pendingProguardReflectiveCompatibility.forEach(this::handleProguardReflectiveBehavior);
+ pendingReflectiveUses.forEach(this::handleReflectiveBehavior);
workList.addAll(proguardCompatibilityWorkList);
proguardCompatibilityWorkList.clear();
- pendingProguardReflectiveCompatibility.clear();
+ pendingReflectiveUses.clear();
}
if (Log.ENABLED) {
Set<DexEncodedMethod> allLive = Sets.newIdentityHashSet();
@@ -1484,15 +1477,15 @@
Action.markMethodLive(method, KeepReason.dueToProguardCompatibilityKeepRule(rule)));
}
- private void handleProguardReflectiveBehavior(DexEncodedMethod method) {
+ private void handleReflectiveBehavior(DexEncodedMethod method) {
DexType originHolder = method.method.holder;
Origin origin = appInfo.originFor(originHolder);
IRCode code = method.buildIR(appInfo, graphLense, options, origin);
code.instructionIterator().forEachRemaining(instr ->
- handleProguardReflectiveBehavior(instr, originHolder));
+ handleReflectiveBehavior(instr, originHolder));
}
- private void handleProguardReflectiveBehavior(Instruction instruction, DexType originHolder) {
+ private void handleReflectiveBehavior(Instruction instruction, DexType originHolder) {
if (!instruction.isInvokeMethod()) {
return;
}
@@ -1503,8 +1496,6 @@
}
DexItemBasedString itemBasedString = identifyIdentiferNameString(appInfo, invoke);
if (itemBasedString == null) {
- warnUndeterminedIdentifierIfNecessary(
- appInfo, options, invokedMethod, originHolder, instruction, null);
return;
}
if (itemBasedString.basedOn instanceof DexType) {
@@ -1692,8 +1683,10 @@
public final Set<DexItem> neverInline;
/**
* All items with -identifiernamestring rule.
+ * Bound boolean value indicates the rule is explicitly specified by users (<code>true</code>)
+ * or not, i.e., implicitly added by R8 (<code>false</code>).
*/
- public final Set<DexItem> identifierNameStrings;
+ public final Object2BooleanMap<DexItem> identifierNameStrings;
/**
* Set of fields that have been identified as proto-lite fields by the
* {@link ProtoLiteExtension}.
@@ -1750,8 +1743,8 @@
this.alwaysInline = enqueuer.rootSet.alwaysInline;
this.forceInline = enqueuer.rootSet.forceInline;
this.neverInline = enqueuer.rootSet.neverInline;
- this.identifierNameStrings =
- Sets.union(enqueuer.rootSet.identifierNameStrings, enqueuer.identifierNameStrings);
+ this.identifierNameStrings = joinIdentifierNameStrings(
+ enqueuer.rootSet.identifierNameStrings, enqueuer.identifierNameStrings);
this.protoLiteFields = enqueuer.protoLiteFields;
this.prunedTypes = Collections.emptySet();
this.switchMaps = Collections.emptyMap();
@@ -1922,6 +1915,18 @@
.collect(ImmutableSortedSet.toImmutableSortedSet(PresortedComparable::slowCompare));
}
+ private Object2BooleanMap<DexItem> joinIdentifierNameStrings(
+ Set<DexItem> explicit, Set<DexItem> implicit) {
+ Object2BooleanMap<DexItem> result = new Object2BooleanArrayMap<>();
+ for (DexItem e : explicit) {
+ result.putIfAbsent(e, true);
+ }
+ for (DexItem i : implicit) {
+ result.putIfAbsent(i, false);
+ }
+ return result;
+ }
+
private <T extends PresortedComparable<T>> SortedSet<T> toSortedDescriptorSet(
Set<? extends KeyedDexItem<T>> set) {
ImmutableSortedSet.Builder<T> builder =
@@ -2031,6 +2036,32 @@
return builder.build();
}
+ private static Object2BooleanMap<DexItem> rewriteMixedItemsConservatively(
+ Object2BooleanMap<DexItem> original, GraphLense lense) {
+ Object2BooleanMap<DexItem> result = new Object2BooleanArrayMap<>();
+ for (Object2BooleanMap.Entry<DexItem> entry : original.object2BooleanEntrySet()) {
+ DexItem item = entry.getKey();
+ // TODO(b/67934123) There should be a common interface to perform the dispatch.
+ if (item instanceof DexType) {
+ result.put(lense.lookupType((DexType) item), entry.getBooleanValue());
+ } else if (item instanceof DexMethod) {
+ DexMethod method = (DexMethod) item;
+ if (lense.isContextFreeForMethod(method)) {
+ result.put(lense.lookupMethod(method), entry.getBooleanValue());
+ } else {
+ for (DexMethod candidate: lense.lookupMethodInAllContexts(method)) {
+ result.put(candidate, entry.getBooleanValue());
+ }
+ }
+ } else if (item instanceof DexField) {
+ result.put(lense.lookupField((DexField) item), entry.getBooleanValue());
+ } else {
+ throw new Unreachable();
+ }
+ }
+ return result;
+ }
+
private static <T> Set<T> mergeSets(Collection<T> first, Collection<T> second) {
ImmutableSet.Builder<T> builder = ImmutableSet.builder();
builder.addAll(first);
diff --git a/src/test/examples/identifiernamestring/keep-rules-3.txt b/src/test/examples/identifiernamestring/keep-rules-3.txt
index aa23772..1c69314 100644
--- a/src/test/examples/identifiernamestring/keep-rules-3.txt
+++ b/src/test/examples/identifiernamestring/keep-rules-3.txt
@@ -11,7 +11,7 @@
-dontshrink
--identifiernamestring class * {
+-identifiernamestring class **.R {
static java.lang.reflect.Field *(java.lang.Class, java.lang.String);
static java.lang.reflect.Method *(java.lang.Class, java.lang.String, java.lang.Class[]);
}
diff --git a/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java b/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
index a9ee851..73cdaaf 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
@@ -142,7 +142,7 @@
FoundMethodSubject foundMain = (FoundMethodSubject) main;
verifyPresenceOfConstString(foundMain);
int renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, foundMain);
- assertEquals(0, renamedYetFoundIdentifierCount);
+ assertEquals(4, renamedYetFoundIdentifierCount);
ClassSubject aClass = inspector.clazz("adaptclassstrings.A");
MethodSubject bar = aClass.method("void", "bar", ImmutableList.of());
@@ -165,7 +165,7 @@
FoundMethodSubject foundMain = (FoundMethodSubject) main;
verifyPresenceOfConstString(foundMain);
int renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, foundMain);
- assertEquals(0, renamedYetFoundIdentifierCount);
+ assertEquals(4, renamedYetFoundIdentifierCount);
ClassSubject aClass = inspector.clazz("adaptclassstrings.A");
MethodSubject bar = aClass.method("void", "bar", ImmutableList.of());
@@ -231,7 +231,7 @@
FoundMethodSubject foundMain = (FoundMethodSubject) main;
verifyPresenceOfConstString(foundMain);
int renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, foundMain);
- assertEquals(0, renamedYetFoundIdentifierCount);
+ assertEquals(1, renamedYetFoundIdentifierCount);
ClassSubject aClass = inspector.clazz("identifiernamestring.A");
MethodSubject aInit =
@@ -255,7 +255,7 @@
FoundMethodSubject foundMain = (FoundMethodSubject) main;
verifyPresenceOfConstString(foundMain);
int renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, foundMain);
- assertEquals(1, renamedYetFoundIdentifierCount);
+ assertEquals(2, renamedYetFoundIdentifierCount);
ClassSubject aClass = inspector.clazz("identifiernamestring.A");
MethodSubject aInit =
@@ -271,7 +271,7 @@
assertEquals(2, renamedYetFoundIdentifierCount);
}
- // With -identifiernamestring for reflective methods
+ // With -identifiernamestring for reflective methods in testing class R.
private static void test2_rule3(CodeInspector inspector) {
ClassSubject mainClass = inspector.clazz("identifiernamestring.Main");
MethodSubject main = mainClass.method(CodeInspector.MAIN);
diff --git a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
index 829cdd0..49ba186 100644
--- a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
+++ b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
@@ -9,6 +9,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.DiagnosticsChecker;
import com.android.tools.r8.OutputMode;
@@ -72,15 +73,17 @@
byte[][] classes,
Class main,
Path out,
+ boolean explicitRule,
boolean enableMinification,
boolean forceProguardCompatibility)
throws Exception {
String minificationModifier = enableMinification ? ",allowobfuscation " : " ";
- String reflectionRules = forceProguardCompatibility ? ""
- : "-identifiernamestring class java.lang.Class {\n"
+ String reflectionRules = explicitRule
+ ? "-identifiernamestring class java.lang.Class {\n"
+ "static java.lang.Class forName(java.lang.String);\n"
+ "java.lang.reflect.Method getDeclaredMethod(java.lang.String, java.lang.Class[]);\n"
- + "}\n";
+ + "}\n"
+ : "";
R8Command.Builder commandBuilder =
R8Command.builder(reporter)
.addProguardConfiguration(
@@ -102,7 +105,8 @@
});
}
- private void reflectionWithBuildter(
+ private void reflectionWithBuilder(
+ boolean explicitRule,
boolean enableMinification,
boolean forceProguardCompatibility) throws Exception {
byte[][] classes = {
@@ -110,7 +114,7 @@
};
Path out = temp.getRoot().toPath();
AndroidApp processedApp = runR8(classes, WarnReflectiveAccessTestMain.class, out,
- enableMinification, forceProguardCompatibility);
+ explicitRule, enableMinification, forceProguardCompatibility);
String main = WarnReflectiveAccessTestMain.class.getCanonicalName();
CodeInspector codeInspector = new CodeInspector(processedApp);
@@ -133,35 +137,59 @@
}
@Test
- public void test_minification_forceProguardCompatibility() throws Exception {
- reflectionWithBuildter(true, true);
+ public void test_explicit_minification_forceProguardCompatibility() throws Exception {
+ reflectionWithBuilder(true, true, true);
assertFalse(handler.warnings.isEmpty());
- DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 54, 1,
- "Cannot determine", "getDeclaredMethod", "resolution failure");
- }
-
- @Test
- public void test_noMinification_forceProguardCompatibility() throws Exception {
- reflectionWithBuildter(false, true);
- assertFalse(handler.warnings.isEmpty());
- DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 54, 1,
- "Cannot determine", "getDeclaredMethod", "resolution failure");
- }
-
- @Test
- public void test_minification_R8() throws Exception {
- reflectionWithBuildter(true, false);
- assertFalse(handler.warnings.isEmpty());
- DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 54, 1,
+ DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 55, 1,
"Cannot determine", "getDeclaredMethod", "-identifiernamestring", "resolution failure");
}
@Test
- public void test_noMinification_R8() throws Exception {
- reflectionWithBuildter(false, false);
+ public void test_explicit_noMinification_forceProguardCompatibility() throws Exception {
+ reflectionWithBuilder(true, false, true);
assertFalse(handler.warnings.isEmpty());
- DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 54, 1,
+ DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 55, 1,
"Cannot determine", "getDeclaredMethod", "-identifiernamestring", "resolution failure");
}
+ @Test
+ public void test_explicit_minification_R8() throws Exception {
+ reflectionWithBuilder(true, true, false);
+ assertFalse(handler.warnings.isEmpty());
+ DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 55, 1,
+ "Cannot determine", "getDeclaredMethod", "-identifiernamestring", "resolution failure");
+ }
+
+ @Test
+ public void test_explicit_noMinification_R8() throws Exception {
+ reflectionWithBuilder(true, false, false);
+ assertFalse(handler.warnings.isEmpty());
+ DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 55, 1,
+ "Cannot determine", "getDeclaredMethod", "-identifiernamestring", "resolution failure");
+ }
+
+ @Test
+ public void test_implicit_minification_forceProguardCompatibility() throws Exception {
+ reflectionWithBuilder(false, true, true);
+ assertTrue(handler.warnings.isEmpty());
+ }
+
+ @Test
+ public void test_implicit_noMinification_forceProguardCompatibility() throws Exception {
+ reflectionWithBuilder(false, false, true);
+ assertTrue(handler.warnings.isEmpty());
+ }
+
+ @Test
+ public void test_implicit_minification_R8() throws Exception {
+ reflectionWithBuilder(false, true, false);
+ assertTrue(handler.warnings.isEmpty());
+ }
+
+ @Test
+ public void test_implicit_noMinification_R8() throws Exception {
+ reflectionWithBuilder(false, false, false);
+ assertTrue(handler.warnings.isEmpty());
+ }
+
}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
index 51baed2..9cf0a85 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationParser;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
-import com.android.tools.r8.shaking.ProguardIdentifierNameStringRule;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.shaking.ProguardKeepRule;
import com.android.tools.r8.shaking.ProguardKeepRuleType;
@@ -261,7 +260,7 @@
assertTrue(inspector.clazz(getJavacGeneratedClassName(mainClass)).isPresent());
forNameClasses.forEach(clazz -> {
ClassSubject subject = inspector.clazz(getJavacGeneratedClassName(clazz));
- assertEquals(forceProguardCompatibility, subject.isPresent());
+ assertTrue(subject.isPresent());
assertEquals(subject.isPresent() && allowObfuscation, subject.isRenamed());
});
@@ -273,8 +272,10 @@
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility) {
List<ProguardConfigurationRule> rules = configuration.getRules();
- assertEquals(3, rules.size());
- Iterables.filter(rules, ProguardKeepRule.class).forEach(rule -> {
+ assertEquals(2, rules.size());
+ for (ProguardConfigurationRule r : rules) {
+ assertTrue(r instanceof ProguardKeepRule);
+ ProguardKeepRule rule = (ProguardKeepRule) r;
assertEquals(ProguardKeepRuleType.KEEP, rule.getType());
assertTrue(rule.getModifiers().allowsObfuscation);
assertTrue(rule.getModifiers().allowsOptimization);
@@ -292,18 +293,7 @@
assertEquals(1, memberRules.size());
assertEquals(ProguardMemberType.INIT, memberRules.iterator().next().getRuleType());
}
- });
- Iterables.filter(rules, ProguardIdentifierNameStringRule.class).forEach(rule -> {
- List<ProguardMemberRule> memberRules = rule.getMemberRules();
- ProguardClassNameList classNames = rule.getClassNames();
- assertEquals(1, classNames.size());
- DexType type = classNames.asSpecificDexTypes().get(0);
- assertEquals("java.lang.Class", type.toSourceString());
- assertEquals(1, memberRules.size());
- ProguardMemberRule memberRule = memberRules.iterator().next();
- assertEquals(ProguardMemberType.METHOD, memberRule.getRuleType());
- assertEquals("forName", memberRule.getName().toString());
- });
+ }
} else {
assertEquals(0, configuration.getRules().size());
}
@@ -367,11 +357,11 @@
assertTrue(classSubject.isPresent());
assertEquals(allowObfuscation, classSubject.isRenamed());
FieldSubject foo = classSubject.field("java.lang.String", "foo");
- assertEquals(forceProguardCompatibility, foo.isPresent());
+ assertTrue(foo.isPresent());
assertEquals(foo.isPresent() && allowObfuscation, foo.isRenamed());
MethodSubject bar =
classSubject.method("java.lang.String", "bar", ImmutableList.of("java.lang.String"));
- assertEquals(forceProguardCompatibility, bar.isPresent());
+ assertTrue(bar.isPresent());
assertEquals(bar.isPresent() && allowObfuscation, bar.isRenamed());
// Check the Proguard compatibility rules generated.
@@ -382,8 +372,10 @@
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility) {
List<ProguardConfigurationRule> rules = configuration.getRules();
- assertEquals(4, rules.size());
- Iterables.filter(rules, ProguardKeepRule.class).forEach(rule -> {
+ assertEquals(2, rules.size());
+ for (ProguardConfigurationRule r : rules) {
+ assertTrue(r instanceof ProguardKeepRule);
+ ProguardKeepRule rule = (ProguardKeepRule) r;
assertEquals(ProguardKeepRuleType.KEEP_CLASS_MEMBERS, rule.getType());
assertTrue(rule.getModifiers().allowsObfuscation);
assertTrue(rule.getModifiers().allowsOptimization);
@@ -400,18 +392,7 @@
assertEquals(ProguardMemberType.METHOD, memberRule.getRuleType());
assertTrue(memberRule.getName().matches("bar"));
}
- });
- Iterables.filter(rules, ProguardIdentifierNameStringRule.class).forEach(rule -> {
- List<ProguardMemberRule> memberRules = rule.getMemberRules();
- ProguardClassNameList classNames = rule.getClassNames();
- assertEquals(1, classNames.size());
- DexType type = classNames.asSpecificDexTypes().get(0);
- assertEquals("java.lang.Class", type.toSourceString());
- assertEquals(1, memberRules.size());
- ProguardMemberRule memberRule = memberRules.iterator().next();
- assertEquals(ProguardMemberType.METHOD, memberRule.getRuleType());
- assertTrue(memberRule.getName().toString().startsWith("getDeclared"));
- });
+ }
} else {
assertEquals(0, configuration.getRules().size());
}
@@ -480,13 +461,13 @@
assertTrue(classSubject.isPresent());
assertEquals(allowObfuscation, classSubject.isRenamed());
FieldSubject f = classSubject.field("int", "intField");
- assertEquals(forceProguardCompatibility, f.isPresent());
+ assertTrue(f.isPresent());
assertEquals(f.isPresent() && allowObfuscation, f.isRenamed());
f = classSubject.field("long", "longField");
- assertEquals(forceProguardCompatibility, f.isPresent());
+ assertTrue(f.isPresent());
assertEquals(f.isPresent() && allowObfuscation, f.isRenamed());
f = classSubject.field("java.lang.Object", "objField");
- assertEquals(forceProguardCompatibility, f.isPresent());
+ assertTrue(f.isPresent());
assertEquals(f.isPresent() && allowObfuscation, f.isRenamed());
// Check the Proguard compatibility rules generated.
@@ -497,9 +478,11 @@
ProguardConfiguration configuration = parser.getConfigRawForTesting();
if (forceProguardCompatibility) {
List<ProguardConfigurationRule> rules = configuration.getRules();
- assertEquals(6, rules.size());
+ assertEquals(3, rules.size());
Object2BooleanMap<String> keptFields = new Object2BooleanArrayMap<>();
- Iterables.filter(rules, ProguardKeepRule.class).forEach(rule -> {
+ for (ProguardConfigurationRule r : rules) {
+ assertTrue(r instanceof ProguardKeepRule);
+ ProguardKeepRule rule = (ProguardKeepRule) r;
assertEquals(ProguardKeepRuleType.KEEP_CLASS_MEMBERS, rule.getType());
assertTrue(rule.getModifiers().allowsObfuscation);
assertTrue(rule.getModifiers().allowsOptimization);
@@ -512,23 +495,11 @@
ProguardMemberRule memberRule = memberRules.iterator().next();
assertEquals(ProguardMemberType.FIELD, memberRule.getRuleType());
keptFields.put(memberRule.getName().toString(), true);
- });
+ }
assertEquals(3, keptFields.size());
assertTrue(keptFields.containsKey("intField"));
assertTrue(keptFields.containsKey("longField"));
assertTrue(keptFields.containsKey("objField"));
- Iterables.filter(rules, ProguardIdentifierNameStringRule.class).forEach(rule -> {
- List<ProguardMemberRule> memberRules = rule.getMemberRules();
- ProguardClassNameList classNames = rule.getClassNames();
- assertEquals(1, classNames.size());
- DexType type = classNames.asSpecificDexTypes().get(0);
- assertTrue(type.toSourceString().startsWith("java.util.concurrent.atomic.Atomic"));
- assertTrue(type.toSourceString().endsWith("FieldUpdater"));
- assertEquals(1, memberRules.size());
- ProguardMemberRule memberRule = memberRules.iterator().next();
- assertEquals(ProguardMemberType.METHOD, memberRule.getRuleType());
- assertEquals("newUpdater", memberRule.getName().toString());
- });
} else {
assertEquals(0, configuration.getRules().size());
}