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