Search in sources :

Example 1 with SurroundWithTryWithResourcesAnalyzer

use of org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryWithResourcesAnalyzer in project eclipse.jdt.ls by eclipse.

the class QuickAssistProcessor method getTryWithResourceProposals.

public static boolean getTryWithResourceProposals(IInvocationContext context, ASTNode node, ArrayList<ASTNode> coveredNodes, Collection<ChangeCorrectionProposal> resultingCollections) throws IllegalArgumentException, CoreException {
    if (!JavaModelUtil.is1d8OrHigher(context.getCompilationUnit().getJavaProject())) {
        return false;
    }
    ASTNode parentStatement = ASTResolving.findAncestor(node, ASTNode.VARIABLE_DECLARATION_STATEMENT);
    if (!(parentStatement instanceof VariableDeclarationStatement) && !(parentStatement instanceof ExpressionStatement) && !(node instanceof SimpleName) && (coveredNodes == null || coveredNodes.isEmpty())) {
        return false;
    }
    List<ASTNode> coveredStatements = new ArrayList<>();
    if (coveredNodes == null || coveredNodes.isEmpty() && parentStatement != null) {
        coveredStatements.add(parentStatement);
    } else {
        for (ASTNode coveredNode : coveredNodes) {
            Statement statement = ASTResolving.findParentStatement(coveredNode);
            if (statement == null) {
                continue;
            }
            if (!coveredStatements.contains(statement)) {
                coveredStatements.add(statement);
            }
        }
    }
    List<ASTNode> coveredAutoClosableNodes = QuickAssistProcessorUtil.getCoveredAutoClosableNodes(coveredStatements);
    if (coveredAutoClosableNodes.isEmpty()) {
        return false;
    }
    ASTNode parentBodyDeclaration = (node instanceof Block || node instanceof BodyDeclaration) ? node : ASTNodes.getFirstAncestorOrNull(node, Block.class, BodyDeclaration.class);
    int start = coveredAutoClosableNodes.get(0).getStartPosition();
    int end = start;
    for (ASTNode astNode : coveredAutoClosableNodes) {
        int endPosition = QuickAssistProcessorUtil.findEndPostion(astNode);
        end = Math.max(end, endPosition);
    }
    // recursive loop to find all nodes affected by wrapping in try block
    List<ASTNode> nodesInRange = SurroundWithTryWithResourcesRefactoringCore.findNodesInRange(parentBodyDeclaration, start, end);
    int oldEnd = end;
    while (true) {
        int newEnd = oldEnd;
        for (ASTNode astNode : nodesInRange) {
            int endPosition = QuickAssistProcessorUtil.findEndPostion(astNode);
            newEnd = Math.max(newEnd, endPosition);
        }
        if (newEnd > oldEnd) {
            oldEnd = newEnd;
            nodesInRange = SurroundWithTryWithResourcesRefactoringCore.findNodesInRange(parentBodyDeclaration, start, newEnd);
            continue;
        }
        break;
    }
    nodesInRange.removeAll(coveredAutoClosableNodes);
    CompilationUnit cu = (CompilationUnit) node.getRoot();
    IBuffer buffer = context.getCompilationUnit().getBuffer();
    AST ast = node.getAST();
    ASTRewrite rewrite = ASTRewrite.create(ast);
    boolean modifyExistingTry = false;
    TryStatement newTryStatement = null;
    Block newTryBody = null;
    TryStatement enclosingTry = (TryStatement) ASTResolving.findAncestor(node, ASTNode.TRY_STATEMENT);
    ListRewrite resourcesRewriter = null;
    ListRewrite clausesRewriter = null;
    if (enclosingTry == null || enclosingTry.getBody() == null || enclosingTry.getBody().statements().get(0) != coveredNodes.get(0)) {
        newTryStatement = ast.newTryStatement();
        newTryBody = ast.newBlock();
        newTryStatement.setBody(newTryBody);
    } else {
        modifyExistingTry = true;
        resourcesRewriter = rewrite.getListRewrite(enclosingTry, TryStatement.RESOURCES2_PROPERTY);
        clausesRewriter = rewrite.getListRewrite(enclosingTry, TryStatement.CATCH_CLAUSES_PROPERTY);
    }
    ICompilationUnit icu = context.getCompilationUnit();
    ASTNode lastNode = nodesInRange.isEmpty() ? coveredAutoClosableNodes.get(coveredAutoClosableNodes.size() - 1) : nodesInRange.get(nodesInRange.size() - 1);
    Selection selection = Selection.createFromStartLength(start, lastNode.getStartPosition() - start + lastNode.getLength());
    SurroundWithTryWithResourcesAnalyzer analyzer = new SurroundWithTryWithResourcesAnalyzer(icu, selection);
    cu.accept(analyzer);
    ITypeBinding[] exceptions = analyzer.getExceptions(analyzer.getSelection());
    List<ITypeBinding> allExceptions = new ArrayList<>(Arrays.asList(exceptions));
    int resourceCount = 0;
    for (ASTNode coveredNode : coveredAutoClosableNodes) {
        ASTNode findAncestor = ASTResolving.findAncestor(coveredNode, ASTNode.VARIABLE_DECLARATION_STATEMENT);
        if (findAncestor == null) {
            findAncestor = ASTResolving.findAncestor(coveredNode, ASTNode.ASSIGNMENT);
        }
        if (findAncestor instanceof VariableDeclarationStatement) {
            VariableDeclarationStatement vds = (VariableDeclarationStatement) findAncestor;
            String commentToken = null;
            int extendedStatementStart = cu.getExtendedStartPosition(vds);
            if (vds.getStartPosition() > extendedStatementStart) {
                commentToken = buffer.getText(extendedStatementStart, vds.getStartPosition() - extendedStatementStart);
            }
            Type type = vds.getType();
            ITypeBinding typeBinding = type.resolveBinding();
            if (typeBinding != null) {
                IMethodBinding close = SurroundWithTryWithResourcesRefactoringCore.findAutocloseMethod(typeBinding);
                if (close != null) {
                    for (ITypeBinding exceptionType : close.getExceptionTypes()) {
                        if (!allExceptions.contains(exceptionType)) {
                            allExceptions.add(exceptionType);
                        }
                    }
                }
            }
            String typeName = buffer.getText(type.getStartPosition(), type.getLength());
            for (Object object : vds.fragments()) {
                VariableDeclarationFragment variableDeclarationFragment = (VariableDeclarationFragment) object;
                VariableDeclarationFragment newVariableDeclarationFragment = ast.newVariableDeclarationFragment();
                SimpleName name = variableDeclarationFragment.getName();
                if (commentToken == null) {
                    int extendedStart = cu.getExtendedStartPosition(variableDeclarationFragment);
                    commentToken = buffer.getText(extendedStart, variableDeclarationFragment.getStartPosition() - extendedStart);
                }
                commentToken = Strings.trimTrailingTabsAndSpaces(commentToken);
                newVariableDeclarationFragment.setName(ast.newSimpleName(name.getIdentifier()));
                Expression newExpression = null;
                Expression initializer = variableDeclarationFragment.getInitializer();
                if (initializer == null) {
                    rewrite.remove(coveredNode, null);
                    continue;
                } else {
                    newExpression = (Expression) rewrite.createMoveTarget(initializer);
                }
                newVariableDeclarationFragment.setInitializer(newExpression);
                VariableDeclarationExpression newVariableDeclarationExpression = ast.newVariableDeclarationExpression(newVariableDeclarationFragment);
                newVariableDeclarationExpression.setType((Type) rewrite.createStringPlaceholder(commentToken + typeName, type.getNodeType()));
                resourceCount++;
                if (modifyExistingTry) {
                    resourcesRewriter.insertLast(newVariableDeclarationExpression, null);
                } else {
                    newTryStatement.resources().add(newVariableDeclarationExpression);
                }
                commentToken = null;
            }
        }
    }
    if (resourceCount == 0) {
        return false;
    }
    String label = CorrectionMessages.QuickAssistProcessor_convert_to_try_with_resource;
    LinkedCorrectionProposal proposal = new LinkedCorrectionProposal(label, CodeActionKind.QuickFix, context.getCompilationUnit(), rewrite, IProposalRelevance.SURROUND_WITH_TRY_CATCH);
    ImportRewrite imports = proposal.createImportRewrite(context.getASTRoot());
    ImportRewriteContext importRewriteContext = new ContextSensitiveImportRewriteContext(node, imports);
    CatchClause catchClause = ast.newCatchClause();
    SingleVariableDeclaration decl = ast.newSingleVariableDeclaration();
    String varName = StubUtility.getExceptionVariableName(icu.getJavaProject());
    parentBodyDeclaration.getRoot().accept(analyzer);
    CodeScopeBuilder.Scope scope = CodeScopeBuilder.perform(analyzer.getEnclosingBodyDeclaration(), selection).findScope(selection.getOffset(), selection.getLength());
    scope.setCursor(selection.getOffset());
    String name = scope.createName(varName, false);
    decl.setName(ast.newSimpleName(name));
    List<ITypeBinding> mustRethrowList = new ArrayList<>();
    List<ITypeBinding> catchExceptions = analyzer.calculateCatchesAndRethrows(ASTNodes.filterSubtypes(allExceptions), mustRethrowList);
    List<ITypeBinding> filteredExceptions = ASTNodes.filterSubtypes(catchExceptions);
    if (catchExceptions.size() > 0) {
        // $NON-NLS-1$
        final String GROUP_EXC_NAME = "exc_name";
        // $NON-NLS-1$
        final String GROUP_EXC_TYPE = "exc_type";
        LinkedProposalModelCore linkedProposalModel = new LinkedProposalModelCore();
        int i = 0;
        if (!modifyExistingTry) {
            for (ITypeBinding mustThrow : mustRethrowList) {
                CatchClause newClause = ast.newCatchClause();
                SingleVariableDeclaration newDecl = ast.newSingleVariableDeclaration();
                newDecl.setName(ast.newSimpleName(name));
                Type importType = imports.addImport(mustThrow, ast, importRewriteContext, TypeLocation.EXCEPTION);
                newDecl.setType(importType);
                newClause.setException(newDecl);
                ThrowStatement newThrowStatement = ast.newThrowStatement();
                newThrowStatement.setExpression(ast.newSimpleName(name));
                linkedProposalModel.getPositionGroup(GROUP_EXC_NAME + i, true).addPosition(rewrite.track(decl.getName()), false);
                newClause.getBody().statements().add(newThrowStatement);
                newTryStatement.catchClauses().add(newClause);
                ++i;
            }
        }
        UnionType unionType = ast.newUnionType();
        List<Type> types = unionType.types();
        for (ITypeBinding exception : filteredExceptions) {
            Type type = imports.addImport(exception, ast, importRewriteContext, TypeLocation.EXCEPTION);
            types.add(type);
            linkedProposalModel.getPositionGroup(GROUP_EXC_TYPE + i, true).addPosition(rewrite.track(type), i == 0);
            i++;
        }
        decl.setType(unionType);
        catchClause.setException(decl);
        linkedProposalModel.getPositionGroup(GROUP_EXC_NAME + 0, true).addPosition(rewrite.track(decl.getName()), false);
        Statement st = null;
        // $NON-NLS-1$
        String s = StubUtility.getCatchBodyContent(icu, "Exception", name, coveredNodes.isEmpty() ? node : coveredNodes.get(0), icu.findRecommendedLineSeparator());
        if (s != null) {
            st = (Statement) rewrite.createStringPlaceholder(s, ASTNode.RETURN_STATEMENT);
        }
        if (st != null) {
            catchClause.getBody().statements().add(st);
        }
        if (modifyExistingTry) {
            clausesRewriter.insertLast(catchClause, null);
        } else {
            newTryStatement.catchClauses().add(catchClause);
        }
    }
    if (modifyExistingTry) {
        for (int i = 0; i < coveredAutoClosableNodes.size(); i++) {
            rewrite.remove(coveredAutoClosableNodes.get(i), null);
        }
    } else {
        if (!nodesInRange.isEmpty()) {
            ASTNode firstNode = nodesInRange.get(0);
            ASTNode methodDeclaration = ASTResolving.findAncestor(firstNode, ASTNode.BLOCK);
            ListRewrite listRewrite = rewrite.getListRewrite(methodDeclaration, Block.STATEMENTS_PROPERTY);
            ASTNode createCopyTarget = listRewrite.createMoveTarget(firstNode, nodesInRange.get(nodesInRange.size() - 1));
            rewrite.getListRewrite(newTryBody, Block.STATEMENTS_PROPERTY).insertFirst(createCopyTarget, null);
        }
        // replace first node and delete the rest of selected nodes
        rewrite.replace(coveredAutoClosableNodes.get(0), newTryStatement, null);
        for (int i = 1; i < coveredAutoClosableNodes.size(); i++) {
            rewrite.remove(coveredAutoClosableNodes.get(i), null);
        }
    }
    resultingCollections.add(proposal);
    return true;
}
Also used : IMethodBinding(org.eclipse.jdt.core.dom.IMethodBinding) UnionType(org.eclipse.jdt.core.dom.UnionType) ImportRewrite(org.eclipse.jdt.core.dom.rewrite.ImportRewrite) Selection(org.eclipse.jdt.internal.corext.dom.Selection) SimpleName(org.eclipse.jdt.core.dom.SimpleName) ArrayList(java.util.ArrayList) ListRewrite(org.eclipse.jdt.core.dom.rewrite.ListRewrite) SurroundWithTryWithResourcesAnalyzer(org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryWithResourcesAnalyzer) IBuffer(org.eclipse.jdt.core.IBuffer) TryStatement(org.eclipse.jdt.core.dom.TryStatement) VariableDeclarationFragment(org.eclipse.jdt.core.dom.VariableDeclarationFragment) ITypeBinding(org.eclipse.jdt.core.dom.ITypeBinding) ASTNode(org.eclipse.jdt.core.dom.ASTNode) VariableDeclarationStatement(org.eclipse.jdt.core.dom.VariableDeclarationStatement) ASTRewrite(org.eclipse.jdt.core.dom.rewrite.ASTRewrite) ThrowStatement(org.eclipse.jdt.core.dom.ThrowStatement) CodeScopeBuilder(org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder) CompilationUnit(org.eclipse.jdt.core.dom.CompilationUnit) ICompilationUnit(org.eclipse.jdt.core.ICompilationUnit) ICompilationUnit(org.eclipse.jdt.core.ICompilationUnit) AST(org.eclipse.jdt.core.dom.AST) Statement(org.eclipse.jdt.core.dom.Statement) ThrowStatement(org.eclipse.jdt.core.dom.ThrowStatement) SwitchStatement(org.eclipse.jdt.core.dom.SwitchStatement) ExpressionStatement(org.eclipse.jdt.core.dom.ExpressionStatement) TryStatement(org.eclipse.jdt.core.dom.TryStatement) ReturnStatement(org.eclipse.jdt.core.dom.ReturnStatement) VariableDeclarationStatement(org.eclipse.jdt.core.dom.VariableDeclarationStatement) SingleVariableDeclaration(org.eclipse.jdt.core.dom.SingleVariableDeclaration) VariableDeclarationExpression(org.eclipse.jdt.core.dom.VariableDeclarationExpression) CatchClause(org.eclipse.jdt.core.dom.CatchClause) UnionType(org.eclipse.jdt.core.dom.UnionType) ParameterizedType(org.eclipse.jdt.core.dom.ParameterizedType) QualifiedType(org.eclipse.jdt.core.dom.QualifiedType) PrimitiveType(org.eclipse.jdt.core.dom.PrimitiveType) NameQualifiedType(org.eclipse.jdt.core.dom.NameQualifiedType) ArrayType(org.eclipse.jdt.core.dom.ArrayType) SimpleType(org.eclipse.jdt.core.dom.SimpleType) Type(org.eclipse.jdt.core.dom.Type) ContextSensitiveImportRewriteContext(org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext) LinkedProposalModelCore(org.eclipse.jdt.internal.corext.fix.LinkedProposalModelCore) ImportRewriteContext(org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext) ContextSensitiveImportRewriteContext(org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext) ThisExpression(org.eclipse.jdt.core.dom.ThisExpression) Expression(org.eclipse.jdt.core.dom.Expression) VariableDeclarationExpression(org.eclipse.jdt.core.dom.VariableDeclarationExpression) PostfixExpression(org.eclipse.jdt.core.dom.PostfixExpression) LambdaExpression(org.eclipse.jdt.core.dom.LambdaExpression) PrefixExpression(org.eclipse.jdt.core.dom.PrefixExpression) SwitchExpression(org.eclipse.jdt.core.dom.SwitchExpression) LinkedCorrectionProposal(org.eclipse.jdt.ls.core.internal.corrections.proposals.LinkedCorrectionProposal) ExpressionStatement(org.eclipse.jdt.core.dom.ExpressionStatement) Block(org.eclipse.jdt.core.dom.Block) BodyDeclaration(org.eclipse.jdt.core.dom.BodyDeclaration)

Aggregations

ArrayList (java.util.ArrayList)1 IBuffer (org.eclipse.jdt.core.IBuffer)1 ICompilationUnit (org.eclipse.jdt.core.ICompilationUnit)1 AST (org.eclipse.jdt.core.dom.AST)1 ASTNode (org.eclipse.jdt.core.dom.ASTNode)1 ArrayType (org.eclipse.jdt.core.dom.ArrayType)1 Block (org.eclipse.jdt.core.dom.Block)1 BodyDeclaration (org.eclipse.jdt.core.dom.BodyDeclaration)1 CatchClause (org.eclipse.jdt.core.dom.CatchClause)1 CompilationUnit (org.eclipse.jdt.core.dom.CompilationUnit)1 Expression (org.eclipse.jdt.core.dom.Expression)1 ExpressionStatement (org.eclipse.jdt.core.dom.ExpressionStatement)1 IMethodBinding (org.eclipse.jdt.core.dom.IMethodBinding)1 ITypeBinding (org.eclipse.jdt.core.dom.ITypeBinding)1 LambdaExpression (org.eclipse.jdt.core.dom.LambdaExpression)1 NameQualifiedType (org.eclipse.jdt.core.dom.NameQualifiedType)1 ParameterizedType (org.eclipse.jdt.core.dom.ParameterizedType)1 PostfixExpression (org.eclipse.jdt.core.dom.PostfixExpression)1 PrefixExpression (org.eclipse.jdt.core.dom.PrefixExpression)1 PrimitiveType (org.eclipse.jdt.core.dom.PrimitiveType)1