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 ), 50 ClassItem, 51 TypeParameterListOwner { 52 53 init { 54 @Suppress("LeakingThis") 55 modifiers.setOwner(this) 56 } 57 58 override val isTypeParameter: Boolean = false 59 60 override var artifact: String? = null 61 equalsnull62 override fun equals(other: Any?): Boolean { 63 if (this === other) return true 64 if (other !is ClassItem) return false 65 66 return qualifiedName == other.qualifiedName() 67 } 68 hashCodenull69 override fun hashCode(): Int { 70 return qualifiedName.hashCode() 71 } 72 interfaceTypesnull73 override fun interfaceTypes(): List<TypeItem> = interfaceTypes 74 override fun allInterfaces(): Sequence<ClassItem> { 75 return interfaceTypes.asSequence().map { it.asClass() }.filterNotNull() 76 } 77 78 private var innerClasses: MutableList<ClassItem> = mutableListOf() 79 80 override var stubConstructor: ConstructorItem? = null 81 82 override var hasPrivateConstructor: Boolean = false 83 innerClassesnull84 override fun innerClasses(): List<ClassItem> = innerClasses 85 86 override fun hasImplicitDefaultConstructor(): Boolean { 87 return false 88 } 89 isInterfacenull90 override fun isInterface(): Boolean = isInterface 91 override fun isAnnotationType(): Boolean = isAnnotation 92 override fun isEnum(): Boolean = isEnum 93 94 var containingClass: TextClassItem? = null 95 override fun containingClass(): ClassItem? = containingClass 96 97 private var containingPackage: PackageItem? = null 98 99 fun setContainingPackage(containingPackage: TextPackageItem) { 100 this.containingPackage = containingPackage 101 } 102 setIsAnnotationTypenull103 fun setIsAnnotationType(isAnnotation: Boolean) { 104 this.isAnnotation = isAnnotation 105 } 106 setIsEnumnull107 fun setIsEnum(isEnum: Boolean) { 108 this.isEnum = isEnum 109 } 110 containingPackagenull111 override fun containingPackage(): PackageItem = 112 containingClass?.containingPackage() ?: containingPackage ?: error(this) 113 114 override fun toType(): TypeItem { 115 val typeParameterListString = typeParameterList().toString() 116 return codebase.obtainTypeFromString( 117 if (typeParameterListString.isNotEmpty()) { 118 // TODO: No, handle List<String>[], though this is highly unlikely in a class 119 qualifiedName() + typeParameterListString 120 } else qualifiedName() 121 ) 122 } 123 hasTypeVariablesnull124 override fun hasTypeVariables(): Boolean { 125 return typeInfo?.hasTypeArguments() ?: false 126 } 127 128 private var typeParameterList: TypeParameterList? = null 129 typeParameterListnull130 override fun typeParameterList(): TypeParameterList { 131 if (typeParameterList == null) { 132 val s = typeInfo.toString() 133 // TODO: No, handle List<String>[] (though it's not likely for type parameters) 134 val index = s.indexOf('<') 135 typeParameterList = if (index != -1) { 136 TextTypeParameterList.create(codebase, this, s.substring(index)) 137 } else { 138 TypeParameterList.NONE 139 } 140 } 141 142 return typeParameterList!! 143 } 144 typeParameterListOwnerParentnull145 override fun typeParameterListOwnerParent(): TypeParameterListOwner? { 146 return containingClass 147 } 148 resolveParameternull149 override fun resolveParameter(variable: String): TypeParameterItem? { 150 if (hasTypeVariables()) { 151 for (t in typeParameterList().typeParameters()) { 152 if (t.simpleName() == variable) { 153 return t 154 } 155 } 156 } 157 158 return null 159 } 160 161 private var superClass: ClassItem? = null 162 private var superClassType: TypeItem? = null 163 superClassnull164 override fun superClass(): ClassItem? = superClass 165 override fun superClassType(): TypeItem? = superClassType 166 167 override fun setSuperClass(superClass: ClassItem?, superClassType: TypeItem?) { 168 this.superClass = superClass 169 this.superClassType = superClassType 170 } 171 setInterfaceTypesnull172 override fun setInterfaceTypes(interfaceTypes: List<TypeItem>) { 173 this.interfaceTypes = interfaceTypes.toMutableList() 174 } 175 176 private var typeInfo: TextTypeItem? = null setTypeInfonull177 fun setTypeInfo(typeInfo: TextTypeItem) { 178 this.typeInfo = typeInfo 179 } 180 asTypeInfonull181 fun asTypeInfo(): TextTypeItem { 182 if (typeInfo == null) { 183 typeInfo = codebase.obtainTypeFromString(qualifiedTypeName) 184 } 185 return typeInfo!! 186 } 187 188 private var interfaceTypes = mutableListOf<TypeItem>() 189 private val constructors = mutableListOf<ConstructorItem>() 190 private val methods = mutableListOf<MethodItem>() 191 private val fields = mutableListOf<FieldItem>() 192 private val properties = mutableListOf<PropertyItem>() 193 constructorsnull194 override fun constructors(): List<ConstructorItem> = constructors 195 override fun methods(): List<MethodItem> = methods 196 override fun fields(): List<FieldItem> = fields 197 override fun properties(): List<PropertyItem> = properties 198 199 fun addInterface(itf: TypeItem) { 200 interfaceTypes.add(itf) 201 } 202 addConstructornull203 fun addConstructor(constructor: TextConstructorItem) { 204 constructors += constructor 205 } 206 addMethodnull207 fun addMethod(method: TextMethodItem) { 208 methods += method 209 } 210 addFieldnull211 fun addField(field: TextFieldItem) { 212 fields += field 213 } 214 addPropertynull215 fun addProperty(property: TextPropertyItem) { 216 properties += property 217 } 218 addEnumConstantnull219 fun addEnumConstant(field: TextFieldItem) { 220 field.setEnumConstant(true) 221 fields += field 222 } 223 addInnerClassnull224 fun addInnerClass(cls: TextClassItem) { 225 innerClasses.add(cls) 226 } 227 filteredSuperClassTypenull228 override fun filteredSuperClassType(predicate: Predicate<Item>): TypeItem? { 229 // No filtering in signature files: we assume signature APIs 230 // have already been filtered and all items should match. 231 // This lets us load signature files and rewrite them using updated 232 // output formats etc. 233 return superClassType 234 } 235 236 private var retention: AnnotationRetention? = null 237 getRetentionnull238 override fun getRetention(): AnnotationRetention { 239 retention?.let { return it } 240 241 if (!isAnnotationType()) { 242 error("getRetention() should only be called on annotation classes") 243 } 244 245 retention = ClassItem.findRetention(this) 246 return retention!! 247 } 248 249 private var fullName: String = name simpleNamenull250 override fun simpleName(): String = name.substring(name.lastIndexOf('.') + 1) 251 override fun fullName(): String = fullName 252 override fun qualifiedName(): String = qualifiedName 253 override fun isDefined(): Boolean { 254 assert(emit == (position != SourcePositionInfo.UNKNOWN)) 255 return emit 256 } toStringnull257 override fun toString(): String = "class ${qualifiedName()}" 258 259 override fun mapTypeVariables(target: ClassItem): Map<String, String> { 260 return emptyMap() 261 } 262 263 companion object { createClassStubnull264 fun createClassStub(codebase: TextCodebase, name: String): TextClassItem = 265 createStub(codebase, name, isInterface = false) 266 267 fun createInterfaceStub(codebase: TextCodebase, name: String): TextClassItem = 268 createStub(codebase, name, isInterface = true) 269 270 private fun createStub(codebase: TextCodebase, name: String, isInterface: Boolean): TextClassItem { 271 val index = if (name.endsWith(">")) name.indexOf('<') else -1 272 val qualifiedName = if (index == -1) name else name.substring(0, index) 273 val fullName = getFullName(qualifiedName) 274 val cls = TextClassItem( 275 codebase = codebase, 276 name = fullName, 277 qualifiedName = qualifiedName, 278 isInterface = isInterface, 279 modifiers = TextModifiers(codebase, DefaultModifierList.PUBLIC) 280 ) 281 cls.emit = false // it's a stub 282 283 if (index != -1) { 284 cls.typeParameterList = TextTypeParameterList.create(codebase, cls, name.substring(index)) 285 } 286 287 return cls 288 } 289 getFullNamenull290 private fun getFullName(qualifiedName: String): String { 291 var end = -1 292 val length = qualifiedName.length 293 var prev = qualifiedName[length - 1] 294 for (i in length - 2 downTo 0) { 295 val c = qualifiedName[i] 296 if (c == '.' && prev.isUpperCase()) { 297 end = i + 1 298 } 299 prev = c 300 } 301 if (end != -1) { 302 return qualifiedName.substring(end) 303 } 304 305 return qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1) 306 } 307 } 308 } 309