• 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                 newClass.addSuperClass("java/lang/Object", apiLevel)
116             }
117 
118             for (interfaceType in cls.filteredInterfaceTypes(filterReference)) {
119                 val interfaceClass = interfaceType.asClass() ?: return
120                 newClass.addInterface(interfaceClass.internalName(), apiLevel)
121             }
122         }
123 
124         override fun visitMethod(method: MethodItem) {
125             if (method.isPrivate || method.isPackagePrivate) {
126                 return
127             }
128             val name = method.internalName() +
129                 // Use "V" instead of the type of the constructor for backwards compatibility
130                 // with the older bytecode
131                 method.internalDesc(voidConstructorTypes = true)
132             currentClass?.addMethod(name, apiLevel, method.deprecated)
133         }
134 
135         override fun visitField(field: FieldItem) {
136             if (field.isPrivate || field.isPackagePrivate) {
137                 return
138             }
139 
140             currentClass?.addField(field.internalName(), apiLevel, field.deprecated)
141         }
142     })
143 }