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