xref: /aosp_15_r20/tools/metalava/metalava-model/src/main/java/com/android/tools/metalava/model/item/DefaultClassItem.kt (revision 115816f9299ab6ddd6b9673b81f34e707f6bacab)
1 /*
<lambda>null2  * Copyright (C) 2024 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 com.android.tools.metalava.model.item
18 
19 import com.android.tools.metalava.model.AnnotationRetention
20 import com.android.tools.metalava.model.ApiVariantSelectorsFactory
21 import com.android.tools.metalava.model.BaseModifierList
22 import com.android.tools.metalava.model.ClassItem
23 import com.android.tools.metalava.model.ClassKind
24 import com.android.tools.metalava.model.ClassOrigin
25 import com.android.tools.metalava.model.ClassTypeItem
26 import com.android.tools.metalava.model.ConstructorItem
27 import com.android.tools.metalava.model.FieldItem
28 import com.android.tools.metalava.model.ItemDocumentationFactory
29 import com.android.tools.metalava.model.ItemLanguage
30 import com.android.tools.metalava.model.MethodItem
31 import com.android.tools.metalava.model.MutableModifierList
32 import com.android.tools.metalava.model.PackageItem
33 import com.android.tools.metalava.model.PropertyItem
34 import com.android.tools.metalava.model.SourceFile
35 import com.android.tools.metalava.model.TypeParameterList
36 import com.android.tools.metalava.model.VisibilityLevel
37 import com.android.tools.metalava.model.type.DefaultResolvedClassTypeItem
38 import com.android.tools.metalava.reporter.FileLocation
39 
40 open class DefaultClassItem(
41     codebase: DefaultCodebase,
42     fileLocation: FileLocation,
43     itemLanguage: ItemLanguage,
44     modifiers: BaseModifierList,
45     documentationFactory: ItemDocumentationFactory,
46     variantSelectorsFactory: ApiVariantSelectorsFactory,
47     private val source: SourceFile?,
48     final override val classKind: ClassKind,
49     private val containingClass: ClassItem?,
50     private val containingPackage: PackageItem,
51     private val qualifiedName: String,
52     final override val typeParameterList: TypeParameterList,
53     final override val origin: ClassOrigin,
54     private var superClassType: ClassTypeItem?,
55     private var interfaceTypes: List<ClassTypeItem>,
56 ) :
57     DefaultSelectableItem(
58         codebase = codebase,
59         fileLocation = fileLocation,
60         itemLanguage = itemLanguage,
61         modifiers = modifiers,
62         documentationFactory = documentationFactory,
63         variantSelectorsFactory = variantSelectorsFactory,
64     ),
65     ClassItem {
66 
67     private val simpleName = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1)
68 
69     private val fullName: String
70 
71     init {
72         // Register the class first. Leaking `this` is ok as it only uses its qualified name and
73         // fileLocation, both of which have been initialized. If registration succeeded then wire
74         // the class into the containing package/containing class. If it failed, because it is a
75         // duplicate, then do nothing.
76         if (codebase.registerClass(@Suppress("LeakingThis") this)) {
77             // Only emit classes that were specified on the command line.
78             emit = emit && origin == ClassOrigin.COMMAND_LINE
79 
80             // If this class is emittable then make sure its package is too.
81             if (emit) {
82                 containingPackage.emit = true
83             }
84 
85             if (containingClass == null) {
86                 (containingPackage as DefaultPackageItem).addTopClass(this)
87                 fullName = simpleName
88             } else {
89                 (containingClass as DefaultClassItem).addNestedClass(this)
90                 fullName = "${containingClass.fullName()}.$simpleName"
91             }
92         } else {
93             // The fullName needs to be initialized to something so initializing it to something
94             // invalid will ensure it is not accidentally used.
95             fullName = "duplicate class"
96         }
97     }
98 
99     /** If [source] is not set and this is a nested class then try the containing class. */
100     override fun sourceFile() = source ?: containingClass?.sourceFile()
101 
102     final override fun containingPackage(): PackageItem = containingPackage
103 
104     final override fun containingClass() = containingClass
105 
106     final override fun qualifiedName() = qualifiedName
107 
108     final override fun simpleName() = simpleName
109 
110     final override fun fullName() = fullName
111 
112     final override fun hasTypeVariables(): Boolean = typeParameterList.isNotEmpty()
113 
114     /** Must only be used by [type] to cache its result. */
115     private lateinit var cachedType: ClassTypeItem
116 
117     final override fun type(): ClassTypeItem {
118         if (!::cachedType.isInitialized) {
119             cachedType = createClassTypeItemForThis()
120         }
121         return cachedType
122     }
123 
124     protected open fun createClassTypeItemForThis() =
125         DefaultResolvedClassTypeItem.createForClass(this)
126 
127     final override var frozen = false
128         private set
129 
130     override fun freeze() {
131         if (frozen) return
132         frozen = true
133         superClass()?.freeze()
134         for (interfaceType in interfaceTypes) {
135             interfaceType.asClass()?.freeze()
136         }
137     }
138 
139     private fun ensureNotFrozen() {
140         if (frozen) error("Cannot modify frozen $this")
141     }
142 
143     final override fun mutateModifiers(mutator: MutableModifierList.() -> Unit) {
144         ensureNotFrozen()
145         super.mutateModifiers(mutator)
146     }
147 
148     final override fun superClassType(): ClassTypeItem? = superClassType
149 
150     /** Set the super class [ClassTypeItem]. */
151     fun setSuperClassType(superClassType: ClassTypeItem?) {
152         ensureNotFrozen()
153         this.superClassType = superClassType
154     }
155 
156     final override fun interfaceTypes(): List<ClassTypeItem> = interfaceTypes
157 
158     final override fun setInterfaceTypes(interfaceTypes: List<ClassTypeItem>) {
159         ensureNotFrozen()
160         this.interfaceTypes = interfaceTypes
161     }
162 
163     /** Cache of the results of calling [cacheAllInterfaces]. */
164     private var cacheAllInterfaces: List<ClassItem>? = null
165 
166     final override fun allInterfaces(): Sequence<ClassItem> {
167         if (cacheAllInterfaces == null) {
168             cacheAllInterfaces = computeAllInterfaces()
169         }
170 
171         return cacheAllInterfaces!!.asSequence()
172     }
173 
174     /** Compute the value for [ClassItem.allInterfaces]. */
175     private fun computeAllInterfaces() = buildList {
176         // Add self as interface if applicable
177         if (isInterface()) {
178             add(this@DefaultClassItem)
179         }
180 
181         // Add all the interfaces of super class
182         superClass()?.let { superClass -> superClass.allInterfaces().forEach { add(it) } }
183 
184         // Add all the interfaces of direct interfaces
185         interfaceTypes().forEach { interfaceType ->
186             val itf = interfaceType.asClass()
187             itf?.allInterfaces()?.forEach { add(it) }
188         }
189     }
190 
191     /** The mutable list of [ConstructorItem] that backs [constructors]. */
192     private val mutableConstructors = mutableListOf<ConstructorItem>()
193 
194     final override fun constructors(): List<ConstructorItem> = mutableConstructors
195 
196     /** Add a constructor to this class. */
197     fun addConstructor(constructor: ConstructorItem) {
198         ensureNotFrozen()
199         mutableConstructors += constructor
200 
201         // Keep track of whether any implicit constructors were added.
202         if (constructor.isImplicitConstructor()) {
203             hasImplicitDefaultConstructor = true
204         }
205     }
206 
207     /** Tracks whether the class has an implicit default constructor. */
208     private var hasImplicitDefaultConstructor = false
209 
210     final override fun hasImplicitDefaultConstructor(): Boolean = hasImplicitDefaultConstructor
211 
212     override fun createDefaultConstructor(visibility: VisibilityLevel): ConstructorItem {
213         return DefaultConstructorItem.createDefaultConstructor(
214             codebase = codebase,
215             itemLanguage = itemLanguage,
216             variantSelectorsFactory = variantSelectors::duplicate,
217             containingClass = this,
218             visibility = visibility,
219         )
220     }
221 
222     /** The mutable list of [MethodItem] that backs [methods]. */
223     private val mutableMethods = mutableListOf<MethodItem>()
224 
225     final override fun methods(): List<MethodItem> = mutableMethods
226 
227     /** Add a method to this class. */
228     final override fun addMethod(method: MethodItem) {
229         ensureNotFrozen()
230         mutableMethods += method
231     }
232 
233     /**
234      * Replace an existing method with [method], if no such method exists then just add [method] to
235      * the list of methods.
236      */
237     fun replaceOrAddMethod(method: MethodItem) {
238         ensureNotFrozen()
239         val iterator = mutableMethods.listIterator()
240         while (iterator.hasNext()) {
241             val existing = iterator.next()
242             if (existing == method) {
243                 iterator.set(method)
244                 return
245             }
246         }
247         mutableMethods += method
248     }
249 
250     /** The mutable list of [FieldItem] that backs [fields]. */
251     private val mutableFields = mutableListOf<FieldItem>()
252 
253     /** Add a field to this class. */
254     fun addField(field: FieldItem) {
255         ensureNotFrozen()
256         mutableFields += field
257     }
258 
259     final override fun fields(): List<FieldItem> = mutableFields
260 
261     /** The mutable list of [PropertyItem] that backs [properties]. */
262     private val mutableProperties = mutableListOf<PropertyItem>()
263 
264     final override fun properties(): List<PropertyItem> = mutableProperties
265 
266     /** Add a property to this class. */
267     fun addProperty(property: PropertyItem) {
268         ensureNotFrozen()
269         mutableProperties += property
270     }
271 
272     /** The mutable list of nested [ClassItem] that backs [nestedClasses]. */
273     private val mutableNestedClasses = mutableListOf<ClassItem>()
274 
275     final override fun nestedClasses(): List<ClassItem> = mutableNestedClasses
276 
277     /** Add a nested class to this class. */
278     private fun addNestedClass(classItem: ClassItem) {
279         ensureNotFrozen()
280         mutableNestedClasses.add(classItem)
281     }
282 
283     /** Cache result of [getRetention]. */
284     private var cacheRetention: AnnotationRetention? = null
285 
286     final override fun getRetention(): AnnotationRetention {
287         cacheRetention?.let {
288             return it
289         }
290 
291         if (!isAnnotationType()) {
292             error("getRetention() should only be called on annotation classes")
293         }
294 
295         cacheRetention = ClassItem.findRetention(this)
296         return cacheRetention!!
297     }
298 }
299