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