[KeepAnno] Generalize the mapping to compatible rules.
This introduces a target kind that distinguishes between targets that
should include the class or member targets as a disjunction (e.g.,
keep), or as a conjuction (e.g., keepclasseswithmembers) or if the
targets are only the members (e.g., keepclassmembers).
The rule printing now avoids splitting the class and members rules in
the disjunctive case when possible. When a class target is needed, its
rule is amended with the Object::finalize member to avoid keeping
<init>().
Bug: b/248408342
Change-Id: I6cd024ec362f4e23d91778e405a5dcebacaafb87
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
index 7738b17..ee80978 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
@@ -16,11 +16,10 @@
import com.android.tools.r8.keepanno.ast.KeepOptions;
import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern;
import com.android.tools.r8.keepanno.ast.KeepTarget;
-import com.android.tools.r8.keepanno.keeprules.PgRule.PgConditionalClassRule;
-import com.android.tools.r8.keepanno.keeprules.PgRule.PgConditionalMemberRule;
-import com.android.tools.r8.keepanno.keeprules.PgRule.PgDependentClassRule;
+import com.android.tools.r8.keepanno.keeprules.PgRule.PgConditionalRule;
import com.android.tools.r8.keepanno.keeprules.PgRule.PgDependentMembersRule;
-import com.android.tools.r8.keepanno.keeprules.PgRule.PgUnconditionalClassRule;
+import com.android.tools.r8.keepanno.keeprules.PgRule.PgUnconditionalRule;
+import com.android.tools.r8.keepanno.keeprules.PgRule.TargetKeepKind;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
@@ -205,29 +204,31 @@
}
@FunctionalInterface
- private interface OnKeepMembers {
+ private interface OnTargetCallback {
void accept(
Map<String, KeepMemberPattern> memberPatterns,
- List<String> targets,
- boolean classAndMembers);
+ List<String> memberTargets,
+ TargetKeepKind keepKind);
}
private static void computeTargets(
Set<String> targets,
KeepBindings bindings,
Map<String, KeepMemberPattern> memberPatterns,
- Runnable onKeepClass,
- OnKeepMembers onKeepMembers) {
- List<String> targetMembers = new ArrayList<>();
+ OnTargetCallback callback) {
boolean keepClassTarget = false;
+ List<String> disjunctiveTargetMembers = new ArrayList<>();
+ List<String> classConjunctiveTargetMembers = new ArrayList<>();
+
for (String targetReference : targets) {
KeepItemPattern item = bindings.get(targetReference).getItem();
if (bindings.isAny(item)) {
- // If the target is "any item" then it contains any other target pattern so just emit the
- // single "any item" targets: class and members both.
- onKeepClass.run();
+ // If the target is "any item" then it contains any other target pattern.
memberPatterns.put(targetReference, item.getMemberPattern());
- onKeepMembers.accept(memberPatterns, Collections.singletonList(targetReference), false);
+ callback.accept(
+ memberPatterns,
+ Collections.singletonList(targetReference),
+ TargetKeepKind.CLASS_OR_MEMBERS);
return;
}
if (item.isClassItemPattern()) {
@@ -236,18 +237,38 @@
memberPatterns.putIfAbsent(targetReference, item.getMemberPattern());
if (item.isClassAndMemberPattern()) {
// If a target is a "class and member" target then it must be added as a separate rule.
- onKeepMembers.accept(memberPatterns, Collections.singletonList(targetReference), true);
+ classConjunctiveTargetMembers.add(targetReference);
} else {
assert item.isMemberItemPattern();
- targetMembers.add(targetReference);
+ disjunctiveTargetMembers.add(targetReference);
}
}
}
+
+ // The class is targeted, so that part of a class-and-member conjunction is satisfied.
+ // The conjunctive members can thus be moved to the disjunctive set.
if (keepClassTarget) {
- onKeepClass.run();
+ disjunctiveTargetMembers.addAll(classConjunctiveTargetMembers);
+ classConjunctiveTargetMembers.clear();
}
- if (!targetMembers.isEmpty()) {
- onKeepMembers.accept(memberPatterns, targetMembers, false);
+
+ if (!disjunctiveTargetMembers.isEmpty()) {
+ TargetKeepKind keepKind =
+ keepClassTarget ? TargetKeepKind.CLASS_OR_MEMBERS : TargetKeepKind.JUST_MEMBERS;
+ callback.accept(memberPatterns, disjunctiveTargetMembers, keepKind);
+ } else if (keepClassTarget) {
+ callback.accept(
+ Collections.emptyMap(), Collections.emptyList(), TargetKeepKind.CLASS_OR_MEMBERS);
+ }
+
+ if (!classConjunctiveTargetMembers.isEmpty()) {
+ assert !keepClassTarget;
+ for (String targetReference : classConjunctiveTargetMembers) {
+ callback.accept(
+ memberPatterns,
+ Collections.singletonList(targetReference),
+ TargetKeepKind.CLASS_AND_MEMBERS);
+ }
}
}
@@ -262,20 +283,23 @@
targets,
bindings,
new HashMap<>(),
- () -> {
- rules.add(new PgUnconditionalClassRule(metaInfo, options, holder));
- },
- (memberPatterns, targetMembers, classAndMembers) -> {
- // Members are still dependent on the class, so they go to the implicitly dependent rule.
- rules.add(
- new PgDependentMembersRule(
- metaInfo,
- holder,
- options,
- memberPatterns,
- Collections.emptyList(),
- targetMembers,
- classAndMembers));
+ (memberPatterns, targetMembers, targetKeepKind) -> {
+ if (targetKeepKind.equals(TargetKeepKind.JUST_MEMBERS)) {
+ // Members dependent on the class, so they go to the implicitly dependent rule.
+ rules.add(
+ new PgDependentMembersRule(
+ metaInfo,
+ holder,
+ options,
+ memberPatterns,
+ Collections.emptyList(),
+ targetMembers,
+ targetKeepKind));
+ } else {
+ rules.add(
+ new PgUnconditionalRule(
+ metaInfo, holder, options, memberPatterns, targetMembers, targetKeepKind));
+ }
});
}
@@ -288,26 +312,15 @@
KeepOptions options,
Set<String> conditions,
Set<String> targets) {
-
Map<String, KeepMemberPattern> memberPatterns = new HashMap<>();
List<String> conditionMembers = computeConditions(conditions, bindings, memberPatterns);
-
computeTargets(
targets,
bindings,
memberPatterns,
- () ->
+ (ignore, targetMembers, targetKeepKind) ->
rules.add(
- new PgConditionalClassRule(
- metaInfo,
- options,
- conditionHolder,
- targetHolder,
- memberPatterns,
- conditionMembers)),
- (ignore, targetMembers, classAndMembers) ->
- rules.add(
- new PgConditionalMemberRule(
+ new PgConditionalRule(
metaInfo,
options,
conditionHolder,
@@ -315,37 +328,9 @@
memberPatterns,
conditionMembers,
targetMembers,
- classAndMembers)));
+ targetKeepKind)));
}
- // For a conditional and dependent edge (e.g., the condition and target both reference holder X),
- // we can assume the general form of:
- //
- // { X, memberConds } -> { X, memberTargets }
- //
- // First, we assume that if memberConds=={} then X is in the conditions, otherwise the conditions
- // are empty (i.e. always true) and this is not a dependent edge.
- //
- // Without change in meaning we can always assume X in conditions as it either was and if not then
- // the condition on a member implicitly entails a condition on the holder.
- //
- // Next we can split any such edge into two edges:
- //
- // { X, memberConds } -> { X }
- // { X, memberConds } -> { memberTargets }
- //
- // The first edge, if present, gives rise to the rule:
- //
- // -if class X { memberConds } -keep class <1>
- //
- // The second rule only pertains to keeping member targets and those targets are kept as a
- // -keepclassmembers such that they are still conditional on the holder being referenced/live.
- // If the only precondition is the holder, then it can omitted, thus we generate:
- // If memberConds={}:
- // -keepclassmembers class X { memberTargets }
- // else:
- // -if class X { memberConds } -keepclassmembers X { memberTargets }
- //
private static void createDependentRules(
List<PgRule> rules,
Holder holder,
@@ -360,12 +345,8 @@
targets,
bindings,
memberPatterns,
- () ->
- rules.add(
- new PgDependentClassRule(
- metaInfo, holder, options, memberPatterns, conditionMembers)),
- (ignore, targetMembers, classAndMembers) -> {
- List<String> typedTargets = new ArrayList<>(targetMembers.size());
+ (ignore, targetMembers, targetKeepKind) -> {
+ List<String> nonAllMemberTargets = new ArrayList<>(targetMembers.size());
for (String targetMember : targetMembers) {
KeepMemberPattern memberPattern = memberPatterns.get(targetMember);
if (memberPattern.isAllMembers() && conditionMembers.contains(targetMember)) {
@@ -382,7 +363,7 @@
copyWithMethod,
conditionMembers,
Collections.singletonList(targetMember),
- classAndMembers));
+ targetKeepKind));
HashMap<String, KeepMemberPattern> copyWithField = new HashMap<>(memberPatterns);
copyWithField.put(targetMember, KeepFieldPattern.allFields());
rules.add(
@@ -393,22 +374,23 @@
copyWithField,
conditionMembers,
Collections.singletonList(targetMember),
- classAndMembers));
+ targetKeepKind));
} else {
- typedTargets.add(targetMember);
+ nonAllMemberTargets.add(targetMember);
}
}
- if (!typedTargets.isEmpty()) {
- rules.add(
- new PgDependentMembersRule(
- metaInfo,
- holder,
- options,
- memberPatterns,
- conditionMembers,
- typedTargets,
- classAndMembers));
+ if (targetKeepKind.equals(TargetKeepKind.JUST_MEMBERS) && nonAllMemberTargets.isEmpty()) {
+ return;
}
+ rules.add(
+ new PgDependentMembersRule(
+ metaInfo,
+ holder,
+ options,
+ memberPatterns,
+ conditionMembers,
+ nonAllMemberTargets,
+ targetKeepKind));
});
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/PgRule.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/PgRule.java
index c713f53..412a91e 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/PgRule.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/PgRule.java
@@ -15,13 +15,34 @@
import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern;
import com.android.tools.r8.keepanno.keeprules.KeepRuleExtractor.Holder;
import com.android.tools.r8.keepanno.keeprules.RulePrinter.BackReferencePrinter;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
public abstract class PgRule {
+ public enum TargetKeepKind {
+ JUST_MEMBERS(RulePrintingUtils.KEEP_CLASS_MEMBERS),
+ CLASS_OR_MEMBERS(RulePrintingUtils.KEEP),
+ CLASS_AND_MEMBERS(RulePrintingUtils.KEEP_CLASSES_WITH_MEMBERS);
+
+ private final String ruleKind;
+
+ TargetKeepKind(String ruleKind) {
+ this.ruleKind = ruleKind;
+ }
+
+ String getKeepRuleKind() {
+ return ruleKind;
+ }
+ }
+
+ private static void printNonEmptyMembersPatternAsDefaultInitWorkaround(StringBuilder builder) {
+ // If no members is given, compat R8 and legacy full mode will implicitly keep <init>().
+ // Add a keep of finalize which is a library method that would be kept in any case.
+ builder.append(" { void finalize(); }");
+ }
+
private final KeepEdgeMetaInfo metaInfo;
private final KeepOptions options;
@@ -112,63 +133,97 @@
abstract void printTargetMember(StringBuilder builder, String member);
/**
- * Representation of an unconditional rule to keep a class.
+ * Representation of an unconditional rule to keep a class and methods.
*
* <pre>
- * -keep class <holder>
+ * -keep[classeswithmembers] class <holder> [{ <members> }]
* </pre>
*
* and with no dependencies / back-references.
*/
- static class PgUnconditionalClassRule extends PgRule {
- final KeepQualifiedClassNamePattern holderNamePattern;
- final KeepItemPattern holderPattern;
+ static class PgUnconditionalRule extends PgRule {
+ private final KeepQualifiedClassNamePattern holderNamePattern;
+ private final KeepItemPattern holderPattern;
+ private final TargetKeepKind targetKeepKind;
+ private final List<String> targetMembers;
+ private final Map<String, KeepMemberPattern> memberPatterns;
- public PgUnconditionalClassRule(KeepEdgeMetaInfo metaInfo, KeepOptions options, Holder holder) {
+ public PgUnconditionalRule(
+ KeepEdgeMetaInfo metaInfo,
+ Holder holder,
+ KeepOptions options,
+ Map<String, KeepMemberPattern> memberPatterns,
+ List<String> targetMembers,
+ TargetKeepKind targetKeepKind) {
super(metaInfo, options);
+ assert !targetKeepKind.equals(TargetKeepKind.JUST_MEMBERS);
this.holderNamePattern = holder.namePattern;
this.holderPattern = holder.itemPattern;
+ this.targetKeepKind = targetKeepKind;
+ this.memberPatterns = memberPatterns;
+ this.targetMembers = targetMembers;
}
@Override
String getConsequenceKeepType() {
- return RulePrintingUtils.KEEP;
+ return targetKeepKind.getKeepRuleKind();
}
@Override
List<String> getTargetMembers() {
- return Collections.emptyList();
+ return targetMembers;
}
@Override
void printTargetHolder(StringBuilder builder) {
printClassHeader(builder, holderPattern, classReferencePrinter(holderNamePattern));
+ if (getTargetMembers().isEmpty()) {
+ printNonEmptyMembersPatternAsDefaultInitWorkaround(builder);
+ }
}
@Override
void printTargetMember(StringBuilder builder, String memberReference) {
- throw new KeepEdgeException("Unreachable");
+ KeepMemberPattern memberPattern = memberPatterns.get(memberReference);
+ printMemberClause(memberPattern, RulePrinter.withoutBackReferences(builder));
}
}
- abstract static class PgConditionalRuleBase extends PgRule {
+ /**
+ * Representation of conditional rules but without dependencies between condition and target.
+ *
+ * <pre>
+ * -if class <class-condition> [{ <member-conditions> }]
+ * -keepX class <class-target> [{ <member-targets> }]
+ * </pre>
+ *
+ * and with no dependencies / back-references.
+ */
+ static class PgConditionalRule extends PgRule {
+
final KeepItemPattern classCondition;
final KeepItemPattern classTarget;
final Map<String, KeepMemberPattern> memberPatterns;
final List<String> memberConditions;
+ private final List<String> memberTargets;
+ private final TargetKeepKind keepKind;
- public PgConditionalRuleBase(
+ public PgConditionalRule(
KeepEdgeMetaInfo metaInfo,
KeepOptions options,
Holder classCondition,
Holder classTarget,
Map<String, KeepMemberPattern> memberPatterns,
- List<String> memberConditions) {
+ List<String> memberConditions,
+ List<String> memberTargets,
+ TargetKeepKind keepKind) {
super(metaInfo, options);
this.classCondition = classCondition.itemPattern;
this.classTarget = classTarget.itemPattern;
this.memberPatterns = memberPatterns;
this.memberConditions = memberConditions;
+ this.memberTargets = memberTargets;
+ this.keepKind = keepKind;
}
@Override
@@ -195,86 +250,14 @@
@Override
void printTargetHolder(StringBuilder builder) {
printClassHeader(builder, classTarget, this::printClassName);
- }
-
- void printClassName(StringBuilder builder, KeepClassReference clazz) {
- RulePrintingUtils.printClassName(
- clazz.asClassNamePattern(), RulePrinter.withoutBackReferences(builder));
- }
- }
-
- /**
- * Representation of conditional rules but without dependencies between condition and target.
- *
- * <pre>
- * -if class <class-condition> { <member-conditions> }
- * -keep class <class-target>
- * </pre>
- *
- * and with no dependencies / back-references.
- */
- static class PgConditionalClassRule extends PgConditionalRuleBase {
-
- public PgConditionalClassRule(
- KeepEdgeMetaInfo metaInfo,
- KeepOptions options,
- Holder classCondition,
- Holder classTarget,
- Map<String, KeepMemberPattern> memberPatterns,
- List<String> memberConditions) {
- super(metaInfo, options, classCondition, classTarget, memberPatterns, memberConditions);
+ if (getTargetMembers().isEmpty()) {
+ PgRule.printNonEmptyMembersPatternAsDefaultInitWorkaround(builder);
+ }
}
@Override
String getConsequenceKeepType() {
- return RulePrintingUtils.KEEP;
- }
-
- @Override
- List<String> getTargetMembers() {
- return Collections.emptyList();
- }
-
- @Override
- void printTargetMember(StringBuilder builder, String member) {
- throw new KeepEdgeException("Unreachable");
- }
- }
-
- /**
- * Representation of conditional rules but without dependencies between condition and target.
- *
- * <pre>
- * -if class <class-condition> { <member-conditions> }
- * -keepclassmembers class <class-target> { <member-targets> }
- * </pre>
- *
- * and with no dependencies / back-references.
- */
- static class PgConditionalMemberRule extends PgConditionalRuleBase {
-
- private final List<String> memberTargets;
- private final boolean classAndMembers;
-
- public PgConditionalMemberRule(
- KeepEdgeMetaInfo metaInfo,
- KeepOptions options,
- Holder classCondition,
- Holder classTarget,
- Map<String, KeepMemberPattern> memberPatterns,
- List<String> memberConditions,
- List<String> memberTargets,
- boolean classAndMembers) {
- super(metaInfo, options, classCondition, classTarget, memberPatterns, memberConditions);
- this.memberTargets = memberTargets;
- this.classAndMembers = classAndMembers;
- }
-
- @Override
- String getConsequenceKeepType() {
- return classAndMembers
- ? RulePrintingUtils.KEEP_CLASSES_WITH_MEMBERS
- : RulePrintingUtils.KEEP_CLASS_MEMBERS;
+ return keepKind.getKeepRuleKind();
}
@Override
@@ -287,32 +270,74 @@
KeepMemberPattern memberPattern = memberPatterns.get(member);
printMemberClause(memberPattern, RulePrinter.withoutBackReferences(builder));
}
+
+ private void printClassName(StringBuilder builder, KeepClassReference clazz) {
+ RulePrintingUtils.printClassName(
+ clazz.asClassNamePattern(), RulePrinter.withoutBackReferences(builder));
+ }
}
- abstract static class PgDependentRuleBase extends PgRule {
+ /**
+ * Representation of a conditional rule that is match/instance dependent.
+ *
+ * <pre>
+ * -if class <class-pattern> [{ <member-condition>* }]
+ * -keepX class <class-backref> [{ <member-target | member-backref>* }]
+ * </pre>
+ *
+ * or if the only condition is the class itself and targeting members, just:
+ *
+ * <pre>
+ * -keepclassmembers <class-pattern> { <member-target> }
+ * </pre>
+ */
+ static class PgDependentMembersRule extends PgRule {
- final KeepQualifiedClassNamePattern holderNamePattern;
- final KeepItemPattern holderPattern;
- final Map<String, KeepMemberPattern> memberPatterns;
- final List<String> memberConditions;
+ private final KeepQualifiedClassNamePattern holderNamePattern;
+ private final KeepItemPattern holderPattern;
+ private final Map<String, KeepMemberPattern> memberPatterns;
+ private final List<String> memberConditions;
+ private final List<String> memberTargets;
+ private final TargetKeepKind keepKind;
- public PgDependentRuleBase(
+ private int nextBackReferenceNumber = 1;
+ private String holderBackReferencePattern = null;
+ private Map<String, String> membersBackReferencePatterns = new HashMap<>();
+
+ public PgDependentMembersRule(
KeepEdgeMetaInfo metaInfo,
Holder holder,
KeepOptions options,
Map<String, KeepMemberPattern> memberPatterns,
- List<String> memberConditions) {
+ List<String> memberConditions,
+ List<String> memberTargets,
+ TargetKeepKind keepKind) {
super(metaInfo, options);
this.holderNamePattern = holder.namePattern;
this.holderPattern = holder.itemPattern;
this.memberPatterns = memberPatterns;
this.memberConditions = memberConditions;
+ this.memberTargets = memberTargets;
+ this.keepKind = keepKind;
}
- int nextBackReferenceNumber = 1;
+ private int getNextBackReferenceNumber() {
+ return nextBackReferenceNumber++;
+ }
- String holderBackReferencePattern;
- Map<String, String> membersBackReferencePatterns = new HashMap<>();
+ @Override
+ boolean hasCondition() {
+ // We can avoid an if-rule if the condition is simply the class and the target is just
+ // members.
+ boolean canUseDependentRule =
+ memberConditions.isEmpty() && keepKind == TargetKeepKind.JUST_MEMBERS;
+ return !canUseDependentRule;
+ }
+
+ @Override
+ String getConsequenceKeepType() {
+ return keepKind.getKeepRuleKind();
+ }
@Override
List<String> getConditionMembers() {
@@ -320,13 +345,18 @@
}
@Override
+ List<String> getTargetMembers() {
+ return memberTargets;
+ }
+
+ @Override
void printConditionHolder(StringBuilder b) {
printClassHeader(
b,
holderPattern,
(builder, classReference) -> {
BackReferencePrinter printer =
- RulePrinter.withBackReferences(b, () -> nextBackReferenceNumber++);
+ RulePrinter.withBackReferences(b, this::getNextBackReferenceNumber);
RulePrintingUtils.printClassName(holderNamePattern, printer);
holderBackReferencePattern = printer.getBackReference();
});
@@ -336,7 +366,7 @@
void printConditionMember(StringBuilder builder, String member) {
KeepMemberPattern memberPattern = memberPatterns.get(member);
BackReferencePrinter printer =
- RulePrinter.withBackReferences(builder, () -> nextBackReferenceNumber++);
+ RulePrinter.withBackReferences(builder, this::getNextBackReferenceNumber);
printMemberClause(memberPattern, printer);
membersBackReferencePatterns.put(member, printer.getBackReference());
}
@@ -349,107 +379,16 @@
(b, reference) -> {
assert reference.isBindingReference()
|| reference.asClassNamePattern().equals(holderNamePattern);
- b.append(holderBackReferencePattern);
+ if (hasCondition()) {
+ b.append(holderBackReferencePattern);
+ } else {
+ assert holderBackReferencePattern == null;
+ RulePrintingUtils.printClassName(
+ holderNamePattern, RulePrinter.withoutBackReferences(builder));
+ }
});
- }
- }
-
- /**
- * Representation of a conditional class rule that is match/instance dependent.
- *
- * <pre>
- * -if class <class-pattern> { <member-condition>* }
- * -keep class <class-backref>
- * </pre>
- */
- static class PgDependentClassRule extends PgDependentRuleBase {
-
- public PgDependentClassRule(
- KeepEdgeMetaInfo metaInfo,
- Holder holder,
- KeepOptions options,
- Map<String, KeepMemberPattern> memberPatterns,
- List<String> memberConditions) {
- super(metaInfo, holder, options, memberPatterns, memberConditions);
- }
-
- @Override
- String getConsequenceKeepType() {
- return RulePrintingUtils.KEEP;
- }
-
- @Override
- boolean hasCondition() {
- return true;
- }
-
- @Override
- List<String> getTargetMembers() {
- return Collections.emptyList();
- }
-
- @Override
- void printTargetMember(StringBuilder builder, String member) {
- throw new KeepEdgeException("Unreachable");
- }
- }
-
- /**
- * Representation of a conditional member rule that is match/instance dependent.
- *
- * <pre>
- * -if class <class-pattern> { <member-condition>* }
- * -keepclassmembers class <class-backref> { <member-target | member-backref>* }
- * </pre>
- *
- * or if the only condition is the class itself, just:
- *
- * <pre>
- * -keepclassmembers <class-pattern> { <member-target> }
- * </pre>
- */
- static class PgDependentMembersRule extends PgDependentRuleBase {
-
- final List<String> memberTargets;
- final boolean classAndMembers;
-
- public PgDependentMembersRule(
- KeepEdgeMetaInfo metaInfo,
- Holder holder,
- KeepOptions options,
- Map<String, KeepMemberPattern> memberPatterns,
- List<String> memberConditions,
- List<String> memberTargets,
- boolean classAndMembers) {
- super(metaInfo, holder, options, memberPatterns, memberConditions);
- assert !memberTargets.isEmpty();
- this.memberTargets = memberTargets;
- this.classAndMembers = classAndMembers;
- }
-
- @Override
- boolean hasCondition() {
- return !memberConditions.isEmpty() && !classAndMembers;
- }
-
- @Override
- String getConsequenceKeepType() {
- return classAndMembers
- ? RulePrintingUtils.KEEP_CLASSES_WITH_MEMBERS
- : RulePrintingUtils.KEEP_CLASS_MEMBERS;
- }
-
- @Override
- List<String> getTargetMembers() {
- return memberTargets;
- }
-
- @Override
- void printTargetHolder(StringBuilder builder) {
- if (hasCondition()) {
- super.printTargetHolder(builder);
- } else {
- printClassHeader(builder, holderPattern, classReferencePrinter(holderNamePattern));
+ if (getTargetMembers().isEmpty()) {
+ PgRule.printNonEmptyMembersPatternAsDefaultInitWorkaround(builder);
}
}
@@ -466,5 +405,4 @@
printMemberClause(memberPattern, RulePrinter.withoutBackReferences(builder));
}
}
-
}
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarSameClassTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarSameClassTest.java
index e43398a..922a3ce 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarSameClassTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepFooIfBarSameClassTest.java
@@ -84,8 +84,7 @@
assertThat(inspector.clazz(B.class), isPresent());
assertThat(inspector.clazz(B.class).uniqueMethodWithOriginalName("foo"), isAbsent());
assertThat(inspector.clazz(B.class).uniqueMethodWithOriginalName("bar"), isAbsent());
- // TODO(b/248408342): R8 full is keeping the default constructor. Avoid that.
- assertThat(inspector.clazz(B.class).uniqueInstanceInitializer(), isPresent());
+ assertThat(inspector.clazz(B.class).uniqueInstanceInitializer(), isAbsent());
}
@KeepEdge(consequences = {@KeepTarget(classConstant = A.class)})
diff --git a/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java b/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
index b85a41b..dbe4642 100644
--- a/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/ast/KeepEdgeAstTest.java
@@ -47,8 +47,7 @@
.addTarget(KeepTarget.builder().setItemPattern(KeepItemPattern.any()).build())
.build())
.build();
- assertEquals(
- StringUtils.unixLines("-keep class *", "-keepclassmembers class * { *; }"), extract(edge));
+ assertEquals(StringUtils.unixLines("-keep class * { *; }"), extract(edge));
}
@Test
@@ -70,11 +69,7 @@
String allows = String.join(",allow", options);
// The "any" item will be split in two rules, one for the targeted types and one for the
// targeted members.
- assertEquals(
- StringUtils.unixLines(
- "-keep,allow" + allows + " class *",
- "-keepclassmembers,allow" + allows + " class * { *; }"),
- extract(edge));
+ assertEquals(StringUtils.unixLines("-keep,allow" + allows + " class * { *; }"), extract(edge));
}
@Test
@@ -93,9 +88,7 @@
.build();
// Allow is just the ordered list of options.
assertEquals(
- StringUtils.unixLines(
- "-keep,allowshrinking,allowobfuscation class *",
- "-keepclassmembers,allowshrinking,allowobfuscation class * { *; }"),
+ StringUtils.unixLines("-keep,allowshrinking,allowobfuscation class * { *; }"),
extract(edge));
}
@@ -104,7 +97,8 @@
KeepTarget target = target(classItem(CLASS));
KeepConsequences consequences = KeepConsequences.builder().addTarget(target).build();
KeepEdge edge = KeepEdge.builder().setConsequences(consequences).build();
- assertEquals(StringUtils.unixLines("-keep class " + CLASS), extract(edge));
+ assertEquals(
+ StringUtils.unixLines("-keep class " + CLASS + " { void finalize(); }"), extract(edge));
}
@Test
@@ -140,7 +134,9 @@
.setConsequences(KeepConsequences.builder().addTarget(target(classItem(CLASS))).build())
.build();
assertEquals(
- StringUtils.unixLines("-if class " + CLASS + " -keep class " + CLASS), extract(edge));
+ StringUtils.unixLines(
+ "-if class " + CLASS + " -keep class " + CLASS + " { void finalize(); }"),
+ extract(edge));
}
@Test
@@ -163,8 +159,7 @@
.build();
assertEquals(
StringUtils.unixLines(
- "-if class " + CLASS + " -keep class " + CLASS,
- "-keepclassmembers class " + CLASS + " { void <init>(); }"),
+ "-if class " + CLASS + " -keep class " + CLASS + " { void <init>(); }"),
extract(edge));
}