1 /* 2 * Copyright (C) 2011 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.lint.client.api; 18 19 import static com.android.tools.lint.detector.api.LintConstants.ANDROID_PKG; 20 import static com.android.tools.lint.detector.api.LintConstants.R_CLASS; 21 22 import com.android.annotations.NonNull; 23 import com.android.tools.lint.detector.api.Detector; 24 import com.android.tools.lint.detector.api.Detector.JavaScanner; 25 import com.android.tools.lint.detector.api.Detector.XmlScanner; 26 import com.android.tools.lint.detector.api.JavaContext; 27 28 import java.io.File; 29 import java.util.ArrayList; 30 import java.util.HashMap; 31 import java.util.List; 32 import java.util.Map; 33 34 import lombok.ast.AlternateConstructorInvocation; 35 import lombok.ast.Annotation; 36 import lombok.ast.AnnotationDeclaration; 37 import lombok.ast.AnnotationElement; 38 import lombok.ast.AnnotationMethodDeclaration; 39 import lombok.ast.AnnotationValueArray; 40 import lombok.ast.ArrayAccess; 41 import lombok.ast.ArrayCreation; 42 import lombok.ast.ArrayDimension; 43 import lombok.ast.ArrayInitializer; 44 import lombok.ast.Assert; 45 import lombok.ast.AstVisitor; 46 import lombok.ast.BinaryExpression; 47 import lombok.ast.Block; 48 import lombok.ast.BooleanLiteral; 49 import lombok.ast.Break; 50 import lombok.ast.Case; 51 import lombok.ast.Cast; 52 import lombok.ast.Catch; 53 import lombok.ast.CharLiteral; 54 import lombok.ast.ClassDeclaration; 55 import lombok.ast.ClassLiteral; 56 import lombok.ast.Comment; 57 import lombok.ast.CompilationUnit; 58 import lombok.ast.ConstructorDeclaration; 59 import lombok.ast.ConstructorInvocation; 60 import lombok.ast.Continue; 61 import lombok.ast.Default; 62 import lombok.ast.DoWhile; 63 import lombok.ast.EmptyDeclaration; 64 import lombok.ast.EmptyStatement; 65 import lombok.ast.EnumConstant; 66 import lombok.ast.EnumDeclaration; 67 import lombok.ast.EnumTypeBody; 68 import lombok.ast.Expression; 69 import lombok.ast.ExpressionStatement; 70 import lombok.ast.FloatingPointLiteral; 71 import lombok.ast.For; 72 import lombok.ast.ForEach; 73 import lombok.ast.Identifier; 74 import lombok.ast.If; 75 import lombok.ast.ImportDeclaration; 76 import lombok.ast.InlineIfExpression; 77 import lombok.ast.InstanceInitializer; 78 import lombok.ast.InstanceOf; 79 import lombok.ast.IntegralLiteral; 80 import lombok.ast.InterfaceDeclaration; 81 import lombok.ast.KeywordModifier; 82 import lombok.ast.LabelledStatement; 83 import lombok.ast.MethodDeclaration; 84 import lombok.ast.MethodInvocation; 85 import lombok.ast.Modifiers; 86 import lombok.ast.Node; 87 import lombok.ast.NormalTypeBody; 88 import lombok.ast.NullLiteral; 89 import lombok.ast.PackageDeclaration; 90 import lombok.ast.Return; 91 import lombok.ast.Select; 92 import lombok.ast.StaticInitializer; 93 import lombok.ast.StringLiteral; 94 import lombok.ast.Super; 95 import lombok.ast.SuperConstructorInvocation; 96 import lombok.ast.Switch; 97 import lombok.ast.Synchronized; 98 import lombok.ast.This; 99 import lombok.ast.Throw; 100 import lombok.ast.Try; 101 import lombok.ast.TypeReference; 102 import lombok.ast.TypeReferencePart; 103 import lombok.ast.TypeVariable; 104 import lombok.ast.UnaryExpression; 105 import lombok.ast.VariableDeclaration; 106 import lombok.ast.VariableDefinition; 107 import lombok.ast.VariableDefinitionEntry; 108 import lombok.ast.VariableReference; 109 import lombok.ast.While; 110 111 112 /** 113 * Specialized visitor for running detectors on a Java AST. 114 * It operates in three phases: 115 * <ol> 116 * <li> First, it computes a set of maps where it generates a map from each 117 * significant AST attribute (such as method call names) to a list 118 * of detectors to consult whenever that attribute is encountered. 119 * Examples of "attributes" are method names, Android resource identifiers, 120 * and general AST node types such as "cast" nodes etc. These are 121 * defined on the {@link JavaScanner} interface. 122 * <li> Second, it iterates over the document a single time, delegating to 123 * the detectors found at each relevant AST attribute. 124 * <li> Finally, it calls the remaining visitors (those that need to process a 125 * whole document on their own). 126 * </ol> 127 * It also notifies all the detectors before and after the document is processed 128 * such that they can do pre- and post-processing. 129 */ 130 public class JavaVisitor { 131 /** Default size of lists holding detectors of the same type for a given node type */ 132 private static final int SAME_TYPE_COUNT = 8; 133 134 private final Map<String, List<VisitingDetector>> mMethodDetectors = 135 new HashMap<String, List<VisitingDetector>>(); 136 private final List<VisitingDetector> mResourceFieldDetectors = 137 new ArrayList<VisitingDetector>(); 138 private final List<VisitingDetector> mAllDetectors; 139 private final List<VisitingDetector> mFullTreeDetectors; 140 private Map<Class<? extends Node>, List<VisitingDetector>> mNodeTypeDetectors = 141 new HashMap<Class<? extends Node>, List<VisitingDetector>>(); 142 private final IJavaParser mParser; 143 144 JavaVisitor(@NonNull IJavaParser parser, @NonNull List<Detector> detectors) { 145 mParser = parser; 146 mAllDetectors = new ArrayList<VisitingDetector>(detectors.size()); 147 mFullTreeDetectors = new ArrayList<VisitingDetector>(detectors.size()); 148 149 for (Detector detector : detectors) { 150 VisitingDetector v = new VisitingDetector(detector, (JavaScanner) detector); 151 mAllDetectors.add(v); 152 153 List<Class<? extends Node>> nodeTypes = detector.getApplicableNodeTypes(); 154 if (nodeTypes != null) { 155 for (Class<? extends Node> type : nodeTypes) { 156 List<VisitingDetector> list = mNodeTypeDetectors.get(type); 157 if (list == null) { 158 list = new ArrayList<VisitingDetector>(SAME_TYPE_COUNT); 159 mNodeTypeDetectors.put(type, list); 160 } 161 list.add(v); 162 } 163 } 164 165 List<String> names = detector.getApplicableMethodNames(); 166 if (names != null) { 167 // not supported in Java visitors; adding a method invocation node is trivial 168 // for that case. 169 assert names != XmlScanner.ALL; 170 171 for (String name : names) { 172 List<VisitingDetector> list = mMethodDetectors.get(name); 173 if (list == null) { 174 list = new ArrayList<VisitingDetector>(SAME_TYPE_COUNT); 175 mMethodDetectors.put(name, list); 176 } 177 list.add(v); 178 } 179 } 180 181 if (detector.appliesToResourceRefs()) { 182 mResourceFieldDetectors.add(v); 183 } else if ((names == null || names.size() == 0) 184 && (nodeTypes == null || nodeTypes.size() ==0)) { 185 mFullTreeDetectors.add(v); 186 } 187 } 188 } 189 190 void visitFile(@NonNull JavaContext context, @NonNull File file) { 191 context.parser = mParser; 192 193 Node compilationUnit = null; 194 try { 195 compilationUnit = mParser.parseJava(context); 196 if (compilationUnit == null) { 197 // No need to log this; the parser should be reporting 198 // a full warning (such as IssueRegistry#PARSER_ERROR) 199 // with details, location, etc. 200 return; 201 } 202 context.compilationUnit = compilationUnit; 203 204 for (VisitingDetector v : mAllDetectors) { 205 v.setContext(context); 206 v.getDetector().beforeCheckFile(context); 207 } 208 209 for (VisitingDetector v : mFullTreeDetectors) { 210 AstVisitor visitor = v.getVisitor(); 211 if (visitor != null) { 212 compilationUnit.accept(visitor); 213 } else { 214 assert false : v.getDetector().getClass().getName(); 215 } 216 } 217 218 if (mMethodDetectors.size() > 0 || mResourceFieldDetectors.size() > 0) { 219 AstVisitor visitor = new DelegatingJavaVisitor(context); 220 compilationUnit.accept(visitor); 221 } else if (mNodeTypeDetectors.size() > 0) { 222 AstVisitor visitor = new DispatchVisitor(); 223 compilationUnit.accept(visitor); 224 } 225 226 for (VisitingDetector v : mAllDetectors) { 227 v.getDetector().afterCheckFile(context); 228 } 229 } finally { 230 if (compilationUnit != null) { 231 mParser.dispose(context, compilationUnit); 232 } 233 } 234 } 235 236 private static class VisitingDetector { 237 private AstVisitor mVisitor; // construct lazily, and clear out on context switch! 238 private JavaContext mContext; 239 public final Detector mDetector; 240 public final JavaScanner mJavaScanner; 241 242 public VisitingDetector(@NonNull Detector detector, @NonNull JavaScanner javaScanner) { 243 mDetector = detector; 244 mJavaScanner = javaScanner; 245 } 246 247 @NonNull 248 public Detector getDetector() { 249 return mDetector; 250 } 251 252 @NonNull 253 public JavaScanner getJavaScanner() { 254 return mJavaScanner; 255 } 256 257 public void setContext(@NonNull JavaContext context) { 258 mContext = context; 259 260 // The visitors are one-per-context, so clear them out here and construct 261 // lazily only if needed 262 mVisitor = null; 263 } 264 265 @NonNull 266 AstVisitor getVisitor() { 267 if (mVisitor == null) { 268 mVisitor = mDetector.createJavaVisitor(mContext); 269 } 270 return mVisitor; 271 } 272 } 273 274 /** 275 * Generic dispatcher which visits all nodes (once) and dispatches to 276 * specific visitors for each node. Each visitor typically only wants to 277 * look at a small part of a tree, such as a method call or a class 278 * declaration, so this means we avoid visiting all "uninteresting" nodes in 279 * the tree repeatedly. 280 */ 281 private class DispatchVisitor extends AstVisitor { 282 @Override 283 public void endVisit(Node node) { 284 } 285 286 @Override 287 public boolean visitAlternateConstructorInvocation(AlternateConstructorInvocation node) { 288 List<VisitingDetector> list = 289 mNodeTypeDetectors.get(AlternateConstructorInvocation.class); 290 if (list != null) { 291 for (VisitingDetector v : list) { 292 v.getVisitor().visitAlternateConstructorInvocation(node); 293 } 294 } 295 return false; 296 } 297 298 @Override 299 public boolean visitAnnotation(Annotation node) { 300 List<VisitingDetector> list = mNodeTypeDetectors.get(Annotation.class); 301 if (list != null) { 302 for (VisitingDetector v : list) { 303 v.getVisitor().visitAnnotation(node); 304 } 305 } 306 return false; 307 } 308 309 @Override 310 public boolean visitAnnotationDeclaration(AnnotationDeclaration node) { 311 List<VisitingDetector> list = mNodeTypeDetectors.get(AnnotationDeclaration.class); 312 if (list != null) { 313 for (VisitingDetector v : list) { 314 v.getVisitor().visitAnnotationDeclaration(node); 315 } 316 } 317 return false; 318 } 319 320 @Override 321 public boolean visitAnnotationElement(AnnotationElement node) { 322 List<VisitingDetector> list = mNodeTypeDetectors.get(AnnotationElement.class); 323 if (list != null) { 324 for (VisitingDetector v : list) { 325 v.getVisitor().visitAnnotationElement(node); 326 } 327 } 328 return false; 329 } 330 331 @Override 332 public boolean visitAnnotationMethodDeclaration(AnnotationMethodDeclaration node) { 333 List<VisitingDetector> list = 334 mNodeTypeDetectors.get(AnnotationMethodDeclaration.class); 335 if (list != null) { 336 for (VisitingDetector v : list) { 337 v.getVisitor().visitAnnotationMethodDeclaration(node); 338 } 339 } 340 return false; 341 } 342 343 @Override 344 public boolean visitAnnotationValueArray(AnnotationValueArray node) { 345 List<VisitingDetector> list = mNodeTypeDetectors.get(AnnotationValueArray.class); 346 if (list != null) { 347 for (VisitingDetector v : list) { 348 v.getVisitor().visitAnnotationValueArray(node); 349 } 350 } 351 return false; 352 } 353 354 @Override 355 public boolean visitArrayAccess(ArrayAccess node) { 356 List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayAccess.class); 357 if (list != null) { 358 for (VisitingDetector v : list) { 359 v.getVisitor().visitArrayAccess(node); 360 } 361 } 362 return false; 363 } 364 365 @Override 366 public boolean visitArrayCreation(ArrayCreation node) { 367 List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayCreation.class); 368 if (list != null) { 369 for (VisitingDetector v : list) { 370 v.getVisitor().visitArrayCreation(node); 371 } 372 } 373 return false; 374 } 375 376 @Override 377 public boolean visitArrayDimension(ArrayDimension node) { 378 List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayDimension.class); 379 if (list != null) { 380 for (VisitingDetector v : list) { 381 v.getVisitor().visitArrayDimension(node); 382 } 383 } 384 return false; 385 } 386 387 @Override 388 public boolean visitArrayInitializer(ArrayInitializer node) { 389 List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayInitializer.class); 390 if (list != null) { 391 for (VisitingDetector v : list) { 392 v.getVisitor().visitArrayInitializer(node); 393 } 394 } 395 return false; 396 } 397 398 @Override 399 public boolean visitAssert(Assert node) { 400 List<VisitingDetector> list = mNodeTypeDetectors.get(Assert.class); 401 if (list != null) { 402 for (VisitingDetector v : list) { 403 v.getVisitor().visitAssert(node); 404 } 405 } 406 return false; 407 } 408 409 @Override 410 public boolean visitBinaryExpression(BinaryExpression node) { 411 List<VisitingDetector> list = mNodeTypeDetectors.get(BinaryExpression.class); 412 if (list != null) { 413 for (VisitingDetector v : list) { 414 v.getVisitor().visitBinaryExpression(node); 415 } 416 } 417 return false; 418 } 419 420 @Override 421 public boolean visitBlock(Block node) { 422 List<VisitingDetector> list = mNodeTypeDetectors.get(Block.class); 423 if (list != null) { 424 for (VisitingDetector v : list) { 425 v.getVisitor().visitBlock(node); 426 } 427 } 428 return false; 429 } 430 431 @Override 432 public boolean visitBooleanLiteral(BooleanLiteral node) { 433 List<VisitingDetector> list = mNodeTypeDetectors.get(BooleanLiteral.class); 434 if (list != null) { 435 for (VisitingDetector v : list) { 436 v.getVisitor().visitBooleanLiteral(node); 437 } 438 } 439 return false; 440 } 441 442 @Override 443 public boolean visitBreak(Break node) { 444 List<VisitingDetector> list = mNodeTypeDetectors.get(Break.class); 445 if (list != null) { 446 for (VisitingDetector v : list) { 447 v.getVisitor().visitBreak(node); 448 } 449 } 450 return false; 451 } 452 453 @Override 454 public boolean visitCase(Case node) { 455 List<VisitingDetector> list = mNodeTypeDetectors.get(Case.class); 456 if (list != null) { 457 for (VisitingDetector v : list) { 458 v.getVisitor().visitCase(node); 459 } 460 } 461 return false; 462 } 463 464 @Override 465 public boolean visitCast(Cast node) { 466 List<VisitingDetector> list = mNodeTypeDetectors.get(Cast.class); 467 if (list != null) { 468 for (VisitingDetector v : list) { 469 v.getVisitor().visitCast(node); 470 } 471 } 472 return false; 473 } 474 475 @Override 476 public boolean visitCatch(Catch node) { 477 List<VisitingDetector> list = mNodeTypeDetectors.get(Catch.class); 478 if (list != null) { 479 for (VisitingDetector v : list) { 480 v.getVisitor().visitCatch(node); 481 } 482 } 483 return false; 484 } 485 486 @Override 487 public boolean visitCharLiteral(CharLiteral node) { 488 List<VisitingDetector> list = mNodeTypeDetectors.get(CharLiteral.class); 489 if (list != null) { 490 for (VisitingDetector v : list) { 491 v.getVisitor().visitCharLiteral(node); 492 } 493 } 494 return false; 495 } 496 497 @Override 498 public boolean visitClassDeclaration(ClassDeclaration node) { 499 List<VisitingDetector> list = mNodeTypeDetectors.get(ClassDeclaration.class); 500 if (list != null) { 501 for (VisitingDetector v : list) { 502 v.getVisitor().visitClassDeclaration(node); 503 } 504 } 505 return false; 506 } 507 508 @Override 509 public boolean visitClassLiteral(ClassLiteral node) { 510 List<VisitingDetector> list = mNodeTypeDetectors.get(ClassLiteral.class); 511 if (list != null) { 512 for (VisitingDetector v : list) { 513 v.getVisitor().visitClassLiteral(node); 514 } 515 } 516 return false; 517 } 518 519 @Override 520 public boolean visitComment(Comment node) { 521 List<VisitingDetector> list = mNodeTypeDetectors.get(Comment.class); 522 if (list != null) { 523 for (VisitingDetector v : list) { 524 v.getVisitor().visitComment(node); 525 } 526 } 527 return false; 528 } 529 530 @Override 531 public boolean visitCompilationUnit(CompilationUnit node) { 532 List<VisitingDetector> list = mNodeTypeDetectors.get(CompilationUnit.class); 533 if (list != null) { 534 for (VisitingDetector v : list) { 535 v.getVisitor().visitCompilationUnit(node); 536 } 537 } 538 return false; 539 } 540 541 @Override 542 public boolean visitConstructorDeclaration(ConstructorDeclaration node) { 543 List<VisitingDetector> list = mNodeTypeDetectors.get(ConstructorDeclaration.class); 544 if (list != null) { 545 for (VisitingDetector v : list) { 546 v.getVisitor().visitConstructorDeclaration(node); 547 } 548 } 549 return false; 550 } 551 552 @Override 553 public boolean visitConstructorInvocation(ConstructorInvocation node) { 554 List<VisitingDetector> list = mNodeTypeDetectors.get(ConstructorInvocation.class); 555 if (list != null) { 556 for (VisitingDetector v : list) { 557 v.getVisitor().visitConstructorInvocation(node); 558 } 559 } 560 return false; 561 } 562 563 @Override 564 public boolean visitContinue(Continue node) { 565 List<VisitingDetector> list = mNodeTypeDetectors.get(Continue.class); 566 if (list != null) { 567 for (VisitingDetector v : list) { 568 v.getVisitor().visitContinue(node); 569 } 570 } 571 return false; 572 } 573 574 @Override 575 public boolean visitDefault(Default node) { 576 List<VisitingDetector> list = mNodeTypeDetectors.get(Default.class); 577 if (list != null) { 578 for (VisitingDetector v : list) { 579 v.getVisitor().visitDefault(node); 580 } 581 } 582 return false; 583 } 584 585 @Override 586 public boolean visitDoWhile(DoWhile node) { 587 List<VisitingDetector> list = mNodeTypeDetectors.get(DoWhile.class); 588 if (list != null) { 589 for (VisitingDetector v : list) { 590 v.getVisitor().visitDoWhile(node); 591 } 592 } 593 return false; 594 } 595 596 @Override 597 public boolean visitEmptyDeclaration(EmptyDeclaration node) { 598 List<VisitingDetector> list = mNodeTypeDetectors.get(EmptyDeclaration.class); 599 if (list != null) { 600 for (VisitingDetector v : list) { 601 v.getVisitor().visitEmptyDeclaration(node); 602 } 603 } 604 return false; 605 } 606 607 @Override 608 public boolean visitEmptyStatement(EmptyStatement node) { 609 List<VisitingDetector> list = mNodeTypeDetectors.get(EmptyStatement.class); 610 if (list != null) { 611 for (VisitingDetector v : list) { 612 v.getVisitor().visitEmptyStatement(node); 613 } 614 } 615 return false; 616 } 617 618 @Override 619 public boolean visitEnumConstant(EnumConstant node) { 620 List<VisitingDetector> list = mNodeTypeDetectors.get(EnumConstant.class); 621 if (list != null) { 622 for (VisitingDetector v : list) { 623 v.getVisitor().visitEnumConstant(node); 624 } 625 } 626 return false; 627 } 628 629 @Override 630 public boolean visitEnumDeclaration(EnumDeclaration node) { 631 List<VisitingDetector> list = mNodeTypeDetectors.get(EnumDeclaration.class); 632 if (list != null) { 633 for (VisitingDetector v : list) { 634 v.getVisitor().visitEnumDeclaration(node); 635 } 636 } 637 return false; 638 } 639 640 @Override 641 public boolean visitEnumTypeBody(EnumTypeBody node) { 642 List<VisitingDetector> list = mNodeTypeDetectors.get(EnumTypeBody.class); 643 if (list != null) { 644 for (VisitingDetector v : list) { 645 v.getVisitor().visitEnumTypeBody(node); 646 } 647 } 648 return false; 649 } 650 651 @Override 652 public boolean visitExpressionStatement(ExpressionStatement node) { 653 List<VisitingDetector> list = mNodeTypeDetectors.get(ExpressionStatement.class); 654 if (list != null) { 655 for (VisitingDetector v : list) { 656 v.getVisitor().visitExpressionStatement(node); 657 } 658 } 659 return false; 660 } 661 662 @Override 663 public boolean visitFloatingPointLiteral(FloatingPointLiteral node) { 664 List<VisitingDetector> list = mNodeTypeDetectors.get(FloatingPointLiteral.class); 665 if (list != null) { 666 for (VisitingDetector v : list) { 667 v.getVisitor().visitFloatingPointLiteral(node); 668 } 669 } 670 return false; 671 } 672 673 @Override 674 public boolean visitFor(For node) { 675 List<VisitingDetector> list = mNodeTypeDetectors.get(For.class); 676 if (list != null) { 677 for (VisitingDetector v : list) { 678 v.getVisitor().visitFor(node); 679 } 680 } 681 return false; 682 } 683 684 @Override 685 public boolean visitForEach(ForEach node) { 686 List<VisitingDetector> list = mNodeTypeDetectors.get(ForEach.class); 687 if (list != null) { 688 for (VisitingDetector v : list) { 689 v.getVisitor().visitForEach(node); 690 } 691 } 692 return false; 693 } 694 695 @Override 696 public boolean visitIdentifier(Identifier node) { 697 List<VisitingDetector> list = mNodeTypeDetectors.get(Identifier.class); 698 if (list != null) { 699 for (VisitingDetector v : list) { 700 v.getVisitor().visitIdentifier(node); 701 } 702 } 703 return false; 704 } 705 706 @Override 707 public boolean visitIf(If node) { 708 List<VisitingDetector> list = mNodeTypeDetectors.get(If.class); 709 if (list != null) { 710 for (VisitingDetector v : list) { 711 v.getVisitor().visitIf(node); 712 } 713 } 714 return false; 715 } 716 717 @Override 718 public boolean visitImportDeclaration(ImportDeclaration node) { 719 List<VisitingDetector> list = mNodeTypeDetectors.get(ImportDeclaration.class); 720 if (list != null) { 721 for (VisitingDetector v : list) { 722 v.getVisitor().visitImportDeclaration(node); 723 } 724 } 725 return false; 726 } 727 728 @Override 729 public boolean visitInlineIfExpression(InlineIfExpression node) { 730 List<VisitingDetector> list = mNodeTypeDetectors.get(InlineIfExpression.class); 731 if (list != null) { 732 for (VisitingDetector v : list) { 733 v.getVisitor().visitInlineIfExpression(node); 734 } 735 } 736 return false; 737 } 738 739 @Override 740 public boolean visitInstanceInitializer(InstanceInitializer node) { 741 List<VisitingDetector> list = mNodeTypeDetectors.get(InstanceInitializer.class); 742 if (list != null) { 743 for (VisitingDetector v : list) { 744 v.getVisitor().visitInstanceInitializer(node); 745 } 746 } 747 return false; 748 } 749 750 @Override 751 public boolean visitInstanceOf(InstanceOf node) { 752 List<VisitingDetector> list = mNodeTypeDetectors.get(InstanceOf.class); 753 if (list != null) { 754 for (VisitingDetector v : list) { 755 v.getVisitor().visitInstanceOf(node); 756 } 757 } 758 return false; 759 } 760 761 @Override 762 public boolean visitIntegralLiteral(IntegralLiteral node) { 763 List<VisitingDetector> list = mNodeTypeDetectors.get(IntegralLiteral.class); 764 if (list != null) { 765 for (VisitingDetector v : list) { 766 v.getVisitor().visitIntegralLiteral(node); 767 } 768 } 769 return false; 770 } 771 772 @Override 773 public boolean visitInterfaceDeclaration(InterfaceDeclaration node) { 774 List<VisitingDetector> list = mNodeTypeDetectors.get(InterfaceDeclaration.class); 775 if (list != null) { 776 for (VisitingDetector v : list) { 777 v.getVisitor().visitInterfaceDeclaration(node); 778 } 779 } 780 return false; 781 } 782 783 @Override 784 public boolean visitKeywordModifier(KeywordModifier node) { 785 List<VisitingDetector> list = mNodeTypeDetectors.get(KeywordModifier.class); 786 if (list != null) { 787 for (VisitingDetector v : list) { 788 v.getVisitor().visitKeywordModifier(node); 789 } 790 } 791 return false; 792 } 793 794 @Override 795 public boolean visitLabelledStatement(LabelledStatement node) { 796 List<VisitingDetector> list = mNodeTypeDetectors.get(LabelledStatement.class); 797 if (list != null) { 798 for (VisitingDetector v : list) { 799 v.getVisitor().visitLabelledStatement(node); 800 } 801 } 802 return false; 803 } 804 805 @Override 806 public boolean visitMethodDeclaration(MethodDeclaration node) { 807 List<VisitingDetector> list = mNodeTypeDetectors.get(MethodDeclaration.class); 808 if (list != null) { 809 for (VisitingDetector v : list) { 810 v.getVisitor().visitMethodDeclaration(node); 811 } 812 } 813 return false; 814 } 815 816 @Override 817 public boolean visitMethodInvocation(MethodInvocation node) { 818 List<VisitingDetector> list = mNodeTypeDetectors.get(MethodInvocation.class); 819 if (list != null) { 820 for (VisitingDetector v : list) { 821 v.getVisitor().visitMethodInvocation(node); 822 } 823 } 824 return false; 825 } 826 827 @Override 828 public boolean visitModifiers(Modifiers node) { 829 List<VisitingDetector> list = mNodeTypeDetectors.get(Modifiers.class); 830 if (list != null) { 831 for (VisitingDetector v : list) { 832 v.getVisitor().visitModifiers(node); 833 } 834 } 835 return false; 836 } 837 838 @Override 839 public boolean visitNormalTypeBody(NormalTypeBody node) { 840 List<VisitingDetector> list = mNodeTypeDetectors.get(NormalTypeBody.class); 841 if (list != null) { 842 for (VisitingDetector v : list) { 843 v.getVisitor().visitNormalTypeBody(node); 844 } 845 } 846 return false; 847 } 848 849 @Override 850 public boolean visitNullLiteral(NullLiteral node) { 851 List<VisitingDetector> list = mNodeTypeDetectors.get(NullLiteral.class); 852 if (list != null) { 853 for (VisitingDetector v : list) { 854 v.getVisitor().visitNullLiteral(node); 855 } 856 } 857 return false; 858 } 859 860 @Override 861 public boolean visitPackageDeclaration(PackageDeclaration node) { 862 List<VisitingDetector> list = mNodeTypeDetectors.get(PackageDeclaration.class); 863 if (list != null) { 864 for (VisitingDetector v : list) { 865 v.getVisitor().visitPackageDeclaration(node); 866 } 867 } 868 return false; 869 } 870 871 @Override 872 public boolean visitParseArtefact(Node node) { 873 List<VisitingDetector> list = mNodeTypeDetectors.get(Node.class); 874 if (list != null) { 875 for (VisitingDetector v : list) { 876 v.getVisitor().visitParseArtefact(node); 877 } 878 } 879 return false; 880 } 881 882 @Override 883 public boolean visitReturn(Return node) { 884 List<VisitingDetector> list = mNodeTypeDetectors.get(Return.class); 885 if (list != null) { 886 for (VisitingDetector v : list) { 887 v.getVisitor().visitReturn(node); 888 } 889 } 890 return false; 891 } 892 893 @Override 894 public boolean visitSelect(Select node) { 895 List<VisitingDetector> list = mNodeTypeDetectors.get(Select.class); 896 if (list != null) { 897 for (VisitingDetector v : list) { 898 v.getVisitor().visitSelect(node); 899 } 900 } 901 return false; 902 } 903 904 @Override 905 public boolean visitStaticInitializer(StaticInitializer node) { 906 List<VisitingDetector> list = mNodeTypeDetectors.get(StaticInitializer.class); 907 if (list != null) { 908 for (VisitingDetector v : list) { 909 v.getVisitor().visitStaticInitializer(node); 910 } 911 } 912 return false; 913 } 914 915 @Override 916 public boolean visitStringLiteral(StringLiteral node) { 917 List<VisitingDetector> list = mNodeTypeDetectors.get(StringLiteral.class); 918 if (list != null) { 919 for (VisitingDetector v : list) { 920 v.getVisitor().visitStringLiteral(node); 921 } 922 } 923 return false; 924 } 925 926 @Override 927 public boolean visitSuper(Super node) { 928 List<VisitingDetector> list = mNodeTypeDetectors.get(Super.class); 929 if (list != null) { 930 for (VisitingDetector v : list) { 931 v.getVisitor().visitSuper(node); 932 } 933 } 934 return false; 935 } 936 937 @Override 938 public boolean visitSuperConstructorInvocation(SuperConstructorInvocation node) { 939 List<VisitingDetector> list = mNodeTypeDetectors.get(SuperConstructorInvocation.class); 940 if (list != null) { 941 for (VisitingDetector v : list) { 942 v.getVisitor().visitSuperConstructorInvocation(node); 943 } 944 } 945 return false; 946 } 947 948 @Override 949 public boolean visitSwitch(Switch node) { 950 List<VisitingDetector> list = mNodeTypeDetectors.get(Switch.class); 951 if (list != null) { 952 for (VisitingDetector v : list) { 953 v.getVisitor().visitSwitch(node); 954 } 955 } 956 return false; 957 } 958 959 @Override 960 public boolean visitSynchronized(Synchronized node) { 961 List<VisitingDetector> list = mNodeTypeDetectors.get(Synchronized.class); 962 if (list != null) { 963 for (VisitingDetector v : list) { 964 v.getVisitor().visitSynchronized(node); 965 } 966 } 967 return false; 968 } 969 970 @Override 971 public boolean visitThis(This node) { 972 List<VisitingDetector> list = mNodeTypeDetectors.get(This.class); 973 if (list != null) { 974 for (VisitingDetector v : list) { 975 v.getVisitor().visitThis(node); 976 } 977 } 978 return false; 979 } 980 981 @Override 982 public boolean visitThrow(Throw node) { 983 List<VisitingDetector> list = mNodeTypeDetectors.get(Throw.class); 984 if (list != null) { 985 for (VisitingDetector v : list) { 986 v.getVisitor().visitThrow(node); 987 } 988 } 989 return false; 990 } 991 992 @Override 993 public boolean visitTry(Try node) { 994 List<VisitingDetector> list = mNodeTypeDetectors.get(Try.class); 995 if (list != null) { 996 for (VisitingDetector v : list) { 997 v.getVisitor().visitTry(node); 998 } 999 } 1000 return false; 1001 } 1002 1003 @Override 1004 public boolean visitTypeReference(TypeReference node) { 1005 List<VisitingDetector> list = mNodeTypeDetectors.get(TypeReference.class); 1006 if (list != null) { 1007 for (VisitingDetector v : list) { 1008 v.getVisitor().visitTypeReference(node); 1009 } 1010 } 1011 return false; 1012 } 1013 1014 @Override 1015 public boolean visitTypeReferencePart(TypeReferencePart node) { 1016 List<VisitingDetector> list = mNodeTypeDetectors.get(TypeReferencePart.class); 1017 if (list != null) { 1018 for (VisitingDetector v : list) { 1019 v.getVisitor().visitTypeReferencePart(node); 1020 } 1021 } 1022 return false; 1023 } 1024 1025 @Override 1026 public boolean visitTypeVariable(TypeVariable node) { 1027 List<VisitingDetector> list = mNodeTypeDetectors.get(TypeVariable.class); 1028 if (list != null) { 1029 for (VisitingDetector v : list) { 1030 v.getVisitor().visitTypeVariable(node); 1031 } 1032 } 1033 return false; 1034 } 1035 1036 @Override 1037 public boolean visitUnaryExpression(UnaryExpression node) { 1038 List<VisitingDetector> list = mNodeTypeDetectors.get(UnaryExpression.class); 1039 if (list != null) { 1040 for (VisitingDetector v : list) { 1041 v.getVisitor().visitUnaryExpression(node); 1042 } 1043 } 1044 return false; 1045 } 1046 1047 @Override 1048 public boolean visitVariableDeclaration(VariableDeclaration node) { 1049 List<VisitingDetector> list = mNodeTypeDetectors.get(VariableDeclaration.class); 1050 if (list != null) { 1051 for (VisitingDetector v : list) { 1052 v.getVisitor().visitVariableDeclaration(node); 1053 } 1054 } 1055 return false; 1056 } 1057 1058 @Override 1059 public boolean visitVariableDefinition(VariableDefinition node) { 1060 List<VisitingDetector> list = mNodeTypeDetectors.get(VariableDefinition.class); 1061 if (list != null) { 1062 for (VisitingDetector v : list) { 1063 v.getVisitor().visitVariableDefinition(node); 1064 } 1065 } 1066 return false; 1067 } 1068 1069 @Override 1070 public boolean visitVariableDefinitionEntry(VariableDefinitionEntry node) { 1071 List<VisitingDetector> list = mNodeTypeDetectors.get(VariableDefinitionEntry.class); 1072 if (list != null) { 1073 for (VisitingDetector v : list) { 1074 v.getVisitor().visitVariableDefinitionEntry(node); 1075 } 1076 } 1077 return false; 1078 } 1079 1080 @Override 1081 public boolean visitVariableReference(VariableReference node) { 1082 List<VisitingDetector> list = mNodeTypeDetectors.get(VariableReference.class); 1083 if (list != null) { 1084 for (VisitingDetector v : list) { 1085 v.getVisitor().visitVariableReference(node); 1086 } 1087 } 1088 return false; 1089 } 1090 1091 @Override 1092 public boolean visitWhile(While node) { 1093 List<VisitingDetector> list = mNodeTypeDetectors.get(While.class); 1094 if (list != null) { 1095 for (VisitingDetector v : list) { 1096 v.getVisitor().visitWhile(node); 1097 } 1098 } 1099 return false; 1100 } 1101 } 1102 1103 /** Performs common AST searches for method calls and R-type-field references. 1104 * Note that this is a specialized form of the {@link DispatchVisitor}. */ 1105 private class DelegatingJavaVisitor extends DispatchVisitor { 1106 private final JavaContext mContext; 1107 private final boolean mVisitResources; 1108 private final boolean mVisitMethods; 1109 1110 public DelegatingJavaVisitor(JavaContext context) { 1111 mContext = context; 1112 1113 mVisitMethods = mMethodDetectors.size() > 0; 1114 mVisitResources = mResourceFieldDetectors.size() > 0; 1115 } 1116 1117 @Override 1118 public boolean visitSelect(Select node) { 1119 if (mVisitResources) { 1120 // R.type.name 1121 if (node.astOperand() instanceof Select) { 1122 Select select = (Select) node.astOperand(); 1123 if (select.astOperand() instanceof VariableReference) { 1124 VariableReference reference = (VariableReference) select.astOperand(); 1125 if (reference.astIdentifier().astValue().equals(R_CLASS)) { 1126 String type = select.astIdentifier().astValue(); 1127 String name = node.astIdentifier().astValue(); 1128 1129 // R -could- be referenced locally and really have been 1130 // imported as "import android.R;" in the import statements, 1131 // but this is not recommended (and in fact there's a specific 1132 // lint rule warning against it) 1133 boolean isFramework = false; 1134 1135 for (VisitingDetector v : mResourceFieldDetectors) { 1136 JavaScanner detector = v.getJavaScanner(); 1137 detector.visitResourceReference(mContext, v.getVisitor(), 1138 node, type, name, isFramework); 1139 } 1140 1141 return super.visitSelect(node); 1142 } 1143 } 1144 } 1145 1146 // Arbitrary packages -- android.R.type.name, foo.bar.R.type.name 1147 if (node.astIdentifier().astValue().equals(R_CLASS)) { 1148 Node parent = node.getParent(); 1149 if (parent instanceof Select) { 1150 Node grandParent = parent.getParent(); 1151 if (grandParent instanceof Select) { 1152 Select select = (Select) grandParent; 1153 String name = select.astIdentifier().astValue(); 1154 Expression typeOperand = select.astOperand(); 1155 if (typeOperand instanceof Select) { 1156 Select typeSelect = (Select) typeOperand; 1157 String type = typeSelect.astIdentifier().astValue(); 1158 boolean isFramework = 1159 node.astIdentifier().astValue().equals(ANDROID_PKG); 1160 for (VisitingDetector v : mResourceFieldDetectors) { 1161 JavaScanner detector = v.getJavaScanner(); 1162 detector.visitResourceReference(mContext, v.getVisitor(), 1163 node, type, name, isFramework); 1164 } 1165 } 1166 } 1167 } 1168 } 1169 } 1170 1171 return super.visitSelect(node); 1172 } 1173 1174 @Override 1175 public boolean visitMethodInvocation(@NonNull MethodInvocation node) { 1176 if (mVisitMethods) { 1177 String methodName = node.astName().getDescription(); 1178 List<VisitingDetector> list = mMethodDetectors.get(methodName); 1179 if (list != null) { 1180 for (VisitingDetector v : list) { 1181 v.getJavaScanner().visitMethod(mContext, v.getVisitor(), node); 1182 } 1183 } 1184 } 1185 1186 return super.visitMethodInvocation(node); 1187 } 1188 } 1189 } 1190