1 /* 2 * Copyright (C) 2017 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.text 18 19 import com.android.tools.metalava.model.AnnotationRetention 20 import com.android.tools.metalava.model.ClassItem 21 import com.android.tools.metalava.model.ConstructorItem 22 import com.android.tools.metalava.model.DefaultModifierList 23 import com.android.tools.metalava.model.FieldItem 24 import com.android.tools.metalava.model.Item 25 import com.android.tools.metalava.model.MethodItem 26 import com.android.tools.metalava.model.PackageItem 27 import com.android.tools.metalava.model.PropertyItem 28 import com.android.tools.metalava.model.TypeItem 29 import com.android.tools.metalava.model.TypeParameterItem 30 import com.android.tools.metalava.model.TypeParameterList 31 import com.android.tools.metalava.model.TypeParameterListOwner 32 import java.util.function.Predicate 33 34 open class TextClassItem( 35 override val codebase: TextCodebase, 36 position: SourcePositionInfo = SourcePositionInfo.UNKNOWN, 37 modifiers: TextModifiers, 38 private var isInterface: Boolean = false, 39 private var isEnum: Boolean = false, 40 private var isAnnotation: Boolean = false, 41 val qualifiedName: String = "", 42 private val qualifiedTypeName: String = qualifiedName, 43 var name: String = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1), 44 val annotations: List<String>? = null 45 ) : TextItem( 46 codebase = codebase, 47 position = position, 48 modifiers = modifiers 49 ), ClassItem, TypeParameterListOwner { 50 51 init { 52 @Suppress("LeakingThis") 53 modifiers.setOwner(this) 54 } 55 56 override val isTypeParameter: Boolean = false 57 58 override var artifact: String? = null 59 equalsnull60 override fun equals(other: Any?): Boolean { 61 if (this === other) return true 62 if (other !is ClassItem) return false 63 64 return qualifiedName == other.qualifiedName() 65 } 66 hashCodenull67 override fun hashCode(): Int { 68 return qualifiedName.hashCode() 69 } 70 interfaceTypesnull71 override fun interfaceTypes(): List<TypeItem> = interfaceTypes 72 override fun allInterfaces(): Sequence<ClassItem> { 73 return interfaceTypes.asSequence().map { it.asClass() }.filterNotNull() 74 } 75 76 private var innerClasses: MutableList<ClassItem> = mutableListOf() 77 78 override var stubConstructor: ConstructorItem? = null 79 80 override var hasPrivateConstructor: Boolean = false 81 innerClassesnull82 override fun innerClasses(): List<ClassItem> = innerClasses 83 84 override fun hasImplicitDefaultConstructor(): Boolean { 85 return false 86 } 87 isInterfacenull88 override fun isInterface(): Boolean = isInterface 89 override fun isAnnotationType(): Boolean = isAnnotation 90 override fun isEnum(): Boolean = isEnum 91 92 var containingClass: TextClassItem? = null 93 override fun containingClass(): ClassItem? = containingClass 94 95 private var containingPackage: PackageItem? = null 96 97 fun setContainingPackage(containingPackage: TextPackageItem) { 98 this.containingPackage = containingPackage 99 } 100 setIsAnnotationTypenull101 fun setIsAnnotationType(isAnnotation: Boolean) { 102 this.isAnnotation = isAnnotation 103 } 104 setIsEnumnull105 fun setIsEnum(isEnum: Boolean) { 106 this.isEnum = isEnum 107 } 108 containingPackagenull109 override fun containingPackage(): PackageItem = 110 containingClass?.containingPackage() ?: containingPackage ?: error(this) 111 112 override fun toType(): TypeItem { 113 val typeParameterListString = typeParameterList().toString() 114 return codebase.obtainTypeFromString( 115 if (typeParameterListString.isNotEmpty()) { 116 // TODO: No, handle List<String>[], though this is highly unlikely in a class 117 qualifiedName() + typeParameterListString 118 } else qualifiedName() 119 ) 120 } 121 hasTypeVariablesnull122 override fun hasTypeVariables(): Boolean { 123 return typeInfo?.hasTypeArguments() ?: false 124 } 125 126 private var typeParameterList: TypeParameterList? = null 127 typeParameterListnull128 override fun typeParameterList(): TypeParameterList { 129 if (typeParameterList == null) { 130 val s = typeInfo.toString() 131 // TODO: No, handle List<String>[] (though it's not likely for type parameters) 132 val index = s.indexOf('<') 133 typeParameterList = if (index != -1) { 134 TextTypeParameterList.create(codebase, this, s.substring(index)) 135 } else { 136 TypeParameterList.NONE 137 } 138 } 139 140 return typeParameterList!! 141 } 142 typeParameterListOwnerParentnull143 override fun typeParameterListOwnerParent(): TypeParameterListOwner? { 144 return containingClass 145 } 146 resolveParameternull147 override fun resolveParameter(variable: String): TypeParameterItem? { 148 if (hasTypeVariables()) { 149 for (t in typeParameterList().typeParameters()) { 150 if (t.simpleName() == variable) { 151 return t 152 } 153 } 154 } 155 156 return null 157 } 158 159 private var superClass: ClassItem? = null 160 private var superClassType: TypeItem? = null 161 superClassnull162 override fun superClass(): ClassItem? = superClass 163 override fun superClassType(): TypeItem? = superClassType 164 165 override fun setSuperClass(superClass: ClassItem?, superClassType: TypeItem?) { 166 this.superClass = superClass 167 this.superClassType = superClassType 168 } 169 setInterfaceTypesnull170 override fun setInterfaceTypes(interfaceTypes: List<TypeItem>) { 171 this.interfaceTypes = interfaceTypes.toMutableList() 172 } 173 174 private var typeInfo: TextTypeItem? = null setTypeInfonull175 fun setTypeInfo(typeInfo: TextTypeItem) { 176 this.typeInfo = typeInfo 177 } 178 asTypeInfonull179 fun asTypeInfo(): TextTypeItem { 180 if (typeInfo == null) { 181 typeInfo = codebase.obtainTypeFromString(qualifiedTypeName) 182 } 183 return typeInfo!! 184 } 185 186 private var interfaceTypes = mutableListOf<TypeItem>() 187 private val constructors = mutableListOf<ConstructorItem>() 188 private val methods = mutableListOf<MethodItem>() 189 private val fields = mutableListOf<FieldItem>() 190 private val properties = mutableListOf<PropertyItem>() 191 constructorsnull192 override fun constructors(): List<ConstructorItem> = constructors 193 override fun methods(): List<MethodItem> = methods 194 override fun fields(): List<FieldItem> = fields 195 override fun properties(): List<PropertyItem> = properties 196 197 fun addInterface(itf: TypeItem) { 198 interfaceTypes.add(itf) 199 } 200 addConstructornull201 fun addConstructor(constructor: TextConstructorItem) { 202 constructors += constructor 203 } 204 addMethodnull205 fun addMethod(method: TextMethodItem) { 206 methods += method 207 } 208 addFieldnull209 fun addField(field: TextFieldItem) { 210 fields += field 211 } 212 addPropertynull213 fun addProperty(property: TextPropertyItem) { 214 properties += property 215 } 216 addEnumConstantnull217 fun addEnumConstant(field: TextFieldItem) { 218 field.setEnumConstant(true) 219 fields += field 220 } 221 addInnerClassnull222 fun addInnerClass(cls: TextClassItem) { 223 innerClasses.add(cls) 224 } 225 filteredSuperClassTypenull226 override fun filteredSuperClassType(predicate: Predicate<Item>): TypeItem? { 227 // No filtering in signature files: we assume signature APIs 228 // have already been filtered and all items should match. 229 // This lets us load signature files and rewrite them using updated 230 // output formats etc. 231 return superClassType 232 } 233 234 private var retention: AnnotationRetention? = null 235 getRetentionnull236 override fun getRetention(): AnnotationRetention { 237 retention?.let { return it } 238 239 if (!isAnnotationType()) { 240 error("getRetention() should only be called on annotation classes") 241 } 242 243 retention = ClassItem.findRetention(this) 244 return retention!! 245 } 246 247 private var fullName: String = name simpleNamenull248 override fun simpleName(): String = name.substring(name.lastIndexOf('.') + 1) 249 override fun fullName(): String = fullName 250 override fun qualifiedName(): String = qualifiedName 251 override fun isDefined(): Boolean { 252 assert(emit == (position != SourcePositionInfo.UNKNOWN)) 253 return emit 254 } toStringnull255 override fun toString(): String = "class ${qualifiedName()}" 256 257 override fun mapTypeVariables(target: ClassItem): Map<String, String> { 258 return emptyMap() 259 } 260 261 companion object { createClassStubnull262 fun createClassStub(codebase: TextCodebase, name: String): TextClassItem = 263 createStub(codebase, name, isInterface = false) 264 265 fun createInterfaceStub(codebase: TextCodebase, name: String): TextClassItem = 266 createStub(codebase, name, isInterface = true) 267 268 private fun createStub(codebase: TextCodebase, name: String, isInterface: Boolean): TextClassItem { 269 val index = if (name.endsWith(">")) name.indexOf('<') else -1 270 val qualifiedName = if (index == -1) name else name.substring(0, index) 271 val fullName = getFullName(qualifiedName) 272 val cls = TextClassItem( 273 codebase = codebase, 274 name = fullName, 275 qualifiedName = qualifiedName, 276 isInterface = isInterface, 277 modifiers = TextModifiers(codebase, DefaultModifierList.PUBLIC) 278 ) 279 cls.emit = false // it's a stub 280 281 if (index != -1) { 282 cls.typeParameterList = TextTypeParameterList.create(codebase, cls, name.substring(index)) 283 } 284 285 return cls 286 } 287 getFullNamenull288 private fun getFullName(qualifiedName: String): String { 289 var end = -1 290 val length = qualifiedName.length 291 var prev = qualifiedName[length - 1] 292 for (i in length - 2 downTo 0) { 293 val c = qualifiedName[i] 294 if (c == '.' && prev.isUpperCase()) { 295 end = i + 1 296 } 297 prev = c 298 } 299 if (end != -1) { 300 return qualifiedName.substring(end) 301 } 302 303 return qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1) 304 } 305 } 306 } 307