1package annotator.find; 2 3import java.util.ArrayList; 4import java.util.List; 5 6import javax.lang.model.element.Modifier; 7import javax.lang.model.type.TypeKind; 8 9import annotations.io.ASTPath; 10import annotator.Main; 11 12import com.sun.source.tree.AnnotatedTypeTree; 13import com.sun.source.tree.AnnotationTree; 14import com.sun.source.tree.ArrayAccessTree; 15import com.sun.source.tree.ArrayTypeTree; 16import com.sun.source.tree.AssertTree; 17import com.sun.source.tree.AssignmentTree; 18import com.sun.source.tree.BinaryTree; 19import com.sun.source.tree.BlockTree; 20import com.sun.source.tree.CaseTree; 21import com.sun.source.tree.CatchTree; 22import com.sun.source.tree.ClassTree; 23import com.sun.source.tree.CompoundAssignmentTree; 24import com.sun.source.tree.ConditionalExpressionTree; 25import com.sun.source.tree.DoWhileLoopTree; 26import com.sun.source.tree.EnhancedForLoopTree; 27import com.sun.source.tree.ExpressionStatementTree; 28import com.sun.source.tree.ExpressionTree; 29import com.sun.source.tree.ForLoopTree; 30import com.sun.source.tree.IdentifierTree; 31import com.sun.source.tree.IfTree; 32import com.sun.source.tree.InstanceOfTree; 33import com.sun.source.tree.LabeledStatementTree; 34import com.sun.source.tree.LambdaExpressionTree; 35import com.sun.source.tree.MemberReferenceTree; 36import com.sun.source.tree.MemberSelectTree; 37import com.sun.source.tree.MethodInvocationTree; 38import com.sun.source.tree.MethodTree; 39import com.sun.source.tree.NewArrayTree; 40import com.sun.source.tree.NewClassTree; 41import com.sun.source.tree.ParameterizedTypeTree; 42import com.sun.source.tree.ParenthesizedTree; 43import com.sun.source.tree.ReturnTree; 44import com.sun.source.tree.StatementTree; 45import com.sun.source.tree.SwitchTree; 46import com.sun.source.tree.SynchronizedTree; 47import com.sun.source.tree.ThrowTree; 48import com.sun.source.tree.Tree; 49import com.sun.source.tree.TryTree; 50import com.sun.source.tree.TypeCastTree; 51import com.sun.source.tree.TypeParameterTree; 52import com.sun.source.tree.UnaryTree; 53import com.sun.source.tree.UnionTypeTree; 54import com.sun.source.tree.VariableTree; 55import com.sun.source.tree.WhileLoopTree; 56import com.sun.source.tree.WildcardTree; 57import com.sun.source.tree.Tree.Kind; 58import com.sun.source.util.SimpleTreeVisitor; 59import com.sun.source.util.TreePath; 60import com.sun.tools.javac.code.Flags; 61import com.sun.tools.javac.code.Type; 62import com.sun.tools.javac.tree.JCTree; 63 64/** 65 * A criterion to determine if a node matches a path through the AST. 66 */ 67public class ASTPathCriterion implements Criterion { 68 69 public static boolean debug = Main.debug; 70 71 /** 72 * The path through the AST to match. 73 */ 74 ASTPath astPath; 75 76 /** 77 * Constructs a new ASTPathCriterion to match the given AST path. 78 * <p> 79 * This assumes that the astPath is valid. Specifically, that all of its 80 * arguments have been previously validated. 81 * 82 * @param astPath 83 * the AST path to match 84 */ 85 public ASTPathCriterion(ASTPath astPath) { 86 this.astPath = astPath; 87 } 88 89 /** {@inheritDoc} */ 90 @Override 91 public boolean isSatisfiedBy(TreePath path, Tree leaf) { 92 assert path == null || path.getLeaf() == leaf; 93 return isSatisfiedBy(path); 94 } 95 96 /** {@inheritDoc} */ 97 @Override 98 public boolean isSatisfiedBy(TreePath path) { 99 if (path == null) { 100 return false; 101 } 102 103 // actualPath stores the path through the source code AST to this 104 // location (specified by the "path" parameter to this method). It is 105 // computed by traversing from this location up the source code AST 106 // until it reaches a method node (this gets only the part of the path 107 // within a method) or class node (this gets only the part of the path 108 // within a field). 109 List<Tree> actualPath = new ArrayList<Tree>(); 110 Tree leaf = path.getLeaf(); 111 Tree.Kind kind = leaf.getKind(); 112 while (kind != Tree.Kind.METHOD && !ASTPath.isClassEquiv(kind)) { 113 actualPath.add(0, leaf); 114 path = path.getParentPath(); 115 if (path == null) { break; } 116 leaf = path.getLeaf(); 117 kind = leaf.getKind(); 118 } 119 120 // If astPath starts with Method.* or Class.*, include the 121 // MethodTree or ClassTree on actualPath. 122 if (path != null && !astPath.isEmpty()) { 123 Tree.Kind entryKind = astPath.get(0).getTreeKind(); 124 if (entryKind == Tree.Kind.METHOD 125 && kind == Tree.Kind.METHOD 126 || entryKind == Tree.Kind.CLASS 127 && ASTPath.isClassEquiv(kind)) { 128 actualPath.add(0, leaf); 129 } 130 } 131 132 if (debug) { 133 System.out.println("ASTPathCriterion.isSatisfiedBy"); 134 System.out.println(" " + astPath); 135 for (Tree t : actualPath) { 136 System.out.println(" " + t.getKind() + ": " 137 + t.toString().replace('\n', ' ')); 138 } 139 } 140 141 int astPathLen = astPath.size(); 142 int actualPathLen = actualPath.size(); 143 if (astPathLen == 0 || actualPathLen == 0) { return false; } 144 // if (actualPathLen != astPathLen + (isOnNewArrayType ? 0 : 1)) { 145 // return false; 146 // } 147 148 Tree next = null; 149 int i = 0; 150 while (true) { 151 ASTPath.ASTEntry astNode = astPath.get(i); 152 Tree actualNode = actualPath.get(i); 153 if (!kindsMatch(astNode.getTreeKind(), actualNode.getKind())) { 154 return isBoundableWildcard(actualPath, i); 155 } 156 157 if (debug) { 158 System.out.println("astNode: " + astNode); 159 System.out.println("actualNode: " + actualNode.getKind()); 160 } 161 162 // Based on the child selector and (optional) argument in "astNode", 163 // "next" will get set to the next source node below "actualNode". 164 // Then "next" will be compared with the node following "astNode" 165 // in "actualPath". If it's not a match, this is not the correct 166 // location. If it is a match, keep going. 167 next = getNext(actualNode, astPath, i); 168 if (next == null) { 169 return checkNull(actualPath, i); 170 } 171 if (!(next instanceof JCTree)) { 172 // converted from array type, not in source AST... 173 if (actualPathLen == i+1) { 174 // need to extend actualPath with "artificial" node 175 actualPath.add(next); 176 ++actualPathLen; 177 } 178 } 179 if (debug) { 180 System.out.println("next: " + next); 181 } 182 183 // if (++i >= astPathLen || i >= actualPathLen) { break; } 184 if (++i >= astPathLen) { break; } 185 if (i >= actualPathLen) { 186 return checkNull(actualPath, i-1); 187 } 188 if (!matchNext(next, actualPath.get(i))) { 189 if (debug) { 190 System.out.println("no next match"); 191 } 192 return false; 193 } 194 } 195 196 if (i < actualPathLen && matchNext(next, actualPath.get(i)) 197 || i <= actualPathLen 198 && next.getKind() == Tree.Kind.NEW_ARRAY) { 199 return true; 200 } 201 202 if (debug) { 203 System.out.println("no next match"); 204 } 205 return false; 206 } 207 208 private boolean matchNext(Tree next, Tree node) { 209 boolean b1 = next instanceof JCTree; 210 boolean b2 = node instanceof JCTree; 211 if (b1 && !b2) { 212 next = Insertions.TypeTree.fromJCTree((JCTree) next); 213 } else if (b2 && !b1) { 214 node = Insertions.TypeTree.fromJCTree((JCTree) node); 215 } 216 217 try { 218 return next.accept(new SimpleTreeVisitor<Boolean, Tree>() { 219 @Override 220 public Boolean 221 defaultAction(Tree t1, Tree t2) { 222 return t1 == t2; 223 } 224 225 @Override 226 public Boolean 227 visitIdentifier(IdentifierTree v, Tree t) { 228 return v == t; 229 // IdentifierTree i2 = (IdentifierTree) t; 230 // return i1.getName().toString() 231 // .equals(i2.getName().toString()); 232 } 233 234 @Override 235 public Boolean 236 visitAnnotatedType(AnnotatedTypeTree a1, Tree t) { 237 AnnotatedTypeTree a2 = (AnnotatedTypeTree) t; 238 return matchNext(a1.getUnderlyingType(), 239 a2.getUnderlyingType()); 240 } 241 242 // @Override 243 // public Boolean 244 // visitArrayType(ArrayTypeTree b1, Tree t) { 245 // ArrayTypeTree b2 = (ArrayTypeTree) t; 246 // return matchNext(b1.getType(), b2.getType()); 247 // } 248 249 @Override 250 public Boolean 251 visitMemberSelect(MemberSelectTree c1, Tree t) { 252 MemberSelectTree c2 = (MemberSelectTree) t; 253 return c1.getIdentifier().toString() 254 .equals(c2.getIdentifier().toString()) 255 && matchNext(c1.getExpression(), 256 c2.getExpression()); 257 } 258 259 @Override 260 public Boolean 261 visitWildcard(WildcardTree d1, Tree t) { 262 return d1 == (WildcardTree) t; 263 // WildcardTree d2 = (WildcardTree) t; 264 // Tree bound2 = d2.getBound(); 265 // Tree bound1 = d1.getBound(); 266 // return bound1 == bound2 || matchNext(bound1, bound2); 267 } 268 269 @Override 270 public Boolean 271 visitParameterizedType(ParameterizedTypeTree e1, Tree t) { 272 ParameterizedTypeTree e2 = (ParameterizedTypeTree) t; 273 List<? extends Tree> l2 = e2.getTypeArguments(); 274 List<? extends Tree> l1 = e1.getTypeArguments(); 275 if (l1.size() == l2.size()) { 276 int i = 0; 277 for (Tree t1 : l1) { 278 Tree t2 = l2.get(i++); 279 if (!matchNext(t1, t2)) { return false; } 280 } 281 return matchNext(e1.getType(), e2.getType()); 282 } 283 return false; 284 } 285 }, node); 286 } catch (RuntimeException ex) { 287 return false; 288 } 289 } 290 291 private Tree getNext(Tree actualNode, ASTPath astPath, int ix) { 292 try { 293 ASTPath.ASTEntry astNode = astPath.get(ix); 294 switch (actualNode.getKind()) { 295 case ANNOTATED_TYPE: { 296 AnnotatedTypeTree annotatedType = 297 (AnnotatedTypeTree) actualNode; 298 if (astNode.childSelectorIs(ASTPath.ANNOTATION)) { 299 int arg = astNode.getArgument(); 300 List<? extends AnnotationTree> annos = 301 annotatedType.getAnnotations(); 302 if (arg >= annos.size()) { 303 return null; 304 } 305 return annos.get(arg); 306 } else { 307 return annotatedType.getUnderlyingType(); 308 } 309 } 310 case ARRAY_ACCESS: { 311 ArrayAccessTree arrayAccess = (ArrayAccessTree) actualNode; 312 if (astNode.childSelectorIs(ASTPath.EXPRESSION)) { 313 return arrayAccess.getExpression(); 314 } else { 315 return arrayAccess.getIndex(); 316 } 317 } 318 case ARRAY_TYPE: { 319 ArrayTypeTree arrayType = (ArrayTypeTree) actualNode; 320 return arrayType.getType(); 321 } 322 case ASSERT: { 323 AssertTree azzert = (AssertTree) actualNode; 324 if (astNode.childSelectorIs(ASTPath.CONDITION)) { 325 return azzert.getCondition(); 326 } else { 327 return azzert.getDetail(); 328 } 329 } 330 case ASSIGNMENT: { 331 AssignmentTree assignment = (AssignmentTree) actualNode; 332 if (astNode.childSelectorIs(ASTPath.VARIABLE)) { 333 return assignment.getVariable(); 334 } else { 335 return assignment.getExpression(); 336 } 337 } 338 case BLOCK: { 339 BlockTree block = (BlockTree) actualNode; 340 int arg = astNode.getArgument(); 341 List<? extends StatementTree> statements = block.getStatements(); 342 if (arg >= block.getStatements().size()) { 343 return null; 344 } 345 return statements.get(arg); 346 } 347 case CASE: { 348 CaseTree caze = (CaseTree) actualNode; 349 if (astNode.childSelectorIs(ASTPath.EXPRESSION)) { 350 return caze.getExpression(); 351 } else { 352 int arg = astNode.getArgument(); 353 List<? extends StatementTree> statements = caze.getStatements(); 354 if (arg >= statements.size()) { 355 return null; 356 } 357 return statements.get(arg); 358 } 359 } 360 case CATCH: { 361 CatchTree cach = (CatchTree) actualNode; 362 if (astNode.childSelectorIs(ASTPath.PARAMETER)) { 363 return cach.getParameter(); 364 } else { 365 return cach.getBlock(); 366 } 367 } 368 case ANNOTATION: 369 case CLASS: 370 case ENUM: 371 case INTERFACE: { 372 ClassTree clazz = (ClassTree) actualNode; 373 int arg = astNode.getArgument(); 374 if (astNode.childSelectorIs(ASTPath.TYPE_PARAMETER)) { 375 return clazz.getTypeParameters().get(arg); 376 } else if (astNode.childSelectorIs(ASTPath.INITIALIZER)) { 377 int i = 0; 378 for (Tree member : clazz.getMembers()) { 379 if (member.getKind() == Tree.Kind.BLOCK && arg == i++) { 380 return member; 381 } 382 } 383 return null; 384 } else if (astNode.childSelectorIs(ASTPath.BOUND)) { 385 return arg < 0 ? clazz.getExtendsClause() 386 : clazz.getImplementsClause().get(arg); 387 } else { 388 return null; 389 } 390 } 391 case CONDITIONAL_EXPRESSION: { 392 ConditionalExpressionTree conditionalExpression = (ConditionalExpressionTree) actualNode; 393 if (astNode.childSelectorIs(ASTPath.CONDITION)) { 394 return conditionalExpression.getCondition(); 395 } else if (astNode.childSelectorIs(ASTPath.TRUE_EXPRESSION)) { 396 return conditionalExpression.getTrueExpression(); 397 } else { 398 return conditionalExpression.getFalseExpression(); 399 } 400 } 401 case DO_WHILE_LOOP: { 402 DoWhileLoopTree doWhileLoop = (DoWhileLoopTree) actualNode; 403 if (astNode.childSelectorIs(ASTPath.CONDITION)) { 404 return doWhileLoop.getCondition(); 405 } else { 406 return doWhileLoop.getStatement(); 407 } 408 } 409 case ENHANCED_FOR_LOOP: { 410 EnhancedForLoopTree enhancedForLoop = (EnhancedForLoopTree) actualNode; 411 if (astNode.childSelectorIs(ASTPath.VARIABLE)) { 412 return enhancedForLoop.getVariable(); 413 } else if (astNode.childSelectorIs(ASTPath.EXPRESSION)) { 414 return enhancedForLoop.getExpression(); 415 } else { 416 return enhancedForLoop.getStatement(); 417 } 418 } 419 case EXPRESSION_STATEMENT: { 420 ExpressionStatementTree expressionStatement = (ExpressionStatementTree) actualNode; 421 return expressionStatement.getExpression(); 422 } 423 case FOR_LOOP: { 424 ForLoopTree forLoop = (ForLoopTree) actualNode; 425 if (astNode.childSelectorIs(ASTPath.INITIALIZER)) { 426 int arg = astNode.getArgument(); 427 List<? extends StatementTree> inits = forLoop.getInitializer(); 428 if (arg >= inits.size()) { 429 return null; 430 } 431 return inits.get(arg); 432 } else if (astNode.childSelectorIs(ASTPath.CONDITION)) { 433 return forLoop.getCondition(); 434 } else if (astNode.childSelectorIs(ASTPath.UPDATE)) { 435 int arg = astNode.getArgument(); 436 List<? extends ExpressionStatementTree> updates = forLoop.getUpdate(); 437 if (arg >= updates.size()) { 438 return null; 439 } 440 return updates.get(arg); 441 } else { 442 return forLoop.getStatement(); 443 } 444 } 445 case IF: { 446 IfTree iff = (IfTree) actualNode; 447 if (astNode.childSelectorIs(ASTPath.CONDITION)) { 448 return iff.getCondition(); 449 } else if (astNode.childSelectorIs(ASTPath.THEN_STATEMENT)) { 450 return iff.getThenStatement(); 451 } else { 452 return iff.getElseStatement(); 453 } 454 } 455 case INSTANCE_OF: { 456 InstanceOfTree instanceOf = (InstanceOfTree) actualNode; 457 if (astNode.childSelectorIs(ASTPath.EXPRESSION)) { 458 return instanceOf.getExpression(); 459 } else { 460 return instanceOf.getType(); 461 } 462 } 463 case LABELED_STATEMENT: { 464 LabeledStatementTree labeledStatement = (LabeledStatementTree) actualNode; 465 return labeledStatement.getStatement(); 466 } 467 case LAMBDA_EXPRESSION: { 468 LambdaExpressionTree lambdaExpression = (LambdaExpressionTree) actualNode; 469 if (astNode.childSelectorIs(ASTPath.PARAMETER)) { 470 int arg = astNode.getArgument(); 471 List<? extends VariableTree> params = lambdaExpression.getParameters(); 472 if (arg >= params.size()) { 473 return null; 474 } 475 return params.get(arg); 476 } else { 477 return lambdaExpression.getBody(); 478 } 479 } 480 case MEMBER_REFERENCE: { 481 MemberReferenceTree memberReference = (MemberReferenceTree) actualNode; 482 if (astNode.childSelectorIs(ASTPath.QUALIFIER_EXPRESSION)) { 483 return memberReference.getQualifierExpression(); 484 } else { 485 int arg = astNode.getArgument(); 486 List<? extends ExpressionTree> typeArgs = memberReference.getTypeArguments(); 487 if (arg >= typeArgs.size()) { 488 return null; 489 } 490 return typeArgs.get(arg); 491 } 492 } 493 case MEMBER_SELECT: { 494 MemberSelectTree memberSelect = (MemberSelectTree) actualNode; 495 return memberSelect.getExpression(); 496 } 497 case METHOD: { 498 MethodTree method = (MethodTree) actualNode; 499 if (astNode.childSelectorIs(ASTPath.TYPE)) { 500 return method.getReturnType(); 501 } else if (astNode.childSelectorIs(ASTPath.PARAMETER)) { 502 int arg = astNode.getArgument(); 503 List<? extends VariableTree> params = 504 method.getParameters(); 505 return arg < 0 ? method.getReceiverParameter() 506 : arg < params.size() ? params.get(arg) : null; 507 } else if (astNode.childSelectorIs(ASTPath.TYPE_PARAMETER)) { 508 int arg = astNode.getArgument(); 509 return method.getTypeParameters().get(arg); 510 } else { // BODY 511 return method.getBody(); 512 } 513 } 514 case METHOD_INVOCATION: { 515 MethodInvocationTree methodInvocation = (MethodInvocationTree) actualNode; 516 if (astNode.childSelectorIs(ASTPath.TYPE_ARGUMENT)) { 517 int arg = astNode.getArgument(); 518 List<? extends Tree> typeArgs = methodInvocation.getTypeArguments(); 519 if (arg >= typeArgs.size()) { 520 return null; 521 } 522 return typeArgs.get(arg); 523 } else if (astNode.childSelectorIs(ASTPath.METHOD_SELECT)) { 524 return methodInvocation.getMethodSelect(); 525 } else { 526 int arg = astNode.getArgument(); 527 List<? extends ExpressionTree> args = methodInvocation.getArguments(); 528 if (arg >= args.size()) { 529 return null; 530 } 531 return args.get(arg); 532 } 533 } 534 case NEW_ARRAY: { 535 NewArrayTree newArray = (NewArrayTree) actualNode; 536 if (astNode.childSelectorIs(ASTPath.TYPE)) { 537 Type type = ((JCTree.JCNewArray) newArray).type; 538 Tree typeTree = Insertions.TypeTree.fromType(type); 539 int arg = astNode.getArgument(); 540 if (arg == 0 && astPath.size() == ix+1) { 541 return newArray; 542 // if (astPath.size() != ix+1) { return null; } 543 // return typeTree; 544 // return ((ArrayTypeTree) typeTree).getType(); 545 // return newArray; 546 } 547 typeTree = ((NewArrayTree) typeTree).getType(); 548 while (--arg > 0) { 549 if (typeTree.getKind() != Tree.Kind.ARRAY_TYPE) { 550 return null; 551 } 552 typeTree = ((ArrayTypeTree) typeTree).getType(); 553 } 554 return typeTree; 555 } else if (astNode.childSelectorIs(ASTPath.DIMENSION)) { 556 int arg = astNode.getArgument(); 557 List<? extends ExpressionTree> dims = newArray.getDimensions(); 558 return arg < dims.size() ? dims.get(arg) : null; 559 } else { 560 int arg = astNode.getArgument(); 561 List<? extends ExpressionTree> inits = 562 newArray.getInitializers(); 563 return arg < inits.size() ? inits.get(arg) : null; 564 } 565 } 566 case NEW_CLASS: { 567 NewClassTree newClass = (NewClassTree) actualNode; 568 if (astNode.childSelectorIs(ASTPath.ENCLOSING_EXPRESSION)) { 569 return newClass.getEnclosingExpression(); 570 } else if (astNode.childSelectorIs(ASTPath.TYPE_ARGUMENT)) { 571 int arg = astNode.getArgument(); 572 List<? extends Tree> typeArgs = newClass.getTypeArguments(); 573 if (arg >= typeArgs.size()) { 574 return null; 575 } 576 return typeArgs.get(arg); 577 } else if (astNode.childSelectorIs(ASTPath.IDENTIFIER)) { 578 return newClass.getIdentifier(); 579 } else if (astNode.childSelectorIs(ASTPath.ARGUMENT)) { 580 int arg = astNode.getArgument(); 581 List<? extends ExpressionTree> args = newClass.getArguments(); 582 if (arg >= args.size()) { 583 return null; 584 } 585 return args.get(arg); 586 } else { 587 return newClass.getClassBody(); // For anonymous classes 588 } 589 } 590 case PARAMETERIZED_TYPE: { 591 ParameterizedTypeTree parameterizedType = (ParameterizedTypeTree) actualNode; 592 if (astNode.childSelectorIs(ASTPath.TYPE)) { 593 return parameterizedType.getType(); 594 } else { 595 int arg = astNode.getArgument(); 596 List<? extends Tree> typeArgs = parameterizedType.getTypeArguments(); 597 if (arg >= typeArgs.size()) { 598 return null; 599 } 600 return typeArgs.get(arg); 601 } 602 } 603 case PARENTHESIZED: { 604 ParenthesizedTree parenthesized = (ParenthesizedTree) actualNode; 605 return parenthesized.getExpression(); 606 } 607 case RETURN: { 608 ReturnTree returnn = (ReturnTree) actualNode; 609 return returnn.getExpression(); 610 } 611 case SWITCH: { 612 SwitchTree zwitch = (SwitchTree) actualNode; 613 if (astNode.childSelectorIs(ASTPath.EXPRESSION)) { 614 return zwitch.getExpression(); 615 } else { 616 int arg = astNode.getArgument(); 617 List<? extends CaseTree> cases = zwitch.getCases(); 618 if (arg >= cases.size()) { 619 return null; 620 } 621 return cases.get(arg); 622 } 623 } 624 case SYNCHRONIZED: { 625 SynchronizedTree synchronizzed = (SynchronizedTree) actualNode; 626 if (astNode.childSelectorIs(ASTPath.EXPRESSION)) { 627 return synchronizzed.getExpression(); 628 } else { 629 return synchronizzed.getBlock(); 630 } 631 } 632 case THROW: { 633 ThrowTree throww = (ThrowTree) actualNode; 634 return throww.getExpression(); 635 } 636 case TRY: { 637 TryTree tryy = (TryTree) actualNode; 638 if (astNode.childSelectorIs(ASTPath.BLOCK)) { 639 return tryy.getBlock(); 640 } else if (astNode.childSelectorIs(ASTPath.CATCH)) { 641 int arg = astNode.getArgument(); 642 List<? extends CatchTree> catches = tryy.getCatches(); 643 if (arg >= catches.size()) { 644 return null; 645 } 646 return catches.get(arg); 647 } else if (astNode.childSelectorIs(ASTPath.FINALLY_BLOCK)) { 648 return tryy.getFinallyBlock(); 649 } else { 650 int arg = astNode.getArgument(); 651 List<? extends Tree> resources = tryy.getResources(); 652 if (arg >= resources.size()) { 653 return null; 654 } 655 return resources.get(arg); 656 } 657 } 658 case TYPE_CAST: { 659 TypeCastTree typeCast = (TypeCastTree) actualNode; 660 if (astNode.childSelectorIs(ASTPath.TYPE)) { 661 return typeCast.getType(); 662 } else { 663 return typeCast.getExpression(); 664 } 665 } 666 case TYPE_PARAMETER: { 667 TypeParameterTree typeParam = (TypeParameterTree) actualNode; 668 List<? extends Tree> bounds = typeParam.getBounds(); 669 int arg = astNode.getArgument(); 670 return bounds.get(arg); 671 } 672 case UNION_TYPE: { 673 UnionTypeTree unionType = (UnionTypeTree) actualNode; 674 int arg = astNode.getArgument(); 675 List<? extends Tree> typeAlts = unionType.getTypeAlternatives(); 676 if (arg >= typeAlts.size()) { 677 return null; 678 } 679 return typeAlts.get(arg); 680 } 681 case VARIABLE: { 682 // A VariableTree can have modifiers, but we only look at 683 // the initializer and type because modifiers can't be 684 // annotated. Any annotations on the LHS must be on the type. 685 VariableTree var = (VariableTree) actualNode; 686 if (astNode.childSelectorIs(ASTPath.INITIALIZER)) { 687 return var.getInitializer(); 688 } else if (astNode.childSelectorIs(ASTPath.TYPE)) { 689 return var.getType(); 690 } else { 691 return null; 692 } 693 } 694 case WHILE_LOOP: { 695 WhileLoopTree whileLoop = (WhileLoopTree) actualNode; 696 if (astNode.childSelectorIs(ASTPath.CONDITION)) { 697 return whileLoop.getCondition(); 698 } else { 699 return whileLoop.getStatement(); 700 } 701 } 702 default: { 703 if (ASTPath.isBinaryOperator(actualNode.getKind())) { 704 BinaryTree binary = (BinaryTree) actualNode; 705 if (astNode.childSelectorIs(ASTPath.LEFT_OPERAND)) { 706 return binary.getLeftOperand(); 707 } else { 708 return binary.getRightOperand(); 709 } 710 } else if (ASTPath.isCompoundAssignment(actualNode.getKind())) { 711 CompoundAssignmentTree compoundAssignment = 712 (CompoundAssignmentTree) actualNode; 713 if (astNode.childSelectorIs(ASTPath.VARIABLE)) { 714 return compoundAssignment.getVariable(); 715 } else { 716 return compoundAssignment.getExpression(); 717 } 718 } else if (ASTPath.isUnaryOperator(actualNode.getKind())) { 719 UnaryTree unary = (UnaryTree) actualNode; 720 return unary.getExpression(); 721 } else if (isWildcard(actualNode.getKind())) { 722 WildcardTree wildcard = (WildcardTree) actualNode; 723 return wildcard.getBound(); 724 } else { 725 throw new IllegalArgumentException("Illegal kind: " 726 + actualNode.getKind()); 727 } 728 } 729 } 730 } catch (RuntimeException ex) { return null; } 731 } 732 733 private boolean checkNull(List<Tree> path, int ix) { 734 Tree node = path.get(path.size()-1); 735 int last = astPath.size() - 1; 736 ASTPath.ASTEntry entry = astPath.get(ix); 737 Tree.Kind kind = entry.getTreeKind(); 738 739 switch (kind) { 740 // case ANNOTATION: 741 // case INTERFACE: 742 case CLASS: // "extends" clause? 743 return ASTPath.isClassEquiv(kind) 744 && ix == last && entry.getArgument() == -1 745 && entry.childSelectorIs(ASTPath.BOUND); 746 case TYPE_PARAMETER: 747 return node.getKind() == Tree.Kind.TYPE_PARAMETER 748 && ix == last && entry.getArgument() == 0 749 && entry.childSelectorIs(ASTPath.BOUND); 750 case METHOD: // nullary constructor? receiver? 751 if (node.getKind() != Tree.Kind.METHOD) { return false; } 752 MethodTree method = (MethodTree) node; 753 List<? extends VariableTree> params = method.getParameters(); 754 if ("<init>".equals(method.getName().toString())) { 755 if (ix == last) { return true; } 756 ASTPath.ASTEntry next = astPath.get(++ix); 757 String selector = next.getChildSelector(); 758 Tree typeTree = 759 ASTPath.TYPE_PARAMETER.equals(selector) 760 ? method.getTypeParameters().get(next.getArgument()) 761 : ASTPath.PARAMETER.equals(selector) 762 ? params.get(next.getArgument()).getType() 763 : null; 764 return typeTree != null && checkTypePath(ix, typeTree); 765 } else if (entry.childSelectorIs(ASTPath.PARAMETER) 766 && entry.getArgument() == -1) { 767 if (ix == last) { return true; } 768 VariableTree rcvrParam = method.getReceiverParameter(); 769 if (rcvrParam == null) { // TODO 770 // ClassTree clazz = methodReceiverType(path); 771 // return checkReceiverType(ix, 772 // ((JCTree.JCClassDecl) clazz).type); 773 } else { 774 return checkTypePath(ix+1, rcvrParam.getType()); 775 } 776 } 777 return false; 778 case NEW_ARRAY: 779 if (node.getKind() != Tree.Kind.NEW_ARRAY) { return false; } 780 NewArrayTree newArray = (NewArrayTree) node; 781 int arg = entry.getArgument(); 782 if (entry.childSelectorIs(ASTPath.TYPE)) { 783 if (ix == last) { return true; } 784 // Tree t = newArray.getType(); 785 // int depth = 1; 786 // while (t.getKind() == Tree.Kind.ARRAY_TYPE) { 787 // t = ((ArrayTypeTree) t).getType(); 788 // ++depth; 789 // } 790 return arg == arrayDepth(newArray); 791 } else { 792 List<? extends ExpressionTree> typeTrees = 793 entry.childSelectorIs(ASTPath.DIMENSION) 794 ? newArray.getDimensions() 795 : entry.childSelectorIs(ASTPath.INITIALIZER) 796 ? newArray.getInitializers() 797 : null; 798 return typeTrees != null && arg < typeTrees.size() 799 && checkTypePath(ix+1, typeTrees.get(arg)); 800 } 801 case UNBOUNDED_WILDCARD: 802 return isBoundableWildcard(path, path.size()-1); 803 default: // TODO: casts? 804 return false; 805 } 806 } 807 808 private static int arrayDepth(Tree tree) { 809 if (tree.getKind() == Tree.Kind.NEW_ARRAY) { 810 NewArrayTree newArray = (NewArrayTree) tree; 811 Tree type = newArray.getType(); 812 if (type != null) { 813 return type.accept(new SimpleTreeVisitor<Integer, Integer>() { 814 @Override 815 public Integer visitArrayType(ArrayTypeTree t, Integer i) { 816 return t.getType().accept(this, i+1); 817 } 818 @Override 819 public Integer defaultAction(Tree t, Integer i) { 820 return i; 821 } 822 }, 1); 823 } 824 int depth = newArray.getDimensions().size(); 825 for (ExpressionTree elem : newArray.getInitializers()) { 826 Tree.Kind kind = elem.getKind(); 827 if (kind == Tree.Kind.NEW_ARRAY 828 || kind == Tree.Kind.ARRAY_TYPE) { 829 depth = Math.max(depth, arrayDepth(elem)+1); 830 } 831 } 832 return depth; 833 } else if (tree.getKind() == Tree.Kind.ANNOTATED_TYPE) { 834 return arrayDepth(((AnnotatedTypeTree) tree).getUnderlyingType()); 835 } else if (tree.getKind() == Tree.Kind.ARRAY_TYPE) { 836 return 1 + arrayDepth(((ArrayTypeTree) tree).getType()); 837 } else { 838 return 0; 839 } 840 } 841 842 private boolean checkReceiverType(int i, Type t) { 843 if (t == null) { return false; } 844 while (++i < astPath.size()) { 845 ASTPath.ASTEntry entry = astPath.get(i); 846 switch (entry.getTreeKind()) { 847 case ANNOTATED_TYPE: 848 break; 849 case ARRAY_TYPE: 850 if (t.getKind() != TypeKind.ARRAY) { return false; } 851 t = ((Type.ArrayType) t).getComponentType(); 852 break; 853 case MEMBER_SELECT: 854 // TODO 855 break; 856 case PARAMETERIZED_TYPE: 857 if (entry.childSelectorIs(ASTPath.TYPE_PARAMETER)) { 858 if (!t.isParameterized()) { return false; } 859 List<Type> args = t.getTypeArguments(); 860 int a = entry.getArgument(); 861 if (a >= args.size()) { return false; } 862 t = args.get(a); 863 } // else TYPE -- stay? 864 break; 865 case TYPE_PARAMETER: 866 if (t.getKind() != TypeKind.WILDCARD) { return false; } 867 t = t.getLowerBound(); 868 break; 869 case EXTENDS_WILDCARD: 870 if (t.getKind() != TypeKind.WILDCARD) { return false; } 871 t = ((Type.WildcardType) t).getExtendsBound(); 872 break; 873 case SUPER_WILDCARD: 874 if (t.getKind() != TypeKind.WILDCARD) { return false; } 875 t = ((Type.WildcardType) t).getSuperBound(); 876 break; 877 case UNBOUNDED_WILDCARD: 878 if (t.getKind() != TypeKind.WILDCARD) { return false; } 879 t = t.getLowerBound(); 880 break; 881 default: 882 return false; 883 } 884 if (t == null) { return false; } 885 } 886 return true; 887 } 888 889 private static ClassTree methodReceiverType(TreePath path) { 890 Tree t = path.getLeaf(); 891 if (t.getKind() != Tree.Kind.METHOD) { return null; } 892 JCTree.JCMethodDecl method = (JCTree.JCMethodDecl) t; 893 if ((method.mods.flags & Flags.STATIC) != 0) { return null; } 894 895 // Find the name of the class with type parameters to create the 896 // receiver. Walk up the tree and pick up class names to add to 897 // the receiver type. Since we're starting from the innermost 898 // class, the classes we get to at earlier iterations of the loop 899 // are inside of the classes we get to at later iterations. 900 TreePath parent = path.getParentPath(); 901 Tree leaf = parent.getLeaf(); 902 Tree.Kind kind = leaf.getKind(); 903 904 // For an inner class constructor, the receiver comes from the 905 // superclass, so skip past the first type definition. 906 boolean skip = method.getReturnType() == null; 907 908 while (kind != Tree.Kind.COMPILATION_UNIT 909 && kind != Tree.Kind.NEW_CLASS) { 910 if (kind == Tree.Kind.CLASS 911 || kind == Tree.Kind.INTERFACE 912 || kind == Tree.Kind.ENUM 913 || kind == Tree.Kind.ANNOTATION_TYPE) { 914 JCTree.JCClassDecl clazz = (JCTree.JCClassDecl) leaf; 915 boolean isStatic = kind == Tree.Kind.INTERFACE 916 || kind == Tree.Kind.ENUM 917 || clazz.getModifiers().getFlags().contains(Modifier.STATIC); 918 skip &= !isStatic; 919 if (!skip || isStatic) { return clazz; } 920 skip = false; 921 } 922 923 parent = path.getParentPath(); 924 leaf = parent.getLeaf(); 925 kind = leaf.getKind(); 926 } 927 928 throw new IllegalArgumentException("no receiver for non-inner constructor"); 929 } 930 931 private boolean checkTypePath(int i, Tree typeTree) { 932 try { 933loop: while (typeTree != null && i < astPath.size()) { 934 ASTPath.ASTEntry entry = astPath.get(i); 935 Tree.Kind kind = entry.getTreeKind(); 936 switch (kind) { 937 case ANNOTATED_TYPE: 938 typeTree = ((AnnotatedTypeTree) typeTree) 939 .getUnderlyingType(); 940 continue; 941 case ARRAY_TYPE: 942 typeTree = ((ArrayTypeTree) typeTree).getType(); 943 break; 944 case MEMBER_SELECT: 945 typeTree = ((MemberSelectTree) typeTree).getExpression(); 946 break; 947 case PARAMETERIZED_TYPE: 948 if (entry.childSelectorIs(ASTPath.TYPE_ARGUMENT)) { 949 int arg = entry.getArgument(); 950 typeTree = ((ParameterizedTypeTree) typeTree) 951 .getTypeArguments().get(arg); 952 } else { // TYPE 953 typeTree = ((ParameterizedTypeTree) typeTree).getType(); 954 } 955 break; 956 default: 957 if (isWildcard(kind)) { 958 return ++i == astPath.size(); // ??? 959 } 960 break loop; 961 } 962 ++i; 963 } 964 } catch (RuntimeException ex) {} 965 return false; 966 } 967 968 /** 969 * Determines if the given kinds match, false otherwise. Two kinds match if 970 * they're exactly the same or if the two kinds are both compound 971 * assignments, unary operators, binary operators or wildcards. 972 * <p> 973 * This is necessary because in the JAIF file these kinds are represented by 974 * their general types (i.e. BinaryOperator, CompoundOperator, etc.) rather 975 * than their kind (i.e. PLUS, MINUS, PLUS_ASSIGNMENT, XOR_ASSIGNMENT, 976 * etc.). Internally, a single kind is used to represent each general type 977 * (i.e. PLUS is used for BinaryOperator, PLUS_ASSIGNMENT is used for 978 * CompoundAssignment, etc.). Yet, the actual source nodes have the correct 979 * kind. So if an AST path entry has a PLUS kind, that really means it could 980 * be any BinaryOperator, resulting in PLUS matching any other 981 * BinaryOperator. 982 * 983 * @param kind1 984 * the first kind to match 985 * @param kind2 986 * the second kind to match 987 * @return {@code true} if the kinds match as described above, {@code false} 988 * otherwise. 989 */ 990 private boolean kindsMatch(Tree.Kind kind1, Tree.Kind kind2) { 991 return kind1 == kind2 ? true 992 : ASTPath.isClassEquiv(kind1) 993 ? ASTPath.isClassEquiv(kind2) 994 : ASTPath.isCompoundAssignment(kind1) 995 ? ASTPath.isCompoundAssignment(kind2) 996 : ASTPath.isUnaryOperator(kind1) 997 ? ASTPath.isUnaryOperator(kind2) 998 : ASTPath.isBinaryOperator(kind1) 999 ? ASTPath.isBinaryOperator(kind2) 1000 : ASTPath.isWildcard(kind1) 1001 ? ASTPath.isWildcard(kind2) 1002 : false; 1003 } 1004 1005 /** 1006 * Determines if the given kind is a binary operator. 1007 * 1008 * @param kind 1009 * the kind to test 1010 * @return true if the given kind is a binary operator 1011 */ 1012 public boolean isBinaryOperator(Tree.Kind kind) { 1013 return kind == Tree.Kind.MULTIPLY || kind == Tree.Kind.DIVIDE 1014 || kind == Tree.Kind.REMAINDER || kind == Tree.Kind.PLUS 1015 || kind == Tree.Kind.MINUS || kind == Tree.Kind.LEFT_SHIFT 1016 || kind == Tree.Kind.RIGHT_SHIFT 1017 || kind == Tree.Kind.UNSIGNED_RIGHT_SHIFT 1018 || kind == Tree.Kind.LESS_THAN 1019 || kind == Tree.Kind.GREATER_THAN 1020 || kind == Tree.Kind.LESS_THAN_EQUAL 1021 || kind == Tree.Kind.GREATER_THAN_EQUAL 1022 || kind == Tree.Kind.EQUAL_TO || kind == Tree.Kind.NOT_EQUAL_TO 1023 || kind == Tree.Kind.AND || kind == Tree.Kind.XOR 1024 || kind == Tree.Kind.OR || kind == Tree.Kind.CONDITIONAL_AND 1025 || kind == Tree.Kind.CONDITIONAL_OR; 1026 } 1027 1028 public boolean isExpression(Tree.Kind kind) { 1029 switch (kind) { 1030 case ARRAY_ACCESS: 1031 case ASSIGNMENT: 1032 case CONDITIONAL_EXPRESSION: 1033 case EXPRESSION_STATEMENT: 1034 case MEMBER_SELECT: 1035 case MEMBER_REFERENCE: 1036 case IDENTIFIER: 1037 case INSTANCE_OF: 1038 case METHOD_INVOCATION: 1039 case NEW_ARRAY: 1040 case NEW_CLASS: 1041 case LAMBDA_EXPRESSION: 1042 case PARENTHESIZED: 1043 case TYPE_CAST: 1044 case POSTFIX_INCREMENT: 1045 case POSTFIX_DECREMENT: 1046 case PREFIX_INCREMENT: 1047 case PREFIX_DECREMENT: 1048 case UNARY_PLUS: 1049 case UNARY_MINUS: 1050 case BITWISE_COMPLEMENT: 1051 case LOGICAL_COMPLEMENT: 1052 case MULTIPLY: 1053 case DIVIDE: 1054 case REMAINDER: 1055 case PLUS: 1056 case MINUS: 1057 case LEFT_SHIFT: 1058 case RIGHT_SHIFT: 1059 case UNSIGNED_RIGHT_SHIFT: 1060 case LESS_THAN: 1061 case GREATER_THAN: 1062 case LESS_THAN_EQUAL: 1063 case GREATER_THAN_EQUAL: 1064 case EQUAL_TO: 1065 case NOT_EQUAL_TO: 1066 case AND: 1067 case XOR: 1068 case OR: 1069 case CONDITIONAL_AND: 1070 case CONDITIONAL_OR: 1071 case MULTIPLY_ASSIGNMENT: 1072 case DIVIDE_ASSIGNMENT: 1073 case REMAINDER_ASSIGNMENT: 1074 case PLUS_ASSIGNMENT: 1075 case MINUS_ASSIGNMENT: 1076 case LEFT_SHIFT_ASSIGNMENT: 1077 case RIGHT_SHIFT_ASSIGNMENT: 1078 case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT: 1079 case AND_ASSIGNMENT: 1080 case XOR_ASSIGNMENT: 1081 case OR_ASSIGNMENT: 1082 case INT_LITERAL: 1083 case LONG_LITERAL: 1084 case FLOAT_LITERAL: 1085 case DOUBLE_LITERAL: 1086 case BOOLEAN_LITERAL: 1087 case CHAR_LITERAL: 1088 case STRING_LITERAL: 1089 case NULL_LITERAL: 1090 return true; 1091 default: 1092 return false; 1093 } 1094 } 1095 1096 /** 1097 * Determines if the given kind is a wildcard. 1098 * 1099 * @param kind 1100 * the kind to test 1101 * @return true if the given kind is a wildcard 1102 */ 1103 private boolean isWildcard(Tree.Kind kind) { 1104 return kind == Tree.Kind.UNBOUNDED_WILDCARD 1105 || kind == Tree.Kind.EXTENDS_WILDCARD 1106 || kind == Tree.Kind.SUPER_WILDCARD; 1107 } 1108 1109 // The following check is necessary because Oracle has decided that 1110 // x instanceof Class<? extends Object> 1111 // will remain illegal even though it means the same thing as 1112 // x instanceof Class<?>. 1113 private boolean isBoundableWildcard(List<Tree> actualPath, int i) { 1114 if (i <= 0) { return false; } 1115 Tree actualNode = actualPath.get(i); 1116 if (actualNode.getKind() == Tree.Kind.UNBOUNDED_WILDCARD) { 1117 // isWildcard(actualNode.getKind()) 1118 // TODO: refactor GenericArrayLoc to use same code? 1119 Tree ancestor = actualPath.get(i-1); 1120 if (ancestor.getKind() == Tree.Kind.INSTANCE_OF) { 1121 TreeFinder.warn.debug("WARNING: wildcard bounds not allowed " 1122 + "in 'instanceof' expression; skipping insertion%n"); 1123 return false; 1124 } else if (i > 1 && ancestor.getKind() == 1125 Tree.Kind.PARAMETERIZED_TYPE) { 1126 ancestor = actualPath.get(i-2); 1127 if (ancestor.getKind() == Tree.Kind.ARRAY_TYPE) { 1128 TreeFinder.warn.debug("WARNING: wildcard bounds not allowed " 1129 + "in 'instanceof' expression; skipping insertion%n"); 1130 return false; 1131 } 1132 } 1133 return true; 1134 } 1135 return false; 1136 } 1137 1138 /** {@inheritDoc} */ 1139 @Override 1140 public Kind getKind() { 1141 return Kind.AST_PATH; 1142 } 1143 1144 /** {@inheritDoc} */ 1145 @Override 1146 public String toString() { 1147 return "ASTPathCriterion: " + astPath; 1148 } 1149} 1150