1 /*
<lambda>null2  * Copyright (C) 2017 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 package androidx.lifecycle
18 
19 import androidx.lifecycle.model.EventMethod
20 import androidx.lifecycle.model.InputModel
21 import androidx.lifecycle.model.LifecycleObserverInfo
22 import androidx.lifecycle.model.getAdapterName
23 import com.google.auto.common.MoreElements
24 import com.google.auto.common.MoreTypes
25 import javax.annotation.processing.ProcessingEnvironment
26 import javax.annotation.processing.RoundEnvironment
27 import javax.lang.model.element.Element
28 import javax.lang.model.element.ElementKind
29 import javax.lang.model.element.ExecutableElement
30 import javax.lang.model.element.Modifier
31 import javax.lang.model.element.TypeElement
32 import javax.lang.model.element.VariableElement
33 import javax.lang.model.type.TypeMirror
34 import javax.lang.model.util.Elements
35 import javax.lang.model.util.Types
36 import javax.tools.Diagnostic
37 
38 @Suppress("DEPRECATION")
39 fun collectAndVerifyInput(
40     processingEnv: ProcessingEnvironment,
41     roundEnv: RoundEnvironment
42 ): InputModel {
43     val validator = Validator(processingEnv)
44     val worldCollector = ObserversCollector(processingEnv)
45     val roots =
46         roundEnv
47             .getElementsAnnotatedWith(OnLifecycleEvent::class.java)
48             .map { elem ->
49                 if (elem.kind != ElementKind.METHOD) {
50                     validator.printErrorMessage(ErrorMessages.INVALID_ANNOTATED_ELEMENT, elem)
51                     null
52                 } else {
53                     val enclosingElement = elem.enclosingElement
54                     if (validator.validateClass(enclosingElement)) {
55                         MoreElements.asType(enclosingElement)
56                     } else {
57                         null
58                     }
59                 }
60             }
61             .filterNotNull()
62             .toSet()
63     roots.forEach { worldCollector.collect(it) }
64     val observersInfo = worldCollector.observers
65     val generatedAdapters =
66         worldCollector.observers.keys
67             .mapNotNull { type -> worldCollector.generatedAdapterInfoFor(type)?.let { type to it } }
68             .toMap()
69     return InputModel(roots, observersInfo, generatedAdapters)
70 }
71 
72 class ObserversCollector(processingEnv: ProcessingEnvironment) {
73     val typeUtils: Types = processingEnv.typeUtils
74     val elementUtils: Elements = processingEnv.elementUtils
75     val lifecycleObserverTypeMirror: TypeMirror =
76         elementUtils.getTypeElement(LifecycleObserver::class.java.canonicalName).asType()
77     val validator = Validator(processingEnv)
78     val observers: MutableMap<TypeElement, LifecycleObserverInfo> = mutableMapOf()
79 
collectnull80     fun collect(type: TypeElement): LifecycleObserverInfo? {
81         if (type in observers) {
82             return observers[type]
83         }
84         val parents =
85             (listOf(type.superclass) + type.interfaces)
86                 .filter { typeUtils.isAssignable(it, lifecycleObserverTypeMirror) }
87                 .filterNot { typeUtils.isSameType(it, lifecycleObserverTypeMirror) }
88                 .map { collect(MoreTypes.asTypeElement(it)) }
89                 .filterNotNull()
90         val info = createObserverInfo(type, parents)
91         if (info != null) {
92             observers[type] = info
93         }
94         return info
95     }
96 
generatedAdapterInfoFornull97     fun generatedAdapterInfoFor(type: TypeElement): List<ExecutableElement>? {
98         val packageName = if (type.getPackageQName().isEmpty()) "" else "${type.getPackageQName()}."
99         val adapterType = elementUtils.getTypeElement(packageName + getAdapterName(type))
100         return adapterType?.methods()?.filter { executable -> isSyntheticMethod(executable) }
101     }
102 
103     @Suppress("DEPRECATION")
createObserverInfonull104     private fun createObserverInfo(
105         typeElement: TypeElement,
106         parents: List<LifecycleObserverInfo>
107     ): LifecycleObserverInfo? {
108         if (!validator.validateClass(typeElement)) {
109             return null
110         }
111         val methods =
112             typeElement
113                 .methods()
114                 .filter { executable ->
115                     MoreElements.isAnnotationPresent(executable, OnLifecycleEvent::class.java)
116                 }
117                 .map { executable ->
118                     val onState = executable.getAnnotation(OnLifecycleEvent::class.java)
119                     if (validator.validateMethod(executable, onState.value)) {
120                         EventMethod(executable, onState, typeElement)
121                     } else {
122                         null
123                     }
124                 }
125                 .filterNotNull()
126         return LifecycleObserverInfo(typeElement, methods, parents)
127     }
128 }
129 
130 class Validator(val processingEnv: ProcessingEnvironment) {
131 
printErrorMessagenull132     fun printErrorMessage(msg: CharSequence, elem: Element) {
133         processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, msg, elem)
134     }
135 
validateParamnull136     fun validateParam(param: VariableElement, expectedType: Class<*>, errorMsg: String): Boolean {
137         if (!MoreTypes.isTypeOf(expectedType, param.asType())) {
138             printErrorMessage(errorMsg, param)
139             return false
140         }
141         return true
142     }
143 
validateMethodnull144     fun validateMethod(method: ExecutableElement, event: Lifecycle.Event): Boolean {
145         if (Modifier.PRIVATE in method.modifiers) {
146             printErrorMessage(ErrorMessages.INVALID_METHOD_MODIFIER, method)
147             return false
148         }
149         val params = method.parameters
150         if ((params.size > 2)) {
151             printErrorMessage(ErrorMessages.TOO_MANY_ARGS, method)
152             return false
153         }
154 
155         if (params.size == 2 && event != Lifecycle.Event.ON_ANY) {
156             printErrorMessage(ErrorMessages.TOO_MANY_ARGS_NOT_ON_ANY, method)
157             return false
158         }
159 
160         if (
161             params.size == 2 &&
162                 !validateParam(
163                     params[1],
164                     Lifecycle.Event::class.java,
165                     ErrorMessages.INVALID_SECOND_ARGUMENT
166                 )
167         ) {
168             return false
169         }
170 
171         if (params.size > 0) {
172             return validateParam(
173                 params[0],
174                 LifecycleOwner::class.java,
175                 ErrorMessages.INVALID_FIRST_ARGUMENT
176             )
177         }
178         return true
179     }
180 
validateClassnull181     fun validateClass(classElement: Element): Boolean {
182         if (!MoreElements.isType(classElement)) {
183             printErrorMessage(ErrorMessages.INVALID_ENCLOSING_ELEMENT, classElement)
184             return false
185         }
186         if (Modifier.PRIVATE in classElement.modifiers) {
187             printErrorMessage(ErrorMessages.INVALID_CLASS_MODIFIER, classElement)
188             return false
189         }
190         return true
191     }
192 }
193