| // Copyright (c) 2022, 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 java.util.Collection; |
| import java.util.Objects; |
| import java.util.function.Predicate; |
| |
| /** |
| * A pattern for matching items in the program. |
| * |
| * <p>An item pattern can be any item, or it can describe a family of classes or a family of members |
| * on a classes. |
| * |
| * <p>A pattern cannot describe both a class *and* a member of a class. Either it is a pattern on |
| * classes or it is a pattern on members. The distinction is defined by having a "none" member |
| * pattern. |
| */ |
| public class KeepItemPattern { |
| |
| public static KeepItemPattern any() { |
| return builder().any().build(); |
| } |
| |
| public static Builder builder() { |
| return new Builder(); |
| } |
| |
| public boolean isClassAndMemberPattern() { |
| return kind == KeepItemKind.CLASS_AND_MEMBERS; |
| } |
| |
| public boolean isClassItemPattern() { |
| return kind == KeepItemKind.ONLY_CLASS; |
| } |
| |
| public boolean isMemberItemPattern() { |
| return kind == KeepItemKind.ONLY_MEMBERS; |
| } |
| |
| public static class Builder { |
| |
| private KeepItemKind kind = null; |
| private KeepClassReference classReference = |
| KeepClassReference.fromClassNamePattern(KeepQualifiedClassNamePattern.any()); |
| private KeepExtendsPattern extendsPattern = KeepExtendsPattern.any(); |
| private KeepMemberPattern memberPattern = KeepMemberPattern.none(); |
| |
| private Builder() {} |
| |
| public Builder copyFrom(KeepItemPattern pattern) { |
| return setKind(pattern.getKind()) |
| .setClassReference(pattern.getClassReference()) |
| .setExtendsPattern(pattern.getExtendsPattern()) |
| .setMemberPattern(pattern.getMemberPattern()); |
| } |
| |
| public Builder any() { |
| kind = KeepItemKind.CLASS_AND_MEMBERS; |
| classReference = KeepClassReference.fromClassNamePattern(KeepQualifiedClassNamePattern.any()); |
| extendsPattern = KeepExtendsPattern.any(); |
| memberPattern = KeepMemberPattern.allMembers(); |
| return this; |
| } |
| |
| public Builder setKind(KeepItemKind kind) { |
| this.kind = kind; |
| return this; |
| } |
| |
| public Builder setClassReference(KeepClassReference classReference) { |
| this.classReference = classReference; |
| return this; |
| } |
| |
| public Builder setClassPattern(KeepQualifiedClassNamePattern qualifiedClassNamePattern) { |
| return setClassReference(KeepClassReference.fromClassNamePattern(qualifiedClassNamePattern)); |
| } |
| |
| public Builder setExtendsPattern(KeepExtendsPattern extendsPattern) { |
| this.extendsPattern = extendsPattern; |
| return this; |
| } |
| |
| public Builder setMemberPattern(KeepMemberPattern memberPattern) { |
| this.memberPattern = memberPattern; |
| return this; |
| } |
| |
| public KeepItemPattern build() { |
| if (kind == null) { |
| kind = memberPattern.isNone() ? KeepItemKind.ONLY_CLASS : KeepItemKind.ONLY_MEMBERS; |
| } |
| if (kind == KeepItemKind.ONLY_CLASS && !memberPattern.isNone()) { |
| throw new KeepEdgeException( |
| "Invalid kind ONLY_CLASS for item with member pattern: " + memberPattern); |
| } |
| if (kind == KeepItemKind.ONLY_MEMBERS && memberPattern.isNone()) { |
| throw new KeepEdgeException("Invalid kind ONLY_MEMBERS for item with no member pattern"); |
| } |
| if (kind == KeepItemKind.CLASS_AND_MEMBERS && memberPattern.isNone()) { |
| throw new KeepEdgeException( |
| "Invalid kind CLASS_AND_MEMBERS for item with no member pattern"); |
| } |
| return new KeepItemPattern(kind, classReference, extendsPattern, memberPattern); |
| } |
| } |
| |
| private final KeepItemKind kind; |
| private final KeepClassReference classReference; |
| private final KeepExtendsPattern extendsPattern; |
| private final KeepMemberPattern memberPattern; |
| // TODO: class annotations |
| |
| private KeepItemPattern( |
| KeepItemKind kind, |
| KeepClassReference classReference, |
| KeepExtendsPattern extendsPattern, |
| KeepMemberPattern memberPattern) { |
| assert kind != null; |
| assert classReference != null; |
| assert extendsPattern != null; |
| assert memberPattern != null; |
| this.kind = kind; |
| this.classReference = classReference; |
| this.extendsPattern = extendsPattern; |
| this.memberPattern = memberPattern; |
| } |
| |
| public boolean isAny(Predicate<String> onReference) { |
| return kind.equals(KeepItemKind.CLASS_AND_MEMBERS) |
| && extendsPattern.isAny() |
| && memberPattern.isAllMembers() |
| && classReference.isAny(onReference); |
| } |
| |
| public KeepItemKind getKind() { |
| return kind; |
| } |
| |
| public KeepClassReference getClassReference() { |
| return classReference; |
| } |
| |
| public KeepExtendsPattern getExtendsPattern() { |
| return extendsPattern; |
| } |
| |
| public KeepMemberPattern getMemberPattern() { |
| return memberPattern; |
| } |
| |
| public Collection<String> getBindingReferences() { |
| return classReference.getBindingReferences(); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null || getClass() != obj.getClass()) { |
| return false; |
| } |
| KeepItemPattern that = (KeepItemPattern) obj; |
| return kind.equals(that.kind) |
| && classReference.equals(that.classReference) |
| && extendsPattern.equals(that.extendsPattern) |
| && memberPattern.equals(that.memberPattern); |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash(kind, classReference, extendsPattern, memberPattern); |
| } |
| |
| @Override |
| public String toString() { |
| return "KeepClassPattern{" |
| + "kind=" |
| + kind |
| + ", classReference=" |
| + classReference |
| + ", extendsPattern=" |
| + extendsPattern |
| + ", memberPattern=" |
| + memberPattern |
| + '}'; |
| } |
| } |