• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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