Home | History | Annotate | Download | only in annotation
      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