[KeepAnno] Support annotated-by member patterns
Bug: b/248408342
Change-Id: Ic51685de7588e9688fde354e2062009cc5f03798
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepBinding.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepBinding.java
index 408abf2..2f8ff1c 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepBinding.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepBinding.java
@@ -334,6 +334,66 @@
ClassNamePattern classAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
/**
+ * Define the member-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassConstant
+ * <li>memberAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String memberAnnotatedByClassName() default "";
+
+ /**
+ * Define the member-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> memberAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the member-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern memberAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the member-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field and method properties as use restricts the match to both
@@ -344,6 +404,63 @@
MemberAccessFlags[] memberAccess() default {};
/**
+ * Define the method-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassConstant
+ * <li>methodAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String methodAnnotatedByClassName() default "";
+
+ /**
+ * Define the method-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> methodAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the method-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern methodAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the method-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field properties.
@@ -469,6 +586,63 @@
TypePattern[] methodParameterTypePatterns() default {@TypePattern(name = "")};
/**
+ * Define the field-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassConstant
+ * <li>fieldAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String fieldAnnotatedByClassName() default "";
+
+ /**
+ * Define the field-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> fieldAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the field-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern fieldAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the field-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all method properties.
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepCondition.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepCondition.java
index 5737edf..4a39ca8 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepCondition.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepCondition.java
@@ -306,6 +306,69 @@
String memberFromBinding() default "";
/**
+ * Define the member-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassConstant
+ * <li>memberAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String memberAnnotatedByClassName() default "";
+
+ /**
+ * Define the member-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> memberAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the member-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassConstant
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern memberAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the member-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field and method properties as use restricts the match to both
@@ -318,6 +381,66 @@
MemberAccessFlags[] memberAccess() default {};
/**
+ * Define the method-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassConstant
+ * <li>methodAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String methodAnnotatedByClassName() default "";
+
+ /**
+ * Define the method-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> methodAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the method-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassConstant
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern methodAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the method-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field properties.
@@ -468,6 +591,66 @@
TypePattern[] methodParameterTypePatterns() default {@TypePattern(name = "")};
/**
+ * Define the field-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassConstant
+ * <li>fieldAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String fieldAnnotatedByClassName() default "";
+
+ /**
+ * Define the field-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> fieldAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the field-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassConstant
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern fieldAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the field-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all method properties.
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepForApi.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepForApi.java
index 4b56b2e..91934e0 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepForApi.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepForApi.java
@@ -56,6 +56,66 @@
KeepItemKind kind() default KeepItemKind.DEFAULT;
/**
+ * Define the member-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassConstant
+ * <li>memberAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String memberAnnotatedByClassName() default "";
+
+ /**
+ * Define the member-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> memberAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the member-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern memberAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the member-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field and method properties as use restricts the match to both
@@ -66,6 +126,63 @@
MemberAccessFlags[] memberAccess() default {};
/**
+ * Define the method-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassConstant
+ * <li>methodAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String methodAnnotatedByClassName() default "";
+
+ /**
+ * Define the method-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> methodAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the method-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern methodAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the method-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field properties.
@@ -191,6 +308,63 @@
TypePattern[] methodParameterTypePatterns() default {@TypePattern(name = "")};
/**
+ * Define the field-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassConstant
+ * <li>fieldAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String fieldAnnotatedByClassName() default "";
+
+ /**
+ * Define the field-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> fieldAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the field-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern fieldAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the field-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all method properties.
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepTarget.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepTarget.java
index ed5e0ce..d18f91d 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepTarget.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepTarget.java
@@ -403,6 +403,69 @@
String memberFromBinding() default "";
/**
+ * Define the member-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassConstant
+ * <li>memberAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String memberAnnotatedByClassName() default "";
+
+ /**
+ * Define the member-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> memberAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the member-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassConstant
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern memberAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the member-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field and method properties as use restricts the match to both
@@ -415,6 +478,66 @@
MemberAccessFlags[] memberAccess() default {};
/**
+ * Define the method-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassConstant
+ * <li>methodAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String methodAnnotatedByClassName() default "";
+
+ /**
+ * Define the method-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> methodAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the method-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassConstant
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern methodAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the method-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field properties.
@@ -565,6 +688,66 @@
TypePattern[] methodParameterTypePatterns() default {@TypePattern(name = "")};
/**
+ * Define the field-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassConstant
+ * <li>fieldAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String fieldAnnotatedByClassName() default "";
+
+ /**
+ * Define the field-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassNamePattern
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> fieldAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the field-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassConstant
+ * <li>memberFromBinding
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern fieldAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the field-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all method properties.
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/UsedByNative.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/UsedByNative.java
index f025c0e..b547778 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/UsedByNative.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/UsedByNative.java
@@ -99,6 +99,66 @@
KeepConstraint[] constraints() default {};
/**
+ * Define the member-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassConstant
+ * <li>memberAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String memberAnnotatedByClassName() default "";
+
+ /**
+ * Define the member-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> memberAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the member-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern memberAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the member-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field and method properties as use restricts the match to both
@@ -109,6 +169,63 @@
MemberAccessFlags[] memberAccess() default {};
/**
+ * Define the method-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassConstant
+ * <li>methodAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String methodAnnotatedByClassName() default "";
+
+ /**
+ * Define the method-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> methodAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the method-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern methodAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the method-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field properties.
@@ -234,6 +351,63 @@
TypePattern[] methodParameterTypePatterns() default {@TypePattern(name = "")};
/**
+ * Define the field-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassConstant
+ * <li>fieldAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String fieldAnnotatedByClassName() default "";
+
+ /**
+ * Define the field-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> fieldAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the field-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern fieldAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the field-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all method properties.
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/UsedByReflection.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/UsedByReflection.java
index 8076e51..a139965 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/UsedByReflection.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/UsedByReflection.java
@@ -99,6 +99,66 @@
KeepConstraint[] constraints() default {};
/**
+ * Define the member-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassConstant
+ * <li>memberAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String memberAnnotatedByClassName() default "";
+
+ /**
+ * Define the member-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> memberAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the member-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining member-annotated-by:
+ *
+ * <ul>
+ * <li>memberAnnotatedByClassName
+ * <li>memberAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field and method properties as use restricts the match to both
+ * types of members.
+ *
+ * <p>If none are specified the default is to match any member regardless of what the member is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern memberAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the member-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field and method properties as use restricts the match to both
@@ -109,6 +169,63 @@
MemberAccessFlags[] memberAccess() default {};
/**
+ * Define the method-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassConstant
+ * <li>methodAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String methodAnnotatedByClassName() default "";
+
+ /**
+ * Define the method-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> methodAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the method-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining method-annotated-by:
+ *
+ * <ul>
+ * <li>methodAnnotatedByClassName
+ * <li>methodAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all field properties.
+ *
+ * <p>If none are specified the default is to match any method regardless of what the method is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern methodAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the method-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all field properties.
@@ -234,6 +351,63 @@
TypePattern[] methodParameterTypePatterns() default {@TypePattern(name = "")};
/**
+ * Define the field-annotated-by pattern by fully qualified class name.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassConstant
+ * <li>fieldAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The qualified class name that defines the annotation.
+ */
+ String fieldAnnotatedByClassName() default "";
+
+ /**
+ * Define the field-annotated-by pattern by reference to a Class constant.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassNamePattern
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-constant that defines the annotation.
+ */
+ Class<?> fieldAnnotatedByClassConstant() default Object.class;
+
+ /**
+ * Define the field-annotated-by pattern by reference to a class-name pattern.
+ *
+ * <p>Mutually exclusive with the following other properties defining field-annotated-by:
+ *
+ * <ul>
+ * <li>fieldAnnotatedByClassName
+ * <li>fieldAnnotatedByClassConstant
+ * </ul>
+ *
+ * <p>Mutually exclusive with all method properties.
+ *
+ * <p>If none are specified the default is to match any field regardless of what the field is
+ * annotated by.
+ *
+ * @return The class-name pattern that defines the annotation.
+ */
+ ClassNamePattern fieldAnnotatedByClassNamePattern() default @ClassNamePattern(simpleName = "");
+
+ /**
* Define the field-access pattern by matching on access flags.
*
* <p>Mutually exclusive with all method properties.
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
index 6da12d5..b8b81ae 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
@@ -1297,6 +1297,7 @@
private final ParsingContext parsingContext;
private KeepMethodAccessPattern.Builder accessBuilder = null;
private KeepMethodPattern.Builder builder = null;
+ private final ClassNameParser annotatedByParser;
private final StringPatternParser nameParser;
private final MethodReturnTypeParser returnTypeParser;
private final MethodParametersParser parametersParser;
@@ -1306,6 +1307,13 @@
private MethodDeclarationParser(ParsingContext parsingContext) {
this.parsingContext = parsingContext;
+ annotatedByParser = new ClassNameParser(parsingContext.group(Item.methodAnnotatedByGroup));
+ annotatedByParser.setProperty(Item.methodAnnotatedByClassName, ClassNameProperty.NAME);
+ annotatedByParser.setProperty(
+ Item.methodAnnotatedByClassConstant, ClassNameProperty.CONSTANT);
+ annotatedByParser.setProperty(
+ Item.methodAnnotatedByClassNamePattern, ClassNameProperty.PATTERN);
+
nameParser = new StringPatternParser(parsingContext.group(Item.methodNameGroup));
nameParser.setProperty(Item.methodName, StringProperty.EXACT);
nameParser.setProperty(Item.methodNamePattern, StringProperty.PATTERN);
@@ -1319,7 +1327,7 @@
parametersParser.setProperty(Item.methodParameters, TypeProperty.TYPE_NAME);
parametersParser.setProperty(Item.methodParameterTypePatterns, TypeProperty.TYPE_PATTERN);
- parsers = ImmutableList.of(nameParser, returnTypeParser, parametersParser);
+ parsers = ImmutableList.of(annotatedByParser, nameParser, returnTypeParser, parametersParser);
}
@Override
@@ -1343,14 +1351,17 @@
if (accessBuilder != null) {
getBuilder().setAccessPattern(accessBuilder.build());
}
- if (!nameParser.isDefault()) {
+ if (annotatedByParser.isDeclared()) {
+ getBuilder().setAnnotatedByPattern(OptionalPattern.of(annotatedByParser.getValue()));
+ }
+ if (nameParser.isDeclared()) {
KeepStringPattern namePattern = nameParser.getValue();
getBuilder().setNamePattern(KeepMethodNamePattern.fromStringPattern(namePattern));
}
- if (!returnTypeParser.isDefault()) {
+ if (returnTypeParser.isDeclared()) {
getBuilder().setReturnTypePattern(returnTypeParser.getValue());
}
- if (!parametersParser.isDefault()) {
+ if (parametersParser.isDeclared()) {
getBuilder().setParametersPattern(parametersParser.getValue());
}
return builder != null ? builder.build() : null;
@@ -1369,6 +1380,7 @@
private static class FieldDeclarationParser extends DeclarationParser<KeepFieldPattern> {
private final ParsingContext parsingContext;
+ private final ClassNameParser annotatedByParser;
private final StringPatternParser nameParser;
private final FieldTypeParser typeParser;
private KeepFieldAccessPattern.Builder accessBuilder = null;
@@ -1377,6 +1389,12 @@
public FieldDeclarationParser(ParsingContext parsingContext) {
this.parsingContext = parsingContext;
+ annotatedByParser = new ClassNameParser(parsingContext.group(Item.fieldAnnotatedByGroup));
+ annotatedByParser.setProperty(Item.fieldAnnotatedByClassName, ClassNameProperty.NAME);
+ annotatedByParser.setProperty(Item.fieldAnnotatedByClassConstant, ClassNameProperty.CONSTANT);
+ annotatedByParser.setProperty(
+ Item.fieldAnnotatedByClassNamePattern, ClassNameProperty.PATTERN);
+
nameParser = new StringPatternParser(parsingContext.group(Item.fieldNameGroup));
nameParser.setProperty(Item.fieldName, StringProperty.EXACT);
nameParser.setProperty(Item.fieldNamePattern, StringProperty.PATTERN);
@@ -1386,7 +1404,7 @@
typeParser.setProperty(Item.fieldType, TypeProperty.TYPE_NAME);
typeParser.setProperty(Item.fieldTypeConstant, TypeProperty.TYPE_CONSTANT);
- parsers = ImmutableList.of(nameParser, typeParser);
+ parsers = ImmutableList.of(annotatedByParser, nameParser, typeParser);
}
@Override
@@ -1403,17 +1421,20 @@
@Override
public boolean isDeclared() {
- return accessBuilder != null || builder != null;
+ return accessBuilder != null || builder != null || super.isDeclared();
}
public KeepFieldPattern getValue() {
if (accessBuilder != null) {
getBuilder().setAccessPattern(accessBuilder.build());
}
- if (!nameParser.isDefault()) {
+ if (annotatedByParser.isDeclared()) {
+ getBuilder().setAnnotatedByPattern(OptionalPattern.of(annotatedByParser.getValue()));
+ }
+ if (nameParser.isDeclared()) {
getBuilder().setNamePattern(KeepFieldNamePattern.fromStringPattern(nameParser.getValue()));
}
- if (!typeParser.isDefault()) {
+ if (typeParser.isDeclared()) {
getBuilder().setTypePattern(typeParser.getValue());
}
return builder != null ? builder.build() : null;
@@ -1433,15 +1454,25 @@
private final ParsingContext parsingContext;
private KeepMemberAccessPattern.Builder accessBuilder = null;
+ private final ClassNameParser annotatedByParser;
+
private final MethodDeclarationParser methodDeclaration;
private final FieldDeclarationParser fieldDeclaration;
private final List<Parser<?>> parsers;
MemberDeclarationParser(ParsingContext parsingContext) {
this.parsingContext = parsingContext.group(Item.memberGroup);
+
+ annotatedByParser = new ClassNameParser(parsingContext.group(Item.memberAnnotatedByGroup));
+ annotatedByParser.setProperty(Item.memberAnnotatedByClassName, ClassNameProperty.NAME);
+ annotatedByParser.setProperty(
+ Item.memberAnnotatedByClassConstant, ClassNameProperty.CONSTANT);
+ annotatedByParser.setProperty(
+ Item.memberAnnotatedByClassNamePattern, ClassNameProperty.PATTERN);
+
methodDeclaration = new MethodDeclarationParser(parsingContext);
fieldDeclaration = new FieldDeclarationParser(parsingContext);
- parsers = ImmutableList.of(methodDeclaration, fieldDeclaration);
+ parsers = ImmutableList.of(annotatedByParser, methodDeclaration, fieldDeclaration);
}
@Override
@@ -1451,20 +1482,23 @@
@Override
public boolean isDeclared() {
- return accessBuilder != null
- || methodDeclaration.isDeclared()
- || fieldDeclaration.isDeclared();
+ return accessBuilder != null || super.isDeclared();
}
public KeepMemberPattern getValue() {
KeepMethodPattern method = methodDeclaration.getValue();
KeepFieldPattern field = fieldDeclaration.getValue();
- if (accessBuilder != null) {
+ if (accessBuilder != null || annotatedByParser.isDeclared()) {
if (method != null || field != null) {
throw parsingContext.error(
"Cannot define common member access as well as field or method pattern");
}
- return KeepMemberPattern.memberBuilder().setAccessPattern(accessBuilder.build()).build();
+ KeepMemberPattern.Builder builder = KeepMemberPattern.memberBuilder();
+ if (accessBuilder != null) {
+ builder.setAccessPattern(accessBuilder.build());
+ }
+ builder.setAnnotatedByPattern(OptionalPattern.ofNullable(annotatedByParser.getValue()));
+ return builder.build();
}
if (method != null && field != null) {
throw parsingContext.error("Cannot define both a field and a method pattern");
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 40010dc..2ac416c 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
@@ -86,7 +86,17 @@
public static final String classAnnotatedByClassConstant = "classAnnotatedByClassConstant";
public static final String classAnnotatedByClassNamePattern =
"classAnnotatedByClassNamePattern";
+ public static final String memberAnnotatedByGroup = "member-annotated-by";
+ public static final String memberAnnotatedByClassName = "memberAnnotatedByClassName";
+ public static final String memberAnnotatedByClassConstant = "memberAnnotatedByClassConstant";
+ public static final String memberAnnotatedByClassNamePattern =
+ "memberAnnotatedByClassNamePattern";
public static final String memberAccess = "memberAccess";
+ public static final String methodAnnotatedByGroup = "method-annotated-by";
+ public static final String methodAnnotatedByClassName = "methodAnnotatedByClassName";
+ public static final String methodAnnotatedByClassConstant = "methodAnnotatedByClassConstant";
+ public static final String methodAnnotatedByClassNamePattern =
+ "methodAnnotatedByClassNamePattern";
public static final String methodAccess = "methodAccess";
public static final String methodNameGroup = "method-name";
public static final String methodName = "methodName";
@@ -98,6 +108,11 @@
public static final String parametersGroup = "parameters";
public static final String methodParameters = "methodParameters";
public static final String methodParameterTypePatterns = "methodParameterTypePatterns";
+ public static final String fieldAnnotatedByGroup = "field-annotated-by";
+ public static final String fieldAnnotatedByClassName = "fieldAnnotatedByClassName";
+ public static final String fieldAnnotatedByClassConstant = "fieldAnnotatedByClassConstant";
+ public static final String fieldAnnotatedByClassNamePattern =
+ "fieldAnnotatedByClassNamePattern";
public static final String fieldAccess = "fieldAccess";
public static final String fieldNameGroup = "field-name";
public static final String fieldName = "fieldName";
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
index 992cf1e..713686a 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepEdge.java
@@ -44,7 +44,7 @@
*
* ITEM_PATTERN ::= CLASS_ITEM_PATTERN | MEMBER_ITEM_PATTERN
* CLASS_ITEM_PATTERN ::= class QUALIFIED_CLASS_NAME_PATTERN
- * annotated-by OPT(ANNOTATED_BY_PATTERN)
+ * annotated-by ANNOTATED_BY_PATTERN
* instance-of INSTANCE_OF_PATTERN
* MEMBER_ITEM_PATTERN ::= CLASS_ITEM_REFERENCE { MEMBER_PATTERN }
*
@@ -69,19 +69,24 @@
* INSTANCE_OF_PATTERN_INCLUSIVE ::= QUALIFIED_CLASS_NAME_PATTERN
* INSTANCE_OF_PATTERN_EXCLUSIVE ::= QUALIFIED_CLASS_NAME_PATTERN
*
- * ANNOTATED_BY_PATTERN ::= QUALIFIED_CLASS_NAME_PATTERN
+ * ANNOTATED_BY_PATTERN ::= OPT(QUALIFIED_CLASS_NAME_PATTERN)
*
* MEMBER_PATTERN ::= GENERAL_MEMBER_PATTERN | FIELD_PATTERN | METHOD_PATTERN
*
- * GENERAL_MEMBER_PATTERN ::= MEMBER_ACCESS_PATTERN any
+ * GENERAL_MEMBER_PATTERN
+ * ::= ANNOTATED_BY_PATTERN
+ * MEMBER_ACCESS_PATTERN
+ * any
*
* FIELD_PATTERN
- * ::= FIELD_ACCESS_PATTERN
+ * ::= ANNOTATED_BY_PATTERN
+ * FIELD_ACCESS_PATTERN
* FIELD_TYPE_PATTERN
* FIELD_NAME_PATTERN;
*
* METHOD_PATTERN
- * ::= METHOD_ACCESS_PATTERN
+ * ::= ANNOTATED_BY_PATTERN
+ * METHOD_ACCESS_PATTERN
* METHOD_RETURN_TYPE_PATTERN
* METHOD_NAME_PATTERN
* METHOD_PARAMETERS_PATTERN
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java
index b5b028d..64b8ed8 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldPattern.java
@@ -17,6 +17,8 @@
public static class Builder {
+ private OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern =
+ OptionalPattern.absent();
private KeepFieldAccessPattern accessPattern = KeepFieldAccessPattern.anyFieldAccess();
private KeepFieldNamePattern namePattern = KeepFieldNamePattern.any();
private KeepFieldTypePattern typePattern = KeepFieldTypePattern.any();
@@ -35,6 +37,12 @@
.build());
}
+ public Builder setAnnotatedByPattern(
+ OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern) {
+ this.annotatedByPattern = annotatedByPattern;
+ return this;
+ }
+
public Builder setAccessPattern(KeepFieldAccessPattern accessPattern) {
this.accessPattern = accessPattern;
return self();
@@ -51,21 +59,25 @@
}
public KeepFieldPattern build() {
- return new KeepFieldPattern(accessPattern, namePattern, typePattern);
+ return new KeepFieldPattern(annotatedByPattern, accessPattern, namePattern, typePattern);
}
}
+ private final OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern;
private final KeepFieldAccessPattern accessPattern;
private final KeepFieldNamePattern namePattern;
private final KeepFieldTypePattern typePattern;
private KeepFieldPattern(
+ OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern,
KeepFieldAccessPattern accessPattern,
KeepFieldNamePattern namePattern,
KeepFieldTypePattern typePattern) {
+ assert annotatedByPattern != null;
assert accessPattern != null;
assert namePattern != null;
assert typePattern != null;
+ this.annotatedByPattern = annotatedByPattern;
this.accessPattern = accessPattern;
this.namePattern = namePattern;
this.typePattern = typePattern;
@@ -77,7 +89,15 @@
}
public boolean isAnyField() {
- return accessPattern.isAny() && namePattern.isAny() && typePattern.isAny();
+ return annotatedByPattern.isAbsent()
+ && accessPattern.isAny()
+ && namePattern.isAny()
+ && typePattern.isAny();
+ }
+
+ @Override
+ public OptionalPattern<KeepQualifiedClassNamePattern> getAnnotatedByPattern() {
+ return annotatedByPattern;
}
@Override
@@ -102,19 +122,22 @@
return false;
}
KeepFieldPattern that = (KeepFieldPattern) o;
- return accessPattern.equals(that.accessPattern)
+ return annotatedByPattern.equals(that.annotatedByPattern)
+ && accessPattern.equals(that.accessPattern)
&& namePattern.equals(that.namePattern)
&& typePattern.equals(that.typePattern);
}
@Override
public int hashCode() {
- return Objects.hash(accessPattern, namePattern, typePattern);
+ return Objects.hash(annotatedByPattern, accessPattern, namePattern, typePattern);
}
@Override
public String toString() {
return "KeepFieldPattern{"
+ + "annotated-by="
+ + annotatedByPattern
+ "access="
+ accessPattern
+ ", name="
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
index 5cbf53d..fd9cf63 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberPattern.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.keepanno.ast;
+import java.util.Objects;
+
public abstract class KeepMemberPattern {
public static KeepMemberPattern allMembers() {
@@ -14,32 +16,48 @@
}
public static class Builder {
+ private OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern;
private KeepMemberAccessPattern accessPattern = KeepMemberAccessPattern.anyMemberAccess();
+ public Builder setAnnotatedByPattern(
+ OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern) {
+ this.annotatedByPattern = annotatedByPattern;
+ return this;
+ }
+
public Builder setAccessPattern(KeepMemberAccessPattern accessPattern) {
this.accessPattern = accessPattern;
return this;
}
public KeepMemberPattern build() {
- if (accessPattern.isAny()) {
+ if (annotatedByPattern.isAbsent() && accessPattern.isAny()) {
return allMembers();
}
- return new Some(accessPattern);
+ return new Some(annotatedByPattern, accessPattern);
}
}
private static class Some extends KeepMemberPattern {
private static final KeepMemberPattern ANY =
- new Some(KeepMemberAccessPattern.anyMemberAccess());
+ new Some(OptionalPattern.absent(), KeepMemberAccessPattern.anyMemberAccess());
+ private final OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern;
private final KeepMemberAccessPattern accessPattern;
- public Some(KeepMemberAccessPattern accessPattern) {
+ public Some(
+ OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern,
+ KeepMemberAccessPattern accessPattern) {
+ this.annotatedByPattern = annotatedByPattern;
this.accessPattern = accessPattern;
}
@Override
+ public OptionalPattern<KeepQualifiedClassNamePattern> getAnnotatedByPattern() {
+ return annotatedByPattern;
+ }
+
+ @Override
public KeepMemberAccessPattern getAccessPattern() {
return accessPattern;
}
@@ -53,17 +71,18 @@
return false;
}
Some some = (Some) o;
- return accessPattern.equals(some.accessPattern);
+ return annotatedByPattern.equals(some.annotatedByPattern)
+ && accessPattern.equals(some.accessPattern);
}
@Override
public int hashCode() {
- return accessPattern.hashCode();
+ return Objects.hash(annotatedByPattern, accessPattern);
}
@Override
public String toString() {
- return "Member{" + "access=" + accessPattern + '}';
+ return "Member{" + "annotated-by=" + annotatedByPattern + ", access=" + accessPattern + '}';
}
}
@@ -94,4 +113,6 @@
}
public abstract KeepMemberAccessPattern getAccessPattern();
+
+ public abstract OptionalPattern<KeepQualifiedClassNamePattern> getAnnotatedByPattern();
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
index 0e30b11..27128ba 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodPattern.java
@@ -17,6 +17,8 @@
public static class Builder {
+ private OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern =
+ OptionalPattern.absent();
private KeepMethodAccessPattern accessPattern = KeepMethodAccessPattern.anyMethodAccess();
private KeepMethodNamePattern namePattern = KeepMethodNamePattern.any();
private KeepMethodReturnTypePattern returnTypePattern = KeepMethodReturnTypePattern.any();
@@ -36,6 +38,12 @@
.build());
}
+ public Builder setAnnotatedByPattern(
+ OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern) {
+ this.annotatedByPattern = annotatedByPattern;
+ return this;
+ }
+
public Builder setAccessPattern(KeepMethodAccessPattern accessPattern) {
this.accessPattern = accessPattern;
return self();
@@ -69,24 +77,28 @@
returnTypePattern = KeepMethodReturnTypePattern.voidType();
}
return new KeepMethodPattern(
- accessPattern, namePattern, returnTypePattern, parametersPattern);
+ annotatedByPattern, accessPattern, namePattern, returnTypePattern, parametersPattern);
}
}
+ private final OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern;
private final KeepMethodAccessPattern accessPattern;
private final KeepMethodNamePattern namePattern;
private final KeepMethodReturnTypePattern returnTypePattern;
private final KeepMethodParametersPattern parametersPattern;
private KeepMethodPattern(
+ OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern,
KeepMethodAccessPattern accessPattern,
KeepMethodNamePattern namePattern,
KeepMethodReturnTypePattern returnTypePattern,
KeepMethodParametersPattern parametersPattern) {
+ assert annotatedByPattern != null;
assert accessPattern != null;
assert namePattern != null;
assert returnTypePattern != null;
assert parametersPattern != null;
+ this.annotatedByPattern = annotatedByPattern;
this.accessPattern = accessPattern;
this.namePattern = namePattern;
this.returnTypePattern = returnTypePattern;
@@ -99,13 +111,19 @@
}
public boolean isAnyMethod() {
- return accessPattern.isAny()
+ return annotatedByPattern.isAbsent()
+ && accessPattern.isAny()
&& namePattern.isAny()
&& returnTypePattern.isAny()
&& parametersPattern.isAny();
}
@Override
+ public OptionalPattern<KeepQualifiedClassNamePattern> getAnnotatedByPattern() {
+ return annotatedByPattern;
+ }
+
+ @Override
public KeepMethodAccessPattern getAccessPattern() {
return accessPattern;
}
@@ -131,7 +149,8 @@
return false;
}
KeepMethodPattern that = (KeepMethodPattern) o;
- return accessPattern.equals(that.accessPattern)
+ return annotatedByPattern.equals(that.annotatedByPattern)
+ && accessPattern.equals(that.accessPattern)
&& namePattern.equals(that.namePattern)
&& returnTypePattern.equals(that.returnTypePattern)
&& parametersPattern.equals(that.parametersPattern);
@@ -139,12 +158,15 @@
@Override
public int hashCode() {
- return Objects.hash(accessPattern, namePattern, returnTypePattern, parametersPattern);
+ return Objects.hash(
+ annotatedByPattern, accessPattern, namePattern, returnTypePattern, parametersPattern);
}
@Override
public String toString() {
return "KeepMethodPattern{"
+ + "annotated-by="
+ + annotatedByPattern
+ "access="
+ accessPattern
+ ", name="
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 3e78d23..7eddae7 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
@@ -123,6 +123,11 @@
// members via a binding must be split in two up front: one for methods and one for fields.
return printer.appendWithoutBackReferenceAssert("*").append(";");
}
+ if (member.getAnnotatedByPattern().isPresent()) {
+ printer.append("@");
+ printClassName(member.getAnnotatedByPattern().get(), printer);
+ printer.append(" ");
+ }
if (member.isMethod()) {
return printMethod(member.asMethod(), printer);
}
@@ -130,27 +135,27 @@
return printField(member.asField(), printer);
}
// The pattern is a restricted member pattern, e.g., it must apply to fields and methods
- // without any specifics not common to both. For now that is just the access pattern.
- assert !member.getAccessPattern().isAny();
+ // without any specifics not common to both. For now that is annotated-by and access patterns.
+ assert !member.getAccessPattern().isAny() || member.getAnnotatedByPattern().isPresent();
printMemberAccess(printer, member.getAccessPattern());
return printer.appendWithoutBackReferenceAssert("*").append(";");
}
- private static RulePrinter printField(KeepFieldPattern fieldPattern, RulePrinter builder) {
- printFieldAccess(builder, fieldPattern.getAccessPattern());
- printType(builder, fieldPattern.getTypePattern().asType());
- builder.append(" ");
- printFieldName(builder, fieldPattern.getNamePattern());
- return builder.append(";");
+ private static RulePrinter printField(KeepFieldPattern fieldPattern, RulePrinter printer) {
+ printFieldAccess(printer, fieldPattern.getAccessPattern());
+ printType(printer, fieldPattern.getTypePattern().asType());
+ printer.append(" ");
+ printFieldName(printer, fieldPattern.getNamePattern());
+ return printer.append(";");
}
- private static RulePrinter printMethod(KeepMethodPattern methodPattern, RulePrinter builder) {
- printMethodAccess(builder, methodPattern.getAccessPattern());
- printReturnType(builder, methodPattern.getReturnTypePattern());
- builder.append(" ");
- printMethodName(builder, methodPattern.getNamePattern());
- printParameters(builder, methodPattern.getParametersPattern());
- return builder.append(";");
+ private static RulePrinter printMethod(KeepMethodPattern methodPattern, RulePrinter printer) {
+ printMethodAccess(printer, methodPattern.getAccessPattern());
+ printReturnType(printer, methodPattern.getReturnTypePattern());
+ printer.append(" ");
+ printMethodName(printer, methodPattern.getNamePattern());
+ printParameters(printer, methodPattern.getParametersPattern());
+ return printer.append(";");
}
private static RulePrinter printParameters(
diff --git a/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java b/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java
new file mode 100644
index 0000000..9bbcd59
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java
@@ -0,0 +1,196 @@
+// Copyright (c) 2024, 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.keepanno;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.keepanno.annotations.ClassNamePattern;
+import com.android.tools.r8.keepanno.annotations.KeepConstraint;
+import com.android.tools.r8.keepanno.annotations.KeepItemKind;
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsedByReflection;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MembersAnnotatedByPatternsTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("b", "bar", "a", "foo");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
+ }
+
+ public MembersAnnotatedByPatternsTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testReference() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(getInputClasses())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .enableExperimentalKeepAnnotations()
+ .addProgramClasses(getInputClasses())
+ .setMinApi(parameters)
+ // TODO(b/248408342): Make this implicit when annotations are kept by the keep-annotation.
+ .addKeepRuntimeVisibleAnnotations()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(this::checkOutput);
+ }
+
+ public List<Class<?>> getInputClasses() {
+ return ImmutableList.of(
+ TestClass.class,
+ Reflector.class,
+ A.class,
+ B.class,
+ C.class,
+ OnMembers.class,
+ OnFields.class,
+ OnMethods.class);
+ }
+
+ private void checkOutput(CodeInspector inspector) {
+ // The class constant use will ensure the annotation remains.
+ assertThat(inspector.clazz(A.class), isPresentAndRenamed());
+
+ ClassSubject onMembers = inspector.clazz(OnMembers.class);
+ assertThat(onMembers.uniqueFieldWithOriginalName("a"), isAbsent());
+ assertThat(onMembers.uniqueFieldWithOriginalName("b"), isPresentAndNotRenamed());
+ assertThat(onMembers.uniqueMethodWithOriginalName("foo"), isAbsent());
+ assertThat(onMembers.uniqueMethodWithOriginalName("bar"), isPresentAndNotRenamed());
+
+ ClassSubject onFields = inspector.clazz(OnFields.class);
+ assertThat(onFields.uniqueFieldWithOriginalName("a"), isPresentAndNotRenamed());
+ assertThat(onFields.uniqueFieldWithOriginalName("b"), isAbsent());
+ assertThat(onFields.uniqueMethodWithOriginalName("foo"), isAbsent());
+ assertThat(onFields.uniqueMethodWithOriginalName("bar"), isAbsent());
+
+ ClassSubject onMethods = inspector.clazz(OnMethods.class);
+ assertThat(onMethods.uniqueFieldWithOriginalName("a"), isAbsent());
+ assertThat(onMethods.uniqueFieldWithOriginalName("b"), isAbsent());
+ assertThat(onMethods.uniqueMethodWithOriginalName("foo"), isPresentAndNotRenamed());
+ assertThat(onMethods.uniqueMethodWithOriginalName("bar"), isAbsent());
+ }
+
+ @Target({ElementType.FIELD, ElementType.METHOD})
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface A {}
+
+ @Target({ElementType.FIELD})
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface B {}
+
+ @Target({ElementType.METHOD})
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface C {}
+
+ static class Reflector {
+
+ @UsesReflection({
+ @KeepTarget(
+ classConstant = OnMembers.class,
+ kind = KeepItemKind.CLASS_AND_MEMBERS,
+ memberAnnotatedByClassConstant = A.class,
+ constraints = {KeepConstraint.LOOKUP, KeepConstraint.ANNOTATIONS, KeepConstraint.NAME}),
+ @KeepTarget(
+ classConstant = OnFields.class,
+ kind = KeepItemKind.CLASS_AND_FIELDS,
+ fieldAnnotatedByClassName =
+ "com.android.tools.r8.keepanno.MembersAnnotatedByPatternsTest$B",
+ constraints = {KeepConstraint.LOOKUP, KeepConstraint.ANNOTATIONS, KeepConstraint.NAME}),
+ @KeepTarget(
+ classConstant = OnMethods.class,
+ kind = KeepItemKind.CLASS_AND_METHODS,
+ methodAnnotatedByClassNamePattern =
+ @ClassNamePattern(simpleName = "MembersAnnotatedByPatternsTest$C"),
+ constraints = {KeepConstraint.LOOKUP, KeepConstraint.ANNOTATIONS, KeepConstraint.NAME})
+ })
+ public void foo(Class<?> clazz) throws Exception {
+ for (Field field : clazz.getDeclaredFields()) {
+ if (field.isAnnotationPresent(A.class) || field.isAnnotationPresent(B.class)) {
+ System.out.println(field.getName());
+ }
+ }
+ for (Method method : clazz.getDeclaredMethods()) {
+ if (method.isAnnotationPresent(A.class) || method.isAnnotationPresent(C.class)) {
+ System.out.println(method.getName());
+ }
+ }
+ }
+ }
+
+ static class OnMembers {
+ int a;
+
+ @A int b;
+
+ void foo() {}
+
+ @A
+ void bar() {}
+ }
+
+ static class OnFields {
+ @B int a;
+
+ int b;
+
+ void foo() {}
+
+ void bar() {}
+ }
+
+ static class OnMethods {
+ int a;
+
+ int b;
+
+ @C
+ void foo() {}
+
+ void bar() {}
+ }
+
+ static class TestClass {
+
+ @UsedByReflection(kind = KeepItemKind.CLASS_AND_METHODS)
+ public static void main(String[] args) throws Exception {
+ new Reflector().foo(OnMembers.class);
+ new Reflector().foo(OnFields.class);
+ new Reflector().foo(OnMethods.class);
+ }
+ }
+}
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 4b7c0c4..b12f190 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
@@ -298,6 +298,9 @@
private static String CLASS_NAME_GROUP = "class-name";
private static String INSTANCE_OF_GROUP = "instance-of";
private static String CLASS_ANNOTATED_BY_GROUP = "class-annotated-by";
+ private static String MEMBER_ANNOTATED_BY_GROUP = "member-annotated-by";
+ private static String METHOD_ANNOTATED_BY_GROUP = "method-annotated-by";
+ private static String FIELD_ANNOTATED_BY_GROUP = "field-annotated-by";
private Group createDescriptionGroup() {
return new Group("description")
@@ -682,42 +685,40 @@
"If none are specified the default is to match any class instance.");
}
- private GroupMember classAnnotatedByClassName() {
- return new GroupMember("classAnnotatedByClassName")
- .setDocTitle(
- "Define the " + CLASS_ANNOTATED_BY_GROUP + " pattern by fully qualified class name.")
- .setDocReturn("The qualified class name that defines the annotation.")
- .defaultEmptyString();
+ private String annotatedByDefaultDocFooter(String name) {
+ return "If none are specified the default is to match any "
+ + name
+ + " regardless of what the "
+ + name
+ + " is annotated by.";
}
- private GroupMember classAnnotatedByClassConstant() {
- return new GroupMember("classAnnotatedByClassConstant")
- .setDocTitle(
- "Define the "
- + CLASS_ANNOTATED_BY_GROUP
- + " pattern by reference to a Class constant.")
- .setDocReturn("The class-constant that defines the annotation.")
- .defaultObjectClass();
- }
-
- private GroupMember classAnnotatedByClassNamePattern() {
- return new GroupMember("classAnnotatedByClassNamePattern")
- .setDocTitle(
- "Define the "
- + CLASS_ANNOTATED_BY_GROUP
- + " pattern by reference to a class-name pattern.")
- .setDocReturn("The class-name pattern that defines the annotation.")
- .defaultValue(ClassNamePattern.class, DEFAULT_INVALID_CLASS_NAME_PATTERN);
+ private Group createAnnotatedByPatternGroup(String name, String groupName) {
+ return new Group(groupName)
+ .addMember(
+ new GroupMember(name + "AnnotatedByClassName")
+ .setDocTitle(
+ "Define the " + groupName + " pattern by fully qualified class name.")
+ .setDocReturn("The qualified class name that defines the annotation.")
+ .defaultEmptyString())
+ .addMember(
+ new GroupMember(name + "AnnotatedByClassConstant")
+ .setDocTitle(
+ "Define the " + groupName + " pattern by reference to a Class constant.")
+ .setDocReturn("The class-constant that defines the annotation.")
+ .defaultObjectClass())
+ .addMember(
+ new GroupMember(name + "AnnotatedByClassNamePattern")
+ .setDocTitle(
+ "Define the " + groupName + " pattern by reference to a class-name pattern.")
+ .setDocReturn("The class-name pattern that defines the annotation.")
+ .defaultValue(ClassNamePattern.class, DEFAULT_INVALID_CLASS_NAME_PATTERN));
}
private Group createClassAnnotatedByPatternGroup() {
- return new Group(CLASS_ANNOTATED_BY_GROUP)
- .addMember(classAnnotatedByClassName())
- .addMember(classAnnotatedByClassConstant())
- .addMember(classAnnotatedByClassNamePattern())
- .addDocFooterParagraph(
- "If none are specified the default is to match any class "
- + "regardless of what the class is annotated by.");
+ String name = "class";
+ return createAnnotatedByPatternGroup(name, CLASS_ANNOTATED_BY_GROUP)
+ .addDocFooterParagraph(annotatedByDefaultDocFooter(name));
}
private Group createMemberBindingGroup() {
@@ -734,18 +735,28 @@
.defaultEmptyString());
}
+ private Group createMemberAnnotatedByGroup() {
+ String name = "member";
+ return createAnnotatedByPatternGroup(name, MEMBER_ANNOTATED_BY_GROUP)
+ .addDocFooterParagraph(getMutuallyExclusiveForMemberProperties())
+ .addDocFooterParagraph(annotatedByDefaultDocFooter(name));
+ }
+
private Group createMemberAccessGroup() {
return new Group("member-access")
.addMember(
new GroupMember("memberAccess")
.setDocTitle("Define the member-access pattern by matching on access flags.")
- .addParagraph(
- "Mutually exclusive with all field and method properties",
- "as use restricts the match to both types of members.")
+ .addParagraph(getMutuallyExclusiveForMemberProperties())
.setDocReturn("The member access-flag constraints that must be met.")
.defaultArrayEmpty(MemberAccessFlags.class));
}
+ private String getMutuallyExclusiveForMemberProperties() {
+ return "Mutually exclusive with all field and method properties "
+ + "as use restricts the match to both types of members.";
+ }
+
private String getMutuallyExclusiveForMethodProperties() {
return "Mutually exclusive with all field properties.";
}
@@ -766,6 +777,13 @@
+ ".";
}
+ private Group createMethodAnnotatedByGroup() {
+ String name = "method";
+ return createAnnotatedByPatternGroup(name, METHOD_ANNOTATED_BY_GROUP)
+ .addDocFooterParagraph(getMutuallyExclusiveForMethodProperties())
+ .addDocFooterParagraph(annotatedByDefaultDocFooter(name));
+ }
+
private Group createMethodAccessGroup() {
return new Group("method-access")
.addMember(
@@ -841,6 +859,13 @@
.defaultArrayValue(TypePattern.class, DEFAULT_INVALID_TYPE_PATTERN));
}
+ private Group createFieldAnnotatedByGroup() {
+ String name = "field";
+ return createAnnotatedByPatternGroup(name, FIELD_ANNOTATED_BY_GROUP)
+ .addDocFooterParagraph(getMutuallyExclusiveForFieldProperties())
+ .addDocFooterParagraph(annotatedByDefaultDocFooter(name));
+ }
+
private Group createFieldAccessGroup() {
return new Group("field-access")
.addMember(
@@ -948,10 +973,14 @@
private void internalGenerateMemberPropertiesNoBinding(Group memberBindingGroup) {
// General member properties.
+ maybeLink(createMemberAnnotatedByGroup(), memberBindingGroup).generate(this);
+ println();
maybeLink(createMemberAccessGroup(), memberBindingGroup).generate(this);
println();
// Method properties.
+ maybeLink(createMethodAnnotatedByGroup(), memberBindingGroup).generate(this);
+ println();
maybeLink(createMethodAccessGroup(), memberBindingGroup).generate(this);
println();
maybeLink(createMethodNameGroup(), memberBindingGroup).generate(this);
@@ -962,6 +991,8 @@
println();
// Field properties.
+ maybeLink(createFieldAnnotatedByGroup(), memberBindingGroup).generate(this);
+ println();
maybeLink(createFieldAccessGroup(), memberBindingGroup).generate(this);
println();
maybeLink(createFieldNameGroup(), memberBindingGroup).generate(this);
@@ -1479,13 +1510,16 @@
createClassInstanceOfPatternGroup().generateConstants(this);
createClassAnnotatedByPatternGroup().generateConstants(this);
// Members.
+ createMemberAnnotatedByGroup().generateConstants(this);
createMemberAccessGroup().generateConstants(this);
// Methods.
+ createMethodAnnotatedByGroup().generateConstants(this);
createMethodAccessGroup().generateConstants(this);
createMethodNameGroup().generateConstants(this);
createMethodReturnTypeGroup().generateConstants(this);
createMethodParametersGroup().generateConstants(this);
// Fields.
+ createFieldAnnotatedByGroup().generateConstants(this);
createFieldAccessGroup().generateConstants(this);
createFieldNameGroup().generateConstants(this);
createFieldTypeGroup().generateConstants(this);