• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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