• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AnnotationClass(TypeMirror typeMirror)54     public AnnotationClass(TypeMirror typeMirror) {
55         mTypeMirror = typeMirror;
56     }
57 
58     @Override
toJavaCode()59     public String toJavaCode() {
60         return mTypeMirror.toString();
61     }
62 
63     @Override
isArray()64     public boolean isArray() {
65         return mTypeMirror.getKind() == TypeKind.ARRAY;
66     }
67 
68     @Override
getComponentType()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 
findInterface(TypeMirror interfaceType)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
isNullable()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
isPrimitive()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
isBoolean()157     public boolean isBoolean() {
158         return mTypeMirror.getKind() == TypeKind.BOOLEAN;
159     }
160 
161     @Override
isChar()162     public boolean isChar() {
163         return mTypeMirror.getKind() == TypeKind.CHAR;
164     }
165 
166     @Override
isByte()167     public boolean isByte() {
168         return mTypeMirror.getKind() == TypeKind.BYTE;
169     }
170 
171     @Override
isShort()172     public boolean isShort() {
173         return mTypeMirror.getKind() == TypeKind.SHORT;
174     }
175 
176     @Override
isInt()177     public boolean isInt() {
178         return mTypeMirror.getKind() == TypeKind.INT;
179     }
180 
181     @Override
isLong()182     public boolean isLong() {
183         return mTypeMirror.getKind() == TypeKind.LONG;
184     }
185 
186     @Override
isFloat()187     public boolean isFloat() {
188         return mTypeMirror.getKind() == TypeKind.FLOAT;
189     }
190 
191     @Override
isDouble()192     public boolean isDouble() {
193         return mTypeMirror.getKind() == TypeKind.DOUBLE;
194     }
195 
196     @Override
isGeneric()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
getMinApi()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
getTypeArguments()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
isTypeVar()245     public boolean isTypeVar() {
246         return mTypeMirror.getKind() == TypeKind.TYPEVAR;
247     }
248 
249     @Override
isInterface()250     public boolean isInterface() {
251         return mTypeMirror.getKind() == TypeKind.DECLARED &&
252                 ((DeclaredType)mTypeMirror).asElement().getKind() == ElementKind.INTERFACE;
253     }
254 
255     @Override
isVoid()256     public boolean isVoid() {
257         return mTypeMirror.getKind() == TypeKind.VOID;
258     }
259 
260     @Override
unbox()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
box()274     public AnnotationClass box() {
275         if (!isPrimitive()) {
276             return this;
277         }
278         return new AnnotationClass(getTypeUtils().boxedClass((PrimitiveType) mTypeMirror).asType());
279     }
280 
281     @Override
isAssignableFrom(ModelClass that)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
getDeclaredMethods()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
getSuperclass()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
getCanonicalName()323     public String getCanonicalName() {
324         return getTypeUtils().erasure(mTypeMirror).toString();
325     }
326 
327     @Override
erasure()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
getJniDescription()338     public String getJniDescription() {
339         return TypeUtil.getInstance().getDescription(this);
340     }
341 
342     @Override
getDeclaredFields()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
equals(Object obj)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
hashCode()371     public int hashCode() {
372         return mTypeMirror.toString().hashCode();
373     }
374 
getTypeUtils()375     private static Types getTypeUtils() {
376         return AnnotationAnalyzer.get().mProcessingEnv.getTypeUtils();
377     }
378 
getElementUtils()379     private static Elements getElementUtils() {
380         return AnnotationAnalyzer.get().mProcessingEnv.getElementUtils();
381     }
382 
383     @Override
toString()384     public String toString() {
385         return mTypeMirror.toString();
386     }
387 }
388