1 /* 2 * Copyright (C) 2019 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.hilt.processor.internal; 18 19 import static com.google.auto.common.MoreElements.asPackage; 20 import static com.google.auto.common.MoreElements.asType; 21 import static com.google.auto.common.MoreElements.asVariable; 22 import static com.google.common.base.Preconditions.checkNotNull; 23 import static dagger.internal.codegen.extension.DaggerCollectors.toOptional; 24 import static javax.lang.model.element.Modifier.ABSTRACT; 25 import static javax.lang.model.element.Modifier.PUBLIC; 26 import static javax.lang.model.element.Modifier.STATIC; 27 28 import com.google.auto.common.AnnotationMirrors; 29 import com.google.auto.common.GeneratedAnnotations; 30 import com.google.auto.common.MoreElements; 31 import com.google.auto.common.MoreTypes; 32 import com.google.common.base.CaseFormat; 33 import com.google.common.base.Equivalence.Wrapper; 34 import com.google.common.base.Joiner; 35 import com.google.common.base.Preconditions; 36 import com.google.common.collect.FluentIterable; 37 import com.google.common.collect.ImmutableList; 38 import com.google.common.collect.ImmutableMap; 39 import com.google.common.collect.ImmutableSet; 40 import com.google.common.collect.Iterables; 41 import com.google.common.collect.LinkedHashMultimap; 42 import com.google.common.collect.Multimap; 43 import com.google.common.collect.SetMultimap; 44 import com.squareup.javapoet.AnnotationSpec; 45 import com.squareup.javapoet.ClassName; 46 import com.squareup.javapoet.JavaFile; 47 import com.squareup.javapoet.MethodSpec; 48 import com.squareup.javapoet.ParameterSpec; 49 import com.squareup.javapoet.ParameterizedTypeName; 50 import com.squareup.javapoet.TypeName; 51 import com.squareup.javapoet.TypeSpec; 52 import dagger.internal.codegen.extension.DaggerStreams; 53 import dagger.internal.codegen.kotlin.KotlinMetadataUtil; 54 import java.io.IOException; 55 import java.lang.annotation.Annotation; 56 import java.util.LinkedHashSet; 57 import java.util.List; 58 import java.util.Map; 59 import java.util.Optional; 60 import java.util.Set; 61 import java.util.stream.Collectors; 62 import java.util.stream.Stream; 63 import javax.annotation.processing.ProcessingEnvironment; 64 import javax.annotation.processing.RoundEnvironment; 65 import javax.lang.model.element.AnnotationMirror; 66 import javax.lang.model.element.AnnotationValue; 67 import javax.lang.model.element.Element; 68 import javax.lang.model.element.ElementKind; 69 import javax.lang.model.element.ExecutableElement; 70 import javax.lang.model.element.Modifier; 71 import javax.lang.model.element.PackageElement; 72 import javax.lang.model.element.TypeElement; 73 import javax.lang.model.element.VariableElement; 74 import javax.lang.model.type.ArrayType; 75 import javax.lang.model.type.DeclaredType; 76 import javax.lang.model.type.ErrorType; 77 import javax.lang.model.type.PrimitiveType; 78 import javax.lang.model.type.TypeKind; 79 import javax.lang.model.type.TypeMirror; 80 import javax.lang.model.util.ElementFilter; 81 import javax.lang.model.util.Elements; 82 import javax.lang.model.util.SimpleAnnotationValueVisitor7; 83 import javax.lang.model.util.SimpleTypeVisitor7; 84 85 /** Static helper methods for writing a processor. */ 86 public final class Processors { 87 88 public static final String CONSTRUCTOR_NAME = "<init>"; 89 90 public static final String STATIC_INITIALIZER_NAME = "<clinit>"; 91 92 private static final String JAVA_CLASS = "java.lang.Class"; 93 generateAggregatingClass( String aggregatingPackage, AnnotationSpec aggregatingAnnotation, TypeElement element, Class<?> generatedAnnotationClass, ProcessingEnvironment env)94 public static void generateAggregatingClass( 95 String aggregatingPackage, 96 AnnotationSpec aggregatingAnnotation, 97 TypeElement element, 98 Class<?> generatedAnnotationClass, 99 ProcessingEnvironment env) throws IOException { 100 ClassName name = ClassName.get(aggregatingPackage, "_" + getFullEnclosedName(element)); 101 TypeSpec.Builder builder = 102 TypeSpec.classBuilder(name) 103 .addModifiers(PUBLIC) 104 .addOriginatingElement(element) 105 .addAnnotation(aggregatingAnnotation) 106 .addJavadoc("This class should only be referenced by generated code! ") 107 .addJavadoc("This class aggregates information across multiple compilations.\n");; 108 109 addGeneratedAnnotation(builder, env, generatedAnnotationClass); 110 111 JavaFile.builder(name.packageName(), builder.build()).build().writeTo(env.getFiler()); 112 } 113 114 /** Returns a map from {@link AnnotationMirror} attribute name to {@link AnnotationValue}s */ getAnnotationValues(Elements elements, AnnotationMirror annotation)115 public static ImmutableMap<String, AnnotationValue> getAnnotationValues(Elements elements, 116 AnnotationMirror annotation) { 117 ImmutableMap.Builder<String, AnnotationValue> annotationMembers = ImmutableMap.builder(); 118 for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e 119 : elements.getElementValuesWithDefaults(annotation).entrySet()) { 120 annotationMembers.put(e.getKey().getSimpleName().toString(), e.getValue()); 121 } 122 return annotationMembers.build(); 123 } 124 125 /** 126 * Returns a multimap from attribute name to the values that are an array of annotation mirrors. 127 * The returned map will not contain mappings for any attributes that are not Annotation Arrays. 128 * 129 * <p>e.g. if the input was the annotation mirror for 130 * <pre> 131 * {@literal @}Foo({{@literal @}Bar("hello"), {@literal @}Bar("world")}) 132 * </pre> 133 * the map returned would have "value" map to a set containing the two @Bar annotation mirrors. 134 */ getAnnotationAnnotationArrayValues( Elements elements, AnnotationMirror annotation)135 public static Multimap<String, AnnotationMirror> getAnnotationAnnotationArrayValues( 136 Elements elements, AnnotationMirror annotation) { 137 SetMultimap<String, AnnotationMirror> annotationMembers = LinkedHashMultimap.create(); 138 for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e 139 : elements.getElementValuesWithDefaults(annotation).entrySet()) { 140 String attribute = e.getKey().getSimpleName().toString(); 141 Set<AnnotationMirror> annotationMirrors = new LinkedHashSet<>(); 142 e.getValue().accept(new AnnotationMirrorAnnotationValueVisitor(), annotationMirrors); 143 annotationMembers.putAll(attribute, annotationMirrors); 144 } 145 return annotationMembers; 146 } 147 148 private static final class AnnotationMirrorAnnotationValueVisitor 149 extends SimpleAnnotationValueVisitor7<Void, Set<AnnotationMirror>> { 150 151 @Override visitArray(List<? extends AnnotationValue> vals, Set<AnnotationMirror> types)152 public Void visitArray(List<? extends AnnotationValue> vals, Set<AnnotationMirror> types) { 153 for (AnnotationValue val : vals) { 154 val.accept(this, types); 155 } 156 return null; 157 } 158 159 @Override visitAnnotation(AnnotationMirror a, Set<AnnotationMirror> annotationMirrors)160 public Void visitAnnotation(AnnotationMirror a, Set<AnnotationMirror> annotationMirrors) { 161 annotationMirrors.add(a); 162 return null; 163 } 164 } 165 166 /** Returns the {@link TypeElement} for a class attribute on an annotation. */ getAnnotationClassValue( Elements elements, AnnotationMirror annotation, String key)167 public static TypeElement getAnnotationClassValue( 168 Elements elements, AnnotationMirror annotation, String key) { 169 return Iterables.getOnlyElement(getAnnotationClassValues(elements, annotation, key)); 170 } 171 172 /** Returns a list of {@link TypeElement}s for a class attribute on an annotation. */ getAnnotationClassValues( Elements elements, AnnotationMirror annotation, String key)173 public static ImmutableList<TypeElement> getAnnotationClassValues( 174 Elements elements, AnnotationMirror annotation, String key) { 175 ImmutableList<TypeElement> values = getOptionalAnnotationClassValues(elements, annotation, key); 176 177 ProcessorErrors.checkState( 178 values.size() >= 1, 179 // TODO(b/152801981): Point to the annotation value rather than the annotated element. 180 annotation.getAnnotationType().asElement(), 181 "@%s, '%s' class is invalid or missing: %s", 182 annotation.getAnnotationType().asElement().getSimpleName(), 183 key, 184 annotation); 185 186 return values; 187 } 188 189 /** Returns a multimap from attribute name to elements for class valued attributes. */ getAnnotationClassValues( Elements elements, AnnotationMirror annotation)190 private static Multimap<String, DeclaredType> getAnnotationClassValues( 191 Elements elements, AnnotationMirror annotation) { 192 Element javaClass = elements.getTypeElement(JAVA_CLASS); 193 SetMultimap<String, DeclaredType> annotationMembers = LinkedHashMultimap.create(); 194 for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e : 195 elements.getElementValuesWithDefaults(annotation).entrySet()) { 196 Optional<DeclaredType> returnType = getOptionalDeclaredType(e.getKey().getReturnType()); 197 if (returnType.isPresent() && returnType.get().asElement().equals(javaClass)) { 198 String attribute = e.getKey().getSimpleName().toString(); 199 Set<DeclaredType> declaredTypes = new LinkedHashSet<DeclaredType>(); 200 e.getValue().accept(new DeclaredTypeAnnotationValueVisitor(), declaredTypes); 201 annotationMembers.putAll(attribute, declaredTypes); 202 } 203 } 204 return annotationMembers; 205 } 206 207 /** Returns an optional {@link TypeElement} for a class attribute on an annotation. */ getOptionalAnnotationClassValue( Elements elements, AnnotationMirror annotation, String key)208 public static Optional<TypeElement> getOptionalAnnotationClassValue( 209 Elements elements, AnnotationMirror annotation, String key) { 210 return getAnnotationClassValues(elements, annotation).get(key).stream() 211 .map(MoreTypes::asTypeElement) 212 .collect(toOptional()); 213 } 214 215 /** Returns a list of {@link TypeElement}s for a class attribute on an annotation. */ getOptionalAnnotationClassValues( Elements elements, AnnotationMirror annotation, String key)216 public static ImmutableList<TypeElement> getOptionalAnnotationClassValues( 217 Elements elements, AnnotationMirror annotation, String key) { 218 return ImmutableList.copyOf( 219 getAnnotationClassValues(elements, annotation).get(key).stream() 220 .map(MoreTypes::asTypeElement) 221 .collect(Collectors.toList())); 222 } 223 224 private static final class DeclaredTypeAnnotationValueVisitor 225 extends SimpleAnnotationValueVisitor7<Void, Set<DeclaredType>> { 226 visitArray( List<? extends AnnotationValue> vals, Set<DeclaredType> types)227 @Override public Void visitArray( 228 List<? extends AnnotationValue> vals, Set<DeclaredType> types) { 229 for (AnnotationValue val : vals) { 230 val.accept(this, types); 231 } 232 return null; 233 } 234 visitType(TypeMirror t, Set<DeclaredType> types)235 @Override public Void visitType(TypeMirror t, Set<DeclaredType> types) { 236 DeclaredType declared = MoreTypes.asDeclared(t); 237 checkNotNull(declared); 238 types.add(declared); 239 return null; 240 } 241 } 242 243 /** 244 * If the received mirror represents a primitive type or an array of primitive types, this returns 245 * the represented primitive type. Otherwise throws an IllegalStateException. 246 */ getPrimitiveType(TypeMirror type)247 public static PrimitiveType getPrimitiveType(TypeMirror type) { 248 return type.accept( 249 new SimpleTypeVisitor7<PrimitiveType, Void> () { 250 @Override public PrimitiveType visitArray(ArrayType type, Void unused) { 251 return getPrimitiveType(type.getComponentType()); 252 } 253 254 @Override public PrimitiveType visitPrimitive(PrimitiveType type, Void unused) { 255 return type; 256 } 257 258 @Override public PrimitiveType defaultAction(TypeMirror type, Void unused) { 259 throw new IllegalStateException("Unhandled type: " + type); 260 } 261 }, null /* the Void accumulator */); 262 } 263 264 /** 265 * Returns an {@link Optional#of} the declared type if the received mirror represents a declared 266 * type or an array of declared types, otherwise returns {@link Optional#empty}. 267 */ 268 public static Optional<DeclaredType> getOptionalDeclaredType(TypeMirror type) { 269 return Optional.ofNullable( 270 type.accept( 271 new SimpleTypeVisitor7<DeclaredType, Void>(null /* defaultValue */) { 272 @Override 273 public DeclaredType visitArray(ArrayType type, Void unused) { 274 return MoreTypes.asDeclared(type.getComponentType()); 275 } 276 277 @Override 278 public DeclaredType visitDeclared(DeclaredType type, Void unused) { 279 return type; 280 } 281 282 @Override 283 public DeclaredType visitError(ErrorType type, Void unused) { 284 return type; 285 } 286 }, 287 null /* the Void accumulator */)); 288 } 289 290 /** 291 * Returns the declared type if the received mirror represents a declared type or an array of 292 * declared types, otherwise throws an {@link IllegalStateException}. 293 */ 294 public static DeclaredType getDeclaredType(TypeMirror type) { 295 return getOptionalDeclaredType(type) 296 .orElseThrow(() -> new IllegalStateException("Not a declared type: " + type)); 297 } 298 299 /** Gets the values from an annotation value representing a string array. */ 300 public static ImmutableList<String> getStringArrayAnnotationValue(AnnotationValue value) { 301 return value.accept(new SimpleAnnotationValueVisitor7<ImmutableList<String>, Void>() { 302 @Override 303 public ImmutableList<String> defaultAction(Object o, Void unused) { 304 throw new IllegalStateException("Expected an array, got instead: " + o); 305 } 306 307 @Override 308 public ImmutableList<String> visitArray(List<? extends AnnotationValue> values, 309 Void unused) { 310 ImmutableList.Builder<String> builder = ImmutableList.builder(); 311 for (AnnotationValue value : values) { 312 builder.add(getStringAnnotationValue(value)); 313 } 314 return builder.build(); 315 } 316 }, /* unused accumulator */ null); 317 } 318 319 /** Gets the values from an annotation value representing an int. */ 320 public static Boolean getBooleanAnnotationValue(AnnotationValue value) { 321 return value.accept( 322 new SimpleAnnotationValueVisitor7<Boolean, Void>() { 323 @Override 324 public Boolean defaultAction(Object o, Void unused) { 325 throw new IllegalStateException("Expected a boolean, got instead: " + o); 326 } 327 328 @Override 329 public Boolean visitBoolean(boolean value, Void unused) { 330 return value; 331 } 332 }, /* unused accumulator */ 333 null); 334 } 335 336 /** Gets the values from an annotation value representing an int. */ 337 public static Integer getIntAnnotationValue(AnnotationValue value) { 338 return value.accept(new SimpleAnnotationValueVisitor7<Integer, Void>() { 339 @Override 340 public Integer defaultAction(Object o, Void unused) { 341 throw new IllegalStateException("Expected an int, got instead: " + o); 342 } 343 344 @Override 345 public Integer visitInt(int value, Void unused) { 346 return value; 347 } 348 }, /* unused accumulator */ null); 349 } 350 351 /** Gets the values from an annotation value representing a long. */ 352 public static Long getLongAnnotationValue(AnnotationValue value) { 353 return value.accept( 354 new SimpleAnnotationValueVisitor7<Long, Void>() { 355 @Override 356 public Long defaultAction(Object o, Void unused) { 357 throw new IllegalStateException("Expected an int, got instead: " + o); 358 } 359 360 @Override 361 public Long visitLong(long value, Void unused) { 362 return value; 363 } 364 }, 365 null /* unused accumulator */); 366 } 367 368 /** Gets the values from an annotation value representing a string. */ 369 public static String getStringAnnotationValue(AnnotationValue value) { 370 return value.accept(new SimpleAnnotationValueVisitor7<String, Void>() { 371 @Override 372 public String defaultAction(Object o, Void unused) { 373 throw new IllegalStateException("Expected a string, got instead: " + o); 374 } 375 376 @Override 377 public String visitString(String value, Void unused) { 378 return value; 379 } 380 }, /* unused accumulator */ null); 381 } 382 383 /** Gets the values from an annotation value representing a DeclaredType. */ 384 public static DeclaredType getDeclaredTypeAnnotationValue(AnnotationValue value) { 385 return value.accept( 386 new SimpleAnnotationValueVisitor7<DeclaredType, Void>() { 387 @Override 388 public DeclaredType defaultAction(Object o, Void unused) { 389 throw new IllegalStateException("Expected a TypeMirror, got instead: " + o); 390 } 391 392 @Override 393 public DeclaredType visitType(TypeMirror typeMirror, Void unused) { 394 return MoreTypes.asDeclared(typeMirror); 395 } 396 }, /* unused accumulator */ 397 null); 398 } 399 400 private static final SimpleAnnotationValueVisitor7<ImmutableSet<VariableElement>, Void> 401 ENUM_ANNOTATION_VALUE_VISITOR = 402 new SimpleAnnotationValueVisitor7<ImmutableSet<VariableElement>, Void>() { 403 @Override 404 public ImmutableSet<VariableElement> defaultAction(Object o, Void unused) { 405 throw new IllegalStateException( 406 "Expected an Enum or an Enum array, got instead: " + o); 407 } 408 409 @Override 410 public ImmutableSet<VariableElement> visitArray( 411 List<? extends AnnotationValue> values, Void unused) { 412 ImmutableSet.Builder<VariableElement> builder = ImmutableSet.builder(); 413 for (AnnotationValue value : values) { 414 builder.addAll(value.accept(this, null)); 415 } 416 return builder.build(); 417 } 418 419 @Override 420 public ImmutableSet<VariableElement> visitEnumConstant( 421 VariableElement value, Void unused) { 422 return ImmutableSet.of(value); 423 } 424 }; 425 426 /** Gets the values from an annotation value representing a Enum array. */ 427 public static ImmutableSet<VariableElement> getEnumArrayAnnotationValue(AnnotationValue value) { 428 return value.accept(ENUM_ANNOTATION_VALUE_VISITOR, /* unused accumulator */ null); 429 } 430 431 /** Converts an annotation value map to be keyed by the attribute name. */ 432 public static ImmutableMap<String, AnnotationValue> convertToAttributeNameMap( 433 Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValues) { 434 ImmutableMap.Builder<String, AnnotationValue> builder = ImmutableMap.builder(); 435 for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e 436 : annotationValues.entrySet()) { 437 String attribute = e.getKey().getSimpleName().toString(); 438 builder.put(attribute, e.getValue()); 439 } 440 return builder.build(); 441 } 442 443 /** Returns the given elements containing package element. */ 444 public static PackageElement getPackageElement(Element originalElement) { 445 checkNotNull(originalElement); 446 for (Element e = originalElement; e != null; e = e.getEnclosingElement()) { 447 if (e instanceof PackageElement) { 448 return (PackageElement) e; 449 } 450 } 451 throw new IllegalStateException("Cannot find a package for " + originalElement); 452 } 453 454 public static TypeElement getTopLevelType(Element originalElement) { 455 checkNotNull(originalElement); 456 for (Element e = originalElement; e != null; e = e.getEnclosingElement()) { 457 if (isTopLevel(e)) { 458 return MoreElements.asType(e); 459 } 460 } 461 throw new IllegalStateException("Cannot find a top-level type for " + originalElement); 462 } 463 464 /** Returns true if the given element is a top-level element. */ 465 public static boolean isTopLevel(Element element) { 466 return element.getEnclosingElement().getKind() == ElementKind.PACKAGE; 467 } 468 469 /** Returns true if the given element is annotated with the given annotation. */ 470 public static boolean hasAnnotation(Element element, Class<? extends Annotation> annotation) { 471 return element.getAnnotation(annotation) != null; 472 } 473 474 /** Returns true if the given element has an annotation with the given class name. */ 475 public static boolean hasAnnotation(Element element, ClassName className) { 476 return getAnnotationMirrorOptional(element, className).isPresent(); 477 } 478 479 /** Returns true if the given element has an annotation with the given class name. */ 480 public static boolean hasAnnotation(AnnotationMirror mirror, ClassName className) { 481 return hasAnnotation(mirror.getAnnotationType().asElement(), className); 482 } 483 484 /** Returns true if the given element is annotated with the given annotation. */ 485 public static boolean hasAnnotation( 486 AnnotationMirror mirror, Class<? extends Annotation> annotation) { 487 return hasAnnotation(mirror.getAnnotationType().asElement(), annotation); 488 } 489 490 /** Returns true if the given element has an annotation that is an error kind. */ 491 public static boolean hasErrorTypeAnnotation(Element element) { 492 for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { 493 if (annotationMirror.getAnnotationType().getKind() == TypeKind.ERROR) { 494 return true; 495 } 496 } 497 return false; 498 } 499 500 501 /** 502 * Returns all elements in the round that are annotated with at least 1 of the given 503 * annotations. 504 */ 505 @SafeVarargs 506 public static ImmutableSet<Element> getElementsAnnotatedWith(RoundEnvironment roundEnv, 507 Class<? extends Annotation>... annotations) { 508 ImmutableSet.Builder<Element> builder = ImmutableSet.builder(); 509 for (Class<? extends Annotation> annotation : annotations){ 510 builder.addAll(roundEnv.getElementsAnnotatedWith(annotation)); 511 } 512 513 return builder.build(); 514 } 515 516 /** 517 * Returns the name of a class, including prefixing with enclosing class names. i.e. for inner 518 * class Foo enclosed by Bar, returns Bar_Foo instead of just Foo 519 */ 520 public static String getEnclosedName(ClassName name) { 521 return Joiner.on('_').join(name.simpleNames()); 522 } 523 524 /** Returns the name of a class. See {@link #getEnclosedName(ClassName)}. */ 525 public static String getEnclosedName(TypeElement element) { 526 return getEnclosedName(ClassName.get(element)); 527 } 528 529 /** 530 * Returns an equivalent class name with the {@code .} (dots) used for inner classes replaced with 531 * {@code _}. 532 */ 533 public static ClassName getEnclosedClassName(ClassName className) { 534 return ClassName.get(className.packageName(), getEnclosedName(className)); 535 } 536 537 /** 538 * Returns an equivalent class name with the {@code .} (dots) used for inner classes replaced with 539 * {@code _}. 540 */ 541 public static ClassName getEnclosedClassName(TypeElement typeElement) { 542 return getEnclosedClassName(ClassName.get(typeElement)); 543 } 544 545 /** Returns the fully qualified class name, with _ instead of . */ 546 public static String getFullyQualifiedEnclosedClassName(ClassName className) { 547 return className.packageName().replace('.', '_') + getEnclosedName(className); 548 } 549 550 /** 551 * Returns the fully qualified class name, with _ instead of . For elements that are not type 552 * elements, this continues to append the simple name of elements. For example, 553 * foo_bar_Outer_Inner_fooMethod. 554 */ 555 public static String getFullEnclosedName(Element element) { 556 Preconditions.checkNotNull(element); 557 String qualifiedName = ""; 558 while (element != null) { 559 if (element.getKind().equals(ElementKind.PACKAGE)) { 560 qualifiedName = asPackage(element).getQualifiedName() + qualifiedName; 561 } else { 562 // This check is needed to keep the name stable when compiled with jdk8 vs jdk11. jdk11 563 // contains newly added "module" enclosing elements of packages, which adds an addtional "_" 564 // prefix to the name due to an empty module element compared with jdk8. 565 if (!element.getSimpleName().toString().isEmpty()) { 566 qualifiedName = "." + element.getSimpleName() + qualifiedName; 567 } 568 } 569 element = element.getEnclosingElement(); 570 } 571 return qualifiedName.replace('.', '_'); 572 } 573 574 /** Appends the given string to the end of the class name. */ 575 public static ClassName append(ClassName name, String suffix) { 576 return name.peerClass(name.simpleName() + suffix); 577 } 578 579 /** Prepends the given string to the beginning of the class name. */ 580 public static ClassName prepend(ClassName name, String prefix) { 581 return name.peerClass(prefix + name.simpleName()); 582 } 583 584 /** 585 * Removes the string {@code suffix} from the simple name of {@code type} and returns it. 586 * 587 * @throws BadInputException if the simple name of {@code type} does not end with {@code suffix} 588 */ 589 public static ClassName removeNameSuffix(TypeElement type, String suffix) { 590 ClassName originalName = ClassName.get(type); 591 String originalSimpleName = originalName.simpleName(); 592 ProcessorErrors.checkState(originalSimpleName.endsWith(suffix), 593 type, "Name of type %s must end with '%s'", originalName, suffix); 594 String withoutSuffix = 595 originalSimpleName.substring(0, originalSimpleName.length() - suffix.length()); 596 return originalName.peerClass(withoutSuffix); 597 } 598 599 /** @see #getAnnotationMirror(Element, ClassName) */ 600 public static AnnotationMirror getAnnotationMirror( 601 Element element, Class<? extends Annotation> annotationClass) { 602 return getAnnotationMirror(element, ClassName.get(annotationClass)); 603 } 604 605 /** @see #getAnnotationMirror(Element, ClassName) */ 606 public static AnnotationMirror getAnnotationMirror(Element element, String annotationClassName) { 607 return getAnnotationMirror(element, ClassName.bestGuess(annotationClassName)); 608 } 609 610 /** 611 * Returns the annotation mirror from the given element that corresponds to the given class. 612 * 613 * @throws IllegalStateException if the given element isn't annotated with that annotation. 614 */ 615 public static AnnotationMirror getAnnotationMirror(Element element, ClassName className) { 616 Optional<AnnotationMirror> annotationMirror = getAnnotationMirrorOptional(element, className); 617 if (annotationMirror.isPresent()) { 618 return annotationMirror.get(); 619 } else { 620 throw new IllegalStateException( 621 String.format( 622 "Couldn't find annotation %s on element %s. Found annotations: %s", 623 className, element.getSimpleName(), element.getAnnotationMirrors())); 624 } 625 } 626 627 /** 628 * Returns the annotation mirror from the given element that corresponds to the given class. 629 * 630 * @throws {@link IllegalArgumentException} if 2 or more annotations are found. 631 * @return {@link Optional#empty()} if no annotation is found on the element. 632 */ 633 static Optional<AnnotationMirror> getAnnotationMirrorOptional( 634 Element element, ClassName className) { 635 return element.getAnnotationMirrors().stream() 636 .filter(mirror -> ClassName.get(mirror.getAnnotationType()).equals(className)) 637 .collect(toOptional()); 638 } 639 640 /** @return true if element inherits directly or indirectly from the className */ 641 public static boolean isAssignableFrom(TypeElement element, ClassName className) { 642 return isAssignableFromAnyOf(element, ImmutableSet.of(className)); 643 } 644 645 /** @return true if element inherits directly or indirectly from any of the classNames */ 646 public static boolean isAssignableFromAnyOf(TypeElement element, 647 ImmutableSet<ClassName> classNames) { 648 for (ClassName className : classNames) { 649 if (ClassName.get(element).equals(className)) { 650 return true; 651 } 652 } 653 654 TypeMirror superClass = element.getSuperclass(); 655 // None type is returned if this is an interface or Object 656 // Error type is returned for classes that are generated by this processor 657 if ((superClass.getKind() != TypeKind.NONE) && (superClass.getKind() != TypeKind.ERROR)) { 658 Preconditions.checkState(superClass.getKind() == TypeKind.DECLARED); 659 if (isAssignableFromAnyOf(MoreTypes.asTypeElement(superClass), classNames)) { 660 return true; 661 } 662 } 663 664 for (TypeMirror iface : element.getInterfaces()) { 665 // Skip errors and keep looking. This is especially needed for classes generated by this 666 // processor. 667 if (iface.getKind() == TypeKind.ERROR) { 668 continue; 669 } 670 Preconditions.checkState(iface.getKind() == TypeKind.DECLARED, 671 "Interface type is %s", iface.getKind()); 672 if (isAssignableFromAnyOf(MoreTypes.asTypeElement(iface), classNames)) { 673 return true; 674 } 675 } 676 677 return false; 678 } 679 680 /** Returns methods from a given TypeElement, not including constructors. */ 681 public static ImmutableList<ExecutableElement> getMethods(TypeElement element) { 682 ImmutableList.Builder<ExecutableElement> builder = ImmutableList.builder(); 683 for (Element e : element.getEnclosedElements()) { 684 // Only look for executable elements, not fields, etc 685 if (e instanceof ExecutableElement) { 686 ExecutableElement method = (ExecutableElement) e; 687 if (!method.getSimpleName().contentEquals(CONSTRUCTOR_NAME) 688 && !method.getSimpleName().contentEquals(STATIC_INITIALIZER_NAME)) { 689 builder.add(method); 690 } 691 } 692 } 693 return builder.build(); 694 } 695 696 public static ImmutableList<ExecutableElement> getConstructors(TypeElement element) { 697 ImmutableList.Builder<ExecutableElement> builder = ImmutableList.builder(); 698 for (Element enclosed : element.getEnclosedElements()) { 699 // Only look for executable elements, not fields, etc 700 if (enclosed instanceof ExecutableElement) { 701 ExecutableElement method = (ExecutableElement) enclosed; 702 if (method.getSimpleName().contentEquals(CONSTRUCTOR_NAME)) { 703 builder.add(method); 704 } 705 } 706 } 707 return builder.build(); 708 } 709 710 /** 711 * Returns all transitive methods from a given TypeElement, not including constructors. Also does 712 * not include methods from Object or that override methods on Object. 713 */ 714 public static ImmutableList<ExecutableElement> getAllMethods(TypeElement element) { 715 ImmutableList.Builder<ExecutableElement> builder = ImmutableList.builder(); 716 builder.addAll( 717 Iterables.filter( 718 getMethods(element), 719 method -> { 720 return !isObjectMethod(method); 721 })); 722 TypeMirror superclass = element.getSuperclass(); 723 if (superclass.getKind() != TypeKind.NONE) { 724 TypeElement superclassElement = MoreTypes.asTypeElement(superclass); 725 builder.addAll(getAllMethods(superclassElement)); 726 } 727 for (TypeMirror iface : element.getInterfaces()) { 728 builder.addAll(getAllMethods(MoreTypes.asTypeElement(iface))); 729 } 730 return builder.build(); 731 } 732 733 /** Checks that the given element is not the error type. */ 734 public static void checkForCompilationError(TypeElement e) { 735 ProcessorErrors.checkState(e.asType().getKind() != TypeKind.ERROR, e, 736 "Unable to resolve the type %s. Look for compilation errors above related to this type.", 737 e); 738 } 739 740 private static void addInterfaceMethods( 741 TypeElement type, ImmutableList.Builder<ExecutableElement> interfaceMethods) { 742 for (TypeMirror interfaceMirror : type.getInterfaces()) { 743 TypeElement interfaceElement = MoreTypes.asTypeElement(interfaceMirror); 744 interfaceMethods.addAll(getMethods(interfaceElement)); 745 addInterfaceMethods(interfaceElement, interfaceMethods); 746 } 747 } 748 749 /** 750 * Finds methods of interfaces implemented by {@code type}. This method also checks the 751 * superinterfaces of those interfaces. This method does not check the interfaces of any 752 * superclass of {@code type}. 753 */ 754 public static ImmutableList<ExecutableElement> methodsOnInterfaces(TypeElement type) { 755 ImmutableList.Builder<ExecutableElement> interfaceMethods = new ImmutableList.Builder<>(); 756 addInterfaceMethods(type, interfaceMethods); 757 return interfaceMethods.build(); 758 } 759 760 /** Returns MapKey annotated annotations found on an element. */ 761 public static ImmutableList<AnnotationMirror> getMapKeyAnnotations(Element element) { 762 return getAnnotationsAnnotatedWith(element, ClassName.get("dagger", "MapKey")); 763 } 764 765 /** Returns Qualifier annotated annotations found on an element. */ 766 public static ImmutableList<AnnotationMirror> getQualifierAnnotations(Element element) { 767 // TODO(bcorso): Consolidate this logic with InjectionAnnotations in Dagger 768 ImmutableSet<? extends AnnotationMirror> qualifiers = 769 AnnotationMirrors.getAnnotatedAnnotations(element, ClassNames.QUALIFIER.canonicalName()); 770 KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil(); 771 if (element.getKind() == ElementKind.FIELD 772 // static fields are generally not supported, no need to get qualifier from kotlin metadata 773 && !element.getModifiers().contains(STATIC) 774 && metadataUtil.hasMetadata(element)) { 775 VariableElement fieldElement = asVariable(element); 776 return Stream.concat( 777 qualifiers.stream(), 778 metadataUtil.isMissingSyntheticPropertyForAnnotations(fieldElement) 779 ? Stream.empty() 780 : metadataUtil 781 .getSyntheticPropertyAnnotations(fieldElement, ClassNames.QUALIFIER) 782 .stream()) 783 .map(AnnotationMirrors.equivalence()::wrap) 784 .distinct() 785 .map(Wrapper::get) 786 .collect(DaggerStreams.toImmutableList()); 787 } else { 788 return ImmutableList.copyOf(qualifiers); 789 } 790 } 791 792 /** Returns Scope annotated annotations found on an element. */ 793 public static ImmutableList<AnnotationMirror> getScopeAnnotations(Element element) { 794 return getAnnotationsAnnotatedWith(element, ClassNames.SCOPE); 795 } 796 797 /** Returns annotations of element that are annotated with subAnnotation */ 798 public static ImmutableList<AnnotationMirror> getAnnotationsAnnotatedWith( 799 Element element, ClassName subAnnotation) { 800 ImmutableList.Builder<AnnotationMirror> builder = ImmutableList.builder(); 801 element.getAnnotationMirrors().stream() 802 .filter(annotation -> hasAnnotation(annotation, subAnnotation)) 803 .forEach(builder::add); 804 return builder.build(); 805 } 806 807 /** Returns true if there are any annotations of element that are annotated with subAnnotation */ 808 public static boolean hasAnnotationsAnnotatedWith(Element element, ClassName subAnnotation) { 809 return !getAnnotationsAnnotatedWith(element, subAnnotation).isEmpty(); 810 } 811 812 /** 813 * Returns true iff the given {@code method} is one of the public or protected methods on {@link 814 * Object}, or an overridden version thereof. 815 * 816 * <p>This method ignores the return type of the given method, but this is generally fine since 817 * two methods which only differ by their return type will cause a compiler error. (e.g. a 818 * non-static method with the signature {@code int equals(Object)}) 819 */ 820 public static boolean isObjectMethod(ExecutableElement method) { 821 // First check if this method is directly defined on Object 822 Element enclosingElement = method.getEnclosingElement(); 823 if (enclosingElement.getKind() == ElementKind.CLASS 824 && TypeName.get(enclosingElement.asType()).equals(TypeName.OBJECT)) { 825 return true; 826 } 827 828 if (method.getModifiers().contains(Modifier.STATIC)) { 829 return false; 830 } 831 switch (method.getSimpleName().toString()) { 832 case "equals": 833 return (method.getParameters().size() == 1) 834 && (method.getParameters().get(0).asType().toString().equals("java.lang.Object")); 835 case "hashCode": 836 case "toString": 837 case "clone": 838 case "getClass": 839 case "notify": 840 case "notifyAll": 841 case "finalize": 842 return method.getParameters().isEmpty(); 843 case "wait": 844 if (method.getParameters().isEmpty()) { 845 return true; 846 } else if ((method.getParameters().size() == 1) 847 && (method.getParameters().get(0).asType().toString().equals("long"))) { 848 return true; 849 } else if ((method.getParameters().size() == 2) 850 && (method.getParameters().get(0).asType().toString().equals("long")) 851 && (method.getParameters().get(1).asType().toString().equals("int"))) { 852 return true; 853 } 854 return false; 855 default: 856 return false; 857 } 858 } 859 860 public static ParameterSpec parameterSpecFromVariableElement(VariableElement element) { 861 return ParameterSpec.builder( 862 ClassName.get(element.asType()), 863 upperToLowerCamel(element.getSimpleName().toString())) 864 .build(); 865 } 866 867 /** 868 * Shortcut for converting from upper camel to lower camel case 869 * 870 * <p>Example: "SomeString" => "someString" 871 */ 872 public static String upperToLowerCamel(String upperCamel) { 873 return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, upperCamel); 874 } 875 876 /** @return copy of the given MethodSpec as {@link MethodSpec.Builder} with method body removed */ 877 public static MethodSpec.Builder copyMethodSpecWithoutBody(MethodSpec methodSpec) { 878 MethodSpec.Builder builder; 879 880 if (methodSpec.isConstructor()) { 881 // Constructors cannot have return types 882 builder = MethodSpec.constructorBuilder(); 883 } else { 884 builder = MethodSpec.methodBuilder(methodSpec.name) 885 .returns(methodSpec.returnType); 886 } 887 888 return builder 889 .addAnnotations(methodSpec.annotations) 890 .addModifiers(methodSpec.modifiers) 891 .addParameters(methodSpec.parameters) 892 .addExceptions(methodSpec.exceptions) 893 .addJavadoc(methodSpec.javadoc.toString()) 894 .addTypeVariables(methodSpec.typeVariables); 895 } 896 897 /** @return A method spec for an empty constructor (useful for abstract Dagger modules). */ 898 public static MethodSpec privateEmptyConstructor() { 899 return MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build(); 900 } 901 902 /** 903 * Returns true if the given method is annotated with one of the annotations Dagger recognizes 904 * for abstract methods (e.g. @Binds). 905 */ 906 public static boolean hasDaggerAbstractMethodAnnotation(ExecutableElement method) { 907 return hasAnnotation(method, ClassNames.BINDS) 908 || hasAnnotation(method, ClassNames.BINDS_OPTIONAL_OF) 909 || hasAnnotation(method, ClassNames.MULTIBINDS) 910 || hasAnnotation(method, ClassNames.CONTRIBUTES_ANDROID_INJECTOR); 911 } 912 913 public static ImmutableSet<TypeElement> toTypeElements(Elements elements, String[] classes) { 914 return FluentIterable.from(classes).transform(elements::getTypeElement).toSet(); 915 } 916 917 public static ImmutableSet<ClassName> toClassNames(Iterable<TypeElement> elements) { 918 return FluentIterable.from(elements).transform(ClassName::get).toSet(); 919 } 920 921 public static boolean requiresModuleInstance(Elements elements, TypeElement module) { 922 // Binding methods that lack ABSTRACT or STATIC require module instantiation. 923 // Required by Dagger. See b/31489617. 924 return ElementFilter.methodsIn(elements.getAllMembers(module)).stream() 925 .filter(Processors::isBindingMethod) 926 .map(ExecutableElement::getModifiers) 927 .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC)) 928 // TODO(erichang): Getting a new KotlinMetadataUtil each time isn't great here, but until 929 // we have some sort of dependency management it will be difficult to share the instance. 930 && !KotlinMetadataUtils.getMetadataUtil().isObjectOrCompanionObjectClass(module); 931 } 932 933 public static boolean hasVisibleEmptyConstructor(TypeElement type) { 934 List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements()); 935 return constructors.isEmpty() 936 || constructors.stream() 937 .filter(constructor -> constructor.getParameters().isEmpty()) 938 .anyMatch( 939 constructor -> 940 !constructor.getModifiers().contains(Modifier.PRIVATE) 941 ); 942 } 943 944 private static boolean isBindingMethod(ExecutableElement method) { 945 return hasAnnotation(method, ClassNames.PROVIDES) 946 || hasAnnotation(method, ClassNames.BINDS) 947 || hasAnnotation(method, ClassNames.BINDS_OPTIONAL_OF) 948 || hasAnnotation(method, ClassNames.MULTIBINDS); 949 } 950 951 public static void addGeneratedAnnotation( 952 TypeSpec.Builder typeSpecBuilder, ProcessingEnvironment env, Class<?> generatorClass) { 953 addGeneratedAnnotation(typeSpecBuilder, env, generatorClass.getName()); 954 } 955 956 public static void addGeneratedAnnotation( 957 TypeSpec.Builder typeSpecBuilder, ProcessingEnvironment env, String generatorClass) { 958 GeneratedAnnotations.generatedAnnotation(env.getElementUtils(), env.getSourceVersion()) 959 .ifPresent( 960 annotation -> 961 typeSpecBuilder.addAnnotation( 962 AnnotationSpec.builder(ClassName.get(annotation)) 963 .addMember("value", "$S", generatorClass) 964 .build())); 965 } 966 967 public static AnnotationSpec getOriginatingElementAnnotation(TypeElement element) { 968 TypeName rawType = rawTypeName(ClassName.get(getTopLevelType(element))); 969 return AnnotationSpec.builder(ClassNames.ORIGINATING_ELEMENT) 970 .addMember("topLevelClass", "$T.class", rawType) 971 .build(); 972 } 973 974 /** 975 * Returns the {@link TypeName} for the raw type of the given type name. If the argument isn't a 976 * parameterized type, it returns the argument unchanged. 977 */ 978 public static TypeName rawTypeName(TypeName typeName) { 979 return (typeName instanceof ParameterizedTypeName) 980 ? ((ParameterizedTypeName) typeName).rawType 981 : typeName; 982 } 983 984 public static Optional<TypeElement> getOriginatingTestElement( 985 Element element, Elements elements) { 986 TypeElement topLevelType = getOriginatingTopLevelType(element, elements); 987 return hasAnnotation(topLevelType, ClassNames.HILT_ANDROID_TEST) 988 ? Optional.of(asType(topLevelType)) 989 : Optional.empty(); 990 } 991 992 private static TypeElement getOriginatingTopLevelType(Element element, Elements elements) { 993 TypeElement topLevelType = getTopLevelType(element); 994 if (hasAnnotation(topLevelType, ClassNames.ORIGINATING_ELEMENT)) { 995 return getOriginatingTopLevelType( 996 getAnnotationClassValue( 997 elements, 998 getAnnotationMirror(topLevelType, ClassNames.ORIGINATING_ELEMENT), 999 "topLevelClass"), 1000 elements); 1001 } 1002 1003 return topLevelType; 1004 } 1005 1006 private Processors() {} 1007 } 1008