All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.android.tools.lint.client.api.JavaVisitor Maven / Gradle / Ivy

There is a newer version: 25.3.0
Show newest version
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.tools.lint.client.api;

import static com.android.SdkConstants.ANDROID_PKG;
import static com.android.SdkConstants.R_CLASS;

import com.android.annotations.NonNull;
import com.android.tools.lint.client.api.JavaParser.ResolvedClass;
import com.android.tools.lint.client.api.JavaParser.ResolvedMethod;
import com.android.tools.lint.client.api.JavaParser.ResolvedNode;
import com.android.tools.lint.detector.api.Detector;
import com.android.tools.lint.detector.api.Detector.JavaScanner;
import com.android.tools.lint.detector.api.Detector.XmlScanner;
import com.android.tools.lint.detector.api.JavaContext;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import lombok.ast.AlternateConstructorInvocation;
import lombok.ast.Annotation;
import lombok.ast.AnnotationDeclaration;
import lombok.ast.AnnotationElement;
import lombok.ast.AnnotationMethodDeclaration;
import lombok.ast.AnnotationValueArray;
import lombok.ast.ArrayAccess;
import lombok.ast.ArrayCreation;
import lombok.ast.ArrayDimension;
import lombok.ast.ArrayInitializer;
import lombok.ast.Assert;
import lombok.ast.AstVisitor;
import lombok.ast.BinaryExpression;
import lombok.ast.Block;
import lombok.ast.BooleanLiteral;
import lombok.ast.Break;
import lombok.ast.Case;
import lombok.ast.Cast;
import lombok.ast.Catch;
import lombok.ast.CharLiteral;
import lombok.ast.ClassDeclaration;
import lombok.ast.ClassLiteral;
import lombok.ast.Comment;
import lombok.ast.CompilationUnit;
import lombok.ast.ConstructorDeclaration;
import lombok.ast.ConstructorInvocation;
import lombok.ast.Continue;
import lombok.ast.Default;
import lombok.ast.DoWhile;
import lombok.ast.EmptyDeclaration;
import lombok.ast.EmptyStatement;
import lombok.ast.EnumConstant;
import lombok.ast.EnumDeclaration;
import lombok.ast.EnumTypeBody;
import lombok.ast.Expression;
import lombok.ast.ExpressionStatement;
import lombok.ast.FloatingPointLiteral;
import lombok.ast.For;
import lombok.ast.ForEach;
import lombok.ast.ForwardingAstVisitor;
import lombok.ast.Identifier;
import lombok.ast.If;
import lombok.ast.ImportDeclaration;
import lombok.ast.InlineIfExpression;
import lombok.ast.InstanceInitializer;
import lombok.ast.InstanceOf;
import lombok.ast.IntegralLiteral;
import lombok.ast.InterfaceDeclaration;
import lombok.ast.KeywordModifier;
import lombok.ast.LabelledStatement;
import lombok.ast.MethodDeclaration;
import lombok.ast.MethodInvocation;
import lombok.ast.Modifiers;
import lombok.ast.Node;
import lombok.ast.NormalTypeBody;
import lombok.ast.NullLiteral;
import lombok.ast.PackageDeclaration;
import lombok.ast.Return;
import lombok.ast.Select;
import lombok.ast.StaticInitializer;
import lombok.ast.StringLiteral;
import lombok.ast.Super;
import lombok.ast.SuperConstructorInvocation;
import lombok.ast.Switch;
import lombok.ast.Synchronized;
import lombok.ast.This;
import lombok.ast.Throw;
import lombok.ast.Try;
import lombok.ast.TypeReference;
import lombok.ast.TypeReferencePart;
import lombok.ast.TypeVariable;
import lombok.ast.UnaryExpression;
import lombok.ast.VariableDeclaration;
import lombok.ast.VariableDefinition;
import lombok.ast.VariableDefinitionEntry;
import lombok.ast.VariableReference;
import lombok.ast.While;

/**
 * Specialized visitor for running detectors on a Java AST.
 * It operates in three phases:
 * 
    *
  1. First, it computes a set of maps where it generates a map from each * significant AST attribute (such as method call names) to a list * of detectors to consult whenever that attribute is encountered. * Examples of "attributes" are method names, Android resource identifiers, * and general AST node types such as "cast" nodes etc. These are * defined on the {@link JavaScanner} interface. *
  2. Second, it iterates over the document a single time, delegating to * the detectors found at each relevant AST attribute. *
  3. Finally, it calls the remaining visitors (those that need to process a * whole document on their own). *
* It also notifies all the detectors before and after the document is processed * such that they can do pre- and post-processing. */ public class JavaVisitor { /** Default size of lists holding detectors of the same type for a given node type */ private static final int SAME_TYPE_COUNT = 8; private final Map> mMethodDetectors = Maps.newHashMapWithExpectedSize(40); private final Map> mConstructorDetectors = Maps.newHashMapWithExpectedSize(12); private Set mConstructorSimpleNames; private final List mResourceFieldDetectors = new ArrayList(); private final List mAllDetectors; private final List mFullTreeDetectors; private final Map, List> mNodeTypeDetectors = new HashMap, List>(16); private final JavaParser mParser; private final Map> mSuperClassDetectors = new HashMap>(); JavaVisitor(@NonNull JavaParser parser, @NonNull List detectors) { mParser = parser; mAllDetectors = new ArrayList(detectors.size()); mFullTreeDetectors = new ArrayList(detectors.size()); for (Detector detector : detectors) { VisitingDetector v = new VisitingDetector(detector, (JavaScanner) detector); mAllDetectors.add(v); List applicableSuperClasses = detector.applicableSuperClasses(); if (applicableSuperClasses != null) { for (String fqn : applicableSuperClasses) { List list = mSuperClassDetectors.get(fqn); if (list == null) { list = new ArrayList(SAME_TYPE_COUNT); mSuperClassDetectors.put(fqn, list); } list.add(v); } continue; } List> nodeTypes = detector.getApplicableNodeTypes(); if (nodeTypes != null) { for (Class type : nodeTypes) { List list = mNodeTypeDetectors.get(type); if (list == null) { list = new ArrayList(SAME_TYPE_COUNT); mNodeTypeDetectors.put(type, list); } list.add(v); } } List names = detector.getApplicableMethodNames(); if (names != null) { // not supported in Java visitors; adding a method invocation node is trivial // for that case. assert names != XmlScanner.ALL; for (String name : names) { List list = mMethodDetectors.get(name); if (list == null) { list = new ArrayList(SAME_TYPE_COUNT); mMethodDetectors.put(name, list); } list.add(v); } } List types = detector.getApplicableConstructorTypes(); if (types != null) { // not supported in Java visitors; adding a method invocation node is trivial // for that case. assert types != XmlScanner.ALL; if (mConstructorSimpleNames == null) { mConstructorSimpleNames = Sets.newHashSet(); } for (String type : types) { List list = mConstructorDetectors.get(type); if (list == null) { list = new ArrayList(SAME_TYPE_COUNT); mConstructorDetectors.put(type, list); mConstructorSimpleNames.add(type.substring(type.lastIndexOf('.')+1)); } list.add(v); } } if (detector.appliesToResourceRefs()) { mResourceFieldDetectors.add(v); } else if ((names == null || names.isEmpty()) && (nodeTypes == null || nodeTypes.isEmpty()) && (types == null || types.isEmpty())) { mFullTreeDetectors.add(v); } } } void visitFile(@NonNull JavaContext context) { Node compilationUnit = null; try { compilationUnit = mParser.parseJava(context); if (compilationUnit == null) { // No need to log this; the parser should be reporting // a full warning (such as IssueRegistry#PARSER_ERROR) // with details, location, etc. return; } context.setCompilationUnit(compilationUnit); for (VisitingDetector v : mAllDetectors) { v.setContext(context); v.getDetector().beforeCheckFile(context); } if (!mSuperClassDetectors.isEmpty()) { SuperclassVisitor visitor = new SuperclassVisitor(context); compilationUnit.accept(visitor); } for (VisitingDetector v : mFullTreeDetectors) { AstVisitor visitor = v.getVisitor(); compilationUnit.accept(visitor); } if (!mMethodDetectors.isEmpty() || !mResourceFieldDetectors.isEmpty() || !mConstructorDetectors.isEmpty()) { AstVisitor visitor = new DelegatingJavaVisitor(context); compilationUnit.accept(visitor); } else if (!mNodeTypeDetectors.isEmpty()) { AstVisitor visitor = new DispatchVisitor(); compilationUnit.accept(visitor); } for (VisitingDetector v : mAllDetectors) { v.getDetector().afterCheckFile(context); } } finally { if (compilationUnit != null) { mParser.dispose(context, compilationUnit); } } } public void prepare(@NonNull List contexts) { mParser.prepareJavaParse(contexts); } public void dispose() { mParser.dispose(); } private static class VisitingDetector { private AstVisitor mVisitor; // construct lazily, and clear out on context switch! private JavaContext mContext; public final Detector mDetector; public final JavaScanner mJavaScanner; public VisitingDetector(@NonNull Detector detector, @NonNull JavaScanner javaScanner) { mDetector = detector; mJavaScanner = javaScanner; } @NonNull public Detector getDetector() { return mDetector; } @NonNull public JavaScanner getJavaScanner() { return mJavaScanner; } public void setContext(@NonNull JavaContext context) { mContext = context; // The visitors are one-per-context, so clear them out here and construct // lazily only if needed mVisitor = null; } @NonNull AstVisitor getVisitor() { if (mVisitor == null) { mVisitor = mDetector.createJavaVisitor(mContext); if (mVisitor == null) { mVisitor = new ForwardingAstVisitor() { }; } } return mVisitor; } } private class SuperclassVisitor extends ForwardingAstVisitor { private JavaContext mContext; public SuperclassVisitor(@NonNull JavaContext context) { mContext = context; } @Override public boolean visitClassDeclaration(ClassDeclaration node) { ResolvedNode resolved = mContext.resolve(node); if (!(resolved instanceof ResolvedClass)) { return true; } ResolvedClass resolvedClass = (ResolvedClass) resolved; ResolvedClass cls = resolvedClass; while (cls != null) { String fqcn = cls.getSignature(); if (fqcn != null) { List list = mSuperClassDetectors.get(fqcn); if (list != null) { for (VisitingDetector v : list) { v.getJavaScanner().checkClass(mContext, node, node, resolvedClass); } } } cls = cls.getSuperClass(); } return false; } @Override public boolean visitConstructorInvocation(ConstructorInvocation node) { NormalTypeBody anonymous = node.astAnonymousClassBody(); if (anonymous != null) { ResolvedNode resolved = mContext.resolve(anonymous); if (resolved instanceof ResolvedMethod) { resolved = ((ResolvedMethod) resolved).getContainingClass(); } if (!(resolved instanceof ResolvedClass)) { return true; } ResolvedClass resolvedClass = (ResolvedClass) resolved; ResolvedClass cls = resolvedClass; while (cls != null) { String fqcn = cls.getSignature(); if (fqcn != null) { List list = mSuperClassDetectors.get(fqcn); if (list != null) { for (VisitingDetector v : list) { v.getJavaScanner().checkClass(mContext, null, anonymous, resolvedClass); } } } cls = cls.getSuperClass(); } } return true; } @Override public boolean visitImportDeclaration(ImportDeclaration node) { return true; } } /** * Generic dispatcher which visits all nodes (once) and dispatches to * specific visitors for each node. Each visitor typically only wants to * look at a small part of a tree, such as a method call or a class * declaration, so this means we avoid visiting all "uninteresting" nodes in * the tree repeatedly. */ private class DispatchVisitor extends ForwardingAstVisitor { @Override public void endVisit(Node node) { for (VisitingDetector v : mAllDetectors) { v.getVisitor().endVisit(node); } } @Override public boolean visitAlternateConstructorInvocation(AlternateConstructorInvocation node) { List list = mNodeTypeDetectors.get(AlternateConstructorInvocation.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitAlternateConstructorInvocation(node); } } return false; } @Override public boolean visitAnnotation(Annotation node) { List list = mNodeTypeDetectors.get(Annotation.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitAnnotation(node); } } return false; } @Override public boolean visitAnnotationDeclaration(AnnotationDeclaration node) { List list = mNodeTypeDetectors.get(AnnotationDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitAnnotationDeclaration(node); } } return false; } @Override public boolean visitAnnotationElement(AnnotationElement node) { List list = mNodeTypeDetectors.get(AnnotationElement.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitAnnotationElement(node); } } return false; } @Override public boolean visitAnnotationMethodDeclaration(AnnotationMethodDeclaration node) { List list = mNodeTypeDetectors.get(AnnotationMethodDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitAnnotationMethodDeclaration(node); } } return false; } @Override public boolean visitAnnotationValueArray(AnnotationValueArray node) { List list = mNodeTypeDetectors.get(AnnotationValueArray.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitAnnotationValueArray(node); } } return false; } @Override public boolean visitArrayAccess(ArrayAccess node) { List list = mNodeTypeDetectors.get(ArrayAccess.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitArrayAccess(node); } } return false; } @Override public boolean visitArrayCreation(ArrayCreation node) { List list = mNodeTypeDetectors.get(ArrayCreation.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitArrayCreation(node); } } return false; } @Override public boolean visitArrayDimension(ArrayDimension node) { List list = mNodeTypeDetectors.get(ArrayDimension.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitArrayDimension(node); } } return false; } @Override public boolean visitArrayInitializer(ArrayInitializer node) { List list = mNodeTypeDetectors.get(ArrayInitializer.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitArrayInitializer(node); } } return false; } @Override public boolean visitAssert(Assert node) { List list = mNodeTypeDetectors.get(Assert.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitAssert(node); } } return false; } @Override public boolean visitBinaryExpression(BinaryExpression node) { List list = mNodeTypeDetectors.get(BinaryExpression.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitBinaryExpression(node); } } return false; } @Override public boolean visitBlock(Block node) { List list = mNodeTypeDetectors.get(Block.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitBlock(node); } } return false; } @Override public boolean visitBooleanLiteral(BooleanLiteral node) { List list = mNodeTypeDetectors.get(BooleanLiteral.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitBooleanLiteral(node); } } return false; } @Override public boolean visitBreak(Break node) { List list = mNodeTypeDetectors.get(Break.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitBreak(node); } } return false; } @Override public boolean visitCase(Case node) { List list = mNodeTypeDetectors.get(Case.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitCase(node); } } return false; } @Override public boolean visitCast(Cast node) { List list = mNodeTypeDetectors.get(Cast.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitCast(node); } } return false; } @Override public boolean visitCatch(Catch node) { List list = mNodeTypeDetectors.get(Catch.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitCatch(node); } } return false; } @Override public boolean visitCharLiteral(CharLiteral node) { List list = mNodeTypeDetectors.get(CharLiteral.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitCharLiteral(node); } } return false; } @Override public boolean visitClassDeclaration(ClassDeclaration node) { List list = mNodeTypeDetectors.get(ClassDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitClassDeclaration(node); } } return false; } @Override public boolean visitClassLiteral(ClassLiteral node) { List list = mNodeTypeDetectors.get(ClassLiteral.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitClassLiteral(node); } } return false; } @Override public boolean visitComment(Comment node) { List list = mNodeTypeDetectors.get(Comment.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitComment(node); } } return false; } @Override public boolean visitCompilationUnit(CompilationUnit node) { List list = mNodeTypeDetectors.get(CompilationUnit.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitCompilationUnit(node); } } return false; } @Override public boolean visitConstructorDeclaration(ConstructorDeclaration node) { List list = mNodeTypeDetectors.get(ConstructorDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitConstructorDeclaration(node); } } return false; } @Override public boolean visitConstructorInvocation(ConstructorInvocation node) { List list = mNodeTypeDetectors.get(ConstructorInvocation.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitConstructorInvocation(node); } } return false; } @Override public boolean visitContinue(Continue node) { List list = mNodeTypeDetectors.get(Continue.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitContinue(node); } } return false; } @Override public boolean visitDefault(Default node) { List list = mNodeTypeDetectors.get(Default.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitDefault(node); } } return false; } @Override public boolean visitDoWhile(DoWhile node) { List list = mNodeTypeDetectors.get(DoWhile.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitDoWhile(node); } } return false; } @Override public boolean visitEmptyDeclaration(EmptyDeclaration node) { List list = mNodeTypeDetectors.get(EmptyDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitEmptyDeclaration(node); } } return false; } @Override public boolean visitEmptyStatement(EmptyStatement node) { List list = mNodeTypeDetectors.get(EmptyStatement.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitEmptyStatement(node); } } return false; } @Override public boolean visitEnumConstant(EnumConstant node) { List list = mNodeTypeDetectors.get(EnumConstant.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitEnumConstant(node); } } return false; } @Override public boolean visitEnumDeclaration(EnumDeclaration node) { List list = mNodeTypeDetectors.get(EnumDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitEnumDeclaration(node); } } return false; } @Override public boolean visitEnumTypeBody(EnumTypeBody node) { List list = mNodeTypeDetectors.get(EnumTypeBody.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitEnumTypeBody(node); } } return false; } @Override public boolean visitExpressionStatement(ExpressionStatement node) { List list = mNodeTypeDetectors.get(ExpressionStatement.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitExpressionStatement(node); } } return false; } @Override public boolean visitFloatingPointLiteral(FloatingPointLiteral node) { List list = mNodeTypeDetectors.get(FloatingPointLiteral.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitFloatingPointLiteral(node); } } return false; } @Override public boolean visitFor(For node) { List list = mNodeTypeDetectors.get(For.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitFor(node); } } return false; } @Override public boolean visitForEach(ForEach node) { List list = mNodeTypeDetectors.get(ForEach.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitForEach(node); } } return false; } @Override public boolean visitIdentifier(Identifier node) { List list = mNodeTypeDetectors.get(Identifier.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitIdentifier(node); } } return false; } @Override public boolean visitIf(If node) { List list = mNodeTypeDetectors.get(If.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitIf(node); } } return false; } @Override public boolean visitImportDeclaration(ImportDeclaration node) { List list = mNodeTypeDetectors.get(ImportDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitImportDeclaration(node); } } return false; } @Override public boolean visitInlineIfExpression(InlineIfExpression node) { List list = mNodeTypeDetectors.get(InlineIfExpression.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitInlineIfExpression(node); } } return false; } @Override public boolean visitInstanceInitializer(InstanceInitializer node) { List list = mNodeTypeDetectors.get(InstanceInitializer.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitInstanceInitializer(node); } } return false; } @Override public boolean visitInstanceOf(InstanceOf node) { List list = mNodeTypeDetectors.get(InstanceOf.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitInstanceOf(node); } } return false; } @Override public boolean visitIntegralLiteral(IntegralLiteral node) { List list = mNodeTypeDetectors.get(IntegralLiteral.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitIntegralLiteral(node); } } return false; } @Override public boolean visitInterfaceDeclaration(InterfaceDeclaration node) { List list = mNodeTypeDetectors.get(InterfaceDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitInterfaceDeclaration(node); } } return false; } @Override public boolean visitKeywordModifier(KeywordModifier node) { List list = mNodeTypeDetectors.get(KeywordModifier.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitKeywordModifier(node); } } return false; } @Override public boolean visitLabelledStatement(LabelledStatement node) { List list = mNodeTypeDetectors.get(LabelledStatement.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitLabelledStatement(node); } } return false; } @Override public boolean visitMethodDeclaration(MethodDeclaration node) { List list = mNodeTypeDetectors.get(MethodDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitMethodDeclaration(node); } } return false; } @Override public boolean visitMethodInvocation(MethodInvocation node) { List list = mNodeTypeDetectors.get(MethodInvocation.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitMethodInvocation(node); } } return false; } @Override public boolean visitModifiers(Modifiers node) { List list = mNodeTypeDetectors.get(Modifiers.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitModifiers(node); } } return false; } @Override public boolean visitNormalTypeBody(NormalTypeBody node) { List list = mNodeTypeDetectors.get(NormalTypeBody.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitNormalTypeBody(node); } } return false; } @Override public boolean visitNullLiteral(NullLiteral node) { List list = mNodeTypeDetectors.get(NullLiteral.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitNullLiteral(node); } } return false; } @Override public boolean visitPackageDeclaration(PackageDeclaration node) { List list = mNodeTypeDetectors.get(PackageDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitPackageDeclaration(node); } } return false; } @Override public boolean visitParseArtefact(Node node) { List list = mNodeTypeDetectors.get(Node.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitParseArtefact(node); } } return false; } @Override public boolean visitReturn(Return node) { List list = mNodeTypeDetectors.get(Return.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitReturn(node); } } return false; } @Override public boolean visitSelect(Select node) { List list = mNodeTypeDetectors.get(Select.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitSelect(node); } } return false; } @Override public boolean visitStaticInitializer(StaticInitializer node) { List list = mNodeTypeDetectors.get(StaticInitializer.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitStaticInitializer(node); } } return false; } @Override public boolean visitStringLiteral(StringLiteral node) { List list = mNodeTypeDetectors.get(StringLiteral.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitStringLiteral(node); } } return false; } @Override public boolean visitSuper(Super node) { List list = mNodeTypeDetectors.get(Super.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitSuper(node); } } return false; } @Override public boolean visitSuperConstructorInvocation(SuperConstructorInvocation node) { List list = mNodeTypeDetectors.get(SuperConstructorInvocation.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitSuperConstructorInvocation(node); } } return false; } @Override public boolean visitSwitch(Switch node) { List list = mNodeTypeDetectors.get(Switch.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitSwitch(node); } } return false; } @Override public boolean visitSynchronized(Synchronized node) { List list = mNodeTypeDetectors.get(Synchronized.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitSynchronized(node); } } return false; } @Override public boolean visitThis(This node) { List list = mNodeTypeDetectors.get(This.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitThis(node); } } return false; } @Override public boolean visitThrow(Throw node) { List list = mNodeTypeDetectors.get(Throw.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitThrow(node); } } return false; } @Override public boolean visitTry(Try node) { List list = mNodeTypeDetectors.get(Try.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitTry(node); } } return false; } @Override public boolean visitTypeReference(TypeReference node) { List list = mNodeTypeDetectors.get(TypeReference.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitTypeReference(node); } } return false; } @Override public boolean visitTypeReferencePart(TypeReferencePart node) { List list = mNodeTypeDetectors.get(TypeReferencePart.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitTypeReferencePart(node); } } return false; } @Override public boolean visitTypeVariable(TypeVariable node) { List list = mNodeTypeDetectors.get(TypeVariable.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitTypeVariable(node); } } return false; } @Override public boolean visitUnaryExpression(UnaryExpression node) { List list = mNodeTypeDetectors.get(UnaryExpression.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitUnaryExpression(node); } } return false; } @Override public boolean visitVariableDeclaration(VariableDeclaration node) { List list = mNodeTypeDetectors.get(VariableDeclaration.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitVariableDeclaration(node); } } return false; } @Override public boolean visitVariableDefinition(VariableDefinition node) { List list = mNodeTypeDetectors.get(VariableDefinition.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitVariableDefinition(node); } } return false; } @Override public boolean visitVariableDefinitionEntry(VariableDefinitionEntry node) { List list = mNodeTypeDetectors.get(VariableDefinitionEntry.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitVariableDefinitionEntry(node); } } return false; } @Override public boolean visitVariableReference(VariableReference node) { List list = mNodeTypeDetectors.get(VariableReference.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitVariableReference(node); } } return false; } @Override public boolean visitWhile(While node) { List list = mNodeTypeDetectors.get(While.class); if (list != null) { for (VisitingDetector v : list) { v.getVisitor().visitWhile(node); } } return false; } } /** Performs common AST searches for method calls and R-type-field references. * Note that this is a specialized form of the {@link DispatchVisitor}. */ private class DelegatingJavaVisitor extends DispatchVisitor { private final JavaContext mContext; private final boolean mVisitResources; private final boolean mVisitMethods; private final boolean mVisitConstructors; public DelegatingJavaVisitor(JavaContext context) { mContext = context; mVisitMethods = !mMethodDetectors.isEmpty(); mVisitConstructors = !mConstructorDetectors.isEmpty(); mVisitResources = !mResourceFieldDetectors.isEmpty(); } @Override public boolean visitSelect(Select node) { if (mVisitResources) { // R.type.name if (node.astOperand() instanceof Select) { Select select = (Select) node.astOperand(); if (select.astOperand() instanceof VariableReference) { VariableReference reference = (VariableReference) select.astOperand(); if (reference.astIdentifier().astValue().equals(R_CLASS)) { String type = select.astIdentifier().astValue(); String name = node.astIdentifier().astValue(); // R -could- be referenced locally and really have been // imported as "import android.R;" in the import statements, // but this is not recommended (and in fact there's a specific // lint rule warning against it) boolean isFramework = false; for (VisitingDetector v : mResourceFieldDetectors) { JavaScanner detector = v.getJavaScanner(); //noinspection ConstantConditions detector.visitResourceReference(mContext, v.getVisitor(), node, type, name, isFramework); } return super.visitSelect(node); } } } // Arbitrary packages -- android.R.type.name, foo.bar.R.type.name if (node.astIdentifier().astValue().equals(R_CLASS)) { Node parent = node.getParent(); if (parent instanceof Select) { Node grandParent = parent.getParent(); if (grandParent instanceof Select) { Select select = (Select) grandParent; String name = select.astIdentifier().astValue(); Expression typeOperand = select.astOperand(); if (typeOperand instanceof Select) { Select typeSelect = (Select) typeOperand; String type = typeSelect.astIdentifier().astValue(); boolean isFramework = node.astIdentifier().astValue().equals(ANDROID_PKG); for (VisitingDetector v : mResourceFieldDetectors) { JavaScanner detector = v.getJavaScanner(); detector.visitResourceReference(mContext, v.getVisitor(), node, type, name, isFramework); } } } } } } return super.visitSelect(node); } @Override public boolean visitMethodInvocation(MethodInvocation node) { if (mVisitMethods) { String methodName = node.astName().astValue(); List list = mMethodDetectors.get(methodName); if (list != null) { for (VisitingDetector v : list) { v.getJavaScanner().visitMethod(mContext, v.getVisitor(), node); } } } return super.visitMethodInvocation(node); } @Override public boolean visitConstructorInvocation(ConstructorInvocation node) { if (mVisitConstructors) { TypeReference typeReference = node.astTypeReference(); if (typeReference != null) { TypeReferencePart last = typeReference.astParts().last(); if (last != null) { String name = last.astIdentifier().astValue(); if (mConstructorSimpleNames.contains(name)) { ResolvedNode resolved = mContext.resolve(node); if (resolved instanceof ResolvedMethod) { ResolvedMethod method = (ResolvedMethod) resolved; String type = method.getContainingClass().getSignature(); List list = mConstructorDetectors.get(type); if (list != null) { for (VisitingDetector v : list) { v.getJavaScanner().visitConstructor(mContext, v.getVisitor(), node, method); } } } } } } } return super.visitConstructorInvocation(node); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy