• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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.ClassItem
20 import com.android.tools.metalava.model.Codebase
21 import com.android.tools.metalava.model.FieldItem
22 import com.android.tools.metalava.model.MethodItem
23 import com.android.tools.metalava.model.visitors.ApiVisitor
24 
25 /** Visits the API codebase and inserts into the [Api] the classes, methods and fields */
addApisFromCodebasenull26 fun addApisFromCodebase(api: Api, apiLevel: Int, codebase: Codebase) {
27     codebase.accept(object : ApiVisitor(
28         visitConstructorsAsMethods = true,
29         nestInnerClasses = false
30     ) {
31 
32             var currentClass: ApiClass? = null
33 
34             override fun afterVisitClass(cls: ClassItem) {
35                 currentClass = null
36             }
37 
38             override fun visitClass(cls: ClassItem) {
39                 val newClass = api.addClass(cls.internalName(), apiLevel, cls.deprecated)
40                 currentClass = newClass
41 
42                 if (cls.isClass()) {
43                     // The jar files historically contain package private parents instead of
44                     // the real API so we need to correct the data we've already read in
45 
46                     val filteredSuperClass = cls.filteredSuperclass(filterReference)
47                     val superClass = cls.superClass()
48                     if (filteredSuperClass != superClass && filteredSuperClass != null) {
49                         val existing = newClass.superClasses.firstOrNull()?.name
50                         val superInternalName = superClass?.internalName()
51                         if (existing == superInternalName) {
52                             // The bytecode used to point to the old hidden super class. Point
53                             // to the real one (that the signature files referenced) instead.
54                             val removed = newClass.removeSuperClass(superInternalName)
55                             val since = removed?.since ?: apiLevel
56                             val entry = newClass.addSuperClass(filteredSuperClass.internalName(), since)
57                             // Show that it's also seen here
58                             entry.update(apiLevel)
59 
60                             // Also inherit the interfaces from that API level, unless it was added later
61                             val superClassEntry = api.findClass(superInternalName)
62                             if (superClassEntry != null) {
63                                 for (interfaceType in superClass!!.filteredInterfaceTypes(filterReference)) {
64                                     val interfaceClass = interfaceType.asClass() ?: return
65                                     var mergedSince = since
66                                     val interfaceName = interfaceClass.internalName()
67                                     for (itf in superClassEntry.interfaces) {
68                                         val currentInterface = itf.name
69                                         if (interfaceName == currentInterface) {
70                                             mergedSince = itf.since
71                                             break
72                                         }
73                                     }
74                                     newClass.addInterface(interfaceClass.internalName(), mergedSince)
75                                 }
76                             }
77                         } else {
78                             newClass.addSuperClass(filteredSuperClass.internalName(), apiLevel)
79                         }
80                     } else if (superClass != null) {
81                         newClass.addSuperClass(superClass.internalName(), apiLevel)
82                     }
83                 } else if (cls.isInterface()) {
84                     val superClass = cls.superClass()
85                     if (superClass != null && !superClass.isJavaLangObject()) {
86                         newClass.addInterface(superClass.internalName(), apiLevel)
87                     }
88                 } else if (cls.isEnum()) {
89                     // Implicit super class; match convention from bytecode
90                     if (newClass.name != "java/lang/Enum") {
91                         newClass.addSuperClass("java/lang/Enum", apiLevel)
92                     }
93 
94                     // Mimic doclava enum methods
95                     newClass.addMethod("valueOf(Ljava/lang/String;)L" + newClass.name + ";", apiLevel, false)
96                     newClass.addMethod("values()[L" + newClass.name + ";", apiLevel, false)
97                 } else if (cls.isAnnotationType()) {
98                     // Implicit super class; match convention from bytecode
99                     if (newClass.name != "java/lang/annotation/Annotation") {
100                         newClass.addSuperClass("java/lang/Object", apiLevel)
101                         newClass.addInterface("java/lang/annotation/Annotation", apiLevel)
102                     }
103                 }
104 
105                 // Ensure we don't end up with
106                 //    -  <extends name="java/lang/Object"/>
107                 //    +  <extends name="java/lang/Object" removed="29"/>
108                 // which can happen because the bytecode always explicitly contains extends java.lang.Object
109                 // but in the source code we don't see it, and the lack of presence of this shouldn't be
110                 // taken as a sign that we no longer extend object. But only do this if the class didn't
111                 // previously extend object and now extends something else.
112                 if ((cls.isClass() || cls.isInterface()) &&
113                     newClass.superClasses.size == 1 &&
114                     newClass.superClasses[0].name == "java/lang/Object"
115                 ) {
116                     newClass.addSuperClass("java/lang/Object", apiLevel)
117                 }
118 
119                 for (interfaceType in cls.filteredInterfaceTypes(filterReference)) {
120                     val interfaceClass = interfaceType.asClass() ?: return
121                     newClass.addInterface(interfaceClass.internalName(), apiLevel)
122                 }
123             }
124 
125             override fun visitMethod(method: MethodItem) {
126                 if (method.isPrivate || method.isPackagePrivate) {
127                     return
128                 }
129                 val name = method.internalName() +
130                     // Use "V" instead of the type of the constructor for backwards compatibility
131                     // with the older bytecode
132                     method.internalDesc(voidConstructorTypes = true)
133                 currentClass?.addMethod(name, apiLevel, method.deprecated)
134             }
135 
136             override fun visitField(field: FieldItem) {
137                 if (field.isPrivate || field.isPackagePrivate) {
138                     return
139                 }
140 
141                 currentClass?.addField(field.internalName(), apiLevel, field.deprecated)
142             }
143         })
144 }
145