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