/* * Copyright 2011 Google Inc. All Rights Reserved. * * 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.google.errorprone.scanner; import com.google.common.collect.ImmutableMap; import com.google.errorprone.BugPattern; import com.google.errorprone.BugPattern.SeverityLevel; import com.google.errorprone.BugPattern.Suppressibility; import com.google.errorprone.ErrorProneError; import com.google.errorprone.VisitorState; import com.google.errorprone.bugpatterns.BugChecker; import com.google.errorprone.bugpatterns.BugChecker.AnnotatedTypeTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ArrayAccessTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ArrayTypeTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.AssertTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.AssignmentTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.BinaryTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.BlockTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.BreakTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.CaseTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.CatchTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.CompoundAssignmentTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ConditionalExpressionTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ContinueTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.DoWhileLoopTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.EmptyStatementTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.EnhancedForLoopTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ExpressionStatementTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ForLoopTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.IdentifierTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.IfTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ImportTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.InstanceOfTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.IntersectionTypeTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.LabeledStatementTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.LambdaExpressionTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.LiteralTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.MemberReferenceTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.MemberSelectTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ModifiersTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.NewArrayTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.NewClassTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ParameterizedTypeTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ParenthesizedTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.PrimitiveTypeTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ReturnTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.SwitchTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.SynchronizedTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.ThrowTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.TryTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.TypeCastTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.TypeParameterTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.UnaryTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.UnionTypeTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.WhileLoopTreeMatcher; import com.google.errorprone.bugpatterns.BugChecker.WildcardTreeMatcher; import com.google.errorprone.matchers.Suppressible; import com.google.errorprone.util.ASTHelpers; import com.sun.source.tree.AnnotatedTypeTree; import com.sun.source.tree.AnnotationTree; import com.sun.source.tree.ArrayAccessTree; import com.sun.source.tree.ArrayTypeTree; import com.sun.source.tree.AssertTree; import com.sun.source.tree.AssignmentTree; import com.sun.source.tree.BinaryTree; import com.sun.source.tree.BlockTree; import com.sun.source.tree.BreakTree; import com.sun.source.tree.CaseTree; import com.sun.source.tree.CatchTree; import com.sun.source.tree.ClassTree; import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.CompoundAssignmentTree; import com.sun.source.tree.ConditionalExpressionTree; import com.sun.source.tree.ContinueTree; import com.sun.source.tree.DoWhileLoopTree; import com.sun.source.tree.EmptyStatementTree; import com.sun.source.tree.EnhancedForLoopTree; import com.sun.source.tree.ExpressionStatementTree; import com.sun.source.tree.ForLoopTree; import com.sun.source.tree.IdentifierTree; import com.sun.source.tree.IfTree; import com.sun.source.tree.ImportTree; import com.sun.source.tree.InstanceOfTree; import com.sun.source.tree.IntersectionTypeTree; import com.sun.source.tree.LabeledStatementTree; import com.sun.source.tree.LambdaExpressionTree; import com.sun.source.tree.LiteralTree; import com.sun.source.tree.MemberReferenceTree; import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.MethodTree; import com.sun.source.tree.ModifiersTree; import com.sun.source.tree.NewArrayTree; import com.sun.source.tree.NewClassTree; import com.sun.source.tree.ParameterizedTypeTree; import com.sun.source.tree.ParenthesizedTree; import com.sun.source.tree.PrimitiveTypeTree; import com.sun.source.tree.ReturnTree; import com.sun.source.tree.SwitchTree; import com.sun.source.tree.SynchronizedTree; import com.sun.source.tree.ThrowTree; import com.sun.source.tree.TryTree; import com.sun.source.tree.TypeCastTree; import com.sun.source.tree.TypeParameterTree; import com.sun.source.tree.UnaryTree; import com.sun.source.tree.UnionTypeTree; import com.sun.source.tree.VariableTree; import com.sun.source.tree.WhileLoopTree; import com.sun.source.tree.WildcardTree; import com.sun.source.util.TreePath; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * Scans the parsed AST, looking for violations of any of the enabled checks. * @author Alex Eagle (alexeagle@google.com) */ public class ErrorProneScanner extends Scanner { private final Set<Class<? extends Annotation>> customSuppressionAnnotations = new HashSet<>(); private final Map<String, SeverityLevel> severities; /** * Create an error-prone scanner for a non-hardcoded set of checkers. * * @param checkers The checkers that this scanner should use. */ public ErrorProneScanner(BugChecker... checkers) { this(Arrays.asList(checkers)); } private static Map<String, BugPattern.SeverityLevel> defaultSeverities( Iterable<BugChecker> checkers) { ImmutableMap.Builder<String, BugPattern.SeverityLevel> builder = ImmutableMap.builder(); for (BugChecker check : checkers) { builder.put(check.canonicalName(), check.defaultSeverity()); } return builder.build(); } /** * Create an error-prone scanner for a non-hardcoded set of checkers. * * @param checkers The checkers that this scanner should use. */ public ErrorProneScanner(Iterable<BugChecker> checkers) { this(checkers, defaultSeverities(checkers)); } /** * Create an error-prone scanner for a non-hardcoded set of checkers. * * @param checkers The checkers that this scanner should use. * @param severities The default check severities. */ public ErrorProneScanner(Iterable<BugChecker> checkers, Map<String, SeverityLevel> severities) { this.severities = severities; for (BugChecker checker : checkers) { registerNodeTypes(checker); } } @Override protected Set<Class<? extends Annotation>> getCustomSuppressionAnnotations() { return customSuppressionAnnotations; } private final List<AnnotationTreeMatcher> annotationMatchers = new ArrayList<>(); private final List<AnnotatedTypeTreeMatcher> annotatedTypeMatchers = new ArrayList<>(); private final List<ArrayAccessTreeMatcher> arrayAccessMatchers = new ArrayList<>(); private final List<ArrayTypeTreeMatcher> arrayTypeMatchers = new ArrayList<>(); private final List<AssertTreeMatcher> assertMatchers = new ArrayList<>(); private final List<AssignmentTreeMatcher> assignmentMatchers = new ArrayList<>(); private final List<BinaryTreeMatcher> binaryMatchers = new ArrayList<>(); private final List<BlockTreeMatcher> blockMatchers = new ArrayList<>(); private final List<BreakTreeMatcher> breakMatchers = new ArrayList<>(); private final List<CaseTreeMatcher> caseMatchers = new ArrayList<>(); private final List<CatchTreeMatcher> catchMatchers = new ArrayList<>(); private final List<ClassTreeMatcher> classMatchers = new ArrayList<>(); private final List<CompilationUnitTreeMatcher> compilationUnitMatchers = new ArrayList<>(); private final List<CompoundAssignmentTreeMatcher> compoundAssignmentMatchers = new ArrayList<>(); private final List<ConditionalExpressionTreeMatcher> conditionalExpressionMatchers = new ArrayList<>(); private final List<ContinueTreeMatcher> continueMatchers = new ArrayList<>(); private final List<DoWhileLoopTreeMatcher> doWhileLoopMatchers = new ArrayList<>(); private final List<EmptyStatementTreeMatcher> emptyStatementMatchers = new ArrayList<>(); private final List<EnhancedForLoopTreeMatcher> enhancedForLoopMatchers = new ArrayList<>(); private final List<ExpressionStatementTreeMatcher> expressionStatementMatchers = new ArrayList<>(); private final List<ForLoopTreeMatcher> forLoopMatchers = new ArrayList<>(); private final List<IdentifierTreeMatcher> identifierMatchers = new ArrayList<>(); private final List<IfTreeMatcher> ifMatchers = new ArrayList<>(); private final List<ImportTreeMatcher> importMatchers = new ArrayList<>(); private final List<InstanceOfTreeMatcher> instanceOfMatchers = new ArrayList<>(); private final List<IntersectionTypeTreeMatcher> intersectionTypeMatchers = new ArrayList<>(); private final List<LabeledStatementTreeMatcher> labeledStatementMatchers = new ArrayList<>(); private final List<LambdaExpressionTreeMatcher> lambdaExpressionMatchers = new ArrayList<>(); private final List<LiteralTreeMatcher> literalMatchers = new ArrayList<>(); private final List<MemberReferenceTreeMatcher> memberReferenceMatchers = new ArrayList<>(); private final List<MemberSelectTreeMatcher> memberSelectMatchers = new ArrayList<>(); private final List<MethodTreeMatcher> methodMatchers = new ArrayList<>(); private final List<MethodInvocationTreeMatcher> methodInvocationMatchers = new ArrayList<>(); private final List<ModifiersTreeMatcher> modifiersMatchers = new ArrayList<>(); private final List<NewArrayTreeMatcher> newArrayMatchers = new ArrayList<>(); private final List<NewClassTreeMatcher> newClassMatchers = new ArrayList<>(); private final List<ParameterizedTypeTreeMatcher> parameterizedTypeMatchers = new ArrayList<>(); private final List<ParenthesizedTreeMatcher> parenthesizedMatchers = new ArrayList<>(); private final List<PrimitiveTypeTreeMatcher> primitiveTypeMatchers = new ArrayList<>(); private final List<ReturnTreeMatcher> returnMatchers = new ArrayList<>(); private final List<SwitchTreeMatcher> switchMatchers = new ArrayList<>(); private final List<SynchronizedTreeMatcher> synchronizedMatchers = new ArrayList<>(); private final List<ThrowTreeMatcher> throwMatchers = new ArrayList<>(); private final List<TryTreeMatcher> tryMatchers = new ArrayList<>(); private final List<TypeCastTreeMatcher> typeCastMatchers = new ArrayList<>(); private final List<TypeParameterTreeMatcher> typeParameterMatchers = new ArrayList<>(); private final List<UnaryTreeMatcher> unaryMatchers = new ArrayList<>(); private final List<UnionTypeTreeMatcher> unionTypeMatchers = new ArrayList<>(); private final List<VariableTreeMatcher> variableMatchers = new ArrayList<>(); private final List<WhileLoopTreeMatcher> whileLoopMatchers = new ArrayList<>(); private final List<WildcardTreeMatcher> wildcardMatchers = new ArrayList<>(); private void registerNodeTypes(BugChecker checker) { if (checker.suppressibility() == Suppressibility.CUSTOM_ANNOTATION) { customSuppressionAnnotations.addAll(checker.customSuppressionAnnotations()); } if (checker instanceof AnnotationTreeMatcher) { annotationMatchers.add((AnnotationTreeMatcher) checker); } if (checker instanceof AnnotatedTypeTreeMatcher) { annotatedTypeMatchers.add((AnnotatedTypeTreeMatcher) checker); } if (checker instanceof ArrayAccessTreeMatcher) { arrayAccessMatchers.add((ArrayAccessTreeMatcher) checker); } if (checker instanceof ArrayTypeTreeMatcher) { arrayTypeMatchers.add((ArrayTypeTreeMatcher) checker); } if (checker instanceof AssertTreeMatcher) { assertMatchers.add((AssertTreeMatcher) checker); } if (checker instanceof AssignmentTreeMatcher) { assignmentMatchers.add((AssignmentTreeMatcher) checker); } if (checker instanceof BinaryTreeMatcher) { binaryMatchers.add((BinaryTreeMatcher) checker); } if (checker instanceof BlockTreeMatcher) { blockMatchers.add((BlockTreeMatcher) checker); } if (checker instanceof BreakTreeMatcher) { breakMatchers.add((BreakTreeMatcher) checker); } if (checker instanceof CaseTreeMatcher) { caseMatchers.add((CaseTreeMatcher) checker); } if (checker instanceof CatchTreeMatcher) { catchMatchers.add((CatchTreeMatcher) checker); } if (checker instanceof ClassTreeMatcher) { classMatchers.add((ClassTreeMatcher) checker); } if (checker instanceof CompilationUnitTreeMatcher) { compilationUnitMatchers.add((CompilationUnitTreeMatcher) checker); } if (checker instanceof CompoundAssignmentTreeMatcher) { compoundAssignmentMatchers.add((CompoundAssignmentTreeMatcher) checker); } if (checker instanceof ConditionalExpressionTreeMatcher) { conditionalExpressionMatchers.add((ConditionalExpressionTreeMatcher) checker); } if (checker instanceof ContinueTreeMatcher) { continueMatchers.add((ContinueTreeMatcher) checker); } if (checker instanceof DoWhileLoopTreeMatcher) { doWhileLoopMatchers.add((DoWhileLoopTreeMatcher) checker); } if (checker instanceof EmptyStatementTreeMatcher) { emptyStatementMatchers.add((EmptyStatementTreeMatcher) checker); } if (checker instanceof EnhancedForLoopTreeMatcher) { enhancedForLoopMatchers.add((EnhancedForLoopTreeMatcher) checker); } if (checker instanceof ExpressionStatementTreeMatcher) { expressionStatementMatchers.add((ExpressionStatementTreeMatcher) checker); } if (checker instanceof ForLoopTreeMatcher) { forLoopMatchers.add((ForLoopTreeMatcher) checker); } if (checker instanceof IdentifierTreeMatcher) { identifierMatchers.add((IdentifierTreeMatcher) checker); } if (checker instanceof IfTreeMatcher) { ifMatchers.add((IfTreeMatcher) checker); } if (checker instanceof ImportTreeMatcher) { importMatchers.add((ImportTreeMatcher) checker); } if (checker instanceof InstanceOfTreeMatcher) { instanceOfMatchers.add((InstanceOfTreeMatcher) checker); } if (checker instanceof IntersectionTypeTreeMatcher) { intersectionTypeMatchers.add((IntersectionTypeTreeMatcher) checker); } if (checker instanceof LabeledStatementTreeMatcher) { labeledStatementMatchers.add((LabeledStatementTreeMatcher) checker); } if (checker instanceof LambdaExpressionTreeMatcher) { lambdaExpressionMatchers.add((LambdaExpressionTreeMatcher) checker); } if (checker instanceof LiteralTreeMatcher) { literalMatchers.add((LiteralTreeMatcher) checker); } if (checker instanceof MemberReferenceTreeMatcher) { memberReferenceMatchers.add((MemberReferenceTreeMatcher) checker); } if (checker instanceof MemberSelectTreeMatcher) { memberSelectMatchers.add((MemberSelectTreeMatcher) checker); } if (checker instanceof MethodTreeMatcher) { methodMatchers.add((MethodTreeMatcher) checker); } if (checker instanceof MethodInvocationTreeMatcher) { methodInvocationMatchers.add((MethodInvocationTreeMatcher) checker); } if (checker instanceof ModifiersTreeMatcher) { modifiersMatchers.add((ModifiersTreeMatcher) checker); } if (checker instanceof NewArrayTreeMatcher) { newArrayMatchers.add((NewArrayTreeMatcher) checker); } if (checker instanceof NewClassTreeMatcher) { newClassMatchers.add((NewClassTreeMatcher) checker); } if (checker instanceof ParameterizedTypeTreeMatcher) { parameterizedTypeMatchers.add((ParameterizedTypeTreeMatcher) checker); } if (checker instanceof ParenthesizedTreeMatcher) { parenthesizedMatchers.add((ParenthesizedTreeMatcher) checker); } if (checker instanceof PrimitiveTypeTreeMatcher) { primitiveTypeMatchers.add((PrimitiveTypeTreeMatcher) checker); } if (checker instanceof ReturnTreeMatcher) { returnMatchers.add((ReturnTreeMatcher) checker); } if (checker instanceof SwitchTreeMatcher) { switchMatchers.add((SwitchTreeMatcher) checker); } if (checker instanceof SynchronizedTreeMatcher) { synchronizedMatchers.add((SynchronizedTreeMatcher) checker); } if (checker instanceof ThrowTreeMatcher) { throwMatchers.add((ThrowTreeMatcher) checker); } if (checker instanceof TryTreeMatcher) { tryMatchers.add((TryTreeMatcher) checker); } if (checker instanceof TypeCastTreeMatcher) { typeCastMatchers.add((TypeCastTreeMatcher) checker); } if (checker instanceof TypeParameterTreeMatcher) { typeParameterMatchers.add((TypeParameterTreeMatcher) checker); } if (checker instanceof UnaryTreeMatcher) { unaryMatchers.add((UnaryTreeMatcher) checker); } if (checker instanceof UnionTypeTreeMatcher) { unionTypeMatchers.add((UnionTypeTreeMatcher) checker); } if (checker instanceof VariableTreeMatcher) { variableMatchers.add((VariableTreeMatcher) checker); } if (checker instanceof WhileLoopTreeMatcher) { whileLoopMatchers.add((WhileLoopTreeMatcher) checker); } if (checker instanceof WildcardTreeMatcher) { wildcardMatchers.add((WildcardTreeMatcher) checker); } } @Override public Void visitAnnotation(AnnotationTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (AnnotationTreeMatcher matcher : annotationMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchAnnotation(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitAnnotation(tree, state); } @Override public Void visitAnnotatedType(AnnotatedTypeTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (AnnotatedTypeTreeMatcher matcher : annotatedTypeMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchAnnotatedType(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitAnnotatedType(tree, state); } @Override public Void visitArrayAccess(ArrayAccessTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ArrayAccessTreeMatcher matcher : arrayAccessMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchArrayAccess(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitArrayAccess(tree, state); } @Override public Void visitArrayType(ArrayTypeTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ArrayTypeTreeMatcher matcher : arrayTypeMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchArrayType(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitArrayType(tree, state); } @Override public Void visitAssert(AssertTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (AssertTreeMatcher matcher : assertMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchAssert(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitAssert(tree, state); } @Override public Void visitAssignment(AssignmentTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (AssignmentTreeMatcher matcher : assignmentMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchAssignment(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitAssignment(tree, state); } @Override public Void visitBinary(BinaryTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (BinaryTreeMatcher matcher : binaryMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchBinary(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitBinary(tree, state); } @Override public Void visitBlock(BlockTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (BlockTreeMatcher matcher : blockMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchBlock(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitBlock(tree, state); } @Override public Void visitBreak(BreakTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (BreakTreeMatcher matcher : breakMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchBreak(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitBreak(tree, state); } @Override public Void visitCase(CaseTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (CaseTreeMatcher matcher : caseMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchCase(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitCase(tree, state); } @Override public Void visitCatch(CatchTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (CatchTreeMatcher matcher : catchMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchCatch(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitCatch(tree, state); } @Override public Void visitClass(ClassTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ClassTreeMatcher matcher : classMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchClass(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitClass(tree, state); } @Override public Void visitCompilationUnit(CompilationUnitTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (CompilationUnitTreeMatcher matcher : compilationUnitMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchCompilationUnit(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitCompilationUnit(tree, state); } @Override public Void visitCompoundAssignment(CompoundAssignmentTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (CompoundAssignmentTreeMatcher matcher : compoundAssignmentMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchCompoundAssignment(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitCompoundAssignment(tree, state); } @Override public Void visitConditionalExpression( ConditionalExpressionTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ConditionalExpressionTreeMatcher matcher : conditionalExpressionMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchConditionalExpression(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitConditionalExpression(tree, state); } @Override public Void visitContinue(ContinueTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ContinueTreeMatcher matcher : continueMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchContinue(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitContinue(tree, state); } @Override public Void visitDoWhileLoop(DoWhileLoopTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (DoWhileLoopTreeMatcher matcher : doWhileLoopMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchDoWhileLoop(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitDoWhileLoop(tree, state); } @Override public Void visitEmptyStatement(EmptyStatementTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (EmptyStatementTreeMatcher matcher : emptyStatementMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchEmptyStatement(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitEmptyStatement(tree, state); } @Override public Void visitEnhancedForLoop(EnhancedForLoopTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (EnhancedForLoopTreeMatcher matcher : enhancedForLoopMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchEnhancedForLoop(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitEnhancedForLoop(tree, state); } // Intentionally skip visitErroneous -- we don't analyze malformed expressions. @Override public Void visitExpressionStatement(ExpressionStatementTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ExpressionStatementTreeMatcher matcher : expressionStatementMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchExpressionStatement(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitExpressionStatement(tree, state); } @Override public Void visitForLoop(ForLoopTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ForLoopTreeMatcher matcher : forLoopMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchForLoop(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitForLoop(tree, state); } @Override public Void visitIdentifier(IdentifierTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (IdentifierTreeMatcher matcher : identifierMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchIdentifier(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitIdentifier(tree, state); } @Override public Void visitIf(IfTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (IfTreeMatcher matcher : ifMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchIf(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitIf(tree, state); } @Override public Void visitImport(ImportTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ImportTreeMatcher matcher : importMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchImport(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitImport(tree, state); } @Override public Void visitInstanceOf(InstanceOfTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (InstanceOfTreeMatcher matcher : instanceOfMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchInstanceOf(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitInstanceOf(tree, state); } @Override public Void visitIntersectionType(IntersectionTypeTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (IntersectionTypeTreeMatcher matcher : intersectionTypeMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchIntersectionType(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitIntersectionType(tree, state); } @Override public Void visitLabeledStatement(LabeledStatementTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (LabeledStatementTreeMatcher matcher : labeledStatementMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchLabeledStatement(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitLabeledStatement(tree, state); } @Override public Void visitLambdaExpression(LambdaExpressionTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (LambdaExpressionTreeMatcher matcher : lambdaExpressionMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchLambdaExpression(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitLambdaExpression(tree, state); } @Override public Void visitLiteral(LiteralTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (LiteralTreeMatcher matcher : literalMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchLiteral(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitLiteral(tree, state); } @Override public Void visitMemberReference(MemberReferenceTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (MemberReferenceTreeMatcher matcher : memberReferenceMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchMemberReference(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitMemberReference(tree, state); } @Override public Void visitMemberSelect(MemberSelectTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (MemberSelectTreeMatcher matcher : memberSelectMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchMemberSelect(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitMemberSelect(tree, state); } @Override public Void visitMethod(MethodTree tree, VisitorState visitorState) { // Ignore synthetic constructors: if (ASTHelpers.isGeneratedConstructor(tree)) { return null; } VisitorState state = visitorState.withPath(getCurrentPath()); for (MethodTreeMatcher matcher : methodMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchMethod(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitMethod(tree, state); } @Override public Void visitMethodInvocation(MethodInvocationTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (MethodInvocationTreeMatcher matcher : methodInvocationMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchMethodInvocation(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitMethodInvocation(tree, state); } @Override public Void visitModifiers(ModifiersTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ModifiersTreeMatcher matcher : modifiersMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchModifiers(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitModifiers(tree, state); } @Override public Void visitNewArray(NewArrayTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (NewArrayTreeMatcher matcher : newArrayMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchNewArray(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitNewArray(tree, state); } @Override public Void visitNewClass(NewClassTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (NewClassTreeMatcher matcher : newClassMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchNewClass(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitNewClass(tree, state); } // Intentionally skip visitOther. It seems to be used only for let expressions, which are // generated by javac to implement autoboxing. We are only interested in source-level constructs. @Override public Void visitParameterizedType(ParameterizedTypeTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ParameterizedTypeTreeMatcher matcher : parameterizedTypeMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchParameterizedType(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitParameterizedType(tree, state); } @Override public Void visitParenthesized(ParenthesizedTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ParenthesizedTreeMatcher matcher : parenthesizedMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchParenthesized(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitParenthesized(tree, state); } @Override public Void visitPrimitiveType(PrimitiveTypeTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (PrimitiveTypeTreeMatcher matcher : primitiveTypeMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchPrimitiveType(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitPrimitiveType(tree, state); } @Override public Void visitReturn(ReturnTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ReturnTreeMatcher matcher : returnMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchReturn(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitReturn(tree, state); } @Override public Void visitSwitch(SwitchTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (SwitchTreeMatcher matcher : switchMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchSwitch(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitSwitch(tree, state); } @Override public Void visitSynchronized(SynchronizedTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (SynchronizedTreeMatcher matcher : synchronizedMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchSynchronized(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitSynchronized(tree, state); } @Override public Void visitThrow(ThrowTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ThrowTreeMatcher matcher : throwMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchThrow(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitThrow(tree, state); } @Override public Void visitTry(TryTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (TryTreeMatcher matcher : tryMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchTry(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitTry(tree, state); } @Override public Void visitTypeCast(TypeCastTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (TypeCastTreeMatcher matcher : typeCastMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchTypeCast(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitTypeCast(tree, state); } @Override public Void visitTypeParameter(TypeParameterTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (TypeParameterTreeMatcher matcher : typeParameterMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchTypeParameter(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitTypeParameter(tree, state); } @Override public Void visitUnary(UnaryTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (UnaryTreeMatcher matcher : unaryMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchUnary(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitUnary(tree, state); } @Override public Void visitUnionType(UnionTypeTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (UnionTypeTreeMatcher matcher : unionTypeMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchUnionType(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitUnionType(tree, state); } @Override public Void visitVariable(VariableTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (VariableTreeMatcher matcher : variableMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchVariable(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitVariable(tree, state); } @Override public Void visitWhileLoop(WhileLoopTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (WhileLoopTreeMatcher matcher : whileLoopMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchWhileLoop(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitWhileLoop(tree, state); } @Override public Void visitWildcard(WildcardTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (WildcardTreeMatcher matcher : wildcardMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchWildcard(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitWildcard(tree, state); } /** * Handles an exception thrown by an individual BugPattern. By default, wraps the exception in an * {@link ErrorProneError} and rethrows. May be overridden by subclasses, for example to log the * error and continue. */ @Override protected void handleError(Suppressible s, Throwable t) { if (t instanceof ErrorProneError) { throw (ErrorProneError) t; } TreePath path = getCurrentPath(); throw new ErrorProneError( s.canonicalName(), t, (DiagnosticPosition) path.getLeaf(), path.getCompilationUnit().getSourceFile()); } @Override public Map<String, SeverityLevel> severityMap() { return severities; } }