1 /* 2 * Copyright 2018 Google LLC 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 package com.google.auto.value.processor; 17 18 import static com.google.auto.common.AnnotationMirrors.getAnnotationValue; 19 import static com.google.auto.common.GeneratedAnnotations.generatedAnnotation; 20 import static com.google.auto.common.MoreElements.getPackage; 21 import static com.google.auto.common.MoreElements.isAnnotationPresent; 22 import static com.google.auto.value.processor.ClassNames.AUTO_VALUE_PACKAGE_NAME; 23 import static com.google.auto.value.processor.ClassNames.COPY_ANNOTATIONS_NAME; 24 import static com.google.common.collect.Iterables.getOnlyElement; 25 import static com.google.common.collect.Sets.union; 26 import static java.util.stream.Collectors.joining; 27 import static java.util.stream.Collectors.toCollection; 28 import static java.util.stream.Collectors.toList; 29 import static java.util.stream.Collectors.toSet; 30 31 import com.google.auto.common.MoreElements; 32 import com.google.auto.common.MoreTypes; 33 import com.google.auto.common.Visibility; 34 import com.google.auto.value.processor.MissingTypes.MissingTypeException; 35 import com.google.common.base.Throwables; 36 import com.google.common.collect.ImmutableBiMap; 37 import com.google.common.collect.ImmutableList; 38 import com.google.common.collect.ImmutableListMultimap; 39 import com.google.common.collect.ImmutableMap; 40 import com.google.common.collect.ImmutableSet; 41 import java.io.IOException; 42 import java.io.Serializable; 43 import java.io.Writer; 44 import java.lang.annotation.ElementType; 45 import java.lang.annotation.Inherited; 46 import java.lang.annotation.Target; 47 import java.util.ArrayList; 48 import java.util.Arrays; 49 import java.util.Collection; 50 import java.util.EnumMap; 51 import java.util.HashSet; 52 import java.util.LinkedHashMap; 53 import java.util.List; 54 import java.util.Map; 55 import java.util.Optional; 56 import java.util.OptionalInt; 57 import java.util.Set; 58 import java.util.function.Predicate; 59 import javax.annotation.processing.AbstractProcessor; 60 import javax.annotation.processing.ProcessingEnvironment; 61 import javax.annotation.processing.RoundEnvironment; 62 import javax.lang.model.SourceVersion; 63 import javax.lang.model.element.AnnotationMirror; 64 import javax.lang.model.element.AnnotationValue; 65 import javax.lang.model.element.Element; 66 import javax.lang.model.element.ElementKind; 67 import javax.lang.model.element.ExecutableElement; 68 import javax.lang.model.element.Modifier; 69 import javax.lang.model.element.Name; 70 import javax.lang.model.element.QualifiedNameable; 71 import javax.lang.model.element.TypeElement; 72 import javax.lang.model.element.TypeParameterElement; 73 import javax.lang.model.element.VariableElement; 74 import javax.lang.model.type.DeclaredType; 75 import javax.lang.model.type.TypeKind; 76 import javax.lang.model.type.TypeMirror; 77 import javax.lang.model.util.ElementFilter; 78 import javax.lang.model.util.Elements; 79 import javax.lang.model.util.SimpleAnnotationValueVisitor8; 80 import javax.lang.model.util.Types; 81 import javax.tools.Diagnostic; 82 import javax.tools.JavaFileObject; 83 84 /** 85 * Shared code between AutoValueProcessor and AutoOneOfProcessor. 86 * 87 * @author emcmanus@google.com (Éamonn McManus) 88 */ 89 abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { 90 private final String annotationClassName; 91 92 /** 93 * Qualified names of {@code @AutoValue} or {@code AutoOneOf} classes that we attempted to process 94 * but had to abandon because we needed other types that they referenced and those other types 95 * were missing. 96 */ 97 private final List<String> deferredTypeNames = new ArrayList<>(); 98 AutoValueOrOneOfProcessor(String annotationClassName)99 AutoValueOrOneOfProcessor(String annotationClassName) { 100 this.annotationClassName = annotationClassName; 101 } 102 103 /** The annotation we are processing, {@code AutoValue} or {@code AutoOneOf}. */ 104 private TypeElement annotationType; 105 /** The simple name of {@link #annotationType}. */ 106 private String simpleAnnotationName; 107 108 private ErrorReporter errorReporter; 109 110 @Override init(ProcessingEnvironment processingEnv)111 public synchronized void init(ProcessingEnvironment processingEnv) { 112 super.init(processingEnv); 113 errorReporter = new ErrorReporter(processingEnv); 114 } 115 errorReporter()116 final ErrorReporter errorReporter() { 117 return errorReporter; 118 } 119 typeUtils()120 final Types typeUtils() { 121 return processingEnv.getTypeUtils(); 122 } 123 elementUtils()124 final Elements elementUtils() { 125 return processingEnv.getElementUtils(); 126 } 127 128 /** 129 * Qualified names of {@code @AutoValue} or {@code AutoOneOf} classes that we attempted to process 130 * but had to abandon because we needed other types that they referenced and those other types 131 * were missing. This is used by tests. 132 */ deferredTypeNames()133 final ImmutableList<String> deferredTypeNames() { 134 return ImmutableList.copyOf(deferredTypeNames); 135 } 136 137 @Override getSupportedSourceVersion()138 public final SourceVersion getSupportedSourceVersion() { 139 return SourceVersion.latestSupported(); 140 } 141 142 /** 143 * A property of an {@code @AutoValue} or {@code @AutoOneOf} class, defined by one of its abstract 144 * methods. An instance of this class is made available to the Velocity template engine for each 145 * property. The public methods of this class define JavaBeans-style properties that are 146 * accessible from templates. For example {@link #getType()} means we can write {@code $p.type} 147 * for a Velocity variable {@code $p} that is a {@code Property}. 148 */ 149 public static class Property { 150 private final String name; 151 private final String identifier; 152 private final ExecutableElement method; 153 private final String type; 154 private final ImmutableList<String> fieldAnnotations; 155 private final ImmutableList<String> methodAnnotations; 156 private final Optional<String> nullableAnnotation; 157 private final Optionalish optional; 158 Property( String name, String identifier, ExecutableElement method, String type, ImmutableList<String> fieldAnnotations, ImmutableList<String> methodAnnotations, Optional<String> nullableAnnotation)159 Property( 160 String name, 161 String identifier, 162 ExecutableElement method, 163 String type, 164 ImmutableList<String> fieldAnnotations, 165 ImmutableList<String> methodAnnotations, 166 Optional<String> nullableAnnotation) { 167 this.name = name; 168 this.identifier = identifier; 169 this.method = method; 170 this.type = type; 171 this.fieldAnnotations = fieldAnnotations; 172 this.methodAnnotations = methodAnnotations; 173 this.nullableAnnotation = nullableAnnotation; 174 TypeMirror propertyType = method.getReturnType(); 175 this.optional = Optionalish.createIfOptional(propertyType); 176 } 177 178 /** 179 * Returns the name of the property as it should be used when declaring identifiers (fields and 180 * parameters). If the original getter method was {@code foo()} then this will be {@code foo}. 181 * If it was {@code getFoo()} then it will be {@code foo}. If it was {@code getPackage()} then 182 * it will be something like {@code package0}, since {@code package} is a reserved word. 183 */ 184 @Override toString()185 public String toString() { 186 return identifier; 187 } 188 189 /** 190 * Returns the name of the property as it should be used in strings visible to users. This is 191 * usually the same as {@code toString()}, except that if we had to use an identifier like 192 * "package0" because "package" is a reserved word, the name here will be the original 193 * "package". 194 */ getName()195 public String getName() { 196 return name; 197 } 198 199 /** 200 * Returns the name of the getter method for this property as defined by the {@code @AutoValue} 201 * class. For property {@code foo}, this will be {@code foo} or {@code getFoo} or {@code isFoo}. 202 */ getGetter()203 public String getGetter() { 204 return method.getSimpleName().toString(); 205 } 206 getTypeMirror()207 public TypeMirror getTypeMirror() { 208 return method.getReturnType(); 209 } 210 getType()211 public String getType() { 212 return type; 213 } 214 getKind()215 public TypeKind getKind() { 216 return method.getReturnType().getKind(); 217 } 218 219 /** 220 * Returns the annotations (in string form) that should be applied to the property's field 221 * declaration. 222 */ getFieldAnnotations()223 public List<String> getFieldAnnotations() { 224 return fieldAnnotations; 225 } 226 227 /** 228 * Returns the annotations (in string form) that should be applied to the property's method 229 * implementation. 230 */ getMethodAnnotations()231 public List<String> getMethodAnnotations() { 232 return methodAnnotations; 233 } 234 235 /** 236 * Returns an {@link Optionalish} representing the kind of Optional that this property's type 237 * is, or null if the type is not an Optional of any kind. 238 */ getOptional()239 public Optionalish getOptional() { 240 return optional; 241 } 242 243 /** 244 * Returns the string to use as a method annotation to indicate the nullability of this 245 * property. It is either the empty string, if the property is not nullable, or an annotation 246 * string with a trailing space, such as {@code "@`javax.annotation.Nullable` "}, where the 247 * {@code ``} is the encoding used by {@link TypeEncoder}. If the property is nullable by virtue 248 * of its <i>type</i> rather than its method being {@code @Nullable}, this method returns the 249 * empty string, because the {@code @Nullable} will appear when the type is spelled out. In this 250 * case, {@link #nullableAnnotation} is present but empty. 251 */ getNullableAnnotation()252 public final String getNullableAnnotation() { 253 return nullableAnnotation.orElse(""); 254 } 255 isNullable()256 public boolean isNullable() { 257 return nullableAnnotation.isPresent(); 258 } 259 getAccess()260 public String getAccess() { 261 return SimpleMethod.access(method); 262 } 263 264 @Override equals(Object obj)265 public boolean equals(Object obj) { 266 return obj instanceof Property && ((Property) obj).method.equals(method); 267 } 268 269 @Override hashCode()270 public int hashCode() { 271 return method.hashCode(); 272 } 273 } 274 275 @Override process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)276 public final boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 277 annotationType = elementUtils().getTypeElement(annotationClassName); 278 if (annotationType == null) { 279 // This should not happen. If the annotation type is not found, how did the processor get 280 // triggered? 281 processingEnv 282 .getMessager() 283 .printMessage( 284 Diagnostic.Kind.ERROR, 285 "Did not process @" 286 + annotationClassName 287 + " because the annotation class was not found"); 288 return false; 289 } 290 simpleAnnotationName = annotationType.getSimpleName().toString(); 291 List<TypeElement> deferredTypes = 292 deferredTypeNames 293 .stream() 294 .map(name -> elementUtils().getTypeElement(name)) 295 .collect(toList()); 296 if (roundEnv.processingOver()) { 297 // This means that the previous round didn't generate any new sources, so we can't have found 298 // any new instances of @AutoValue; and we can't have any new types that are the reason a type 299 // was in deferredTypes. 300 for (TypeElement type : deferredTypes) { 301 errorReporter.reportError( 302 type, 303 "[AutoValueUndefined] Did not generate @%s class for %s because it references" 304 + " undefined types", 305 simpleAnnotationName, 306 type.getQualifiedName()); 307 } 308 return false; 309 } 310 Collection<? extends Element> annotatedElements = 311 roundEnv.getElementsAnnotatedWith(annotationType); 312 List<TypeElement> types = 313 new ImmutableList.Builder<TypeElement>() 314 .addAll(deferredTypes) 315 .addAll(ElementFilter.typesIn(annotatedElements)) 316 .build(); 317 deferredTypeNames.clear(); 318 for (TypeElement type : types) { 319 try { 320 processType(type); 321 } catch (AbortProcessingException e) { 322 // We abandoned this type; continue with the next. 323 } catch (MissingTypeException e) { 324 // We abandoned this type, but only because we needed another type that it references and 325 // that other type was missing. It is possible that the missing type will be generated by 326 // further annotation processing, so we will try again on the next round (perhaps failing 327 // again and adding it back to the list). We save the name of the @AutoValue type rather 328 // than its TypeElement because it is not guaranteed that it will be represented by 329 // the same TypeElement on the next round. 330 deferredTypeNames.add(type.getQualifiedName().toString()); 331 } catch (RuntimeException e) { 332 String trace = Throwables.getStackTraceAsString(e); 333 errorReporter.reportError( 334 type, 335 "[AutoValueException] @%s processor threw an exception: %s", 336 simpleAnnotationName, 337 trace); 338 throw e; 339 } 340 } 341 return false; // never claim annotation, because who knows what other processors want? 342 } 343 344 /** 345 * Analyzes a single {@code @AutoValue} or {@code @AutoOneOf} class, and outputs the corresponding 346 * implementation class or classes. 347 * 348 * @param type the class with the {@code @AutoValue} or {@code @AutoOneOf} annotation. 349 */ processType(TypeElement type)350 abstract void processType(TypeElement type); 351 352 /** 353 * Returns the appropriate {@code @Nullable} annotation to put on the implementation of the given 354 * property method, and indicates whether the property is in fact nullable. The annotation in 355 * question is on the method, not its return type. If instead the return type is 356 * {@code @Nullable}, this method returns {@code Optional.of("")}, to indicate that the property 357 * is nullable but the <i>method</i> isn't. The {@code @Nullable} annotation will instead appear 358 * when the return type of the method is spelled out in the implementation. 359 */ nullableAnnotationForMethod(ExecutableElement propertyMethod)360 abstract Optional<String> nullableAnnotationForMethod(ExecutableElement propertyMethod); 361 362 /** 363 * Returns the ordered set of {@link Property} definitions for the given {@code @AutoValue} or 364 * {@code AutoOneOf} type. 365 * 366 * @param annotatedPropertyMethods a map from property methods to the method annotations that 367 * should go on the implementation of those methods. These annotations are method annotations 368 * specifically. Type annotations do not appear because they are considered part of the return 369 * type and will appear when that is spelled out. Annotations that are excluded by {@code 370 * AutoValue.CopyAnnotations} also do not appear here. 371 */ propertySet( ImmutableMap<ExecutableElement, TypeMirror> propertyMethodsAndTypes, ImmutableListMultimap<ExecutableElement, AnnotationMirror> annotatedPropertyFields, ImmutableListMultimap<ExecutableElement, AnnotationMirror> annotatedPropertyMethods)372 final ImmutableSet<Property> propertySet( 373 ImmutableMap<ExecutableElement, TypeMirror> propertyMethodsAndTypes, 374 ImmutableListMultimap<ExecutableElement, AnnotationMirror> annotatedPropertyFields, 375 ImmutableListMultimap<ExecutableElement, AnnotationMirror> annotatedPropertyMethods) { 376 ImmutableBiMap<ExecutableElement, String> methodToPropertyName = 377 propertyNameToMethodMap(propertyMethodsAndTypes.keySet()).inverse(); 378 Map<ExecutableElement, String> methodToIdentifier = new LinkedHashMap<>(methodToPropertyName); 379 fixReservedIdentifiers(methodToIdentifier); 380 381 ImmutableSet.Builder<Property> props = ImmutableSet.builder(); 382 propertyMethodsAndTypes.forEach( 383 (propertyMethod, returnType) -> { 384 String propertyType = 385 TypeEncoder.encodeWithAnnotations( 386 returnType, getExcludedAnnotationTypes(propertyMethod)); 387 String propertyName = methodToPropertyName.get(propertyMethod); 388 String identifier = methodToIdentifier.get(propertyMethod); 389 ImmutableList<String> fieldAnnotations = 390 annotationStrings(annotatedPropertyFields.get(propertyMethod)); 391 ImmutableList<AnnotationMirror> methodAnnotationMirrors = 392 annotatedPropertyMethods.get(propertyMethod); 393 ImmutableList<String> methodAnnotations = annotationStrings(methodAnnotationMirrors); 394 Optional<String> nullableAnnotation = nullableAnnotationForMethod(propertyMethod); 395 Property p = 396 new Property( 397 propertyName, 398 identifier, 399 propertyMethod, 400 propertyType, 401 fieldAnnotations, 402 methodAnnotations, 403 nullableAnnotation); 404 props.add(p); 405 if (p.isNullable() && returnType.getKind().isPrimitive()) { 406 errorReporter() 407 .reportError( 408 propertyMethod, "[AutoValueNullPrimitive] Primitive types cannot be @Nullable"); 409 } 410 }); 411 return props.build(); 412 } 413 414 /** Defines the template variables that are shared by AutoValue and AutoOneOf. */ defineSharedVarsForType( TypeElement type, ImmutableSet<ExecutableElement> methods, AutoValueOrOneOfTemplateVars vars)415 final void defineSharedVarsForType( 416 TypeElement type, 417 ImmutableSet<ExecutableElement> methods, 418 AutoValueOrOneOfTemplateVars vars) { 419 vars.pkg = TypeSimplifier.packageNameOf(type); 420 vars.origClass = TypeSimplifier.classNameOf(type); 421 vars.simpleClassName = TypeSimplifier.simpleNameOf(vars.origClass); 422 vars.generated = 423 generatedAnnotation(elementUtils(), processingEnv.getSourceVersion()) 424 .map(annotation -> TypeEncoder.encode(annotation.asType())) 425 .orElse(""); 426 vars.formalTypes = TypeEncoder.formalTypeParametersString(type); 427 vars.actualTypes = TypeSimplifier.actualTypeParametersString(type); 428 vars.wildcardTypes = wildcardTypeParametersString(type); 429 vars.annotations = copiedClassAnnotations(type); 430 Map<ObjectMethod, ExecutableElement> methodsToGenerate = 431 determineObjectMethodsToGenerate(methods); 432 vars.toString = methodsToGenerate.containsKey(ObjectMethod.TO_STRING); 433 vars.equals = methodsToGenerate.containsKey(ObjectMethod.EQUALS); 434 vars.hashCode = methodsToGenerate.containsKey(ObjectMethod.HASH_CODE); 435 vars.equalsParameterType = equalsParameterType(methodsToGenerate); 436 } 437 438 /** Returns the spelling to be used in the generated code for the given list of annotations. */ annotationStrings(List<? extends AnnotationMirror> annotations)439 static ImmutableList<String> annotationStrings(List<? extends AnnotationMirror> annotations) { 440 // TODO(b/68008628): use ImmutableList.toImmutableList() when that works. 441 return ImmutableList.copyOf( 442 annotations.stream().map(AnnotationOutput::sourceFormForAnnotation).collect(toList())); 443 } 444 445 /** 446 * Returns the name of the generated {@code @AutoValue} or {@code @AutoOneOf} class, for example 447 * {@code AutoOneOf_TaskResult} or {@code $$AutoValue_SimpleMethod}. 448 * 449 * @param type the name of the type bearing the {@code @AutoValue} or {@code @AutoOneOf} 450 * annotation. 451 * @param prefix the prefix to use in the generated class. This may start with one or more dollar 452 * signs, for an {@code @AutoValue} implementation where there are AutoValue extensions. 453 */ generatedClassName(TypeElement type, String prefix)454 static String generatedClassName(TypeElement type, String prefix) { 455 String name = type.getSimpleName().toString(); 456 while (type.getEnclosingElement() instanceof TypeElement) { 457 type = (TypeElement) type.getEnclosingElement(); 458 name = type.getSimpleName() + "_" + name; 459 } 460 String pkg = TypeSimplifier.packageNameOf(type); 461 String dot = pkg.isEmpty() ? "" : "."; 462 return pkg + dot + prefix + name; 463 } 464 isJavaLangObject(TypeElement type)465 private static boolean isJavaLangObject(TypeElement type) { 466 return type.getSuperclass().getKind() == TypeKind.NONE && type.getKind() == ElementKind.CLASS; 467 } 468 469 enum ObjectMethod { 470 NONE, 471 TO_STRING, 472 EQUALS, 473 HASH_CODE 474 } 475 476 /** 477 * Determines which of the three public non-final methods from {@code java.lang.Object}, if any, 478 * is overridden by the given method. 479 */ objectMethodToOverride(ExecutableElement method)480 static ObjectMethod objectMethodToOverride(ExecutableElement method) { 481 String name = method.getSimpleName().toString(); 482 switch (method.getParameters().size()) { 483 case 0: 484 if (name.equals("toString")) { 485 return ObjectMethod.TO_STRING; 486 } else if (name.equals("hashCode")) { 487 return ObjectMethod.HASH_CODE; 488 } 489 break; 490 case 1: 491 if (name.equals("equals")) { 492 TypeMirror param = getOnlyElement(method.getParameters()).asType(); 493 if (param.getKind().equals(TypeKind.DECLARED)) { 494 TypeElement paramType = MoreTypes.asTypeElement(param); 495 if (paramType.getQualifiedName().contentEquals("java.lang.Object")) { 496 return ObjectMethod.EQUALS; 497 } 498 } 499 } 500 break; 501 default: 502 // No relevant Object methods have more than one parameter. 503 } 504 return ObjectMethod.NONE; 505 } 506 507 /** Returns a bi-map between property names and the corresponding abstract property methods. */ propertyNameToMethodMap( Set<ExecutableElement> propertyMethods)508 final ImmutableBiMap<String, ExecutableElement> propertyNameToMethodMap( 509 Set<ExecutableElement> propertyMethods) { 510 Map<String, ExecutableElement> map = new LinkedHashMap<>(); 511 Set<String> reportedDups = new HashSet<>(); 512 boolean allPrefixed = gettersAllPrefixed(propertyMethods); 513 for (ExecutableElement method : propertyMethods) { 514 String methodName = method.getSimpleName().toString(); 515 String name = allPrefixed ? nameWithoutPrefix(methodName) : methodName; 516 ExecutableElement old = map.put(name, method); 517 if (old != null) { 518 List<ExecutableElement> contexts = new ArrayList<>(Arrays.asList(method)); 519 if (reportedDups.add(name)) { 520 contexts.add(old); 521 } 522 // Report the error for both of the methods. If this is a third or further occurrence, 523 // reportedDups prevents us from reporting more than one error for the same method. 524 for (ExecutableElement context : contexts) { 525 errorReporter.reportError( 526 context, 527 "[AutoValueDupProperty] More than one @%s property called %s", 528 simpleAnnotationName, 529 name); 530 } 531 } 532 } 533 return ImmutableBiMap.copyOf(map); 534 } 535 gettersAllPrefixed(Set<ExecutableElement> methods)536 private static boolean gettersAllPrefixed(Set<ExecutableElement> methods) { 537 return prefixedGettersIn(methods).size() == methods.size(); 538 } 539 540 /** 541 * Returns an appropriate annotation spelling to indicate the nullability of an element. If the 542 * return value is a non-empty Optional, that indicates that the element is nullable, and the 543 * string should be used to annotate it. If the return value is an empty Optional, the element is 544 * not nullable. The return value can be {@code Optional.of("")}, which indicates that the element 545 * is nullable but that the nullability comes from a type annotation. In this case, the annotation 546 * will appear when the type is written, and must not be specified again. If the Optional contains 547 * a present non-empty string then that string will end with a space. 548 * 549 * @param element the element that might be {@code @Nullable}, either a method or a parameter. 550 * @param elementType the relevant type of the element: the return type for a method, or the 551 * parameter type for a parameter. 552 */ nullableAnnotationFor(Element element, TypeMirror elementType)553 static Optional<String> nullableAnnotationFor(Element element, TypeMirror elementType) { 554 List<? extends AnnotationMirror> typeAnnotations = elementType.getAnnotationMirrors(); 555 if (nullableAnnotationIndex(typeAnnotations).isPresent()) { 556 return Optional.of(""); 557 } 558 List<? extends AnnotationMirror> elementAnnotations = element.getAnnotationMirrors(); 559 OptionalInt nullableAnnotationIndex = nullableAnnotationIndex(elementAnnotations); 560 if (nullableAnnotationIndex.isPresent()) { 561 ImmutableList<String> annotations = annotationStrings(elementAnnotations); 562 return Optional.of(annotations.get(nullableAnnotationIndex.getAsInt()) + " "); 563 } else { 564 return Optional.empty(); 565 } 566 } 567 nullableAnnotationIndex(List<? extends AnnotationMirror> annotations)568 private static OptionalInt nullableAnnotationIndex(List<? extends AnnotationMirror> annotations) { 569 for (int i = 0; i < annotations.size(); i++) { 570 if (isNullable(annotations.get(i))) { 571 return OptionalInt.of(i); 572 } 573 } 574 return OptionalInt.empty(); 575 } 576 isNullable(AnnotationMirror annotation)577 private static boolean isNullable(AnnotationMirror annotation) { 578 return annotation.getAnnotationType().asElement().getSimpleName().contentEquals("Nullable"); 579 } 580 581 /** 582 * Returns the subset of the given zero-arg methods whose names begin with {@code get}. Also 583 * includes {@code isFoo} methods if they return {@code boolean}. This corresponds to JavaBeans 584 * conventions. 585 */ prefixedGettersIn(Iterable<ExecutableElement> methods)586 static ImmutableSet<ExecutableElement> prefixedGettersIn(Iterable<ExecutableElement> methods) { 587 ImmutableSet.Builder<ExecutableElement> getters = ImmutableSet.builder(); 588 for (ExecutableElement method : methods) { 589 String name = method.getSimpleName().toString(); 590 // Note that getfoo() (without a capital) is still a getter. 591 boolean get = name.startsWith("get") && !name.equals("get"); 592 boolean is = 593 name.startsWith("is") 594 && !name.equals("is") 595 && method.getReturnType().getKind() == TypeKind.BOOLEAN; 596 if (get || is) { 597 getters.add(method); 598 } 599 } 600 return getters.build(); 601 } 602 603 /** 604 * Returns the name of the property defined by the given getter. A getter called {@code getFoo()} 605 * or {@code isFoo()} defines a property called {@code foo}. For consistency with JavaBeans, a 606 * getter called {@code getHTMLPage()} defines a property called {@code HTMLPage}. The <a 607 * href="https://docs.oracle.com/javase/8/docs/api/java/beans/Introspector.html#decapitalize-java.lang.String-"> 608 * rule</a> is: the name of the property is the part after {@code get} or {@code is}, with the 609 * first letter lowercased <i>unless</i> the first two letters are uppercase. This works well for 610 * the {@code HTMLPage} example, but in these more enlightened times we use {@code HtmlPage} 611 * anyway, so the special behaviour is not useful, and of course it behaves poorly with examples 612 * like {@code OAuth}. 613 */ nameWithoutPrefix(String name)614 private static String nameWithoutPrefix(String name) { 615 if (name.startsWith("get")) { 616 name = name.substring(3); 617 } else { 618 assert name.startsWith("is"); 619 name = name.substring(2); 620 } 621 return PropertyNames.decapitalizeLikeJavaBeans(name); 622 } 623 624 /** 625 * Checks that, if the given {@code @AutoValue} or {@code @AutoOneOf} class is nested, it is 626 * static and not private. This check is not necessary for correctness, since the generated code 627 * would not compile if the check fails, but it produces better error messages for the user. 628 */ checkModifiersIfNested(TypeElement type)629 final void checkModifiersIfNested(TypeElement type) { 630 ElementKind enclosingKind = type.getEnclosingElement().getKind(); 631 if (enclosingKind.isClass() || enclosingKind.isInterface()) { 632 if (type.getModifiers().contains(Modifier.PRIVATE)) { 633 errorReporter.abortWithError( 634 type, "[AutoValuePrivate] @%s class must not be private", simpleAnnotationName); 635 } else if (Visibility.effectiveVisibilityOfElement(type).equals(Visibility.PRIVATE)) { 636 // The previous case, where the class itself is private, is much commoner so it deserves 637 // its own error message, even though it would be caught by the test here too. 638 errorReporter.abortWithError( 639 type, 640 "[AutoValueInPrivate] @%s class must not be nested in a private class", 641 simpleAnnotationName); 642 } 643 if (!type.getModifiers().contains(Modifier.STATIC)) { 644 errorReporter.abortWithError( 645 type, "[AutoValueInner] Nested @%s class must be static", simpleAnnotationName); 646 } 647 } 648 // In principle type.getEnclosingElement() could be an ExecutableElement (for a class 649 // declared inside a method), but since RoundEnvironment.getElementsAnnotatedWith doesn't 650 // return such classes we won't see them here. 651 } 652 653 /** 654 * Modifies the values of the given map to avoid reserved words. If we have a getter called {@code 655 * getPackage()} then we can't use the identifier {@code package} to represent its value since 656 * that's a reserved word. 657 */ fixReservedIdentifiers(Map<?, String> methodToIdentifier)658 static void fixReservedIdentifiers(Map<?, String> methodToIdentifier) { 659 for (Map.Entry<?, String> entry : methodToIdentifier.entrySet()) { 660 String name = entry.getValue(); 661 if (SourceVersion.isKeyword(name) || !Character.isJavaIdentifierStart(name.codePointAt(0))) { 662 entry.setValue(disambiguate(name, methodToIdentifier.values())); 663 } 664 } 665 } 666 disambiguate(String name, Collection<String> existingNames)667 private static String disambiguate(String name, Collection<String> existingNames) { 668 if (!Character.isJavaIdentifierStart(name.codePointAt(0))) { 669 // You've defined a getter called get1st(). What were you thinking? 670 name = "_" + name; 671 if (!existingNames.contains(name)) { 672 return name; 673 } 674 } 675 for (int i = 0; ; i++) { 676 String candidate = name + i; 677 if (!existingNames.contains(candidate)) { 678 return candidate; 679 } 680 } 681 } 682 683 /** 684 * Given a list of all methods defined in or inherited by a class, returns a map indicating which 685 * of equals, hashCode, and toString should be generated. Each value in the map is the method that 686 * will be overridden by the generated method, which might be a method in {@code Object} or an 687 * abstract method in the {@code @AutoValue} class or an ancestor. 688 */ determineObjectMethodsToGenerate( Set<ExecutableElement> methods)689 private static Map<ObjectMethod, ExecutableElement> determineObjectMethodsToGenerate( 690 Set<ExecutableElement> methods) { 691 Map<ObjectMethod, ExecutableElement> methodsToGenerate = new EnumMap<>(ObjectMethod.class); 692 for (ExecutableElement method : methods) { 693 ObjectMethod override = objectMethodToOverride(method); 694 boolean canGenerate = 695 method.getModifiers().contains(Modifier.ABSTRACT) 696 || isJavaLangObject((TypeElement) method.getEnclosingElement()); 697 if (!override.equals(ObjectMethod.NONE) && canGenerate) { 698 methodsToGenerate.put(override, method); 699 } 700 } 701 return methodsToGenerate; 702 } 703 704 /** 705 * Returns the encoded parameter type of the {@code equals(Object)} method that is to be 706 * generated, or an empty string if the method is not being generated. The parameter type includes 707 * any type annotations, for example {@code @Nullable}. 708 */ equalsParameterType(Map<ObjectMethod, ExecutableElement> methodsToGenerate)709 static String equalsParameterType(Map<ObjectMethod, ExecutableElement> methodsToGenerate) { 710 ExecutableElement equals = methodsToGenerate.get(ObjectMethod.EQUALS); 711 if (equals == null) { 712 return ""; // this will not be referenced because no equals method will be generated 713 } 714 TypeMirror parameterType = equals.getParameters().get(0).asType(); 715 return TypeEncoder.encodeWithAnnotations(parameterType); 716 } 717 718 /** 719 * Returns the subset of all abstract methods in the given set of methods. A given method 720 * signature is only mentioned once, even if it is inherited on more than one path. If any of the 721 * abstract methods has a return type or parameter type that is not currently defined then this 722 * method will throw an exception that will cause us to defer processing of the current class 723 * until a later annotation-processing round. 724 */ abstractMethodsIn(Iterable<ExecutableElement> methods)725 static ImmutableSet<ExecutableElement> abstractMethodsIn(Iterable<ExecutableElement> methods) { 726 Set<Name> noArgMethods = new HashSet<>(); 727 ImmutableSet.Builder<ExecutableElement> abstracts = ImmutableSet.builder(); 728 for (ExecutableElement method : methods) { 729 if (method.getModifiers().contains(Modifier.ABSTRACT)) { 730 MissingTypes.deferIfMissingTypesIn(method); 731 boolean hasArgs = !method.getParameters().isEmpty(); 732 if (hasArgs || noArgMethods.add(method.getSimpleName())) { 733 // If an abstract method with the same signature is inherited on more than one path, 734 // we only add it once. At the moment we only do this check for no-arg methods. All 735 // methods that AutoValue will implement are either no-arg methods or equals(Object). 736 // The former is covered by this check and the latter will lead to vars.equals being 737 // set to true, regardless of how many times it appears. So the only case that is 738 // covered imperfectly here is that of a method that is inherited on more than one path 739 // and that will be consumed by an extension. We could check parameters as well, but that 740 // can be a bit tricky if any of the parameters are generic. 741 abstracts.add(method); 742 } 743 } 744 } 745 return abstracts.build(); 746 } 747 748 /** 749 * Returns the subset of property methods in the given set of abstract methods, with their actual 750 * return types. A property method has no arguments, is not void, and is not {@code hashCode()} or 751 * {@code toString()}. 752 */ propertyMethodsIn( Set<ExecutableElement> abstractMethods, TypeElement autoValueOrOneOfType)753 ImmutableMap<ExecutableElement, TypeMirror> propertyMethodsIn( 754 Set<ExecutableElement> abstractMethods, 755 TypeElement autoValueOrOneOfType) { 756 DeclaredType declaredType = MoreTypes.asDeclared(autoValueOrOneOfType.asType()); 757 ImmutableSet.Builder<ExecutableElement> properties = ImmutableSet.builder(); 758 for (ExecutableElement method : abstractMethods) { 759 if (method.getParameters().isEmpty() 760 && (method.getReturnType().getKind() != TypeKind.VOID || propertiesCanBeVoid()) 761 && objectMethodToOverride(method) == ObjectMethod.NONE) { 762 properties.add(method); 763 } 764 } 765 return new EclipseHack(processingEnv).methodReturnTypes(properties.build(), declaredType); 766 } 767 768 /** True if void properties are allowed. */ propertiesCanBeVoid()769 boolean propertiesCanBeVoid() { 770 return false; 771 } 772 773 /** 774 * Checks that the return type of the given property method is allowed. Currently, this means that 775 * it cannot be an array, unless it is a primitive array. 776 */ checkReturnType(TypeElement autoValueClass, ExecutableElement getter)777 final void checkReturnType(TypeElement autoValueClass, ExecutableElement getter) { 778 TypeMirror type = getter.getReturnType(); 779 if (type.getKind() == TypeKind.ARRAY) { 780 TypeMirror componentType = MoreTypes.asArray(type).getComponentType(); 781 if (componentType.getKind().isPrimitive()) { 782 warnAboutPrimitiveArrays(autoValueClass, getter); 783 } else { 784 errorReporter.reportError( 785 getter, 786 "[AutoValueArray] An @%s class cannot define an array-valued property unless it is a" 787 + " primitive array", 788 simpleAnnotationName); 789 } 790 } 791 } 792 warnAboutPrimitiveArrays(TypeElement autoValueClass, ExecutableElement getter)793 private void warnAboutPrimitiveArrays(TypeElement autoValueClass, ExecutableElement getter) { 794 boolean suppressed = false; 795 Optional<AnnotationMirror> maybeAnnotation = 796 getAnnotationMirror(getter, "java.lang.SuppressWarnings"); 797 if (maybeAnnotation.isPresent()) { 798 AnnotationValue listValue = getAnnotationValue(maybeAnnotation.get(), "value"); 799 suppressed = listValue.accept(new ContainsMutableVisitor(), null); 800 } 801 if (!suppressed) { 802 // If the primitive-array property method is defined directly inside the @AutoValue class, 803 // then our error message should point directly to it. But if it is inherited, we don't 804 // want to try to make the error message point to the inherited definition, since that would 805 // be confusing (there is nothing wrong with the definition itself), and won't work if the 806 // inherited class is not being recompiled. Instead, in this case we point to the @AutoValue 807 // class itself, and we include extra text in the error message that shows the full name of 808 // the inherited method. 809 boolean sameClass = getter.getEnclosingElement().equals(autoValueClass); 810 Element element = sameClass ? getter : autoValueClass; 811 String context = sameClass ? "" : (" Method: " + getter.getEnclosingElement() + "." + getter); 812 errorReporter.reportWarning( 813 element, 814 "[AutoValueMutable] An @%s property that is a primitive array returns the original" 815 + " array, which can therefore be modified by the caller. If this is OK, you can" 816 + " suppress this warning with @SuppressWarnings(\"mutable\"). Otherwise, you should" 817 + " replace the property with an immutable type, perhaps a simple wrapper around the" 818 + " original array.%s", 819 simpleAnnotationName, 820 context); 821 } 822 } 823 824 // Detects whether the visited AnnotationValue is an array that contains the string "mutable". 825 // The simpler approach using Element.getAnnotation(SuppressWarnings.class) doesn't work if 826 // the annotation has an undefined reference, like @SuppressWarnings(UNDEFINED). 827 // TODO(emcmanus): replace with a method from auto-common when that is available. 828 private static class ContainsMutableVisitor extends SimpleAnnotationValueVisitor8<Boolean, Void> { 829 @Override visitArray(List<? extends AnnotationValue> list, Void p)830 public Boolean visitArray(List<? extends AnnotationValue> list, Void p) { 831 return list.stream().map(AnnotationValue::getValue).anyMatch("mutable"::equals); 832 } 833 } 834 835 /** 836 * Returns a string like {@code "1234L"} if {@code type instanceof Serializable} and defines 837 * {@code serialVersionUID = 1234L}; otherwise {@code ""}. 838 */ getSerialVersionUID(TypeElement type)839 final String getSerialVersionUID(TypeElement type) { 840 TypeMirror serializable = elementUtils().getTypeElement(Serializable.class.getName()).asType(); 841 if (typeUtils().isAssignable(type.asType(), serializable)) { 842 List<VariableElement> fields = ElementFilter.fieldsIn(type.getEnclosedElements()); 843 for (VariableElement field : fields) { 844 if (field.getSimpleName().contentEquals("serialVersionUID")) { 845 Object value = field.getConstantValue(); 846 if (field.getModifiers().containsAll(Arrays.asList(Modifier.STATIC, Modifier.FINAL)) 847 && field.asType().getKind() == TypeKind.LONG 848 && value != null) { 849 return value + "L"; 850 } else { 851 errorReporter.reportError( 852 field, "serialVersionUID must be a static final long compile-time constant"); 853 break; 854 } 855 } 856 } 857 } 858 return ""; 859 } 860 861 /** Implements the semantics of {@code AutoValue.CopyAnnotations}; see its javadoc. */ annotationsToCopy( Element autoValueType, Element typeOrMethod, Set<String> excludedAnnotations)862 ImmutableList<AnnotationMirror> annotationsToCopy( 863 Element autoValueType, Element typeOrMethod, Set<String> excludedAnnotations) { 864 ImmutableList.Builder<AnnotationMirror> result = ImmutableList.builder(); 865 for (AnnotationMirror annotation : typeOrMethod.getAnnotationMirrors()) { 866 String annotationFqName = getAnnotationFqName(annotation); 867 // To be included, the annotation should not be in com.google.auto.value, 868 // and it should not be in the excludedAnnotations set. 869 if (!isInAutoValuePackage(annotationFqName) 870 && !excludedAnnotations.contains(annotationFqName) 871 && annotationVisibleFrom(annotation, autoValueType)) { 872 result.add(annotation); 873 } 874 } 875 876 return result.build(); 877 } 878 879 /** 880 * True if the given class name is in the com.google.auto.value package or a subpackage. False if 881 * the class name contains {@code Test}, since many AutoValue tests under com.google.auto.value 882 * define their own annotations. 883 */ isInAutoValuePackage(String className)884 private boolean isInAutoValuePackage(String className) { 885 return className.startsWith(AUTO_VALUE_PACKAGE_NAME) && !className.contains("Test"); 886 } 887 copiedClassAnnotations(TypeElement type)888 ImmutableList<String> copiedClassAnnotations(TypeElement type) { 889 // Only copy annotations from a class if it has @AutoValue.CopyAnnotations. 890 if (hasAnnotationMirror(type, COPY_ANNOTATIONS_NAME)) { 891 Set<String> excludedAnnotations = 892 union(getExcludedAnnotationClassNames(type), getAnnotationsMarkedWithInherited(type)); 893 894 return copyAnnotations(type, type, excludedAnnotations); 895 } else { 896 return ImmutableList.of(); 897 } 898 } 899 900 /** Implements the semantics of {@code AutoValue.CopyAnnotations}; see its javadoc. */ copyAnnotations( Element autoValueType, Element typeOrMethod, Set<String> excludedAnnotations)901 private ImmutableList<String> copyAnnotations( 902 Element autoValueType, Element typeOrMethod, Set<String> excludedAnnotations) { 903 ImmutableList<AnnotationMirror> annotationsToCopy = 904 annotationsToCopy(autoValueType, typeOrMethod, excludedAnnotations); 905 return annotationStrings(annotationsToCopy); 906 } 907 908 /** 909 * Returns the contents of the {@code AutoValue.CopyAnnotations.exclude} element, as a set of 910 * {@code TypeMirror} where each type is an annotation type. 911 */ getExcludedAnnotationTypes(Element element)912 private Set<TypeMirror> getExcludedAnnotationTypes(Element element) { 913 Optional<AnnotationMirror> maybeAnnotation = 914 getAnnotationMirror(element, COPY_ANNOTATIONS_NAME); 915 if (!maybeAnnotation.isPresent()) { 916 return ImmutableSet.of(); 917 } 918 919 @SuppressWarnings("unchecked") 920 List<AnnotationValue> excludedClasses = 921 (List<AnnotationValue>) getAnnotationValue(maybeAnnotation.get(), "exclude").getValue(); 922 return excludedClasses 923 .stream() 924 .map(annotationValue -> (DeclaredType) annotationValue.getValue()) 925 .collect(toCollection(TypeMirrorSet::new)); 926 } 927 928 /** 929 * Returns the contents of the {@code AutoValue.CopyAnnotations.exclude} element, as a set of 930 * strings that are fully-qualified class names. 931 */ getExcludedAnnotationClassNames(Element element)932 private Set<String> getExcludedAnnotationClassNames(Element element) { 933 return getExcludedAnnotationTypes(element) 934 .stream() 935 .map(MoreTypes::asTypeElement) 936 .map(typeElement -> typeElement.getQualifiedName().toString()) 937 .collect(toSet()); 938 } 939 getAnnotationsMarkedWithInherited(Element element)940 private static Set<String> getAnnotationsMarkedWithInherited(Element element) { 941 return element 942 .getAnnotationMirrors() 943 .stream() 944 .filter(a -> isAnnotationPresent(a.getAnnotationType().asElement(), Inherited.class)) 945 .map(a -> getAnnotationFqName(a)) 946 .collect(toSet()); 947 } 948 949 /** 950 * Returns the fully-qualified name of an annotation-mirror, e.g. 951 * "com.google.auto.value.AutoValue". 952 */ getAnnotationFqName(AnnotationMirror annotation)953 private static String getAnnotationFqName(AnnotationMirror annotation) { 954 return ((QualifiedNameable) annotation.getAnnotationType().asElement()) 955 .getQualifiedName() 956 .toString(); 957 } 958 propertyMethodAnnotationMap( TypeElement type, ImmutableSet<ExecutableElement> propertyMethods)959 final ImmutableListMultimap<ExecutableElement, AnnotationMirror> propertyMethodAnnotationMap( 960 TypeElement type, ImmutableSet<ExecutableElement> propertyMethods) { 961 ImmutableListMultimap.Builder<ExecutableElement, AnnotationMirror> builder = 962 ImmutableListMultimap.builder(); 963 for (ExecutableElement propertyMethod : propertyMethods) { 964 builder.putAll(propertyMethod, propertyMethodAnnotations(type, propertyMethod)); 965 } 966 return builder.build(); 967 } 968 propertyMethodAnnotations( TypeElement type, ExecutableElement method)969 private ImmutableList<AnnotationMirror> propertyMethodAnnotations( 970 TypeElement type, ExecutableElement method) { 971 ImmutableSet<String> excludedAnnotations = 972 ImmutableSet.<String>builder() 973 .addAll(getExcludedAnnotationClassNames(method)) 974 .add(Override.class.getCanonicalName()) 975 .build(); 976 977 // We need to exclude type annotations from the ones being output on the method, since 978 // they will be output as part of the method's return type. 979 Set<String> returnTypeAnnotations = getReturnTypeAnnotations(method, a -> true); 980 Set<String> excluded = union(excludedAnnotations, returnTypeAnnotations); 981 return annotationsToCopy(type, method, excluded); 982 } 983 propertyFieldAnnotationMap( TypeElement type, ImmutableSet<ExecutableElement> propertyMethods)984 final ImmutableListMultimap<ExecutableElement, AnnotationMirror> propertyFieldAnnotationMap( 985 TypeElement type, ImmutableSet<ExecutableElement> propertyMethods) { 986 ImmutableListMultimap.Builder<ExecutableElement, AnnotationMirror> builder = 987 ImmutableListMultimap.builder(); 988 for (ExecutableElement propertyMethod : propertyMethods) { 989 builder.putAll(propertyMethod, propertyFieldAnnotations(type, propertyMethod)); 990 } 991 return builder.build(); 992 } 993 propertyFieldAnnotations( TypeElement type, ExecutableElement method)994 private ImmutableList<AnnotationMirror> propertyFieldAnnotations( 995 TypeElement type, ExecutableElement method) { 996 if (!hasAnnotationMirror(method, COPY_ANNOTATIONS_NAME)) { 997 return ImmutableList.of(); 998 } 999 ImmutableSet<String> excludedAnnotations = 1000 ImmutableSet.<String>builder() 1001 .addAll(getExcludedAnnotationClassNames(method)) 1002 .add(Override.class.getCanonicalName()) 1003 .build(); 1004 1005 // We need to exclude type annotations from the ones being output on the method, since 1006 // they will be output as part of the field's type. 1007 Set<String> returnTypeAnnotations = 1008 getReturnTypeAnnotations(method, this::annotationAppliesToFields); 1009 Set<String> nonFieldAnnotations = 1010 method 1011 .getAnnotationMirrors() 1012 .stream() 1013 .map(a -> a.getAnnotationType().asElement()) 1014 .map(MoreElements::asType) 1015 .filter(a -> !annotationAppliesToFields(a)) 1016 .map(e -> e.getQualifiedName().toString()) 1017 .collect(toSet()); 1018 1019 Set<String> excluded = 1020 ImmutableSet.<String>builder() 1021 .addAll(excludedAnnotations) 1022 .addAll(returnTypeAnnotations) 1023 .addAll(nonFieldAnnotations) 1024 .build(); 1025 return annotationsToCopy(type, method, excluded); 1026 } 1027 getReturnTypeAnnotations( ExecutableElement method, Predicate<TypeElement> typeFilter)1028 private Set<String> getReturnTypeAnnotations( 1029 ExecutableElement method, Predicate<TypeElement> typeFilter) { 1030 return method 1031 .getReturnType() 1032 .getAnnotationMirrors() 1033 .stream() 1034 .map(a -> a.getAnnotationType().asElement()) 1035 .map(MoreElements::asType) 1036 .filter(typeFilter) 1037 .map(e -> e.getQualifiedName().toString()) 1038 .collect(toSet()); 1039 } 1040 annotationAppliesToFields(TypeElement annotation)1041 private boolean annotationAppliesToFields(TypeElement annotation) { 1042 Target target = annotation.getAnnotation(Target.class); 1043 return target == null || Arrays.asList(target.value()).contains(ElementType.FIELD); 1044 } 1045 annotationVisibleFrom(AnnotationMirror annotation, Element from)1046 private boolean annotationVisibleFrom(AnnotationMirror annotation, Element from) { 1047 Element annotationElement = annotation.getAnnotationType().asElement(); 1048 Visibility visibility = Visibility.effectiveVisibilityOfElement(annotationElement); 1049 switch (visibility) { 1050 case PUBLIC: 1051 return true; 1052 case PROTECTED: 1053 // If the annotation is protected, it must be inside another class, call it C. If our 1054 // @AutoValue class is Foo then, for the annotation to be visible, either Foo must be in the 1055 // same package as C or Foo must be a subclass of C. If the annotation is visible from Foo 1056 // then it is also visible from our generated subclass AutoValue_Foo. 1057 // The protected case only applies to method annotations. An annotation on the AutoValue_Foo 1058 // class itself can't be protected, even if AutoValue_Foo ultimately inherits from the 1059 // class that defines the annotation. The JLS says "Access is permitted only within the 1060 // body of a subclass": 1061 // https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2.1 1062 // AutoValue_Foo is a top-level class, so an annotation on it cannot be in the body of a 1063 // subclass of anything. 1064 return getPackage(annotationElement).equals(getPackage(from)) 1065 || typeUtils() 1066 .isSubtype(from.asType(), annotationElement.getEnclosingElement().asType()); 1067 case DEFAULT: 1068 return getPackage(annotationElement).equals(getPackage(from)); 1069 default: 1070 return false; 1071 } 1072 } 1073 1074 /** 1075 * Returns the {@code @AutoValue} or {@code @AutoOneOf} type parameters, with a ? for every type. 1076 * If we have {@code @AutoValue abstract class Foo<T extends Something>} then this method will 1077 * return just {@code <?>}. 1078 */ wildcardTypeParametersString(TypeElement type)1079 private static String wildcardTypeParametersString(TypeElement type) { 1080 List<? extends TypeParameterElement> typeParameters = type.getTypeParameters(); 1081 if (typeParameters.isEmpty()) { 1082 return ""; 1083 } else { 1084 return typeParameters.stream().map(e -> "?").collect(joining(", ", "<", ">")); 1085 } 1086 } 1087 1088 // TODO(emcmanus,ronshapiro): move to auto-common getAnnotationMirror(Element element, String annotationName)1089 static Optional<AnnotationMirror> getAnnotationMirror(Element element, String annotationName) { 1090 for (AnnotationMirror annotation : element.getAnnotationMirrors()) { 1091 TypeElement annotationElement = MoreTypes.asTypeElement(annotation.getAnnotationType()); 1092 if (annotationElement.getQualifiedName().contentEquals(annotationName)) { 1093 return Optional.of(annotation); 1094 } 1095 } 1096 return Optional.empty(); 1097 } 1098 hasAnnotationMirror(Element element, String annotationName)1099 static boolean hasAnnotationMirror(Element element, String annotationName) { 1100 return getAnnotationMirror(element, annotationName).isPresent(); 1101 } 1102 writeSourceFile(String className, String text, TypeElement originatingType)1103 final void writeSourceFile(String className, String text, TypeElement originatingType) { 1104 try { 1105 JavaFileObject sourceFile = 1106 processingEnv.getFiler().createSourceFile(className, originatingType); 1107 try (Writer writer = sourceFile.openWriter()) { 1108 writer.write(text); 1109 } 1110 } catch (IOException e) { 1111 // This should really be an error, but we make it a warning in the hope of resisting Eclipse 1112 // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599. If that bug manifests, we may get 1113 // invoked more than once for the same file, so ignoring the ability to overwrite it is the 1114 // right thing to do. If we are unable to write for some other reason, we should get a compile 1115 // error later because user code will have a reference to the code we were supposed to 1116 // generate (new AutoValue_Foo() or whatever) and that reference will be undefined. 1117 errorReporter.reportWarning( 1118 originatingType, 1119 "[AutoValueCouldNotWrite] Could not write generated class %s: %s", 1120 className, 1121 e); 1122 } 1123 } 1124 } 1125