1 /*
<lambda>null2  * Copyright 2018 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.room.processor.autovalue
18 
19 import androidx.room.Ignore
20 import androidx.room.compiler.processing.XExecutableElement
21 import androidx.room.compiler.processing.XType
22 import androidx.room.compiler.processing.XTypeElement
23 import androidx.room.processor.Context
24 import androidx.room.processor.DataClassProcessor
25 import androidx.room.processor.DataClassProcessor.Companion.TARGET_METHOD_ANNOTATIONS
26 import androidx.room.processor.ProcessorErrors
27 import androidx.room.vo.Constructor
28 import androidx.room.vo.DataClass
29 import androidx.room.vo.EmbeddedProperty
30 import androidx.room.vo.Property
31 import androidx.room.vo.Warning
32 import com.google.auto.value.AutoValue.CopyAnnotations
33 
34 /** Delegate to process generated AutoValue class as a data class. */
35 class AutoValueDataClassProcessorDelegate(
36     private val context: Context,
37     private val autoValueElement: XTypeElement
38 ) : DataClassProcessor.Delegate {
39 
40     private val autoValueDeclaredType: XType by lazy { autoValueElement.type }
41 
42     override fun onPreProcess(element: XTypeElement) {
43         val allMethods = autoValueElement.getAllMethods()
44         val autoValueAbstractGetters =
45             allMethods.filter { it.isAbstract() && it.parameters.size == 0 }
46 
47         // Warn about missing @AutoValue.CopyAnnotations in the property getters.
48         autoValueAbstractGetters.forEach {
49             val hasRoomAnnotation = it.hasAnnotationWithPackage("androidx.room")
50             if (hasRoomAnnotation && !it.hasAnnotation(CopyAnnotations::class)) {
51                 context.logger.w(
52                     Warning.MISSING_COPY_ANNOTATIONS,
53                     it,
54                     ProcessorErrors.MISSING_COPY_ANNOTATIONS
55                 )
56             }
57         }
58 
59         // Check that certain Room annotations with @Target(METHOD) are not used in methods other
60         // than the auto value abstract getters.
61         (allMethods - autoValueAbstractGetters)
62             .filter { it.hasAnyAnnotation(*TARGET_METHOD_ANNOTATIONS) }
63             .forEach { method ->
64                 val annotationName =
65                     TARGET_METHOD_ANNOTATIONS.first { method.hasAnnotation(it) }.java.simpleName
66                 context.logger.e(
67                     method,
68                     ProcessorErrors.invalidAnnotationTarget(annotationName, method.kindName())
69                 )
70             }
71     }
72 
73     override fun findConstructors(element: XTypeElement): List<XExecutableElement> {
74         return autoValueElement.getDeclaredMethods().filter {
75             it.isStatic() &&
76                 !it.hasAnnotation(Ignore::class) &&
77                 !it.isPrivate() &&
78                 it.returnType.isSameType(autoValueElement.type)
79         }
80     }
81 
82     override fun createDataClass(
83         element: XTypeElement,
84         declaredType: XType,
85         properties: List<Property>,
86         embeddedProperties: List<EmbeddedProperty>,
87         relations: List<androidx.room.vo.Relation>,
88         constructor: Constructor?
89     ): DataClass {
90         return DataClass(
91             element = element,
92             type = autoValueDeclaredType,
93             properties = properties,
94             embeddedProperties = embeddedProperties,
95             relations = relations,
96             constructor = constructor
97         )
98     }
99 
100     companion object {
101         /**
102          * Gets the generated class name of an AutoValue annotated class.
103          *
104          * This is the same naming strategy used by AutoValue's processor.
105          */
106         fun getGeneratedClassName(element: XTypeElement): String {
107             var type = element
108             var name = type.name
109             while (type.enclosingTypeElement != null) {
110                 type = type.enclosingTypeElement!!
111                 name = "${type.name}_$name"
112             }
113             val pkg = type.packageName
114             return "$pkg${if (pkg.isEmpty()) "" else "."}AutoValue_$name"
115         }
116     }
117 }
118