1 /* 2 * 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.visitors 18 19 import com.android.tools.metalava.doclava1.ApiPredicate 20 import com.android.tools.metalava.model.ClassItem 21 import com.android.tools.metalava.model.FieldItem 22 import com.android.tools.metalava.model.Item 23 import com.android.tools.metalava.model.MethodItem 24 import com.android.tools.metalava.model.VisitCandidate 25 import com.android.tools.metalava.options 26 import java.util.function.Predicate 27 28 open class ApiVisitor( 29 /** 30 * Whether constructors should be visited as part of a [#visitMethod] call 31 * instead of just a [#visitConstructor] call. Helps simplify visitors that 32 * don't care to distinguish between the two cases. Defaults to true. 33 */ 34 visitConstructorsAsMethods: Boolean = true, 35 /** 36 * Whether inner classes should be visited "inside" a class; when this property 37 * is true, inner classes are visited before the [#afterVisitClass] method is 38 * called; when false, it's done afterwards. Defaults to false. 39 */ 40 nestInnerClasses: Boolean = false, 41 42 /** 43 * Whether to include inherited fields too 44 */ 45 val inlineInheritedFields: Boolean = true, 46 47 /** Comparator to sort methods with, or null to use natural (source) order */ 48 val methodComparator: Comparator<MethodItem>? = null, 49 50 /** Comparator to sort fields with, or null to use natural (source) order */ 51 val fieldComparator: Comparator<FieldItem>? = null, 52 53 /** The filter to use to determine if we should emit an item */ 54 val filterEmit: Predicate<Item>, 55 56 /** The filter to use to determine if we should emit a reference to an item */ 57 val filterReference: Predicate<Item>, 58 59 /** 60 * Whether the visitor should include visiting top-level classes that have 61 * nothing other than non-empty inner classes within. 62 * Typically these are not included in signature files, but when generating 63 * stubs we need to include them. 64 */ 65 val includeEmptyOuterClasses: Boolean = false, 66 67 /** 68 * Whether this visitor should visit elements that have not been 69 * annotated with one of the annotations passed in using the 70 * --show-annotation flag. This is normally true, but signature files 71 * sometimes sets this to false to make the signature file only contain 72 * the "diff" of the annotated API relative to the base API. 73 */ 74 val showUnannotated: Boolean = true 75 ) : ItemVisitor(visitConstructorsAsMethods, nestInnerClasses) { 76 constructor( 77 /** 78 * Whether constructors should be visited as part of a [#visitMethod] call 79 * instead of just a [#visitConstructor] call. Helps simplify visitors that 80 * don't care to distinguish between the two cases. Defaults to true. 81 */ 82 visitConstructorsAsMethods: Boolean = true, 83 /** 84 * Whether inner classes should be visited "inside" a class; when this property 85 * is true, inner classes are visited before the [#afterVisitClass] method is 86 * called; when false, it's done afterwards. Defaults to false. 87 */ 88 nestInnerClasses: Boolean = false, 89 90 /** Whether to ignore APIs with annotations in the --show-annotations list */ 91 ignoreShown: Boolean = true, 92 93 /** Whether to match APIs marked for removal instead of the normal API */ 94 remove: Boolean = false, 95 96 /** Comparator to sort methods with, or null to use natural (source) order */ 97 methodComparator: Comparator<MethodItem>? = null, 98 99 /** Comparator to sort fields with, or null to use natural (source) order */ 100 fieldComparator: Comparator<FieldItem>? = null 101 ) : this( 102 visitConstructorsAsMethods, nestInnerClasses, 103 true, methodComparator, 104 fieldComparator, 105 ApiPredicate(ignoreShown = ignoreShown, matchRemoved = remove), 106 ApiPredicate(ignoreShown = true, ignoreRemoved = remove) 107 ) 108 109 // The API visitor lazily visits packages only when there's a match within at least one class; 110 // this property keeps track of whether we've already visited the current package 111 var visitingPackage = false 112 113 /** 114 * @return Whether this class is generally one that we want to recurse into 115 */ includenull116 open fun include(cls: ClassItem): Boolean { 117 if (skip(cls)) { 118 return false 119 } 120 val filter = options.stubPackages 121 if (filter != null && !filter.matches(cls.containingPackage())) { 122 return false 123 } 124 125 return cls.emit || cls.codebase.preFiltered 126 } 127 128 /** 129 * @return Whether the given VisitCandidate's visitor should recurse into the given 130 * VisitCandidate's class 131 */ includenull132 fun include(vc: VisitCandidate): Boolean { 133 if (!include(vc.cls)) { 134 return false 135 } 136 return shouldEmitClassBody(vc) || shouldEmitInnerClasses(vc) 137 } 138 139 /** 140 * @return Whether this class should be visited 141 * Note that if [include] returns true then we will still visit classes that are contained by this one 142 */ shouldEmitClassnull143 open fun shouldEmitClass(vc: VisitCandidate): Boolean { 144 return vc.cls.emit && (includeEmptyOuterClasses || shouldEmitClassBody(vc)) 145 } 146 147 /** 148 * @return Whether the body of this class (everything other than the inner classes) emits anything 149 */ shouldEmitClassBodynull150 fun shouldEmitClassBody(vc: VisitCandidate): Boolean { 151 return if (filterEmit.test(vc.cls)) { 152 true 153 } else if (vc.nonEmpty()) { 154 filterReference.test(vc.cls) 155 } else { 156 false 157 } 158 } 159 160 /** 161 * @return Whether the inner classes of this class will emit anything 162 */ shouldEmitInnerClassesnull163 fun shouldEmitInnerClasses(vc: VisitCandidate): Boolean { 164 return vc.innerClasses.any { shouldEmitAnyClass(it) } 165 } 166 167 /** 168 * @return Whether this class will emit anything 169 */ shouldEmitAnyClassnull170 fun shouldEmitAnyClass(vc: VisitCandidate): Boolean { 171 return shouldEmitClassBody(vc) || shouldEmitInnerClasses(vc) 172 } 173 } 174