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 android.databinding.Bindable; 19 import android.databinding.tool.reflection.ModelClass; 20 import android.databinding.tool.reflection.ModelMethod; 21 import android.databinding.tool.reflection.SdkUtil; 22 import android.databinding.tool.reflection.TypeUtil; 23 24 import java.util.List; 25 26 import javax.lang.model.element.Element; 27 import javax.lang.model.element.ElementKind; 28 import javax.lang.model.element.ExecutableElement; 29 import javax.lang.model.element.Modifier; 30 import javax.lang.model.element.TypeElement; 31 import javax.lang.model.type.DeclaredType; 32 import javax.lang.model.type.ExecutableType; 33 import javax.lang.model.type.TypeKind; 34 import javax.lang.model.type.TypeMirror; 35 import javax.lang.model.util.Elements; 36 import javax.lang.model.util.Types; 37 38 class AnnotationMethod extends ModelMethod { 39 final ExecutableType mMethod; 40 final DeclaredType mDeclaringType; 41 final ExecutableElement mExecutableElement; 42 int mApiLevel = -1; // calculated on demand 43 ModelClass mReceiverType; 44 45 public AnnotationMethod(DeclaredType declaringType, ExecutableElement executableElement) { 46 mDeclaringType = declaringType; 47 mExecutableElement = executableElement; 48 Types typeUtils = AnnotationAnalyzer.get().getTypeUtils(); 49 mMethod = (ExecutableType) typeUtils.asMemberOf(declaringType, executableElement); 50 } 51 52 @Override 53 public ModelClass getDeclaringClass() { 54 if (mReceiverType == null) { 55 mReceiverType = findReceiverType(mDeclaringType); 56 if (mReceiverType == null) { 57 mReceiverType = new AnnotationClass(mDeclaringType); 58 } 59 } 60 return mReceiverType; 61 } 62 63 // TODO: When going to Java 1.8, use mExecutableElement.getReceiverType() 64 private ModelClass findReceiverType(DeclaredType subType) { 65 List<? extends TypeMirror> supers = getTypeUtils().directSupertypes(subType); 66 for (TypeMirror superType : supers) { 67 if (superType.getKind() == TypeKind.DECLARED) { 68 DeclaredType declaredType = (DeclaredType) superType; 69 ModelClass inSuper = findReceiverType(declaredType); 70 if (inSuper != null) { 71 return inSuper; 72 } else if (hasExecutableMethod(declaredType)) { 73 return new AnnotationClass(declaredType); 74 } 75 } 76 } 77 return null; 78 } 79 80 private boolean hasExecutableMethod(DeclaredType declaredType) { 81 Elements elementUtils = getElementUtils(); 82 TypeElement enclosing = (TypeElement) mExecutableElement.getEnclosingElement(); 83 TypeElement typeElement = (TypeElement) declaredType.asElement(); 84 for (Element element : typeElement.getEnclosedElements()) { 85 if (element.getKind() == ElementKind.METHOD) { 86 ExecutableElement executableElement = (ExecutableElement) element; 87 if (executableElement.equals(mExecutableElement) || 88 elementUtils.overrides(mExecutableElement, executableElement, enclosing)) { 89 return true; 90 } 91 } 92 } 93 return false; 94 } 95 96 @Override 97 public ModelClass[] getParameterTypes() { 98 List<? extends TypeMirror> parameters = mMethod.getParameterTypes(); 99 ModelClass[] parameterTypes = new ModelClass[parameters.size()]; 100 for (int i = 0; i < parameters.size(); i++) { 101 parameterTypes[i] = new AnnotationClass(parameters.get(i)); 102 } 103 return parameterTypes; 104 } 105 106 @Override 107 public String getName() { 108 return mExecutableElement.getSimpleName().toString(); 109 } 110 111 @Override 112 public ModelClass getReturnType(List<ModelClass> args) { 113 TypeMirror returnType = mMethod.getReturnType(); 114 // TODO: support argument-supplied types 115 // for example: public T[] toArray(T[] arr) 116 return new AnnotationClass(returnType); 117 } 118 119 @Override 120 public boolean isVoid() { 121 return mMethod.getReturnType().getKind() == TypeKind.VOID; 122 } 123 124 @Override 125 public boolean isPublic() { 126 return mExecutableElement.getModifiers().contains(Modifier.PUBLIC); 127 } 128 129 @Override 130 public boolean isProtected() { 131 return mExecutableElement.getModifiers().contains(Modifier.PROTECTED); 132 } 133 134 @Override 135 public boolean isStatic() { 136 return mExecutableElement.getModifiers().contains(Modifier.STATIC); 137 } 138 139 @Override 140 public boolean isAbstract() { 141 return mExecutableElement.getModifiers().contains(Modifier.ABSTRACT); 142 } 143 144 @Override 145 public boolean isBindable() { 146 return mExecutableElement.getAnnotation(Bindable.class) != null; 147 } 148 149 @Override 150 public int getMinApi() { 151 if (mApiLevel == -1) { 152 mApiLevel = SdkUtil.getMinApi(this); 153 } 154 return mApiLevel; 155 } 156 157 @Override 158 public String getJniDescription() { 159 return TypeUtil.getInstance().getDescription(this); 160 } 161 162 @Override 163 public boolean isVarArgs() { 164 return mExecutableElement.isVarArgs(); 165 } 166 167 private static Types getTypeUtils() { 168 return AnnotationAnalyzer.get().mProcessingEnv.getTypeUtils(); 169 } 170 171 private static Elements getElementUtils() { 172 return AnnotationAnalyzer.get().mProcessingEnv.getElementUtils(); 173 } 174 175 @Override 176 public String toString() { 177 return "AnnotationMethod{" + 178 "mMethod=" + mMethod + 179 ", mDeclaringType=" + mDeclaringType + 180 ", mExecutableElement=" + mExecutableElement + 181 ", mApiLevel=" + mApiLevel + 182 '}'; 183 } 184 } 185