1 /*
<lambda>null2  * 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
18 
19 import java.io.File
20 
21 /**
22  * Represents a complete unit of code -- typically in the form of a set of source trees, but also
23  * potentially backed by .jar files or even signature files
24  */
25 interface Codebase {
26     /** Description of what this codebase is (useful during debugging) */
27     val description: String
28 
29     /**
30      * The location of the API. Could point to a signature file, or a directory root for source
31      * files, or a jar file, etc.
32      */
33     val location: File
34 
35     /** The manager of annotations within this codebase. */
36     val annotationManager: AnnotationManager
37 
38     /** The packages in the codebase (may include packages that are not included in the API) */
39     fun getPackages(): PackageList
40 
41     /** The rough size of the codebase (package count) */
42     fun size(): Int
43 
44     /** Returns a class identified by fully qualified name, if in the codebase */
45     fun findClass(className: String): ClassItem?
46 
47     /**
48      * Resolve a class identified by fully qualified name.
49      *
50      * This does everything it can to retrieve a suitable class, e.g. searching classpath (if
51      * available). That may include fabricating the [ClassItem] from nothing in the case of models
52      * that work with a partial set of classes (like text model).
53      */
54     fun resolveClass(className: String): ClassItem?
55 
56     /** Returns a package identified by fully qualified name, if in the codebase */
57     fun findPackage(pkgName: String): PackageItem?
58 
59     /** Returns true if this codebase supports documentation. */
60     fun supportsDocumentation(): Boolean
61 
62     /**
63      * Returns true if this codebase corresponds to an already trusted API (e.g. is read in from
64      * something like an existing signature file); in that case, signature checks etc will not be
65      * performed.
66      */
67     fun trustedApi(): Boolean
68 
69     fun accept(visitor: ItemVisitor) {
70         getPackages().accept(visitor)
71     }
72 
73     /** Creates an annotation item for the given (fully qualified) Java source */
74     fun createAnnotation(
75         source: String,
76         context: Item? = null,
77     ): AnnotationItem
78 
79     /** Reports that the given operation is unsupported for this codebase type */
80     fun unsupported(desc: String? = null): Nothing
81 
82     /** Discards this model */
83     fun dispose()
84 
85     /** If true, this codebase has already been filtered */
86     val preFiltered: Boolean
87 
88     fun isEmpty(): Boolean {
89         return getPackages().packages.isEmpty()
90     }
91 }
92 
93 sealed class MinSdkVersion
94 
95 data class SetMinSdkVersion(val value: Int) : MinSdkVersion()
96 
97 object UnsetMinSdkVersion : MinSdkVersion()
98 
99 const val CLASS_ESTIMATE = 15000
100 
101 abstract class DefaultCodebase(
102     final override var location: File,
103     final override var description: String,
104     final override val preFiltered: Boolean,
105     final override val annotationManager: AnnotationManager,
106 ) : Codebase {
107 
unsupportednull108     override fun unsupported(desc: String?): Nothing {
109         error(
110             desc
111                 ?: "This operation is not available on this type of codebase (${this.javaClass.simpleName})"
112         )
113     }
114 
disposenull115     override fun dispose() {
116         description += " [disposed]"
117     }
118 
119     /** A list of all the classes. Primarily used by [iterateAllClasses]. */
120     private val allClasses: MutableList<ClassItem> = ArrayList(CLASS_ESTIMATE)
121 
122     /**
123      * Add a [ClassItem].
124      *
125      * It is the responsibility of the caller to ensure that each [classItem] is not added more than
126      * once.
127      */
addClassnull128     protected fun addClass(classItem: ClassItem) {
129         allClasses.add(classItem)
130     }
131 
132     /**
133      * Iterate over all the [ClassItem]s in the [Codebase].
134      *
135      * If additional classes are added to the [Codebase] by [body], e.g. by resolving a
136      * `ClassTypeItem` to a class on the classpath that was not previously loaded, then they will be
137      * included in the iteration.
138      */
iterateAllClassesnull139     fun iterateAllClasses(body: (ClassItem) -> Unit) {
140         // Iterate by index not using an iterator to avoid `ConcurrentModificationException`s.
141         // Limit the first round of iteration to just the classes that were present at the start.
142         var start = 0
143         var end = allClasses.size
144         do {
145             // Iterate over the classes in the selected range, invoking [body] pn each.
146             for (i in start until end) {
147                 val classItem = allClasses[i]
148                 body(classItem)
149             }
150 
151             // Move the range to include all the classes, if any, added during the previous round.
152             start = end
153             end = allClasses.size
154 
155             // Repeat until no new classes were added.
156         } while (start < end)
157     }
158 
159     /** Iterate over all the classes resolving their super class and interface types. */
resolveSuperTypesnull160     fun resolveSuperTypes() {
161         iterateAllClasses { classItem ->
162             classItem.superClass()
163             for (interfaceType in classItem.interfaceTypes()) {
164                 interfaceType.asClass()
165             }
166         }
167     }
168 }
169