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