1 /*
<lambda>null2 * Copyright (C) 2016 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
17 @file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
18
19 package androidx.room.ext
20
21 import com.google.auto.common.AnnotationMirrors
22 import com.google.auto.common.MoreElements
23 import com.google.auto.common.MoreTypes
24 import me.eugeniomarletti.kotlin.metadata.shadow.load.java.JvmAbi
25 import javax.annotation.processing.ProcessingEnvironment
26 import javax.lang.model.element.AnnotationValue
27 import javax.lang.model.element.Element
28 import javax.lang.model.element.ElementKind
29 import javax.lang.model.element.Modifier
30 import javax.lang.model.element.TypeElement
31 import javax.lang.model.element.VariableElement
32 import javax.lang.model.type.TypeKind
33 import javax.lang.model.type.TypeMirror
34 import javax.lang.model.type.WildcardType
35 import javax.lang.model.util.SimpleAnnotationValueVisitor6
36 import javax.lang.model.util.SimpleTypeVisitor7
37 import javax.lang.model.util.Types
38 import kotlin.reflect.KClass
39
40 fun Element.hasAnyOf(vararg modifiers: Modifier): Boolean {
41 return this.modifiers.any { modifiers.contains(it) }
42 }
43
hasAnnotationnull44 fun Element.hasAnnotation(klass: KClass<out Annotation>): Boolean {
45 return MoreElements.isAnnotationPresent(this, klass.java)
46 }
47
isNonNullnull48 fun Element.isNonNull() =
49 asType().kind.isPrimitive
50 || hasAnnotation(androidx.annotation.NonNull::class)
51 || hasAnnotation(org.jetbrains.annotations.NotNull::class)
52
53 /**
54 * gets all members including super privates. does not handle duplicate field names!!!
55 */
56 // TODO handle conflicts with super: b/35568142
57 fun TypeElement.getAllFieldsIncludingPrivateSupers(processingEnvironment: ProcessingEnvironment):
58 Set<VariableElement> {
59 val myMembers = processingEnvironment.elementUtils.getAllMembers(this)
60 .filter { it.kind == ElementKind.FIELD }
61 .filter { it is VariableElement }
62 .map { it as VariableElement }
63 .toSet()
64 if (superclass.kind != TypeKind.NONE) {
65 return myMembers + MoreTypes.asTypeElement(superclass)
66 .getAllFieldsIncludingPrivateSupers(processingEnvironment)
67 } else {
68 return myMembers
69 }
70 }
71
72 // code below taken from dagger2
73 // compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java
74 private val TO_LIST_OF_TYPES = object
75 : SimpleAnnotationValueVisitor6<List<TypeMirror>, Void?>() {
visitArraynull76 override fun visitArray(values: MutableList<out AnnotationValue>?, p: Void?): List<TypeMirror> {
77 return values?.mapNotNull {
78 val tmp = TO_TYPE.visit(it)
79 tmp
80 } ?: emptyList()
81 }
82
defaultActionnull83 override fun defaultAction(o: Any?, p: Void?): List<TypeMirror>? {
84 return emptyList()
85 }
86 }
87
88 private val TO_TYPE = object : SimpleAnnotationValueVisitor6<TypeMirror, Void>() {
89
visitTypenull90 override fun visitType(t: TypeMirror, p: Void?): TypeMirror {
91 return t
92 }
93
defaultActionnull94 override fun defaultAction(o: Any?, p: Void?): TypeMirror {
95 throw TypeNotPresentException(o!!.toString(), null)
96 }
97 }
98
AnnotationValuenull99 fun AnnotationValue.toListOfClassTypes(): List<TypeMirror> {
100 return TO_LIST_OF_TYPES.visit(this)
101 }
102
toTypenull103 fun AnnotationValue.toType(): TypeMirror {
104 return TO_TYPE.visit(this)
105 }
106
toClassTypenull107 fun AnnotationValue.toClassType(): TypeMirror? {
108 return TO_TYPE.visit(this)
109 }
110
TypeMirrornull111 fun TypeMirror.isCollection(): Boolean {
112 return MoreTypes.isType(this)
113 && (MoreTypes.isTypeOf(java.util.List::class.java, this)
114 || MoreTypes.isTypeOf(java.util.Set::class.java, this))
115 }
116
getAnnotationValuenull117 fun Element.getAnnotationValue(annotation: Class<out Annotation>, fieldName: String): Any? {
118 return MoreElements.getAnnotationMirror(this, annotation)
119 .orNull()?.let {
120 AnnotationMirrors.getAnnotationValue(it, fieldName)?.value
121 }
122 }
123
124 private val ANNOTATION_VALUE_TO_INT_VISITOR = object : SimpleAnnotationValueVisitor6<Int?, Void>() {
visitIntnull125 override fun visitInt(i: Int, p: Void?): Int? {
126 return i
127 }
128 }
129
130 private val ANNOTATION_VALUE_TO_BOOLEAN_VISITOR = object
131 : SimpleAnnotationValueVisitor6<Boolean?, Void>() {
visitBooleannull132 override fun visitBoolean(b: Boolean, p: Void?): Boolean? {
133 return b
134 }
135 }
136
137 private val ANNOTATION_VALUE_TO_STRING_VISITOR = object
138 : SimpleAnnotationValueVisitor6<String?, Void>() {
visitStringnull139 override fun visitString(s: String?, p: Void?): String? {
140 return s
141 }
142 }
143
144 private val ANNOTATION_VALUE_STRING_ARR_VISITOR = object
145 : SimpleAnnotationValueVisitor6<List<String>, Void>() {
visitArraynull146 override fun visitArray(vals: MutableList<out AnnotationValue>?, p: Void?): List<String> {
147 return vals?.mapNotNull {
148 ANNOTATION_VALUE_TO_STRING_VISITOR.visit(it)
149 } ?: emptyList()
150 }
151 }
152
AnnotationValuenull153 fun AnnotationValue.getAsInt(def: Int? = null): Int? {
154 return ANNOTATION_VALUE_TO_INT_VISITOR.visit(this) ?: def
155 }
156
AnnotationValuenull157 fun AnnotationValue.getAsString(def: String? = null): String? {
158 return ANNOTATION_VALUE_TO_STRING_VISITOR.visit(this) ?: def
159 }
160
getAsBooleannull161 fun AnnotationValue.getAsBoolean(def: Boolean): Boolean {
162 return ANNOTATION_VALUE_TO_BOOLEAN_VISITOR.visit(this) ?: def
163 }
164
AnnotationValuenull165 fun AnnotationValue.getAsStringList(): List<String> {
166 return ANNOTATION_VALUE_STRING_ARR_VISITOR.visit(this)
167 }
168
169 // a variant of Types.isAssignable that ignores variance.
Typesnull170 fun Types.isAssignableWithoutVariance(from: TypeMirror, to: TypeMirror): Boolean {
171 val assignable = isAssignable(from, to)
172 if (assignable) {
173 return true
174 }
175 if (from.kind != TypeKind.DECLARED || to.kind != TypeKind.DECLARED) {
176 return false
177 }
178 val declaredFrom = MoreTypes.asDeclared(from)
179 val declaredTo = MoreTypes.asDeclared(to)
180 val fromTypeArgs = declaredFrom.typeArguments
181 val toTypeArgs = declaredTo.typeArguments
182 // no type arguments, we don't need extra checks
183 if (fromTypeArgs.isEmpty() || fromTypeArgs.size != toTypeArgs.size) {
184 return false
185 }
186 // check erasure version first, if it does not match, no reason to proceed
187 if (!isAssignable(erasure(from), erasure(to))) {
188 return false
189 }
190 // convert from args to their upper bounds if it exists
191 val fromExtendsBounds = fromTypeArgs.map {
192 it.extendsBound()
193 }
194 // if there are no upper bound conversions, return.
195 if (fromExtendsBounds.all { it == null }) {
196 return false
197 }
198 // try to move the types of the from to their upper bounds. It does not matter for the "to"
199 // because Types.isAssignable handles it as it is valid java
200 return (0 until fromTypeArgs.size).all { index ->
201 isAssignableWithoutVariance(
202 from = fromExtendsBounds[index] ?: fromTypeArgs[index],
203 to = toTypeArgs[index])
204 }
205 }
206
207 // converts ? in Set< ? extends Foo> to Foo
extendsBoundnull208 fun TypeMirror.extendsBound(): TypeMirror? {
209 return this.accept(object : SimpleTypeVisitor7<TypeMirror?, Void?>() {
210 override fun visitWildcard(type: WildcardType, ignored: Void?): TypeMirror? {
211 return type.extendsBound
212 }
213 }, null)
214 }
215
216 /**
217 * If the type mirror is in form of ? extends Foo, it returns Foo; otherwise, returns the TypeMirror
218 * itself.
219 */
TypeMirrornull220 fun TypeMirror.extendsBoundOrSelf(): TypeMirror {
221 return extendsBound() ?: this
222 }
223
224 /**
225 * Finds the default implementation method corresponding to this Kotlin interface method.
226 */
findKotlinDefaultImplnull227 fun Element.findKotlinDefaultImpl(typeUtils: Types): Element? {
228 fun paramsMatch(ourParams: List<VariableElement>, theirParams: List<VariableElement>): Boolean {
229 if (ourParams.size != theirParams.size - 1) {
230 return false
231 }
232 ourParams.forEachIndexed { i, variableElement ->
233 // Plus 1 to their index because their first param is a self object.
234 if (!typeUtils.isSameType(theirParams[i + 1].asType(), variableElement.asType())) {
235 return false
236 }
237 }
238 return true
239 }
240
241 val parent = this.enclosingElement as TypeElement
242 val innerClass = parent.enclosedElements.find {
243 it.kind == ElementKind.CLASS && it.simpleName.contentEquals(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)
244 } ?: return null
245 return innerClass.enclosedElements.find {
246 it.kind == ElementKind.METHOD && it.simpleName == this.simpleName
247 && paramsMatch(MoreElements.asExecutable(this).parameters,
248 MoreElements.asExecutable(it).parameters)
249 }
250 }
251