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