Create keepanno structure for TypePattern with instanceOf
Change-Id: I9da62f73d0c26bb7d40f56c6e721f527c6cdb830
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/TypePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/TypePattern.java
index 47fdb1d..9413ca3 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/TypePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/TypePattern.java
@@ -34,6 +34,7 @@
* <ul>
* <li>constant
* <li>classNamePattern
+ * <li>instanceOfPattern
* </ul>
*/
String name() default "";
@@ -48,6 +49,7 @@
* <ul>
* <li>name
* <li>classNamePattern
+ * <li>instanceOfPattern
* </ul>
*/
Class<?> constant() default Object.class;
@@ -60,7 +62,23 @@
* <ul>
* <li>name
* <li>constant
+ * <li>instanceOfPattern
* </ul>
*/
ClassNamePattern classNamePattern() default @ClassNamePattern(unqualifiedName = "");
+
+ /**
+ * Define the instance-of with a pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining type-pattern:
+ *
+ * <ul>
+ * <li>name
+ * <li>constant
+ * <li>classNamePattern
+ * </ul>
+ *
+ * @return The pattern that defines what instance-of the class must be.
+ */
+ InstanceOfPattern instanceOfPattern() default @InstanceOfPattern();
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java
index 538c8ca..e0ef6b5 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java
@@ -69,7 +69,11 @@
arrayTypePattern -> {
throw parsingContext.error("Invalid use of array type where class type was expected");
},
- classNamePattern -> classNamePattern);
+ classNamePattern -> classNamePattern,
+ instanceOfPattern -> {
+ throw parsingContext.error(
+ "Invalid use of instance of type where class type was expected");
+ });
}
@Override
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
index c1f8c13..2645b35 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
@@ -466,6 +466,9 @@
},
clazz -> {
writeClassNamePattern(clazz, TypePattern.classNamePattern, v);
+ },
+ instanceOf -> {
+ writeInstanceOfPattern(instanceOf, v);
}));
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java
index a0c0afc..f81610e 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.keepanno.asm;
import com.android.tools.r8.keepanno.asm.ClassNameParser.ClassNameProperty;
+import com.android.tools.r8.keepanno.asm.InstanceOfParser.InstanceOfProperties;
import com.android.tools.r8.keepanno.asm.TypeParser.TypeProperty;
import com.android.tools.r8.keepanno.ast.AnnotationConstants.TypePattern;
import com.android.tools.r8.keepanno.ast.KeepTypePattern;
@@ -24,7 +25,8 @@
TYPE_PATTERN,
TYPE_NAME,
TYPE_CONSTANT,
- CLASS_NAME_PATTERN
+ CLASS_NAME_PATTERN,
+ INSTANCE_OF_PATTERN
}
@Override
@@ -56,6 +58,7 @@
typeParser.setProperty(TypePattern.name, TypeProperty.TYPE_NAME);
typeParser.setProperty(TypePattern.constant, TypeProperty.TYPE_CONSTANT);
typeParser.setProperty(TypePattern.classNamePattern, TypeProperty.CLASS_NAME_PATTERN);
+ typeParser.setProperty(TypePattern.instanceOfPattern, TypeProperty.INSTANCE_OF_PATTERN);
return new ParserVisitor(
context,
typeParser,
@@ -70,6 +73,15 @@
descriptor,
value -> setValue.accept(KeepTypePattern.fromClass(value)));
}
+ case INSTANCE_OF_PATTERN:
+ {
+ InstanceOfParser parser = new InstanceOfParser(getParsingContext());
+ return parser.tryPropertyAnnotation(
+ InstanceOfProperties.PATTERN,
+ name,
+ descriptor,
+ value -> setValue.accept(KeepTypePattern.fromInstanceOf(value)));
+ }
default:
return null;
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java
index 9b0ae29..77643cd 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java
@@ -237,6 +237,7 @@
public static final String name = "name";
public static final String constant = "constant";
public static final String classNamePattern = "classNamePattern";
+ public static final String instanceOfPattern = "instanceOfPattern";
}
public static final class ClassNamePattern {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepArrayTypePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepArrayTypePattern.java
index 6194fb3..5981336 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepArrayTypePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepArrayTypePattern.java
@@ -47,11 +47,14 @@
() -> {
throw new KeepEdgeException("No descriptor exists for 'any primitive' array");
},
- primitive -> primitive.getDescriptor(),
+ KeepPrimitiveTypePattern::getDescriptor,
array -> {
throw new KeepEdgeException("Unexpected nested array");
},
- clazz -> clazz.getExactDescriptor());
+ KeepQualifiedClassNamePattern::getExactDescriptor,
+ instanceOf -> {
+ throw new KeepEdgeException("No descriptor exists for instanceOf array");
+ });
}
@Override
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java
index a0edf23..7e3c088 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java
@@ -28,6 +28,10 @@
return new ClassType(type);
}
+ public static KeepTypePattern fromInstanceOf(KeepInstanceOfPattern pattern) {
+ return new KeepInstanceOf(pattern);
+ }
+
public static KeepTypePattern fromDescriptor(String typeDescriptor) {
char c = typeDescriptor.charAt(0);
if (c == 'L') {
@@ -56,18 +60,21 @@
Supplier<T> onAny,
Function<KeepPrimitiveTypePattern, T> onPrimitive,
Function<KeepArrayTypePattern, T> onArray,
- Function<KeepQualifiedClassNamePattern, T> onClass);
+ Function<KeepQualifiedClassNamePattern, T> onClass,
+ Function<KeepInstanceOfPattern, T> onInstanceOf);
public final void match(
Runnable onAny,
Consumer<KeepPrimitiveTypePattern> onPrimitive,
Consumer<KeepArrayTypePattern> onArray,
- Consumer<KeepQualifiedClassNamePattern> onClass) {
+ Consumer<KeepQualifiedClassNamePattern> onClass,
+ Consumer<KeepInstanceOfPattern> onInstanceOf) {
apply(
AstUtils.toVoidSupplier(onAny),
AstUtils.toVoidFunction(onPrimitive),
AstUtils.toVoidFunction(onArray),
- AstUtils.toVoidFunction(onClass));
+ AstUtils.toVoidFunction(onClass),
+ AstUtils.toVoidFunction(onInstanceOf));
}
public boolean isAny() {
@@ -87,7 +94,8 @@
Supplier<T> onAny,
Function<KeepPrimitiveTypePattern, T> onPrimitive,
Function<KeepArrayTypePattern, T> onArray,
- Function<KeepQualifiedClassNamePattern, T> onClass) {
+ Function<KeepQualifiedClassNamePattern, T> onClass,
+ Function<KeepInstanceOfPattern, T> onInstanceOf) {
return onAny.get();
}
@@ -152,7 +160,8 @@
Supplier<T> onAny,
Function<KeepPrimitiveTypePattern, T> onPrimitive,
Function<KeepArrayTypePattern, T> onArray,
- Function<KeepQualifiedClassNamePattern, T> onClass) {
+ Function<KeepQualifiedClassNamePattern, T> onClass,
+ Function<KeepInstanceOfPattern, T> onInstanceOf) {
return onPrimitive.apply(type);
}
}
@@ -169,7 +178,8 @@
Supplier<T> onAny,
Function<KeepPrimitiveTypePattern, T> onPrimitive,
Function<KeepArrayTypePattern, T> onArray,
- Function<KeepQualifiedClassNamePattern, T> onClass) {
+ Function<KeepQualifiedClassNamePattern, T> onClass,
+ Function<KeepInstanceOfPattern, T> onInstanceOf) {
return onClass.apply(type);
}
@@ -208,7 +218,8 @@
Supplier<T> onAny,
Function<KeepPrimitiveTypePattern, T> onPrimitive,
Function<KeepArrayTypePattern, T> onArray,
- Function<KeepQualifiedClassNamePattern, T> onClass) {
+ Function<KeepQualifiedClassNamePattern, T> onClass,
+ Function<KeepInstanceOfPattern, T> onInstanceOf) {
return onArray.apply(type);
}
@@ -234,4 +245,22 @@
return type.toString();
}
}
+
+ private static class KeepInstanceOf extends KeepTypePattern {
+ private final KeepInstanceOfPattern instanceOf;
+
+ private KeepInstanceOf(KeepInstanceOfPattern instanceOf) {
+ this.instanceOf = instanceOf;
+ }
+
+ @Override
+ public <T> T apply(
+ Supplier<T> onAny,
+ Function<KeepPrimitiveTypePattern, T> onPrimitive,
+ Function<KeepArrayTypePattern, T> onArray,
+ Function<KeepQualifiedClassNamePattern, T> onClass,
+ Function<KeepInstanceOfPattern, T> onInstanceOf) {
+ return onInstanceOf.apply(instanceOf);
+ }
+ }
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrintingUtils.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrintingUtils.java
index 12d2caa..38a768f 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrintingUtils.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrintingUtils.java
@@ -221,7 +221,13 @@
printer::appendTripleStar,
primitivePattern -> printPrimitiveType(printer, primitivePattern),
arrayTypePattern -> printArrayType(printer, arrayTypePattern),
- classTypePattern -> printClassName(classTypePattern, printer));
+ classTypePattern -> printClassName(classTypePattern, printer),
+ instanceOfPattern -> printInstanceOf(instanceOfPattern, printer));
+ }
+
+ private static RulePrinter printInstanceOf(
+ KeepInstanceOfPattern instanceOfPattern, RulePrinter printer) {
+ throw new Unimplemented();
}
private static RulePrinter printPrimitiveType(
diff --git a/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java b/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java
index dea79c9..052c9ad 100644
--- a/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java
+++ b/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java
@@ -408,10 +408,11 @@
},
fieldPattern ->
holder.forEachProgramFieldMatching(
- f -> predicates.matchesField(f, fieldPattern), continueWithMember),
+ f -> predicates.matchesField(f, fieldPattern, appInfo), continueWithMember),
methodPattern ->
holder.forEachProgramMethodMatching(
- m -> predicates.matchesMethod(m, methodPattern), continueWithMember));
+ m -> predicates.matchesMethod(m, methodPattern, appInfo),
+ continueWithMember));
if (didContinue.isFalse()) {
// No match for the member pattern existed, continue with next class.
continueWithNoClassClearingMembers(
diff --git a/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcherPredicates.java b/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcherPredicates.java
index 0982747..dfe3f51 100644
--- a/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcherPredicates.java
+++ b/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcherPredicates.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMember;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -84,7 +85,16 @@
}
private boolean matchesInstanceOfPattern(
- DexProgramClass clazz, KeepInstanceOfPattern pattern, AppInfoWithClassHierarchy appInfo) {
+ DexType type, KeepInstanceOfPattern pattern, AppInfoWithClassHierarchy appInfo) {
+ DexClass dexClass = appInfo.definitionFor(type);
+ if (dexClass != null) {
+ return matchesInstanceOfPattern(dexClass.asProgramClass(), pattern, appInfo);
+ }
+ return false;
+ }
+
+ private boolean matchesInstanceOfPattern(
+ DexClass clazz, KeepInstanceOfPattern pattern, AppInfoWithClassHierarchy appInfo) {
if (pattern.isAny()) {
return true;
}
@@ -115,23 +125,25 @@
&& matchesGeneralMemberAccess(member.getAccessFlags(), pattern.getAccessPattern());
}
- public boolean matchesMethod(DexEncodedMethod method, KeepMethodPattern pattern) {
+ public boolean matchesMethod(
+ DexEncodedMethod method, KeepMethodPattern pattern, AppInfoWithClassHierarchy appInfo) {
if (pattern.isAnyMethod()) {
return true;
}
return matchesString(method.getName(), pattern.getNamePattern().asStringPattern())
- && matchesReturnType(method.getReturnType(), pattern.getReturnTypePattern())
- && matchesParameters(method.getParameters(), pattern.getParametersPattern())
+ && matchesReturnType(method.getReturnType(), pattern.getReturnTypePattern(), appInfo)
+ && matchesParameters(method.getParameters(), pattern.getParametersPattern(), appInfo)
&& matchesAnnotatedBy(method.annotations(), pattern.getAnnotatedByPattern())
&& matchesMethodAccess(method.getAccessFlags(), pattern.getAccessPattern());
}
- public boolean matchesField(DexEncodedField field, KeepFieldPattern pattern) {
+ public boolean matchesField(
+ DexEncodedField field, KeepFieldPattern pattern, AppInfoWithClassHierarchy appInfo) {
if (pattern.isAnyField()) {
return true;
}
return matchesString(field.getName(), pattern.getNamePattern().asStringPattern())
- && matchesType(field.getType(), pattern.getTypePattern().asType())
+ && matchesType(field.getType(), pattern.getTypePattern().asType(), appInfo)
&& matchesAnnotatedBy(field.annotations(), pattern.getAnnotatedByPattern())
&& matchesFieldAccess(field.getAccessFlags(), pattern.getAccessPattern());
}
@@ -211,7 +223,10 @@
return false;
}
- public boolean matchesParameters(DexTypeList parameters, KeepMethodParametersPattern pattern) {
+ public boolean matchesParameters(
+ DexTypeList parameters,
+ KeepMethodParametersPattern pattern,
+ AppInfoWithClassHierarchy appInfo) {
if (pattern.isAny()) {
return true;
}
@@ -221,7 +236,7 @@
}
int size = parameters.size();
for (int i = 0; i < size; i++) {
- if (!matchesType(parameters.get(i), patternList.get(i))) {
+ if (!matchesType(parameters.get(i), patternList.get(i), appInfo)) {
return false;
}
}
@@ -263,29 +278,34 @@
}
public boolean matchesReturnType(
- DexType returnType, KeepMethodReturnTypePattern returnTypePattern) {
+ DexType returnType,
+ KeepMethodReturnTypePattern returnTypePattern,
+ AppInfoWithClassHierarchy appInfo) {
if (returnTypePattern.isAny()) {
return true;
}
if (returnTypePattern.isVoid()) {
return returnType.isVoidType();
}
- return matchesType(returnType, returnTypePattern.asType());
+ return matchesType(returnType, returnTypePattern.asType(), appInfo);
}
- public boolean matchesType(DexType type, KeepTypePattern pattern) {
+ public boolean matchesType(
+ DexType type, KeepTypePattern pattern, AppInfoWithClassHierarchy appInfo) {
return pattern.apply(
() -> true,
p -> matchesPrimitiveType(type, p),
- p -> matchesArrayType(type, p),
- p -> matchesClassType(type, p));
+ p -> matchesArrayType(type, p, appInfo),
+ p -> matchesClassType(type, p),
+ p -> matchesInstanceOfPattern(type, p, appInfo));
}
public boolean matchesClassType(DexType type, KeepQualifiedClassNamePattern pattern) {
return type.isClassType() && matchesClassName(type, pattern);
}
- public boolean matchesArrayType(DexType type, KeepArrayTypePattern pattern) {
+ public boolean matchesArrayType(
+ DexType type, KeepArrayTypePattern pattern, AppInfoWithClassHierarchy appInfo) {
if (!type.isArrayType()) {
return false;
}
@@ -296,7 +316,9 @@
return false;
}
return matchesType(
- type.toArrayElementAfterDimension(pattern.getDimensions(), factory), pattern.getBaseType());
+ type.toArrayElementAfterDimension(pattern.getDimensions(), factory),
+ pattern.getBaseType(),
+ appInfo);
}
public boolean matchesPrimitiveType(DexType type, KeepPrimitiveTypePattern pattern) {
diff --git a/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java b/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java
index b6be4dc..e92c4d8 100644
--- a/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java
+++ b/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java
@@ -581,7 +581,8 @@
.addMember(
new GroupMember("classNamePattern")
.setDocTitle("Classes matching the class-name pattern.")
- .defaultValue(CLASS_NAME_PATTERN, DEFAULT_INVALID_CLASS_NAME_PATTERN));
+ .defaultValue(CLASS_NAME_PATTERN, DEFAULT_INVALID_CLASS_NAME_PATTERN))
+ .addMember(instanceOfPattern());
// TODO(b/248408342): Add more injections on type pattern variants.
// /** Exact type name as a string to match any array with that type as member. */
// String arrayOf() default "";