1/* 2 * 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 17package android.arch.lifecycle 18 19import android.arch.lifecycle.model.EventMethod 20import android.arch.lifecycle.model.LifecycleObserverInfo 21import com.google.auto.common.MoreElements 22import com.google.auto.common.MoreTypes 23import javax.annotation.processing.ProcessingEnvironment 24import javax.annotation.processing.RoundEnvironment 25import javax.lang.model.element.Element 26import javax.lang.model.element.ElementKind 27import javax.lang.model.element.ExecutableElement 28import javax.lang.model.element.Modifier 29import javax.lang.model.element.TypeElement 30import javax.lang.model.element.VariableElement 31import javax.tools.Diagnostic 32 33fun collectAndVerifyInput(processingEnv: ProcessingEnvironment, 34 roundEnv: RoundEnvironment): Map<TypeElement, LifecycleObserverInfo> { 35 val validator = Validator(processingEnv) 36 37 return roundEnv.getElementsAnnotatedWith(OnLifecycleEvent::class.java).map { elem -> 38 if (elem.kind != ElementKind.METHOD) { 39 validator.printErrorMessage(ErrorMessages.INVALID_ANNOTATED_ELEMENT, elem) 40 null 41 } else { 42 val enclosingElement = elem.enclosingElement 43 val onState = elem.getAnnotation(OnLifecycleEvent::class.java) 44 val method = MoreElements.asExecutable(elem) 45 if (validator.validateClass(enclosingElement) 46 && validator.validateMethod(method, onState.value)) { 47 EventMethod(method, onState, MoreElements.asType(enclosingElement)) 48 } else { 49 null 50 } 51 } 52 } 53 .filterNotNull() 54 .groupBy { MoreElements.asType(it.method.enclosingElement) } 55 .mapValues { entry -> LifecycleObserverInfo(entry.key, entry.value) } 56 57} 58 59class Validator(val processingEnv: ProcessingEnvironment) { 60 61 fun printErrorMessage(msg: CharSequence, elem: Element) { 62 processingEnv.messager.printMessage(Diagnostic.Kind.ERROR, msg, elem) 63 } 64 65 fun validateParam(param: VariableElement, 66 expectedType: Class<*>, errorMsg: String): Boolean { 67 if (!MoreTypes.isTypeOf(expectedType, param.asType())) { 68 printErrorMessage(errorMsg, param) 69 return false 70 } 71 return true 72 } 73 74 fun validateMethod(method: ExecutableElement, event: Lifecycle.Event): Boolean { 75 if (Modifier.PRIVATE in method.modifiers) { 76 printErrorMessage(ErrorMessages.INVALID_METHOD_MODIFIER, method) 77 return false 78 } 79 val params = method.parameters 80 if ((params.size > 2)) { 81 printErrorMessage(ErrorMessages.TOO_MANY_ARGS, method) 82 return false 83 } 84 85 if (params.size == 2 && event != Lifecycle.Event.ON_ANY) { 86 printErrorMessage(ErrorMessages.TOO_MANY_ARGS_NOT_ON_ANY, method) 87 return false 88 } 89 90 if (params.size == 2 && !validateParam(params[1], Lifecycle.Event::class.java, 91 ErrorMessages.INVALID_SECOND_ARGUMENT)) { 92 return false 93 } 94 95 if (params.size > 0) { 96 return validateParam(params[0], LifecycleOwner::class.java, 97 ErrorMessages.INVALID_FIRST_ARGUMENT) 98 } 99 return true 100 } 101 102 fun validateClass(classElement: Element): Boolean { 103 if (classElement.kind != ElementKind.CLASS && classElement.kind != ElementKind.INTERFACE) { 104 printErrorMessage(ErrorMessages.INVALID_ENCLOSING_ELEMENT, classElement) 105 return false 106 } 107 if (Modifier.PRIVATE in classElement.modifiers) { 108 printErrorMessage(ErrorMessages.INVALID_CLASS_MODIFIER, classElement) 109 return false 110 } 111 return true 112 } 113} 114