• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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.common;
17 
18 import java.util.List;
19 import java.util.Map;
20 import java.util.stream.StreamSupport;
21 import javax.lang.model.element.AnnotationMirror;
22 import javax.lang.model.element.AnnotationValue;
23 import javax.lang.model.element.AnnotationValueVisitor;
24 import javax.lang.model.element.Element;
25 import javax.lang.model.element.ElementVisitor;
26 import javax.lang.model.element.ExecutableElement;
27 import javax.lang.model.element.PackageElement;
28 import javax.lang.model.element.TypeElement;
29 import javax.lang.model.element.TypeParameterElement;
30 import javax.lang.model.element.VariableElement;
31 import javax.lang.model.type.ArrayType;
32 import javax.lang.model.type.DeclaredType;
33 import javax.lang.model.type.ErrorType;
34 import javax.lang.model.type.ExecutableType;
35 import javax.lang.model.type.TypeKind;
36 import javax.lang.model.type.TypeMirror;
37 import javax.lang.model.type.TypeVisitor;
38 import javax.lang.model.type.WildcardType;
39 import javax.lang.model.util.AbstractElementVisitor8;
40 import javax.lang.model.util.SimpleAnnotationValueVisitor8;
41 import javax.lang.model.util.SimpleTypeVisitor8;
42 
43 /**
44  * A utility class that traverses {@link Element} instances and ensures that all type information
45  * is present and resolvable.
46  *
47  * @author Gregory Kick
48  */
49 public final class SuperficialValidation {
50   /**
51    * Returns true if all of the given elements return true from {@link #validateElement(Element)}.
52    */
validateElements(Iterable<? extends Element> elements)53   public static boolean validateElements(Iterable<? extends Element> elements) {
54     return StreamSupport.stream(elements.spliterator(), false)
55         .allMatch(SuperficialValidation::validateElement);
56   }
57 
58   private static final ElementVisitor<Boolean, Void> ELEMENT_VALIDATING_VISITOR =
59       new AbstractElementVisitor8<Boolean, Void>() {
60         @Override
61         public Boolean visitPackage(PackageElement e, Void p) {
62           // don't validate enclosed elements because it will return types in the package
63           return validateAnnotations(e.getAnnotationMirrors());
64         }
65 
66         @Override
67         public Boolean visitType(TypeElement e, Void p) {
68           return isValidBaseElement(e)
69               && validateElements(e.getTypeParameters())
70               && validateTypes(e.getInterfaces())
71               && validateType(e.getSuperclass());
72         }
73 
74         @Override
75         public Boolean visitVariable(VariableElement e, Void p) {
76           return isValidBaseElement(e);
77         }
78 
79         @Override
80         public Boolean visitExecutable(ExecutableElement e, Void p) {
81           AnnotationValue defaultValue = e.getDefaultValue();
82           return isValidBaseElement(e)
83               && (defaultValue == null || validateAnnotationValue(defaultValue, e.getReturnType()))
84               && validateType(e.getReturnType())
85               && validateTypes(e.getThrownTypes())
86               && validateElements(e.getTypeParameters())
87               && validateElements(e.getParameters());
88         }
89 
90         @Override
91         public Boolean visitTypeParameter(TypeParameterElement e, Void p) {
92           return isValidBaseElement(e) && validateTypes(e.getBounds());
93         }
94 
95         @Override
96         public Boolean visitUnknown(Element e, Void p) {
97           // just assume that unknown elements are OK
98           return true;
99         }
100       };
101 
102   /**
103    * Returns true if all types referenced by the given element are defined. The exact meaning of
104    * this depends on the kind of element. For packages, it means that all annotations on the package
105    * are fully defined. For other element kinds, it means that types referenced by the element,
106    * anything it contains, and any of its annotations element are all defined.
107    */
validateElement(Element element)108   public static boolean validateElement(Element element) {
109     return element.accept(ELEMENT_VALIDATING_VISITOR, null);
110   }
111 
isValidBaseElement(Element e)112   private static boolean isValidBaseElement(Element e) {
113     return validateType(e.asType())
114         && validateAnnotations(e.getAnnotationMirrors())
115         && validateElements(e.getEnclosedElements());
116   }
117 
validateTypes(Iterable<? extends TypeMirror> types)118   private static boolean validateTypes(Iterable<? extends TypeMirror> types) {
119     for (TypeMirror type : types) {
120       if (!validateType(type)) {
121         return false;
122       }
123     }
124     return true;
125   }
126 
127   /*
128    * This visitor does not test type variables specifically, but it seems that that is not actually
129    * an issue.  Javac turns the whole type parameter into an error type if it can't figure out the
130    * bounds.
131    */
132   private static final TypeVisitor<Boolean, Void> TYPE_VALIDATING_VISITOR =
133       new SimpleTypeVisitor8<Boolean, Void>() {
134         @Override
135         protected Boolean defaultAction(TypeMirror t, Void p) {
136           return true;
137         }
138 
139         @Override
140         public Boolean visitArray(ArrayType t, Void p) {
141           return validateType(t.getComponentType());
142         }
143 
144         @Override
145         public Boolean visitDeclared(DeclaredType t, Void p) {
146           return validateTypes(t.getTypeArguments());
147         }
148 
149         @Override
150         public Boolean visitError(ErrorType t, Void p) {
151           return false;
152         }
153 
154         @Override
155         public Boolean visitUnknown(TypeMirror t, Void p) {
156           // just make the default choice for unknown types
157           return defaultAction(t, p);
158         }
159 
160         @Override
161         public Boolean visitWildcard(WildcardType t, Void p) {
162           TypeMirror extendsBound = t.getExtendsBound();
163           TypeMirror superBound = t.getSuperBound();
164           return (extendsBound == null || validateType(extendsBound))
165               && (superBound == null || validateType(superBound));
166         }
167 
168         @Override
169         public Boolean visitExecutable(ExecutableType t, Void p) {
170           return validateTypes(t.getParameterTypes())
171               && validateType(t.getReturnType())
172               && validateTypes(t.getThrownTypes())
173               && validateTypes(t.getTypeVariables());
174         }
175       };
176 
177   /**
178    * Returns true if the given type is fully defined. This means that the type itself is defined, as
179    * are any types it references, such as any type arguments or type bounds. For an {@link
180    * ExecutableType}, the parameter and return types must be fully defined, as must types declared
181    * in a {@code throws} clause or in the bounds of any type parameters.
182    */
validateType(TypeMirror type)183   public static boolean validateType(TypeMirror type) {
184     return type.accept(TYPE_VALIDATING_VISITOR, null);
185   }
186 
validateAnnotations( Iterable<? extends AnnotationMirror> annotationMirrors)187   private static boolean validateAnnotations(
188       Iterable<? extends AnnotationMirror> annotationMirrors) {
189     for (AnnotationMirror annotationMirror : annotationMirrors) {
190       if (!validateAnnotation(annotationMirror)) {
191         return false;
192       }
193     }
194     return true;
195   }
196 
validateAnnotation(AnnotationMirror annotationMirror)197   private static boolean validateAnnotation(AnnotationMirror annotationMirror) {
198     return validateType(annotationMirror.getAnnotationType())
199         && validateAnnotationValues(annotationMirror.getElementValues());
200   }
201 
validateAnnotationValues( Map<? extends ExecutableElement, ? extends AnnotationValue> valueMap)202   private static boolean validateAnnotationValues(
203       Map<? extends ExecutableElement, ? extends AnnotationValue> valueMap) {
204     return valueMap.entrySet().stream()
205         .allMatch(
206             valueEntry -> {
207               TypeMirror expectedType = valueEntry.getKey().getReturnType();
208               return validateAnnotationValue(valueEntry.getValue(), expectedType);
209             });
210   }
211 
212   private static final AnnotationValueVisitor<Boolean, TypeMirror> VALUE_VALIDATING_VISITOR =
213       new SimpleAnnotationValueVisitor8<Boolean, TypeMirror>() {
214         @Override
215         protected Boolean defaultAction(Object o, TypeMirror expectedType) {
216           return MoreTypes.isTypeOf(o.getClass(), expectedType);
217         }
218 
219         @Override
220         public Boolean visitUnknown(AnnotationValue av, TypeMirror expectedType) {
221           // just take the default action for the unknown
222           return defaultAction(av, expectedType);
223         }
224 
225         @Override
226         public Boolean visitAnnotation(AnnotationMirror a, TypeMirror expectedType) {
227           return MoreTypes.equivalence().equivalent(a.getAnnotationType(), expectedType)
228               && validateAnnotation(a);
229         }
230 
231         @Override
232         public Boolean visitArray(List<? extends AnnotationValue> values, TypeMirror expectedType) {
233           if (!expectedType.getKind().equals(TypeKind.ARRAY)) {
234             return false;
235           }
236           TypeMirror componentType = MoreTypes.asArray(expectedType).getComponentType();
237           return values.stream().allMatch(value -> value.accept(this, componentType));
238         }
239 
240         @Override
241         public Boolean visitEnumConstant(VariableElement enumConstant, TypeMirror expectedType) {
242           return MoreTypes.equivalence().equivalent(enumConstant.asType(), expectedType)
243               && validateElement(enumConstant);
244         }
245 
246         @Override
247         public Boolean visitType(TypeMirror type, TypeMirror ignored) {
248           // We could check assignability here, but would require a Types instance. Since this
249           // isn't really the sort of thing that shows up in a bad AST from upstream compilation
250           // we ignore the expected type and just validate the type.  It might be wrong, but
251           // it's valid.
252           return validateType(type);
253         }
254 
255         @Override
256         public Boolean visitBoolean(boolean b, TypeMirror expectedType) {
257           return MoreTypes.isTypeOf(Boolean.TYPE, expectedType);
258         }
259 
260         @Override
261         public Boolean visitByte(byte b, TypeMirror expectedType) {
262           return MoreTypes.isTypeOf(Byte.TYPE, expectedType);
263         }
264 
265         @Override
266         public Boolean visitChar(char c, TypeMirror expectedType) {
267           return MoreTypes.isTypeOf(Character.TYPE, expectedType);
268         }
269 
270         @Override
271         public Boolean visitDouble(double d, TypeMirror expectedType) {
272           return MoreTypes.isTypeOf(Double.TYPE, expectedType);
273         }
274 
275         @Override
276         public Boolean visitFloat(float f, TypeMirror expectedType) {
277           return MoreTypes.isTypeOf(Float.TYPE, expectedType);
278         }
279 
280         @Override
281         public Boolean visitInt(int i, TypeMirror expectedType) {
282           return MoreTypes.isTypeOf(Integer.TYPE, expectedType);
283         }
284 
285         @Override
286         public Boolean visitLong(long l, TypeMirror expectedType) {
287           return MoreTypes.isTypeOf(Long.TYPE, expectedType);
288         }
289 
290         @Override
291         public Boolean visitShort(short s, TypeMirror expectedType) {
292           return MoreTypes.isTypeOf(Short.TYPE, expectedType);
293         }
294       };
295 
validateAnnotationValue( AnnotationValue annotationValue, TypeMirror expectedType)296   private static boolean validateAnnotationValue(
297       AnnotationValue annotationValue, TypeMirror expectedType) {
298     return annotationValue.accept(VALUE_VALIDATING_VISITOR, expectedType);
299   }
300 
SuperficialValidation()301   private SuperficialValidation() {}
302 }
303