[keepanno] Add support for keeping subclasses as well
This is an experimental way of specifying this. Implementation to
allow for testing.
Change-Id: I0d87b41a9afbfb4843b8e8c24336b7610a39f70d
Bug: b/392865072
diff --git a/src/keepanno/java/androidx/annotation/keep/UsesReflectionToAccessField.kt b/src/keepanno/java/androidx/annotation/keep/UsesReflectionToAccessField.kt
index b453d72..d0f8a9a 100644
--- a/src/keepanno/java/androidx/annotation/keep/UsesReflectionToAccessField.kt
+++ b/src/keepanno/java/androidx/annotation/keep/UsesReflectionToAccessField.kt
@@ -60,6 +60,9 @@
*/
@Suppress("KotlinDefaultParameterOrder") val className: String = "",
+ /** Also access field on subclasses. */
+ @Suppress("KotlinDefaultParameterOrder") val includeSubclasses: Boolean = false,
+
/** Name (or name pattern) of field accessed by reflection. */
val fieldName: String,
diff --git a/src/keepanno/java/androidx/annotation/keep/UsesReflectionToAccessMethod.kt b/src/keepanno/java/androidx/annotation/keep/UsesReflectionToAccessMethod.kt
index ddaefbf..d15fba6 100644
--- a/src/keepanno/java/androidx/annotation/keep/UsesReflectionToAccessMethod.kt
+++ b/src/keepanno/java/androidx/annotation/keep/UsesReflectionToAccessMethod.kt
@@ -60,6 +60,9 @@
*/
@Suppress("KotlinDefaultParameterOrder") val className: String = "",
+ /** Also access methods on subclasses. */
+ @Suppress("KotlinDefaultParameterOrder") val includeSubclasses: Boolean = false,
+
/** Name (or name pattern) of method accessed by reflection. */
val methodName: String,
diff --git a/src/keepanno/java/androidx/annotation/keep/UsesReflectionToConstruct.kt b/src/keepanno/java/androidx/annotation/keep/UsesReflectionToConstruct.kt
index 8aabcb5..35a04cb 100644
--- a/src/keepanno/java/androidx/annotation/keep/UsesReflectionToConstruct.kt
+++ b/src/keepanno/java/androidx/annotation/keep/UsesReflectionToConstruct.kt
@@ -63,6 +63,9 @@
*/
val className: String = "",
+ /** Also instantiate subclasses. */
+ @Suppress("KotlinDefaultParameterOrder") val includeSubclasses: Boolean = false,
+
/**
* Defines which constructor to keep by specifying the parameter list types.
*
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 70c0c9e..7d4245c 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
@@ -1569,10 +1569,12 @@
private static final String UsesReflectionToXXXClassConstant = "classConstant";
private static final String UsesReflectionToXXXClassName = "className";
+ private static final String UsesReflectionToXXXIncludeSubclasses = "includeSubclasses";
protected final ParsingContext parsingContext;
protected KeepQualifiedClassNamePattern qualifiedName;
+ protected boolean includeSubclasses = false;
UsesReflectionToXXXVisitor(AnnotationParsingContext parsingContext) {
super(parsingContext);
@@ -1583,6 +1585,12 @@
assert UsesReflectionToXXXClassName.equals(UsesReflectionToConstruct.className);
assert UsesReflectionToXXXClassName.equals(UsesReflectionToAccessMethod.className);
assert UsesReflectionToXXXClassName.equals(UsesReflectionToAccessField.className);
+ assert UsesReflectionToXXXIncludeSubclasses.equals(
+ UsesReflectionToConstruct.includeSubclasses);
+ assert UsesReflectionToXXXIncludeSubclasses.equals(
+ UsesReflectionToAccessMethod.includeSubclasses);
+ assert UsesReflectionToXXXIncludeSubclasses.equals(
+ UsesReflectionToAccessField.includeSubclasses);
}
protected boolean maybeVisitQualifiedName(String name, Object value) {
@@ -1597,6 +1605,29 @@
}
return false;
}
+
+ protected boolean maybeVisitIncludeSubclasses(String name, Object value) {
+ if (name.equals(UsesReflectionToXXXIncludeSubclasses) && value instanceof Boolean) {
+ includeSubclasses = (Boolean) value;
+ return true;
+ }
+ return false;
+ }
+
+ protected KeepClassItemPattern getKeepClassItemPattern() {
+ return includeSubclasses
+ ? KeepClassItemPattern.builder()
+ .setInstanceOfPattern(
+ KeepInstanceOfPattern.builder()
+ .classPattern(qualifiedName)
+ .setInclusive(true)
+ .build())
+ .build()
+ : KeepClassItemPattern.builder()
+ .setClassPattern(
+ KeepClassPattern.builder().setClassNamePattern(qualifiedName).build())
+ .build();
+ }
}
private static class UsesReflectionToConstructVisitor extends UsesReflectionToXXXVisitor {
@@ -1627,6 +1658,9 @@
if (maybeVisitQualifiedName(name, value)) {
return;
}
+ if (maybeVisitIncludeSubclasses(name, value)) {
+ return;
+ }
super.visit(name, value);
}
@@ -1649,11 +1683,7 @@
String kotlinMetadataDescriptor = "Lkotlin/Metadata;";
KeepClassBindingReference classBinding =
- bindingsHelper.defineFreshClassBinding(
- KeepClassItemPattern.builder()
- .setClassPattern(
- KeepClassPattern.builder().setClassNamePattern(qualifiedName).build())
- .build());
+ bindingsHelper.defineFreshClassBinding(getKeepClassItemPattern());
KeepMemberBindingReference memberBinding =
bindingsHelper.defineFreshMemberBinding(
KeepMemberItemPattern.builder()
@@ -1799,6 +1829,7 @@
private final UserBindingsHelper bindingsHelper = new UserBindingsHelper();
private KeepQualifiedClassNamePattern qualifiedName;
+ private boolean includeSubclasses = false;
private KeepMethodNamePattern methodName;
private KeepMethodNamePattern methodNameKotlinDefault;
private KeepMethodReturnTypePattern returnType = KeepMethodReturnTypePattern.any();
@@ -1822,6 +1853,9 @@
if (maybeVisitQualifiedName(name, value)) {
return;
}
+ if (maybeVisitIncludeSubclasses(name, value)) {
+ return;
+ }
if (name.equals(UsesReflectionToAccessMethod.methodName) && value instanceof String) {
methodName = KeepMethodNamePattern.exact((String) value);
methodNameKotlinDefault = KeepMethodNamePattern.exact(value + "$default");
@@ -1863,11 +1897,7 @@
String kotlinMetadataDescriptor = "Lkotlin/Metadata;";
KeepClassBindingReference classBinding =
- bindingsHelper.defineFreshClassBinding(
- KeepClassItemPattern.builder()
- .setClassPattern(
- KeepClassPattern.builder().setClassNamePattern(qualifiedName).build())
- .build());
+ bindingsHelper.defineFreshClassBinding(getKeepClassItemPattern());
KeepMemberBindingReference memberBinding =
bindingsHelper.defineFreshMemberBinding(
KeepMemberItemPattern.builder()
@@ -1886,13 +1916,7 @@
// method will be part of the required structure of the class matched. See test
// KeepConjunctiveBindingsTest.
.setClassReference(
- bindingsHelper.defineFreshClassBinding(
- KeepClassItemPattern.builder()
- .setClassPattern(
- KeepClassPattern.builder()
- .setClassNamePattern(qualifiedName)
- .build())
- .build()))
+ bindingsHelper.defineFreshClassBinding(getKeepClassItemPattern()))
.setMemberPattern(
KeepMethodPattern.builder()
.setNamePattern(methodNameKotlinDefault)
@@ -2039,6 +2063,7 @@
private final UserBindingsHelper bindingsHelper = new UserBindingsHelper();
private KeepQualifiedClassNamePattern qualifiedName;
+ private boolean includeSubclasses = false;
private KeepFieldNamePattern fieldName;
private KeepFieldTypePattern fieldType = KeepFieldTypePattern.any();
@@ -2061,6 +2086,9 @@
if (maybeVisitQualifiedName(name, value)) {
return;
}
+ if (maybeVisitIncludeSubclasses(name, value)) {
+ return;
+ }
if (name.equals(UsesReflectionToAccessField.fieldName) && value instanceof String) {
fieldName = KeepFieldNamePattern.exact((String) value);
return;
@@ -2087,11 +2115,7 @@
String kotlinMetadataDescriptor = "Lkotlin/Metadata;";
KeepClassBindingReference classBinding =
- bindingsHelper.defineFreshClassBinding(
- KeepClassItemPattern.builder()
- .setClassPattern(
- KeepClassPattern.builder().setClassNamePattern(qualifiedName).build())
- .build());
+ bindingsHelper.defineFreshClassBinding(getKeepClassItemPattern());
KeepMemberBindingReference memberBinding =
bindingsHelper.defineFreshMemberBinding(
KeepMemberItemPattern.builder()
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 4d813f5..83843e0 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
@@ -153,6 +153,7 @@
public static final String classSelectionGroup = "class-selection";
public static final String classConstant = "classConstant";
public static final String className = "className";
+ public static final String includeSubclasses = "includeSubclasses";
public static final String constructorParametersGroup = "constructor-parameters";
public static final String parameterTypes = "parameterTypes";
public static final String parameterTypeNames = "parameterTypeNames";
@@ -181,6 +182,7 @@
public static final String classSelectionGroup = "class-selection";
public static final String classConstant = "classConstant";
public static final String className = "className";
+ public static final String includeSubclasses = "includeSubclasses";
public static final String methodName = "methodName";
public static final String constructorParametersGroup = "constructor-parameters";
public static final String parameterTypes = "parameterTypes";
@@ -213,6 +215,7 @@
public static final String classSelectionGroup = "class-selection";
public static final String classConstant = "classConstant";
public static final String className = "className";
+ public static final String includeSubclasses = "includeSubclasses";
public static final String fieldName = "fieldName";
public static final String fieldTypeSelectionGroup = "field-type-selection";
public static final String fieldType = "fieldType";
diff --git a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepAnnoTestExtractedRulesBase.java b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepAnnoTestExtractedRulesBase.java
index 699009a..0add3e3 100644
--- a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepAnnoTestExtractedRulesBase.java
+++ b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepAnnoTestExtractedRulesBase.java
@@ -143,6 +143,7 @@
private final String conditionClass;
private final String conditionMembers;
private final String consequentClass;
+ private final boolean extendsConsequentClass;
private final String consequentMembers;
private ExpectedKeepRule(Builder builder) {
@@ -150,6 +151,7 @@
this.conditionClass = builder.conditionClass;
this.conditionMembers = builder.conditionMembers;
this.consequentClass = builder.consequentClass;
+ this.extendsConsequentClass = builder.extendsConsequentClass;
this.consequentMembers = builder.consequentMembers;
}
@@ -162,6 +164,7 @@
+ keepVariant
+ (r8 ? ",allowaccessmodification" : "")
+ " class "
+ + (extendsConsequentClass ? "** extends " : "")
+ consequentClass
+ " "
+ consequentMembers;
@@ -177,6 +180,7 @@
private String conditionClass;
private String conditionMembers;
private String consequentClass;
+ private boolean extendsConsequentClass = false;
private String consequentMembers;
private Builder() {}
@@ -203,6 +207,13 @@
public Builder setConsequentClass(Class<?> consequentClass) {
this.consequentClass = consequentClass.getTypeName();
+ this.extendsConsequentClass = false;
+ return this;
+ }
+
+ public Builder setConsequentExtendsClass(Class<?> consequentClass) {
+ this.consequentClass = consequentClass.getTypeName();
+ this.extendsConsequentClass = true;
return this;
}
diff --git a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionForInstantiationAnyArgsConstructorTest.java b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionForInstantiationAnyArgsConstructorTest.java
index 7418781..a6adf1b 100644
--- a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionForInstantiationAnyArgsConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionForInstantiationAnyArgsConstructorTest.java
@@ -75,7 +75,7 @@
}
private static ExpectedRules getExpectedRulesJava(
- Class<?> conditionClass, String conditionMembers) {
+ Class<?> conditionClass, boolean includeSubclasses, String conditionMembers) {
Consumer<ExpectedKeepRule.Builder> setCondition =
b -> b.setConditionClass(conditionClass).setConditionMembers(conditionMembers);
ExpectedRules.Builder builder =
@@ -86,12 +86,29 @@
.setConsequentClass(KeptClass.class)
.setConsequentMembers("{ void <init>(...); }")
.build());
+ if (includeSubclasses) {
+ builder.add(
+ ExpectedKeepRule.builder()
+ .apply(setCondition)
+ .setConsequentExtendsClass(KeptClass.class)
+ .setConsequentMembers("{ void <init>(...); }")
+ .build());
+ }
addConsequentKotlinMetadata(builder, b -> b.apply(setCondition));
addDefaultInitWorkaround(
builder, b -> b.apply(setCondition).setConsequentClass(KeptClass.class));
+ if (includeSubclasses) {
+ addDefaultInitWorkaround(
+ builder, b -> b.apply(setCondition).setConsequentExtendsClass(KeptClass.class));
+ }
return builder.build();
}
+ private static ExpectedRules getExpectedRulesJava(
+ Class<?> conditionClass, String conditionMembers) {
+ return getExpectedRulesJava(conditionClass, false, conditionMembers);
+ }
+
private static ExpectedRules getExpectedRulesKotlin(String conditionClass) {
return getExpectedRulesKotlin(conditionClass, null);
}
@@ -157,6 +174,22 @@
}
@Test
+ public void testIncludeSubclasses() throws Exception {
+ testExtractedRules(
+ ImmutableList.of(
+ setAnnotationOnMethod(
+ AnyConstructor.class,
+ MethodPredicate.onName("foo"),
+ builder ->
+ builder
+ .setAnnotationClass(
+ Reference.classFromClass(UsesReflectionToConstruct.class))
+ .setField("classConstant", KeptClass.class)
+ .setField("includeSubclasses", true))),
+ getExpectedRulesJava(AnyConstructor.class, true, "{ void foo(java.lang.Class); }"));
+ }
+
+ @Test
public void testAnyConstructorKotlin() throws Exception {
testExtractedRulesAndRunKotlin(
compilationResults,
diff --git a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionForInstantiationNoArgsConstructorTest.java b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionForInstantiationNoArgsConstructorTest.java
index 80e4d35..146385b 100644
--- a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionForInstantiationNoArgsConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionForInstantiationNoArgsConstructorTest.java
@@ -114,7 +114,7 @@
}
private static ExpectedRules getExpectedRulesJava(
- Class<?> conditionClass, String contitionMembers) {
+ Class<?> conditionClass, boolean includeSubclasses, String contitionMembers) {
Consumer<ExpectedKeepRule.Builder> setCondition =
b -> b.setConditionClass(conditionClass).setConditionMembers(contitionMembers);
@@ -126,12 +126,29 @@
.setConsequentClass(KeptClass.class)
.setConsequentMembers("{ void <init>(); }")
.build());
+ if (includeSubclasses) {
+ builder.add(
+ ExpectedKeepRule.builder()
+ .apply(setCondition)
+ .setConsequentExtendsClass(KeptClass.class)
+ .setConsequentMembers("{ void <init>(); }")
+ .build());
+ }
addConsequentKotlinMetadata(builder, b -> b.apply(setCondition));
addDefaultInitWorkaround(
builder, b -> b.apply(setCondition).setConsequentClass(KeptClass.class));
+ if (includeSubclasses) {
+ addDefaultInitWorkaround(
+ builder, b -> b.apply(setCondition).setConsequentExtendsClass(KeptClass.class));
+ }
return builder.build();
}
+ private static ExpectedRules getExpectedRulesJava(
+ Class<?> conditionClass, String contitionMembers) {
+ return getExpectedRulesJava(conditionClass, false, contitionMembers);
+ }
+
private static ExpectedRules getExpectedRulesKotlin(String conditionClass) {
Consumer<ExpectedKeepRule.Builder> setCondition =
b ->
@@ -292,6 +309,24 @@
}
@Test
+ public void testIncludeSubclasses() throws Exception {
+ testExtractedRules(
+ ImmutableList.of(
+ setAnnotationOnMethod(
+ OnlyNoArgsConstructorWithoutAnnotation.class,
+ MethodPredicate.onName("foo"),
+ builder ->
+ builder
+ .setAnnotationClass(
+ Reference.classFromClass(UsesReflectionToConstruct.class))
+ .setField("classConstant", KeptClass.class)
+ .setArray("parameterTypes")
+ .setField("includeSubclasses", true))),
+ getExpectedRulesJava(
+ OnlyNoArgsConstructorWithoutAnnotation.class, true, "{ void foo(java.lang.Class); }"));
+ }
+
+ @Test
public void testOnlyNoArgsConstructorKotlinUsingTransformer() throws Exception {
testExtractedRulesAndRunKotlin(
compilationResultsWithoutAnnotation,
diff --git a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionToAccessFieldTest.java b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionToAccessFieldTest.java
index 5ddca5d..a0446cd 100644
--- a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionToAccessFieldTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionToAccessFieldTest.java
@@ -65,7 +65,7 @@
}
private static ExpectedRules getExpectedRulesJava(
- Class<?> conditionClass, String... consequentMembers) {
+ Class<?> conditionClass, boolean includeSubclasses, String... consequentMembers) {
java.util.function.Consumer<ExpectedKeepRule.Builder> setCondition =
b ->
b.setConditionClass(conditionClass)
@@ -78,13 +78,30 @@
.setConsequentClass(KeptClass.class)
.setConsequentMembers(consequentMembers[i])
.build());
+ if (includeSubclasses) {
+ builder.add(
+ ExpectedKeepRule.builder()
+ .apply(setCondition)
+ .setConsequentExtendsClass(KeptClass.class)
+ .setConsequentMembers(consequentMembers[i])
+ .build());
+ }
}
addConsequentKotlinMetadata(builder, b -> b.apply(setCondition));
addDefaultInitWorkaround(
builder, b -> b.apply(setCondition).setConsequentClass(KeptClass.class));
+ if (includeSubclasses) {
+ addDefaultInitWorkaround(
+ builder, b -> b.apply(setCondition).setConsequentExtendsClass(KeptClass.class));
+ }
return builder.build();
}
+ private static ExpectedRules getExpectedRulesJava(
+ Class<?> conditionClass, String... consequentMembers) {
+ return getExpectedRulesJava(conditionClass, false, consequentMembers);
+ }
+
private static ExpectedRules getExpectedRulesKotlin(
String conditionClass,
String conditionMembers,
@@ -199,6 +216,24 @@
}
@Test
+ public void testIncludeSubclasses() throws Exception {
+ testExtractedRules(
+ ImmutableList.of(
+ setAnnotationOnMethod(
+ ClassWithAnnotation.class,
+ MethodPredicate.onName("foo"),
+ builder -> {
+ builder
+ .setAnnotationClass(
+ Reference.classFromClass(UsesReflectionToAccessField.class))
+ .setField("classConstant", KeptClass.class)
+ .setField("fieldName", "x")
+ .setField("includeSubclasses", true);
+ })),
+ getExpectedRulesJava(ClassWithAnnotation.class, true, "{ *** x; }"));
+ }
+
+ @Test
public void testAnyFieldTypeKotlin() throws Exception {
testExtractedRulesAndRunKotlin(
compilationResults,
diff --git a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionToAccessMethodTest.java b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionToAccessMethodTest.java
index 4e122d4..8755cca 100644
--- a/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionToAccessMethodTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/androidx/KeepUsesReflectionToAccessMethodTest.java
@@ -66,7 +66,7 @@
}
private static ExpectedRules getExpectedRulesJava(
- Class<?> conditionClass, String... consequentMembers) {
+ Class<?> conditionClass, boolean includeSubclasses, String... consequentMembers) {
Consumer<ExpectedKeepRule.Builder> setCondition =
b ->
b.setConditionClass(conditionClass)
@@ -79,13 +79,30 @@
.setConsequentClass(KeptClass.class)
.setConsequentMembers(consequentMembers[i])
.build());
+ if (includeSubclasses) {
+ builder.add(
+ ExpectedKeepRule.builder()
+ .apply(setCondition)
+ .setConsequentExtendsClass(KeptClass.class)
+ .setConsequentMembers(consequentMembers[i])
+ .build());
+ }
}
addConsequentKotlinMetadata(builder, b -> b.apply(setCondition));
addDefaultInitWorkaround(
builder, b -> b.apply(setCondition).setConsequentClass(KeptClass.class));
+ if (includeSubclasses) {
+ addDefaultInitWorkaround(
+ builder, b -> b.apply(setCondition).setConsequentExtendsClass(KeptClass.class));
+ }
return builder.build();
}
+ private static ExpectedRules getExpectedRulesJava(
+ Class<?> conditionClass, String... consequentMembers) {
+ return getExpectedRulesJava(conditionClass, false, consequentMembers);
+ }
+
private static ExpectedRules getExpectedRulesKotlin(
String conditionClass,
String conditionMembers,
@@ -204,6 +221,24 @@
}
@Test
+ public void testIncludeSubclasses() throws Exception {
+ testExtractedRules(
+ ImmutableList.of(
+ setAnnotationOnMethod(
+ ClassWithAnnotation.class,
+ MethodPredicate.onName("foo"),
+ builder ->
+ builder
+ .setAnnotationClass(
+ Reference.classFromClass(UsesReflectionToAccessMethod.class))
+ .setField("classConstant", KeptClass.class)
+ .setField("methodName", "m")
+ .setField("includeSubclasses", true))),
+ getExpectedRulesJava(
+ ClassWithAnnotation.class, true, "{ *** m(...); }", "{ *** m$default(...); }"));
+ }
+
+ @Test
public void testAnyReturnTypeAndAnyParametersKotlin() throws Exception {
testExtractedRulesAndRunKotlin(
compilationResults,
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 e060bbf..dc4e7a6 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
@@ -1878,6 +1878,13 @@
.addMember(className);
}
+ private Group createAndroidXSubclassSelection(Consumer<GroupMember> includeSubclassesConsumer) {
+ GroupMember includeSubclasses =
+ new GroupMember("includeSubclasses").defaultBooleanValue(false);
+ includeSubclassesConsumer.accept(includeSubclasses);
+ return new Group("subclass-selection").forAndroidX().addMember(includeSubclasses);
+ }
+
private Group createAndroidXParameterSelection(
Consumer<GroupMember> paramsConsumer, Consumer<GroupMember> paramTypeNamesConsumer) {
GroupMember params = new GroupMember("parameterTypes").defaultUnspecifiedArray();
@@ -1969,6 +1976,12 @@
g -> g.setDocTitle("Class to be instantiated."))
.generate(this);
println();
+ createAndroidXSubclassSelection(
+ g ->
+ g.setSuppressKotlinDefaultParameterOrder()
+ .setDocTitle("Also instantiate subclasses."))
+ .generate(this);
+ println();
createAndroidXParameterSelection(
g ->
g.setDocTitle(
@@ -2022,6 +2035,12 @@
+ " by reflection."))
.generate(this);
println();
+ createAndroidXSubclassSelection(
+ g ->
+ g.setSuppressKotlinDefaultParameterOrder()
+ .setDocTitle("Also access methods on subclasses."))
+ .generate(this);
+ println();
createMethodNameSelection().generate(this);
println();
createAndroidXParameterSelection(
@@ -2077,6 +2096,12 @@
+ " by reflection."))
.generate(this);
println();
+ createAndroidXSubclassSelection(
+ g ->
+ g.setSuppressKotlinDefaultParameterOrder()
+ .setDocTitle("Also access field on subclasses."))
+ .generate(this);
+ println();
createAndroidXFieldNameSelection().generate(this);
println();
createAndroidXFieldTypeSelection().generate(this);
@@ -2400,11 +2425,13 @@
private void forEachUsesReflectionToConstructGroup(Consumer<Group> fn) {
fn.accept(createAndroidXClassSelection(g -> {}, g -> {}));
+ fn.accept(createAndroidXSubclassSelection(g -> {}));
fn.accept(createAndroidXParameterSelection(g -> {}, g -> {}));
}
private void forEachUsesReflectionToAccessMethodGroup(Consumer<Group> fn) {
fn.accept(createAndroidXClassSelection(g -> {}, g -> {}));
+ fn.accept(createAndroidXSubclassSelection(g -> {}));
fn.accept(createMethodNameSelection());
fn.accept(createAndroidXParameterSelection(g -> {}, g -> {}));
fn.accept(createAndroidXReturnTypeSelection());
@@ -2412,6 +2439,7 @@
private void forEachUsesReflectionToAccessFieldGroup(Consumer<Group> fn) {
fn.accept(createAndroidXClassSelection(g -> {}, g -> {}));
+ fn.accept(createAndroidXSubclassSelection(g -> {}));
fn.accept(createAndroidXFieldNameSelection());
fn.accept(createAndroidXFieldTypeSelection());
}