• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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