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