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