• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.internal.codegen.langmodel;
18 
19 import static com.google.auto.common.MoreElements.asExecutable;
20 import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
21 import static com.google.auto.common.MoreElements.hasModifiers;
22 import static com.google.common.base.Preconditions.checkNotNull;
23 import static com.google.common.collect.Lists.asList;
24 import static java.util.Comparator.comparing;
25 import static java.util.stream.Collectors.toSet;
26 import static javax.lang.model.element.Modifier.ABSTRACT;
27 
28 import com.google.auto.common.MoreElements;
29 import com.google.auto.common.MoreTypes;
30 import com.google.common.collect.FluentIterable;
31 import com.google.common.collect.ImmutableMap;
32 import com.google.common.collect.ImmutableSet;
33 import com.google.common.collect.Iterables;
34 import com.google.common.graph.Traverser;
35 import com.squareup.javapoet.ClassName;
36 import dagger.Reusable;
37 import java.io.Writer;
38 import java.lang.annotation.Annotation;
39 import java.util.Collection;
40 import java.util.Comparator;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Optional;
44 import java.util.Set;
45 import java.util.function.Predicate;
46 import java.util.stream.Collectors;
47 import javax.annotation.processing.ProcessingEnvironment;
48 import javax.lang.model.element.AnnotationMirror;
49 import javax.lang.model.element.AnnotationValue;
50 import javax.lang.model.element.Element;
51 import javax.lang.model.element.ElementKind;
52 import javax.lang.model.element.ElementVisitor;
53 import javax.lang.model.element.ExecutableElement;
54 import javax.lang.model.element.Name;
55 import javax.lang.model.element.PackageElement;
56 import javax.lang.model.element.QualifiedNameable;
57 import javax.lang.model.element.TypeElement;
58 import javax.lang.model.element.VariableElement;
59 import javax.lang.model.type.ArrayType;
60 import javax.lang.model.type.DeclaredType;
61 import javax.lang.model.type.ErrorType;
62 import javax.lang.model.type.ExecutableType;
63 import javax.lang.model.type.IntersectionType;
64 import javax.lang.model.type.NoType;
65 import javax.lang.model.type.NullType;
66 import javax.lang.model.type.PrimitiveType;
67 import javax.lang.model.type.TypeMirror;
68 import javax.lang.model.type.TypeVariable;
69 import javax.lang.model.type.UnionType;
70 import javax.lang.model.type.WildcardType;
71 import javax.lang.model.util.AbstractTypeVisitor8;
72 import javax.lang.model.util.Elements;
73 import javax.lang.model.util.SimpleElementVisitor8;
74 import javax.lang.model.util.Types;
75 
76 /** Extension of {@link Elements} that adds Dagger-specific methods. */
77 @Reusable
78 public final class DaggerElements implements Elements {
79 
80   private final Elements elements;
81   private final Types types;
82 
DaggerElements(Elements elements, Types types)83   public DaggerElements(Elements elements, Types types) {
84     this.elements = checkNotNull(elements);
85     this.types = checkNotNull(types);
86   }
87 
DaggerElements(ProcessingEnvironment processingEnv)88   public DaggerElements(ProcessingEnvironment processingEnv) {
89     this(processingEnv.getElementUtils(), processingEnv.getTypeUtils());
90   }
91 
92   /**
93    * Returns {@code true} if {@code encloser} is equal to {@code enclosed} or recursively encloses
94    * it.
95    */
elementEncloses(TypeElement encloser, Element enclosed)96   public static boolean elementEncloses(TypeElement encloser, Element enclosed) {
97     return Iterables.contains(GET_ENCLOSED_ELEMENTS.breadthFirst(encloser), enclosed);
98   }
99 
100   private static final Traverser<Element> GET_ENCLOSED_ELEMENTS =
101       Traverser.forTree(Element::getEnclosedElements);
102 
getUnimplementedMethods(TypeElement type)103   public ImmutableSet<ExecutableElement> getUnimplementedMethods(TypeElement type) {
104     return FluentIterable.from(getLocalAndInheritedMethods(type, types, elements))
105         .filter(hasModifiers(ABSTRACT))
106         .toSet();
107   }
108 
109   /** Returns the type element for a class. */
getTypeElement(Class<?> clazz)110   public TypeElement getTypeElement(Class<?> clazz) {
111     return getTypeElement(clazz.getCanonicalName());
112   }
113 
114   @Override
getTypeElement(CharSequence name)115   public TypeElement getTypeElement(CharSequence name) {
116     return elements.getTypeElement(name);
117   }
118 
119   /** Returns the type element for a class name. */
getTypeElement(ClassName className)120   public TypeElement getTypeElement(ClassName className) {
121     return getTypeElement(className.withoutAnnotations().toString());
122   }
123 
124   /** Returns the argument or the closest enclosing element that is a {@link TypeElement}. */
closestEnclosingTypeElement(Element element)125   public static TypeElement closestEnclosingTypeElement(Element element) {
126     return element.accept(CLOSEST_ENCLOSING_TYPE_ELEMENT, null);
127   }
128 
129   private static final ElementVisitor<TypeElement, Void> CLOSEST_ENCLOSING_TYPE_ELEMENT =
130       new SimpleElementVisitor8<TypeElement, Void>() {
131         @Override
132         protected TypeElement defaultAction(Element element, Void p) {
133           return element.getEnclosingElement().accept(this, null);
134         }
135 
136         @Override
137         public TypeElement visitType(TypeElement type, Void p) {
138           return type;
139         }
140       };
141 
142   /**
143    * Compares elements according to their declaration order among siblings. Only valid to compare
144    * elements enclosed by the same parent.
145    */
146   public static final Comparator<Element> DECLARATION_ORDER =
147       comparing(element -> siblings(element).indexOf(element));
148 
149   // For parameter elements, element.getEnclosingElement().getEnclosedElements() is empty. So
150   // instead look at the parameter list of the enclosing executable.
siblings(Element element)151   private static List<? extends Element> siblings(Element element) {
152     return element.getKind().equals(ElementKind.PARAMETER)
153         ? asExecutable(element.getEnclosingElement()).getParameters()
154         : element.getEnclosingElement().getEnclosedElements();
155   }
156 
157   /**
158    * Returns {@code true} iff the given element has an {@link AnnotationMirror} whose {@linkplain
159    * AnnotationMirror#getAnnotationType() annotation type} has the same canonical name as any of
160    * that of {@code annotationClasses}.
161    */
isAnyAnnotationPresent( Element element, Iterable<? extends Class<? extends Annotation>> annotationClasses)162   public static boolean isAnyAnnotationPresent(
163       Element element, Iterable<? extends Class<? extends Annotation>> annotationClasses) {
164     for (Class<? extends Annotation> annotation : annotationClasses) {
165       if (MoreElements.isAnnotationPresent(element, annotation)) {
166         return true;
167       }
168     }
169     return false;
170   }
171 
172   @SafeVarargs
isAnyAnnotationPresent( Element element, Class<? extends Annotation> first, Class<? extends Annotation>... otherAnnotations)173   public static boolean isAnyAnnotationPresent(
174       Element element,
175       Class<? extends Annotation> first,
176       Class<? extends Annotation>... otherAnnotations) {
177     return isAnyAnnotationPresent(element, asList(first, otherAnnotations));
178   }
179 
180   /**
181    * Returns {@code true} iff the given element has an {@link AnnotationMirror} whose {@linkplain
182    * AnnotationMirror#getAnnotationType() annotation type} is equivalent to {@code annotationType}.
183    */
isAnnotationPresent(Element element, TypeMirror annotationType)184   public static boolean isAnnotationPresent(Element element, TypeMirror annotationType) {
185     return element.getAnnotationMirrors().stream()
186         .map(AnnotationMirror::getAnnotationType)
187         .anyMatch(candidate -> MoreTypes.equivalence().equivalent(candidate, annotationType));
188   }
189 
190   /**
191    * Returns the annotation present on {@code element} whose type is {@code first} or within {@code
192    * rest}, checking each annotation type in order.
193    */
194   @SafeVarargs
getAnyAnnotation( Element element, Class<? extends Annotation> first, Class<? extends Annotation>... rest)195   public static Optional<AnnotationMirror> getAnyAnnotation(
196       Element element, Class<? extends Annotation> first, Class<? extends Annotation>... rest) {
197     return getAnyAnnotation(element, asList(first, rest));
198   }
199 
200   /**
201    * Returns the annotation present on {@code element} whose type is in {@code annotations},
202    * checking each annotation type in order.
203    */
getAnyAnnotation( Element element, Collection<? extends Class<? extends Annotation>> annotations)204   public static Optional<AnnotationMirror> getAnyAnnotation(
205       Element element, Collection<? extends Class<? extends Annotation>> annotations) {
206     return element.getAnnotationMirrors().stream()
207         .filter(hasAnnotationTypeIn(annotations))
208         .map((AnnotationMirror a) -> a) // Avoid returning Optional<? extends AnnotationMirror>.
209         .findFirst();
210   }
211 
212   /** Returns the annotations present on {@code element} of all types. */
213   @SafeVarargs
getAllAnnotations( Element element, Class<? extends Annotation> first, Class<? extends Annotation>... rest)214   public static ImmutableSet<AnnotationMirror> getAllAnnotations(
215       Element element, Class<? extends Annotation> first, Class<? extends Annotation>... rest) {
216     return ImmutableSet.copyOf(
217         Iterables.filter(
218             element.getAnnotationMirrors(), hasAnnotationTypeIn(asList(first, rest))::test));
219   }
220 
221   /**
222    * Returns an {@link AnnotationMirror} for the annotation of type {@code annotationClass} on
223    * {@code element}, or {@link Optional#empty()} if no such annotation exists. This method is a
224    * safer alternative to calling {@link Element#getAnnotation} as it avoids any interaction with
225    * annotation proxies.
226    */
getAnnotationMirror( Element element, Class<? extends Annotation> annotationClass)227   public static Optional<AnnotationMirror> getAnnotationMirror(
228       Element element, Class<? extends Annotation> annotationClass) {
229     return Optional.ofNullable(MoreElements.getAnnotationMirror(element, annotationClass).orNull());
230   }
231 
hasAnnotationTypeIn( Collection<? extends Class<? extends Annotation>> annotations)232   private static Predicate<AnnotationMirror> hasAnnotationTypeIn(
233       Collection<? extends Class<? extends Annotation>> annotations) {
234     Set<String> annotationClassNames =
235         annotations.stream().map(Class::getCanonicalName).collect(toSet());
236     return annotation ->
237         annotationClassNames.contains(
238             MoreTypes.asTypeElement(annotation.getAnnotationType()).getQualifiedName().toString());
239   }
240 
suppressedWarnings(Element element)241   public static ImmutableSet<String> suppressedWarnings(Element element) {
242     SuppressWarnings suppressedWarnings = element.getAnnotation(SuppressWarnings.class);
243     if (suppressedWarnings == null) {
244       return ImmutableSet.of();
245     }
246     return ImmutableSet.copyOf(suppressedWarnings.value());
247   }
248 
249   /**
250    * Returns the field descriptor of the given {@code element}.
251    *
252    * <p>This is useful for matching Kotlin Metadata JVM Signatures with elements from the AST.
253    *
254    * <p>For reference, see the <a
255    * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2">JVM
256    * specification, section 4.3.2</a>.
257    */
getFieldDescriptor(VariableElement element)258   public static String getFieldDescriptor(VariableElement element) {
259     return element.getSimpleName() + ":" + getDescriptor(element.asType());
260   }
261 
262   /**
263    * Returns the method descriptor of the given {@code element}.
264    *
265    * <p>This is useful for matching Kotlin Metadata JVM Signatures with elements from the AST.
266    *
267    * <p>For reference, see the <a
268    * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3">JVM
269    * specification, section 4.3.3</a>.
270    */
getMethodDescriptor(ExecutableElement element)271   public static String getMethodDescriptor(ExecutableElement element) {
272     return element.getSimpleName() + getDescriptor(element.asType());
273   }
274 
getDescriptor(TypeMirror t)275   private static String getDescriptor(TypeMirror t) {
276     return t.accept(JVM_DESCRIPTOR_TYPE_VISITOR, null);
277   }
278 
279   private static final AbstractTypeVisitor8<String, Void> JVM_DESCRIPTOR_TYPE_VISITOR =
280       new AbstractTypeVisitor8<String, Void>() {
281 
282         @Override
283         public String visitArray(ArrayType arrayType, Void v) {
284           return "[" + getDescriptor(arrayType.getComponentType());
285         }
286 
287         @Override
288         public String visitDeclared(DeclaredType declaredType, Void v) {
289           return "L" + getInternalName(declaredType.asElement()) + ";";
290         }
291 
292         @Override
293         public String visitError(ErrorType errorType, Void v) {
294           // For descriptor generating purposes we don't need a fully modeled type since we are
295           // only interested in obtaining the class name in its "internal form".
296           return visitDeclared(errorType, v);
297         }
298 
299         @Override
300         public String visitExecutable(ExecutableType executableType, Void v) {
301           String parameterDescriptors =
302               executableType.getParameterTypes().stream()
303                   .map(DaggerElements::getDescriptor)
304                   .collect(Collectors.joining());
305           String returnDescriptor = getDescriptor(executableType.getReturnType());
306           return "(" + parameterDescriptors + ")" + returnDescriptor;
307         }
308 
309         @Override
310         public String visitIntersection(IntersectionType intersectionType, Void v) {
311           // For a type variable with multiple bounds: "the erasure of a type variable is determined
312           // by the first type in its bound" - JVM Spec Sec 4.4
313           return getDescriptor(intersectionType.getBounds().get(0));
314         }
315 
316         @Override
317         public String visitNoType(NoType noType, Void v) {
318           return "V";
319         }
320 
321         @Override
322         public String visitNull(NullType nullType, Void v) {
323           return visitUnknown(nullType, null);
324         }
325 
326         @Override
327         public String visitPrimitive(PrimitiveType primitiveType, Void v) {
328           switch (primitiveType.getKind()) {
329             case BOOLEAN:
330               return "Z";
331             case BYTE:
332               return "B";
333             case SHORT:
334               return "S";
335             case INT:
336               return "I";
337             case LONG:
338               return "J";
339             case CHAR:
340               return "C";
341             case FLOAT:
342               return "F";
343             case DOUBLE:
344               return "D";
345             default:
346               throw new IllegalArgumentException("Unknown primitive type.");
347           }
348         }
349 
350         @Override
351         public String visitTypeVariable(TypeVariable typeVariable, Void v) {
352           // The erasure of a type variable is the erasure of its leftmost bound. - JVM Spec Sec 4.6
353           return getDescriptor(typeVariable.getUpperBound());
354         }
355 
356         @Override
357         public String visitUnion(UnionType unionType, Void v) {
358           return visitUnknown(unionType, null);
359         }
360 
361         @Override
362         public String visitUnknown(TypeMirror typeMirror, Void v) {
363           throw new IllegalArgumentException("Unsupported type: " + typeMirror);
364         }
365 
366         @Override
367         public String visitWildcard(WildcardType wildcardType, Void v) {
368           return "";
369         }
370 
371         /**
372          * Returns the name of this element in its "internal form".
373          *
374          * <p>For reference, see the <a
375          * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2">JVM
376          * specification, section 4.2</a>.
377          */
378         private String getInternalName(Element element) {
379           try {
380             TypeElement typeElement = MoreElements.asType(element);
381             switch (typeElement.getNestingKind()) {
382               case TOP_LEVEL:
383                 return typeElement.getQualifiedName().toString().replace('.', '/');
384               case MEMBER:
385                 return getInternalName(typeElement.getEnclosingElement())
386                     + "$"
387                     + typeElement.getSimpleName();
388               default:
389                 throw new IllegalArgumentException("Unsupported nesting kind.");
390             }
391           } catch (IllegalArgumentException e) {
392             // Not a TypeElement, try something else...
393           }
394 
395           if (element instanceof QualifiedNameable) {
396             QualifiedNameable qualifiedNameElement = (QualifiedNameable) element;
397             return qualifiedNameElement.getQualifiedName().toString().replace('.', '/');
398           }
399 
400           return element.getSimpleName().toString();
401         }
402       };
403 
404   /**
405    * Invokes {@link Elements#getTypeElement(CharSequence)}, throwing {@link TypeNotPresentException}
406    * if it is not accessible in the current compilation.
407    */
checkTypePresent(String typeName)408   public TypeElement checkTypePresent(String typeName) {
409     TypeElement type = elements.getTypeElement(typeName);
410     if (type == null) {
411       throw new TypeNotPresentException(typeName, null);
412     }
413     return type;
414   }
415 
416   @Override
getPackageElement(CharSequence name)417   public PackageElement getPackageElement(CharSequence name) {
418     return elements.getPackageElement(name);
419   }
420 
421   @Override
getElementValuesWithDefaults( AnnotationMirror a)422   public Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValuesWithDefaults(
423       AnnotationMirror a) {
424     return elements.getElementValuesWithDefaults(a);
425   }
426 
427   /** Returns a map of annotation values keyed by attribute name. */
getElementValuesWithDefaultsByName( AnnotationMirror a)428   public Map<String, ? extends AnnotationValue> getElementValuesWithDefaultsByName(
429       AnnotationMirror a) {
430     ImmutableMap.Builder<String, AnnotationValue> builder = ImmutableMap.builder();
431     getElementValuesWithDefaults(a).forEach((k, v) -> builder.put(k.getSimpleName().toString(), v));
432     return builder.build();
433   }
434 
435   @Override
getDocComment(Element e)436   public String getDocComment(Element e) {
437     return elements.getDocComment(e);
438   }
439 
440   @Override
isDeprecated(Element e)441   public boolean isDeprecated(Element e) {
442     return elements.isDeprecated(e);
443   }
444 
445   @Override
getBinaryName(TypeElement type)446   public Name getBinaryName(TypeElement type) {
447     return elements.getBinaryName(type);
448   }
449 
450   @Override
getPackageOf(Element type)451   public PackageElement getPackageOf(Element type) {
452     return elements.getPackageOf(type);
453   }
454 
455   @Override
getAllMembers(TypeElement type)456   public List<? extends Element> getAllMembers(TypeElement type) {
457     return elements.getAllMembers(type);
458   }
459 
460   @Override
getAllAnnotationMirrors(Element e)461   public List<? extends AnnotationMirror> getAllAnnotationMirrors(Element e) {
462     return elements.getAllAnnotationMirrors(e);
463   }
464 
465   @Override
hides(Element hider, Element hidden)466   public boolean hides(Element hider, Element hidden) {
467     return elements.hides(hider, hidden);
468   }
469 
470   @Override
overrides( ExecutableElement overrider, ExecutableElement overridden, TypeElement type)471   public boolean overrides(
472       ExecutableElement overrider, ExecutableElement overridden, TypeElement type) {
473     return elements.overrides(overrider, overridden, type);
474   }
475 
476   @Override
getConstantExpression(Object value)477   public String getConstantExpression(Object value) {
478     return elements.getConstantExpression(value);
479   }
480 
481   @Override
printElements(Writer w, Element... elements)482   public void printElements(Writer w, Element... elements) {
483     this.elements.printElements(w, elements);
484   }
485 
486   @Override
getName(CharSequence cs)487   public Name getName(CharSequence cs) {
488     return elements.getName(cs);
489   }
490 
491   @Override
isFunctionalInterface(TypeElement type)492   public boolean isFunctionalInterface(TypeElement type) {
493     return elements.isFunctionalInterface(type);
494   }
495 }
496