Home | History | Annotate | Download | only in api
      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