Search in sources :

Example 6 with CatchTree

use of com.sun.source.tree.CatchTree in project checker-framework by typetools.

the class CFGTranslationPhaseOne method visitTry.

@Override
public Node visitTry(TryTree tree, Void p) {
    List<? extends CatchTree> catches = tree.getCatches();
    BlockTree finallyBlock = tree.getFinallyBlock();
    extendWithNode(new MarkerNode(tree, "start of try statement #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
    List<Pair<TypeMirror, Label>> catchLabels = CollectionsPlume.mapList((CatchTree c) -> {
        return Pair.of(TreeUtils.typeOf(c.getParameter().getType()), new Label());
    }, catches);
    // Store return/break/continue labels, just in case we need them for a finally block.
    TryFinallyScopeCell oldReturnTargetL = returnTargetL;
    TryFinallyScopeCell oldBreakTargetL = breakTargetL;
    Map<Name, Label> oldBreakLabels = breakLabels;
    TryFinallyScopeCell oldContinueTargetL = continueTargetL;
    Map<Name, Label> oldContinueLabels = continueLabels;
    Label finallyLabel = null;
    Label exceptionalFinallyLabel = null;
    if (finallyBlock != null) {
        finallyLabel = new Label();
        exceptionalFinallyLabel = new Label();
        tryStack.pushFrame(new TryFinallyFrame(exceptionalFinallyLabel));
        returnTargetL = new TryFinallyScopeCell();
        breakTargetL = new TryFinallyScopeCell();
        breakLabels = new TryFinallyScopeMap();
        continueTargetL = new TryFinallyScopeCell();
        continueLabels = new TryFinallyScopeMap();
    }
    Label doneLabel = new Label();
    tryStack.pushFrame(new TryCatchFrame(types, catchLabels));
    // Must scan the resources *after* we push frame to tryStack. Otherwise we can lose catch
    // blocks.
    // TODO: Should we handle try-with-resources blocks by also generating code for automatically
    // closing the resources?
    List<? extends Tree> resources = tree.getResources();
    for (Tree resource : resources) {
        scan(resource, p);
    }
    extendWithNode(new MarkerNode(tree, "start of try block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
    scan(tree.getBlock(), p);
    extendWithNode(new MarkerNode(tree, "end of try block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
    extendWithExtendedNode(new UnconditionalJump(CFGBuilder.firstNonNull(finallyLabel, doneLabel)));
    tryStack.popFrame();
    int catchIndex = 0;
    for (CatchTree c : catches) {
        addLabelForNextNode(catchLabels.get(catchIndex).second);
        extendWithNode(new MarkerNode(tree, "start of catch block for " + c.getParameter().getType() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
        scan(c, p);
        extendWithNode(new MarkerNode(tree, "end of catch block for " + c.getParameter().getType() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
        catchIndex++;
        extendWithExtendedNode(new UnconditionalJump(CFGBuilder.firstNonNull(finallyLabel, doneLabel)));
    }
    if (finallyLabel != null) {
        // Reset values before analyzing the finally block!
        tryStack.popFrame();
        {
            // Scan 'finallyBlock' for only 'finallyLabel' (a successful path)
            addLabelForNextNode(finallyLabel);
            extendWithNode(new MarkerNode(tree, "start of finally block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
            scan(finallyBlock, p);
            extendWithNode(new MarkerNode(tree, "end of finally block #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
            extendWithExtendedNode(new UnconditionalJump(doneLabel));
        }
        if (hasExceptionalPath(exceptionalFinallyLabel)) {
            // If an exceptional path exists, scan 'finallyBlock' for 'exceptionalFinallyLabel', and
            // scan copied 'finallyBlock' for 'finallyLabel' (a successful path). If there is no
            // successful path, it will be removed in later phase.
            // TODO: Don't we need a separate finally block for each kind of exception?
            addLabelForNextNode(exceptionalFinallyLabel);
            extendWithNode(new MarkerNode(tree, "start of finally block for Throwable #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
            scan(finallyBlock, p);
            NodeWithExceptionsHolder throwing = extendWithNodeWithException(new MarkerNode(tree, "end of finally block for Throwable #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()), throwableType);
            throwing.setTerminatesExecution(true);
        }
        if (returnTargetL.wasAccessed()) {
            addLabelForNextNode(returnTargetL.peekLabel());
            returnTargetL = oldReturnTargetL;
            extendWithNode(new MarkerNode(tree, "start of finally block for return #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
            scan(finallyBlock, p);
            extendWithNode(new MarkerNode(tree, "end of finally block for return #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
            extendWithExtendedNode(new UnconditionalJump(returnTargetL.accessLabel()));
        } else {
            returnTargetL = oldReturnTargetL;
        }
        if (breakTargetL.wasAccessed()) {
            addLabelForNextNode(breakTargetL.peekLabel());
            breakTargetL = oldBreakTargetL;
            extendWithNode(new MarkerNode(tree, "start of finally block for break #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
            scan(finallyBlock, p);
            extendWithNode(new MarkerNode(tree, "end of finally block for break #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
            extendWithExtendedNode(new UnconditionalJump(breakTargetL.accessLabel()));
        } else {
            breakTargetL = oldBreakTargetL;
        }
        Map<Name, Label> accessedBreakLabels = ((TryFinallyScopeMap) breakLabels).getAccessedNames();
        if (!accessedBreakLabels.isEmpty()) {
            breakLabels = oldBreakLabels;
            for (Map.Entry<Name, Label> access : accessedBreakLabels.entrySet()) {
                addLabelForNextNode(access.getValue());
                extendWithNode(new MarkerNode(tree, "start of finally block for break label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
                scan(finallyBlock, p);
                extendWithNode(new MarkerNode(tree, "end of finally block for break label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
                extendWithExtendedNode(new UnconditionalJump(breakLabels.get(access.getKey())));
            }
        } else {
            breakLabels = oldBreakLabels;
        }
        if (continueTargetL.wasAccessed()) {
            addLabelForNextNode(continueTargetL.peekLabel());
            continueTargetL = oldContinueTargetL;
            extendWithNode(new MarkerNode(tree, "start of finally block for continue #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
            scan(finallyBlock, p);
            extendWithNode(new MarkerNode(tree, "end of finally block for continue #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
            extendWithExtendedNode(new UnconditionalJump(continueTargetL.accessLabel()));
        } else {
            continueTargetL = oldContinueTargetL;
        }
        Map<Name, Label> accessedContinueLabels = ((TryFinallyScopeMap) continueLabels).getAccessedNames();
        if (!accessedContinueLabels.isEmpty()) {
            continueLabels = oldContinueLabels;
            for (Map.Entry<Name, Label> access : accessedContinueLabels.entrySet()) {
                addLabelForNextNode(access.getValue());
                extendWithNode(new MarkerNode(tree, "start of finally block for continue label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
                scan(finallyBlock, p);
                extendWithNode(new MarkerNode(tree, "end of finally block for continue label " + access.getKey() + " #" + TreeUtils.treeUids.get(tree), env.getTypeUtils()));
                extendWithExtendedNode(new UnconditionalJump(continueLabels.get(access.getKey())));
            }
        } else {
            continueLabels = oldContinueLabels;
        }
    }
    addLabelForNextNode(doneLabel);
    return null;
}
Also used : CatchTree(com.sun.source.tree.CatchTree) Name(javax.lang.model.element.Name) MarkerNode(org.checkerframework.dataflow.cfg.node.MarkerNode) BlockTree(com.sun.source.tree.BlockTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) LiteralTree(com.sun.source.tree.LiteralTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) TypeCastTree(com.sun.source.tree.TypeCastTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ForLoopTree(com.sun.source.tree.ForLoopTree) InstanceOfTree(com.sun.source.tree.InstanceOfTree) ParenthesizedTree(com.sun.source.tree.ParenthesizedTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) ThrowTree(com.sun.source.tree.ThrowTree) BlockTree(com.sun.source.tree.BlockTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) ReturnTree(com.sun.source.tree.ReturnTree) ArrayTypeTree(com.sun.source.tree.ArrayTypeTree) LabeledStatementTree(com.sun.source.tree.LabeledStatementTree) UnaryTree(com.sun.source.tree.UnaryTree) VariableTree(com.sun.source.tree.VariableTree) TypeParameterTree(com.sun.source.tree.TypeParameterTree) NewClassTree(com.sun.source.tree.NewClassTree) ParameterizedTypeTree(com.sun.source.tree.ParameterizedTypeTree) BreakTree(com.sun.source.tree.BreakTree) ImportTree(com.sun.source.tree.ImportTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) WildcardTree(com.sun.source.tree.WildcardTree) UnionTypeTree(com.sun.source.tree.UnionTypeTree) ArrayAccessTree(com.sun.source.tree.ArrayAccessTree) AnnotatedTypeTree(com.sun.source.tree.AnnotatedTypeTree) IdentifierTree(com.sun.source.tree.IdentifierTree) CatchTree(com.sun.source.tree.CatchTree) NewArrayTree(com.sun.source.tree.NewArrayTree) ContinueTree(com.sun.source.tree.ContinueTree) CaseTree(com.sun.source.tree.CaseTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) SwitchTree(com.sun.source.tree.SwitchTree) PrimitiveTypeTree(com.sun.source.tree.PrimitiveTypeTree) SynchronizedTree(com.sun.source.tree.SynchronizedTree) AssertTree(com.sun.source.tree.AssertTree) StatementTree(com.sun.source.tree.StatementTree) ModifiersTree(com.sun.source.tree.ModifiersTree) WhileLoopTree(com.sun.source.tree.WhileLoopTree) AnnotationTree(com.sun.source.tree.AnnotationTree) MethodTree(com.sun.source.tree.MethodTree) BinaryTree(com.sun.source.tree.BinaryTree) EmptyStatementTree(com.sun.source.tree.EmptyStatementTree) ClassTree(com.sun.source.tree.ClassTree) IfTree(com.sun.source.tree.IfTree) MemberReferenceTree(com.sun.source.tree.MemberReferenceTree) ErroneousTree(com.sun.source.tree.ErroneousTree) DoWhileLoopTree(com.sun.source.tree.DoWhileLoopTree) TryTree(com.sun.source.tree.TryTree) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap) Pair(org.checkerframework.javacutil.Pair)

Example 7 with CatchTree

use of com.sun.source.tree.CatchTree in project error-prone by google.

the class FindIdentifiers method findAllIdents.

/**
 * Finds the set of all bare variable identifiers in scope at the current location. Identifiers
 * are ordered by ascending distance/scope count from the current location to match shadowing
 * rules. That is, if two variables with the same simple names appear in the set, the one that
 * appears first in iteration order is the one you get if you use the bare name in the source
 * code.
 *
 * <p>We do not report variables that would require a qualfied access. We also do not handle
 * wildcard imports.
 */
public static LinkedHashSet<VarSymbol> findAllIdents(VisitorState state) {
    ImmutableSet.Builder<VarSymbol> result = new ImmutableSet.Builder<>();
    Tree prev = state.getPath().getLeaf();
    for (Tree curr : state.getPath().getParentPath()) {
        switch(curr.getKind()) {
            case BLOCK:
                for (StatementTree stmt : ((BlockTree) curr).getStatements()) {
                    if (stmt.equals(prev)) {
                        break;
                    }
                    addIfVariable(stmt, result);
                }
                break;
            case METHOD:
                for (VariableTree param : ((MethodTree) curr).getParameters()) {
                    result.add(ASTHelpers.getSymbol(param));
                }
                break;
            case CATCH:
                result.add(ASTHelpers.getSymbol(((CatchTree) curr).getParameter()));
                break;
            case CLASS:
            case INTERFACE:
            case ENUM:
            case ANNOTATION_TYPE:
                // field is referred to by qualified name, but we don't support that.
                for (Tree member : ((ClassTree) curr).getMembers()) {
                    if (member.equals(prev)) {
                        break;
                    }
                    addIfVariable(member, result);
                }
                // Collect inherited fields.
                Type classType = ASTHelpers.getType(curr);
                List<Type> classTypeClosure = state.getTypes().closure(classType);
                List<Type> superTypes = classTypeClosure.size() <= 1 ? Collections.emptyList() : classTypeClosure.subList(1, classTypeClosure.size());
                for (Type type : superTypes) {
                    Scope scope = type.tsym.members();
                    ImmutableList.Builder<VarSymbol> varsList = ImmutableList.builder();
                    for (Symbol var : scope.getSymbols(VarSymbol.class::isInstance)) {
                        varsList.add((VarSymbol) var);
                    }
                    result.addAll(varsList.build().reverse());
                }
                break;
            case FOR_LOOP:
                addAllIfVariable(((ForLoopTree) curr).getInitializer(), result);
                break;
            case ENHANCED_FOR_LOOP:
                result.add(ASTHelpers.getSymbol(((EnhancedForLoopTree) curr).getVariable()));
                break;
            case TRY:
                TryTree tryTree = (TryTree) curr;
                boolean inResources = false;
                for (Tree resource : tryTree.getResources()) {
                    if (resource.equals(prev)) {
                        inResources = true;
                        break;
                    }
                }
                if (inResources) {
                    // Case 1: we're in one of the resource declarations
                    for (Tree resource : tryTree.getResources()) {
                        if (resource.equals(prev)) {
                            break;
                        }
                        addIfVariable(resource, result);
                    }
                } else if (tryTree.getBlock().equals(prev)) {
                    // Case 2: We're in the block (not a catch or finally)
                    addAllIfVariable(tryTree.getResources(), result);
                }
                break;
            case COMPILATION_UNIT:
                for (ImportTree importTree : ((CompilationUnitTree) curr).getImports()) {
                    if (importTree.isStatic() && importTree.getQualifiedIdentifier().getKind() == Kind.MEMBER_SELECT) {
                        MemberSelectTree memberSelectTree = (MemberSelectTree) importTree.getQualifiedIdentifier();
                        Scope scope = state.getTypes().membersClosure(ASTHelpers.getType(memberSelectTree.getExpression()), /* skipInterface= */
                        false);
                        for (Symbol var : scope.getSymbols(sym -> sym instanceof VarSymbol && sym.getSimpleName().equals(memberSelectTree.getIdentifier()))) {
                            result.add((VarSymbol) var);
                        }
                    }
                }
                break;
            default:
                // other node types don't introduce variables
                break;
        }
        prev = curr;
    }
    // TODO(eaftan): switch out collector for ImmutableSet.toImmutableSet()
    return result.build().stream().filter(var -> isVisible(var, state.getPath())).collect(Collectors.toCollection(LinkedHashSet::new));
}
Also used : MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassType(com.sun.tools.javac.code.Type.ClassType) Modifier(javax.lang.model.element.Modifier) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) IdentifierTree(com.sun.source.tree.IdentifierTree) CatchTree(com.sun.source.tree.CatchTree) ForLoopTree(com.sun.source.tree.ForLoopTree) Method(java.lang.reflect.Method) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) TreePath(com.sun.source.util.TreePath) ImmutableSet(com.google.common.collect.ImmutableSet) Symbol(com.sun.tools.javac.code.Symbol) Set(java.util.Set) MemberSelectTree(com.sun.source.tree.MemberSelectTree) Env(com.sun.tools.javac.comp.Env) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) JCCompilationUnit(com.sun.tools.javac.tree.JCTree.JCCompilationUnit) TreeScanner(com.sun.source.util.TreeScanner) Objects(java.util.Objects) List(java.util.List) WriteableScope(com.sun.tools.javac.code.Scope.WriteableScope) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) PackageSymbol(com.sun.tools.javac.code.Symbol.PackageSymbol) BlockTree(com.sun.source.tree.BlockTree) StatementTree(com.sun.source.tree.StatementTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) Flags(com.sun.tools.javac.code.Flags) Name(com.sun.tools.javac.util.Name) Scope(com.sun.tools.javac.code.Scope) Type(com.sun.tools.javac.code.Type) MethodTree(com.sun.source.tree.MethodTree) MemberEnter(com.sun.tools.javac.comp.MemberEnter) VariableTree(com.sun.source.tree.VariableTree) AttrContext(com.sun.tools.javac.comp.AttrContext) ArrayList(java.util.ArrayList) VisitorState(com.google.errorprone.VisitorState) BiPredicate(java.util.function.BiPredicate) Kind(com.sun.source.tree.Tree.Kind) ImmutableList(com.google.common.collect.ImmutableList) NewClassTree(com.sun.source.tree.NewClassTree) StreamSupport(java.util.stream.StreamSupport) ImportTree(com.sun.source.tree.ImportTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) LinkedHashSet(java.util.LinkedHashSet) Nullable(javax.annotation.Nullable) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) Enter(com.sun.tools.javac.comp.Enter) ElementKind(javax.lang.model.element.ElementKind) KindSelector(com.sun.tools.javac.code.Kinds.KindSelector) TryTree(com.sun.source.tree.TryTree) Collections(java.util.Collections) Resolve(com.sun.tools.javac.comp.Resolve) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) MethodTree(com.sun.source.tree.MethodTree) CatchTree(com.sun.source.tree.CatchTree) ImmutableList(com.google.common.collect.ImmutableList) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) TypeSymbol(com.sun.tools.javac.code.Symbol.TypeSymbol) Symbol(com.sun.tools.javac.code.Symbol) PackageSymbol(com.sun.tools.javac.code.Symbol.PackageSymbol) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) MemberSelectTree(com.sun.source.tree.MemberSelectTree) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) ClassTree(com.sun.source.tree.ClassTree) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) StatementTree(com.sun.source.tree.StatementTree) ClassType(com.sun.tools.javac.code.Type.ClassType) Type(com.sun.tools.javac.code.Type) ImmutableSet(com.google.common.collect.ImmutableSet) WriteableScope(com.sun.tools.javac.code.Scope.WriteableScope) Scope(com.sun.tools.javac.code.Scope) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) IdentifierTree(com.sun.source.tree.IdentifierTree) CatchTree(com.sun.source.tree.CatchTree) ForLoopTree(com.sun.source.tree.ForLoopTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) BlockTree(com.sun.source.tree.BlockTree) StatementTree(com.sun.source.tree.StatementTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) MethodTree(com.sun.source.tree.MethodTree) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) ImportTree(com.sun.source.tree.ImportTree) Tree(com.sun.source.tree.Tree) ClassTree(com.sun.source.tree.ClassTree) TryTree(com.sun.source.tree.TryTree) BlockTree(com.sun.source.tree.BlockTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) TryTree(com.sun.source.tree.TryTree) ImportTree(com.sun.source.tree.ImportTree)

Example 8 with CatchTree

use of com.sun.source.tree.CatchTree in project error-prone by google.

the class ThreadJoinLoop method matchMethodInvocation.

@Override
public Description matchMethodInvocation(MethodInvocationTree methodInvocationTree, VisitorState visitorState) {
    String threadString;
    if (methodInvocationTree.getMethodSelect() instanceof MemberSelectTree) {
        threadString = ((MemberSelectTree) methodInvocationTree.getMethodSelect()).getExpression().toString();
    } else {
        threadString = "this";
    }
    // with calculating time with declared variables)
    if (!methodInvocationTree.getArguments().isEmpty()) {
        return Description.NO_MATCH;
    }
    if (MATCH_THREAD_JOIN.matches(methodInvocationTree, visitorState)) {
        TreePath treePath = ASTHelpers.findPathFromEnclosingNodeToTopLevel(visitorState.getPath(), TryTree.class);
        if (treePath == null) {
            return Description.NO_MATCH;
        }
        TreePath pathToLoop = ASTHelpers.findPathFromEnclosingNodeToTopLevel(treePath, WhileLoopTree.class);
        // checks to make sure that if there is a while loop with only one statement (the try catch
        // block)
        boolean hasWhileLoopOneStatement = false;
        if (pathToLoop != null) {
            Tree statements = ((WhileLoopTree) pathToLoop.getLeaf()).getStatement();
            if (statements instanceof BlockTree) {
                if (((BlockTree) statements).getStatements().size() == 1) {
                    hasWhileLoopOneStatement = true;
                }
            }
        }
        Type interruptedType = visitorState.getSymtab().interruptedExceptionType;
        Type exceptionType = visitorState.getSymtab().exceptionType;
        TryTree tryTree = (TryTree) treePath.getLeaf();
        // scans the try tree block for any other actions so that we do not accidentally delete
        // important actions when replacing
        TreeScannerMethodInvocations treeScanner = new TreeScannerMethodInvocations();
        treeScanner.scan(tryTree.getBlock(), methodInvocationTree.toString());
        if (treeScanner.count > 0) {
            return Description.NO_MATCH;
        }
        if (tryTree.getFinallyBlock() != null) {
            return Description.NO_MATCH;
        }
        List<? extends CatchTree> catches = tryTree.getCatches();
        for (CatchTree tree : catches) {
            Type typeSym = ASTHelpers.getType(tree.getParameter().getType());
            if (Objects.equals(interruptedType, typeSym) || Objects.equals(exceptionType, typeSym)) {
                List<? extends StatementTree> statementTrees = tree.getBlock().getStatements();
                // replaces the while loop with the try block or replaces just the try block
                if (statementTrees.isEmpty() || (statementTrees.size() == 1 && statementTrees.get(0).toString().equals(";"))) {
                    SuggestedFix.Builder builder = SuggestedFix.builder();
                    builder.replace(hasWhileLoopOneStatement ? pathToLoop.getLeaf() : tryTree, "Uninterruptibles.joinUninterruptibly(" + threadString + ");");
                    builder.addImport("com.google.common.util.concurrent.Uninterruptibles");
                    return describeMatch(methodInvocationTree, builder.build());
                }
            }
        }
    }
    return Description.NO_MATCH;
}
Also used : CatchTree(com.sun.source.tree.CatchTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) Type(com.sun.tools.javac.code.Type) TreePath(com.sun.source.util.TreePath) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) WhileLoopTree(com.sun.source.tree.WhileLoopTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) CatchTree(com.sun.source.tree.CatchTree) Tree(com.sun.source.tree.Tree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) BlockTree(com.sun.source.tree.BlockTree) StatementTree(com.sun.source.tree.StatementTree) TryTree(com.sun.source.tree.TryTree) WhileLoopTree(com.sun.source.tree.WhileLoopTree) BlockTree(com.sun.source.tree.BlockTree) TryTree(com.sun.source.tree.TryTree)

Example 9 with CatchTree

use of com.sun.source.tree.CatchTree in project error-prone by google.

the class ProvidesNull method matchReturn.

/**
 * Matches explicit "return null" statements in methods annotated with {@code @Provides} but not
 * {@code @Nullable}. Suggests either annotating the method with {@code @Nullable} or throwing a
 * {@link RuntimeException} instead.
 */
// TODO(eaftan): Use nullness dataflow analysis when it's ready
@Override
public Description matchReturn(ReturnTree returnTree, VisitorState state) {
    ExpressionTree returnExpression = returnTree.getExpression();
    if (returnExpression == null || returnExpression.getKind() != Kind.NULL_LITERAL) {
        return Description.NO_MATCH;
    }
    TreePath path = state.getPath();
    MethodTree enclosingMethod = null;
    while (true) {
        if (path == null || path.getLeaf() instanceof LambdaExpressionTree) {
            return Description.NO_MATCH;
        } else if (path.getLeaf() instanceof MethodTree) {
            enclosingMethod = (MethodTree) path.getLeaf();
            break;
        } else {
            path = path.getParentPath();
        }
    }
    MethodSymbol enclosingMethodSym = ASTHelpers.getSymbol(enclosingMethod);
    if (enclosingMethodSym == null) {
        return Description.NO_MATCH;
    }
    if (!ASTHelpers.hasAnnotation(enclosingMethodSym, "dagger.Provides", state) || ASTHelpers.hasDirectAnnotationWithSimpleName(enclosingMethodSym, "Nullable")) {
        return Description.NO_MATCH;
    }
    Fix addNullableFix = SuggestedFix.builder().prefixWith(enclosingMethod, "@Nullable\n").addImport("javax.annotation.Nullable").build();
    CatchTree enclosingCatch = ASTHelpers.findEnclosingNode(state.getPath(), CatchTree.class);
    if (enclosingCatch == null) {
        // If not in a catch block, suggest adding @Nullable first, then throwing an exception.
        Fix throwRuntimeExceptionFix = SuggestedFix.replace(returnTree, "throw new RuntimeException();");
        return buildDescription(returnTree).addFix(addNullableFix).addFix(throwRuntimeExceptionFix).build();
    } else {
        // If in a catch block, suggest throwing an exception first, then adding @Nullable.
        String replacement = String.format("throw new RuntimeException(%s);", enclosingCatch.getParameter().getName());
        Fix throwRuntimeExceptionFix = SuggestedFix.replace(returnTree, replacement);
        return buildDescription(returnTree).addFix(throwRuntimeExceptionFix).addFix(addNullableFix).build();
    }
}
Also used : LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) TreePath(com.sun.source.util.TreePath) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) ProvidesFix(com.google.errorprone.BugPattern.ProvidesFix) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) Fix(com.google.errorprone.fixes.Fix) MethodTree(com.sun.source.tree.MethodTree) CatchTree(com.sun.source.tree.CatchTree) ExpressionTree(com.sun.source.tree.ExpressionTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree)

Example 10 with CatchTree

use of com.sun.source.tree.CatchTree in project error-prone by google.

the class CatchFail method deleteFix.

// Extract the argument to a call to assertWithMessage, e.g. in:
// assertWithMessage("message").fail();
Optional<Fix> deleteFix(TryTree tree, ImmutableList<CatchTree> catchBlocks, VisitorState state) {
    SuggestedFix.Builder fix = SuggestedFix.builder();
    if (tree.getFinallyBlock() != null || catchBlocks.size() < tree.getCatches().size()) {
        // If the try statement has a finally region, or other catch blocks, delete only the
        // unnecessary blocks.
        catchBlocks.stream().forEachOrdered(fix::delete);
    } else {
        // The try statement has no finally region and all catch blocks are unnecessary. Replace it
        // with the try statements, deleting all catches.
        List<? extends StatementTree> tryStatements = tree.getBlock().getStatements();
        String source = state.getSourceCode().toString();
        // Replace the full region to work around a GJF partial formatting bug that prevents it from
        // re-indenting unchanged lines. This means that fixes may overlap, but that's (hopefully)
        // unlikely.
        // TODO(b/24140798): emit more precise replacements if GJF is fixed
        fix.replace(tree, source.substring(((JCTree) tryStatements.get(0)).getStartPosition(), state.getEndPosition(Iterables.getLast(tryStatements))));
    }
    MethodTree enclosing = findEnclosing(state.getPath());
    if (enclosing == null) {
        // There isn't an enclosing method, possibly because we're in a lambda or initializer block.
        return Optional.empty();
    }
    if (isExpectedExceptionTest(ASTHelpers.getSymbol(enclosing), state)) {
        // tests, so don't use that fix for methods annotated with @Test(expected=...).
        return Optional.empty();
    }
    // Fix up the enclosing method's throws declaration to include the new thrown exception types.
    Collection<Type> thrownTypes = ASTHelpers.getSymbol(enclosing).getThrownTypes();
    Types types = state.getTypes();
    // Find all types in the deleted catch blocks that are not already in the throws declaration.
    ImmutableList<Type> toThrow = catchBlocks.stream().map(c -> ASTHelpers.getType(c.getParameter())).flatMap(t -> t instanceof UnionClassType ? ImmutableList.copyOf(((UnionClassType) t).getAlternativeTypes()).stream() : Stream.of(t)).filter(t -> thrownTypes.stream().noneMatch(x -> types.isAssignable(t, x))).collect(toImmutableList());
    if (!toThrow.isEmpty()) {
        if (!TEST_CASE.matches(enclosing, state)) {
            // not be a safe local refactoring.
            return Optional.empty();
        }
        String throwsString = toThrow.stream().map(t -> SuggestedFixes.qualifyType(state, fix, t)).distinct().collect(joining(", "));
        if (enclosing.getThrows().isEmpty()) {
            // Add a new throws declaration.
            fix.prefixWith(enclosing.getBody(), "throws " + throwsString);
        } else {
            // Append to an existing throws declaration.
            fix.postfixWith(Iterables.getLast(enclosing.getThrows()), ", " + throwsString);
        }
    }
    return Optional.of(fix.build());
}
Also used : SuggestedFixes(com.google.errorprone.fixes.SuggestedFixes) Iterables(com.google.common.collect.Iterables) Matchers.anyOf(com.google.errorprone.matchers.Matchers.anyOf) MethodSymbol(com.sun.tools.javac.code.Symbol.MethodSymbol) MethodTree(com.sun.source.tree.MethodTree) VisitorState(com.google.errorprone.VisitorState) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) Matchers.expressionStatement(com.google.errorprone.matchers.Matchers.expressionStatement) ImmutableList(com.google.common.collect.ImmutableList) TryTreeMatcher(com.google.errorprone.bugpatterns.BugChecker.TryTreeMatcher) IdentifierTree(com.sun.source.tree.IdentifierTree) CatchTree(com.sun.source.tree.CatchTree) BugPattern(com.google.errorprone.BugPattern) Matcher(com.google.errorprone.matchers.Matcher) Fix(com.google.errorprone.fixes.Fix) Tree(com.sun.source.tree.Tree) MethodNameMatcher(com.google.errorprone.matchers.method.MethodMatchers.MethodNameMatcher) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) TreePath(com.sun.source.util.TreePath) UnionClassType(com.sun.tools.javac.code.Type.UnionClassType) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Matchers.hasAnnotation(com.google.errorprone.matchers.Matchers.hasAnnotation) Collection(java.util.Collection) Compound(com.sun.tools.javac.code.Attribute.Compound) Iterables.getOnlyElement(com.google.common.collect.Iterables.getOnlyElement) NO_MATCH(com.google.errorprone.matchers.Description.NO_MATCH) JCTree(com.sun.tools.javac.tree.JCTree) JUNIT4_TEST_ANNOTATION(com.google.errorprone.matchers.JUnitMatchers.JUNIT4_TEST_ANNOTATION) Collectors.joining(java.util.stream.Collectors.joining) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) JUnitMatchers.isJunit3TestCase(com.google.errorprone.matchers.JUnitMatchers.isJunit3TestCase) TreeScanner(com.sun.source.util.TreeScanner) Objects(java.util.Objects) List(java.util.List) MethodMatchers.staticMethod(com.google.errorprone.matchers.method.MethodMatchers.staticMethod) Types(com.sun.tools.javac.code.Types) Stream(java.util.stream.Stream) JUnitMatchers(com.google.errorprone.matchers.JUnitMatchers) Description(com.google.errorprone.matchers.Description) StatementTree(com.sun.source.tree.StatementTree) TryTree(com.sun.source.tree.TryTree) Optional(java.util.Optional) WARNING(com.google.errorprone.BugPattern.SeverityLevel.WARNING) ProvidesFix(com.google.errorprone.BugPattern.ProvidesFix) SuggestedFix(com.google.errorprone.fixes.SuggestedFix) ASTHelpers(com.google.errorprone.util.ASTHelpers) Type(com.sun.tools.javac.code.Type) UnionClassType(com.sun.tools.javac.code.Type.UnionClassType) Types(com.sun.tools.javac.code.Types) MethodTree(com.sun.source.tree.MethodTree) JCTree(com.sun.tools.javac.tree.JCTree) UnionClassType(com.sun.tools.javac.code.Type.UnionClassType) Type(com.sun.tools.javac.code.Type) SuggestedFix(com.google.errorprone.fixes.SuggestedFix)

Aggregations

CatchTree (com.sun.source.tree.CatchTree)10 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)8 Tree (com.sun.source.tree.Tree)8 MethodTree (com.sun.source.tree.MethodTree)7 TryTree (com.sun.source.tree.TryTree)7 ExpressionTree (com.sun.source.tree.ExpressionTree)6 StatementTree (com.sun.source.tree.StatementTree)6 BlockTree (com.sun.source.tree.BlockTree)5 IdentifierTree (com.sun.source.tree.IdentifierTree)5 MemberSelectTree (com.sun.source.tree.MemberSelectTree)5 VariableTree (com.sun.source.tree.VariableTree)5 TreePath (com.sun.source.util.TreePath)5 ClassTree (com.sun.source.tree.ClassTree)4 EnhancedForLoopTree (com.sun.source.tree.EnhancedForLoopTree)4 ExpressionStatementTree (com.sun.source.tree.ExpressionStatementTree)4 ForLoopTree (com.sun.source.tree.ForLoopTree)4 NewClassTree (com.sun.source.tree.NewClassTree)4 Type (com.sun.tools.javac.code.Type)4 ImmutableList (com.google.common.collect.ImmutableList)3 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)3