| // 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.ast.AnnotationConstants.Constraints; |
| import com.android.tools.r8.keepanno.ast.KeepOptions.KeepOption; |
| import java.util.Set; |
| |
| public abstract class KeepConstraint { |
| |
| @Override |
| public String toString() { |
| String typeName = getClass().getTypeName(); |
| return typeName.substring(typeName.lastIndexOf('$') + 1); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| return this == obj; |
| } |
| |
| @Override |
| public int hashCode() { |
| return System.identityHashCode(this); |
| } |
| |
| public abstract void accept(KeepConstraintVisitor visitor); |
| |
| public abstract String getEnumValue(); |
| |
| public KeepAnnotationPattern asAnnotationPattern() { |
| return null; |
| } |
| |
| public abstract void convertToDisallowKeepOptions(KeepOptions.Builder builder); |
| |
| public void addRequiredKeepAttributes(Set<KeepAttribute> attributes) { |
| // Common case is no required attributes. |
| } |
| |
| public final boolean validForClass() { |
| return !isMethodOnly() && !isFieldOnly(); |
| } |
| |
| public final boolean validForMethod() { |
| return !isClassOnly() && !isFieldOnly(); |
| } |
| |
| public final boolean validForField() { |
| return !isClassOnly() && !isMethodOnly(); |
| } |
| |
| boolean isClassOnly() { |
| return false; |
| } |
| |
| boolean isMethodOnly() { |
| return false; |
| } |
| |
| boolean isFieldOnly() { |
| return false; |
| } |
| |
| public static Lookup lookup() { |
| return Lookup.INSTANCE; |
| } |
| |
| public static final class Lookup extends KeepConstraint { |
| |
| private static final Lookup INSTANCE = new Lookup(); |
| |
| private Lookup() {} |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.LOOKUP; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onLookup(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| builder.add(KeepOption.SHRINKING); |
| } |
| } |
| |
| public static Name name() { |
| return Name.INSTANCE; |
| } |
| |
| public static final class Name extends KeepConstraint { |
| |
| private static final Name INSTANCE = new Name(); |
| |
| private Name() {} |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.NAME; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onName(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| builder.add(KeepOption.OBFUSCATING); |
| } |
| } |
| |
| public static VisibilityRelax visibilityRelax() { |
| return VisibilityRelax.INSTANCE; |
| } |
| |
| public static final class VisibilityRelax extends KeepConstraint { |
| |
| private static final VisibilityRelax INSTANCE = new VisibilityRelax(); |
| |
| private VisibilityRelax() {} |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.VISIBILITY_RELAX; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onVisibilityRelax(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| // The compiler currently satisfies that access is never restricted. |
| } |
| } |
| |
| public static VisibilityRestrict visibilityRestrict() { |
| return VisibilityRestrict.INSTANCE; |
| } |
| |
| public static final class VisibilityRestrict extends KeepConstraint { |
| |
| private static final VisibilityRestrict INSTANCE = new VisibilityRestrict(); |
| |
| private VisibilityRestrict() {} |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.VISIBILITY_RESTRICT; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onVisibilityRestrict(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| // We don't have directional rules so this prohibits any modification. |
| builder.add(KeepOption.ACCESS_MODIFICATION); |
| } |
| } |
| |
| public static NeverInline neverInline() { |
| return NeverInline.INSTANCE; |
| } |
| |
| public static final class NeverInline extends KeepConstraint { |
| |
| private static final NeverInline INSTANCE = new NeverInline(); |
| |
| private NeverInline() {} |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.NEVER_INLINE; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onNeverInline(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| builder.add(KeepOption.OPTIMIZING); |
| } |
| } |
| |
| public static ClassInstantiate classInstantiate() { |
| return ClassInstantiate.INSTANCE; |
| } |
| |
| public static final class ClassInstantiate extends KeepConstraint { |
| |
| private static final ClassInstantiate INSTANCE = new ClassInstantiate(); |
| |
| private ClassInstantiate() {} |
| |
| @Override |
| boolean isClassOnly() { |
| return true; |
| } |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.CLASS_INSTANTIATE; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onClassInstantiate(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| builder.add(KeepOption.OPTIMIZING); |
| } |
| } |
| |
| public static ClassOpenHierarchy classOpenHierarchy() { |
| return ClassOpenHierarchy.INSTANCE; |
| } |
| |
| public static final class ClassOpenHierarchy extends KeepConstraint { |
| |
| private static final ClassOpenHierarchy INSTANCE = new ClassOpenHierarchy(); |
| |
| private ClassOpenHierarchy() {} |
| |
| @Override |
| boolean isClassOnly() { |
| return true; |
| } |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.CLASS_OPEN_HIERARCHY; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onClassOpenHierarchy(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| builder.add(KeepOption.OPTIMIZING); |
| } |
| } |
| |
| public static MethodInvoke methodInvoke() { |
| return MethodInvoke.INSTANCE; |
| } |
| |
| public static final class MethodInvoke extends KeepConstraint { |
| |
| private static final MethodInvoke INSTANCE = new MethodInvoke(); |
| |
| private MethodInvoke() {} |
| |
| @Override |
| boolean isMethodOnly() { |
| return true; |
| } |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.METHOD_INVOKE; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onMethodInvoke(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| builder.add(KeepOption.OPTIMIZING); |
| } |
| } |
| |
| public static MethodReplace methodReplace() { |
| return MethodReplace.INSTANCE; |
| } |
| |
| public static final class MethodReplace extends KeepConstraint { |
| |
| private static final MethodReplace INSTANCE = new MethodReplace(); |
| |
| private MethodReplace() {} |
| |
| @Override |
| boolean isMethodOnly() { |
| return true; |
| } |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.METHOD_REPLACE; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onMethodReplace(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| builder.add(KeepOption.OPTIMIZING); |
| } |
| } |
| |
| public static FieldGet fieldGet() { |
| return FieldGet.INSTANCE; |
| } |
| |
| public static final class FieldGet extends KeepConstraint { |
| |
| private static final FieldGet INSTANCE = new FieldGet(); |
| |
| private FieldGet() {} |
| |
| @Override |
| boolean isFieldOnly() { |
| return true; |
| } |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.FIELD_GET; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onFieldGet(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| builder.add(KeepOption.OPTIMIZING); |
| } |
| } |
| |
| public static FieldSet fieldSet() { |
| return FieldSet.INSTANCE; |
| } |
| |
| public static final class FieldSet extends KeepConstraint { |
| |
| private static final FieldSet INSTANCE = new FieldSet(); |
| |
| private FieldSet() {} |
| |
| @Override |
| boolean isFieldOnly() { |
| return true; |
| } |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.FIELD_SET; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onFieldSet(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| builder.add(KeepOption.OPTIMIZING); |
| } |
| } |
| |
| public static FieldReplace fieldReplace() { |
| return FieldReplace.INSTANCE; |
| } |
| |
| public static final class FieldReplace extends KeepConstraint { |
| |
| private static final FieldReplace INSTANCE = new FieldReplace(); |
| |
| private FieldReplace() {} |
| |
| @Override |
| boolean isFieldOnly() { |
| return true; |
| } |
| |
| @Override |
| public String getEnumValue() { |
| return Constraints.FIELD_REPLACE; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onFieldReplace(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| builder.add(KeepOption.OPTIMIZING); |
| } |
| } |
| |
| public static Annotation annotationsAll() { |
| return Annotation.ALL_INSTANCE; |
| } |
| |
| public static Annotation annotationsAllWithRuntimeRetention() { |
| return Annotation.ALL_WITH_RUNTIME_RETENTION_INSTANCE; |
| } |
| |
| public static Annotation annotationsAllWithClassRetention() { |
| return Annotation.ALL_WITH_CLASS_RETENTION_INSTANCE; |
| } |
| |
| public static Annotation annotation(KeepAnnotationPattern pattern) { |
| if (pattern.isAny()) { |
| return annotationsAll(); |
| } |
| if (pattern.isAnyWithRuntimeRetention()) { |
| return annotationsAllWithRuntimeRetention(); |
| } |
| if (pattern.isAnyWithClassRetention()) { |
| return annotationsAllWithClassRetention(); |
| } |
| return new Annotation(pattern); |
| } |
| |
| public static final class Annotation extends KeepConstraint { |
| |
| private static final Annotation ALL_INSTANCE = new Annotation(KeepAnnotationPattern.any()); |
| |
| private static final Annotation ALL_WITH_RUNTIME_RETENTION_INSTANCE = |
| new Annotation(KeepAnnotationPattern.anyWithRuntimeRetention()); |
| |
| private static final Annotation ALL_WITH_CLASS_RETENTION_INSTANCE = |
| new Annotation(KeepAnnotationPattern.anyWithClassRetention()); |
| |
| private final KeepAnnotationPattern annotationPattern; |
| |
| private Annotation(KeepAnnotationPattern annotationPattern) { |
| assert annotationPattern != null; |
| this.annotationPattern = annotationPattern; |
| } |
| |
| @Override |
| public KeepAnnotationPattern asAnnotationPattern() { |
| return annotationPattern; |
| } |
| |
| @Override |
| public String getEnumValue() { |
| // The annotation constraints cannot be represented by an enum value. |
| return null; |
| } |
| |
| @Override |
| public void accept(KeepConstraintVisitor visitor) { |
| visitor.onAnnotation(this); |
| } |
| |
| @Override |
| public void convertToDisallowKeepOptions(KeepOptions.Builder builder) { |
| // The annotation constraint only implies that annotations should remain, no restrictions |
| // are on the item otherwise. Also, we can't restrict the rule to just the annotations being |
| // constrained in the legacy rules. |
| builder.add(KeepOption.ANNOTATION_REMOVAL); |
| } |
| |
| @Override |
| public void addRequiredKeepAttributes(Set<KeepAttribute> attributes) { |
| if (annotationPattern.includesRuntimeRetention()) { |
| attributes.add(KeepAttribute.RUNTIME_VISIBLE_ANNOTATIONS); |
| attributes.add(KeepAttribute.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS); |
| attributes.add(KeepAttribute.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); |
| } |
| if (annotationPattern.includesClassRetention()) { |
| attributes.add(KeepAttribute.RUNTIME_INVISIBLE_ANNOTATIONS); |
| attributes.add(KeepAttribute.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS); |
| attributes.add(KeepAttribute.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); |
| } |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) { |
| return true; |
| } |
| if (!(o instanceof Annotation)) { |
| return false; |
| } |
| Annotation that = (Annotation) o; |
| return annotationPattern.equals(that.annotationPattern); |
| } |
| |
| @Override |
| public int hashCode() { |
| return annotationPattern.hashCode(); |
| } |
| } |
| } |