1 /* 2 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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.getReceiverParameter(), p, r); 142 r = scanAndReduce(node.getThrows(), p, r); 143 r = scanAndReduce(node.getBody(), p, r); 144 r = scanAndReduce(node.getDefaultValue(), p, r); 145 return r; 146 } 147 148 public R visitVariable(VariableTree node, P p) { 149 R r = scan(node.getModifiers(), p); 150 r = scanAndReduce(node.getType(), p, r); 151 r = scanAndReduce(node.getInitializer(), p, r); 152 return r; 153 } 154 155 public R visitEmptyStatement(EmptyStatementTree node, P p) { 156 return null; 157 } 158 159 public R visitBlock(BlockTree node, P p) { 160 return scan(node.getStatements(), p); 161 } 162 163 public R visitDoWhileLoop(DoWhileLoopTree node, P p) { 164 R r = scan(node.getStatement(), p); 165 r = scanAndReduce(node.getCondition(), p, r); 166 return r; 167 } 168 169 public R visitWhileLoop(WhileLoopTree node, P p) { 170 R r = scan(node.getCondition(), p); 171 r = scanAndReduce(node.getStatement(), p, r); 172 return r; 173 } 174 175 public R visitForLoop(ForLoopTree node, P p) { 176 R r = scan(node.getInitializer(), p); 177 r = scanAndReduce(node.getCondition(), p, r); 178 r = scanAndReduce(node.getUpdate(), p, r); 179 r = scanAndReduce(node.getStatement(), p, r); 180 return r; 181 } 182 183 public R visitEnhancedForLoop(EnhancedForLoopTree node, P p) { 184 R r = scan(node.getVariable(), p); 185 r = scanAndReduce(node.getExpression(), p, r); 186 r = scanAndReduce(node.getStatement(), p, r); 187 return r; 188 } 189 190 public R visitLabeledStatement(LabeledStatementTree node, P p) { 191 return scan(node.getStatement(), p); 192 } 193 194 public R visitSwitch(SwitchTree node, P p) { 195 R r = scan(node.getExpression(), p); 196 r = scanAndReduce(node.getCases(), p, r); 197 return r; 198 } 199 200 public R visitCase(CaseTree node, P p) { 201 R r = scan(node.getExpression(), p); 202 r = scanAndReduce(node.getStatements(), p, r); 203 return r; 204 } 205 206 public R visitSynchronized(SynchronizedTree node, P p) { 207 R r = scan(node.getExpression(), p); 208 r = scanAndReduce(node.getBlock(), p, r); 209 return r; 210 } 211 212 public R visitTry(TryTree node, P p) { 213 R r = scan(node.getResources(), p); 214 r = scanAndReduce(node.getBlock(), p, r); 215 r = scanAndReduce(node.getCatches(), p, r); 216 r = scanAndReduce(node.getFinallyBlock(), p, r); 217 return r; 218 } 219 220 public R visitCatch(CatchTree node, P p) { 221 R r = scan(node.getParameter(), p); 222 r = scanAndReduce(node.getBlock(), p, r); 223 return r; 224 } 225 226 public R visitConditionalExpression(ConditionalExpressionTree node, P p) { 227 R r = scan(node.getCondition(), p); 228 r = scanAndReduce(node.getTrueExpression(), p, r); 229 r = scanAndReduce(node.getFalseExpression(), p, r); 230 return r; 231 } 232 233 public R visitIf(IfTree node, P p) { 234 R r = scan(node.getCondition(), p); 235 r = scanAndReduce(node.getThenStatement(), p, r); 236 r = scanAndReduce(node.getElseStatement(), p, r); 237 return r; 238 } 239 240 public R visitExpressionStatement(ExpressionStatementTree node, P p) { 241 return scan(node.getExpression(), p); 242 } 243 244 public R visitBreak(BreakTree node, P p) { 245 return null; 246 } 247 248 public R visitContinue(ContinueTree node, P p) { 249 return null; 250 } 251 252 public R visitReturn(ReturnTree node, P p) { 253 return scan(node.getExpression(), p); 254 } 255 256 public R visitThrow(ThrowTree node, P p) { 257 return scan(node.getExpression(), p); 258 } 259 260 public R visitAssert(AssertTree node, P p) { 261 R r = scan(node.getCondition(), p); 262 r = scanAndReduce(node.getDetail(), p, r); 263 return r; 264 } 265 266 public R visitMethodInvocation(MethodInvocationTree node, P p) { 267 R r = scan(node.getTypeArguments(), p); 268 r = scanAndReduce(node.getMethodSelect(), p, r); 269 r = scanAndReduce(node.getArguments(), p, r); 270 return r; 271 } 272 273 public R visitNewClass(NewClassTree node, P p) { 274 R r = scan(node.getEnclosingExpression(), p); 275 r = scanAndReduce(node.getIdentifier(), p, r); 276 r = scanAndReduce(node.getTypeArguments(), p, r); 277 r = scanAndReduce(node.getArguments(), p, r); 278 r = scanAndReduce(node.getClassBody(), p, r); 279 return r; 280 } 281 282 public R visitNewArray(NewArrayTree node, P p) { 283 R r = scan(node.getType(), p); 284 r = scanAndReduce(node.getDimensions(), p, r); 285 r = scanAndReduce(node.getInitializers(), p, r); 286 return r; 287 } 288 289 public R visitLambdaExpression(LambdaExpressionTree node, P p) { 290 R r = scan(node.getParameters(), p); 291 r = scanAndReduce(node.getBody(), p, r); 292 return r; 293 } 294 295 public R visitParenthesized(ParenthesizedTree node, P p) { 296 return scan(node.getExpression(), p); 297 } 298 299 public R visitAssignment(AssignmentTree node, P p) { 300 R r = scan(node.getVariable(), p); 301 r = scanAndReduce(node.getExpression(), p, r); 302 return r; 303 } 304 305 public R visitCompoundAssignment(CompoundAssignmentTree node, P p) { 306 R r = scan(node.getVariable(), p); 307 r = scanAndReduce(node.getExpression(), p, r); 308 return r; 309 } 310 311 public R visitUnary(UnaryTree node, P p) { 312 return scan(node.getExpression(), p); 313 } 314 315 public R visitBinary(BinaryTree node, P p) { 316 R r = scan(node.getLeftOperand(), p); 317 r = scanAndReduce(node.getRightOperand(), p, r); 318 return r; 319 } 320 321 public R visitTypeCast(TypeCastTree node, P p) { 322 R r = scan(node.getType(), p); 323 r = scanAndReduce(node.getExpression(), p, r); 324 return r; 325 } 326 327 public R visitInstanceOf(InstanceOfTree node, P p) { 328 R r = scan(node.getExpression(), p); 329 r = scanAndReduce(node.getType(), p, r); 330 return r; 331 } 332 333 public R visitArrayAccess(ArrayAccessTree node, P p) { 334 R r = scan(node.getExpression(), p); 335 r = scanAndReduce(node.getIndex(), p, r); 336 return r; 337 } 338 339 public R visitMemberSelect(MemberSelectTree node, P p) { 340 return scan(node.getExpression(), p); 341 } 342 343 public R visitMemberReference(MemberReferenceTree node, P p) { 344 R r = scan(node.getQualifierExpression(), p); 345 r = scanAndReduce(node.getTypeArguments(), p, r); 346 return r; 347 } 348 349 public R visitIdentifier(IdentifierTree node, P p) { 350 return null; 351 } 352 353 public R visitLiteral(LiteralTree node, P p) { 354 return null; 355 } 356 357 public R visitPrimitiveType(PrimitiveTypeTree node, P p) { 358 return null; 359 } 360 361 public R visitArrayType(ArrayTypeTree node, P p) { 362 return scan(node.getType(), p); 363 } 364 365 public R visitParameterizedType(ParameterizedTypeTree node, P p) { 366 R r = scan(node.getType(), p); 367 r = scanAndReduce(node.getTypeArguments(), p, r); 368 return r; 369 } 370 371 public R visitUnionType(UnionTypeTree node, P p) { 372 return scan(node.getTypeAlternatives(), p); 373 } 374 375 public R visitIntersectionType(IntersectionTypeTree node, P p) { 376 return scan(node.getBounds(), p); 377 } 378 379 public R visitTypeParameter(TypeParameterTree node, P p) { 380 R r = scan(node.getAnnotations(), p); 381 r = scanAndReduce(node.getBounds(), p, r); 382 return r; 383 } 384 385 public R visitWildcard(WildcardTree node, P p) { 386 return scan(node.getBound(), p); 387 } 388 389 public R visitModifiers(ModifiersTree node, P p) { 390 return scan(node.getAnnotations(), p); 391 } 392 393 public R visitAnnotation(AnnotationTree node, P p) { 394 R r = scan(node.getAnnotationType(), p); 395 r = scanAndReduce(node.getArguments(), p, r); 396 return r; 397 } 398 399 public R visitAnnotatedType(AnnotatedTypeTree node, P p) { 400 R r = scan(node.getAnnotations(), p); 401 r = scanAndReduce(node.getUnderlyingType(), p, r); 402 return r; 403 } 404 405 public R visitOther(Tree node, P p) { 406 return null; 407 } 408 409 public R visitErroneous(ErroneousTree node, P p) { 410 return null; 411 } 412 }