Version 2.1.38
Cherry pick: Support for multiple class, inheritance and member annotations
CL: https://r8-review.googlesource.com/c/r8/+/52010
Cherry pick: Remove ImmutableList.builderWithExpectedSize() use
CL: https://r8-review.googlesource.com/c/r8/+/52040
Bug: 158454684
Change-Id: I961eb124a597b733fe94cacb877bbb2b84725569
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index f4cd7bf..bb3e17f 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "2.1.37";
+ public static final String LABEL = "2.1.38";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationMatchResult.java b/src/main/java/com/android/tools/r8/shaking/AnnotationMatchResult.java
index f5a3bbf..5b97077 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationMatchResult.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationMatchResult.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.shaking;
import com.android.tools.r8.graph.DexAnnotation;
+import java.util.List;
public abstract class AnnotationMatchResult {
@@ -30,14 +31,14 @@
static class ConcreteAnnotationMatchResult extends AnnotationMatchResult {
- private final DexAnnotation matchedAnnotation;
+ private final List<DexAnnotation> matchedAnnotations;
- public ConcreteAnnotationMatchResult(DexAnnotation matchedAnnotation) {
- this.matchedAnnotation = matchedAnnotation;
+ public ConcreteAnnotationMatchResult(List<DexAnnotation> matchedAnnotations) {
+ this.matchedAnnotations = matchedAnnotations;
}
- public DexAnnotation getMatchedAnnotation() {
- return matchedAnnotation;
+ public List<DexAnnotation> getMatchedAnnotations() {
+ return matchedAnnotations;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java b/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
index 4e69cd2..ccda8e3 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInlineRule.java
@@ -39,13 +39,13 @@
origin,
getPosition(),
source,
- classAnnotation,
+ buildClassAnnotations(),
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
memberRules,
@@ -59,13 +59,13 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules,
@@ -74,13 +74,13 @@
origin,
position,
source,
- classAnnotation,
+ classAnnotations,
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ inheritanceAnnotations,
inheritanceClassName,
inheritanceIsExtends,
memberRules);
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java b/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
index 43bfe4b..ee57043 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
@@ -34,9 +34,21 @@
@Override
public ClassMergingRule build() {
- return new ClassMergingRule(origin, getPosition(), source, classAnnotation, classAccessFlags,
- negatedClassAccessFlags, classTypeNegated, classType, classNames, inheritanceAnnotation,
- inheritanceClassName, inheritanceIsExtends, memberRules, type);
+ return new ClassMergingRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules,
+ type);
}
}
@@ -46,20 +58,31 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules,
Type type) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
this.type = type;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ConsequentRootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/ConsequentRootSetBuilder.java
index 8288bde..540db63 100644
--- a/src/main/java/com/android/tools/r8/shaking/ConsequentRootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/ConsequentRootSetBuilder.java
@@ -24,7 +24,7 @@
if (enqueuer.getMode().isInitialTreeShaking()
&& annotationMatchResult.isConcreteAnnotationMatchResult()) {
enqueuer.retainAnnotationForFinalTreeShaking(
- annotationMatchResult.asConcreteAnnotationMatchResult().getMatchedAnnotation());
+ annotationMatchResult.asConcreteAnnotationMatchResult().getMatchedAnnotations());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java
index 6d6f424..bc33778 100644
--- a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java
@@ -27,13 +27,13 @@
origin,
getPosition(),
source,
- classAnnotation,
+ buildClassAnnotations(),
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
memberRules);
@@ -44,13 +44,13 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
@@ -58,13 +58,13 @@
origin,
position,
source,
- classAnnotation,
+ classAnnotations,
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ inheritanceAnnotations,
inheritanceClassName,
inheritanceIsExtends,
memberRules);
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 1cc091d..6878c05 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3334,10 +3334,10 @@
desugaredLambdaImplementationMethods.clear();
}
- void retainAnnotationForFinalTreeShaking(DexAnnotation annotation) {
+ void retainAnnotationForFinalTreeShaking(List<DexAnnotation> annotations) {
assert mode.isInitialTreeShaking();
if (annotationRemoverBuilder != null) {
- annotationRemoverBuilder.retainAnnotation(annotation);
+ annotations.forEach(annotationRemoverBuilder::retainAnnotation);
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleClassPartEquivalence.java b/src/main/java/com/android/tools/r8/shaking/IfRuleClassPartEquivalence.java
index aa37771..527565f 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleClassPartEquivalence.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleClassPartEquivalence.java
@@ -12,7 +12,7 @@
@Override
protected boolean doEquivalent(ProguardIfRule p1, ProguardIfRule p2) {
- if (!Objects.equals(p1.getClassAnnotation(), p2.getClassAnnotation())) {
+ if (!p1.getClassAnnotations().equals(p2.getClassAnnotations())) {
return false;
}
if (!p1.getClassAccessFlags().equals(p2.getClassAccessFlags())
@@ -26,7 +26,7 @@
if (p1.getInheritanceIsExtends() != p2.getInheritanceIsExtends()) {
return false;
}
- if (!Objects.equals(p1.getInheritanceAnnotation(), p2.getInheritanceAnnotation())) {
+ if (!p1.getInheritanceAnnotations().equals(p2.getInheritanceAnnotations())) {
return false;
}
if (!Objects.equals(p1.getInheritanceClassName(), p2.getInheritanceClassName())) {
@@ -40,17 +40,13 @@
@Override
protected int doHash(ProguardIfRule rule) {
- int result = (rule.getClassAnnotation() != null ? rule.getClassAnnotation().hashCode() : 0);
+ int result = rule.getClassAnnotations().hashCode();
result = 3 * result + rule.getClassAccessFlags().hashCode();
result = 3 * result + rule.getNegatedClassAccessFlags().hashCode();
result = 3 * result + (rule.getClassTypeNegated() ? 1 : 0);
result = 3 * result + (rule.getClassType() != null ? rule.getClassType().hashCode() : 0);
result = 3 * result + rule.getClassNames().hashCode();
- result =
- 3 * result
- + (rule.getInheritanceAnnotation() != null
- ? rule.getInheritanceAnnotation().hashCode()
- : 0);
+ result = 3 * result + rule.getInheritanceAnnotations().hashCode();
result =
3 * result
+ (rule.getInheritanceClassName() != null
diff --git a/src/main/java/com/android/tools/r8/shaking/InlineRule.java b/src/main/java/com/android/tools/r8/shaking/InlineRule.java
index ca746a1..41b6b33 100644
--- a/src/main/java/com/android/tools/r8/shaking/InlineRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/InlineRule.java
@@ -41,9 +41,21 @@
@Override
public InlineRule build() {
- return new InlineRule(origin, getPosition(), source, classAnnotation, classAccessFlags,
- negatedClassAccessFlags, classTypeNegated, classType, classNames, inheritanceAnnotation,
- inheritanceClassName, inheritanceIsExtends, memberRules, type);
+ return new InlineRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules,
+ type);
}
}
@@ -53,20 +65,31 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules,
Type type) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
this.type = type;
}
@@ -83,13 +106,13 @@
ProguardCheckDiscardRule.Builder builder = ProguardCheckDiscardRule.builder();
builder.setOrigin(checkDiscardOrigin);
builder.setSource(null);
- builder.setClassAnnotation(getClassAnnotation());
+ builder.addClassAnnotations(getClassAnnotations());
builder.setClassAccessFlags(getClassAccessFlags());
builder.setNegatedClassAccessFlags(getNegatedClassAccessFlags());
builder.setClassTypeNegated(getClassTypeNegated());
builder.setClassType(getClassType());
builder.setClassNames(getClassNames());
- builder.setInheritanceAnnotation(getInheritanceAnnotation());
+ builder.addInheritanceAnnotations(getInheritanceAnnotations());
builder.setInheritanceIsExtends(getInheritanceIsExtends());
builder.setMemberRules(getMemberRules());
return builder.build();
diff --git a/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java b/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java
index dde4631..c26832b 100644
--- a/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/MemberValuePropagationRule.java
@@ -35,9 +35,21 @@
@Override
public MemberValuePropagationRule build() {
- return new MemberValuePropagationRule(origin, getPosition(), source, classAnnotation,
- classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
- inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules, type);
+ return new MemberValuePropagationRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules,
+ type);
}
}
@@ -47,20 +59,31 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules,
Type type) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
this.type = type;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeMayHaveSideEffectsRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeMayHaveSideEffectsRule.java
index 01b7a5e..654bc3e 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeMayHaveSideEffectsRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeMayHaveSideEffectsRule.java
@@ -27,13 +27,13 @@
origin,
getPosition(),
source,
- classAnnotation,
+ buildClassAnnotations(),
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
memberRules);
@@ -44,13 +44,13 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
@@ -58,13 +58,13 @@
origin,
position,
source,
- classAnnotation,
+ classAnnotations,
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ inheritanceAnnotations,
inheritanceClassName,
inheritanceIsExtends,
memberRules);
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeNoSideEffectRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeNoSideEffectRule.java
index 5f8e860..ed151aa 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeNoSideEffectRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeNoSideEffectRule.java
@@ -23,9 +23,20 @@
@Override
public ProguardAssumeNoSideEffectRule build() {
- return new ProguardAssumeNoSideEffectRule(origin, getPosition(), source, classAnnotation,
- classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
- inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
+ return new ProguardAssumeNoSideEffectRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
}
@@ -33,19 +44,30 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
/**
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeValuesRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeValuesRule.java
index 8b8f4dd..97d901e 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeValuesRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeValuesRule.java
@@ -23,9 +23,20 @@
@Override
public ProguardAssumeValuesRule build() {
- return new ProguardAssumeValuesRule(origin, getPosition(), source, classAnnotation,
- classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
- inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
+ return new ProguardAssumeValuesRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
}
@@ -33,19 +44,30 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
/**
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
index 664cb25..82b81a4 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
@@ -23,9 +23,20 @@
@Override
public ProguardCheckDiscardRule build() {
- return new ProguardCheckDiscardRule(origin, getPosition(), source, classAnnotation,
- classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
- inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
+ return new ProguardCheckDiscardRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
}
@@ -33,19 +44,30 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
public static Builder builder() {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
index 9ae4986..2bf270a 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.position.TextRange;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
@@ -22,13 +23,15 @@
protected Position start;
protected Position end;
protected String source;
- protected ProguardTypeMatcher classAnnotation;
+ private final ImmutableList.Builder<ProguardTypeMatcher> classAnnotations =
+ ImmutableList.builder();
protected ProguardAccessFlags classAccessFlags = new ProguardAccessFlags();
protected ProguardAccessFlags negatedClassAccessFlags = new ProguardAccessFlags();
protected boolean classTypeNegated = false;
protected ProguardClassType classType = ProguardClassType.UNSPECIFIED;
protected ProguardClassNameList classNames;
- protected ProguardTypeMatcher inheritanceAnnotation;
+ private final ImmutableList.Builder<ProguardTypeMatcher> inheritanceAnnotations =
+ ImmutableList.builder();
protected ProguardTypeMatcher inheritanceClassName;
protected boolean inheritanceIsExtends = false;
protected List<ProguardMemberRule> memberRules = new LinkedList<>();
@@ -105,12 +108,13 @@
this.inheritanceClassName = inheritanceClassName;
}
- public ProguardTypeMatcher getInheritanceAnnotation() {
- return inheritanceAnnotation;
+ public void addInheritanceAnnotations(List<ProguardTypeMatcher> inheritanceAnnotations) {
+ assert inheritanceAnnotations != null;
+ this.inheritanceAnnotations.addAll(inheritanceAnnotations);
}
- public void setInheritanceAnnotation(ProguardTypeMatcher inheritanceAnnotation) {
- this.inheritanceAnnotation = inheritanceAnnotation;
+ public List<ProguardTypeMatcher> buildInheritanceAnnotations() {
+ return inheritanceAnnotations.build();
}
public ProguardClassNameList getClassNames() {
@@ -155,12 +159,17 @@
negatedClassAccessFlags = flags;
}
- public ProguardTypeMatcher getClassAnnotation() {
- return classAnnotation;
+ public void addClassAnnotation(ProguardTypeMatcher classAnnotation) {
+ classAnnotations.add(classAnnotation);
}
- public void setClassAnnotation(ProguardTypeMatcher classAnnotation) {
- this.classAnnotation = classAnnotation;
+ public void addClassAnnotations(List<ProguardTypeMatcher> classAnnotations) {
+ assert classAnnotations != null;
+ this.classAnnotations.addAll(classAnnotations);
+ }
+
+ public List<ProguardTypeMatcher> buildClassAnnotations() {
+ return classAnnotations.build();
}
protected void matchAllSpecification() {
@@ -172,13 +181,13 @@
private final Origin origin;
private final Position position;
private final String source;
- private final ProguardTypeMatcher classAnnotation;
+ private final List<ProguardTypeMatcher> classAnnotations;
private final ProguardAccessFlags classAccessFlags;
private final ProguardAccessFlags negatedClassAccessFlags;
private final boolean classTypeNegated;
private final ProguardClassType classType;
private final ProguardClassNameList classNames;
- private final ProguardTypeMatcher inheritanceAnnotation;
+ private final List<ProguardTypeMatcher> inheritanceAnnotations;
private final ProguardTypeMatcher inheritanceClassName;
private final boolean inheritanceIsExtends;
private final List<ProguardMemberRule> memberRules;
@@ -187,13 +196,13 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
@@ -202,15 +211,15 @@
assert source != null || origin != Origin.unknown();
this.origin = origin;
this.position = position;
- this.source =source;
- this.classAnnotation = classAnnotation;
+ this.source = source;
+ this.classAnnotations = classAnnotations;
this.classAccessFlags = classAccessFlags;
this.negatedClassAccessFlags = negatedClassAccessFlags;
this.classTypeNegated = classTypeNegated;
this.classType = classType;
assert classType != null;
this.classNames = classNames;
- this.inheritanceAnnotation = inheritanceAnnotation;
+ this.inheritanceAnnotations = inheritanceAnnotations;
this.inheritanceClassName = inheritanceClassName;
this.inheritanceIsExtends = inheritanceIsExtends;
this.memberRules = memberRules;
@@ -248,8 +257,8 @@
return inheritanceClassName;
}
- public ProguardTypeMatcher getInheritanceAnnotation() {
- return inheritanceAnnotation;
+ public List<ProguardTypeMatcher> getInheritanceAnnotations() {
+ return inheritanceAnnotations;
}
public ProguardClassNameList getClassNames() {
@@ -272,8 +281,8 @@
return negatedClassAccessFlags;
}
- public ProguardTypeMatcher getClassAnnotation() {
- return classAnnotation;
+ public List<ProguardTypeMatcher> getClassAnnotations() {
+ return classAnnotations;
}
@Override
@@ -289,7 +298,7 @@
if (inheritanceIsExtends != that.inheritanceIsExtends) {
return false;
}
- if (!Objects.equals(classAnnotation, that.classAnnotation)) {
+ if (!Objects.equals(classAnnotations, that.classAnnotations)) {
return false;
}
if (!classAccessFlags.equals(that.classAccessFlags)) {
@@ -304,7 +313,7 @@
if (!classNames.equals(that.classNames)) {
return false;
}
- if (!Objects.equals(inheritanceAnnotation, that.inheritanceAnnotation)) {
+ if (!Objects.equals(inheritanceAnnotations, that.inheritanceAnnotations)) {
return false;
}
if (!Objects.equals(inheritanceClassName, that.inheritanceClassName)) {
@@ -316,13 +325,13 @@
@Override
public int hashCode() {
// Used multiplier 3 to avoid too much overflow when computing hashCode.
- int result = (classAnnotation != null ? classAnnotation.hashCode() : 0);
+ int result = classAnnotations.hashCode();
result = 3 * result + classAccessFlags.hashCode();
result = 3 * result + negatedClassAccessFlags.hashCode();
result = 3 * result + (classTypeNegated ? 1 : 0);
result = 3 * result + (classType != null ? classType.hashCode() : 0);
result = 3 * result + classNames.hashCode();
- result = 3 * result + (inheritanceAnnotation != null ? inheritanceAnnotation.hashCode() : 0);
+ result = 3 * result + inheritanceAnnotations.hashCode();
result = 3 * result + (inheritanceClassName != null ? inheritanceClassName.hashCode() : 0);
result = 3 * result + (inheritanceIsExtends ? 1 : 0);
result = 3 * result + memberRules.hashCode();
@@ -330,9 +339,9 @@
}
protected StringBuilder append(StringBuilder builder, boolean includeMemberRules) {
+ appendAnnotations(classAnnotations, builder);
boolean needsSpaceBeforeClassType =
- StringUtils.appendNonEmpty(builder, "@", classAnnotation, null)
- | StringUtils.appendNonEmpty(builder, "", classAccessFlags, null)
+ StringUtils.appendNonEmpty(builder, null, classAccessFlags, null)
| StringUtils.appendNonEmpty(
builder, "!", negatedClassAccessFlags.toString().replace(" ", " !"), null);
if (needsSpaceBeforeClassType) {
@@ -345,9 +354,8 @@
builder.append(' ');
classNames.writeTo(builder);
if (hasInheritanceClassName()) {
- builder.append(' ').append(inheritanceIsExtends ? "extends" : "implements");
- StringUtils.appendNonEmpty(builder, "@", inheritanceAnnotation, null);
- builder.append(' ');
+ builder.append(' ').append(inheritanceIsExtends ? "extends" : "implements").append(' ');
+ appendAnnotations(inheritanceAnnotations, builder);
builder.append(inheritanceClassName);
}
if (includeMemberRules && !memberRules.isEmpty()) {
@@ -362,6 +370,18 @@
return builder;
}
+ private static void appendAnnotations(
+ List<ProguardTypeMatcher> annotations, StringBuilder builder) {
+ if (!annotations.isEmpty()) {
+ Iterator<ProguardTypeMatcher> annotationIterator = annotations.iterator();
+ builder.append('@').append(annotationIterator.next());
+ while (annotationIterator.hasNext()) {
+ builder.append(" @").append(annotationIterator.next());
+ }
+ builder.append(' ');
+ }
+ }
+
/**
* Short String representation without member rules.
*/
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index aee4a83..58bbdae 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -897,7 +897,7 @@
ProguardClassSpecification.Builder<C, B> builder,
boolean allowValueSpecification)
throws ProguardRuleParserException {
- parseClassFlagsAndAnnotations(builder);
+ parseClassAnnotationsAndFlags(builder);
parseClassType(builder);
builder.setClassNames(parseClassNames());
parseInheritance(builder);
@@ -965,6 +965,18 @@
}
}
+ private List<ProguardTypeMatcher> parseAnnotationList() throws ProguardRuleParserException {
+ List<ProguardTypeMatcher> annotations = null;
+ ProguardTypeMatcher current;
+ while ((current = parseAnnotation()) != null) {
+ if (annotations == null) {
+ annotations = new ArrayList<>(2);
+ }
+ annotations.add(current);
+ }
+ return annotations != null ? annotations : Collections.emptyList();
+ }
+
private ProguardTypeMatcher parseAnnotation() throws ProguardRuleParserException {
skipWhitespace();
int startPosition = position;
@@ -988,16 +1000,14 @@
return acceptChar('!');
}
- private void parseClassFlagsAndAnnotations(ProguardClassSpecification.Builder builder)
+ private void parseClassAnnotationsAndFlags(ProguardClassSpecification.Builder<?, ?> builder)
throws ProguardRuleParserException {
+ // We allow interleaving the class annotations and class flags for compatibility with
+ // Proguard, although this should not be possible according to the grammar.
while (true) {
- skipWhitespace();
ProguardTypeMatcher annotation = parseAnnotation();
if (annotation != null) {
- // TODO(ager): Should we only allow one annotation? It looks that way from the
- // proguard keep rule description, but that seems like a strange restriction?
- assert builder.getClassAnnotation() == null;
- builder.setClassAnnotation(annotation);
+ builder.addClassAnnotation(annotation);
} else {
int start = position;
ProguardAccessFlags flags =
@@ -1025,7 +1035,7 @@
"Expected [!]interface|@interface|class|enum", origin, getPosition(start));
}
- private void parseClassType(ProguardClassSpecification.Builder builder) {
+ private void parseClassType(ProguardClassSpecification.Builder<?, ?> builder) {
skipWhitespace();
TextPosition start = getPosition();
if (acceptChar('!')) {
@@ -1049,7 +1059,8 @@
}
}
- private void parseInheritance(ProguardClassSpecification.Builder classSpecificationBuilder)
+ private void parseInheritance(
+ ProguardClassSpecification.Builder<?, ?> classSpecificationBuilder)
throws ProguardRuleParserException {
skipWhitespace();
if (acceptString("implements")) {
@@ -1059,7 +1070,7 @@
} else {
return;
}
- classSpecificationBuilder.setInheritanceAnnotation(parseAnnotation());
+ classSpecificationBuilder.addInheritanceAnnotations(parseAnnotationList());
classSpecificationBuilder.setInheritanceClassName(ProguardTypeMatcher.create(parseClassName(),
ClassOrType.CLASS, dexItemFactory));
}
@@ -1084,8 +1095,7 @@
private ProguardMemberRule parseMemberRule(boolean allowValueSpecification)
throws ProguardRuleParserException {
ProguardMemberRule.Builder ruleBuilder = ProguardMemberRule.builder();
- skipWhitespace();
- ruleBuilder.setAnnotation(parseAnnotation());
+ ruleBuilder.setAnnotations(parseAnnotationList());
parseMemberAccessFlags(ruleBuilder);
parseMemberPattern(ruleBuilder, allowValueSpecification);
return ruleBuilder.isValid() ? ruleBuilder.build() : null;
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
index 0e21e66..4a19c6f 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -27,19 +27,30 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
public boolean isUsed() {
@@ -124,17 +135,16 @@
protected Iterable<ProguardWildcard> getWildcards() {
List<ProguardMemberRule> memberRules = getMemberRules();
return Iterables.concat(
- ProguardTypeMatcher.getWildcardsOrEmpty(getClassAnnotation()),
+ ProguardTypeMatcher.getWildcardsOrEmpty(getClassAnnotations()),
ProguardClassNameList.getWildcardsOrEmpty(getClassNames()),
- ProguardTypeMatcher.getWildcardsOrEmpty(getInheritanceAnnotation()),
+ ProguardTypeMatcher.getWildcardsOrEmpty(getInheritanceAnnotations()),
ProguardTypeMatcher.getWildcardsOrEmpty(getInheritanceClassName()),
memberRules != null
? memberRules.stream()
- .map(ProguardMemberRule::getWildcards)
- .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
+ .map(ProguardMemberRule::getWildcards)
+ .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
::iterator
- : Collections::emptyIterator
- );
+ : Collections::emptyIterator);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardIdentifierNameStringRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardIdentifierNameStringRule.java
index 8ff7670..37c75a1 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardIdentifierNameStringRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardIdentifierNameStringRule.java
@@ -22,9 +22,20 @@
@Override
public ProguardIdentifierNameStringRule build() {
- return new ProguardIdentifierNameStringRule(origin, getPosition(), source, classAnnotation,
- classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
- inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
+ return new ProguardIdentifierNameStringRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
}
@@ -32,19 +43,30 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
public static Builder builder() {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
index ba9ec8a..c8e185f 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
@@ -58,13 +58,13 @@
origin,
getPosition(),
source,
- classAnnotation,
+ buildClassAnnotations(),
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
memberRules,
@@ -77,22 +77,34 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules,
ProguardKeepRule subsequentRule,
Set<DexReference> preconditions) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules,
- ProguardKeepRuleType.CONDITIONAL, ProguardKeepRuleModifiers.builder().build());
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules,
+ ProguardKeepRuleType.CONDITIONAL,
+ ProguardKeepRuleModifiers.builder().build());
this.subsequentRule = subsequentRule;
this.preconditions = preconditions;
}
@@ -122,15 +134,13 @@
getOrigin(),
getPosition(),
getSource(),
- getClassAnnotation() == null ? null : getClassAnnotation().materialize(dexItemFactory),
+ ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory),
getClassAccessFlags(),
getNegatedClassAccessFlags(),
getClassTypeNegated(),
getClassType(),
getClassNames().materialize(dexItemFactory),
- getInheritanceAnnotation() == null
- ? null
- : getInheritanceAnnotation().materialize(dexItemFactory),
+ ProguardTypeMatcher.materializeList(getInheritanceAnnotations(), dexItemFactory),
getInheritanceClassName() == null
? null
: getInheritanceClassName().materialize(dexItemFactory),
@@ -149,15 +159,13 @@
neverInlineOrigin,
Position.UNKNOWN,
null,
- getClassAnnotation() == null ? null : getClassAnnotation().materialize(dexItemFactory),
+ ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory),
getClassAccessFlags(),
getNegatedClassAccessFlags(),
getClassTypeNegated(),
getClassType(),
getClassNames().materialize(dexItemFactory),
- getInheritanceAnnotation() == null
- ? null
- : getInheritanceAnnotation().materialize(dexItemFactory),
+ ProguardTypeMatcher.materializeList(getInheritanceAnnotations(), dexItemFactory),
getInheritanceClassName() == null
? null
: getInheritanceClassName().materialize(dexItemFactory),
@@ -196,15 +204,13 @@
neverInlineOrigin,
Position.UNKNOWN,
null,
- getClassAnnotation() == null ? null : getClassAnnotation().materialize(dexItemFactory),
+ ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory),
getClassAccessFlags(),
getNegatedClassAccessFlags(),
getClassTypeNegated(),
getClassType(),
getClassNames().materialize(dexItemFactory),
- getInheritanceAnnotation() == null
- ? null
- : getInheritanceAnnotation().materialize(dexItemFactory),
+ ProguardTypeMatcher.materializeList(getInheritanceAnnotations(), dexItemFactory),
getInheritanceClassName() == null
? null
: getInheritanceClassName().materialize(dexItemFactory),
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRule.java
index 4633882..305c108 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRule.java
@@ -25,9 +25,22 @@
@Override
public ProguardKeepRule build() {
- return new ProguardKeepRule(origin, getPosition(), source, classAnnotation, classAccessFlags,
- negatedClassAccessFlags, classTypeNegated, classType, classNames, inheritanceAnnotation,
- inheritanceClassName, inheritanceIsExtends, memberRules, type, modifiersBuilder.build());
+ return new ProguardKeepRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules,
+ type,
+ modifiersBuilder.build());
}
}
@@ -35,21 +48,34 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules,
ProguardKeepRuleType type,
ProguardKeepRuleModifiers modifiers) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules, type, modifiers);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules,
+ type,
+ modifiers);
}
/**
@@ -64,15 +90,13 @@
getOrigin(),
getPosition(),
getSource(),
- getClassAnnotation() == null ? null : getClassAnnotation().materialize(dexItemFactory),
+ ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory),
getClassAccessFlags(),
getNegatedClassAccessFlags(),
getClassTypeNegated(),
getClassType(),
getClassNames() == null ? null : getClassNames().materialize(dexItemFactory),
- getInheritanceAnnotation() == null
- ? null
- : getInheritanceAnnotation().materialize(dexItemFactory),
+ ProguardTypeMatcher.materializeList(getInheritanceAnnotations(), dexItemFactory),
getInheritanceClassName() == null
? null
: getInheritanceClassName().materialize(dexItemFactory),
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java
index 7455469..b87e5a6 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRuleBase.java
@@ -43,21 +43,32 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules,
ProguardKeepRuleType type,
ProguardKeepRuleModifiers modifiers) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
this.type = type;
this.modifiers = modifiers;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
index 1a894d3..3034f6d 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
@@ -24,7 +24,7 @@
public static class Builder {
- private ProguardTypeMatcher annotation;
+ private List<ProguardTypeMatcher> annotations = Collections.emptyList();
private ProguardAccessFlags accessFlags = new ProguardAccessFlags();
private ProguardAccessFlags negatedAccessFlags = new ProguardAccessFlags();
private ProguardMemberType ruleType;
@@ -35,8 +35,9 @@
private Builder() {}
- public void setAnnotation(ProguardTypeMatcher annotation) {
- this.annotation = annotation;
+ public void setAnnotations(List<ProguardTypeMatcher> annotations) {
+ assert annotations != null;
+ this.annotations = annotations;
}
public ProguardAccessFlags getAccessFlags() {
@@ -91,12 +92,19 @@
public ProguardMemberRule build() {
assert isValid();
- return new ProguardMemberRule(annotation, accessFlags, negatedAccessFlags, ruleType, type,
- name, arguments, returnValue);
+ return new ProguardMemberRule(
+ annotations,
+ accessFlags,
+ negatedAccessFlags,
+ ruleType,
+ type,
+ name,
+ arguments,
+ returnValue);
}
}
- private final ProguardTypeMatcher annotation;
+ private final List<ProguardTypeMatcher> annotations;
private final ProguardAccessFlags accessFlags;
private final ProguardAccessFlags negatedAccessFlags;
private final ProguardMemberType ruleType;
@@ -106,7 +114,7 @@
private final ProguardMemberRuleReturnValue returnValue;
private ProguardMemberRule(
- ProguardTypeMatcher annotation,
+ List<ProguardTypeMatcher> annotations,
ProguardAccessFlags accessFlags,
ProguardAccessFlags negatedAccessFlags,
ProguardMemberType ruleType,
@@ -114,7 +122,7 @@
ProguardNameMatcher name,
List<ProguardTypeMatcher> arguments,
ProguardMemberRuleReturnValue returnValue) {
- this.annotation = annotation;
+ this.annotations = annotations;
this.accessFlags = accessFlags;
this.negatedAccessFlags = negatedAccessFlags;
this.ruleType = ruleType;
@@ -131,8 +139,8 @@
return new Builder();
}
- public ProguardTypeMatcher getAnnotation() {
- return annotation;
+ public List<ProguardTypeMatcher> getAnnotations() {
+ return annotations;
}
public ProguardAccessFlags getAccessFlags() {
@@ -187,7 +195,8 @@
break;
}
// Annotations check.
- return RootSetBuilder.containsAnnotation(annotation, field, matchedAnnotationsConsumer);
+ return RootSetBuilder.containsAllAnnotations(
+ annotations, field, matchedAnnotationsConsumer);
}
case FIELD:
@@ -207,7 +216,8 @@
break;
}
// Annotations check
- return RootSetBuilder.containsAnnotation(annotation, field, matchedAnnotationsConsumer);
+ return RootSetBuilder.containsAllAnnotations(
+ annotations, field, matchedAnnotationsConsumer);
}
case ALL_METHODS:
@@ -241,7 +251,8 @@
break;
}
// Annotations check.
- return RootSetBuilder.containsAnnotation(annotation, method, matchedAnnotationsConsumer);
+ return RootSetBuilder.containsAllAnnotations(
+ annotations, method, matchedAnnotationsConsumer);
}
case METHOD:
@@ -266,7 +277,8 @@
break;
}
// Annotations check.
- if (!RootSetBuilder.containsAnnotation(annotation, method, matchedAnnotationsConsumer)) {
+ if (!RootSetBuilder.containsAllAnnotations(
+ annotations, method, matchedAnnotationsConsumer)) {
return false;
}
// Parameter types check.
@@ -309,21 +321,20 @@
Iterable<ProguardWildcard> getWildcards() {
return Iterables.concat(
- ProguardTypeMatcher.getWildcardsOrEmpty(annotation),
+ ProguardTypeMatcher.getWildcardsOrEmpty(annotations),
ProguardTypeMatcher.getWildcardsOrEmpty(type),
ProguardNameMatcher.getWildcardsOrEmpty(name),
arguments != null
? arguments.stream()
- .map(ProguardTypeMatcher::getWildcards)
- .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
+ .map(ProguardTypeMatcher::getWildcards)
+ .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
::iterator
- : Collections::emptyIterator
- );
+ : Collections::emptyIterator);
}
ProguardMemberRule materialize(DexItemFactory dexItemFactory) {
return new ProguardMemberRule(
- getAnnotation() == null ? null : getAnnotation().materialize(dexItemFactory),
+ ProguardTypeMatcher.materializeList(getAnnotations(), dexItemFactory),
getAccessFlags(),
getNegatedAccessFlags(),
getRuleType(),
@@ -345,7 +356,7 @@
ProguardMemberRule that = (ProguardMemberRule) o;
- if (annotation != null ? !annotation.equals(that.annotation) : that.annotation != null) {
+ if (!annotations.equals(that.annotations)) {
return false;
}
if (!accessFlags.equals(that.accessFlags)) {
@@ -368,7 +379,7 @@
@Override
public int hashCode() {
- int result = annotation != null ? annotation.hashCode() : 0;
+ int result = annotations.hashCode();
result = 31 * result + accessFlags.hashCode();
result = 31 * result + negatedAccessFlags.hashCode();
result = 31 * result + (ruleType != null ? ruleType.hashCode() : 0);
@@ -381,7 +392,9 @@
@Override
public String toString() {
StringBuilder result = new StringBuilder();
- ProguardKeepRule.appendNonEmpty(result, "@", annotation, " ");
+ for (ProguardTypeMatcher annotation : annotations) {
+ ProguardKeepRule.appendNonEmpty(result, "@", annotation, " ");
+ }
ProguardKeepRule.appendNonEmpty(result, null, accessFlags, " ");
ProguardKeepRule
.appendNonEmpty(result, null, negatedAccessFlags.toString().replace(" ", " !"), " ");
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java b/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java
index a4db6a2..19bd876 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java
@@ -36,6 +36,10 @@
TYPE
}
+ public MatchSpecificType asSpecificTypeMatcher() {
+ return null;
+ }
+
// Evaluates this matcher on the given type.
public abstract boolean matches(DexType type);
@@ -59,10 +63,30 @@
return typeMatcher == null ? Collections::emptyIterator : typeMatcher.getWildcards();
}
+ static Iterable<ProguardWildcard> getWildcardsOrEmpty(List<ProguardTypeMatcher> typeMatchers) {
+ List<ProguardWildcard> result = new ArrayList<>();
+ for (ProguardTypeMatcher typeMatcher : typeMatchers) {
+ typeMatcher.getWildcards().forEach(result::add);
+ }
+ return result;
+ }
+
protected ProguardTypeMatcher materialize(DexItemFactory dexItemFactory) {
return this;
}
+ public static List<ProguardTypeMatcher> materializeList(
+ List<ProguardTypeMatcher> matchers, DexItemFactory dexItemFactory) {
+ if (matchers.isEmpty()) {
+ return Collections.emptyList();
+ }
+ ImmutableList.Builder<ProguardTypeMatcher> builder = ImmutableList.builder();
+ for (ProguardTypeMatcher matcher : matchers) {
+ builder.add(matcher.materialize(dexItemFactory));
+ }
+ return builder.build();
+ }
+
@Override
public abstract String toString();
@@ -312,6 +336,11 @@
}
@Override
+ public MatchSpecificType asSpecificTypeMatcher() {
+ return this;
+ }
+
+ @Override
public boolean matches(DexType type) {
return this.type == type;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardWhyAreYouKeepingRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardWhyAreYouKeepingRule.java
index 87200fb..4083ff5 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardWhyAreYouKeepingRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardWhyAreYouKeepingRule.java
@@ -23,9 +23,20 @@
@Override
public ProguardWhyAreYouKeepingRule build() {
- return new ProguardWhyAreYouKeepingRule(origin, getPosition(), source, classAnnotation,
- classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType, classNames,
- inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
+ return new ProguardWhyAreYouKeepingRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
}
@@ -33,19 +44,30 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
- super(origin, position, source, classAnnotation, classAccessFlags, negatedClassAccessFlags,
- classTypeNegated, classType, classNames, inheritanceAnnotation, inheritanceClassName,
- inheritanceIsExtends, memberRules);
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
}
public static Builder builder() {
diff --git a/src/main/java/com/android/tools/r8/shaking/ReprocessClassInitializerRule.java b/src/main/java/com/android/tools/r8/shaking/ReprocessClassInitializerRule.java
index 58e03d9..cfcd1fc 100644
--- a/src/main/java/com/android/tools/r8/shaking/ReprocessClassInitializerRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ReprocessClassInitializerRule.java
@@ -40,13 +40,13 @@
origin,
getPosition(),
source,
- classAnnotation,
+ buildClassAnnotations(),
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
memberRules,
@@ -60,13 +60,13 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules,
@@ -75,13 +75,13 @@
origin,
position,
source,
- classAnnotation,
+ classAnnotations,
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ inheritanceAnnotations,
inheritanceClassName,
inheritanceIsExtends,
memberRules);
diff --git a/src/main/java/com/android/tools/r8/shaking/ReprocessMethodRule.java b/src/main/java/com/android/tools/r8/shaking/ReprocessMethodRule.java
index 8e8e288..2c7d19a 100644
--- a/src/main/java/com/android/tools/r8/shaking/ReprocessMethodRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ReprocessMethodRule.java
@@ -40,13 +40,13 @@
origin,
getPosition(),
source,
- classAnnotation,
+ buildClassAnnotations(),
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
memberRules,
@@ -60,13 +60,13 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules,
@@ -75,13 +75,13 @@
origin,
position,
source,
- classAnnotation,
+ classAnnotations,
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ inheritanceAnnotations,
inheritanceClassName,
inheritanceIsExtends,
memberRules);
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 73171b4..8419104 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -754,7 +754,7 @@
}
static AnnotationMatchResult satisfyAnnotation(ProguardConfigurationRule rule, DexClass clazz) {
- return containsAnnotation(rule.getClassAnnotation(), clazz);
+ return containsAllAnnotations(rule.getClassAnnotations(), clazz);
}
boolean satisfyInheritanceRule(DexClass clazz, ProguardConfigurationRule rule) {
@@ -786,7 +786,7 @@
// annotations of `class`.
if (rule.getInheritanceClassName().matches(clazz.type, appView)) {
AnnotationMatchResult annotationMatchResult =
- containsAnnotation(rule.getInheritanceAnnotation(), clazz);
+ containsAllAnnotations(rule.getInheritanceAnnotations(), clazz);
if (annotationMatchResult != null) {
handleMatchedAnnotation(annotationMatchResult);
return true;
@@ -823,7 +823,7 @@
// annotations of `ifaceClass`.
if (rule.getInheritanceClassName().matches(iface, appView)) {
AnnotationMatchResult annotationMatchResult =
- containsAnnotation(rule.getInheritanceAnnotation(), ifaceClass);
+ containsAllAnnotations(rule.getInheritanceAnnotations(), ifaceClass);
if (annotationMatchResult != null) {
handleMatchedAnnotation(annotationMatchResult);
return true;
@@ -899,17 +899,18 @@
return false;
}
- static AnnotationMatchResult containsAnnotation(
- ProguardTypeMatcher classAnnotation, DexClass clazz) {
- return containsAnnotation(classAnnotation, clazz.annotations());
+ static AnnotationMatchResult containsAllAnnotations(
+ List<ProguardTypeMatcher> annotationMatchers, DexClass clazz) {
+ return containsAllAnnotations(annotationMatchers, clazz.annotations());
}
- static <D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> boolean containsAnnotation(
- ProguardTypeMatcher classAnnotation,
- DexEncodedMember<D, R> member,
- Consumer<AnnotationMatchResult> matchedAnnotationsConsumer) {
+ static <D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
+ boolean containsAllAnnotations(
+ List<ProguardTypeMatcher> annotationMatchers,
+ DexEncodedMember<D, R> member,
+ Consumer<AnnotationMatchResult> matchedAnnotationsConsumer) {
AnnotationMatchResult annotationMatchResult =
- containsAnnotation(classAnnotation, member.annotations());
+ containsAllAnnotations(annotationMatchers, member.annotations());
if (annotationMatchResult != null) {
matchedAnnotationsConsumer.accept(annotationMatchResult);
return true;
@@ -918,7 +919,7 @@
DexEncodedMethod method = member.asDexEncodedMethod();
for (int i = 0; i < method.parameterAnnotationsList.size(); i++) {
annotationMatchResult =
- containsAnnotation(classAnnotation, method.parameterAnnotationsList.get(i));
+ containsAllAnnotations(annotationMatchers, method.parameterAnnotationsList.get(i));
if (annotationMatchResult != null) {
matchedAnnotationsConsumer.accept(annotationMatchResult);
return true;
@@ -928,14 +929,28 @@
return false;
}
- private static AnnotationMatchResult containsAnnotation(
- ProguardTypeMatcher classAnnotation, DexAnnotationSet annotations) {
- if (classAnnotation == null) {
+ private static AnnotationMatchResult containsAllAnnotations(
+ List<ProguardTypeMatcher> annotationMatchers, DexAnnotationSet annotations) {
+ if (annotationMatchers.isEmpty()) {
return AnnotationsIgnoredMatchResult.getInstance();
}
+ List<DexAnnotation> matchedAnnotations = new ArrayList<>();
+ for (ProguardTypeMatcher annotationMatcher : annotationMatchers) {
+ DexAnnotation matchedAnnotation =
+ getFirstAnnotationThatMatches(annotationMatcher, annotations);
+ if (matchedAnnotation == null) {
+ return null;
+ }
+ matchedAnnotations.add(matchedAnnotation);
+ }
+ return new ConcreteAnnotationMatchResult(matchedAnnotations);
+ }
+
+ private static DexAnnotation getFirstAnnotationThatMatches(
+ ProguardTypeMatcher annotationMatcher, DexAnnotationSet annotations) {
for (DexAnnotation annotation : annotations.annotations) {
- if (classAnnotation.matches(annotation.annotation.type)) {
- return new ConcreteAnnotationMatchResult(annotation);
+ if (annotationMatcher.matches(annotation.getAnnotationType())) {
+ return annotation;
}
}
return null;
diff --git a/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java
index 1098bcd..dd537bc 100644
--- a/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java
@@ -27,13 +27,13 @@
origin,
getPosition(),
source,
- classAnnotation,
+ buildClassAnnotations(),
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
memberRules);
@@ -44,13 +44,13 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
@@ -58,13 +58,13 @@
origin,
position,
source,
- classAnnotation,
+ classAnnotations,
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ inheritanceAnnotations,
inheritanceClassName,
inheritanceIsExtends,
memberRules);
diff --git a/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java b/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java
index aa52ca3..0f2f684 100644
--- a/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/WhyAreYouNotInliningRule.java
@@ -27,13 +27,13 @@
origin,
getPosition(),
source,
- classAnnotation,
+ buildClassAnnotations(),
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
memberRules);
@@ -44,13 +44,13 @@
Origin origin,
Position position,
String source,
- ProguardTypeMatcher classAnnotation,
+ List<ProguardTypeMatcher> classAnnotations,
ProguardAccessFlags classAccessFlags,
ProguardAccessFlags negatedClassAccessFlags,
boolean classTypeNegated,
ProguardClassType classType,
ProguardClassNameList classNames,
- ProguardTypeMatcher inheritanceAnnotation,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
List<ProguardMemberRule> memberRules) {
@@ -58,13 +58,13 @@
origin,
position,
source,
- classAnnotation,
+ classAnnotations,
classAccessFlags,
negatedClassAccessFlags,
classTypeNegated,
classType,
classNames,
- inheritanceAnnotation,
+ inheritanceAnnotations,
inheritanceClassName,
inheritanceIsExtends,
memberRules);
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 4cada28..222c6a8 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -5,6 +5,7 @@
import static com.android.tools.r8.DiagnosticsChecker.checkDiagnostics;
import static com.android.tools.r8.shaking.ProguardConfigurationSourceStrings.createConfigurationForTesting;
+import static com.android.tools.r8.utils.BooleanUtils.intValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
@@ -17,6 +18,8 @@
import static org.junit.Assert.fail;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.graph.ClassAccessFlags;
@@ -34,10 +37,12 @@
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
import com.android.tools.r8.utils.KeepingDiagnosticHandler;
+import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
@@ -47,6 +52,8 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -55,6 +62,8 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
class EmptyMainClassForProguardTests {
@@ -62,6 +71,7 @@
}
}
+@RunWith(Parameterized.class)
public class ProguardConfigurationParserTest extends TestBase {
private static final String VALID_PROGUARD_DIR = "src/test/proguard/valid/";
@@ -151,6 +161,13 @@
private List<String> lineSeparators = ImmutableList.of("\n", "\r\n");
private List<Character> quotes = ImmutableList.of('"', '\'');
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public ProguardConfigurationParserTest(TestParameters parameters) {}
+
@Before
public void reset() {
handler = new KeepingDiagnosticHandler();
@@ -187,7 +204,7 @@
}
@Test
- public void parseMultipleNamePatterns() throws Exception {
+ public void parseMultipleNamePatterns() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(MULTIPLE_NAME_PATTERNS_FILE));
@@ -210,7 +227,7 @@
}
@Test
- public void parseNonJavaIdentifiers() throws Exception {
+ public void parseNonJavaIdentifiers() {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
new ProguardConfigurationParser(dexItemFactory, new Reporter());
@@ -250,8 +267,8 @@
assertEquals(0x03, matches);
}
- private void testDontXXX(String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern)
- throws Exception {
+ private void testDontXXX(
+ String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -265,13 +282,13 @@
}
@Test
- public void testDontXXX() throws Exception {
+ public void testDontXXX() {
testDontXXX("warn", ProguardConfiguration::getDontWarnPatterns);
testDontXXX("note", ProguardConfiguration::getDontNotePatterns);
}
private void testDontXXXMultiple(
- String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) throws Exception {
+ String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -288,13 +305,13 @@
}
@Test
- public void testDontWarnMultiple() throws Exception {
+ public void testDontWarnMultiple() {
testDontXXXMultiple("warn", ProguardConfiguration::getDontWarnPatterns);
testDontXXXMultiple("note", ProguardConfiguration::getDontNotePatterns);
}
private void testDontXXXAllExplicitly(
- String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) throws Exception {
+ String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -308,13 +325,13 @@
}
@Test
- public void testDontWarnAllExplicitly() throws Exception {
+ public void testDontWarnAllExplicitly() {
testDontXXXAllExplicitly("warn", ProguardConfiguration::getDontWarnPatterns);
testDontXXXAllExplicitly("note", ProguardConfiguration::getDontNotePatterns);
}
private void testDontXXXAllImplicitly(
- String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) throws Exception {
+ String xxx, Function<ProguardConfiguration, ProguardClassFilter> pattern) {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -328,13 +345,13 @@
}
@Test
- public void testDontWarnAllImplicitly() throws Exception {
+ public void testDontWarnAllImplicitly() {
testDontXXXAllImplicitly("warn", ProguardConfiguration::getDontWarnPatterns);
testDontXXXAllImplicitly("note", ProguardConfiguration::getDontNotePatterns);
}
@Test
- public void parseAccessFlags() throws Exception {
+ public void parseAccessFlags() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(ACCESS_FLAGS_FILE));
@@ -380,7 +397,7 @@
}
@Test
- public void parseWhyAreYouKeeping() throws Exception {
+ public void parseWhyAreYouKeeping() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(WHY_ARE_YOU_KEEPING_FILE));
@@ -395,7 +412,7 @@
}
@Test
- public void parseAssumeNoSideEffects() throws Exception {
+ public void parseAssumeNoSideEffects() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(ASSUME_NO_SIDE_EFFECTS));
@@ -408,7 +425,7 @@
}
@Test
- public void parseAssumeNoSideEffectsWithReturnValue() throws Exception {
+ public void parseAssumeNoSideEffectsWithReturnValue() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(ASSUME_NO_SIDE_EFFECTS_WITH_RETURN_VALUE));
@@ -477,7 +494,7 @@
}
@Test
- public void parseAssumeValuesWithReturnValue() throws Exception {
+ public void parseAssumeValuesWithReturnValue() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(ASSUME_VALUES_WITH_RETURN_VALUE));
@@ -546,7 +563,7 @@
}
@Test
- public void testAdaptClassStrings() throws Exception {
+ public void testAdaptClassStrings() {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -563,7 +580,7 @@
}
@Test
- public void testAdaptClassStringsMultiple() throws Exception {
+ public void testAdaptClassStringsMultiple() {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -584,7 +601,7 @@
}
@Test
- public void testAdaptClassStringsAllExplicitly() throws Exception {
+ public void testAdaptClassStringsAllExplicitly() {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -601,7 +618,7 @@
}
@Test
- public void testAdaptClassStringsAllImplicitly() throws Exception {
+ public void testAdaptClassStringsAllImplicitly() {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
new ProguardConfigurationParser(dexItemFactory, reporter);
@@ -618,7 +635,7 @@
}
@Test
- public void testIdentifierNameString() throws Exception {
+ public void testIdentifierNameString() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
String config1 =
@@ -656,14 +673,22 @@
});
assertEquals(1, identifierNameStrings.get(2).getClassNames().size());
assertEquals("*", identifierNameStrings.get(2).getClassNames().toString());
- identifierNameStrings.get(2).getMemberRules().forEach(memberRule -> {
- assertEquals(ProguardMemberType.ALL, memberRule.getRuleType());
- assertTrue(memberRule.getAnnotation().toString().endsWith("IdentifierNameString"));
- });
+ identifierNameStrings
+ .get(2)
+ .getMemberRules()
+ .forEach(
+ memberRule -> {
+ assertEquals(ProguardMemberType.ALL, memberRule.getRuleType());
+ assertEquals(1, memberRule.getAnnotations().size());
+ assertTrue(
+ ListUtils.first(memberRule.getAnnotations())
+ .toString()
+ .endsWith("IdentifierNameString"));
+ });
}
@Test
- public void parseDontobfuscate() throws Exception {
+ public void parseDontobfuscate() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(DONT_OBFUSCATE));
@@ -673,7 +698,7 @@
}
@Test
- public void parseRepackageClassesEmpty() throws Exception {
+ public void parseRepackageClassesEmpty() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(PACKAGE_OBFUSCATION_1));
@@ -685,7 +710,7 @@
}
@Test
- public void parseRepackageClassesNonEmpty() throws Exception {
+ public void parseRepackageClassesNonEmpty() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(PACKAGE_OBFUSCATION_2));
@@ -697,7 +722,7 @@
}
@Test
- public void parseFlattenPackageHierarchyEmpty() throws Exception {
+ public void parseFlattenPackageHierarchyEmpty() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(PACKAGE_OBFUSCATION_3));
@@ -709,7 +734,7 @@
}
@Test
- public void parseFlattenPackageHierarchyNonEmpty() throws Exception {
+ public void parseFlattenPackageHierarchyNonEmpty() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(PACKAGE_OBFUSCATION_4));
@@ -721,7 +746,7 @@
}
@Test
- public void flattenPackageHierarchyCannotOverrideRepackageClasses() throws Exception {
+ public void flattenPackageHierarchyCannotOverrideRepackageClasses() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
Path path = Paths.get(PACKAGE_OBFUSCATION_5);
@@ -735,7 +760,7 @@
}
@Test
- public void repackageClassesOverridesFlattenPackageHierarchy() throws Exception {
+ public void repackageClassesOverridesFlattenPackageHierarchy() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
Path path = Paths.get(PACKAGE_OBFUSCATION_6);
@@ -749,7 +774,7 @@
}
@Test
- public void parseApplyMapping() throws Exception {
+ public void parseApplyMapping() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(APPLY_MAPPING));
@@ -759,7 +784,7 @@
}
@Test
- public void parseApplyMappingWithoutFile() throws Exception {
+ public void parseApplyMappingWithoutFile() {
Path path = Paths.get(APPLY_MAPPING_WITHOUT_FILE);
try {
ProguardConfigurationParser parser =
@@ -781,7 +806,7 @@
}
@Test
- public void parseIncluding() throws Exception {
+ public void parseIncluding() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(Paths.get(INCLUDING));
@@ -789,7 +814,7 @@
}
@Test
- public void parseInvalidIncluding1() throws IOException {
+ public void parseInvalidIncluding1() {
Path path = Paths.get(INVALID_INCLUDING_1);
try {
new ProguardConfigurationParser(new DexItemFactory(), reporter)
@@ -1442,7 +1467,7 @@
}
@Test
- public void parseKeepParameterNames() throws Exception {
+ public void parseKeepParameterNames() {
try {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
@@ -1458,7 +1483,7 @@
}
@Test
- public void parseKeepParameterNamesWithoutMinification() throws Exception {
+ public void parseKeepParameterNamesWithoutMinification() {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(createConfigurationForTesting(ImmutableList.of(
@@ -1483,7 +1508,7 @@
}
@Test
- public void parseShortLine() throws IOException {
+ public void parseShortLine() {
try {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
@@ -1496,7 +1521,7 @@
}
@Test
- public void parseNoLocals() throws IOException {
+ public void parseNoLocals() {
try {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
@@ -2915,4 +2940,239 @@
parser.parse(proguardConfig);
verifyParserEndsCleanly();
}
+
+ @Test
+ public void parseClassAnnotationsAndFlags() {
+ List<String> configurationContents =
+ ImmutableList.of(
+ // 1 annotation without flags.
+ "-keep @Foo class *",
+ // 1 annotation with public flag.
+ "-keep public @Foo class *",
+ "-keep @Foo public class *",
+ // 1 annotation with public final flags.
+ "-keep public final @Foo class *",
+ "-keep public @Foo final class *",
+ "-keep @Foo public final class *",
+ // 2 annotations without flags.
+ "-keep @Foo @Bar class *",
+ // 2 annotations with public flag.
+ "-keep public @Foo @Bar class *",
+ "-keep @Foo public @Bar class *",
+ "-keep @Foo @Bar public class *",
+ // 2 annotations with public final flags.
+ "-keep public final @Foo @Bar class *",
+ "-keep public @Foo final @Bar class *",
+ "-keep public @Foo @Bar final class *",
+ "-keep @Foo public final @Bar class *",
+ "-keep @Foo public @Bar final class *",
+ "-keep @Foo @Bar public final class *");
+ for (String configurationContent : configurationContents) {
+ DexItemFactory dexItemFactory = new DexItemFactory();
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(dexItemFactory, reporter);
+ parser.parse(createConfigurationForTesting(ImmutableList.of(configurationContent)));
+ verifyParserEndsCleanly();
+
+ ProguardConfiguration configuration = parser.getConfig();
+ assertEquals(1, configuration.getRules().size());
+
+ ProguardKeepRule rule = ListUtils.first(configuration.getRules()).asProguardKeepRule();
+ assertEquals(configurationContent.contains("final"), rule.getClassAccessFlags().isFinal());
+ assertEquals(configurationContent.contains("public"), rule.getClassAccessFlags().isPublic());
+ assertEquals(
+ 1 + intValue(configurationContent.contains("@Bar")), rule.getClassAnnotations().size());
+
+ ProguardTypeMatcher.MatchSpecificType fooAnnotation =
+ rule.getClassAnnotations().get(0).asSpecificTypeMatcher();
+ assertEquals("Foo", fooAnnotation.getSpecificType().toSourceString());
+
+ if (configurationContent.contains("@Bar")) {
+ ProguardTypeMatcher.MatchSpecificType barAnnotation =
+ rule.getClassAnnotations().get(1).asSpecificTypeMatcher();
+ assertEquals("Bar", barAnnotation.getSpecificType().toSourceString());
+ }
+ }
+ }
+
+ @Test
+ public void parseFieldAnnotationsAndFlags() {
+ Map<String, Optional<Class<? extends Exception>>> configurationContents =
+ ImmutableMap.<String, Optional<Class<? extends Exception>>>builder()
+ // 1 annotation without flags.
+ .put("-keep class * { @Foo Type FIELD; }", Optional.empty())
+ // 1 annotation with public flag.
+ .put("-keep class * { public @Foo Type FIELD; }", Optional.of(RuntimeException.class))
+ .put("-keep class * { @Foo public Type FIELD; }", Optional.empty())
+ // 1 annotation with public final flags.
+ .put(
+ "-keep class * { public final @Foo Type FIELD; }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { public @Foo final Type FIELD; }",
+ Optional.of(RuntimeException.class))
+ .put("-keep class * { @Foo public final Type FIELD; }", Optional.empty())
+ //// 2 annotations without flags.
+ .put("-keep class * { @Foo @Bar Type FIELD; }", Optional.empty())
+ //// 2 annotations with public flag.
+ .put(
+ "-keep class * { public @Foo @Bar Type FIELD; }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { @Foo public @Bar Type FIELD; }",
+ Optional.of(RuntimeException.class))
+ .put("-keep class * { @Foo @Bar public Type FIELD; }", Optional.empty())
+ //// 2 annotations with public final flags.
+ .put(
+ "-keep class * { public final @Foo @Bar Type FIELD; }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { public @Foo final @Bar Type FIELD; }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { public @Foo @Bar final Type FIELD; }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { @Foo public final @Bar Type FIELD; }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { @Foo public @Bar final Type FIELD; }",
+ Optional.of(RuntimeException.class))
+ .put("-keep class * { @Foo @Bar public final Type FIELD; }", Optional.empty())
+ .build();
+ configurationContents.forEach(
+ (configurationContent, expectedExceptionClass) -> {
+ DexItemFactory dexItemFactory = new DexItemFactory();
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(dexItemFactory, reporter);
+ try {
+ parser.parse(createConfigurationForTesting(ImmutableList.of(configurationContent)));
+ assertFalse(expectedExceptionClass.isPresent());
+ } catch (Throwable e) {
+ assertTrue(expectedExceptionClass.isPresent());
+ assertEquals(expectedExceptionClass.get(), e.getClass());
+ reset();
+ return;
+ }
+
+ verifyParserEndsCleanly();
+
+ ProguardConfiguration configuration = parser.getConfig();
+ assertEquals(1, configuration.getRules().size());
+
+ ProguardKeepRule rule = ListUtils.first(configuration.getRules()).asProguardKeepRule();
+ assertEquals(1, rule.getMemberRules().size());
+
+ ProguardMemberRule memberRule = ListUtils.first(rule.getMemberRules());
+
+ assertEquals(
+ configurationContent.contains("final"), memberRule.getAccessFlags().isFinal());
+ assertEquals(
+ configurationContent.contains("public"), memberRule.getAccessFlags().isPublic());
+ assertEquals(
+ 1 + intValue(configurationContent.contains("@Bar")),
+ memberRule.getAnnotations().size());
+
+ ProguardTypeMatcher.MatchSpecificType fooAnnotation =
+ memberRule.getAnnotations().get(0).asSpecificTypeMatcher();
+ assertEquals("Foo", fooAnnotation.getSpecificType().toSourceString());
+
+ if (configurationContent.contains("@Bar")) {
+ ProguardTypeMatcher.MatchSpecificType barAnnotation =
+ memberRule.getAnnotations().get(1).asSpecificTypeMatcher();
+ assertEquals("Bar", barAnnotation.getSpecificType().toSourceString());
+ }
+ });
+ }
+
+ @Test
+ public void parseMethodAnnotationsAndFlags() {
+ Map<String, Optional<Class<? extends Exception>>> configurationContents =
+ ImmutableMap.<String, Optional<Class<? extends Exception>>>builder()
+ // 1 annotation without flags.
+ .put("-keep class * { @Foo Type method(); }", Optional.empty())
+ // 1 annotation with public flag.
+ .put(
+ "-keep class * { public @Foo Type method(); }", Optional.of(RuntimeException.class))
+ .put("-keep class * { @Foo public Type method(); }", Optional.empty())
+ // 1 annotation with public final flags.
+ .put(
+ "-keep class * { public final @Foo Type method(); }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { public @Foo final Type method(); }",
+ Optional.of(RuntimeException.class))
+ .put("-keep class * { @Foo public final Type method(); }", Optional.empty())
+ //// 2 annotations without flags.
+ .put("-keep class * { @Foo @Bar Type method(); }", Optional.empty())
+ //// 2 annotations with public flag.
+ .put(
+ "-keep class * { public @Foo @Bar Type method(); }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { @Foo public @Bar Type method(); }",
+ Optional.of(RuntimeException.class))
+ .put("-keep class * { @Foo @Bar public Type method(); }", Optional.empty())
+ //// 2 annotations with public final flags.
+ .put(
+ "-keep class * { public final @Foo @Bar Type method(); }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { public @Foo final @Bar Type method(); }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { public @Foo @Bar final Type method(); }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { @Foo public final @Bar Type method(); }",
+ Optional.of(RuntimeException.class))
+ .put(
+ "-keep class * { @Foo public @Bar final Type method(); }",
+ Optional.of(RuntimeException.class))
+ .put("-keep class * { @Foo @Bar public final Type method(); }", Optional.empty())
+ .build();
+ configurationContents.forEach(
+ (configurationContent, expectedExceptionClass) -> {
+ DexItemFactory dexItemFactory = new DexItemFactory();
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(dexItemFactory, reporter);
+ try {
+ parser.parse(createConfigurationForTesting(ImmutableList.of(configurationContent)));
+ assertFalse(expectedExceptionClass.isPresent());
+ } catch (Throwable e) {
+ assertTrue(expectedExceptionClass.isPresent());
+ assertEquals(expectedExceptionClass.get(), e.getClass());
+ reset();
+ return;
+ }
+
+ verifyParserEndsCleanly();
+
+ ProguardConfiguration configuration = parser.getConfig();
+ assertEquals(1, configuration.getRules().size());
+
+ ProguardKeepRule rule = ListUtils.first(configuration.getRules()).asProguardKeepRule();
+ assertEquals(1, rule.getMemberRules().size());
+
+ ProguardMemberRule memberRule = ListUtils.first(rule.getMemberRules());
+
+ assertEquals(
+ configurationContent.contains("final"), memberRule.getAccessFlags().isFinal());
+ assertEquals(
+ configurationContent.contains("public"), memberRule.getAccessFlags().isPublic());
+ assertEquals(
+ 1 + intValue(configurationContent.contains("@Bar")),
+ memberRule.getAnnotations().size());
+
+ ProguardTypeMatcher.MatchSpecificType fooAnnotation =
+ memberRule.getAnnotations().get(0).asSpecificTypeMatcher();
+ assertEquals("Foo", fooAnnotation.getSpecificType().toSourceString());
+
+ if (configurationContent.contains("@Bar")) {
+ ProguardTypeMatcher.MatchSpecificType barAnnotation =
+ memberRule.getAnnotations().get(1).asSpecificTypeMatcher();
+ assertEquals("Bar", barAnnotation.getSpecificType().toSourceString());
+ }
+ });
+ }
}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleClassAnnotationsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleClassAnnotationsTest.java
new file mode 100644
index 0000000..80dab7c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleClassAnnotationsTest.java
@@ -0,0 +1,102 @@
+// 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.annotations;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class KeepWithMultipleClassAnnotationsTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public KeepWithMultipleClassAnnotationsTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testA() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleClassAnnotationsTest.class)
+ .addKeepRules(
+ "-keep @" + A.class.getTypeName() + " class * {",
+ " public static void main(java.lang.String[]);",
+ "}")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ @Test
+ public void testAB() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleClassAnnotationsTest.class)
+ .addKeepRules(
+ "-keep @" + A.class.getTypeName() + " @" + B.class.getTypeName() + " class * {",
+ " public static void main(java.lang.String[]);",
+ "}")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ @Test
+ public void testABC() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleClassAnnotationsTest.class)
+ .addKeepRules(
+ "-keep @"
+ + A.class.getTypeName()
+ + " @"
+ + B.class.getTypeName()
+ + " @"
+ + C.class.getTypeName()
+ + " class * {",
+ " public static void main(java.lang.String[]);",
+ "}")
+ .allowUnusedProguardConfigurationRules()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(inspector -> assertTrue(inspector.allClasses().isEmpty()));
+ }
+
+ @A
+ @B
+ static class TestClass {
+
+ public static void main(String[] args) {
+ System.out.println("Hello world!");
+ }
+ }
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.TYPE})
+ @interface A {}
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.TYPE})
+ @interface B {}
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.TYPE})
+ @interface C {}
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleInheritanceAnnotationsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleInheritanceAnnotationsTest.java
new file mode 100644
index 0000000..25e610b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleInheritanceAnnotationsTest.java
@@ -0,0 +1,108 @@
+// 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.annotations;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class KeepWithMultipleInheritanceAnnotationsTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public KeepWithMultipleInheritanceAnnotationsTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testA() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleInheritanceAnnotationsTest.class)
+ .addKeepRules(
+ "-keep class * extends @" + A.class.getTypeName() + " * {",
+ " public static void main(java.lang.String[]);",
+ "}")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ @Test
+ public void testAB() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleInheritanceAnnotationsTest.class)
+ .addKeepRules(
+ "-keep class * extends @"
+ + A.class.getTypeName()
+ + " @"
+ + B.class.getTypeName()
+ + " * {",
+ " public static void main(java.lang.String[]);",
+ "}")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ @Test
+ public void testABC() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleInheritanceAnnotationsTest.class)
+ .addKeepRules(
+ "-keep class * extends @"
+ + A.class.getTypeName()
+ + " @"
+ + B.class.getTypeName()
+ + " @"
+ + C.class.getTypeName()
+ + " * {",
+ " public static void main(java.lang.String[]);",
+ "}")
+ .allowUnusedProguardConfigurationRules()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(inspector -> assertTrue(inspector.allClasses().isEmpty()));
+ }
+
+ @A
+ @B
+ static class TestClassBase {}
+
+ static class TestClass extends TestClassBase {
+
+ public static void main(String[] args) {
+ System.out.println("Hello world!");
+ }
+ }
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.TYPE})
+ @interface A {}
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.TYPE})
+ @interface B {}
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.TYPE})
+ @interface C {}
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleMemberAnnotationsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleMemberAnnotationsTest.java
new file mode 100644
index 0000000..cafe2a4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleMemberAnnotationsTest.java
@@ -0,0 +1,106 @@
+// 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.annotations;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class KeepWithMultipleMemberAnnotationsTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public KeepWithMultipleMemberAnnotationsTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testA() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleMemberAnnotationsTest.class)
+ .addKeepRules(
+ "-keepclasseswithmembers class * {",
+ " @" + A.class.getTypeName() + " public static void main(java.lang.String[]);",
+ "}")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ @Test
+ public void testAB() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleMemberAnnotationsTest.class)
+ .addKeepRules(
+ "-keepclasseswithmembers class * {",
+ " @"
+ + A.class.getTypeName()
+ + " @"
+ + B.class.getTypeName()
+ + " public static void main(java.lang.String[]);",
+ "}")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ @Test
+ public void testABC() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleMemberAnnotationsTest.class)
+ .addKeepRules(
+ "-keepclasseswithmembers class * {",
+ " @"
+ + A.class.getTypeName()
+ + " @"
+ + B.class.getTypeName()
+ + " @"
+ + C.class.getTypeName()
+ + " public static void main(java.lang.String[]);",
+ "}")
+ .allowUnusedProguardConfigurationRules()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(inspector -> assertTrue(inspector.allClasses().isEmpty()));
+ }
+
+ static class TestClass {
+
+ @A
+ @B
+ public static void main(String[] args) {
+ System.out.println("Hello world!");
+ }
+ }
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.METHOD})
+ @interface A {}
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.METHOD})
+ @interface B {}
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.METHOD})
+ @interface C {}
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleParameterAnnotationsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleParameterAnnotationsTest.java
new file mode 100644
index 0000000..795574a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/KeepWithMultipleParameterAnnotationsTest.java
@@ -0,0 +1,104 @@
+// 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.annotations;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class KeepWithMultipleParameterAnnotationsTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public KeepWithMultipleParameterAnnotationsTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testA() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleParameterAnnotationsTest.class)
+ .addKeepRules(
+ "-keepclasseswithmembers class * {",
+ " @" + A.class.getTypeName() + " public static void main(java.lang.String[]);",
+ "}")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ @Test
+ public void testAB() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleParameterAnnotationsTest.class)
+ .addKeepRules(
+ "-keepclasseswithmembers class * {",
+ " @"
+ + A.class.getTypeName()
+ + " @"
+ + B.class.getTypeName()
+ + " public static void main(java.lang.String[]);",
+ "}")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ @Test
+ public void testABC() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(KeepWithMultipleParameterAnnotationsTest.class)
+ .addKeepRules(
+ "-keepclasseswithmembers class * {",
+ " @"
+ + A.class.getTypeName()
+ + " @"
+ + B.class.getTypeName()
+ + " @"
+ + C.class.getTypeName()
+ + " public static void main(java.lang.String[]);",
+ "}")
+ .allowUnusedProguardConfigurationRules()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(inspector -> assertTrue(inspector.allClasses().isEmpty()));
+ }
+
+ static class TestClass {
+
+ public static void main(@A @B String[] args) {
+ System.out.println("Hello world!");
+ }
+ }
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.PARAMETER})
+ @interface A {}
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.PARAMETER})
+ @interface B {}
+
+ @Retention(RetentionPolicy.CLASS)
+ @Target({ElementType.PARAMETER})
+ @interface C {}
+}