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