10bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets/* 20bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * Copyright (C) 2017 The Android Open Source Project 30bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * 40bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * Licensed under the Apache License, Version 2.0 (the "License"); 50bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * you may not use this file except in compliance with the License. 60bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * You may obtain a copy of the License at 70bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * 80bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * http://www.apache.org/licenses/LICENSE-2.0 90bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * 100bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * Unless required by applicable law or agreed to in writing, software 110bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * distributed under the License is distributed on an "AS IS" BASIS, 120bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * See the License for the specific language governing permissions and 140bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets * limitations under the License. 150bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets */ 160bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 17bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viverettepackage androidx.lifecycle 180bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 19bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.lifecycle.model.EventMethod 20bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.lifecycle.model.InputModel 21bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.lifecycle.model.LifecycleObserverInfo 22bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.lifecycle.model.getAdapterName 230bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport com.google.auto.common.MoreElements 240bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport com.google.auto.common.MoreTypes 250bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport javax.annotation.processing.ProcessingEnvironment 260bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport javax.annotation.processing.RoundEnvironment 270bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport javax.lang.model.element.Element 280bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport javax.lang.model.element.ElementKind 290bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport javax.lang.model.element.ExecutableElement 300bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport javax.lang.model.element.Modifier 310bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport javax.lang.model.element.TypeElement 320bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport javax.lang.model.element.VariableElement 33619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinetsimport javax.lang.model.type.TypeMirror 34619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinetsimport javax.lang.model.util.Elements 35619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinetsimport javax.lang.model.util.Types 360bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsimport javax.tools.Diagnostic 370bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 380bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsfun collectAndVerifyInput(processingEnv: ProcessingEnvironment, 392e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets roundEnv: RoundEnvironment): InputModel { 400bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets val validator = Validator(processingEnv) 41619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets val worldCollector = ObserversCollector(processingEnv) 42ac066ab209fdf179000634d493ca841ec27f2c80Sergey Vasilinets val roots = roundEnv.getElementsAnnotatedWith(OnLifecycleEvent::class.java).map { elem -> 430bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets if (elem.kind != ElementKind.METHOD) { 440bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets validator.printErrorMessage(ErrorMessages.INVALID_ANNOTATED_ELEMENT, elem) 45ac066ab209fdf179000634d493ca841ec27f2c80Sergey Vasilinets null 460bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } else { 470bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets val enclosingElement = elem.enclosingElement 48619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets if (validator.validateClass(enclosingElement)) { 49ac066ab209fdf179000634d493ca841ec27f2c80Sergey Vasilinets MoreElements.asType(enclosingElement) 50ac066ab209fdf179000634d493ca841ec27f2c80Sergey Vasilinets } else { 51ac066ab209fdf179000634d493ca841ec27f2c80Sergey Vasilinets null 520bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 530bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 54ac066ab209fdf179000634d493ca841ec27f2c80Sergey Vasilinets }.filterNotNull().toSet() 55ac066ab209fdf179000634d493ca841ec27f2c80Sergey Vasilinets roots.forEach { worldCollector.collect(it) } 562e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets val observersInfo = worldCollector.observers 572e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets val generatedAdapters = worldCollector.observers.keys 582e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets .mapNotNull { type -> 592e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets worldCollector.generatedAdapterInfoFor(type)?.let { type to it } 602e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets }.toMap() 612e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets return InputModel(roots, observersInfo, generatedAdapters) 62619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets} 630bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 64619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinetsclass ObserversCollector(processingEnv: ProcessingEnvironment) { 65619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets val typeUtils: Types = processingEnv.typeUtils 66619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets val elementUtils: Elements = processingEnv.elementUtils 67619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets val lifecycleObserverTypeMirror: TypeMirror = 68619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets elementUtils.getTypeElement(LifecycleObserver::class.java.canonicalName).asType() 69619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets val validator = Validator(processingEnv) 70619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets val observers: MutableMap<TypeElement, LifecycleObserverInfo> = mutableMapOf() 71619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets 72619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets fun collect(type: TypeElement): LifecycleObserverInfo? { 73619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets if (type in observers) { 74619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets return observers[type] 75619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets } 76619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets val parents = (listOf(type.superclass) + type.interfaces) 77619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets .filter { typeUtils.isAssignable(it, lifecycleObserverTypeMirror) } 78619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets .filterNot { typeUtils.isSameType(it, lifecycleObserverTypeMirror) } 79619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets .map { collect(MoreTypes.asTypeElement(it)) } 80619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets .filterNotNull() 81619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets val info = createObserverInfo(type, parents) 82619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets if (info != null) { 83619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets observers[type] = info 84619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets } 85619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets return info 86619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets } 87619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets 882e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets fun generatedAdapterInfoFor(type: TypeElement): List<ExecutableElement>? { 89619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets val packageName = if (type.getPackageQName().isEmpty()) "" else "${type.getPackageQName()}." 902e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets val adapterType = elementUtils.getTypeElement(packageName + getAdapterName(type)) 912e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets return adapterType?.methods() 922e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets ?.filter { executable -> isSyntheticMethod(executable) } 93619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets } 94619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets 95619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets private fun createObserverInfo(typeElement: TypeElement, 96619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets parents: List<LifecycleObserverInfo>): LifecycleObserverInfo? { 97619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets if (!validator.validateClass(typeElement)) { 98619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets return null 99619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets } 1002e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets val methods = typeElement.methods().filter { executable -> 101619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets MoreElements.isAnnotationPresent(executable, OnLifecycleEvent::class.java) 102619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets }.map { executable -> 103619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets val onState = executable.getAnnotation(OnLifecycleEvent::class.java) 104619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets if (validator.validateMethod(executable, onState.value)) { 105619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets EventMethod(executable, onState, typeElement) 106619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets } else { 107619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets null 108619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets } 109619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets }.filterNotNull() 1102e9de5a9a940a64564f9d08953cfffa84226757bSergey Vasilinets return LifecycleObserverInfo(typeElement, methods, parents) 111619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets } 1120bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets} 1130bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 1140bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinetsclass Validator(val processingEnv: ProcessingEnvironment) { 1150bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 1160bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets fun printErrorMessage(msg: CharSequence, elem: Element) { 1170bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, msg, elem) 1180bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1190bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 1200bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets fun validateParam(param: VariableElement, 1210bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets expectedType: Class<*>, errorMsg: String): Boolean { 1220bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets if (!MoreTypes.isTypeOf(expectedType, param.asType())) { 1230bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets printErrorMessage(errorMsg, param) 1240bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return false 1250bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1260bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return true 1270bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1280bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 1290bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets fun validateMethod(method: ExecutableElement, event: Lifecycle.Event): Boolean { 1300bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets if (Modifier.PRIVATE in method.modifiers) { 1310bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets printErrorMessage(ErrorMessages.INVALID_METHOD_MODIFIER, method) 1320bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return false 1330bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1340bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets val params = method.parameters 1350bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets if ((params.size > 2)) { 1360bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets printErrorMessage(ErrorMessages.TOO_MANY_ARGS, method) 1370bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return false 1380bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1390bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 1400bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets if (params.size == 2 && event != Lifecycle.Event.ON_ANY) { 1410bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets printErrorMessage(ErrorMessages.TOO_MANY_ARGS_NOT_ON_ANY, method) 1420bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return false 1430bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1440bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 1450bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets if (params.size == 2 && !validateParam(params[1], Lifecycle.Event::class.java, 1460bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets ErrorMessages.INVALID_SECOND_ARGUMENT)) { 1470bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return false 1480bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1490bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 1500bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets if (params.size > 0) { 1510bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return validateParam(params[0], LifecycleOwner::class.java, 1520bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets ErrorMessages.INVALID_FIRST_ARGUMENT) 1530bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1540bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return true 1550bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1560bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets 1570bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets fun validateClass(classElement: Element): Boolean { 158619b2be303df81e1b807112100d9a0e92f43e951Sergey Vasilinets if (!MoreElements.isType(classElement)) { 1590bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets printErrorMessage(ErrorMessages.INVALID_ENCLOSING_ELEMENT, classElement) 1600bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return false 1610bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1620bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets if (Modifier.PRIVATE in classElement.modifiers) { 1630bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets printErrorMessage(ErrorMessages.INVALID_CLASS_MODIFIER, classElement) 1640bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return false 1650bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1660bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets return true 1670bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets } 1680bbdd57e9654789f419177f1ff90221d5872b116Sergey Vasilinets} 169