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