1 /* 2 * Copyright (C) 2015 The Android Open Source Project 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 android.databinding.tool.reflection.annotation; 17 18 import org.antlr.v4.codegen.model.decl.Decl; 19 20 import android.databinding.tool.reflection.ModelAnalyzer; 21 import android.databinding.tool.reflection.ModelClass; 22 import android.databinding.tool.reflection.ModelField; 23 import android.databinding.tool.reflection.ModelMethod; 24 import android.databinding.tool.reflection.TypeUtil; 25 import android.databinding.tool.util.L; 26 27 import java.util.ArrayList; 28 import java.util.List; 29 30 import javax.lang.model.element.AnnotationMirror; 31 import javax.lang.model.element.AnnotationValue; 32 import javax.lang.model.element.Element; 33 import javax.lang.model.element.ElementKind; 34 import javax.lang.model.element.ExecutableElement; 35 import javax.lang.model.element.TypeElement; 36 import javax.lang.model.element.VariableElement; 37 import javax.lang.model.type.ArrayType; 38 import javax.lang.model.type.DeclaredType; 39 import javax.lang.model.type.PrimitiveType; 40 import javax.lang.model.type.TypeKind; 41 import javax.lang.model.type.TypeMirror; 42 import javax.lang.model.util.ElementFilter; 43 import javax.lang.model.util.Elements; 44 import javax.lang.model.util.Types; 45 46 /** 47 * This is the implementation of ModelClass for the annotation 48 * processor. It relies on AnnotationAnalyzer. 49 */ 50 class AnnotationClass extends ModelClass { 51 52 final TypeMirror mTypeMirror; 53 54 public AnnotationClass(TypeMirror typeMirror) { 55 mTypeMirror = typeMirror; 56 } 57 58 @Override 59 public String toJavaCode() { 60 return mTypeMirror.toString(); 61 } 62 63 @Override 64 public boolean isArray() { 65 return mTypeMirror.getKind() == TypeKind.ARRAY; 66 } 67 68 @Override 69 public AnnotationClass getComponentType() { 70 TypeMirror component = null; 71 if (isArray()) { 72 component = ((ArrayType) mTypeMirror).getComponentType(); 73 } else if (isList()) { 74 for (ModelMethod method : getMethods("get", 1)) { 75 ModelClass parameter = method.getParameterTypes()[0]; 76 if (parameter.isInt() || parameter.isLong()) { 77 ArrayList<ModelClass> parameters = new ArrayList<ModelClass>(1); 78 parameters.add(parameter); 79 return (AnnotationClass) method.getReturnType(parameters); 80 } 81 } 82 // no "get" call found! 83 return null; 84 } else { 85 AnnotationClass mapClass = (AnnotationClass) ModelAnalyzer.getInstance().getMapType(); 86 DeclaredType mapType = findInterface(mapClass.mTypeMirror); 87 if (mapType == null) { 88 return null; 89 } 90 component = mapType.getTypeArguments().get(1); 91 } 92 93 return new AnnotationClass(component); 94 } 95 96 private DeclaredType findInterface(TypeMirror interfaceType) { 97 Types typeUtil = getTypeUtils(); 98 TypeMirror foundInterface = null; 99 if (typeUtil.isSameType(interfaceType, typeUtil.erasure(mTypeMirror))) { 100 foundInterface = mTypeMirror; 101 } else { 102 ArrayList<TypeMirror> toCheck = new ArrayList<TypeMirror>(); 103 toCheck.add(mTypeMirror); 104 while (!toCheck.isEmpty()) { 105 TypeMirror typeMirror = toCheck.remove(0); 106 if (typeUtil.isSameType(interfaceType, typeUtil.erasure(typeMirror))) { 107 foundInterface = typeMirror; 108 break; 109 } else { 110 toCheck.addAll(typeUtil.directSupertypes(typeMirror)); 111 } 112 } 113 if (foundInterface == null) { 114 L.e("Detected " + interfaceType + " type for " + mTypeMirror + 115 ", but not able to find the implemented interface."); 116 return null; 117 } 118 } 119 if (foundInterface.getKind() != TypeKind.DECLARED) { 120 L.e("Found " + interfaceType + " type for " + mTypeMirror + 121 ", but it isn't a declared type: " + foundInterface); 122 return null; 123 } 124 return (DeclaredType) foundInterface; 125 } 126 127 @Override 128 public boolean isNullable() { 129 switch (mTypeMirror.getKind()) { 130 case ARRAY: 131 case DECLARED: 132 case NULL: 133 return true; 134 default: 135 return false; 136 } 137 } 138 139 @Override 140 public boolean isPrimitive() { 141 switch (mTypeMirror.getKind()) { 142 case BOOLEAN: 143 case BYTE: 144 case SHORT: 145 case INT: 146 case LONG: 147 case CHAR: 148 case FLOAT: 149 case DOUBLE: 150 return true; 151 default: 152 return false; 153 } 154 } 155 156 @Override 157 public boolean isBoolean() { 158 return mTypeMirror.getKind() == TypeKind.BOOLEAN; 159 } 160 161 @Override 162 public boolean isChar() { 163 return mTypeMirror.getKind() == TypeKind.CHAR; 164 } 165 166 @Override 167 public boolean isByte() { 168 return mTypeMirror.getKind() == TypeKind.BYTE; 169 } 170 171 @Override 172 public boolean isShort() { 173 return mTypeMirror.getKind() == TypeKind.SHORT; 174 } 175 176 @Override 177 public boolean isInt() { 178 return mTypeMirror.getKind() == TypeKind.INT; 179 } 180 181 @Override 182 public boolean isLong() { 183 return mTypeMirror.getKind() == TypeKind.LONG; 184 } 185 186 @Override 187 public boolean isFloat() { 188 return mTypeMirror.getKind() == TypeKind.FLOAT; 189 } 190 191 @Override 192 public boolean isDouble() { 193 return mTypeMirror.getKind() == TypeKind.DOUBLE; 194 } 195 196 @Override 197 public boolean isGeneric() { 198 boolean isGeneric = false; 199 if (mTypeMirror.getKind() == TypeKind.DECLARED) { 200 DeclaredType declaredType = (DeclaredType) mTypeMirror; 201 List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments(); 202 isGeneric = typeArguments != null && !typeArguments.isEmpty(); 203 } 204 return isGeneric; 205 } 206 207 @Override 208 public int getMinApi() { 209 if (mTypeMirror.getKind() == TypeKind.DECLARED) { 210 DeclaredType declaredType = (DeclaredType) mTypeMirror; 211 List<? extends AnnotationMirror> annotations = 212 getElementUtils().getAllAnnotationMirrors(declaredType.asElement()); 213 214 TypeElement targetApi = getElementUtils().getTypeElement("android.annotation.TargetApi"); 215 TypeMirror targetApiType = targetApi.asType(); 216 Types typeUtils = getTypeUtils(); 217 for (AnnotationMirror annotation : annotations) { 218 if (typeUtils.isAssignable(annotation.getAnnotationType(), targetApiType)) { 219 for (AnnotationValue value : annotation.getElementValues().values()) { 220 return (Integer) value.getValue(); 221 } 222 } 223 } 224 } 225 return super.getMinApi(); 226 } 227 228 @Override 229 public List<ModelClass> getTypeArguments() { 230 List<ModelClass> types = null; 231 if (mTypeMirror.getKind() == TypeKind.DECLARED) { 232 DeclaredType declaredType = (DeclaredType) mTypeMirror; 233 List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments(); 234 if (typeArguments != null && !typeArguments.isEmpty()) { 235 types = new ArrayList<ModelClass>(); 236 for (TypeMirror typeMirror : typeArguments) { 237 types.add(new AnnotationClass(typeMirror)); 238 } 239 } 240 } 241 return types; 242 } 243 244 @Override 245 public boolean isTypeVar() { 246 return mTypeMirror.getKind() == TypeKind.TYPEVAR; 247 } 248 249 @Override 250 public boolean isInterface() { 251 return mTypeMirror.getKind() == TypeKind.DECLARED && 252 ((DeclaredType)mTypeMirror).asElement().getKind() == ElementKind.INTERFACE; 253 } 254 255 @Override 256 public boolean isVoid() { 257 return mTypeMirror.getKind() == TypeKind.VOID; 258 } 259 260 @Override 261 public AnnotationClass unbox() { 262 if (!isNullable()) { 263 return this; 264 } 265 try { 266 return new AnnotationClass(getTypeUtils().unboxedType(mTypeMirror)); 267 } catch (IllegalArgumentException e) { 268 // I'm being lazy. This is much easier than checking every type. 269 return this; 270 } 271 } 272 273 @Override 274 public AnnotationClass box() { 275 if (!isPrimitive()) { 276 return this; 277 } 278 return new AnnotationClass(getTypeUtils().boxedClass((PrimitiveType) mTypeMirror).asType()); 279 } 280 281 @Override 282 public boolean isAssignableFrom(ModelClass that) { 283 if (that == null) { 284 return false; 285 } 286 AnnotationClass thatAnnotationClass = (AnnotationClass) that; 287 return getTypeUtils().isAssignable(thatAnnotationClass.mTypeMirror, this.mTypeMirror); 288 } 289 290 @Override 291 public ModelMethod[] getDeclaredMethods() { 292 final ModelMethod[] declaredMethods; 293 if (mTypeMirror.getKind() == TypeKind.DECLARED) { 294 DeclaredType declaredType = (DeclaredType) mTypeMirror; 295 Elements elementUtils = getElementUtils(); 296 TypeElement typeElement = (TypeElement) declaredType.asElement(); 297 List<? extends Element> members = elementUtils.getAllMembers(typeElement); 298 List<ExecutableElement> methods = ElementFilter.methodsIn(members); 299 declaredMethods = new ModelMethod[methods.size()]; 300 for (int i = 0; i < declaredMethods.length; i++) { 301 declaredMethods[i] = new AnnotationMethod(declaredType, methods.get(i)); 302 } 303 } else { 304 declaredMethods = new ModelMethod[0]; 305 } 306 return declaredMethods; 307 } 308 309 @Override 310 public AnnotationClass getSuperclass() { 311 if (mTypeMirror.getKind() == TypeKind.DECLARED) { 312 DeclaredType declaredType = (DeclaredType) mTypeMirror; 313 TypeElement typeElement = (TypeElement) declaredType.asElement(); 314 TypeMirror superClass = typeElement.getSuperclass(); 315 if (superClass.getKind() == TypeKind.DECLARED) { 316 return new AnnotationClass(superClass); 317 } 318 } 319 return null; 320 } 321 322 @Override 323 public String getCanonicalName() { 324 return getTypeUtils().erasure(mTypeMirror).toString(); 325 } 326 327 @Override 328 public ModelClass erasure() { 329 final TypeMirror erasure = getTypeUtils().erasure(mTypeMirror); 330 if (erasure == mTypeMirror) { 331 return this; 332 } else { 333 return new AnnotationClass(erasure); 334 } 335 } 336 337 @Override 338 public String getJniDescription() { 339 return TypeUtil.getInstance().getDescription(this); 340 } 341 342 @Override 343 protected ModelField[] getDeclaredFields() { 344 final ModelField[] declaredFields; 345 if (mTypeMirror.getKind() == TypeKind.DECLARED) { 346 DeclaredType declaredType = (DeclaredType) mTypeMirror; 347 Elements elementUtils = getElementUtils(); 348 TypeElement typeElement = (TypeElement) declaredType.asElement(); 349 List<? extends Element> members = elementUtils.getAllMembers(typeElement); 350 List<VariableElement> fields = ElementFilter.fieldsIn(members); 351 declaredFields = new ModelField[fields.size()]; 352 for (int i = 0; i < declaredFields.length; i++) { 353 declaredFields[i] = new AnnotationField(typeElement, fields.get(i)); 354 } 355 } else { 356 declaredFields = new ModelField[0]; 357 } 358 return declaredFields; 359 } 360 361 @Override 362 public boolean equals(Object obj) { 363 if (obj instanceof AnnotationClass) { 364 return getTypeUtils().isSameType(mTypeMirror, ((AnnotationClass) obj).mTypeMirror); 365 } else { 366 return false; 367 } 368 } 369 370 @Override 371 public int hashCode() { 372 return mTypeMirror.toString().hashCode(); 373 } 374 375 private static Types getTypeUtils() { 376 return AnnotationAnalyzer.get().mProcessingEnv.getTypeUtils(); 377 } 378 379 private static Elements getElementUtils() { 380 return AnnotationAnalyzer.get().mProcessingEnv.getElementUtils(); 381 } 382 383 @Override 384 public String toString() { 385 return mTypeMirror.toString(); 386 } 387 } 388