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