blob: 4a734a4813630995fdbfcd59888a013fc5413f80 [file] [log] [blame]
// Copyright (c) 2016, 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;
import static org.junit.Assert.assertFalse;
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;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
public class ProguardNameMatchingTest {
private static final String[] BASIC_TYPES = {
"char", "byte", "short", "int", "long", "float", "double", "boolean"
};
private static final DexItemFactory dexItemFactory = new DexItemFactory();
private static boolean matchTypeName(String typeName, String pattern) {
return ProguardTypeMatcher.create(
toIdentifierPatternWithWildCards(pattern), ClassOrType.TYPE, dexItemFactory)
.matches(dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(typeName)));
}
private static boolean matchClassName(String className, String... patterns) {
return matchClassName(className, ImmutableList.of(Arrays.asList(patterns)));
}
private static boolean matchClassName(String className, List<List<String>> patternsList) {
ProguardClassFilter.Builder builder = ProguardClassFilter.builder();
for (List<String> patterns : patternsList) {
ProguardClassNameList.Builder listBuilder = ProguardClassNameList.builder();
for (String pattern : patterns) {
boolean isNegated = pattern.startsWith("!");
String actualPattern = isNegated ? pattern.substring(1) : pattern;
listBuilder.addClassName(isNegated, ProguardTypeMatcher.create(
toIdentifierPatternWithWildCards(actualPattern), ClassOrType.CLASS, dexItemFactory));
}
builder.addPattern(listBuilder.build());
}
return builder.build()
.matches(dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(className)));
}
@Test
public void matchClassNames() {
assertTrue(matchClassName("", "**"));
assertTrue(matchClassName("a", "**"));
assertTrue(matchClassName("", "*"));
assertTrue(matchClassName("a", "*"));
assertFalse(matchClassName("", "?"));
assertTrue(matchClassName("a", "?"));
assertTrue(matchClassName("java.lang.Object", "**"));
assertFalse(matchClassName("java.lang.Object", "ja*"));
assertTrue(matchClassName("java.lang.Object", "ja**"));
assertTrue(matchClassName("java.lang.Object", "ja**ject"));
// Oddly, the proguard specification for this makes a lonely * synonymous with **.
assertTrue(matchClassName("java.lang.Object", "*"));
assertFalse(matchClassName("java.lang.Object", "ja*ject"));
assertTrue(matchClassName("java.lang.Object", "java.*g.O*"));
assertTrue(matchClassName("java.lang.Object", "java.*g.O?je?t"));
assertFalse(matchClassName("java.lang.Object", "java.*g.O?je?t?"));
assertFalse(matchClassName("java.lang.Object", "java?lang.Object"));
assertTrue(matchClassName("java.lang.Object", "*a*.*a**"));
assertTrue(matchClassName("java.lang.Object", "*a**a**"));
assertTrue(matchClassName("java.lang.Object", "!java.util.**", "java**"));
assertFalse(matchClassName("java.lang.Object", "!java.**", "java.lang.*"));
assertTrue(matchClassName("java.lang.Object", "java.lang.*", "!java.**"));
assertTrue(matchClassName("boobar", "!foobar", "*bar"));
assertFalse(matchClassName("foobar", "!foobar", "*bar"));
assertFalse(matchClassName("foo", "!boo"));
assertFalse(matchClassName("foo", "baz,!boo"));
assertFalse(matchClassName("boo", "!boo", "**"));
assertTrue(matchClassName("boo", "**", "!boo"));
assertTrue(matchClassName("boo",
ImmutableList.of(ImmutableList.of("!boo"), ImmutableList.of("**"))));
assertFalse(matchClassName("boofoo", "!boo*,*foo,boofoo"));
assertTrue(matchClassName("boofoo",
ImmutableList.of(ImmutableList.of("!boo*,*foo"), ImmutableList.of("boofoo"))));
}
private void assertMatchesBasicTypes(String pattern) {
for (String type : BASIC_TYPES) {
assertTrue(matchTypeName(type, pattern));
}
}
private void assertDoesNotMatchBasicTypes(String pattern) {
for (String type : BASIC_TYPES) {
assertFalse(matchTypeName(type, pattern));
}
}
@Test
public void matchTypeNames() {
assertTrue(matchTypeName("java.lang.Object", "**"));
assertDoesNotMatchBasicTypes("**");
assertDoesNotMatchBasicTypes("*");
assertFalse(
matchTypeName("java.lang.Object[]", "**"));
assertFalse(
matchTypeName("java.lang.Object", "**z"));
assertFalse(matchTypeName("java.lang.Object[]", "java.**"
));
assertTrue(
matchTypeName("java.lang.Object[]", "***"));
assertTrue(matchTypeName("java.lang.Object[][]", "***"
));
assertFalse(matchTypeName("java.lang.Object", "%"));
assertTrue(matchTypeName("a", "**"));
assertTrue(matchTypeName("java.lang.Object[]", "**[]"
));
assertFalse(matchTypeName("java.lang.Object[][]", "**[]"
));
assertTrue(matchTypeName("abc", "*"));
assertMatchesBasicTypes("***");
assertMatchesBasicTypes("%");
}
@Test
public void matchFieldOrMethodNames() {
assertTrue(ProguardNameMatcher.matchFieldOrMethodName("*", ""));
assertTrue(ProguardNameMatcher.matchFieldOrMethodName("*", "get"));
assertTrue(ProguardNameMatcher.matchFieldOrMethodName("get*", "get"));
assertTrue(ProguardNameMatcher.matchFieldOrMethodName("get*", "getObject"));
assertTrue(ProguardNameMatcher.matchFieldOrMethodName("*t", "get"));
assertTrue(ProguardNameMatcher.matchFieldOrMethodName("g*t*", "getObject"));
assertTrue(
ProguardNameMatcher.matchFieldOrMethodName("g*t***************", "getObject"));
assertFalse(ProguardNameMatcher.matchFieldOrMethodName("get*y", "getObject"));
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());
}
}