[KeepAnno] Introduce a class pattern in the AST This replaces/unifies the name and instance-of properties on class-items and type-patterns. A follow-up should likely remove the instance-of from type-pattern and only allow it via a @ClassPattern annotation. Bug: b/350647134 Change-Id: I3313f2b6f75793fddb3195912a36f36ca4baa4fb
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java index e0ef6b5..81d3598 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/ClassNameParser.java
@@ -9,6 +9,7 @@ import com.android.tools.r8.keepanno.asm.PackageNameParser.PackageNameProperty; import com.android.tools.r8.keepanno.asm.TypeParser.TypeProperty; import com.android.tools.r8.keepanno.ast.AnnotationConstants.ClassNamePattern; +import com.android.tools.r8.keepanno.ast.KeepClassPattern; import com.android.tools.r8.keepanno.ast.KeepPackagePattern; import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern; import com.android.tools.r8.keepanno.ast.KeepTypePattern; @@ -46,20 +47,22 @@ TypeProperty.TYPE_NAME, name, value, - type -> setValue.accept(typeToClassType(type, getParsingContext().property(name)))); + type -> + setValue.accept(typeToClassNameType(type, getParsingContext().property(name)))); case CONSTANT: return new TypeParser(getParsingContext()) .tryProperty( TypeProperty.TYPE_CONSTANT, name, value, - type -> setValue.accept(typeToClassType(type, getParsingContext().property(name)))); + type -> + setValue.accept(typeToClassNameType(type, getParsingContext().property(name)))); default: return false; } } - KeepQualifiedClassNamePattern typeToClassType( + KeepQualifiedClassNamePattern typeToClassNameType( KeepTypePattern typePattern, PropertyParsingContext parsingContext) { return typePattern.apply( KeepQualifiedClassNamePattern::any, @@ -69,11 +72,7 @@ arrayTypePattern -> { throw parsingContext.error("Invalid use of array type where class type was expected"); }, - classNamePattern -> classNamePattern, - instanceOfPattern -> { - throw parsingContext.error( - "Invalid use of instance of type where class type was expected"); - }); + KeepClassPattern::getClassNamePattern); } @Override
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java index f81610e..85962be 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/TypeParser.java
@@ -8,6 +8,7 @@ import com.android.tools.r8.keepanno.asm.InstanceOfParser.InstanceOfProperties; import com.android.tools.r8.keepanno.asm.TypeParser.TypeProperty; import com.android.tools.r8.keepanno.ast.AnnotationConstants.TypePattern; +import com.android.tools.r8.keepanno.ast.KeepClassPattern; import com.android.tools.r8.keepanno.ast.KeepTypePattern; import com.android.tools.r8.keepanno.ast.ParsingContext; import com.android.tools.r8.keepanno.ast.ParsingContext.AnnotationParsingContext; @@ -71,7 +72,8 @@ ClassNameProperty.PATTERN, name, descriptor, - value -> setValue.accept(KeepTypePattern.fromClass(value))); + value -> + setValue.accept(KeepTypePattern.fromClass(KeepClassPattern.fromName(value)))); } case INSTANCE_OF_PATTERN: { @@ -80,7 +82,10 @@ InstanceOfProperties.PATTERN, name, descriptor, - value -> setValue.accept(KeepTypePattern.fromInstanceOf(value))); + value -> + setValue.accept( + KeepTypePattern.fromClass( + KeepClassPattern.builder().setInstanceOfPattern(value).build()))); } default: return null;
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepAnnotationPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepAnnotationPattern.java index 13d4df3..830417d 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepAnnotationPattern.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepAnnotationPattern.java
@@ -46,7 +46,7 @@ public AnnotationPattern.Builder buildProto() { AnnotationPattern.Builder builder = AnnotationPattern.newBuilder(); - builder.setName(namePattern.buildProto()); + namePattern.buildProtoIfNotAny(builder::setName); if (retentionPolicies == RUNTIME_RETENTION_MASK) { builder.setRetention(AnnotationRetention.RETENTION_RUNTIME); } else if (retentionPolicies == CLASS_RETENTION_MASK) {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepArrayTypePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepArrayTypePattern.java index 0c86c6c..23e2c2e 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepArrayTypePattern.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepArrayTypePattern.java
@@ -52,10 +52,7 @@ array -> { throw new KeepEdgeException("Unexpected nested array"); }, - KeepQualifiedClassNamePattern::getExactDescriptor, - instanceOf -> { - throw new KeepEdgeException("No descriptor exists for instanceOf array"); - }); + clazz -> clazz.getClassNamePattern().getExactDescriptor()); } @Override
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemPattern.java index 4ccfad3..d833da0 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemPattern.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassItemPattern.java
@@ -25,49 +25,48 @@ public ClassItemPattern.Builder buildClassProto() { ClassItemPattern.Builder builder = ClassItemPattern.newBuilder(); + classPattern.buildProtoIfNotAny(builder::setClassPattern); KeepSpecUtils.buildAnnotatedByProto(annotatedByPattern, builder::setAnnotatedBy); - instanceOfPattern.buildProto(builder::setInstanceOf); - return builder.setClassName(classNamePattern.buildProto()); + return builder; } public static class Builder { - private KeepQualifiedClassNamePattern classNamePattern = KeepQualifiedClassNamePattern.any(); - private KeepInstanceOfPattern instanceOfPattern = KeepInstanceOfPattern.any(); + private KeepClassPattern.Builder classPattern = KeepClassPattern.builder(); private OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern = OptionalPattern.absent(); private Builder() {} public Builder applyProto(ClassItemPattern protoItem) { - assert classNamePattern.isAny(); - if (protoItem.hasClassName()) { - setClassNamePattern(KeepQualifiedClassNamePattern.fromProto(protoItem.getClassName())); + assert classPattern.build().isAny(); + if (protoItem.hasClassPattern()) { + setClassPattern(KeepClassPattern.fromProto(protoItem.getClassPattern())); } assert annotatedByPattern.isAbsent(); if (protoItem.hasAnnotatedBy()) { setAnnotatedByPattern(KeepSpecUtils.annotatedByFromProto(protoItem.getAnnotatedBy())); } - assert instanceOfPattern.isAny(); - if (protoItem.hasInstanceOf()) { - setInstanceOfPattern(KeepInstanceOfPattern.fromProto(protoItem.getInstanceOf())); - } return this; } public Builder copyFrom(KeepClassItemPattern pattern) { - return setClassNamePattern(pattern.getClassNamePattern()) - .setInstanceOfPattern(pattern.getInstanceOfPattern()) + return setClassPattern(pattern.getClassPattern()) .setAnnotatedByPattern(pattern.getAnnotatedByPattern()); } + public Builder setClassPattern(KeepClassPattern classPattern) { + this.classPattern = KeepClassPattern.builder().copyFrom(classPattern); + return this; + } + public Builder setClassNamePattern(KeepQualifiedClassNamePattern classNamePattern) { - this.classNamePattern = classNamePattern; + classPattern.setClassNamePattern(classNamePattern); return this; } public Builder setInstanceOfPattern(KeepInstanceOfPattern instanceOfPattern) { - this.instanceOfPattern = instanceOfPattern; + classPattern.setInstanceOfPattern(instanceOfPattern); return this; } @@ -79,23 +78,19 @@ } public KeepClassItemPattern build() { - return new KeepClassItemPattern(classNamePattern, instanceOfPattern, annotatedByPattern); + return new KeepClassItemPattern(classPattern.build(), annotatedByPattern); } } - private final KeepQualifiedClassNamePattern classNamePattern; - private final KeepInstanceOfPattern instanceOfPattern; + private final KeepClassPattern classPattern; private final OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern; public KeepClassItemPattern( - KeepQualifiedClassNamePattern classNamePattern, - KeepInstanceOfPattern instanceOfPattern, + KeepClassPattern classPattern, OptionalPattern<KeepQualifiedClassNamePattern> annotatedByPattern) { - assert classNamePattern != null; - assert instanceOfPattern != null; + assert classPattern != null; assert annotatedByPattern != null; - this.classNamePattern = classNamePattern; - this.instanceOfPattern = instanceOfPattern; + this.classPattern = classPattern; this.annotatedByPattern = annotatedByPattern; } @@ -109,12 +104,16 @@ return Collections.emptyList(); } + public KeepClassPattern getClassPattern() { + return classPattern; + } + public KeepQualifiedClassNamePattern getClassNamePattern() { - return classNamePattern; + return classPattern.getClassNamePattern(); } public KeepInstanceOfPattern getInstanceOfPattern() { - return instanceOfPattern; + return classPattern.getInstanceOfPattern(); } public OptionalPattern<KeepQualifiedClassNamePattern> getAnnotatedByPattern() { @@ -122,7 +121,7 @@ } public boolean isAny() { - return classNamePattern.isAny() && instanceOfPattern.isAny() && annotatedByPattern.isAbsent(); + return classPattern.isAny() && annotatedByPattern.isAbsent(); } @Override @@ -134,25 +133,22 @@ return false; } KeepClassItemPattern that = (KeepClassItemPattern) obj; - return classNamePattern.equals(that.classNamePattern) - && instanceOfPattern.equals(that.instanceOfPattern) + return classPattern.equals(that.classPattern) && annotatedByPattern.equals(that.annotatedByPattern); } @Override public int hashCode() { - return Objects.hash(classNamePattern, instanceOfPattern, annotatedByPattern); + return Objects.hash(classPattern, annotatedByPattern); } @Override public String toString() { return "KeepClassItemPattern" + "{ class=" - + classNamePattern + + classPattern + ", annotated-by=" + annotatedByPattern - + ", instance-of=" - + instanceOfPattern + '}'; } }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassPattern.java new file mode 100644 index 0000000..dee7f6b --- /dev/null +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepClassPattern.java
@@ -0,0 +1,127 @@ +// 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.ast; + +import com.android.tools.r8.keepanno.proto.KeepSpecProtos.ClassPattern; +import java.util.Objects; +import java.util.function.Consumer; + +public class KeepClassPattern { + + private static final KeepClassPattern ANY = + new KeepClassPattern(KeepQualifiedClassNamePattern.any(), KeepInstanceOfPattern.any()); + + public static KeepClassPattern any() { + return ANY; + } + + public static KeepClassPattern fromName(KeepQualifiedClassNamePattern namePattern) { + return builder().setClassNamePattern(namePattern).build(); + } + + public static KeepClassPattern fromProto(ClassPattern proto) { + return builder().applyProto(proto).build(); + } + + public static KeepClassPattern exactFromDescriptor(String typeDescriptor) { + return fromName(KeepQualifiedClassNamePattern.exactFromDescriptor(typeDescriptor)); + } + + private final KeepQualifiedClassNamePattern classNamePattern; + private final KeepInstanceOfPattern instanceOfPattern; + + public KeepClassPattern( + KeepQualifiedClassNamePattern classNamePattern, KeepInstanceOfPattern instanceOfPattern) { + this.classNamePattern = classNamePattern; + this.instanceOfPattern = instanceOfPattern; + } + + public boolean isAny() { + return classNamePattern.isAny() && instanceOfPattern.isAny(); + } + + public KeepQualifiedClassNamePattern getClassNamePattern() { + return classNamePattern; + } + + public KeepInstanceOfPattern getInstanceOfPattern() { + return instanceOfPattern; + } + + public static Builder builder() { + return new Builder(); + } + + public void buildProtoIfNotAny(Consumer<ClassPattern.Builder> setter) { + if (!isAny()) { + setter.accept(buildProto()); + } + } + + public ClassPattern.Builder buildProto() { + ClassPattern.Builder builder = ClassPattern.newBuilder(); + classNamePattern.buildProtoIfNotAny(builder::setClassName); + instanceOfPattern.buildProtoIfNotAny(builder::setInstanceOf); + return builder; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof KeepClassPattern)) { + return false; + } + KeepClassPattern other = (KeepClassPattern) obj; + return classNamePattern.equals(other.classNamePattern) + && instanceOfPattern.equals(other.instanceOfPattern); + } + + @Override + public int hashCode() { + return Objects.hash(classNamePattern, instanceOfPattern); + } + + public static class Builder { + + private KeepQualifiedClassNamePattern classNamePattern = KeepQualifiedClassNamePattern.any(); + private KeepInstanceOfPattern instanceOfPattern = KeepInstanceOfPattern.any(); + + public Builder applyProto(ClassPattern protoItem) { + assert classNamePattern.isAny(); + if (protoItem.hasClassName()) { + setClassNamePattern(KeepQualifiedClassNamePattern.fromProto(protoItem.getClassName())); + } + assert instanceOfPattern.isAny(); + if (protoItem.hasInstanceOf()) { + setInstanceOfPattern(KeepInstanceOfPattern.fromProto(protoItem.getInstanceOf())); + } + return this; + } + + public Builder copyFrom(KeepClassPattern pattern) { + return setClassNamePattern(pattern.getClassNamePattern()) + .setInstanceOfPattern(pattern.getInstanceOfPattern()); + } + + public Builder setClassNamePattern(KeepQualifiedClassNamePattern classNamePattern) { + this.classNamePattern = classNamePattern; + return this; + } + + public Builder setInstanceOfPattern(KeepInstanceOfPattern instanceOfPattern) { + this.instanceOfPattern = instanceOfPattern; + return this; + } + + public KeepClassPattern build() { + if (classNamePattern.isAny() && instanceOfPattern.isAny()) { + return any(); + } + return new KeepClassPattern(classNamePattern, instanceOfPattern); + } + } +}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldAccessPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldAccessPattern.java index b9bf204..2db295e 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldAccessPattern.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepFieldAccessPattern.java
@@ -76,8 +76,8 @@ } MemberAccessField.Builder builder = MemberAccessField.newBuilder(); buildGeneralProto(builder::setGeneralAccess); - volatilePattern.buildProto(builder::setVolatilePattern); - transientPattern.buildProto(builder::setTransientPattern); + volatilePattern.buildProtoIfNotAny(builder::setVolatilePattern); + transientPattern.buildProtoIfNotAny(builder::setTransientPattern); callback.accept(builder); }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepInstanceOfPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepInstanceOfPattern.java index 114ada8..72da0d0 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepInstanceOfPattern.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepInstanceOfPattern.java
@@ -17,14 +17,12 @@ return builder().applyProto(proto).build(); } - public void buildProto(Consumer<InstanceOfPattern.Builder> setter) { - if (isAny()) { - return; + public void buildProtoIfNotAny(Consumer<InstanceOfPattern.Builder> setter) { + if (!isAny()) { + InstanceOfPattern.Builder builder = InstanceOfPattern.newBuilder(); + getClassNamePattern().buildProtoIfNotAny(builder::setClassName); + setter.accept(builder.setInclusive(isInclusive())); } - setter.accept( - InstanceOfPattern.newBuilder() - .setInclusive(isInclusive()) - .setClassName(getClassNamePattern().buildProto())); } public static class Builder {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberAccessPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberAccessPattern.java index 487ddc8..0446b39 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberAccessPattern.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMemberAccessPattern.java
@@ -103,9 +103,9 @@ } builder.setAccessVisibility(visibilityBuilder.build()); } - staticPattern.buildProto(builder::setStaticPattern); - finalPattern.buildProto(builder::setFinalPattern); - syntheticPattern.buildProto(builder::setSyntheticPattern); + staticPattern.buildProtoIfNotAny(builder::setStaticPattern); + finalPattern.buildProtoIfNotAny(builder::setFinalPattern); + syntheticPattern.buildProtoIfNotAny(builder::setSyntheticPattern); callback.accept(builder); }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java index 5b3a1bd..2c14d18 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepMethodAccessPattern.java
@@ -65,11 +65,11 @@ } MemberAccessMethod.Builder builder = MemberAccessMethod.newBuilder(); buildGeneralProto(builder::setGeneralAccess); - synchronizedPattern.buildProto(builder::setSynchronizedPattern); - bridgePattern.buildProto(builder::setBridgePattern); - nativePattern.buildProto(builder::setNativePattern); - abstractPattern.buildProto(builder::setAbstractPattern); - strictFpPattern.buildProto(builder::setStrictFpPattern); + synchronizedPattern.buildProtoIfNotAny(builder::setSynchronizedPattern); + bridgePattern.buildProtoIfNotAny(builder::setBridgePattern); + nativePattern.buildProtoIfNotAny(builder::setNativePattern); + abstractPattern.buildProtoIfNotAny(builder::setAbstractPattern); + strictFpPattern.buildProtoIfNotAny(builder::setStrictFpPattern); callback.accept(builder); }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java index 94445bb..fc1a44a 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepQualifiedClassNamePattern.java
@@ -5,6 +5,7 @@ import com.android.tools.r8.keepanno.proto.KeepSpecProtos.ClassNamePattern; import java.util.Objects; +import java.util.function.Consumer; public final class KeepQualifiedClassNamePattern { @@ -49,11 +50,12 @@ return KeepQualifiedClassNamePattern.builder().applyProto(clazz).build(); } - public ClassNamePattern.Builder buildProto() { - ClassNamePattern.Builder builder = ClassNamePattern.newBuilder(); - return builder - .setPackage(packagePattern.buildProto()) - .setUnqualifiedName(namePattern.buildProto()); + public void buildProtoIfNotAny(Consumer<ClassNamePattern.Builder> setter) { + if (!isAny()) { + ClassNamePattern.Builder builder = ClassNamePattern.newBuilder(); + builder.setPackage(packagePattern.buildProto()).setUnqualifiedName(namePattern.buildProto()); + setter.accept(builder); + } } public static class Builder {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepSpecUtils.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepSpecUtils.java index 5a76764..51da9a9 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepSpecUtils.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepSpecUtils.java
@@ -49,7 +49,11 @@ Consumer<AnnotatedByPattern.Builder> callback) { // If the annotated-by pattern is absent then no restrictions are present, and we don't set it. if (pattern.isPresent()) { - callback.accept(AnnotatedByPattern.newBuilder().setName(pattern.get().buildProto())); + // We must set a pattern here even if the annotation is "any" as that implies that the item + // must be annotated by some annotation. + AnnotatedByPattern.Builder builder = AnnotatedByPattern.newBuilder(); + pattern.get().buildProtoIfNotAny(builder::setName); + callback.accept(builder); } }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java index 15cfef7..a911ca6 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/KeepTypePattern.java
@@ -25,14 +25,10 @@ return new ArrayType(type); } - public static KeepTypePattern fromClass(KeepQualifiedClassNamePattern type) { + public static KeepTypePattern fromClass(KeepClassPattern type) { return new ClassType(type); } - public static KeepTypePattern fromInstanceOf(KeepInstanceOfPattern pattern) { - return new KeepInstanceOf(pattern); - } - public static KeepTypePattern fromDescriptor(String typeDescriptor) { char c = typeDescriptor.charAt(0); if (c == 'L') { @@ -40,7 +36,7 @@ if (typeDescriptor.charAt(end) != ';') { throw new KeepEdgeException("Invalid type descriptor: " + typeDescriptor); } - return fromClass(KeepQualifiedClassNamePattern.exactFromDescriptor(typeDescriptor)); + return fromClass(KeepClassPattern.exactFromDescriptor(typeDescriptor)); } if (c == '[') { int dim = 1; @@ -61,21 +57,18 @@ Supplier<T> onAny, Function<KeepPrimitiveTypePattern, T> onPrimitive, Function<KeepArrayTypePattern, T> onArray, - Function<KeepQualifiedClassNamePattern, T> onClass, - Function<KeepInstanceOfPattern, T> onInstanceOf); + Function<KeepClassPattern, T> onClass); public final void match( Runnable onAny, Consumer<KeepPrimitiveTypePattern> onPrimitive, Consumer<KeepArrayTypePattern> onArray, - Consumer<KeepQualifiedClassNamePattern> onClass, - Consumer<KeepInstanceOfPattern> onInstanceOf) { + Consumer<KeepClassPattern> onClass) { apply( AstUtils.toVoidSupplier(onAny), AstUtils.toVoidFunction(onPrimitive), AstUtils.toVoidFunction(onArray), - AstUtils.toVoidFunction(onClass), - AstUtils.toVoidFunction(onInstanceOf)); + AstUtils.toVoidFunction(onClass)); } public boolean isAny() { @@ -95,8 +88,7 @@ Supplier<T> onAny, Function<KeepPrimitiveTypePattern, T> onPrimitive, Function<KeepArrayTypePattern, T> onArray, - Function<KeepQualifiedClassNamePattern, T> onClass, - Function<KeepInstanceOfPattern, T> onInstanceOf) { + Function<KeepClassPattern, T> onClass) { return onAny.get(); } @@ -161,16 +153,15 @@ Supplier<T> onAny, Function<KeepPrimitiveTypePattern, T> onPrimitive, Function<KeepArrayTypePattern, T> onArray, - Function<KeepQualifiedClassNamePattern, T> onClass, - Function<KeepInstanceOfPattern, T> onInstanceOf) { + Function<KeepClassPattern, T> onClass) { return onPrimitive.apply(type); } } private static class ClassType extends KeepTypePattern { - private final KeepQualifiedClassNamePattern type; + private final KeepClassPattern type; - public ClassType(KeepQualifiedClassNamePattern type) { + public ClassType(KeepClassPattern type) { this.type = type; } @@ -179,8 +170,7 @@ Supplier<T> onAny, Function<KeepPrimitiveTypePattern, T> onPrimitive, Function<KeepArrayTypePattern, T> onArray, - Function<KeepQualifiedClassNamePattern, T> onClass, - Function<KeepInstanceOfPattern, T> onInstanceOf) { + Function<KeepClassPattern, T> onClass) { return onClass.apply(type); } @@ -219,8 +209,7 @@ Supplier<T> onAny, Function<KeepPrimitiveTypePattern, T> onPrimitive, Function<KeepArrayTypePattern, T> onArray, - Function<KeepQualifiedClassNamePattern, T> onClass, - Function<KeepInstanceOfPattern, T> onInstanceOf) { + Function<KeepClassPattern, T> onClass) { return onArray.apply(type); } @@ -247,24 +236,6 @@ } } - private static class KeepInstanceOf extends KeepTypePattern { - private final KeepInstanceOfPattern instanceOf; - - private KeepInstanceOf(KeepInstanceOfPattern instanceOf) { - this.instanceOf = instanceOf; - } - - @Override - public <T> T apply( - Supplier<T> onAny, - Function<KeepPrimitiveTypePattern, T> onPrimitive, - Function<KeepArrayTypePattern, T> onArray, - Function<KeepQualifiedClassNamePattern, T> onClass, - Function<KeepInstanceOfPattern, T> onInstanceOf) { - return onInstanceOf.apply(instanceOf); - } - } - public static KeepTypePattern fromProto(TypePattern typeProto) { if (typeProto.hasPrimitive()) { return KeepTypePattern.fromPrimitive( @@ -273,13 +244,8 @@ if (typeProto.hasArray()) { return KeepTypePattern.fromArray(KeepArrayTypePattern.fromProto(typeProto.getArray())); } - if (typeProto.hasClazz()) { - return KeepTypePattern.fromClass( - KeepQualifiedClassNamePattern.fromProto(typeProto.getClazz())); - } - if (typeProto.hasInstanceOf()) { - return KeepTypePattern.fromInstanceOf( - KeepInstanceOfPattern.fromProto(typeProto.getInstanceOf())); + if (typeProto.hasClassPattern()) { + return KeepTypePattern.fromClass(KeepClassPattern.fromProto(typeProto.getClassPattern())); } return KeepTypePattern.any(); } @@ -292,17 +258,7 @@ }, primitive -> builder.setPrimitive(primitive.buildProto()), array -> builder.setArray(array.buildProto()), - clazz -> builder.setClazz(clazz.buildProto()), - instanceOf -> { - if (instanceOf.isAny()) { - // Note that an "any" instance-of pattern should match any class-type - // TODO(b/350647134): This should become evident when introducing a class-pattern. - // When doing so, consider also if/how to match a general reference type. - builder.setClazz(KeepQualifiedClassNamePattern.any().buildProto()); - } else { - instanceOf.buildProto(builder::setInstanceOf); - } - }); + clazz -> builder.setClassPattern(clazz.buildProto())); return builder; } }
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/ModifierPattern.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/ModifierPattern.java index 1afe19e..0d8ef29 100644 --- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/ModifierPattern.java +++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/ModifierPattern.java
@@ -73,7 +73,7 @@ return System.identityHashCode(this); } - public void buildProto(Consumer<KeepSpecProtos.ModifierPattern.Builder> callback) { + public void buildProtoIfNotAny(Consumer<KeepSpecProtos.ModifierPattern.Builder> callback) { if (isOnlyPositive()) { callback.accept(KeepSpecProtos.ModifierPattern.newBuilder().setValue(true)); } else if (isOnlyNegative()) {
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 3d3e034..9289894 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
@@ -222,13 +222,13 @@ printer::appendTripleStar, primitivePattern -> printPrimitiveType(printer, primitivePattern), arrayTypePattern -> printArrayType(printer, arrayTypePattern), - classTypePattern -> printClassName(classTypePattern, printer), - instanceOfPattern -> printInstanceOf(instanceOfPattern, printer)); - } - - private static RulePrinter printInstanceOf( - KeepInstanceOfPattern instanceOfPattern, RulePrinter printer) { - throw new Unimplemented(); + classTypePattern -> { + if (!classTypePattern.getInstanceOfPattern().isAny()) { + throw new KeepEdgeException( + "Type patterns with instance-of are not supported in rule extraction"); + } + return printClassName(classTypePattern.getClassNamePattern(), printer); + }); } private static RulePrinter printPrimitiveType(
diff --git a/src/keepanno/proto/keepspec.proto b/src/keepanno/proto/keepspec.proto index 4dae6b1..9760fe4 100644 --- a/src/keepanno/proto/keepspec.proto +++ b/src/keepanno/proto/keepspec.proto
@@ -158,9 +158,13 @@ } message ClassItemPattern { + optional ClassPattern class_pattern = 1; + optional AnnotatedByPattern annotated_by = 2; +} + +message ClassPattern { optional ClassNamePattern class_name = 1; optional InstanceOfPattern instance_of = 2; - optional AnnotatedByPattern annotated_by = 3; } message InstanceOfPattern { @@ -300,8 +304,7 @@ // Unset type denotes any type. TypePatternPrimitive primitive = 1; TypePatternArray array = 2; - ClassNamePattern clazz = 3; - InstanceOfPattern instance_of = 4; + ClassPattern class_pattern = 3; } }
diff --git a/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcherPredicates.java b/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcherPredicates.java index dfe3f51..9587d94 100644 --- a/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcherPredicates.java +++ b/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcherPredicates.java
@@ -23,6 +23,7 @@ import com.android.tools.r8.keepanno.ast.KeepAnnotationPattern; import com.android.tools.r8.keepanno.ast.KeepArrayTypePattern; import com.android.tools.r8.keepanno.ast.KeepClassItemPattern; +import com.android.tools.r8.keepanno.ast.KeepClassPattern; import com.android.tools.r8.keepanno.ast.KeepFieldAccessPattern; import com.android.tools.r8.keepanno.ast.KeepFieldPattern; import com.android.tools.r8.keepanno.ast.KeepInstanceOfPattern; @@ -296,8 +297,13 @@ () -> true, p -> matchesPrimitiveType(type, p), p -> matchesArrayType(type, p, appInfo), - p -> matchesClassType(type, p), - p -> matchesInstanceOfPattern(type, p, appInfo)); + p -> matchesClassPattern(type, p, appInfo)); + } + + public boolean matchesClassPattern( + DexType type, KeepClassPattern pattern, AppInfoWithClassHierarchy appInfo) { + return matchesClassType(type, pattern.getClassNamePattern()) + && matchesInstanceOfPattern(type, pattern.getInstanceOfPattern(), appInfo); } public boolean matchesClassType(DexType type, KeepQualifiedClassNamePattern pattern) {