1 /* 2 * Copyright (C) 2024 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.visitors 18 19 import com.android.tools.metalava.model.CallableItem 20 import com.android.tools.metalava.model.ClassItem 21 import com.android.tools.metalava.model.ClassTypeItem 22 import com.android.tools.metalava.model.Codebase 23 import com.android.tools.metalava.model.ConstructorItem 24 import com.android.tools.metalava.model.DelegatedVisitor 25 import com.android.tools.metalava.model.ExceptionTypeItem 26 import com.android.tools.metalava.model.FieldItem 27 import com.android.tools.metalava.model.Item 28 import com.android.tools.metalava.model.ItemVisitor 29 import com.android.tools.metalava.model.MethodItem 30 import com.android.tools.metalava.model.PackageItem 31 import com.android.tools.metalava.model.ParameterItem 32 import com.android.tools.metalava.model.PropertyItem 33 import com.android.tools.metalava.model.SourceFile 34 import com.android.tools.metalava.model.TypeItem 35 import com.android.tools.metalava.model.TypeTransformer 36 import com.android.tools.metalava.model.typeUseAnnotationFilter 37 38 /** 39 * An [ApiVisitor] that filters the input and forwards it to the [delegate] [ItemVisitor]. 40 * 41 * This defines a number of `Filtering*Item` classes that will filter out any [Item] references for 42 * which [filterReference] returns false. They are not suitable for general use. Their sole purpose 43 * is to provide enough functionality for use when writing a representation of the item, e.g. for 44 * signatures, stubs, etc. That means that there may be some methods that are not use by those 45 * writers which will allow access to unfiltered `Item`s. 46 * 47 * Preserves class nesting as required by the [delegate]'s [DelegatedVisitor.requiresClassNesting] 48 * property. 49 */ 50 class FilteringApiVisitor( 51 val delegate: DelegatedVisitor, 52 inlineInheritedFields: Boolean = true, 53 callableComparator: Comparator<CallableItem> = CallableItem.comparator, 54 /** 55 * Optional lambda for sorting the filtered, list of interface types from a [ClassItem]. 56 * 57 * This will only be called if the filtered list contains 2 or more elements. 58 * 59 * This is provided primarily to allow usages where the interface order cannot be enforced by 60 * [interfaceListComparator]. In that case this should be provided and [interfaceListComparator] 61 * should be left unspecified so that the order of the list returned by this is unchanged. 62 * 63 * If this is `null` then it will behave as if it just returned the filtered interface types it 64 * was passed. 65 * 66 * This is mutually exclusive with [interfaceListComparator]. 67 */ 68 private val interfaceListSorter: 69 ((ClassItem, List<ClassTypeItem>, List<ClassTypeItem>) -> List<ClassTypeItem>)? = 70 null, 71 /** 72 * Optional comparator to use for sorting interface list types. 73 * 74 * This is mutually exclusive with [interfaceListSorter]. 75 */ 76 private val interfaceListComparator: Comparator<TypeItem>? = null, 77 apiFilters: ApiFilters, 78 private val preFiltered: Boolean, 79 private val filterSuperClassType: Boolean = true, 80 showUnannotated: Boolean = true, 81 private val ignoreEmit: Boolean = false, 82 ) : 83 ApiVisitor( 84 preserveClassNesting = delegate.requiresClassNesting, 85 // Only `SelectableItem`s can be filtered separately, i.e. `ParameterItem`s will be included 86 // if and only if their containing method is included. 87 visitParameterItems = false, 88 inlineInheritedFields = inlineInheritedFields, 89 callableComparator = callableComparator, 90 apiFilters = apiFilters, 91 showUnannotated = showUnannotated, 92 ), 93 ItemVisitor { 94 95 /** 96 * A [TypeTransformer] that will remove any type annotations for which [filterReference] returns 97 * false when called against the annotation's [ClassItem]. 98 */ 99 private val typeAnnotationFilter = typeUseAnnotationFilter(filterReference) 100 visitCodebasenull101 override fun visitCodebase(codebase: Codebase) { 102 // This does not create a filtering wrapper around the Codebase as the classes to which this 103 // currently delegates do not access any fields within the Codebase. 104 delegate.visitCodebase(codebase) 105 } 106 afterVisitCodebasenull107 override fun afterVisitCodebase(codebase: Codebase) { 108 // This does not create a filtering wrapper around the Codebase as the classes to which this 109 // currently delegates do not access any fields within the Codebase. 110 delegate.afterVisitCodebase(codebase) 111 } 112 visitPackagenull113 override fun visitPackage(pkg: PackageItem) { 114 delegate.visitPackage(pkg) 115 } 116 afterVisitPackagenull117 override fun afterVisitPackage(pkg: PackageItem) { 118 delegate.afterVisitPackage(pkg) 119 } 120 121 /** Stack of the containing classes. */ 122 private val containingClassStack = ArrayDeque<FilteringClassItem?>() 123 124 /** The current [ClassItem] being visited, */ 125 private var currentClassItem: FilteringClassItem? = null 126 includenull127 override fun include(cls: ClassItem): Boolean { 128 return ignoreEmit || cls.emit 129 } 130 visitClassnull131 override fun visitClass(cls: ClassItem) { 132 // Switch the current class, if any, to be a containing class. 133 containingClassStack.addLast(currentClassItem) 134 135 // Create a new FilteringClassItem for the current class and visit it before its contents. 136 currentClassItem = FilteringClassItem(delegate = cls) 137 delegate.visitClass(currentClassItem!!) 138 } 139 afterVisitClassnull140 override fun afterVisitClass(cls: ClassItem) { 141 // Consistency check to make sure that the visitClass/afterVisitClass are called correctly. 142 if (currentClassItem?.delegate !== cls) 143 throw IllegalStateException("Expected ${currentClassItem?.delegate}, found ${cls}") 144 145 // Visit the class after its contents. 146 delegate.afterVisitClass(currentClassItem!!) 147 148 // Switch back to the containing class, if any. 149 currentClassItem = containingClassStack.removeLast() 150 } 151 visitConstructornull152 override fun visitConstructor(constructor: ConstructorItem) { 153 val filteringConstructor = FilteringConstructorItem(constructor) 154 delegate.visitConstructor(filteringConstructor) 155 } 156 visitMethodnull157 override fun visitMethod(method: MethodItem) { 158 val filteringMethod = FilteringMethodItem(method) 159 delegate.visitMethod(filteringMethod) 160 } 161 visitFieldnull162 override fun visitField(field: FieldItem) { 163 val filteringField = FilteringFieldItem(field) 164 delegate.visitField(filteringField) 165 } 166 visitPropertynull167 override fun visitProperty(property: PropertyItem) { 168 val filteringProperty = FilteringPropertyItem(property) 169 delegate.visitProperty(filteringProperty) 170 } 171 172 /** 173 * [SourceFile] that will filter out anything which is not to be written out by the 174 * [FilteringApiVisitor.delegate]. 175 */ <lambda>null176 private inner class FilteringSourceFile(val delegate: SourceFile) : SourceFile by delegate { 177 178 override fun getImports() = delegate.getImports(filterReference) 179 } 180 181 /** 182 * [ClassItem] that will filter out anything which is not to be written out by the 183 * [FilteringApiVisitor.delegate]. 184 */ 185 private inner class FilteringClassItem( 186 val delegate: ClassItem, <lambda>null187 ) : ClassItem by delegate { 188 189 override fun sourceFile() = delegate.sourceFile()?.let { FilteringSourceFile(it) } 190 191 override fun superClass() = superClassType()?.asClass() 192 193 override fun superClassType() = 194 if (!filterSuperClassType || preFiltered) delegate.superClassType() 195 else delegate.filteredSuperClassType(filterReference)?.transform(typeAnnotationFilter) 196 197 override fun interfaceTypes(): List<ClassTypeItem> { 198 // Get the filtered list from the delegate. 199 val filtered = 200 if (preFiltered) delegate.interfaceTypes() 201 else delegate.filteredInterfaceTypes(filterReference).toList() 202 203 // If the list is empty then nothing else is needed. 204 if (filtered.isEmpty()) return emptyList() 205 206 // Order the list. 207 val ordered = 208 when { 209 // 0. If the list only has 1 element then it does not need sorting 210 filtered.size == 1 -> filtered 211 212 // 1. Use the custom sorter, if available. 213 interfaceListSorter != null -> { 214 // Make sure a interfaceListComparator was not provided as well. 215 interfaceListComparator?.let { 216 error( 217 "Cannot specify both interfaceListSorter and interfaceListComparator" 218 ) 219 } 220 221 // Get the unfiltered lists from the delegate. 222 val unfiltered = 223 if (preFiltered) { 224 // If pre-filtered then the filtered and unfiltered are the 225 // same. 226 filtered 227 } else delegate.interfaceTypes() 228 229 interfaceListSorter.invoke(delegate, filtered, unfiltered) 230 } 231 232 // 2. Sort using the comparator, if available. 233 interfaceListComparator != null -> { 234 filtered.sortedWith(interfaceListComparator) 235 } 236 237 // 3. Preserve the input order. 238 else -> filtered 239 } 240 241 // If required then filter annotation types from the ordered list before returning. 242 return if (preFiltered) ordered 243 else 244 ordered.map { 245 // Filter any inaccessible annotations from the interfaces 246 it.transform(typeAnnotationFilter) 247 } 248 } 249 250 override fun constructors() = 251 delegate 252 .filteredConstructors(filterReference) 253 .map { FilteringConstructorItem(it) } 254 .toList() 255 256 override fun fields(): List<FieldItem> = 257 delegate.filteredFields(filterReference, showUnannotated).map { FilteringFieldItem(it) } 258 } 259 260 /** 261 * [ParameterItem] that will filter out anything which is not to be written out by the 262 * [FilteringApiVisitor.delegate]. 263 */ 264 private inner class FilteringParameterItem(private val delegate: ParameterItem) : <lambda>null265 ParameterItem by delegate { 266 267 override fun type() = delegate.type().transform(typeAnnotationFilter) 268 } 269 270 /** Get the [MethodItem.returnType] and apply the [typeAnnotationFilter] to it. */ filteredReturnTypenull271 fun filteredReturnType(callableItem: CallableItem) = 272 callableItem.returnType().transform(typeAnnotationFilter) 273 274 /** Get the [MethodItem.parameters] and wrap each one in a [FilteringParameterItem]. */ 275 fun filteredParameters(callableItem: CallableItem): List<ParameterItem> = 276 callableItem.parameters().map { FilteringParameterItem(it) } 277 278 /** 279 * Get the [MethodItem.filteredThrowsTypes] and apply [typeAnnotationFilter] to each 280 * [ExceptionTypeItem] in the list. 281 */ filteredThrowsTypesnull282 private fun filteredThrowsTypes(callableItem: CallableItem) = 283 if (preFiltered) callableItem.throwsTypes() 284 else 285 callableItem.filteredThrowsTypes(filterReference).map { 286 it.transform(typeAnnotationFilter) 287 } 288 289 /** 290 * [ConstructorItem] that will filter out anything which is not to be written out by the 291 * [FilteringApiVisitor.delegate]. 292 */ 293 private inner class FilteringConstructorItem(private val delegate: ConstructorItem) : <lambda>null294 ConstructorItem by delegate { 295 296 override fun containingClass() = FilteringClassItem(delegate.containingClass()) 297 298 override fun returnType() = filteredReturnType(delegate) as ClassTypeItem 299 300 override fun parameters() = filteredParameters(delegate) 301 302 override fun throwsTypes() = filteredThrowsTypes(delegate) 303 } 304 305 /** 306 * [MethodItem] that will filter out anything which is not to be written out by the 307 * [FilteringApiVisitor.delegate]. 308 */ 309 private inner class FilteringMethodItem(private val delegate: MethodItem) : <lambda>null310 MethodItem by delegate { 311 312 override fun returnType() = filteredReturnType(delegate) 313 314 override fun parameters() = filteredParameters(delegate) 315 316 override fun throwsTypes() = filteredThrowsTypes(delegate) 317 } 318 319 /** 320 * [FieldItem] that will filter out anything which is not to be written out by the 321 * [FilteringApiVisitor.delegate]. 322 */ 323 private inner class FilteringFieldItem(private val delegate: FieldItem) : <lambda>null324 FieldItem by delegate { 325 326 override fun type() = delegate.type().transform(typeAnnotationFilter) 327 } 328 329 /** 330 * [PropertyItem] that will filter out anything which is not to be written out by the 331 * [FilteringApiVisitor.delegate]. 332 */ 333 private inner class FilteringPropertyItem(private val delegate: PropertyItem) : <lambda>null334 PropertyItem by delegate { 335 336 override fun type() = delegate.type().transform(typeAnnotationFilter) 337 } 338 } 339