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