• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         @Suppress("LeakingThis") val classItem = this
77         if (codebase.registerClass(classItem)) {
78             // Only emit classes that were specified on the command line.
79             emit = emit && origin == ClassOrigin.COMMAND_LINE
80 
81             // If this class is emittable then make sure its package is too.
82             if (emit) {
83                 containingPackage.emit = true
84             }
85 
86             if (containingClass == null) {
87                 (containingPackage as DefaultPackageItem).addTopClass(classItem)
88                 fullName = simpleName
89             } else {
90                 (containingClass as DefaultClassItem).addNestedClass(classItem)
91                 fullName = "${containingClass.fullName()}.$simpleName"
92             }
93         } else {
94             // The fullName needs to be initialized to something so initializing it to something
95             // invalid will ensure it is not accidentally used.
96             fullName = "duplicate class"
97         }
98     }
99 
100     /** If [source] is not set and this is a nested class then try the containing class. */
101     override fun sourceFile() = source ?: containingClass?.sourceFile()
102 
103     final override fun containingPackage(): PackageItem = containingPackage
104 
105     final override fun containingClass() = containingClass
106 
107     final override fun qualifiedName() = qualifiedName
108 
109     final override fun simpleName() = simpleName
110 
111     final override fun fullName() = fullName
112 
113     final override fun hasTypeVariables(): Boolean = typeParameterList.isNotEmpty()
114 
115     /** Must only be used by [type] to cache its result. */
116     private lateinit var cachedType: ClassTypeItem
117 
118     final override fun type(): ClassTypeItem {
119         if (!::cachedType.isInitialized) {
120             cachedType = createClassTypeItemForThis()
121         }
122         return cachedType
123     }
124 
125     protected open fun createClassTypeItemForThis() =
126         DefaultResolvedClassTypeItem.createForClass(this)
127 
128     final override var frozen = false
129         private set
130 
131     override fun freeze() {
132         if (frozen) return
133         frozen = true
134         superClass()?.freeze()
135         for (interfaceType in interfaceTypes) {
136             interfaceType.asClass()?.freeze()
137         }
138     }
139 
140     private fun ensureNotFrozen() {
141         if (frozen) error("Cannot modify frozen $this")
142     }
143 
144     final override fun mutateModifiers(mutator: MutableModifierList.() -> Unit) {
145         ensureNotFrozen()
146         super.mutateModifiers(mutator)
147     }
148 
149     final override fun superClassType(): ClassTypeItem? = superClassType
150 
151     /** Set the super class [ClassTypeItem]. */
152     fun setSuperClassType(superClassType: ClassTypeItem?) {
153         ensureNotFrozen()
154         this.superClassType = superClassType
155     }
156 
157     final override fun interfaceTypes(): List<ClassTypeItem> = interfaceTypes
158 
159     final override fun setInterfaceTypes(interfaceTypes: List<ClassTypeItem>) {
160         ensureNotFrozen()
161         this.interfaceTypes = interfaceTypes
162     }
163 
164     /** Cache of the results of calling [cacheAllInterfaces]. */
165     private var cacheAllInterfaces: List<ClassItem>? = null
166 
167     final override fun allInterfaces(): Sequence<ClassItem> {
168         if (cacheAllInterfaces == null) {
169             cacheAllInterfaces = computeAllInterfaces()
170         }
171 
172         return cacheAllInterfaces!!.asSequence()
173     }
174 
175     /** Compute the value for [ClassItem.allInterfaces]. */
176     private fun computeAllInterfaces() = buildList {
177         // Add self as interface if applicable
178         if (isInterface()) {
179             add(this@DefaultClassItem)
180         }
181 
182         // Add all the interfaces of super class
183         superClass()?.let { superClass -> superClass.allInterfaces().forEach { add(it) } }
184 
185         // Add all the interfaces of direct interfaces
186         interfaceTypes().forEach { interfaceType ->
187             val itf = interfaceType.asClass()
188             itf?.allInterfaces()?.forEach { add(it) }
189         }
190     }
191 
192     /** The mutable list of [ConstructorItem] that backs [constructors]. */
193     private val mutableConstructors = mutableListOf<ConstructorItem>()
194 
195     final override fun constructors(): List<ConstructorItem> = mutableConstructors
196 
197     /** Add a constructor to this class. */
198     fun addConstructor(constructor: ConstructorItem) {
199         ensureNotFrozen()
200         mutableConstructors += constructor
201 
202         // Keep track of whether any implicit constructors were added.
203         if (constructor.isImplicitConstructor()) {
204             hasImplicitDefaultConstructor = true
205         }
206     }
207 
208     /** Tracks whether the class has an implicit default constructor. */
209     private var hasImplicitDefaultConstructor = false
210 
211     final override fun hasImplicitDefaultConstructor(): Boolean = hasImplicitDefaultConstructor
212 
213     override fun createDefaultConstructor(visibility: VisibilityLevel): ConstructorItem {
214         return DefaultConstructorItem.createDefaultConstructor(
215             codebase = codebase,
216             itemLanguage = itemLanguage,
217             variantSelectorsFactory = variantSelectors::duplicate,
218             containingClass = this,
219             visibility = visibility,
220         )
221     }
222 
223     /** The mutable list of [MethodItem] that backs [methods]. */
224     private val mutableMethods = mutableListOf<MethodItem>()
225 
226     final override fun methods(): List<MethodItem> = mutableMethods
227 
228     /** Add a method to this class. */
229     final override fun addMethod(method: MethodItem) {
230         ensureNotFrozen()
231         mutableMethods += method
232     }
233 
234     /**
235      * Replace an existing method with [method], if no such method exists then just add [method] to
236      * the list of methods.
237      */
238     fun replaceOrAddMethod(method: MethodItem) {
239         ensureNotFrozen()
240         val iterator = mutableMethods.listIterator()
241         while (iterator.hasNext()) {
242             val existing = iterator.next()
243             if (existing == method) {
244                 iterator.set(method)
245                 return
246             }
247         }
248         mutableMethods += method
249     }
250 
251     /** The mutable list of [FieldItem] that backs [fields]. */
252     private val mutableFields = mutableListOf<FieldItem>()
253 
254     /** Add a field to this class. */
255     fun addField(field: FieldItem) {
256         ensureNotFrozen()
257         mutableFields += field
258     }
259 
260     final override fun fields(): List<FieldItem> = mutableFields
261 
262     /** The mutable list of [PropertyItem] that backs [properties]. */
263     private val mutableProperties = mutableListOf<PropertyItem>()
264 
265     final override fun properties(): List<PropertyItem> = mutableProperties
266 
267     /** Add a property to this class. */
268     fun addProperty(property: PropertyItem) {
269         ensureNotFrozen()
270         mutableProperties += property
271     }
272 
273     /** The mutable list of nested [ClassItem] that backs [nestedClasses]. */
274     private val mutableNestedClasses = mutableListOf<ClassItem>()
275 
276     final override fun nestedClasses(): List<ClassItem> = mutableNestedClasses
277 
278     /** Add a nested class to this class. */
279     private fun addNestedClass(classItem: ClassItem) {
280         ensureNotFrozen()
281         mutableNestedClasses.add(classItem)
282     }
283 
284     /** Cache result of [getRetention]. */
285     private var cacheRetention: AnnotationRetention? = null
286 
287     final override fun getRetention(): AnnotationRetention {
288         cacheRetention?.let {
289             return it
290         }
291 
292         if (!isAnnotationType()) {
293             error("getRetention() should only be called on annotation classes")
294         }
295 
296         cacheRetention = ClassItem.findRetention(this)
297         return cacheRetention!!
298     }
299 }
300