Merge "Collect wildcards while parsing Proguard configuration contents."
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardAlwaysInlineRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardAlwaysInlineRule.java
index ab8342d..8d4a14b 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardAlwaysInlineRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardAlwaysInlineRule.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import java.util.Set;
+import java.util.List;
public class ProguardAlwaysInlineRule extends ProguardConfigurationRule {
@@ -29,7 +29,7 @@
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules) {
+ List<ProguardMemberRule> memberRules) {
super(classAnnotation, classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType,
classNames, inheritanceAnnotation, 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 736c778..39d0335 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeNoSideEffectRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeNoSideEffectRule.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import java.util.Set;
+import java.util.List;
public class ProguardAssumeNoSideEffectRule extends ProguardConfigurationRule {
@@ -28,7 +28,7 @@
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules) {
+ List<ProguardMemberRule> memberRules) {
super(classAnnotation, classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType,
classNames, inheritanceAnnotation, 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 97cb5c3..0dafb11 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardAssumeValuesRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardAssumeValuesRule.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import java.util.Set;
+import java.util.List;
public class ProguardAssumeValuesRule extends ProguardConfigurationRule {
public static class Builder extends ProguardClassSpecification.Builder {
@@ -27,7 +27,7 @@
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules) {
+ List<ProguardMemberRule> memberRules) {
super(classAnnotation, classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType,
classNames, inheritanceAnnotation, 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 da5bb26..2461732 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardCheckDiscardRule.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import java.util.Set;
+import java.util.List;
public class ProguardCheckDiscardRule extends ProguardConfigurationRule {
@@ -29,7 +29,7 @@
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules) {
+ List<ProguardMemberRule> memberRules) {
super(classAnnotation, classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType,
classNames, inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
index 0a71f43..fd1d305 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
@@ -14,6 +14,7 @@
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
public abstract class ProguardClassNameList {
@@ -74,6 +75,10 @@
public abstract boolean matches(DexType type);
+ protected Iterable<String> getWildcards() {
+ return ImmutableList.of();
+ }
+
public abstract void forEachTypeMatcher(Consumer<ProguardTypeMatcher> consumer);
private static class EmptyClassNameList extends ProguardClassNameList {
@@ -135,6 +140,11 @@
}
@Override
+ protected Iterable<String> getWildcards() {
+ return className.getWildcards();
+ }
+
+ @Override
public void forEachTypeMatcher(Consumer<ProguardTypeMatcher> consumer) {
consumer.accept(className);
}
@@ -180,6 +190,14 @@
}
@Override
+ protected Iterable<String> getWildcards() {
+ return classNames.stream()
+ .map(ProguardTypeMatcher::getWildcards)
+ .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
+ .collect(Collectors.toList());
+ }
+
+ @Override
public void forEachTypeMatcher(Consumer<ProguardTypeMatcher> consumer) {
classNames.forEach(consumer);
}
@@ -230,6 +248,14 @@
}
@Override
+ protected Iterable<String> getWildcards() {
+ return classNames.keySet().stream()
+ .map(ProguardTypeMatcher::getWildcards)
+ .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
+ .collect(Collectors.toList());
+ }
+
+ @Override
public void forEachTypeMatcher(Consumer<ProguardTypeMatcher> consumer) {
classNames.object2BooleanEntrySet().forEach(entry -> consumer.accept(entry.getKey()));
}
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 cb81639..653f0cf 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
@@ -4,10 +4,10 @@
package com.android.tools.r8.shaking;
import com.android.tools.r8.utils.StringUtils;
-import java.util.Collections;
-import java.util.LinkedHashSet;
+import com.google.common.collect.ImmutableList;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Objects;
-import java.util.Set;
public abstract class ProguardClassSpecification {
@@ -22,16 +22,16 @@
protected ProguardTypeMatcher inheritanceAnnotation;
protected ProguardTypeMatcher inheritanceClassName;
protected boolean inheritanceIsExtends = false;
- protected Set<ProguardMemberRule> memberRules = new LinkedHashSet<>();
+ protected List<ProguardMemberRule> memberRules = new LinkedList<>();
protected Builder() {
}
- public Set<ProguardMemberRule> getMemberRules() {
+ public List<ProguardMemberRule> getMemberRules() {
return memberRules;
}
- public void setMemberRules(Set<ProguardMemberRule> memberRules) {
+ public void setMemberRules(List<ProguardMemberRule> memberRules) {
this.memberRules = memberRules;
}
@@ -113,7 +113,7 @@
protected void matchAllSpecification() {
setClassNames(ProguardClassNameList.singletonList(ProguardTypeMatcher.defaultAllMatcher()));
- setMemberRules(Collections.singleton(ProguardMemberRule.defaultKeepAllRule()));
+ setMemberRules(ImmutableList.of(ProguardMemberRule.defaultKeepAllRule()));
}
}
@@ -126,7 +126,7 @@
private final ProguardTypeMatcher inheritanceAnnotation;
private final ProguardTypeMatcher inheritanceClassName;
private final boolean inheritanceIsExtends;
- private final Set<ProguardMemberRule> memberRules;
+ private final List<ProguardMemberRule> memberRules;
protected ProguardClassSpecification(
ProguardTypeMatcher classAnnotation,
@@ -138,7 +138,7 @@
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules) {
+ List<ProguardMemberRule> memberRules) {
this.classAnnotation = classAnnotation;
this.classAccessFlags = classAccessFlags;
this.negatedClassAccessFlags = negatedClassAccessFlags;
@@ -152,7 +152,7 @@
this.memberRules = memberRules;
}
- public Set<ProguardMemberRule> getMemberRules() {
+ public List<ProguardMemberRule> getMemberRules() {
return memberRules;
}
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 9b89374..568ba54 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import static com.android.tools.r8.utils.DescriptorUtils.javaTypeToDescriptor;
+
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
@@ -16,7 +18,6 @@
import com.android.tools.r8.shaking.ProguardConfiguration.Builder;
import com.android.tools.r8.shaking.ProguardTypeMatcher.ClassOrType;
import com.android.tools.r8.shaking.ProguardTypeMatcher.MatchSpecificType;
-import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.IdentifierUtils;
import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
import com.android.tools.r8.utils.LongInterval;
@@ -33,9 +34,12 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class ProguardConfigurationParser {
@@ -511,7 +515,8 @@
// If there are no member rules, a default rule for the parameterless constructor
// applies. So we add that here.
ProguardMemberRule.Builder defaultRuleBuilder = ProguardMemberRule.builder();
- defaultRuleBuilder.setName(Constants.INSTANCE_INITIALIZER_NAME);
+ defaultRuleBuilder.setName(
+ IdentifierPatternWithWildcards.withoutWildcards(Constants.INSTANCE_INITIALIZER_NAME));
defaultRuleBuilder.setRuleType(ProguardMemberType.INIT);
defaultRuleBuilder.setArguments(Collections.emptyList());
keepRuleBuilder.getMemberRules().add(defaultRuleBuilder.build());
@@ -565,10 +570,33 @@
if (acceptString("-keep")) {
ProguardKeepRule subsequentRule = parseKeepRule();
ifRuleBuilder.setSubsequentRule(subsequentRule);
- return ifRuleBuilder.build();
+ ProguardIfRule ifRule = ifRuleBuilder.build();
+ verifyWildcardRange(ifRule.getWildcards());
+ return ifRule;
}
throw reporter.fatalError(new StringDiagnostic(
- "Option -if without a subsequent keep rule.", origin, getPosition(optionStart)));
+ "Expecting '-keep' option after '-if' option.", origin, getPosition(optionStart)));
+ }
+
+ private void verifyWildcardRange(Iterable<String> wildcards) {
+ Pattern backReference = Pattern.compile("<(\\d+)>");
+ int i = 1;
+ Iterator<String> iterator = wildcards.iterator();
+ while (iterator.hasNext()) {
+ String wildcard = iterator.next();
+ Matcher m = backReference.matcher(wildcard);
+ if (m.matches()) {
+ int n = Integer.parseInt(m.group(1));
+ if (i <= n) {
+ throw reporter.fatalError(new StringDiagnostic(
+ "Wildcard <" + n + "> is invalid.", origin, getPosition()));
+ }
+ } else {
+ // Increase the index of wildcards for non-back-reference only
+ // to not allow one back-reference to point to another back-reference
+ i++;
+ }
+ }
}
private void parseClassSpec(
@@ -639,14 +667,16 @@
skipWhitespace();
int startPosition = position;
if (acceptChar('@')) {
- String className = parseClassName();
+ IdentifierPatternWithWildcards identifierPatternWithWildcards = parseClassName();
+ String className = identifierPatternWithWildcards.pattern;
if (className.equals("interface")) {
// Not an annotation after all but a class type. Move position back to start
// so this can be dealt with as a class type instead.
position = startPosition;
return null;
}
- return ProguardTypeMatcher.create(className, ClassOrType.CLASS, dexItemFactory);
+ return ProguardTypeMatcher.create(
+ identifierPatternWithWildcards, ClassOrType.CLASS, dexItemFactory);
}
return null;
}
@@ -815,13 +845,14 @@
ruleBuilder.setRuleType(ProguardMemberType.ALL_FIELDS);
} else if (acceptString("<init>")) {
ruleBuilder.setRuleType(ProguardMemberType.INIT);
- ruleBuilder.setName("<init>");
+ ruleBuilder.setName(IdentifierPatternWithWildcards.withoutWildcards("<init>"));
ruleBuilder.setArguments(parseArgumentList());
} else {
- String first = acceptIdentifierWithBackreference(IdentifierType.ANY);
+ IdentifierPatternWithWildcards first =
+ acceptIdentifierWithBackreference(IdentifierType.ANY);
if (first != null) {
skipWhitespace();
- if (first.equals("*") && hasNextChar(';')) {
+ if (first.pattern.equals("*") && hasNextChar(';')) {
ruleBuilder.setRuleType(ProguardMemberType.ALL);
} else {
if (hasNextChar('(')) {
@@ -829,7 +860,8 @@
ruleBuilder.setName(first);
ruleBuilder.setArguments(parseArgumentList());
} else {
- String second = acceptIdentifierWithBackreference(IdentifierType.ANY);
+ IdentifierPatternWithWildcards second =
+ acceptIdentifierWithBackreference(IdentifierType.ANY);
if (second != null) {
skipWhitespace();
if (hasNextChar('(')) {
@@ -880,7 +912,7 @@
.getTypeMatcher()).type;
DexType fieldClass =
dexItemFactory.createType(
- DescriptorUtils.javaTypeToDescriptor(
+ javaTypeToDescriptor(
qualifiedFieldNameOrInteger.substring(0, lastDotIndex)));
DexString fieldName =
dexItemFactory.createString(
@@ -918,13 +950,16 @@
return arguments;
}
if (acceptString("...")) {
- arguments
- .add(ProguardTypeMatcher.create("...", ClassOrType.TYPE, dexItemFactory));
+ arguments.add(ProguardTypeMatcher.create(
+ IdentifierPatternWithWildcards.withoutWildcards("..."),
+ ClassOrType.TYPE,
+ dexItemFactory));
} else {
- for (String name = parseClassName(); name != null; name =
- acceptChar(',') ? parseClassName() : null) {
- arguments
- .add(ProguardTypeMatcher.create(name, ClassOrType.TYPE, dexItemFactory));
+ for (IdentifierPatternWithWildcards identifierPatternWithWildcards = parseClassName();
+ identifierPatternWithWildcards != null;
+ identifierPatternWithWildcards = acceptChar(',') ? parseClassName() : null) {
+ arguments.add(ProguardTypeMatcher.create(
+ identifierPatternWithWildcards, ClassOrType.TYPE, dexItemFactory));
skipWhitespace();
}
}
@@ -1126,13 +1161,17 @@
return acceptString(CLASS_NAME_PREDICATE);
}
- private String acceptIdentifierWithBackreference(IdentifierType kind) {
+ private IdentifierPatternWithWildcards acceptIdentifierWithBackreference(IdentifierType kind) {
+ ImmutableList.Builder<String> wildcardsCollector = ImmutableList.builder();
+ StringBuilder currentAsterisks = null;
StringBuilder currentBackreference = null;
skipWhitespace();
int start = position;
int end = position;
while (!eof(end)) {
int current = contents.codePointAt(end);
+ // Should not be both in asterisk collecting state and back reference collecting state.
+ assert currentAsterisks == null || currentBackreference == null;
if (currentBackreference != null) {
if (current == '>') {
try {
@@ -1146,29 +1185,55 @@
"Wildcard <" + currentBackreference.toString() + "> is invalid.",
origin, getPosition()));
}
+ wildcardsCollector.add("<" + currentBackreference.toString() + ">");
currentBackreference = null;
+ end += Character.charCount(current);
+ continue;
} else if (('0' <= current && current <= '9')
- // Only collect integer literal for the backreference.
+ // Only collect integer literal for the back reference.
|| (current == '-' && currentBackreference.length() == 0)) {
currentBackreference.append((char) current);
+ end += Character.charCount(current);
+ continue;
} else if (kind == IdentifierType.CLASS_NAME) {
throw reporter.fatalError(new StringDiagnostic(
"Use of generics not allowed for java type.", origin, getPosition()));
} else {
// If not parsing a class name allow identifiers including <'s by canceling the
- // collection of the backreference.
+ // collection of the back reference.
currentBackreference = null;
}
+ } else if (currentAsterisks != null) {
+ if (current == '*') {
+ currentAsterisks.append((char) current);
+ end += Character.charCount(current);
+ continue;
+ } else {
+ wildcardsCollector.add(currentAsterisks.toString());
+ currentAsterisks = null;
+ }
+ }
+ // From now on, neither in asterisk collecting state nor back reference collecting state.
+ assert currentAsterisks == null && currentBackreference == null;
+ if (current == '*') {
+ currentAsterisks = new StringBuilder();
+ currentAsterisks.append((char) current);
+ end += Character.charCount(current);
+ } else if (current == '?' || current == '%') {
+ wildcardsCollector.add(String.valueOf((char) current));
end += Character.charCount(current);
} else if (CLASS_NAME_PREDICATE.test(current) || current == '>') {
end += Character.charCount(current);
} else if (current == '<') {
currentBackreference = new StringBuilder();
- ++end;
+ end += Character.charCount(current);
} else {
break;
}
}
+ if (currentAsterisks != null) {
+ wildcardsCollector.add(currentAsterisks.toString());
+ }
if (kind == IdentifierType.CLASS_NAME && currentBackreference != null) {
// Proguard 6 reports this error message, so try to be compatible.
throw reporter.fatalError(
@@ -1178,7 +1243,9 @@
return null;
}
position = end;
- return contents.substring(start, end);
+ return new IdentifierPatternWithWildcards(
+ contents.substring(start, end),
+ wildcardsCollector.build());
}
private String acceptFieldNameOrIntegerForReturn() {
@@ -1292,8 +1359,9 @@
return name == null ? "" : name;
}
- private String parseClassName() throws ProguardRuleParserException {
- String name = acceptIdentifierWithBackreference(IdentifierType.CLASS_NAME);
+ private IdentifierPatternWithWildcards parseClassName() throws ProguardRuleParserException {
+ IdentifierPatternWithWildcards name =
+ acceptIdentifierWithBackreference(IdentifierType.CLASS_NAME);
if (name == null) {
throw parseError("Class name expected");
}
@@ -1408,4 +1476,22 @@
return position - lineStartPosition + 1 /* column starts at 1 */;
}
}
+
+ static class IdentifierPatternWithWildcards {
+ final String pattern;
+ final List<String> wildcards;
+
+ IdentifierPatternWithWildcards(String pattern, List<String> wildcards) {
+ this.pattern = pattern;
+ this.wildcards = wildcards;
+ }
+
+ static IdentifierPatternWithWildcards withoutWildcards(String pattern) {
+ return new IdentifierPatternWithWildcards(pattern, ImmutableList.of());
+ }
+
+ boolean isMatchAllNames() {
+ return pattern.equals("*");
+ }
+ }
}
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 af1948c..9791def 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -4,7 +4,11 @@
package com.android.tools.r8.shaking;
import com.android.tools.r8.utils.StringUtils;
-import java.util.Set;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
public abstract class ProguardConfigurationRule extends ProguardClassSpecification {
ProguardConfigurationRule(
@@ -17,7 +21,7 @@
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules) {
+ List<ProguardMemberRule> memberRules) {
super(classAnnotation, classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType,
classNames, inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
}
@@ -32,6 +36,25 @@
return false;
}
+ protected Iterable<String> getWildcards() {
+ ProguardTypeMatcher classAnnotation = getClassAnnotation();
+ ProguardTypeMatcher inheritanceAnnotation = getInheritanceAnnotation();
+ ProguardTypeMatcher inheritanceClassName = getInheritanceClassName();
+ List<ProguardMemberRule> memberRules = getMemberRules();
+ return Iterables.concat(
+ classAnnotation != null ? classAnnotation.getWildcards() : ImmutableList.of(),
+ getClassNames().getWildcards(),
+ inheritanceAnnotation != null ? inheritanceAnnotation.getWildcards() : ImmutableList.of(),
+ inheritanceClassName != null ? inheritanceClassName.getWildcards() : ImmutableList.of(),
+ memberRules != null
+ ? memberRules.stream()
+ .map(ProguardMemberRule::getWildcards)
+ .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
+ .collect(Collectors.toList())
+ : ImmutableList.of()
+ );
+ }
+
@Override
public boolean equals(Object o) {
if (!(o instanceof ProguardConfigurationRule)) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
index 5852cd9..400422f 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.shaking.ProguardConfigurationParser.IdentifierPatternWithWildcards;
import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.List;
@@ -30,7 +31,7 @@
if (clazz.hasDefaultInitializer()) {
ProguardMemberRule.Builder memberRuleBuilder = ProguardMemberRule.builder();
memberRuleBuilder.setRuleType(ProguardMemberType.INIT);
- memberRuleBuilder.setName("<init>");
+ memberRuleBuilder.setName(IdentifierPatternWithWildcards.withoutWildcards("<init>"));
memberRuleBuilder.setArguments(ImmutableList.of());
builder.getMemberRules().add(memberRuleBuilder.build());
}
@@ -54,7 +55,8 @@
ProguardMemberRule.Builder memberRuleBuilder = ProguardMemberRule.builder();
memberRuleBuilder.setRuleType(ProguardMemberType.FIELD);
memberRuleBuilder.getAccessFlags().setFlags(field.accessFlags);
- memberRuleBuilder.setName(field.field.name.toString());
+ memberRuleBuilder.setName(
+ IdentifierPatternWithWildcards.withoutWildcards(field.field.name.toString()));
memberRuleBuilder.setTypeMatcher(ProguardTypeMatcher.create(field.field.type));
builder.getMemberRules().add(memberRuleBuilder.build());
return builder.build();
@@ -77,7 +79,8 @@
ProguardMemberRule.Builder memberRuleBuilder = ProguardMemberRule.builder();
memberRuleBuilder.setRuleType(ProguardMemberType.METHOD);
memberRuleBuilder.getAccessFlags().setFlags(method.accessFlags);
- memberRuleBuilder.setName(method.method.name.toString());
+ memberRuleBuilder.setName(
+ IdentifierPatternWithWildcards.withoutWildcards(method.method.name.toString()));
memberRuleBuilder.setTypeMatcher(ProguardTypeMatcher.create(method.method.proto.returnType));
List<ProguardTypeMatcher> arguments = Arrays.stream(method.method.proto.parameters.values)
.map(ProguardTypeMatcher::create)
@@ -96,13 +99,15 @@
DexField field = (DexField) item;
holderType = field.getHolder();
memberRuleBuilder.setRuleType(ProguardMemberType.FIELD);
- memberRuleBuilder.setName(field.name.toString());
+ memberRuleBuilder.setName(
+ IdentifierPatternWithWildcards.withoutWildcards(field.name.toString()));
memberRuleBuilder.setTypeMatcher(ProguardTypeMatcher.create(field.type));
} else {
DexMethod method = (DexMethod) item;
holderType = method.getHolder();
memberRuleBuilder.setRuleType(ProguardMemberType.METHOD);
- memberRuleBuilder.setName(method.name.toString());
+ memberRuleBuilder.setName(
+ IdentifierPatternWithWildcards.withoutWildcards(method.name.toString()));
memberRuleBuilder.setTypeMatcher(ProguardTypeMatcher.create(method.proto.returnType));
List<ProguardTypeMatcher> arguments = Arrays.stream(method.proto.parameters.values)
.map(ProguardTypeMatcher::create)
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 f0d7c63..07ffd85 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardIdentifierNameStringRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardIdentifierNameStringRule.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import java.util.Set;
+import java.util.List;
public class ProguardIdentifierNameStringRule extends ProguardConfigurationRule {
@@ -28,7 +28,7 @@
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules) {
+ List<ProguardMemberRule> memberRules) {
super(classAnnotation, classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType,
classNames, inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
}
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 9659954..67a0572 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
@@ -3,7 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import java.util.Set;
+import com.google.common.collect.Iterables;
+import java.util.List;
public class ProguardIfRule extends ProguardKeepRule {
@@ -32,7 +33,7 @@
ProguardClassType classType, ProguardClassNameList classNames,
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName, boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules,
+ List<ProguardMemberRule> memberRules,
ProguardKeepRule subsequentRule) {
super(classAnnotation, classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType,
classNames, inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules,
@@ -45,6 +46,11 @@
}
@Override
+ protected Iterable<String> getWildcards() {
+ return Iterables.concat(super.getWildcards(), subsequentRule.getWildcards());
+ }
+
+ @Override
public boolean equals(Object o) {
if (!(o instanceof ProguardIfRule)) {
return false;
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardKeepPackageNamesRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardKeepPackageNamesRule.java
index c4731c6..66fdd50 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardKeepPackageNamesRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardKeepPackageNamesRule.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import java.util.Set;
+import java.util.List;
public class ProguardKeepPackageNamesRule extends ProguardConfigurationRule {
@@ -29,7 +29,7 @@
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules) {
+ List<ProguardMemberRule> memberRules) {
super(classAnnotation, classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType,
classNames, inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
}
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 d3d6705..8756f1a 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardKeepRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardKeepRule.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import java.util.Set;
+import java.util.List;
import java.util.function.Consumer;
public class ProguardKeepRule extends ProguardConfigurationRule {
@@ -11,8 +11,8 @@
public static class Builder extends ProguardClassSpecification.Builder {
private ProguardKeepRuleType type;
- private final ProguardKeepRuleModifiers.Builder modifiersBuilder
- = ProguardKeepRuleModifiers.builder();
+ private final ProguardKeepRuleModifiers.Builder modifiersBuilder =
+ ProguardKeepRuleModifiers.builder();
protected Builder() {}
@@ -44,7 +44,7 @@
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules,
+ List<ProguardMemberRule> memberRules,
ProguardKeepRuleType type,
ProguardKeepRuleModifiers modifiers) {
super(classAnnotation, classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType,
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 5e1293f..1e089a9 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRule.java
@@ -7,9 +7,14 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.shaking.ProguardConfigurationParser.IdentifierPatternWithWildcards;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
public class ProguardMemberRule {
@@ -19,8 +24,8 @@
private ProguardAccessFlags accessFlags = new ProguardAccessFlags();
private ProguardAccessFlags negatedAccessFlags = new ProguardAccessFlags();
private ProguardMemberType ruleType;
- private ProguardNameMatcher name;
private ProguardTypeMatcher type;
+ private ProguardNameMatcher name;
private List<ProguardTypeMatcher> arguments;
private ProguardMemberRuleReturnValue returnValue;
@@ -50,10 +55,6 @@
this.ruleType = ruleType;
}
- public void setName(String name) {
- this.name = ProguardNameMatcher.create(name);
- }
-
public ProguardTypeMatcher getTypeMatcher() {
return type;
}
@@ -62,6 +63,10 @@
this.type = type;
}
+ public void setName(IdentifierPatternWithWildcards identifierPatternWithWildcards) {
+ this.name = ProguardNameMatcher.create(identifierPatternWithWildcards);
+ }
+
public void setArguments(List<ProguardTypeMatcher> arguments) {
this.arguments = arguments;
}
@@ -76,8 +81,8 @@
public ProguardMemberRule build() {
assert isValid();
- return new ProguardMemberRule(annotation, accessFlags, negatedAccessFlags, ruleType, name,
- type, arguments, returnValue);
+ return new ProguardMemberRule(annotation, accessFlags, negatedAccessFlags, ruleType, type,
+ name, arguments, returnValue);
}
}
@@ -85,8 +90,8 @@
private final ProguardAccessFlags accessFlags;
private final ProguardAccessFlags negatedAccessFlags;
private final ProguardMemberType ruleType;
- private final ProguardNameMatcher name;
private final ProguardTypeMatcher type;
+ private final ProguardNameMatcher name;
private final List<ProguardTypeMatcher> arguments;
private final ProguardMemberRuleReturnValue returnValue;
@@ -95,17 +100,17 @@
ProguardAccessFlags accessFlags,
ProguardAccessFlags negatedAccessFlags,
ProguardMemberType ruleType,
- ProguardNameMatcher name,
ProguardTypeMatcher type,
+ ProguardNameMatcher name,
List<ProguardTypeMatcher> arguments,
ProguardMemberRuleReturnValue returnValue) {
this.annotation = annotation;
this.accessFlags = accessFlags;
this.negatedAccessFlags = negatedAccessFlags;
this.ruleType = ruleType;
- this.name = name;
this.type = type;
- this.arguments = arguments != null ? ImmutableList.copyOf(arguments) : null;
+ this.name = name;
+ this.arguments = arguments != null ? Collections.unmodifiableList(arguments) : null;
this.returnValue = returnValue;
}
@@ -132,14 +137,14 @@
return ruleType;
}
- public ProguardNameMatcher getName() {
- return name;
- }
-
public ProguardTypeMatcher getType() {
return type;
}
+ public ProguardNameMatcher getName() {
+ return name;
+ }
+
public List<ProguardTypeMatcher> getArguments() {
return arguments;
}
@@ -261,6 +266,20 @@
return false;
}
+ Iterable<String> getWildcards() {
+ return Iterables.concat(
+ annotation != null ? annotation.getWildcards() : ImmutableList.of(),
+ type != null ? type.getWildcards() : ImmutableList.of(),
+ name != null ? name.getWildcards() : ImmutableList.of(),
+ arguments != null
+ ? arguments.stream()
+ .map(ProguardTypeMatcher::getWildcards)
+ .flatMap(it -> StreamSupport.stream(it.spliterator(), false))
+ .collect(Collectors.toList())
+ : ImmutableList.of()
+ );
+ }
+
@Override
public boolean equals(Object o) {
if (!(o instanceof ProguardMemberRule)) {
@@ -296,8 +315,8 @@
result = 31 * result + accessFlags.hashCode();
result = 31 * result + negatedAccessFlags.hashCode();
result = 31 * result + (ruleType != null ? ruleType.hashCode() : 0);
- result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (type != null ? type.hashCode() : 0);
+ result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (arguments != null ? arguments.hashCode() : 0);
return result;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardNameMatcher.java b/src/main/java/com/android/tools/r8/shaking/ProguardNameMatcher.java
index 9286d0a..b8f583d 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardNameMatcher.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardNameMatcher.java
@@ -3,21 +3,25 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import com.android.tools.r8.shaking.ProguardConfigurationParser.IdentifierPatternWithWildcards;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+
public abstract class ProguardNameMatcher {
private static final ProguardNameMatcher MATCH_ALL_NAMES = new MatchAllNames();
private ProguardNameMatcher() {
-
}
- public static ProguardNameMatcher create(String pattern) {
- if (pattern.equals("*")) {
+ public static ProguardNameMatcher create(
+ IdentifierPatternWithWildcards identifierPatternWithWildcards) {
+ if (identifierPatternWithWildcards.isMatchAllNames()) {
return MATCH_ALL_NAMES;
- } else if (pattern.contains("*") || pattern.contains("?")) {
- return new MatchNamePattern(pattern);
+ } else if (identifierPatternWithWildcards.wildcards.isEmpty()) {
+ return new MatchSpecificName(identifierPatternWithWildcards.pattern);
} else {
- return new MatchSpecificName(pattern);
+ return new MatchNamePattern(identifierPatternWithWildcards);
}
}
@@ -63,6 +67,10 @@
public abstract boolean matches(String name);
+ protected Iterable<String> getWildcards() {
+ return ImmutableList.of();
+ }
+
private static class MatchAllNames extends ProguardNameMatcher {
@Override
@@ -71,6 +79,11 @@
}
@Override
+ protected Iterable<String> getWildcards() {
+ return ImmutableList.of("*");
+ }
+
+ @Override
public String toString() {
return "*";
}
@@ -79,9 +92,11 @@
private static class MatchNamePattern extends ProguardNameMatcher {
private final String pattern;
+ private final List<String> wildcards;
- MatchNamePattern(String pattern) {
- this.pattern = pattern;
+ MatchNamePattern(IdentifierPatternWithWildcards identifierPatternWithWildcards) {
+ this.pattern = identifierPatternWithWildcards.pattern;
+ this.wildcards = identifierPatternWithWildcards.wildcards;
}
@Override
@@ -90,6 +105,11 @@
}
@Override
+ protected Iterable<String> getWildcards() {
+ return wildcards;
+ }
+
+ @Override
public String toString() {
return pattern;
}
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 809278f..51d11bb 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardTypeMatcher.java
@@ -3,9 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import static com.android.tools.r8.utils.DescriptorUtils.javaTypeToDescriptor;
+
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.shaking.ProguardConfigurationParser.IdentifierPatternWithWildcards;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
public abstract class ProguardTypeMatcher {
@@ -25,6 +29,10 @@
public abstract boolean matches(DexType type);
+ protected Iterable<String> getWildcards() {
+ return ImmutableList.of();
+ }
+
@Override
public abstract String toString();
@@ -32,12 +40,14 @@
return false;
}
- public static ProguardTypeMatcher create(String pattern, ClassOrType kind,
+ public static ProguardTypeMatcher create(
+ IdentifierPatternWithWildcards identifierPatternWithWildcards,
+ ClassOrType kind,
DexItemFactory dexItemFactory) {
- if (pattern == null) {
+ if (identifierPatternWithWildcards == null || identifierPatternWithWildcards.pattern == null) {
return null;
}
- switch (pattern) {
+ switch (identifierPatternWithWildcards.pattern) {
case MATCH_ALL_PATTERN:
return MatchAllTypes.MATCH_ALL_TYPES;
case MATCH_ANY_ARG_SEQUENCE_PATTERN:
@@ -49,11 +59,11 @@
case MATCH_BASIC_PATTERN:
return MatchBasicTypes.MATCH_BASIC_TYPES;
default:
- if (!pattern.contains("*") && !pattern.contains("%") && !pattern.contains("?")) {
- return new MatchSpecificType(
- dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(pattern)));
+ if (identifierPatternWithWildcards.wildcards.isEmpty()) {
+ return new MatchSpecificType(dexItemFactory.createType(
+ javaTypeToDescriptor(identifierPatternWithWildcards.pattern)));
}
- return new MatchTypePattern(pattern, kind);
+ return new MatchTypePattern(identifierPatternWithWildcards, kind);
}
}
@@ -85,6 +95,11 @@
}
@Override
+ protected Iterable<String> getWildcards() {
+ return ImmutableList.of(MATCH_ALL_PATTERN);
+ }
+
+ @Override
public String toString() {
return MATCH_ALL_PATTERN;
}
@@ -150,6 +165,11 @@
}
@Override
+ protected Iterable<String> getWildcards() {
+ return ImmutableList.of(pattern);
+ }
+
+ @Override
public String toString() {
return pattern;
}
@@ -175,6 +195,11 @@
}
@Override
+ protected Iterable<String> getWildcards() {
+ return ImmutableList.of(MATCH_BASIC_PATTERN);
+ }
+
+ @Override
public String toString() {
return MATCH_BASIC_PATTERN;
}
@@ -230,10 +255,13 @@
private static class MatchTypePattern extends ProguardTypeMatcher {
private final String pattern;
+ private final List<String> wildcards;
private final ClassOrType kind;
- private MatchTypePattern(String pattern, ClassOrType kind) {
- this.pattern = pattern;
+ private MatchTypePattern(
+ IdentifierPatternWithWildcards identifierPatternWithWildcards, ClassOrType kind) {
+ this.pattern = identifierPatternWithWildcards.pattern;
+ this.wildcards = identifierPatternWithWildcards.wildcards;
this.kind = kind;
}
@@ -244,6 +272,11 @@
return matchClassOrTypeNameImpl(pattern, 0, typeName, 0, kind);
}
+ @Override
+ protected Iterable<String> getWildcards() {
+ return wildcards;
+ }
+
private static boolean matchClassOrTypeNameImpl(
String pattern, int patternIndex, String className, int nameIndex, ClassOrType kind) {
for (int i = patternIndex; i < pattern.length(); i++) {
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 ef83926..73b5538 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardWhyAreYouKeepingRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardWhyAreYouKeepingRule.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import java.util.Set;
+import java.util.List;
public class ProguardWhyAreYouKeepingRule extends ProguardConfigurationRule {
@@ -29,7 +29,7 @@
ProguardTypeMatcher inheritanceAnnotation,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- Set<ProguardMemberRule> memberRules) {
+ List<ProguardMemberRule> memberRules) {
super(classAnnotation, classAccessFlags, negatedClassAccessFlags, classTypeNegated, classType,
classNames, inheritanceAnnotation, inheritanceClassName, inheritanceIsExtends, memberRules);
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 43a443e..e978b86 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -1183,6 +1183,11 @@
return result.stdout;
}
+ public static ProcessResult runProguardRaw(Path inJar, Path outJar, List<Path> config, Path map)
+ throws IOException {
+ return runProguardRaw(getProguardScript(), inJar, outJar, config, map);
+ }
+
public static ProcessResult runProguardRaw(Path inJar, Path outJar, Path config, Path map)
throws IOException {
return runProguardRaw(getProguardScript(), inJar, outJar, ImmutableList.of(config), map);
@@ -1204,6 +1209,11 @@
}
public static ProcessResult runProguard6Raw(
+ Path inJar, Path outJar, List<Path> config, Path map) throws IOException {
+ return runProguardRaw(getProguard6Script(), inJar, outJar, config, map);
+ }
+
+ public static ProcessResult runProguard6Raw(
Path inJar, Path outJar, Path lib, Path config, Path map) throws IOException {
return runProguardRaw(getProguard6Script(), inJar, outJar, lib, ImmutableList.of(config), map);
}
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 89a7291..2dfe42e 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -30,6 +30,7 @@
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.position.TextPosition;
import com.android.tools.r8.position.TextRange;
+import com.android.tools.r8.shaking.ProguardConfigurationParser.IdentifierPatternWithWildcards;
import com.android.tools.r8.utils.AbortException;
import com.android.tools.r8.utils.DefaultDiagnosticsHandler;
import com.android.tools.r8.utils.DexInspector;
@@ -46,7 +47,6 @@
import java.util.List;
import java.util.function.Function;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
class EmptyMainClassForProguardTests {
@@ -205,7 +205,8 @@
assertEquals("some.library.Class", rule.getInheritanceClassName().toString());
ProguardMemberRule memberRule = rule.getMemberRules().iterator().next();
assertTrue(memberRule.getAccessFlags().isProtected());
- assertEquals(ProguardNameMatcher.create("getContents"), memberRule.getName());
+ assertEquals(ProguardNameMatcher.create(
+ IdentifierPatternWithWildcards.withoutWildcards("getContents")), memberRule.getName());
assertEquals("java.lang.Object[][]", memberRule.getType().toString());
assertEquals(ProguardMemberType.METHOD, memberRule.getRuleType());
assertEquals(0, memberRule.getArguments().size());
@@ -1410,10 +1411,12 @@
assertEquals(ProguardKeepRuleType.KEEP, if0.subsequentRule.getType());
assertEquals("**$D<2>", if0.subsequentRule.getClassNames().toString());
// TODO(b/73800755): Test <2> matches with expected wildcard: ** after '$R'.
+
+ verifyWithProguard6(proguardConfig);
}
@Test
- public void parse_if_nthWildcard_notNumber() throws Exception {
+ public void parse_if_nthWildcard_notNumber_literalN() throws Exception {
Path proguardConfig = writeTextToTempFile(
"-if class **$R**",
"-keep class **D<n>"
@@ -1424,7 +1427,6 @@
parser.parse(proguardConfig);
fail();
} catch (AbortException e) {
- System.out.println(handler.errors.get(0));
checkDiagnostic(handler.errors, proguardConfig, 2, 13,
"Use of generics not allowed for java type");
}
@@ -1432,6 +1434,76 @@
}
@Test
+ public void parse_if_nthWildcard_notNumber_asterisk_inClassName() throws Exception {
+ Path proguardConfig = writeTextToTempFile(
+ "-if class **$R**",
+ "-keep class **D<*>"
+ );
+ try {
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(proguardConfig);
+ fail();
+ } catch (AbortException e) {
+ checkDiagnostic(handler.errors, proguardConfig, 2, 13,
+ "Use of generics not allowed for java type");
+ }
+ verifyFailWithProguard6(proguardConfig, "Use of generics not allowed for java type");
+ }
+
+ @Test
+ public void parse_if_nthWildcard_notNumber_asterisk_inMemberName() throws Exception {
+ Path proguardConfig = writeTextToTempFile(
+ "-if class **$R**",
+ "-keep class **D<2> {",
+ " int id<*>;",
+ "}"
+ );
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(proguardConfig);
+ verifyParserEndsCleanly();
+
+ verifyWithProguard6(proguardConfig);
+ }
+
+ @Test
+ public void parse_if_nestedAngularBrackets_inMemberName() throws Exception {
+ Path proguardConfig = writeTextToTempFile(
+ "-if class **$R**",
+ "-keep class **D<2> {",
+ " int id<<*>>;",
+ "}"
+ );
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(proguardConfig);
+ verifyParserEndsCleanly();
+
+ verifyWithProguard6(proguardConfig);
+ }
+
+ @Test
+ public void parse_if_nestedAngularBrackets_outOfRange() throws Exception {
+ Path proguardConfig = writeTextToTempFile(
+ "-if class **$R**",
+ "-keep class **D<2> {",
+ " int id<<4>>;", // There are 3 previous referable wildcards in this rule.
+ "}"
+ );
+ try {
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(proguardConfig);
+ fail();
+ } catch (AbortException e) {
+ checkDiagnostic(handler.errors, proguardConfig, 4, 2,
+ "Wildcard", "<4>", "invalid");
+ }
+ verifyFailWithProguard6(proguardConfig, "Invalid reference to wildcard (4,");
+ }
+
+ @Test
public void parse_if_nthWildcard_outOfRange_tooSmall() throws Exception {
Path proguardConfig = writeTextToTempFile(
"-if class **$R**",
@@ -1446,9 +1518,9 @@
checkDiagnostic(handler.errors, proguardConfig, 2, 13,
"Wildcard", "<0>", "invalid");
}
+ verifyFailWithProguard6(proguardConfig, "Invalid reference to wildcard (0,");
}
- @Ignore("b/73800755: verify the range of <n>")
@Test
public void parse_if_nthWildcard_outOfRange_tooBig() throws Exception {
Path proguardConfig = writeTextToTempFile(
@@ -1461,12 +1533,12 @@
parser.parse(proguardConfig);
fail();
} catch (AbortException e) {
- checkDiagnostic(handler.errors, proguardConfig, 1, 1,
+ checkDiagnostic(handler.errors, proguardConfig, 3, 1,
"Wildcard", "<4>", "invalid");
}
+ verifyFailWithProguard6(proguardConfig, "Invalid reference to wildcard (4,");
}
- @Ignore("b/73800755: verify the range of <n>")
@Test
public void parse_if_nthWildcard_outOfRange_inIf() throws Exception {
Path proguardConfig = writeTextToTempFile(
@@ -1479,12 +1551,12 @@
parser.parse(proguardConfig);
fail();
} catch (AbortException e) {
- checkDiagnostic(handler.errors, proguardConfig, 1, 1,
+ checkDiagnostic(handler.errors, proguardConfig, 3, 1,
"Wildcard", "<2>", "invalid");
}
+ verifyFailWithProguard6(proguardConfig, "Invalid reference to wildcard (2,");
}
- @Ignore("b/73800755: verify the range of <n>")
@Test
public void parse_if_nthWildcard_not_referable() throws Exception {
Path proguardConfig = writeTextToTempFile(
@@ -1501,9 +1573,10 @@
parser.parse(proguardConfig);
fail();
} catch (AbortException e) {
- checkDiagnostic(handler.errors, proguardConfig, 1, 1,
+ checkDiagnostic(handler.errors, proguardConfig, 6, 2,
"Wildcard", "<3>", "invalid");
}
+ verifyFailWithProguard6(proguardConfig, "Invalid reference to wildcard (3,");
}
@Test
@@ -1519,8 +1592,9 @@
fail();
} catch (AbortException e) {
checkDiagnostic(handler.errors, proguardConfig, 1, 1,
- "without", "subsequent", "keep");
+ "Expecting", "'-keep'", "after", "'-if'");
}
+ verifyFailWithProguard6(proguardConfig, "Expecting '-keep' option after '-if' option");
}
@Test
@@ -1535,8 +1609,9 @@
fail();
} catch (AbortException e) {
checkDiagnostic(handler.errors, proguardConfig, 1, 1,
- "without", "subsequent", "keep");
+ "Expecting", "'-keep'", "after", "'-if'");
}
+ verifyFailWithProguard6(proguardConfig, "Expecting '-keep' option after '-if' option");
}
@Test
@@ -1690,9 +1765,35 @@
);
Path proguardedJar =
File.createTempFile("proguarded", FileUtils.JAR_EXTENSION, temp.getRoot()).toPath();
- ToolHelper
- .runProguard(jarTestClasses(ImmutableList.of(classToKeepForTest)),
- proguardedJar, ImmutableList.of(proguardConfig, additionalProguardConfig), null);
+ ProcessResult result = ToolHelper.runProguardRaw(
+ jarTestClasses(ImmutableList.of(classToKeepForTest)),
+ proguardedJar,
+ ImmutableList.of(proguardConfig, additionalProguardConfig),
+ null);
+ assertEquals(0, result.exitCode);
+ DexInspector proguardInspector = new DexInspector(readJar(proguardedJar));
+ assertEquals(1, proguardInspector.allClasses().size());
+ }
+ }
+
+ private void verifyWithProguard6(Path proguardConfig) throws Exception {
+ if (isRunProguard()) {
+ // Add a keep rule for the test class as Proguard will fail if the resulting output jar is
+ // empty
+ Class classToKeepForTest = EmptyMainClassForProguardTests.class;
+ Path additionalProguardConfig = writeTextToTempFile(
+ "-keep class " + classToKeepForTest.getCanonicalName() + " {",
+ " public static void main(java.lang.String[]);",
+ "}"
+ );
+ Path proguardedJar =
+ File.createTempFile("proguarded", FileUtils.JAR_EXTENSION, temp.getRoot()).toPath();
+ ProcessResult result = ToolHelper.runProguard6Raw(
+ jarTestClasses(ImmutableList.of(classToKeepForTest)),
+ proguardedJar,
+ ImmutableList.of(proguardConfig, additionalProguardConfig),
+ null);
+ assertEquals(0, result.exitCode);
DexInspector proguardInspector = new DexInspector(readJar(proguardedJar));
assertEquals(1, proguardInspector.allClasses().size());
}
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java
index d8c43c9..4a734a4 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.shaking.ProguardConfigurationParser.IdentifierPatternWithWildcards;
import com.android.tools.r8.shaking.ProguardTypeMatcher.ClassOrType;
import com.android.tools.r8.utils.DescriptorUtils;
import com.google.common.collect.ImmutableList;
@@ -22,7 +23,8 @@
private static final DexItemFactory dexItemFactory = new DexItemFactory();
private static boolean matchTypeName(String typeName, String pattern) {
- return ProguardTypeMatcher.create(pattern, ClassOrType.TYPE, dexItemFactory)
+ return ProguardTypeMatcher.create(
+ toIdentifierPatternWithWildCards(pattern), ClassOrType.TYPE, dexItemFactory)
.matches(dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(typeName)));
}
@@ -37,8 +39,8 @@
for (String pattern : patterns) {
boolean isNegated = pattern.startsWith("!");
String actualPattern = isNegated ? pattern.substring(1) : pattern;
- listBuilder.addClassName(isNegated,
- ProguardTypeMatcher.create(actualPattern, ClassOrType.CLASS, dexItemFactory));
+ listBuilder.addClassName(isNegated, ProguardTypeMatcher.create(
+ toIdentifierPatternWithWildCards(actualPattern), ClassOrType.CLASS, dexItemFactory));
}
builder.addPattern(listBuilder.build());
}
@@ -142,5 +144,36 @@
assertFalse(ProguardNameMatcher.matchFieldOrMethodName("getObject?", "getObject"));
assertTrue(ProguardNameMatcher.matchFieldOrMethodName("getObject?", "getObject1"));
assertTrue(ProguardNameMatcher.matchFieldOrMethodName("getObject?", "getObject5"));
- }
+ }
+
+ private static IdentifierPatternWithWildcards toIdentifierPatternWithWildCards(String pattern) {
+ ImmutableList.Builder<String> builder = ImmutableList.builder();
+ String allPattern = "";
+ String backReference = "";
+ for (int i = 0; i < pattern.length(); i++) {
+ char patternChar = pattern.charAt(i);
+ if (patternChar == '?' || patternChar == '%') {
+ builder.add(String.valueOf(patternChar));
+ } else if (patternChar == '*') {
+ allPattern += patternChar;
+ } else if (patternChar == '<') {
+ backReference += patternChar;
+ } else if (patternChar == '>') {
+ backReference += patternChar;
+ builder.add(backReference);
+ backReference = "";
+ } else {
+ if (allPattern.length() > 0) {
+ builder.add(allPattern);
+ allPattern = "";
+ } else if (backReference.length() > 0) {
+ backReference += patternChar;
+ }
+ }
+ }
+ if (allPattern.length() > 0) {
+ builder.add(allPattern);
+ }
+ return new IdentifierPatternWithWildcards(pattern, builder.build());
+ }
}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
index abbe3d3..1151648 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
@@ -50,7 +50,6 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import org.junit.Test;
public class ForceProguardCompatibilityTest extends TestBase {
@@ -157,7 +156,7 @@
assertEquals(1, classNames.size());
assertEquals(testClass.getCanonicalName(),
classNames.asSpecificDexTypes().get(0).toSourceString());
- Set<ProguardMemberRule> memberRules = configuration.getRules().get(0).getMemberRules();
+ List<ProguardMemberRule> memberRules = configuration.getRules().get(0).getMemberRules();
assertEquals(1, memberRules.size());
assertEquals(ProguardMemberType.INIT, memberRules.iterator().next().getRuleType());
} else {
@@ -279,7 +278,7 @@
assertEquals(ProguardKeepRuleType.KEEP, rule.getType());
assertTrue(rule.getModifiers().allowsObfuscation);
assertTrue(rule.getModifiers().allowsOptimization);
- Set<ProguardMemberRule> memberRules = rule.getMemberRules();
+ List<ProguardMemberRule> memberRules = rule.getMemberRules();
ProguardClassNameList classNames = rule.getClassNames();
assertEquals(1, classNames.size());
DexType type = classNames.asSpecificDexTypes().get(0);
@@ -295,7 +294,7 @@
}
});
Iterables.filter(rules, ProguardIdentifierNameStringRule.class).forEach(rule -> {
- Set<ProguardMemberRule> memberRules = rule.getMemberRules();
+ List<ProguardMemberRule> memberRules = rule.getMemberRules();
ProguardClassNameList classNames = rule.getClassNames();
assertEquals(1, classNames.size());
DexType type = classNames.asSpecificDexTypes().get(0);
@@ -388,7 +387,7 @@
assertEquals(ProguardKeepRuleType.KEEP_CLASS_MEMBERS, rule.getType());
assertTrue(rule.getModifiers().allowsObfuscation);
assertTrue(rule.getModifiers().allowsOptimization);
- Set<ProguardMemberRule> memberRules = rule.getMemberRules();
+ List<ProguardMemberRule> memberRules = rule.getMemberRules();
ProguardClassNameList classNames = rule.getClassNames();
assertEquals(1, classNames.size());
DexType type = classNames.asSpecificDexTypes().get(0);
@@ -403,7 +402,7 @@
}
});
Iterables.filter(rules, ProguardIdentifierNameStringRule.class).forEach(rule -> {
- Set<ProguardMemberRule> memberRules = rule.getMemberRules();
+ List<ProguardMemberRule> memberRules = rule.getMemberRules();
ProguardClassNameList classNames = rule.getClassNames();
assertEquals(1, classNames.size());
DexType type = classNames.asSpecificDexTypes().get(0);
@@ -504,7 +503,7 @@
assertEquals(ProguardKeepRuleType.KEEP_CLASS_MEMBERS, rule.getType());
assertTrue(rule.getModifiers().allowsObfuscation);
assertTrue(rule.getModifiers().allowsOptimization);
- Set<ProguardMemberRule> memberRules = rule.getMemberRules();
+ List<ProguardMemberRule> memberRules = rule.getMemberRules();
ProguardClassNameList classNames = rule.getClassNames();
assertEquals(1, classNames.size());
DexType type = classNames.asSpecificDexTypes().get(0);
@@ -519,7 +518,7 @@
assertTrue(keptFields.containsKey("longField"));
assertTrue(keptFields.containsKey("objField"));
Iterables.filter(rules, ProguardIdentifierNameStringRule.class).forEach(rule -> {
- Set<ProguardMemberRule> memberRules = rule.getMemberRules();
+ List<ProguardMemberRule> memberRules = rule.getMemberRules();
ProguardClassNameList classNames = rule.getClassNames();
assertEquals(1, classNames.size());
DexType type = classNames.asSpecificDexTypes().get(0);
@@ -683,7 +682,7 @@
private void defaultMethodCompatibilityRules(ProguardConfiguration configuration) {
assertEquals(1, configuration.getRules().size());
ProguardConfigurationRule rule = configuration.getRules().get(0);
- Set<ProguardMemberRule> memberRules = rule.getMemberRules();
+ List<ProguardMemberRule> memberRules = rule.getMemberRules();
ProguardClassNameList classNames = rule.getClassNames();
assertEquals(1, classNames.size());
DexType type = classNames.asSpecificDexTypes().get(0);
@@ -708,7 +707,7 @@
private void defaultMethod2CompatibilityRules(ProguardConfiguration configuration) {
assertEquals(1, configuration.getRules().size());
ProguardConfigurationRule rule = configuration.getRules().get(0);
- Set<ProguardMemberRule> memberRules = rule.getMemberRules();
+ List<ProguardMemberRule> memberRules = rule.getMemberRules();
ProguardClassNameList classNames = rule.getClassNames();
assertEquals(1, classNames.size());
DexType type = classNames.asSpecificDexTypes().get(0);