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