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