• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2018 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.apilevels
18 
19 import com.android.tools.metalava.model.CallableItem
20 import com.android.tools.metalava.model.ClassItem
21 import com.android.tools.metalava.model.ClassKind
22 import com.android.tools.metalava.model.CodebaseFragment
23 import com.android.tools.metalava.model.ConstructorItem
24 import com.android.tools.metalava.model.DelegatedVisitor
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 
29 /**
30  * Visits the API codebase and inserts into the [Api] the classes, methods and fields.
31  *
32  * The [Item]s to be visited is determined by the [codebaseFragment].
33  */
34 fun addApisFromCodebase(
35     api: Api,
36     updater: ApiHistoryUpdater,
37     codebaseFragment: CodebaseFragment,
38 ) {
39     val useInternalNames = api.useInternalNames
40 
41     // Keep track of the versions added to this api, if necessary.
42     updater.update(api)
43 
44     val delegatedVisitor =
45         object : DelegatedVisitor {
46 
47             var currentClass: ApiClass? = null
48 
49             override fun afterVisitClass(cls: ClassItem) {
50                 currentClass = null
51             }
52 
53             override fun visitClass(cls: ClassItem) {
54                 val newClass = api.updateClass(cls.nameInApi(), updater, cls.effectivelyDeprecated)
55                 currentClass = newClass
56 
57                 when (cls.classKind) {
58                     ClassKind.CLASS -> {
59                         val superClass = cls.superClass()
60                         if (superClass != null) {
61                             newClass.updateSuperClass(superClass.nameInApi(), updater)
62                         }
63                     }
64                     ClassKind.INTERFACE -> {
65                         // Implicit super class; match convention from bytecode
66                         newClass.updateSuperClass(objectClass, updater)
67                     }
68                     ClassKind.ENUM -> {
69                         // Implicit super class; match convention from bytecode
70                         if (newClass.name != enumClass) {
71                             newClass.updateSuperClass(enumClass, updater)
72                         }
73 
74                         // Mimic doclava enum methods
75                         enumMethodNames(newClass.name).forEach { name ->
76                             newClass.updateMethod(name, updater, false)
77                         }
78                     }
79                     ClassKind.ANNOTATION_TYPE -> {
80                         // Implicit super class; match convention from bytecode
81                         if (newClass.name != annotationClass) {
82                             newClass.updateSuperClass(objectClass, updater)
83                             newClass.updateInterface(annotationClass, updater)
84                         }
85                     }
86                 }
87 
88                 for (interfaceType in cls.interfaceTypes()) {
89                     val interfaceClass = interfaceType.asClass() ?: return
90                     newClass.updateInterface(interfaceClass.nameInApi(), updater)
91                 }
92             }
93 
94             private fun visitCallable(callable: CallableItem) {
95                 if (callable.isPrivate || callable.isPackagePrivate) {
96                     return
97                 }
98                 currentClass?.updateMethod(
99                     callable.nameInApi(),
100                     updater,
101                     callable.effectivelyDeprecated
102                 )
103             }
104 
105             override fun visitConstructor(constructor: ConstructorItem) {
106                 visitCallable(constructor)
107             }
108 
109             override fun visitMethod(method: MethodItem) {
110                 visitCallable(method)
111             }
112 
113             override fun visitField(field: FieldItem) {
114                 if (field.isPrivate || field.isPackagePrivate) {
115                     return
116                 }
117                 currentClass?.updateField(field.nameInApi(), updater, field.effectivelyDeprecated)
118             }
119 
120             /** The name of the field in this [Api], based on [Api.useInternalNames] */
121             fun FieldItem.nameInApi(): String {
122                 return if (useInternalNames) {
123                     internalName()
124                 } else {
125                     name()
126                 }
127             }
128 
129             /** The name of the method in this [Api], based on [Api.useInternalNames] */
130             fun CallableItem.nameInApi(): String {
131                 return if (useInternalNames) {
132                     internalName() +
133                         // Use "V" instead of the type of the constructor for backwards
134                         // compatibility
135                         // with the older bytecode
136                         internalDesc(voidConstructorTypes = true)
137                 } else {
138                     val paramString = parameters().joinToString(",") { it.type().toTypeString() }
139                     name() + typeParameterList + "(" + paramString + ")"
140                 }
141             }
142 
143             /** The name of the class in this [Api], based on [Api.useInternalNames] */
144             fun ClassItem.nameInApi(): String {
145                 return if (useInternalNames) {
146                     internalName()
147                 } else {
148                     qualifiedName()
149                 }
150             }
151 
152             // The names of some common classes, based on [useInternalNames]
153             val objectClass = nameForClass("java", "lang", "Object")
154             val annotationClass = nameForClass("java", "lang", "annotation", "Annotation")
155             val enumClass = nameForClass("java", "lang", "Enum")
156 
157             /** Generates a class name from the package and class names in [nameParts] */
158             fun nameForClass(vararg nameParts: String): String {
159                 val separator = if (useInternalNames) "/" else "."
160                 return nameParts.joinToString(separator)
161             }
162 
163             /** The names of the doclava enum methods, based on [Api.useInternalNames] */
164             fun enumMethodNames(className: String): List<String> {
165                 return if (useInternalNames) {
166                     listOf("valueOf(Ljava/lang/String;)L$className;", "values()[L$className;")
167                 } else {
168                     listOf("valueOf(java.lang.String)", "values()")
169                 }
170             }
171         }
172 
173     codebaseFragment.accept(delegatedVisitor)
174 }
175 
176 /**
177  * Like [CallableItem.internalName] but is the desc-portion of the internal signature, e.g. for the
178  * method "void create(int x, int y)" the internal name of the constructor is "create" and the desc
179  * is "(II)V"
180  */
CallableItemnull181 fun CallableItem.internalDesc(voidConstructorTypes: Boolean = false): String {
182     val sb = StringBuilder()
183     sb.append("(")
184 
185     // Inner, i.e. non-static nested, classes get an implicit constructor parameter for the
186     // outer type
187     if (
188         isConstructor() &&
189             containingClass().containingClass() != null &&
190             !containingClass().modifiers.isStatic()
191     ) {
192         sb.append(containingClass().containingClass()?.type()?.internalName() ?: "")
193     }
194 
195     for (parameter in parameters()) {
196         sb.append(parameter.type().internalName())
197     }
198 
199     sb.append(")")
200     sb.append(if (voidConstructorTypes && isConstructor()) "V" else returnType().internalName())
201     return sb.toString()
202 }
203