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.doclava1.SourcePositionInfo 20 import com.android.tools.metalava.doclava1.TextCodebase 21 import com.android.tools.metalava.model.AnnotationRetention 22 import com.android.tools.metalava.model.ClassItem 23 import com.android.tools.metalava.model.ConstructorItem 24 import com.android.tools.metalava.model.DefaultModifierList 25 import com.android.tools.metalava.model.FieldItem 26 import com.android.tools.metalava.model.Item 27 import com.android.tools.metalava.model.MethodItem 28 import com.android.tools.metalava.model.PackageItem 29 import com.android.tools.metalava.model.PropertyItem 30 import com.android.tools.metalava.model.TypeItem 31 import com.android.tools.metalava.model.TypeParameterItem 32 import com.android.tools.metalava.model.TypeParameterList 33 import com.android.tools.metalava.model.TypeParameterListOwner 34 import java.util.function.Predicate 35 36 open class TextClassItem( 37 override val codebase: TextCodebase, 38 position: SourcePositionInfo = SourcePositionInfo.UNKNOWN, 39 modifiers: TextModifiers, 40 private var isInterface: Boolean = false, 41 private var isEnum: Boolean = false, 42 private var isAnnotation: Boolean = false, 43 val qualifiedName: String = "", 44 private val qualifiedTypeName: String = qualifiedName, 45 var name: String = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1), 46 val annotations: List<String>? = null 47 ) : TextItem( 48 codebase = codebase, 49 position = position, 50 modifiers = modifiers 51 ), ClassItem, TypeParameterListOwner { 52 53 init { 54 @Suppress("LeakingThis") 55 modifiers.setOwner(this) 56 } 57 58 override val isTypeParameter: Boolean = false 59 60 override var notStrippable = false 61 62 override var artifact: String? = null 63 equalsnull64 override fun equals(other: Any?): Boolean { 65 if (this === other) return true 66 if (other !is ClassItem) return false 67 68 return qualifiedName == other.qualifiedName() 69 } 70 hashCodenull71 override fun hashCode(): Int { 72 return qualifiedName.hashCode() 73 } 74 interfaceTypesnull75 override fun interfaceTypes(): List<TypeItem> = interfaceTypes 76 override fun allInterfaces(): Sequence<ClassItem> { 77 return interfaceTypes.asSequence().map { it.asClass() }.filterNotNull() 78 } 79 80 private var innerClasses: List<ClassItem> = mutableListOf() 81 82 override var defaultConstructor: ConstructorItem? = null 83 84 override var hasPrivateConstructor: Boolean = false 85 innerClassesnull86 override fun innerClasses(): List<ClassItem> = innerClasses 87 88 override fun hasImplicitDefaultConstructor(): Boolean { 89 return false 90 } 91 isInterfacenull92 override fun isInterface(): Boolean = isInterface 93 override fun isAnnotationType(): Boolean = isAnnotation 94 override fun isEnum(): Boolean = isEnum 95 96 var containingClass: TextClassItem? = null 97 override fun containingClass(): ClassItem? = containingClass 98 99 private var containingPackage: PackageItem? = null 100 101 fun setContainingPackage(containingPackage: TextPackageItem) { 102 this.containingPackage = containingPackage 103 } 104 setIsAnnotationTypenull105 fun setIsAnnotationType(isAnnotation: Boolean) { 106 this.isAnnotation = isAnnotation 107 } 108 setIsEnumnull109 fun setIsEnum(isEnum: Boolean) { 110 this.isEnum = isEnum 111 } 112 containingPackagenull113 override fun containingPackage(): PackageItem = 114 containingClass?.containingPackage() ?: containingPackage ?: error(this) 115 116 override fun toType(): TypeItem { 117 val typeParameterListString = typeParameterList().toString() 118 return codebase.obtainTypeFromString( 119 if (typeParameterListString.isNotEmpty()) { 120 // TODO: No, handle List<String>[], though this is highly unlikely in a class 121 qualifiedName() + typeParameterListString 122 } else qualifiedName() 123 ) 124 } 125 hasTypeVariablesnull126 override fun hasTypeVariables(): Boolean { 127 return typeInfo?.hasTypeArguments() ?: false 128 } 129 130 private var typeParameterList: TypeParameterList? = null 131 typeParameterListnull132 override fun typeParameterList(): TypeParameterList { 133 if (typeParameterList == null) { 134 val s = typeInfo.toString() 135 // TODO: No, handle List<String>[] (though it's not likely for type parameters) 136 val index = s.indexOf('<') 137 typeParameterList = if (index != -1) { 138 TextTypeParameterList.create(codebase, this, s.substring(index)) 139 } else { 140 TypeParameterList.NONE 141 } 142 } 143 144 return typeParameterList!! 145 } 146 typeParameterListOwnerParentnull147 override fun typeParameterListOwnerParent(): TypeParameterListOwner? { 148 return containingClass 149 } 150 resolveParameternull151 override fun resolveParameter(variable: String): TypeParameterItem? { 152 if (hasTypeVariables()) { 153 for (t in typeParameterList().typeParameters()) { 154 if (t.simpleName() == variable) { 155 return t 156 } 157 } 158 } 159 160 return null 161 } 162 163 private var superClass: ClassItem? = null 164 private var superClassType: TypeItem? = null 165 superClassnull166 override fun superClass(): ClassItem? = superClass 167 override fun superClassType(): TypeItem? = superClassType 168 169 override fun setSuperClass(superClass: ClassItem?, superClassType: TypeItem?) { 170 this.superClass = superClass 171 this.superClassType = superClassType 172 } 173 setInterfaceTypesnull174 override fun setInterfaceTypes(interfaceTypes: List<TypeItem>) { 175 this.interfaceTypes = interfaceTypes.toMutableList() 176 } 177 178 private var typeInfo: TextTypeItem? = null setTypeInfonull179 fun setTypeInfo(typeInfo: TextTypeItem) { 180 this.typeInfo = typeInfo 181 } 182 asTypeInfonull183 fun asTypeInfo(): TextTypeItem { 184 if (typeInfo == null) { 185 typeInfo = codebase.obtainTypeFromString(qualifiedTypeName) 186 } 187 return typeInfo!! 188 } 189 190 private var interfaceTypes = mutableListOf<TypeItem>() 191 private val constructors = mutableListOf<ConstructorItem>() 192 private val methods = mutableListOf<MethodItem>() 193 private val fields = mutableListOf<FieldItem>() 194 private val properties = mutableListOf<PropertyItem>() 195 constructorsnull196 override fun constructors(): List<ConstructorItem> = constructors 197 override fun methods(): List<MethodItem> = methods 198 override fun fields(): List<FieldItem> = fields 199 override fun properties(): List<PropertyItem> = properties 200 201 fun addInterface(itf: TypeItem) { 202 interfaceTypes.add(itf) 203 } 204 addConstructornull205 fun addConstructor(constructor: TextConstructorItem) { 206 constructors += constructor 207 } 208 addMethodnull209 fun addMethod(method: TextMethodItem) { 210 methods += method 211 } 212 addFieldnull213 fun addField(field: TextFieldItem) { 214 fields += field 215 } 216 addPropertynull217 fun addProperty(property: TextPropertyItem) { 218 properties += property 219 } 220 addEnumConstantnull221 fun addEnumConstant(field: TextFieldItem) { 222 field.setEnumConstant(true) 223 fields += field 224 } 225 addInnerClassnull226 fun addInnerClass(cls: TextClassItem) { 227 innerClasses += cls 228 } 229 filteredSuperClassTypenull230 override fun filteredSuperClassType(predicate: Predicate<Item>): TypeItem? { 231 // No filtering in signature files: we assume signature APIs 232 // have already been filtered and all items should match. 233 // This lets us load signature files and rewrite them using updated 234 // output formats etc. 235 return superClassType 236 } 237 238 private var retention: AnnotationRetention? = null 239 getRetentionnull240 override fun getRetention(): AnnotationRetention { 241 retention?.let { return it } 242 243 if (!isAnnotationType()) { 244 error("getRetention() should only be called on annotation classes") 245 } 246 247 retention = ClassItem.findRetention(this) 248 return retention!! 249 } 250 251 private var fullName: String = name simpleNamenull252 override fun simpleName(): String = name.substring(name.lastIndexOf('.') + 1) 253 override fun fullName(): String = fullName 254 override fun qualifiedName(): String = qualifiedName 255 override fun toString(): String = 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