1 | /* |
2 | * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. Sun designates this |
8 | * particular file as subject to the "Classpath" exception as provided |
9 | * by Sun in the LICENSE file that accompanied this code. |
10 | * |
11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | * version 2 for more details (a copy is included in the LICENSE file that |
15 | * accompanied this code). |
16 | * |
17 | * You should have received a copy of the GNU General Public License version |
18 | * 2 along with this work; if not, write to the Free Software Foundation, |
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | * |
21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
23 | * have any questions. |
24 | */ |
25 | |
26 | package com.sun.source.util; |
27 | |
28 | import com.sun.source.tree.*; |
29 | |
30 | /** |
31 | * A TreeVisitor that visits all the child tree nodes. |
32 | * To visit nodes of a particular type, just override the |
33 | * corresponding visitXYZ method. |
34 | * Inside your method, call super.visitXYZ to visit descendant |
35 | * nodes. |
36 | * |
37 | * <p>The default implementation of the visitXYZ methods will determine |
38 | * a result as follows: |
39 | * <ul> |
40 | * <li>If the node being visited has no children, the result will be null. |
41 | * <li>If the node being visited has one child, the result will be the |
42 | * result of calling {@code scan} on that child. The child may be a simple node |
43 | * or itself a list of nodes. |
44 | * <li> If the node being visited has more than one child, the result will |
45 | * be determined by calling {@code scan} each child in turn, and then combining the |
46 | * result of each scan after the first with the cumulative result |
47 | * so far, as determined by the {@link #reduce} method. Each child may be either |
48 | * a simple node of a list of nodes. The default behavior of the {@code reduce} |
49 | * method is such that the result of the visitXYZ method will be the result of |
50 | * the last child scanned. |
51 | * </ul> |
52 | * |
53 | * <p>Here is an example to count the number of identifier nodes in a tree: |
54 | * <pre> |
55 | * class CountIdentifiers extends TreeScanner<Integer,Void> { |
56 | * {@literal @}Override |
57 | * public Integer visitIdentifier(IdentifierTree node, Void p) { |
58 | * return 1; |
59 | * } |
60 | * {@literal @}Override |
61 | * public Integer reduce(Integer r1, Integer r2) { |
62 | * return (r1 == null ? 0 : r1) + (r2 == null ? 0 : r2); |
63 | * } |
64 | * } |
65 | * </pre> |
66 | * |
67 | * @author Peter von der Ahé |
68 | * @author Jonathan Gibbons |
69 | * @since 1.6 |
70 | */ |
71 | public class TreeScanner<R,P> implements TreeVisitor<R,P> { |
72 | |
73 | /** Scan a single node. |
74 | */ |
75 | public R scan(Tree node, P p) { |
76 | return (node == null) ? null : node.accept(this, p); |
77 | } |
78 | |
79 | private R scanAndReduce(Tree node, P p, R r) { |
80 | return reduce(scan(node, p), r); |
81 | } |
82 | |
83 | /** Scan a list of nodes. |
84 | */ |
85 | public R scan(Iterable<? extends Tree> nodes, P p) { |
86 | R r = null; |
87 | if (nodes != null) { |
88 | boolean first = true; |
89 | for (Tree node : nodes) { |
90 | r = (first ? scan(node, p) : scanAndReduce(node, p, r)); |
91 | first = false; |
92 | } |
93 | } |
94 | return r; |
95 | } |
96 | |
97 | private R scanAndReduce(Iterable<? extends Tree> nodes, P p, R r) { |
98 | return reduce(scan(nodes, p), r); |
99 | } |
100 | |
101 | /** |
102 | * Reduces two results into a combined result. |
103 | * The default implementation is to return the first parameter. |
104 | * The general contract of the method is that it may take any action whatsoever. |
105 | */ |
106 | public R reduce(R r1, R r2) { |
107 | return r1; |
108 | } |
109 | |
110 | |
111 | /* *************************************************************************** |
112 | * Visitor methods |
113 | ****************************************************************************/ |
114 | |
115 | public R visitCompilationUnit(CompilationUnitTree node, P p) { |
116 | R r = scan(node.getPackageAnnotations(), p); |
117 | r = scanAndReduce(node.getPackageName(), p, r); |
118 | r = scanAndReduce(node.getImports(), p, r); |
119 | r = scanAndReduce(node.getTypeDecls(), p, r); |
120 | return r; |
121 | } |
122 | |
123 | public R visitImport(ImportTree node, P p) { |
124 | return scan(node.getQualifiedIdentifier(), p); |
125 | } |
126 | |
127 | public R visitClass(ClassTree node, P p) { |
128 | R r = scan(node.getModifiers(), p); |
129 | r = scanAndReduce(node.getTypeParameters(), p, r); |
130 | r = scanAndReduce(node.getExtendsClause(), p, r); |
131 | r = scanAndReduce(node.getImplementsClause(), p, r); |
132 | r = scanAndReduce(node.getMembers(), p, r); |
133 | return r; |
134 | } |
135 | |
136 | public R visitMethod(MethodTree node, P p) { |
137 | R r = scan(node.getModifiers(), p); |
138 | r = scanAndReduce(node.getReturnType(), p, r); |
139 | r = scanAndReduce(node.getTypeParameters(), p, r); |
140 | r = scanAndReduce(node.getParameters(), p, r); |
141 | r = scanAndReduce(node.getThrows(), p, r); |
142 | r = scanAndReduce(node.getBody(), p, r); |
143 | return r; |
144 | } |
145 | |
146 | public R visitVariable(VariableTree node, P p) { |
147 | R r = scan(node.getModifiers(), p); |
148 | r = scanAndReduce(node.getType(), p, r); |
149 | r = scanAndReduce(node.getInitializer(), p, r); |
150 | return r; |
151 | } |
152 | |
153 | public R visitEmptyStatement(EmptyStatementTree node, P p) { |
154 | return null; |
155 | } |
156 | |
157 | public R visitBlock(BlockTree node, P p) { |
158 | return scan(node.getStatements(), p); |
159 | } |
160 | |
161 | public R visitDoWhileLoop(DoWhileLoopTree node, P p) { |
162 | R r = scan(node.getStatement(), p); |
163 | r = scanAndReduce(node.getCondition(), p, r); |
164 | return r; |
165 | } |
166 | |
167 | public R visitWhileLoop(WhileLoopTree node, P p) { |
168 | R r = scan(node.getCondition(), p); |
169 | r = scanAndReduce(node.getStatement(), p, r); |
170 | return r; |
171 | } |
172 | |
173 | public R visitForLoop(ForLoopTree node, P p) { |
174 | R r = scan(node.getInitializer(), p); |
175 | r = scanAndReduce(node.getCondition(), p, r); |
176 | r = scanAndReduce(node.getUpdate(), p, r); |
177 | r = scanAndReduce(node.getStatement(), p, r); |
178 | return r; |
179 | } |
180 | |
181 | public R visitEnhancedForLoop(EnhancedForLoopTree node, P p) { |
182 | R r = scan(node.getVariable(), p); |
183 | r = scanAndReduce(node.getExpression(), p, r); |
184 | r = scanAndReduce(node.getStatement(), p, r); |
185 | return r; |
186 | } |
187 | |
188 | public R visitLabeledStatement(LabeledStatementTree node, P p) { |
189 | return scan(node.getStatement(), p); |
190 | } |
191 | |
192 | public R visitSwitch(SwitchTree node, P p) { |
193 | R r = scan(node.getExpression(), p); |
194 | r = scanAndReduce(node.getCases(), p, r); |
195 | return r; |
196 | } |
197 | |
198 | public R visitCase(CaseTree node, P p) { |
199 | R r = scan(node.getExpression(), p); |
200 | r = scanAndReduce(node.getStatements(), p, r); |
201 | return r; |
202 | } |
203 | |
204 | public R visitSynchronized(SynchronizedTree node, P p) { |
205 | R r = scan(node.getExpression(), p); |
206 | r = scanAndReduce(node.getBlock(), p, r); |
207 | return r; |
208 | } |
209 | |
210 | public R visitTry(TryTree node, P p) { |
211 | R r = scan(node.getBlock(), p); |
212 | r = scanAndReduce(node.getCatches(), p, r); |
213 | r = scanAndReduce(node.getFinallyBlock(), p, r); |
214 | return r; |
215 | } |
216 | |
217 | public R visitCatch(CatchTree node, P p) { |
218 | R r = scan(node.getParameter(), p); |
219 | r = scanAndReduce(node.getBlock(), p, r); |
220 | return r; |
221 | } |
222 | |
223 | public R visitConditionalExpression(ConditionalExpressionTree node, P p) { |
224 | R r = scan(node.getCondition(), p); |
225 | r = scanAndReduce(node.getTrueExpression(), p, r); |
226 | r = scanAndReduce(node.getFalseExpression(), p, r); |
227 | return r; |
228 | } |
229 | |
230 | public R visitIf(IfTree node, P p) { |
231 | R r = scan(node.getCondition(), p); |
232 | r = scanAndReduce(node.getThenStatement(), p, r); |
233 | r = scanAndReduce(node.getElseStatement(), p, r); |
234 | return r; |
235 | } |
236 | |
237 | public R visitExpressionStatement(ExpressionStatementTree node, P p) { |
238 | return scan(node.getExpression(), p); |
239 | } |
240 | |
241 | public R visitBreak(BreakTree node, P p) { |
242 | return null; |
243 | } |
244 | |
245 | public R visitContinue(ContinueTree node, P p) { |
246 | return null; |
247 | } |
248 | |
249 | public R visitReturn(ReturnTree node, P p) { |
250 | return scan(node.getExpression(), p); |
251 | } |
252 | |
253 | public R visitThrow(ThrowTree node, P p) { |
254 | return scan(node.getExpression(), p); |
255 | } |
256 | |
257 | public R visitAssert(AssertTree node, P p) { |
258 | R r = scan(node.getCondition(), p); |
259 | r = scanAndReduce(node.getDetail(), p, r); |
260 | return r; |
261 | } |
262 | |
263 | public R visitMethodInvocation(MethodInvocationTree node, P p) { |
264 | R r = scan(node.getTypeArguments(), p); |
265 | r = scanAndReduce(node.getMethodSelect(), p, r); |
266 | r = scanAndReduce(node.getArguments(), p, r); |
267 | return r; |
268 | } |
269 | |
270 | public R visitNewClass(NewClassTree node, P p) { |
271 | R r = scan(node.getEnclosingExpression(), p); |
272 | r = scanAndReduce(node.getIdentifier(), p, r); |
273 | r = scanAndReduce(node.getTypeArguments(), p, r); |
274 | r = scanAndReduce(node.getArguments(), p, r); |
275 | r = scanAndReduce(node.getClassBody(), p, r); |
276 | return r; |
277 | } |
278 | |
279 | public R visitNewArray(NewArrayTree node, P p) { |
280 | R r = scan(node.getType(), p); |
281 | r = scanAndReduce(node.getDimensions(), p, r); |
282 | r = scanAndReduce(node.getInitializers(), p, r); |
283 | return r; |
284 | } |
285 | |
286 | public R visitParenthesized(ParenthesizedTree node, P p) { |
287 | return scan(node.getExpression(), p); |
288 | } |
289 | |
290 | public R visitAssignment(AssignmentTree node, P p) { |
291 | R r = scan(node.getVariable(), p); |
292 | r = scanAndReduce(node.getExpression(), p, r); |
293 | return r; |
294 | } |
295 | |
296 | public R visitCompoundAssignment(CompoundAssignmentTree node, P p) { |
297 | R r = scan(node.getVariable(), p); |
298 | r = scanAndReduce(node.getExpression(), p, r); |
299 | return r; |
300 | } |
301 | |
302 | public R visitUnary(UnaryTree node, P p) { |
303 | return scan(node.getExpression(), p); |
304 | } |
305 | |
306 | public R visitBinary(BinaryTree node, P p) { |
307 | R r = scan(node.getLeftOperand(), p); |
308 | r = scanAndReduce(node.getRightOperand(), p, r); |
309 | return r; |
310 | } |
311 | |
312 | public R visitTypeCast(TypeCastTree node, P p) { |
313 | R r = scan(node.getType(), p); |
314 | r = scanAndReduce(node.getExpression(), p, r); |
315 | return r; |
316 | } |
317 | |
318 | public R visitInstanceOf(InstanceOfTree node, P p) { |
319 | R r = scan(node.getExpression(), p); |
320 | r = scanAndReduce(node.getType(), p, r); |
321 | return r; |
322 | } |
323 | |
324 | public R visitArrayAccess(ArrayAccessTree node, P p) { |
325 | R r = scan(node.getExpression(), p); |
326 | r = scanAndReduce(node.getIndex(), p, r); |
327 | return r; |
328 | } |
329 | |
330 | public R visitMemberSelect(MemberSelectTree node, P p) { |
331 | return scan(node.getExpression(), p); |
332 | } |
333 | |
334 | public R visitIdentifier(IdentifierTree node, P p) { |
335 | return null; |
336 | } |
337 | |
338 | public R visitLiteral(LiteralTree node, P p) { |
339 | return null; |
340 | } |
341 | |
342 | public R visitPrimitiveType(PrimitiveTypeTree node, P p) { |
343 | return null; |
344 | } |
345 | |
346 | public R visitArrayType(ArrayTypeTree node, P p) { |
347 | return scan(node.getType(), p); |
348 | } |
349 | |
350 | public R visitParameterizedType(ParameterizedTypeTree node, P p) { |
351 | R r = scan(node.getType(), p); |
352 | r = scanAndReduce(node.getTypeArguments(), p, r); |
353 | return r; |
354 | } |
355 | |
356 | public R visitTypeParameter(TypeParameterTree node, P p) { |
357 | return scan(node.getBounds(), p); |
358 | } |
359 | |
360 | public R visitWildcard(WildcardTree node, P p) { |
361 | return scan(node.getBound(), p); |
362 | } |
363 | |
364 | public R visitModifiers(ModifiersTree node, P p) { |
365 | return scan(node.getAnnotations(), p); |
366 | } |
367 | |
368 | public R visitAnnotation(AnnotationTree node, P p) { |
369 | R r = scan(node.getAnnotationType(), p); |
370 | r = scanAndReduce(node.getArguments(), p, r); |
371 | return r; |
372 | } |
373 | |
374 | public R visitOther(Tree node, P p) { |
375 | return null; |
376 | } |
377 | |
378 | public R visitErroneous(ErroneousTree node, P p) { |
379 | return null; |
380 | } |
381 | } |