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