Home | History | Annotate | Download | only in shaking
      1 // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
      2 // for details. All rights reserved. Use of this source code is governed by a
      3 // BSD-style license that can be found in the LICENSE file.
      4 package com.android.tools.r8.shaking;
      5 
      6 import com.android.tools.r8.graph.DexAccessFlags;
      7 import com.android.tools.r8.utils.StringUtils;
      8 import java.util.Collections;
      9 import java.util.LinkedHashSet;
     10 import java.util.List;
     11 import java.util.Objects;
     12 import java.util.Set;
     13 
     14 public abstract class ProguardClassSpecification {
     15 
     16   public static class Builder {
     17 
     18     protected ProguardTypeMatcher classAnnotation;
     19     protected DexAccessFlags classAccessFlags = new DexAccessFlags(0);
     20     protected DexAccessFlags negatedClassAccessFlags = new DexAccessFlags(0);
     21     protected boolean classTypeNegated = false;
     22     protected ProguardClassType classType;
     23     protected List<ProguardTypeMatcher> classNames;
     24     protected ProguardTypeMatcher inheritanceAnnotation;
     25     protected ProguardTypeMatcher inheritanceClassName;
     26     protected boolean inheritanceIsExtends = false;
     27     protected Set<ProguardMemberRule> memberRules = new LinkedHashSet<>();
     28 
     29     protected Builder() {
     30     }
     31 
     32     public Set<ProguardMemberRule> getMemberRules() {
     33       return memberRules;
     34     }
     35 
     36     public void setMemberRules(Set<ProguardMemberRule> memberRules) {
     37       this.memberRules = memberRules;
     38     }
     39 
     40     public boolean getInheritanceIsExtends() {
     41       return inheritanceIsExtends;
     42     }
     43 
     44     public void setInheritanceIsExtends(boolean inheritanceIsExtends) {
     45       this.inheritanceIsExtends = inheritanceIsExtends;
     46     }
     47 
     48     public boolean hasInheritanceClassName() {
     49       return inheritanceClassName != null;
     50     }
     51 
     52     public ProguardTypeMatcher getInheritanceClassName() {
     53       return inheritanceClassName;
     54     }
     55 
     56     public void setInheritanceClassName(ProguardTypeMatcher inheritanceClassName) {
     57       this.inheritanceClassName = inheritanceClassName;
     58     }
     59 
     60     public ProguardTypeMatcher getInheritanceAnnotation() {
     61       return inheritanceAnnotation;
     62     }
     63 
     64     public void setInheritanceAnnotation(ProguardTypeMatcher inheritanceAnnotation) {
     65       this.inheritanceAnnotation = inheritanceAnnotation;
     66     }
     67 
     68     public List<ProguardTypeMatcher> getClassNames() {
     69       return classNames;
     70     }
     71 
     72     public void setClassNames(List<ProguardTypeMatcher> classNames) {
     73       this.classNames = classNames;
     74     }
     75 
     76     public ProguardClassType getClassType() {
     77       return classType;
     78     }
     79 
     80     public void setClassType(ProguardClassType classType) {
     81       this.classType = classType;
     82     }
     83 
     84     public boolean getClassTypeNegated() {
     85       return classTypeNegated;
     86     }
     87 
     88     public void setClassTypeNegated(boolean classTypeNegated) {
     89       this.classTypeNegated = classTypeNegated;
     90     }
     91 
     92     public DexAccessFlags getClassAccessFlags() {
     93       return classAccessFlags;
     94     }
     95 
     96     public void setClassAccessFlags(DexAccessFlags flags) {
     97       classAccessFlags = flags;
     98     }
     99 
    100     public DexAccessFlags getNegatedClassAccessFlags() {
    101       return negatedClassAccessFlags;
    102     }
    103 
    104     public void setNegatedClassAccessFlags(DexAccessFlags flags) {
    105       negatedClassAccessFlags = flags;
    106     }
    107 
    108     public ProguardTypeMatcher getClassAnnotation() {
    109       return classAnnotation;
    110     }
    111 
    112     public void setClassAnnotation(ProguardTypeMatcher classAnnotation) {
    113       this.classAnnotation = classAnnotation;
    114     }
    115 
    116     protected void matchAllSpecification() {
    117       setClassNames(Collections.singletonList(ProguardTypeMatcher.defaultAllMatcher()));
    118       setMemberRules(Collections.singleton(ProguardMemberRule.defaultKeepAllRule()));
    119     }
    120   }
    121 
    122   private final ProguardTypeMatcher classAnnotation;
    123   private final DexAccessFlags classAccessFlags;
    124   private final DexAccessFlags negatedClassAccessFlags;
    125   private final boolean classTypeNegated;
    126   private final ProguardClassType classType;
    127   private final List<ProguardTypeMatcher> classNames;
    128   private final ProguardTypeMatcher inheritanceAnnotation;
    129   private final ProguardTypeMatcher inheritanceClassName;
    130   private final boolean inheritanceIsExtends;
    131   private final Set<ProguardMemberRule> memberRules;
    132 
    133   protected ProguardClassSpecification(
    134       ProguardTypeMatcher classAnnotation,
    135       DexAccessFlags classAccessFlags,
    136       DexAccessFlags negatedClassAccessFlags,
    137       boolean classTypeNegated,
    138       ProguardClassType classType,
    139       List<ProguardTypeMatcher> classNames,
    140       ProguardTypeMatcher inheritanceAnnotation,
    141       ProguardTypeMatcher inheritanceClassName,
    142       boolean inheritanceIsExtends,
    143       Set<ProguardMemberRule> memberRules) {
    144     this.classAnnotation = classAnnotation;
    145     this.classAccessFlags = classAccessFlags;
    146     this.negatedClassAccessFlags = negatedClassAccessFlags;
    147     this.classTypeNegated = classTypeNegated;
    148     this.classType = classType;
    149     this.classNames = classNames;
    150     this.inheritanceAnnotation = inheritanceAnnotation;
    151     this.inheritanceClassName = inheritanceClassName;
    152     this.inheritanceIsExtends = inheritanceIsExtends;
    153     this.memberRules = memberRules;
    154   }
    155 
    156   public Set<ProguardMemberRule> getMemberRules() {
    157     return memberRules;
    158   }
    159 
    160   public boolean getInheritanceIsExtends() {
    161     return inheritanceIsExtends;
    162   }
    163 
    164   public boolean hasInheritanceClassName() {
    165     return inheritanceClassName != null;
    166   }
    167 
    168   public ProguardTypeMatcher getInheritanceClassName() {
    169     return inheritanceClassName;
    170   }
    171 
    172   public ProguardTypeMatcher getInheritanceAnnotation() {
    173     return inheritanceAnnotation;
    174   }
    175 
    176   public List<ProguardTypeMatcher> getClassNames() {
    177     return classNames;
    178   }
    179 
    180   public ProguardClassType getClassType() {
    181     return classType;
    182   }
    183 
    184   public boolean getClassTypeNegated() {
    185     return classTypeNegated;
    186   }
    187 
    188   public DexAccessFlags getClassAccessFlags() {
    189     return classAccessFlags;
    190   }
    191 
    192   public DexAccessFlags getNegatedClassAccessFlags() {
    193     return negatedClassAccessFlags;
    194   }
    195 
    196   public ProguardTypeMatcher getClassAnnotation() {
    197     return classAnnotation;
    198   }
    199 
    200   @Override
    201   public boolean equals(Object o) {
    202     if (!(o instanceof ProguardClassSpecification)) {
    203       return false;
    204     }
    205     ProguardClassSpecification that = (ProguardClassSpecification) o;
    206 
    207     if (classTypeNegated != that.classTypeNegated) {
    208       return false;
    209     }
    210     if (inheritanceIsExtends != that.inheritanceIsExtends) {
    211       return false;
    212     }
    213     if (!Objects.equals(classAnnotation, that.classAnnotation)) {
    214       return false;
    215     }
    216     if (!classAccessFlags.equals(that.classAccessFlags)) {
    217       return false;
    218     }
    219     if (!negatedClassAccessFlags.equals(that.negatedClassAccessFlags)) {
    220       return false;
    221     }
    222     if (classType != that.classType) {
    223       return false;
    224     }
    225     if (!classNames.equals(that.classNames)) {
    226       return false;
    227     }
    228     if (!Objects.equals(inheritanceAnnotation, that.inheritanceAnnotation)) {
    229       return false;
    230     }
    231     if (!Objects.equals(inheritanceClassName, that.inheritanceClassName)) {
    232       return false;
    233     }
    234     return memberRules.equals(that.memberRules);
    235   }
    236 
    237   @Override
    238   public int hashCode() {
    239     // Used multiplier 3 to avoid too much overflow when computing hashCode.
    240     int result = (classAnnotation != null ? classAnnotation.hashCode() : 0);
    241     result = 3 * result + classAccessFlags.hashCode();
    242     result = 3 * result + negatedClassAccessFlags.hashCode();
    243     result = 3 * result + (classTypeNegated ? 1 : 0);
    244     result = 3 * result + (classType != null ? classType.hashCode() : 0);
    245     result = 3 * result + classNames.hashCode();
    246     result = 3 * result + (inheritanceAnnotation != null ? inheritanceAnnotation.hashCode() : 0);
    247     result = 3 * result + (inheritanceClassName != null ? inheritanceClassName.hashCode() : 0);
    248     result = 3 * result + (inheritanceIsExtends ? 1 : 0);
    249     result = 3 * result + memberRules.hashCode();
    250     return result;
    251   }
    252 
    253   @Override
    254   public String toString() {
    255     StringBuilder builder = new StringBuilder();
    256     StringUtils.appendNonEmpty(builder, " @", classAnnotation, null);
    257     StringUtils.appendNonEmpty(builder, " ", classAccessFlags, null);
    258     StringUtils.appendNonEmpty(builder, " !", negatedClassAccessFlags.toString().replace(" ", " !"),
    259         null);
    260     if (builder.length() > 0) {
    261       builder.append(' ');
    262     }
    263     builder.append(classType);
    264     builder.append(' ');
    265     boolean first = true;
    266     for (ProguardTypeMatcher className : classNames) {
    267       builder.append(className);
    268       if (!first) {
    269         builder.append(',');
    270       }
    271       first = false;
    272     }
    273     if (hasInheritanceClassName()) {
    274       builder.append(inheritanceIsExtends ? " extends" : " implements");
    275       StringUtils.appendNonEmpty(builder, " @", inheritanceAnnotation, null);
    276       builder.append(' ');
    277       builder.append(inheritanceClassName);
    278     }
    279     builder.append(" {\n");
    280     memberRules.forEach(memberRule -> {
    281       builder.append("  ");
    282       builder.append(memberRule);
    283       builder.append(";\n");
    284     });
    285     builder.append("}");
    286     return builder.toString();
    287   }
    288 }
    289