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 18 19 open class BaseItemVisitor( 20 /** 21 * Whether constructors should be visited as part of a [#visitMethod] call instead of just a 22 * [#visitConstructor] call. Helps simplify visitors that don't care to distinguish between the 23 * two cases. Defaults to true. 24 */ 25 val visitConstructorsAsMethods: Boolean = true, 26 /** 27 * Whether inner classes should be visited "inside" a class; when this property is true, inner 28 * classes are visited before the [#afterVisitClass] method is called; when false, it's done 29 * afterwards. Defaults to false. 30 */ 31 val nestInnerClasses: Boolean = false, 32 ) : ItemVisitor { visitnull33 override fun visit(cls: ClassItem) { 34 if (skip(cls)) { 35 return 36 } 37 38 visitItem(cls) 39 visitClass(cls) 40 41 for (constructor in cls.constructors()) { 42 constructor.accept(this) 43 } 44 45 for (method in cls.methods()) { 46 method.accept(this) 47 } 48 49 for (property in cls.properties()) { 50 property.accept(this) 51 } 52 53 if (cls.isEnum()) { 54 // In enums, visit the enum constants first, then the fields 55 for (field in cls.fields()) { 56 if (field.isEnumConstant()) { 57 field.accept(this) 58 } 59 } 60 for (field in cls.fields()) { 61 if (!field.isEnumConstant()) { 62 field.accept(this) 63 } 64 } 65 } else { 66 for (field in cls.fields()) { 67 field.accept(this) 68 } 69 } 70 71 if (nestInnerClasses) { 72 for (innerCls in cls.innerClasses()) { 73 innerCls.accept(this) 74 } 75 } // otherwise done below 76 77 afterVisitClass(cls) 78 afterVisitItem(cls) 79 80 if (!nestInnerClasses) { 81 for (innerCls in cls.innerClasses()) { 82 innerCls.accept(this) 83 } 84 } 85 } 86 visitnull87 override fun visit(field: FieldItem) { 88 if (skip(field)) { 89 return 90 } 91 92 visitItem(field) 93 visitField(field) 94 95 afterVisitField(field) 96 afterVisitItem(field) 97 } 98 visitnull99 override fun visit(method: MethodItem) { 100 if (skip(method)) { 101 return 102 } 103 104 visitItem(method) 105 if (method.isConstructor()) { 106 visitConstructor(method as ConstructorItem) 107 } else { 108 visitMethod(method) 109 } 110 111 for (parameter in method.parameters()) { 112 parameter.accept(this) 113 } 114 115 if (method.isConstructor()) { 116 afterVisitConstructor(method as ConstructorItem) 117 } else { 118 afterVisitMethod(method) 119 } 120 afterVisitItem(method) 121 } 122 visitnull123 override fun visit(pkg: PackageItem) { 124 if (skip(pkg)) { 125 return 126 } 127 128 visitItem(pkg) 129 visitPackage(pkg) 130 131 for (cls in pkg.topLevelClasses()) { 132 cls.accept(this) 133 } 134 135 afterVisitPackage(pkg) 136 afterVisitItem(pkg) 137 } 138 visitnull139 override fun visit(packageList: PackageList) { 140 visitCodebase(packageList.codebase) 141 packageList.packages.forEach { it.accept(this) } 142 afterVisitCodebase(packageList.codebase) 143 } 144 visitnull145 override fun visit(parameter: ParameterItem) { 146 if (skip(parameter)) { 147 return 148 } 149 150 visitItem(parameter) 151 visitParameter(parameter) 152 153 afterVisitParameter(parameter) 154 afterVisitItem(parameter) 155 } 156 visitnull157 override fun visit(property: PropertyItem) { 158 if (skip(property)) { 159 return 160 } 161 162 visitItem(property) 163 visitProperty(property) 164 165 afterVisitProperty(property) 166 afterVisitItem(property) 167 } 168 skipnull169 open fun skip(item: Item): Boolean = false 170 171 /** 172 * Visits the item. This is always called before other more specialized visit methods, such as 173 * [visitClass]. 174 */ 175 open fun visitItem(item: Item) {} 176 visitCodebasenull177 open fun visitCodebase(codebase: Codebase) {} 178 visitPackagenull179 open fun visitPackage(pkg: PackageItem) {} 180 visitClassnull181 open fun visitClass(cls: ClassItem) {} 182 visitConstructornull183 open fun visitConstructor(constructor: ConstructorItem) { 184 if (visitConstructorsAsMethods) { 185 visitMethod(constructor) 186 } 187 } 188 visitFieldnull189 open fun visitField(field: FieldItem) {} 190 visitMethodnull191 open fun visitMethod(method: MethodItem) {} 192 visitParameternull193 open fun visitParameter(parameter: ParameterItem) {} 194 visitPropertynull195 open fun visitProperty(property: PropertyItem) {} 196 afterVisitItemnull197 open fun afterVisitItem(item: Item) {} 198 afterVisitCodebasenull199 open fun afterVisitCodebase(codebase: Codebase) {} 200 afterVisitPackagenull201 open fun afterVisitPackage(pkg: PackageItem) {} 202 afterVisitClassnull203 open fun afterVisitClass(cls: ClassItem) {} 204 afterVisitConstructornull205 open fun afterVisitConstructor(constructor: ConstructorItem) { 206 if (visitConstructorsAsMethods) { 207 afterVisitMethod(constructor) 208 } 209 } 210 afterVisitFieldnull211 open fun afterVisitField(field: FieldItem) {} 212 afterVisitMethodnull213 open fun afterVisitMethod(method: MethodItem) {} 214 afterVisitParameternull215 open fun afterVisitParameter(parameter: ParameterItem) {} 216 afterVisitPropertynull217 open fun afterVisitProperty(property: PropertyItem) {} 218 } 219