| /******************************************************************************* |
| * Copyright (c) 2000, 2006 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Konstantin Scheglov (scheglov_ke@nlmk.ru) - initial API and implementation |
| * (reports 71244 & 74746: New Quick Assist's [quick assist]) |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.ui.text.correction; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.CoreException; |
| |
| import org.eclipse.swt.graphics.Image; |
| |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.NamingConventions; |
| import org.eclipse.jdt.core.dom.AST; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.Assignment; |
| import org.eclipse.jdt.core.dom.Block; |
| import org.eclipse.jdt.core.dom.BooleanLiteral; |
| import org.eclipse.jdt.core.dom.BreakStatement; |
| import org.eclipse.jdt.core.dom.CastExpression; |
| import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; |
| import org.eclipse.jdt.core.dom.ClassInstanceCreation; |
| import org.eclipse.jdt.core.dom.ConditionalExpression; |
| import org.eclipse.jdt.core.dom.ConstructorInvocation; |
| import org.eclipse.jdt.core.dom.ContinueStatement; |
| import org.eclipse.jdt.core.dom.DoStatement; |
| import org.eclipse.jdt.core.dom.EnumConstantDeclaration; |
| import org.eclipse.jdt.core.dom.Expression; |
| import org.eclipse.jdt.core.dom.ExpressionStatement; |
| import org.eclipse.jdt.core.dom.ForStatement; |
| import org.eclipse.jdt.core.dom.IBinding; |
| import org.eclipse.jdt.core.dom.IPackageBinding; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jdt.core.dom.IVariableBinding; |
| import org.eclipse.jdt.core.dom.IfStatement; |
| import org.eclipse.jdt.core.dom.InfixExpression; |
| import org.eclipse.jdt.core.dom.InstanceofExpression; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| import org.eclipse.jdt.core.dom.MethodInvocation; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.ParenthesizedExpression; |
| import org.eclipse.jdt.core.dom.PostfixExpression; |
| import org.eclipse.jdt.core.dom.PrefixExpression; |
| import org.eclipse.jdt.core.dom.PrimitiveType; |
| import org.eclipse.jdt.core.dom.QualifiedName; |
| import org.eclipse.jdt.core.dom.ReturnStatement; |
| import org.eclipse.jdt.core.dom.SimpleName; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.Statement; |
| import org.eclipse.jdt.core.dom.StringLiteral; |
| import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; |
| import org.eclipse.jdt.core.dom.SuperConstructorInvocation; |
| import org.eclipse.jdt.core.dom.SuperMethodInvocation; |
| import org.eclipse.jdt.core.dom.SwitchCase; |
| import org.eclipse.jdt.core.dom.SwitchStatement; |
| import org.eclipse.jdt.core.dom.Type; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.jdt.core.dom.VariableDeclarationStatement; |
| import org.eclipse.jdt.core.dom.WhileStatement; |
| import org.eclipse.jdt.core.dom.InfixExpression.Operator; |
| import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; |
| import org.eclipse.jdt.core.dom.rewrite.ListRewrite; |
| |
| import org.eclipse.jdt.internal.corext.dom.ASTNodes; |
| import org.eclipse.jdt.internal.corext.dom.GenericVisitor; |
| import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder; |
| import org.eclipse.jdt.internal.corext.fix.ExpressionsFix; |
| import org.eclipse.jdt.internal.corext.fix.IFix; |
| import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| |
| import org.eclipse.jdt.ui.text.java.IInvocationContext; |
| import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; |
| import org.eclipse.jdt.ui.text.java.IProblemLocation; |
| import org.eclipse.jdt.ui.text.java.IQuickAssistProcessor; |
| |
| import org.eclipse.jdt.internal.ui.JavaPluginImages; |
| import org.eclipse.jdt.internal.ui.fix.ExpressionsCleanUp; |
| |
| /** |
| */ |
| public class AdvancedQuickAssistProcessor implements IQuickAssistProcessor { |
| public AdvancedQuickAssistProcessor() { |
| super(); |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.ui.text.correction.IAssistProcessor#hasAssists(org.eclipse.jdt.internal.ui.text.correction.IAssistContext) |
| */ |
| public boolean hasAssists(IInvocationContext context) throws CoreException { |
| ASTNode coveringNode = context.getCoveringNode(); |
| if (coveringNode != null) { |
| ArrayList coveredNodes= getFullyCoveredNodes(context, coveringNode); |
| return getInverseIfProposals(context, coveringNode, null) |
| || getIfReturnIntoIfElseAtEndOfVoidMethodProposals(context, coveringNode, null) |
| || getInverseIfContinueIntoIfThenInLoopsProposals(context, coveringNode, null) |
| || getInverseIfIntoContinueInLoopsProposals(context, coveringNode, null) |
| || getInverseConditionProposals(context, coveringNode, coveredNodes, null) |
| || getRemoveExtraParenthesisProposals(context, coveringNode, coveredNodes, null) |
| || getAddParanoidalParenthesisProposals(context, coveringNode, coveredNodes, null) |
| || getJoinAndIfStatementsProposals(context, coveringNode, null) |
| || getSplitAndConditionProposals(context, coveringNode, null) |
| || getJoinOrIfStatementsProposals(context, coveringNode, coveredNodes, null) |
| || getSplitOrConditionProposals(context, coveringNode, null) |
| || getInverseConditionalExpressionProposals(context, coveringNode, null) |
| || getExchangeInnerAndOuterIfConditionsProposals(context, coveringNode, null) |
| || getExchangeOperandsProposals(context, coveringNode, null) |
| || getCastAndAssignIfStatementProposals(context, coveringNode, null) |
| || getPickOutStringProposals(context, coveringNode, null) |
| || getReplaceIfElseWithConditionalProposals(context, coveringNode, null) |
| || getReplaceConditionalWithIfElseProposals(context, coveringNode, null) |
| || getInverseLocalVariableProposals(context, coveringNode, null) |
| || getPushNegationDownProposals(context, coveringNode, null) |
| || getPullNegationUpProposals(context, coveringNode, coveredNodes, null) |
| || getJoinIfListInIfElseIfProposals(context, coveringNode, coveredNodes, null) |
| || getConvertSwitchToIfProposals(context, coveringNode, null); |
| } |
| return false; |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.internal.ui.text.correction.IAssistProcessor#getAssists(org.eclipse.jdt.internal.ui.text.correction.IAssistContext, org.eclipse.jdt.internal.ui.text.correction.IProblemLocation[]) |
| */ |
| public IJavaCompletionProposal[] getAssists(IInvocationContext context, IProblemLocation[] locations) |
| throws CoreException { |
| ASTNode coveringNode = context.getCoveringNode(); |
| if (coveringNode != null) { |
| ArrayList coveredNodes = getFullyCoveredNodes(context, coveringNode); |
| ArrayList resultingCollections = new ArrayList(); |
| if (noErrorsAtLocation(locations)) { |
| getInverseIfProposals(context, coveringNode, resultingCollections); |
| getIfReturnIntoIfElseAtEndOfVoidMethodProposals(context, coveringNode, resultingCollections); |
| getInverseIfContinueIntoIfThenInLoopsProposals(context, coveringNode, resultingCollections); |
| getInverseIfIntoContinueInLoopsProposals(context, coveringNode, resultingCollections); |
| getInverseConditionProposals(context, coveringNode, coveredNodes, resultingCollections); |
| getRemoveExtraParenthesisProposals(context, coveringNode, coveredNodes, resultingCollections); |
| getAddParanoidalParenthesisProposals(context, coveringNode, coveredNodes, resultingCollections); |
| getJoinAndIfStatementsProposals(context, coveringNode, resultingCollections); |
| getSplitAndConditionProposals(context, coveringNode, resultingCollections); |
| getJoinOrIfStatementsProposals(context, coveringNode, coveredNodes, resultingCollections); |
| getSplitOrConditionProposals(context, coveringNode, resultingCollections); |
| getInverseConditionalExpressionProposals(context, coveringNode, resultingCollections); |
| getExchangeInnerAndOuterIfConditionsProposals(context, coveringNode, resultingCollections); |
| getExchangeOperandsProposals(context, coveringNode, resultingCollections); |
| getCastAndAssignIfStatementProposals(context, coveringNode, resultingCollections); |
| getPickOutStringProposals(context, coveringNode, resultingCollections); |
| getReplaceIfElseWithConditionalProposals(context, coveringNode, resultingCollections); |
| getReplaceConditionalWithIfElseProposals(context, coveringNode, resultingCollections); |
| getInverseLocalVariableProposals(context, coveringNode, resultingCollections); |
| getPushNegationDownProposals(context, coveringNode, resultingCollections); |
| getPullNegationUpProposals(context, coveringNode, coveredNodes, resultingCollections); |
| getJoinIfListInIfElseIfProposals(context, coveringNode, coveredNodes, resultingCollections); |
| getConvertSwitchToIfProposals(context, coveringNode, resultingCollections); |
| } |
| return (IJavaCompletionProposal[]) resultingCollections.toArray(new IJavaCompletionProposal[resultingCollections.size()]); |
| } |
| return null; |
| } |
| private static boolean noErrorsAtLocation(IProblemLocation[] locations) { |
| if (locations != null) { |
| for (int i = 0; i < locations.length; i++) { |
| if (locations[i].isError()) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| private static boolean getIfReturnIntoIfElseAtEndOfVoidMethodProposals(IInvocationContext context, ASTNode covering, |
| Collection resultingCollections) { |
| Statement coveringStatement = ASTResolving.findParentStatement(covering); |
| if (!(coveringStatement instanceof IfStatement)) { |
| return false; |
| } |
| IfStatement ifStatement = (IfStatement) coveringStatement; |
| if (ifStatement.getElseStatement() != null) { |
| return false; |
| } |
| // 'then' block should have 'return' as last statement |
| Statement thenStatement = ifStatement.getThenStatement(); |
| if (!(thenStatement instanceof Block)) { |
| return false; |
| } |
| Block thenBlock = (Block) thenStatement; |
| List thenStatements = thenBlock.statements(); |
| if (thenStatements.isEmpty() || !(thenStatements.get(thenStatements.size() - 1) instanceof ReturnStatement)) { |
| return false; |
| } |
| // method should return 'void' |
| MethodDeclaration coveringMetod = ASTResolving.findParentMethodDeclaration(covering); |
| if (coveringMetod == null) { |
| return false; |
| } |
| Type returnType = coveringMetod.getReturnType2(); |
| if (!(returnType instanceof PrimitiveType) |
| || ((PrimitiveType) returnType).getPrimitiveTypeCode() != PrimitiveType.VOID) |
| return false; |
| // |
| List statements = coveringMetod.getBody().statements(); |
| int ifIndex = statements.indexOf(ifStatement); |
| if (ifIndex == -1) { |
| return false; |
| } |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast = coveringStatement.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| // remove last 'return' in 'then' block |
| ListRewrite listRewriter = rewrite.getListRewrite(thenBlock, |
| (ChildListPropertyDescriptor) ifStatement.getLocationInParent()); |
| listRewriter.remove((ASTNode) thenStatements.get(thenStatements.size() - 1), null); |
| // prepare original nodes |
| Expression conditionPlaceholder = (Expression) rewrite.createMoveTarget(ifStatement.getExpression()); |
| Statement thenPlaceholder = (Statement) rewrite.createMoveTarget(ifStatement.getThenStatement()); |
| // prepare 'else' block |
| Block elseBlock = ast.newBlock(); |
| for (int i = ifIndex + 1; i < statements.size(); i++) { |
| Statement statement = (Statement) statements.get(i); |
| elseBlock.statements().add(rewrite.createMoveTarget(statement)); |
| } |
| // prepare new 'if' statement |
| IfStatement newIf = ast.newIfStatement(); |
| newIf.setExpression(conditionPlaceholder); |
| newIf.setThenStatement(thenPlaceholder); |
| newIf.setElseStatement(elseBlock); |
| rewrite.replace(ifStatement, newIf, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_convertToIfElse_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), |
| rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static boolean getInverseIfProposals(IInvocationContext context, ASTNode covering, Collection resultingCollections) { |
| Statement coveringStatement = ASTResolving.findParentStatement(covering); |
| if (!(coveringStatement instanceof IfStatement)) { |
| return false; |
| } |
| IfStatement ifStatement = (IfStatement) coveringStatement; |
| if (ifStatement.getElseStatement() == null) { |
| return false; |
| } |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast = coveringStatement.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| Statement thenStatement= ifStatement.getThenStatement(); |
| Statement elseStatement= ifStatement.getElseStatement(); |
| |
| // prepare original nodes |
| Expression inversedExpression = getInversedBooleanExpression(ast, rewrite, ifStatement.getExpression()); |
| |
| Statement newElseStatement = (Statement) rewrite.createMoveTarget(thenStatement); |
| Statement newThenStatement = (Statement) rewrite.createMoveTarget(elseStatement); |
| // set new nodes |
| rewrite.set(ifStatement, IfStatement.EXPRESSION_PROPERTY, inversedExpression, null); |
| |
| if (elseStatement instanceof IfStatement) {// bug 79507 && bug 74580 |
| Block elseBlock = ast.newBlock(); |
| elseBlock.statements().add(newThenStatement); |
| newThenStatement= elseBlock; |
| } |
| rewrite.set(ifStatement, IfStatement.THEN_STATEMENT_PROPERTY, newThenStatement, null); |
| rewrite.set(ifStatement, IfStatement.ELSE_STATEMENT_PROPERTY, newElseStatement, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_inverseIf_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), |
| rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static boolean getInverseIfContinueIntoIfThenInLoopsProposals(IInvocationContext context, ASTNode covering, |
| Collection resultingCollections) { |
| Statement coveringStatement = ASTResolving.findParentStatement(covering); |
| if (!(coveringStatement instanceof IfStatement)) { |
| return false; |
| } |
| IfStatement ifStatement = (IfStatement) coveringStatement; |
| if (ifStatement.getElseStatement() != null) { |
| return false; |
| } |
| // check that 'then' is 'continue' |
| if (!(ifStatement.getThenStatement() instanceof ContinueStatement)) { |
| return false; |
| } |
| // check that 'if' statement is statement in block that is body of loop |
| Block loopBlock = null; |
| if ((ifStatement.getParent() instanceof Block) && (ifStatement.getParent().getParent() instanceof ForStatement)) { |
| loopBlock = (Block) ifStatement.getParent(); |
| } else if ((ifStatement.getParent() instanceof Block) |
| && (ifStatement.getParent().getParent() instanceof WhileStatement)) { |
| loopBlock = (Block) ifStatement.getParent(); |
| } else { |
| return false; |
| } |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast = coveringStatement.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| // create inversed 'if' statement |
| Expression inversedExpression = getInversedBooleanExpression(ast, rewrite, ifStatement.getExpression()); |
| IfStatement newIf = ast.newIfStatement(); |
| newIf.setExpression(inversedExpression); |
| // prepare 'then' for new 'if' |
| Block thenBlock = ast.newBlock(); |
| int ifIndex = loopBlock.statements().indexOf(ifStatement); |
| for (int i = ifIndex + 1; i < loopBlock.statements().size(); i++) { |
| Statement statement = (Statement) loopBlock.statements().get(i); |
| thenBlock.statements().add(rewrite.createMoveTarget(statement)); |
| } |
| newIf.setThenStatement(thenBlock); |
| // replace 'if' statement in loop |
| rewrite.replace(ifStatement, newIf, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_inverseIfContinue_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), |
| rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static boolean getInverseIfIntoContinueInLoopsProposals(IInvocationContext context, ASTNode covering, |
| Collection resultingCollections) { |
| Statement coveringStatement = ASTResolving.findParentStatement(covering); |
| if (!(coveringStatement instanceof IfStatement)) { |
| return false; |
| } |
| IfStatement ifStatement = (IfStatement) coveringStatement; |
| if (ifStatement.getElseStatement() != null) { |
| return false; |
| } |
| // prepare outer control structure and block that contains 'if' statement |
| ASTNode ifParent = ifStatement.getParent(); |
| Block ifParentBlock = null; |
| ASTNode ifParentStructure = ifParent; |
| if (ifParentStructure instanceof Block) { |
| ifParentBlock = (Block) ifParent; |
| ifParentStructure = ifParentStructure.getParent(); |
| } |
| // check that control structure is loop and 'if' statement if last statement |
| if (!(ifParentStructure instanceof ForStatement) && !(ifParentStructure instanceof WhileStatement)) { |
| return false; |
| } |
| if ((ifParentBlock != null) |
| && (ifParentBlock.statements().indexOf(ifStatement) != ifParentBlock.statements().size() - 1)) { |
| return false; |
| } |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast = coveringStatement.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| // create inversed 'if' statement |
| Expression inversedExpression = getInversedBooleanExpression(ast, rewrite, ifStatement.getExpression()); |
| IfStatement newIf = ast.newIfStatement(); |
| newIf.setExpression(inversedExpression); |
| newIf.setThenStatement(ast.newContinueStatement()); |
| // |
| if (ifParentBlock == null) { |
| // if there is no block, create it |
| ifParentBlock = ast.newBlock(); |
| ifParentBlock.statements().add(newIf); |
| for (Iterator I = getUnwrappedStatements(ifStatement.getThenStatement()).iterator(); I.hasNext();) { |
| Statement statement = (Statement) I.next(); |
| ifParentBlock.statements().add(rewrite.createMoveTarget(statement)); |
| } |
| // replace 'if' statement as body with new block |
| if (ifParentStructure instanceof ForStatement) { |
| rewrite.set(ifParentStructure, ForStatement.BODY_PROPERTY, ifParentBlock, null); |
| } else if (ifParentStructure instanceof WhileStatement) { |
| rewrite.set(ifParentStructure, WhileStatement.BODY_PROPERTY, ifParentBlock, null); |
| } |
| } else { |
| // if there was block, replace |
| ListRewrite listRewriter = rewrite.getListRewrite(ifParentBlock, |
| (ChildListPropertyDescriptor) ifStatement.getLocationInParent()); |
| listRewriter.replace(ifStatement, newIf, null); |
| // add statements from 'then' to the end of block |
| for (Iterator I = getUnwrappedStatements(ifStatement.getThenStatement()).iterator(); I.hasNext();) { |
| Statement statement = (Statement) I.next(); |
| listRewriter.insertLast(rewrite.createMoveTarget(statement), null); |
| } |
| } |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_inverseIfToContinue_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), |
| rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static ArrayList getUnwrappedStatements(Statement body) { |
| ArrayList statements = new ArrayList(); |
| if (body instanceof Block) { |
| for (Iterator I = ((Block) body).statements().iterator(); I.hasNext();) { |
| Statement statement = (Statement) I.next(); |
| statements.add(statement); |
| } |
| } else { |
| statements.add(body); |
| } |
| return statements; |
| } |
| private static boolean getInverseConditionProposals(IInvocationContext context, ASTNode covering, ArrayList coveredNodes, Collection resultingCollections) { |
| if (coveredNodes.isEmpty()) { |
| return false; |
| } |
| // |
| final AST ast = covering.getAST(); |
| final ASTRewrite rewrite = ASTRewrite.create(ast); |
| // check sub-expressions in fully covered nodes |
| boolean hasChanges = false; |
| for (Iterator I = coveredNodes.iterator(); I.hasNext();) { |
| ASTNode covered = (ASTNode) I.next(); |
| Expression coveredExpression= getBooleanExpression(covered); |
| if (coveredExpression != null) { |
| Expression inversedExpression = getInversedBooleanExpression(ast, rewrite, coveredExpression); |
| rewrite.replace(coveredExpression, inversedExpression, null); |
| hasChanges = true; |
| } |
| } |
| // |
| if (!hasChanges) { |
| return false; |
| } |
| if (resultingCollections == null) { |
| return true; |
| } |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_inverseConditions_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), |
| rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static Expression getInversedBooleanExpression(AST ast, ASTRewrite rewrite, Expression expression) { |
| return getInversedBooleanExpression(ast, rewrite, expression, null); |
| } |
| private interface SimpleNameRenameProvider { |
| SimpleName getRenamed(SimpleName name); |
| } |
| private static Expression getRenamedNameCopy(SimpleNameRenameProvider provider, |
| ASTRewrite rewrite, |
| Expression expression) { |
| if (provider != null) { |
| if (expression instanceof SimpleName) { |
| SimpleName name= (SimpleName) expression; |
| SimpleName newName= provider.getRenamed(name); |
| if (newName != null) { |
| return newName; |
| } |
| } |
| } |
| return (Expression) rewrite.createCopyTarget(expression); |
| } |
| private static Expression getInversedBooleanExpression(AST ast, |
| ASTRewrite rewrite, |
| Expression expression, |
| SimpleNameRenameProvider provider) { |
| if (!isBoolean(expression)) { |
| return (Expression) rewrite.createCopyTarget(expression); |
| } |
| // |
| if (expression instanceof BooleanLiteral) { |
| BooleanLiteral booleanLiteral= (BooleanLiteral) expression; |
| if (booleanLiteral.booleanValue()) { |
| return ast.newBooleanLiteral(false); |
| } else { |
| return ast.newBooleanLiteral(true); |
| } |
| } |
| if (expression instanceof InfixExpression) { |
| InfixExpression infixExpression= (InfixExpression) expression; |
| InfixExpression.Operator operator= infixExpression.getOperator(); |
| if (operator == InfixExpression.Operator.LESS) { |
| return getInversedInfixBooleanExpression(ast, |
| rewrite, |
| infixExpression, |
| InfixExpression.Operator.GREATER_EQUALS, |
| provider); |
| } |
| if (operator == InfixExpression.Operator.GREATER) { |
| return getInversedInfixBooleanExpression(ast, |
| rewrite, |
| infixExpression, |
| InfixExpression.Operator.LESS_EQUALS, |
| provider); |
| } |
| if (operator == InfixExpression.Operator.LESS_EQUALS) { |
| return getInversedInfixBooleanExpression(ast, |
| rewrite, |
| infixExpression, |
| InfixExpression.Operator.GREATER, |
| provider); |
| } |
| if (operator == InfixExpression.Operator.GREATER_EQUALS) { |
| return getInversedInfixBooleanExpression(ast, |
| rewrite, |
| infixExpression, |
| InfixExpression.Operator.LESS, |
| provider); |
| } |
| if (operator == InfixExpression.Operator.EQUALS) { |
| return getInversedInfixBooleanExpression(ast, |
| rewrite, |
| infixExpression, |
| InfixExpression.Operator.NOT_EQUALS, |
| provider); |
| } |
| if (operator == InfixExpression.Operator.NOT_EQUALS) { |
| return getInversedInfixBooleanExpression(ast, |
| rewrite, |
| infixExpression, |
| InfixExpression.Operator.EQUALS, |
| provider); |
| } |
| if (operator == InfixExpression.Operator.CONDITIONAL_AND) { |
| Operator newOperator= InfixExpression.Operator.CONDITIONAL_OR; |
| return getInversedAndOrExpression(ast, rewrite, infixExpression, newOperator, provider); |
| } |
| if (operator == InfixExpression.Operator.CONDITIONAL_OR) { |
| Operator newOperator= InfixExpression.Operator.CONDITIONAL_AND; |
| return getInversedAndOrExpression(ast, rewrite, infixExpression, newOperator, provider); |
| } |
| if (operator == InfixExpression.Operator.AND) { |
| Operator newOperator= InfixExpression.Operator.OR; |
| return getInversedAndOrExpression(ast, rewrite, infixExpression, newOperator, provider); |
| } |
| if (operator == InfixExpression.Operator.OR) { |
| Operator newOperator= InfixExpression.Operator.AND; |
| return getInversedAndOrExpression(ast, rewrite, infixExpression, newOperator, provider); |
| } |
| } |
| if (expression instanceof PrefixExpression) { |
| PrefixExpression prefixExpression= (PrefixExpression) expression; |
| if (prefixExpression.getOperator() == PrefixExpression.Operator.NOT) { |
| return getRenamedNameCopy(provider, rewrite, prefixExpression.getOperand()); |
| } |
| } |
| if (expression instanceof InstanceofExpression) { |
| PrefixExpression prefixExpression= ast.newPrefixExpression(); |
| prefixExpression.setOperator(PrefixExpression.Operator.NOT); |
| ParenthesizedExpression parenthesizedExpression= ast.newParenthesizedExpression(); |
| parenthesizedExpression.setExpression((Expression) rewrite.createCopyTarget(expression)); |
| prefixExpression.setOperand(parenthesizedExpression); |
| return prefixExpression; |
| } |
| if (expression instanceof ParenthesizedExpression) { |
| ParenthesizedExpression parenthesizedExpression= (ParenthesizedExpression) expression; |
| Expression innerExpression= parenthesizedExpression.getExpression(); |
| while (innerExpression instanceof ParenthesizedExpression) { |
| innerExpression= ((ParenthesizedExpression) innerExpression).getExpression(); |
| } |
| if (innerExpression instanceof InstanceofExpression) { |
| return getInversedBooleanExpression(ast, rewrite, innerExpression, provider); |
| } |
| parenthesizedExpression= ast.newParenthesizedExpression(); |
| parenthesizedExpression.setExpression(getInversedBooleanExpression(ast, rewrite, innerExpression, provider)); |
| return parenthesizedExpression; |
| } |
| // |
| PrefixExpression prefixExpression= ast.newPrefixExpression(); |
| prefixExpression.setOperator(PrefixExpression.Operator.NOT); |
| prefixExpression.setOperand(getRenamedNameCopy(provider, rewrite, expression)); |
| return prefixExpression; |
| } |
| private static boolean isBoolean(Expression expression) { |
| return expression.resolveTypeBinding() == expression.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$ |
| } |
| private static Expression getInversedInfixBooleanExpression(AST ast, ASTRewrite rewrite, |
| InfixExpression expression, InfixExpression.Operator newOperator, SimpleNameRenameProvider provider) { |
| InfixExpression newExpression = ast.newInfixExpression(); |
| newExpression.setOperator(newOperator); |
| newExpression.setLeftOperand(getInversedBooleanExpression(ast, rewrite, expression.getLeftOperand(), provider)); |
| newExpression.setRightOperand(getInversedBooleanExpression(ast, rewrite, expression.getRightOperand(), provider)); |
| return newExpression; |
| } |
| private static Expression getInversedAndOrExpression(AST ast, ASTRewrite rewrite, InfixExpression infixExpression, |
| Operator newOperator, SimpleNameRenameProvider provider) { |
| int newOperatorPrecedence = getInfixOperatorPrecedence(newOperator); |
| // |
| Expression leftOperand = getInversedBooleanExpression(ast, rewrite, infixExpression.getLeftOperand(), provider); |
| int leftPrecedence = getExpressionPrecedence(leftOperand); |
| if (newOperatorPrecedence < leftPrecedence) { |
| leftOperand = getParenthesizedExpression(ast, leftOperand); |
| } |
| // |
| Expression rightOperand = getInversedBooleanExpression(ast, rewrite, infixExpression.getRightOperand(), provider); |
| int rightPrecedence = getExpressionPrecedence(rightOperand); |
| if (newOperatorPrecedence < rightPrecedence) { |
| rightOperand = getParenthesizedExpression(ast, rightOperand); |
| } |
| // |
| InfixExpression newExpression = ast.newInfixExpression(); |
| newExpression.setOperator(newOperator); |
| newExpression.setLeftOperand(leftOperand); |
| newExpression.setRightOperand(rightOperand); |
| return newExpression; |
| } |
| private static boolean getRemoveExtraParenthesisProposals(IInvocationContext context, ASTNode covering, ArrayList coveredNodes, |
| Collection resultingCollections) { |
| ArrayList nodes; |
| if ((context.getSelectionLength() == 0) && (covering instanceof ParenthesizedExpression)) { |
| nodes = new ArrayList(); |
| nodes.add(covering); |
| } else { |
| nodes= coveredNodes; |
| } |
| if (nodes.isEmpty()) |
| return false; |
| |
| IFix fix= ExpressionsFix.createRemoveUnnecessaryParenthesisFix(context.getASTRoot(), (ASTNode[])nodes.toArray(new ASTNode[nodes.size()])); |
| if (fix == null) |
| return false; |
| |
| if (resultingCollections == null) |
| return true; |
| |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_REMOVE); |
| FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new ExpressionsCleanUp(ExpressionsCleanUp.REMOVE_UNNECESSARY_PARENTHESIS), 1, image, context); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static int getExpressionPrecedence(Expression expression) { |
| if (expression instanceof PostfixExpression) { |
| return 0; |
| } |
| if (expression instanceof PrefixExpression) { |
| return 1; |
| } |
| if ((expression instanceof ClassInstanceCreation) || (expression instanceof CastExpression)) { |
| return 2; |
| } |
| if (expression instanceof InfixExpression) { |
| InfixExpression infixExpression = (InfixExpression) expression; |
| InfixExpression.Operator operator = infixExpression.getOperator(); |
| return getInfixOperatorPrecedence(operator); |
| } |
| if (expression instanceof InstanceofExpression) { |
| return 6; |
| } |
| if (expression instanceof ConditionalExpression) { |
| return 13; |
| } |
| if (expression instanceof Assignment) { |
| return 14; |
| } |
| if (expression instanceof MethodInvocation) { |
| return 15; |
| } |
| return -1; |
| } |
| private static int getInfixOperatorPrecedence(InfixExpression.Operator operator) { |
| if ((operator == InfixExpression.Operator.TIMES) || (operator == InfixExpression.Operator.DIVIDE) |
| || (operator == InfixExpression.Operator.REMAINDER)) { |
| return 3; |
| } |
| if ((operator == InfixExpression.Operator.PLUS) || (operator == InfixExpression.Operator.MINUS)) { |
| return 4; |
| } |
| if ((operator == InfixExpression.Operator.LEFT_SHIFT) |
| || (operator == InfixExpression.Operator.RIGHT_SHIFT_SIGNED) |
| || (operator == InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED)) { |
| return 5; |
| } |
| if ((operator == InfixExpression.Operator.LESS) || (operator == InfixExpression.Operator.GREATER) |
| || (operator == InfixExpression.Operator.LESS_EQUALS) |
| || (operator == InfixExpression.Operator.GREATER_EQUALS)) { |
| return 6; |
| } |
| if ((operator == InfixExpression.Operator.EQUALS) || (operator == InfixExpression.Operator.NOT_EQUALS)) { |
| return 7; |
| } |
| if (operator == InfixExpression.Operator.AND) { |
| return 8; |
| } |
| if (operator == InfixExpression.Operator.XOR) { |
| return 9; |
| } |
| if (operator == InfixExpression.Operator.OR) { |
| return 10; |
| } |
| if (operator == InfixExpression.Operator.CONDITIONAL_AND) { |
| return 11; |
| } |
| if (operator == InfixExpression.Operator.CONDITIONAL_OR) { |
| return 12; |
| } |
| return -1; |
| } |
| |
| private static boolean getAddParanoidalParenthesisProposals(IInvocationContext context, ASTNode covering, ArrayList coveredNodes, |
| Collection resultingCollections) throws CoreException { |
| |
| IFix fix= ExpressionsFix.createAddParanoidalParenthesisFix(context.getASTRoot(), (ASTNode[])coveredNodes.toArray(new ASTNode[coveredNodes.size()])); |
| if (fix == null) |
| return false; |
| |
| if (resultingCollections == null) |
| return true; |
| |
| // add correction proposal |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new ExpressionsCleanUp(ExpressionsCleanUp.ADD_PARANOIC_PARENTHESIS), 1, image, context); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| |
| private static ArrayList getFullyCoveredNodes(IInvocationContext context, ASTNode coveringNode) { |
| final ArrayList coveredNodes = new ArrayList(); |
| final int selectionBegin = context.getSelectionOffset(); |
| final int selectionEnd = selectionBegin + context.getSelectionLength(); |
| coveringNode.accept(new GenericVisitor() { |
| protected boolean visitNode(ASTNode node) { |
| int nodeStart= node.getStartPosition(); |
| int nodeEnd= nodeStart + node.getLength(); |
| // if node does not intersects with selection, don't visit children |
| if (nodeEnd < selectionBegin || selectionEnd < nodeStart) { |
| return false; |
| } |
| // if node is fully covered, we don't need to visit children |
| if (isCovered(node)) { |
| ASTNode parent = node.getParent(); |
| if ((parent == null) || !isCovered(parent)) { |
| coveredNodes.add(node); |
| return false; |
| } |
| } |
| // if node only partly intersects with selection, we try to find fully covered children |
| return true; |
| } |
| private boolean isCovered(ASTNode node) { |
| int begin = node.getStartPosition(); |
| int end = begin + node.getLength(); |
| return (begin >= selectionBegin) && (end <= selectionEnd); |
| } |
| }); |
| return coveredNodes; |
| } |
| private static boolean getJoinAndIfStatementsProposals(IInvocationContext context, ASTNode node, |
| Collection resultingCollections) { |
| Operator andOperator = InfixExpression.Operator.CONDITIONAL_AND; |
| boolean result = false; |
| // |
| Statement statement = ASTResolving.findParentStatement(node); |
| if (!(statement instanceof IfStatement)) { |
| return false; |
| } |
| IfStatement ifStatement = (IfStatement) statement; |
| if (ifStatement.getElseStatement() != null) { |
| return false; |
| } |
| // case when current IfStatement is sole child of another IfStatement |
| { |
| IfStatement outerIf = null; |
| if (ifStatement.getParent() instanceof IfStatement) { |
| outerIf = (IfStatement) ifStatement.getParent(); |
| } else if (ifStatement.getParent() instanceof Block) { |
| Block block = (Block) ifStatement.getParent(); |
| if ((block.getParent() instanceof IfStatement) && (block.statements().size() == 1)) { |
| outerIf = (IfStatement) block.getParent(); |
| } |
| } |
| if ((outerIf != null) && (outerIf.getElseStatement() == null)) { |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast = statement.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| // prepare condition parts, add parenthesis if needed |
| Expression outerCondition = getParenthesizedForAndIfNeeded(ast, rewrite, outerIf.getExpression()); |
| Expression innerCondition = getParenthesizedForAndIfNeeded(ast, rewrite, ifStatement.getExpression()); |
| // create compound condition |
| InfixExpression condition = ast.newInfixExpression(); |
| condition.setOperator(andOperator); |
| condition.setLeftOperand(outerCondition); |
| condition.setRightOperand(innerCondition); |
| // create new IfStatement |
| IfStatement newIf = ast.newIfStatement(); |
| newIf.setExpression(condition); |
| Statement bodyPlaceholder = (Statement) rewrite.createCopyTarget(ifStatement.getThenStatement()); |
| newIf.setThenStatement(bodyPlaceholder); |
| rewrite.replace(outerIf, newIf, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_joinWithOuter_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, |
| context.getCompilationUnit(), rewrite, 1, image); |
| resultingCollections.add(proposal); |
| result = true; |
| } |
| } |
| // case when current IfStatement has another IfStatement as sole child |
| { |
| IfStatement innerIf = null; |
| if (ifStatement.getThenStatement() instanceof IfStatement) { |
| innerIf = (IfStatement) ifStatement.getThenStatement(); |
| } else if (ifStatement.getThenStatement() instanceof Block) { |
| Block block = (Block) ifStatement.getThenStatement(); |
| if ((block.statements().size() == 1) && (block.statements().get(0) instanceof IfStatement)) { |
| innerIf = (IfStatement) block.statements().get(0); |
| } |
| } |
| if ((innerIf != null) && (innerIf.getElseStatement() == null)) { |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast = statement.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| // prepare condition parts, add parenthesis if needed |
| Expression outerCondition = getParenthesizedForAndIfNeeded(ast, rewrite, ifStatement.getExpression()); |
| Expression innerCondition = getParenthesizedForAndIfNeeded(ast, rewrite, innerIf.getExpression()); |
| // create compound condition |
| InfixExpression condition = ast.newInfixExpression(); |
| condition.setOperator(andOperator); |
| condition.setLeftOperand(outerCondition); |
| condition.setRightOperand(innerCondition); |
| // create new IfStatement |
| IfStatement newIf = ast.newIfStatement(); |
| newIf.setExpression(condition); |
| Statement bodyPlaceholder = (Statement) rewrite.createCopyTarget(innerIf.getThenStatement()); |
| newIf.setThenStatement(bodyPlaceholder); |
| rewrite.replace(ifStatement, newIf, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_joinWithInner_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, |
| context.getCompilationUnit(), rewrite, 1, image); |
| resultingCollections.add(proposal); |
| result = true; |
| } |
| } |
| return result; |
| } |
| private static Expression getParenthesizedForAndIfNeeded(AST ast, ASTRewrite rewrite, Expression expression) { |
| boolean addParentheses = false; |
| int nodeType = expression.getNodeType(); |
| if (nodeType == ASTNode.INFIX_EXPRESSION) { |
| InfixExpression infixExpression = (InfixExpression) expression; |
| addParentheses = infixExpression.getOperator() == InfixExpression.Operator.CONDITIONAL_OR; |
| } else { |
| addParentheses = nodeType == ASTNode.CONDITIONAL_EXPRESSION || nodeType == ASTNode.ASSIGNMENT |
| || nodeType == ASTNode.INSTANCEOF_EXPRESSION; |
| } |
| expression = (Expression) rewrite.createCopyTarget(expression); |
| if (addParentheses) { |
| return getParenthesizedExpression(ast, expression); |
| } |
| return expression; |
| } |
| private static Expression getParenthesizedExpression(AST ast, Expression expression) { |
| ParenthesizedExpression parenthesizedExpression = ast.newParenthesizedExpression(); |
| parenthesizedExpression.setExpression(expression); |
| return parenthesizedExpression; |
| } |
| private static boolean getSplitAndConditionProposals(IInvocationContext context, ASTNode node, |
| Collection resultingCollections) { |
| Operator andOperator = InfixExpression.Operator.CONDITIONAL_AND; |
| // check that user invokes quick assist on infix expression |
| if (!(node instanceof InfixExpression)) { |
| return false; |
| } |
| InfixExpression infixExpression = (InfixExpression) node; |
| if (infixExpression.getOperator() != andOperator) { |
| return false; |
| } |
| int offset= isOperatorSelected(infixExpression, context.getSelectionOffset(), context.getSelectionLength()); |
| if (offset == -1) { |
| return false; |
| } |
| |
| // check that infix expression belongs to IfStatement |
| Statement statement = ASTResolving.findParentStatement(node); |
| if (!(statement instanceof IfStatement)) { |
| return false; |
| } |
| IfStatement ifStatement = (IfStatement) statement; |
| if (ifStatement.getElseStatement() != null) { |
| return false; |
| } |
| // check that infix expression is part of first level && condition of IfStatement |
| InfixExpression topInfixExpression = infixExpression; |
| while ((topInfixExpression.getParent() instanceof InfixExpression) |
| && ((InfixExpression) topInfixExpression.getParent()).getOperator() == andOperator) { |
| topInfixExpression = (InfixExpression) topInfixExpression.getParent(); |
| } |
| if (ifStatement.getExpression() != topInfixExpression) { |
| return false; |
| } |
| // |
| if (resultingCollections == null) { |
| return true; |
| } |
| AST ast = ifStatement.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| |
| // prepare left and right conditions |
| Expression[] newOperands= { null, null }; |
| breakInfixOperationAtOperation(rewrite, topInfixExpression, andOperator, offset, true, newOperands); |
| |
| Expression leftCondition= newOperands[0]; |
| Expression rightCondition= newOperands[1]; |
| |
| // replace condition in inner IfStatement |
| rewrite.set(ifStatement, IfStatement.EXPRESSION_PROPERTY, rightCondition, null); |
| // prepare outter IfStatement |
| IfStatement outerIfStatement = ast.newIfStatement(); |
| outerIfStatement.setExpression(leftCondition); |
| Block outerBlock = ast.newBlock(); |
| outerIfStatement.setThenStatement(outerBlock); |
| ASTNode ifPlaceholder = rewrite.createMoveTarget(ifStatement); |
| outerBlock.statements().add(ifPlaceholder); |
| // replace ifStatement |
| rewrite.replace(ifStatement, outerIfStatement, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_splitAndCondition_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), |
| rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static boolean isSelectingOperator(ASTNode n1, ASTNode n2, int offset, int length) { |
| // between the nodes |
| if (offset + length <= n2.getStartPosition() && offset >= ASTNodes.getExclusiveEnd(n1)) { |
| return true; |
| } |
| // or exactly select the node (but not with infix expressions) |
| if (n1.getStartPosition() == offset && ASTNodes.getExclusiveEnd(n2) == offset + length) { |
| if (n1 instanceof InfixExpression || n2 instanceof InfixExpression) { |
| return false; |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| private static int isOperatorSelected(InfixExpression infixExpression, int offset, int length) { |
| ASTNode left= infixExpression.getLeftOperand(); |
| ASTNode right= infixExpression.getRightOperand(); |
| |
| if (isSelectingOperator(left, right, offset, length)) { |
| return ASTNodes.getExclusiveEnd(left); |
| } |
| List extended= infixExpression.extendedOperands(); |
| for (int i= 0; i < extended.size(); i++) { |
| left= right; |
| right= (ASTNode) extended.get(i); |
| if (isSelectingOperator(left, right, offset, length)) { |
| return ASTNodes.getExclusiveEnd(left); |
| } |
| } |
| return -1; |
| } |
| |
| private static boolean getJoinOrIfStatementsProposals(IInvocationContext context, ASTNode covering, ArrayList coveredNodes, |
| Collection resultingCollections) { |
| Operator orOperator = InfixExpression.Operator.CONDITIONAL_OR; |
| if (coveredNodes.size() < 2) |
| return false; |
| // check that all covered nodes are IfStatement's with same 'then' statement and without 'else' |
| String commonThenSource = null; |
| for (Iterator I = coveredNodes.iterator(); I.hasNext();) { |
| ASTNode node = (ASTNode) I.next(); |
| if (!(node instanceof IfStatement)) |
| return false; |
| // |
| IfStatement ifStatement = (IfStatement) node; |
| if (ifStatement.getElseStatement() != null) |
| return false; |
| // |
| Statement thenStatement = ifStatement.getThenStatement(); |
| try { |
| String thenSource = context.getCompilationUnit().getBuffer().getText(thenStatement.getStartPosition(), |
| thenStatement.getLength()); |
| if (commonThenSource == null) { |
| commonThenSource = thenSource; |
| } else { |
| if (!commonThenSource.equals(thenSource)) |
| return false; |
| } |
| } catch (Throwable e) { |
| return false; |
| } |
| } |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| final AST ast = covering.getAST(); |
| final ASTRewrite rewrite = ASTRewrite.create(ast); |
| // prepare OR'ed condition |
| InfixExpression condition = null; |
| boolean hasRightOperand = false; |
| Statement thenStatement = null; |
| for (Iterator I = coveredNodes.iterator(); I.hasNext();) { |
| IfStatement ifStatement = (IfStatement) I.next(); |
| if (thenStatement == null) |
| thenStatement = (Statement) rewrite.createCopyTarget(ifStatement.getThenStatement()); |
| Expression ifCondition = getParenthesizedForOrIfNeeded(ast, rewrite, ifStatement.getExpression()); |
| if (condition == null) { |
| condition = ast.newInfixExpression(); |
| condition.setOperator(orOperator); |
| condition.setLeftOperand(ifCondition); |
| } else if (!hasRightOperand) { |
| condition.setRightOperand(ifCondition); |
| hasRightOperand = true; |
| } else { |
| InfixExpression newCondition = ast.newInfixExpression(); |
| newCondition.setOperator(orOperator); |
| newCondition.setLeftOperand(condition); |
| newCondition.setRightOperand(ifCondition); |
| condition = newCondition; |
| } |
| } |
| // prepare new IfStatement with OR'ed condition |
| IfStatement newIf = ast.newIfStatement(); |
| newIf.setExpression(condition); |
| newIf.setThenStatement(thenStatement); |
| // |
| ListRewrite listRewriter = null; |
| for (Iterator I = coveredNodes.iterator(); I.hasNext();) { |
| IfStatement ifStatement = (IfStatement) I.next(); |
| if (listRewriter == null) { |
| Block sourceBlock = (Block) ifStatement.getParent(); |
| //int insertIndex = sourceBlock.statements().indexOf(ifStatement); |
| listRewriter = rewrite.getListRewrite(sourceBlock, |
| (ChildListPropertyDescriptor) ifStatement.getLocationInParent()); |
| } |
| if (newIf != null) { |
| listRewriter.replace(ifStatement, newIf, null); |
| newIf = null; |
| } else { |
| listRewriter.remove(ifStatement, null); |
| } |
| } |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_joinWithOr_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), |
| rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static Expression getParenthesizedForOrIfNeeded(AST ast, ASTRewrite rewrite, Expression expression) { |
| boolean addParentheses = false; |
| int nodeType = expression.getNodeType(); |
| addParentheses = nodeType == ASTNode.CONDITIONAL_EXPRESSION || nodeType == ASTNode.ASSIGNMENT |
| || nodeType == ASTNode.INSTANCEOF_EXPRESSION; |
| expression = (Expression) rewrite.createCopyTarget(expression); |
| if (addParentheses) { |
| return getParenthesizedExpression(ast, expression); |
| } |
| return expression; |
| } |
| private static boolean getSplitOrConditionProposals(IInvocationContext context, ASTNode node, |
| Collection resultingCollections) { |
| Operator orOperator = InfixExpression.Operator.CONDITIONAL_OR; |
| // check that user invokes quick assist on infix expression |
| if (!(node instanceof InfixExpression)) { |
| return false; |
| } |
| InfixExpression infixExpression = (InfixExpression) node; |
| if (infixExpression.getOperator() != orOperator) { |
| return false; |
| } |
| int offset= isOperatorSelected(infixExpression, context.getSelectionOffset(), context.getSelectionLength()); |
| if (offset == -1) { |
| return false; |
| } |
| // check that infix expression belongs to IfStatement |
| Statement statement = ASTResolving.findParentStatement(node); |
| if (!(statement instanceof IfStatement)) { |
| return false; |
| } |
| IfStatement ifStatement = (IfStatement) statement; |
| if (ifStatement.getElseStatement() != null) { |
| return false; |
| } |
| // check that infix expression is part of first level || condition of IfStatement |
| InfixExpression topInfixExpression = infixExpression; |
| while ((topInfixExpression.getParent() instanceof InfixExpression) |
| && ((InfixExpression) topInfixExpression.getParent()).getOperator() == orOperator) { |
| topInfixExpression = (InfixExpression) topInfixExpression.getParent(); |
| } |
| if (ifStatement.getExpression() != topInfixExpression) { |
| return false; |
| } |
| // |
| if (resultingCollections == null) { |
| return true; |
| } |
| AST ast = ifStatement.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| |
| // prepare left and right conditions |
| Expression[] newOperands= { null, null }; |
| breakInfixOperationAtOperation(rewrite, topInfixExpression, orOperator, offset, true, newOperands); |
| |
| Expression leftCondition= newOperands[0]; |
| Expression rightCondition= newOperands[1]; |
| |
| // prepare first statement |
| IfStatement firstIf = ast.newIfStatement(); |
| firstIf.setExpression(leftCondition); |
| firstIf.setThenStatement((Statement) rewrite.createCopyTarget(ifStatement.getThenStatement())); |
| // prepare second statement |
| IfStatement secondIf = ast.newIfStatement(); |
| secondIf.setExpression(rightCondition); |
| secondIf.setThenStatement((Statement) rewrite.createCopyTarget(ifStatement.getThenStatement())); |
| // add first and second IfStatement's |
| Block sourceBlock = (Block) ifStatement.getParent(); |
| int insertIndex = sourceBlock.statements().indexOf(ifStatement); |
| ListRewrite listRewriter = rewrite.getListRewrite(sourceBlock, |
| (ChildListPropertyDescriptor) statement.getLocationInParent()); |
| listRewriter.replace(ifStatement, firstIf, null); |
| listRewriter.insertAt(secondIf, insertIndex + 1, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_splitOrCondition_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), |
| rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static boolean getInverseConditionalExpressionProposals(IInvocationContext context, ASTNode covering, |
| Collection resultingCollections) { |
| // try to find conditional expression as parent |
| while (covering instanceof Expression) { |
| if (covering instanceof ConditionalExpression) |
| break; |
| covering = covering.getParent(); |
| } |
| if (!(covering instanceof ConditionalExpression)) { |
| return false; |
| } |
| ConditionalExpression expression = (ConditionalExpression) covering; |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast = covering.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| // prepare new conditional expresion |
| ConditionalExpression newExpression = ast.newConditionalExpression(); |
| newExpression.setExpression(getInversedBooleanExpression(ast, rewrite, expression.getExpression())); |
| newExpression.setThenExpression((Expression) rewrite.createCopyTarget(expression.getElseExpression())); |
| newExpression.setElseExpression((Expression) rewrite.createCopyTarget(expression.getThenExpression())); |
| // replace old expression with new |
| rewrite.replace(expression, newExpression, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_inverseConditionalExpression_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), |
| rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static boolean getExchangeInnerAndOuterIfConditionsProposals(IInvocationContext context, ASTNode node, |
| Collection resultingCollections) { |
| boolean result = false; |
| // |
| Statement statement = ASTResolving.findParentStatement(node); |
| if (!(statement instanceof IfStatement)) { |
| return false; |
| } |
| IfStatement ifStatement = (IfStatement) statement; |
| if (ifStatement.getElseStatement() != null) { |
| return false; |
| } |
| // case when current IfStatement is sole child of another IfStatement |
| { |
| IfStatement outerIf = null; |
| if (ifStatement.getParent() instanceof IfStatement) { |
| outerIf = (IfStatement) ifStatement.getParent(); |
| } else if (ifStatement.getParent() instanceof Block) { |
| Block block = (Block) ifStatement.getParent(); |
| if ((block.getParent() instanceof IfStatement) && (block.statements().size() == 1)) { |
| outerIf = (IfStatement) block.getParent(); |
| } |
| } |
| if ((outerIf != null) && (outerIf.getElseStatement() == null)) { |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast = statement.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| // prepare conditions |
| Expression outerCondition = (Expression) rewrite.createCopyTarget(outerIf.getExpression()); |
| Expression innerCondition = (Expression) rewrite.createCopyTarget(ifStatement.getExpression()); |
| // exchange conditions |
| rewrite.replace(outerIf.getExpression(), innerCondition, null); |
| rewrite.replace(ifStatement.getExpression(), outerCondition, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_exchangeInnerAndOuterIfConditions_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, |
| context.getCompilationUnit(), rewrite, 1, image); |
| resultingCollections.add(proposal); |
| result = true; |
| } |
| } |
| // case when current IfStatement has another IfStatement as sole child |
| { |
| IfStatement innerIf = null; |
| if (ifStatement.getThenStatement() instanceof IfStatement) { |
| innerIf = (IfStatement) ifStatement.getThenStatement(); |
| } else if (ifStatement.getThenStatement() instanceof Block) { |
| Block block = (Block) ifStatement.getThenStatement(); |
| if ((block.statements().size() == 1) && (block.statements().get(0) instanceof IfStatement)) { |
| innerIf = (IfStatement) block.statements().get(0); |
| } |
| } |
| if ((innerIf != null) && (innerIf.getElseStatement() == null)) { |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast = statement.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| // prepare conditions |
| Expression innerCondition = (Expression) rewrite.createCopyTarget(innerIf.getExpression()); |
| Expression outerCondition = (Expression) rewrite.createCopyTarget(ifStatement.getExpression()); |
| // exchange conditions |
| rewrite.replace(innerIf.getExpression(), outerCondition, null); |
| rewrite.replace(ifStatement.getExpression(), innerCondition, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_exchangeInnerAndOuterIfConditions_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, |
| context.getCompilationUnit(), rewrite, 1, image); |
| resultingCollections.add(proposal); |
| result = true; |
| } |
| } |
| return result; |
| } |
| private static boolean getExchangeOperandsProposals(IInvocationContext context, ASTNode node, |
| Collection resultingCollections) { |
| // check that user invokes quick assist on infix expression |
| if (!(node instanceof InfixExpression)) { |
| return false; |
| } |
| InfixExpression infixExpression = (InfixExpression) node; |
| Operator operator = infixExpression.getOperator(); |
| if ((operator != InfixExpression.Operator.CONDITIONAL_AND) && (operator != InfixExpression.Operator.AND) |
| && (operator != InfixExpression.Operator.CONDITIONAL_OR) && (operator != InfixExpression.Operator.OR) |
| && (operator != InfixExpression.Operator.EQUALS) && (operator != InfixExpression.Operator.PLUS) |
| && (operator != InfixExpression.Operator.TIMES) && (operator != InfixExpression.Operator.XOR)) { |
| return false; |
| } |
| |
| int offset= isOperatorSelected(infixExpression, context.getSelectionOffset(), context.getSelectionLength()); |
| if (offset == -1) { |
| return false; |
| } |
| |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| AST ast = infixExpression.getAST(); |
| ASTRewrite rewrite = ASTRewrite.create(ast); |
| // prepare left and right expressions |
| Expression leftExpression = null; |
| Expression rightExpression = null; |
| InfixExpression currentExpression = infixExpression; |
| leftExpression= combineOperands(rewrite, leftExpression, infixExpression.getLeftOperand(), true, operator); |
| if (infixExpression.getRightOperand().getStartPosition() <= context.getSelectionOffset()) { |
| leftExpression= combineOperands(rewrite, leftExpression, infixExpression.getRightOperand(), true, operator); |
| } else { |
| rightExpression= combineOperands(rewrite, rightExpression, infixExpression.getRightOperand(), true, operator); |
| } |
| for (Iterator I= currentExpression.extendedOperands().iterator(); I.hasNext();) { |
| Expression extendedOperand= (Expression) I.next(); |
| if (extendedOperand.getStartPosition() <= context.getSelectionOffset()) { |
| leftExpression= combineOperands(rewrite, leftExpression, extendedOperand, true, operator); |
| } else { |
| rightExpression= combineOperands(rewrite, rightExpression, extendedOperand, true, operator); |
| } |
| } |
| // create new infix expression |
| InfixExpression newInfix = ast.newInfixExpression(); |
| newInfix.setOperator(operator); |
| newInfix.setLeftOperand(rightExpression); |
| newInfix.setRightOperand(leftExpression); |
| rewrite.replace(infixExpression, newInfix, null); |
| // add correction proposal |
| String label = CorrectionMessages.AdvancedQuickAssistProcessor_exchangeOperands_description; |
| Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| |
| /** |
| * Breaks an infix operation with possible extended operators at the given operator and returns the new left and right operands. |
| * a & b & c -> [[a' & b' ] & c' ] (c' == copy of c) |
| * @param rewrite |
| * @param expression |
| * @param operator |
| * @param operatorOffset |
| */ |
| private static void breakInfixOperationAtOperation(ASTRewrite rewrite, Expression expression, Operator operator, int operatorOffset, boolean removeParenthesis, Expression[] res) { |
| if (expression.getStartPosition() + expression.getLength() <= operatorOffset) { |
| // add to the left |
| res[0]= combineOperands(rewrite, res[0], expression, removeParenthesis, operator); |
| return; |
| } |
| if (operatorOffset <= expression.getStartPosition()) { |
| // add to the right |
| res[1]= combineOperands(rewrite, res[1], expression, removeParenthesis, operator); |
| return; |
| } |
| if (!(expression instanceof InfixExpression)) { |
| throw new IllegalArgumentException("Cannot break up non-infix expression"); //$NON-NLS-1$ |
| } |
| InfixExpression infixExpression= (InfixExpression) expression; |
| if (infixExpression.getOperator() != operator) { |
| throw new IllegalArgumentException("Incompatible operator"); //$NON-NLS-1$ |
| } |
| breakInfixOperationAtOperation(rewrite, infixExpression.getLeftOperand(), operator, operatorOffset, removeParenthesis, res); |
| breakInfixOperationAtOperation(rewrite, infixExpression.getRightOperand(), operator, operatorOffset, removeParenthesis, res); |
| |
| List extended= infixExpression.extendedOperands(); |
| for (int i= 0; i < extended.size(); i++) { |
| breakInfixOperationAtOperation(rewrite, (Expression) extended.get(i), operator, operatorOffset, removeParenthesis, res); |
| } |
| } |
| |
| private static Expression combineOperands(ASTRewrite rewrite, Expression existing, Expression nodeToAdd, boolean removeParenthesis, Operator operator) { |
| if (existing == null && removeParenthesis) { |
| while (nodeToAdd instanceof ParenthesizedExpression) { |
| nodeToAdd= ((ParenthesizedExpression) nodeToAdd).getExpression(); |
| } |
| } |
| Expression newRight= (Expression) rewrite.createMoveTarget(nodeToAdd); |
| if (existing == null) { |
| return newRight; |
| } |
| AST ast= rewrite.getAST(); |
| InfixExpression infix= ast.newInfixExpression(); |
| infix.setOperator(operator); |
| infix.setLeftOperand(existing); |
| infix.setRightOperand(newRight); |
| return infix; |
| } |
| |
| private static boolean getCastAndAssignIfStatementProposals(IInvocationContext context, ASTNode node, Collection resultingCollections) { |
| if (!(node instanceof InstanceofExpression)) { |
| return false; |
| } |
| InstanceofExpression expression= (InstanceofExpression) node; |
| // test that we are the expression of a 'while' or 'if' |
| while (node.getParent() instanceof Expression) { |
| node= node.getParent(); |
| } |
| StructuralPropertyDescriptor locationInParent= node.getLocationInParent(); |
| |
| boolean negated= isNegated(expression); |
| |
| Statement body= null; |
| ASTNode insertionPosition= null; |
| if (negated) { |
| insertionPosition= node.getParent(); |
| if (locationInParent == IfStatement.EXPRESSION_PROPERTY) { |
| body= ((IfStatement) node.getParent()).getElseStatement(); |
| if (body != null) { |
| negated= false; |
| } |
| } |
| if (body == null && insertionPosition.getParent() instanceof Block) { |
| body= (Statement)insertionPosition.getParent(); |
| } |
| } else { |
| if (locationInParent == IfStatement.EXPRESSION_PROPERTY) { |
| body= ((IfStatement) node.getParent()).getThenStatement(); |
| } else if (locationInParent == WhileStatement.EXPRESSION_PROPERTY) { |
| body= ((WhileStatement) node.getParent()).getBody(); |
| } |
| } |
| if (body == null) { |
| return false; |
| } |
| |
| Type originalType= expression.getRightOperand(); |
| if (originalType.resolveBinding() == null) { |
| return false; |
| } |
| |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| |
| final String KEY_NAME= "name"; //$NON-NLS-1$ |
| final String KEY_TYPE= "type"; //$NON-NLS-1$ |
| // |
| AST ast= expression.getAST(); |
| ASTRewrite rewrite= ASTRewrite.create(ast); |
| ICompilationUnit cu= context.getCompilationUnit(); |
| // prepare correction proposal |
| String label= CorrectionMessages.AdvancedQuickAssistProcessor_castAndAssign; |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_LOCAL); |
| LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, cu, rewrite, 7, image); |
| // prepare possible variable names |
| String[] varNames= suggestLocalVariableNames(cu, originalType.resolveBinding()); |
| for (int i= 0; i < varNames.length; i++) { |
| proposal.addLinkedPositionProposal(KEY_NAME, varNames[i], null); |
| } |
| CastExpression castExpression= ast.newCastExpression(); |
| castExpression.setExpression((Expression) rewrite.createCopyTarget(expression.getLeftOperand())); |
| castExpression.setType((Type) ASTNode.copySubtree(ast, originalType)); |
| // prepare new variable declaration |
| VariableDeclarationFragment vdf= ast.newVariableDeclarationFragment(); |
| vdf.setName(ast.newSimpleName(varNames[0])); |
| vdf.setInitializer(castExpression); |
| // prepare new variable declaration statement |
| VariableDeclarationStatement vds= ast.newVariableDeclarationStatement(vdf); |
| vds.setType((Type) ASTNode.copySubtree(ast, originalType)); |
| |
| // add new variable declaration statement |
| if (negated) { |
| ListRewrite listRewriter= rewrite.getListRewrite(body, Block.STATEMENTS_PROPERTY); |
| listRewriter.insertAfter(vds, insertionPosition, null); |
| } else { |
| if (body instanceof Block) { |
| ListRewrite listRewriter= rewrite.getListRewrite(body, Block.STATEMENTS_PROPERTY); |
| listRewriter.insertAt(vds, 0, null); |
| } else { |
| Block newBlock= ast.newBlock(); |
| List statements= newBlock.statements(); |
| statements.add(vds); |
| statements.add(rewrite.createMoveTarget(body)); |
| rewrite.replace(body, newBlock, null); |
| } |
| } |
| |
| // setup linked positions |
| proposal.addLinkedPosition(rewrite.track(vdf.getName()), true, KEY_NAME); |
| proposal.addLinkedPosition(rewrite.track(vds.getType()), false, KEY_TYPE); |
| proposal.addLinkedPosition(rewrite.track(castExpression.getType()), false, KEY_TYPE); |
| proposal.setEndPosition(rewrite.track(vds)); // set cursor after expression statement |
| // add correction proposal |
| resultingCollections.add(proposal); |
| return true; |
| } |
| |
| private static boolean isNegated(Expression expression) { |
| if (!(expression.getParent() instanceof ParenthesizedExpression)) |
| return false; |
| |
| ParenthesizedExpression parenthesis= (ParenthesizedExpression)expression.getParent(); |
| if (!(parenthesis.getParent() instanceof PrefixExpression)) |
| return false; |
| |
| PrefixExpression prefix= (PrefixExpression)parenthesis.getParent(); |
| if (!(prefix.getOperator() == PrefixExpression.Operator.NOT)) |
| return false; |
| |
| return true; |
| } |
| private static String[] suggestLocalVariableNames(ICompilationUnit cu, ITypeBinding binding) { |
| ITypeBinding base= binding.isArray() ? binding.getElementType() : binding; |
| IPackageBinding packBinding= base.getPackage(); |
| String packName= packBinding != null ? packBinding.getName() : ""; //$NON-NLS-1$ |
| String typeName= base.getName(); |
| return NamingConventions.suggestLocalVariableNames(cu.getJavaProject(), packName, typeName, binding.getDimensions(), new String[0]); |
| } |
| |
| private static boolean getPickOutStringProposals(IInvocationContext context, ASTNode node, Collection resultingCollections) { |
| // we work with String's |
| if (!(node instanceof StringLiteral)) { |
| return false; |
| } |
| // user should select part of String |
| int selectionPos= context.getSelectionOffset(); |
| int selectionLen= context.getSelectionLength(); |
| if (selectionLen == 0) { |
| return false; |
| } |
| int valueStart= node.getStartPosition() + 1; |
| int valueEnd= node.getStartPosition() + node.getLength() - 1; |
| |
| // selection must be inside node and the quotes and not contain the full value |
| if ((selectionPos < valueStart) || (selectionPos + selectionLen > valueEnd) || (valueEnd - valueStart == selectionLen)) { |
| return false; |
| } |
| |
| // prepare string parts positions |
| StringLiteral stringLiteral= (StringLiteral) node; |
| String stringValue= stringLiteral.getEscapedValue(); |
| |
| int firstPos= selectionPos - node.getStartPosition(); |
| int secondPos= firstPos + selectionLen; |
| |
| |
| // prepare new string literals |
| |
| AST ast= node.getAST(); |
| StringLiteral leftLiteral= ast.newStringLiteral(); |
| StringLiteral centerLiteral= ast.newStringLiteral(); |
| StringLiteral rightLiteral= ast.newStringLiteral(); |
| try { |
| leftLiteral.setEscapedValue('"' + stringValue.substring(1, firstPos) + '"'); |
| centerLiteral.setEscapedValue('"' + stringValue.substring(firstPos, secondPos) + '"'); |
| rightLiteral.setEscapedValue('"' + stringValue.substring(secondPos, stringValue.length() - 1) + '"'); |
| } catch (IllegalArgumentException e) { |
| return false; |
| } |
| if (resultingCollections == null) { |
| return true; |
| } |
| |
| ASTRewrite rewrite= ASTRewrite.create(ast); |
| |
| // prepare new expression instead of StringLiteral |
| InfixExpression expression= ast.newInfixExpression(); |
| expression.setOperator(InfixExpression.Operator.PLUS); |
| if (firstPos != 1 ) { |
| expression.setLeftOperand(leftLiteral); |
| } |
| |
| |
| if (firstPos == 1) { |
| expression.setLeftOperand(centerLiteral); |
| } else { |
| expression.setRightOperand(centerLiteral); |
| } |
| |
| if (secondPos < stringValue.length() - 1) { |
| if (firstPos == 1) { |
| expression.setRightOperand(rightLiteral); |
| } else { |
| expression.extendedOperands().add(rightLiteral); |
| } |
| } |
| // use new expression instead of old StirngLiteral |
| rewrite.replace(stringLiteral, expression, null); |
| // add correction proposal |
| String label= CorrectionMessages.AdvancedQuickAssistProcessor_pickSelectedString; |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image); |
| proposal.addLinkedPosition(rewrite.track(centerLiteral), true, "CENTER_STRING"); //$NON-NLS-1$ |
| resultingCollections.add(proposal); |
| return true; |
| } |
| |
| private static Statement getSingleStatement(Statement statement) { |
| if (statement instanceof Block) { |
| List blockStatements= ((Block) statement).statements(); |
| if (blockStatements.size() != 1) { |
| return null; |
| } |
| return (Statement) blockStatements.get(0); |
| } |
| return statement; |
| } |
| |
| private static boolean getReplaceIfElseWithConditionalProposals(IInvocationContext context, ASTNode node, Collection resultingCollections) { |
| if (!(node instanceof IfStatement)) { |
| return false; |
| } |
| IfStatement ifStatement= (IfStatement) node; |
| Statement thenStatement= getSingleStatement(ifStatement.getThenStatement()); |
| Statement elseStatement= getSingleStatement(ifStatement.getElseStatement()); |
| if (thenStatement == null || elseStatement == null) { |
| return false; |
| } |
| Expression assigned= null; |
| Expression thenExpression= null; |
| Expression elseExpression= null; |
| |
| ITypeBinding exprBinding= null; |
| if (thenStatement instanceof ReturnStatement && elseStatement instanceof ReturnStatement) { |
| thenExpression= ((ReturnStatement) thenStatement).getExpression(); |
| elseExpression= ((ReturnStatement) elseStatement).getExpression(); |
| MethodDeclaration declaration= ASTResolving.findParentMethodDeclaration(node); |
| if (declaration == null || declaration.isConstructor()) { |
| return false; |
| } |
| exprBinding= declaration.getReturnType2().resolveBinding(); |
| } else if (thenStatement instanceof ExpressionStatement && elseStatement instanceof ExpressionStatement) { |
| Expression inner1= ((ExpressionStatement) thenStatement).getExpression(); |
| Expression inner2= ((ExpressionStatement) elseStatement).getExpression(); |
| if (inner1 instanceof Assignment && inner2 instanceof Assignment) { |
| Assignment assign1= (Assignment) inner1; |
| Assignment assign2= (Assignment) inner2; |
| Expression left1= assign1.getLeftHandSide(); |
| Expression left2= assign2.getLeftHandSide(); |
| if (left1 instanceof Name && left2 instanceof Name && assign1.getOperator() == assign2.getOperator()) { |
| IBinding bind1= ((Name) left1).resolveBinding(); |
| IBinding bind2= ((Name) left2).resolveBinding(); |
| if (bind1 == bind2 && bind1 instanceof IVariableBinding) { |
| assigned= left1; |
| exprBinding= ((IVariableBinding) bind1).getType(); |
| thenExpression= assign1.getRightHandSide(); |
| elseExpression= assign2.getRightHandSide(); |
| } |
| } |
| } |
| } |
| if (thenExpression == null || elseExpression == null) { |
| return false; |
| } |
| |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast= node.getAST(); |
| ASTRewrite rewrite= ASTRewrite.create(ast); |
| |
| String label= CorrectionMessages.AdvancedQuickAssistProcessor_replaceIfWithConditional; |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image); |
| |
| |
| // prepare conditional expression |
| ConditionalExpression conditionalExpression = ast.newConditionalExpression(); |
| Expression conditionCopy= (Expression) rewrite.createCopyTarget(ifStatement.getExpression()); |
| conditionalExpression.setExpression(conditionCopy); |
| Expression thenCopy= (Expression) rewrite.createCopyTarget(thenExpression); |
| Expression elseCopy= (Expression) rewrite.createCopyTarget(elseExpression); |
| |
| |
| if (!JavaModelUtil.is50OrHigher(context.getCompilationUnit().getJavaProject())) { |
| ITypeBinding thenBinding= thenExpression.resolveTypeBinding(); |
| ITypeBinding elseBinding= elseExpression.resolveTypeBinding(); |
| if (thenBinding != null && elseBinding != null && exprBinding != null && !elseBinding.isAssignmentCompatible(thenBinding)) { |
| CastExpression castException= ast.newCastExpression(); |
| proposal.createImportRewrite(context.getASTRoot()); |
| castException.setType(proposal.getImportRewrite().addImport(exprBinding, ast)); |
| castException.setExpression(elseCopy); |
| elseCopy= castException; |
| } |
| } |
| conditionalExpression.setThenExpression(thenCopy); |
| conditionalExpression.setElseExpression(elseCopy); |
| |
| // replace 'if' statement with conditional expression |
| if (assigned == null) { |
| ReturnStatement returnStatement = ast.newReturnStatement(); |
| returnStatement.setExpression(conditionalExpression); |
| rewrite.replace(ifStatement, returnStatement, null); |
| } else { |
| Assignment assignment= ast.newAssignment(); |
| assignment.setLeftHandSide((Expression) rewrite.createCopyTarget(assigned)); |
| assignment.setRightHandSide(conditionalExpression); |
| assignment.setOperator(((Assignment) assigned.getParent()).getOperator()); |
| |
| ExpressionStatement expressionStatement = ast.newExpressionStatement(assignment); |
| rewrite.replace(ifStatement, expressionStatement, null); |
| } |
| |
| // add correction proposal |
| resultingCollections.add(proposal); |
| return true; |
| } |
| |
| private static ReturnStatement createReturnExpression(ASTRewrite rewrite, Expression expression) { |
| AST ast= rewrite.getAST(); |
| ReturnStatement thenReturn = ast.newReturnStatement(); |
| thenReturn.setExpression((Expression) rewrite.createCopyTarget(expression)); |
| return thenReturn; |
| } |
| |
| private static Statement createAssignmentStatement(ASTRewrite rewrite, Assignment.Operator assignmentOperator, Expression origAssignee, Expression origAssigned) { |
| AST ast= rewrite.getAST(); |
| Assignment elseAssignment= ast.newAssignment(); |
| elseAssignment.setOperator(assignmentOperator); |
| elseAssignment.setLeftHandSide((Expression) rewrite.createCopyTarget(origAssignee)); |
| elseAssignment.setRightHandSide((Expression) rewrite.createCopyTarget(origAssigned)); |
| ExpressionStatement statement = ast.newExpressionStatement(elseAssignment); |
| return statement; |
| } |
| |
| private static boolean getReplaceConditionalWithIfElseProposals(IInvocationContext context, ASTNode covering, Collection resultingCollections) { |
| // check that parent statement is assignment |
| while (!(covering instanceof ConditionalExpression) && covering instanceof Expression) { |
| covering= covering.getParent(); |
| } |
| if (!(covering instanceof ConditionalExpression)) { |
| return false; |
| } |
| |
| StructuralPropertyDescriptor locationInParent= covering.getLocationInParent(); |
| if (locationInParent == Assignment.RIGHT_HAND_SIDE_PROPERTY) { |
| if (covering.getParent().getLocationInParent() != ExpressionStatement.EXPRESSION_PROPERTY) { |
| return false; |
| } |
| } else if (locationInParent == VariableDeclarationFragment.INITIALIZER_PROPERTY) { |
| ASTNode statement= covering.getParent().getParent(); |
| if (!(statement instanceof VariableDeclarationStatement) || statement.getLocationInParent() != Block.STATEMENTS_PROPERTY) { |
| return false; |
| } |
| } else if (locationInParent != ReturnStatement.EXPRESSION_PROPERTY) { |
| return false; |
| } |
| |
| ConditionalExpression conditional= (ConditionalExpression) covering; |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast= covering.getAST(); |
| ASTRewrite rewrite= ASTRewrite.create(ast); |
| // prepare new 'if' statement |
| Expression expression= conditional.getExpression(); |
| while (expression instanceof ParenthesizedExpression) { |
| expression= ((ParenthesizedExpression) expression).getExpression(); |
| } |
| IfStatement ifStatement= ast.newIfStatement(); |
| ifStatement.setExpression((Expression) rewrite.createCopyTarget(expression)); |
| if (locationInParent == Assignment.RIGHT_HAND_SIDE_PROPERTY) { |
| Assignment assignment= (Assignment) covering.getParent(); |
| Expression assignee= assignment.getLeftHandSide(); |
| Assignment.Operator op= assignment.getOperator(); |
| |
| ifStatement.setThenStatement(createAssignmentStatement(rewrite, op, assignee, conditional.getThenExpression())); |
| ifStatement.setElseStatement(createAssignmentStatement(rewrite, op, assignee, conditional.getElseExpression())); |
| |
| // replace return conditional expression with if/then/else/return |
| rewrite.replace(covering.getParent().getParent(), ifStatement, null); |
| |
| } else if (locationInParent == ReturnStatement.EXPRESSION_PROPERTY) { |
| ifStatement.setThenStatement(createReturnExpression(rewrite, conditional.getThenExpression())); |
| ifStatement.setElseStatement(createReturnExpression(rewrite, conditional.getElseExpression())); |
| // |
| // replace return conditional expression with if/then/else/return |
| rewrite.replace(conditional.getParent(), ifStatement, null); |
| } else if (locationInParent == VariableDeclarationFragment.INITIALIZER_PROPERTY) { |
| VariableDeclarationFragment frag= (VariableDeclarationFragment) covering.getParent(); |
| Assignment.Operator op= Assignment.Operator.ASSIGN; |
| |
| Expression assignee= frag.getName(); |
| ifStatement.setThenStatement(createAssignmentStatement(rewrite, op, assignee, conditional.getThenExpression())); |
| ifStatement.setElseStatement(createAssignmentStatement(rewrite, op, assignee, conditional.getElseExpression())); |
| |
| rewrite.set(frag, VariableDeclarationFragment.INITIALIZER_PROPERTY, null, null); // clear initializer |
| |
| ASTNode statement= frag.getParent(); |
| rewrite.getListRewrite(statement.getParent(), Block.STATEMENTS_PROPERTY).insertAfter(ifStatement, statement, null); |
| } |
| |
| // add correction proposal |
| String label= CorrectionMessages.AdvancedQuickAssistProcessor_replaceConditionalWithIf; |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static boolean getInverseLocalVariableProposals(IInvocationContext context, |
| ASTNode covering, |
| Collection resultingCollections) { |
| final AST ast= covering.getAST(); |
| // cursor should be placed on variable name |
| if (!(covering instanceof SimpleName)) { |
| return false; |
| } |
| SimpleName coveringName= (SimpleName) covering; |
| if (!coveringName.isDeclaration()) { |
| return false; |
| } |
| // prepare bindings |
| final IBinding variableBinding= coveringName.resolveBinding(); |
| if (!(variableBinding instanceof IVariableBinding)) { |
| return false; |
| } |
| IVariableBinding binding= (IVariableBinding) variableBinding; |
| if (binding.isField()) { |
| return false; |
| } |
| // we operate only on boolean variable |
| if (!isBoolean(coveringName)) { |
| return false; |
| } |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| // find linked nodes |
| final MethodDeclaration method= ASTResolving.findParentMethodDeclaration(covering); |
| SimpleName[] linkedNodes= LinkedNodeFinder.findByBinding(method, variableBinding); |
| // |
| final ASTRewrite rewrite= ASTRewrite.create(ast); |
| // create proposal |
| String label= CorrectionMessages.AdvancedQuickAssistProcessor_inverseBooleanVariable; |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| final String KEY_NAME= "name"; //$NON-NLS-1$ |
| final LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, |
| context.getCompilationUnit(), |
| rewrite, |
| 1, |
| image); |
| // prepare new variable identifier |
| final String oldIdentifier= coveringName.getIdentifier(); |
| final String notString = Messages.format(CorrectionMessages.AdvancedQuickAssistProcessor_negatedVariableName, ""); //$NON-NLS-1$ |
| final String newIdentifier; |
| if (oldIdentifier.startsWith(notString)) { |
| int notLength= notString.length(); |
| if (oldIdentifier.length() > notLength) { |
| newIdentifier= Character.toLowerCase(oldIdentifier.charAt(notLength)) + oldIdentifier.substring(notLength + 1); |
| } else { |
| newIdentifier= oldIdentifier; |
| } |
| } else { |
| newIdentifier= Messages.format(CorrectionMessages.AdvancedQuickAssistProcessor_negatedVariableName, Character.toUpperCase(oldIdentifier.charAt(0)) + oldIdentifier.substring(1)); |
| } |
| // |
| proposal.addLinkedPositionProposal(KEY_NAME, newIdentifier, null); |
| proposal.addLinkedPositionProposal(KEY_NAME, oldIdentifier, null); |
| // iterate over linked nodes and replace variable references with negated reference |
| final HashSet renamedNames= new HashSet(); |
| for (int i= 0; i < linkedNodes.length; i++) { |
| SimpleName name= linkedNodes[i]; |
| if (renamedNames.contains(name)) { |
| continue; |
| } |
| // prepare new name with new identifier |
| SimpleName newName= ast.newSimpleName(newIdentifier); |
| proposal.addLinkedPosition(rewrite.track(newName), name == coveringName, KEY_NAME); |
| // |
| StructuralPropertyDescriptor location= name.getLocationInParent(); |
| if (location == SingleVariableDeclaration.NAME_PROPERTY) { |
| // set new name |
| rewrite.replace(name, newName, null); |
| } else if (location == Assignment.LEFT_HAND_SIDE_PROPERTY) { |
| Assignment assignment= (Assignment) name.getParent(); |
| Expression expression= assignment.getRightHandSide(); |
| int exStart= expression.getStartPosition(); |
| int exEnd= exStart + expression.getLength(); |
| // collect all names that are used in assignments |
| HashSet overlapNames= new HashSet(); |
| for (int j= 0; j < linkedNodes.length; j++) { |
| SimpleName name2= linkedNodes[j]; |
| if (name2 == null) { |
| continue; |
| } |
| int name2Start= name2.getStartPosition(); |
| if (exStart <= name2Start && name2Start < exEnd) { |
| overlapNames.add(name2); |
| } |
| } |
| // prepare inversed expression |
| SimpleNameRenameProvider provider= new SimpleNameRenameProvider() { |
| public SimpleName getRenamed(SimpleName simpleName) { |
| if (simpleName.resolveBinding() == variableBinding) { |
| renamedNames.add(simpleName); |
| return ast.newSimpleName(newIdentifier); |
| } |
| return null; |
| } |
| }; |
| Expression inversedExpression= getInversedBooleanExpression(ast, rewrite, expression, provider); |
| // if any name was not renamed during expression inversing, we can not already renate it, so fail to create assist |
| for (Iterator I= overlapNames.iterator(); I.hasNext();) { |
| Object o= I.next(); |
| if (!renamedNames.contains(o)) { |
| return false; |
| } |
| } |
| // check operator and replace if needed |
| Assignment.Operator operator= assignment.getOperator(); |
| if (operator == Assignment.Operator.BIT_AND_ASSIGN) { |
| Assignment newAssignment= ast.newAssignment(); |
| newAssignment.setLeftHandSide(newName); |
| newAssignment.setRightHandSide(inversedExpression); |
| newAssignment.setOperator(Assignment.Operator.BIT_OR_ASSIGN); |
| rewrite.replace(assignment, newAssignment, null); |
| } else if (operator == Assignment.Operator.BIT_OR_ASSIGN) { |
| Assignment newAssignment= ast.newAssignment(); |
| newAssignment.setLeftHandSide(newName); |
| newAssignment.setRightHandSide(inversedExpression); |
| newAssignment.setOperator(Assignment.Operator.BIT_AND_ASSIGN); |
| rewrite.replace(assignment, newAssignment, null); |
| } else { |
| rewrite.replace(expression, inversedExpression, null); |
| // set new name |
| rewrite.replace(name, newName, null); |
| } |
| } else if (location == VariableDeclarationFragment.NAME_PROPERTY) { |
| // replace initializer for variable |
| VariableDeclarationFragment vdf= (VariableDeclarationFragment) name.getParent(); |
| Expression expression= vdf.getInitializer(); |
| if (expression != null) { |
| rewrite.replace(expression, getInversedBooleanExpression(ast, rewrite, expression), null); |
| } |
| // set new name |
| rewrite.replace(name, newName, null); |
| } else if ((name.getParent() instanceof PrefixExpression) |
| && (((PrefixExpression) name.getParent()).getOperator() == PrefixExpression.Operator.NOT)) { |
| rewrite.replace(name.getParent(), newName, null); |
| } else { |
| PrefixExpression expression= ast.newPrefixExpression(); |
| expression.setOperator(PrefixExpression.Operator.NOT); |
| expression.setOperand(newName); |
| rewrite.replace(name, expression, null); |
| } |
| } |
| // add correction proposal |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static boolean getPushNegationDownProposals(IInvocationContext context, |
| ASTNode covering, |
| Collection resultingCollections) { |
| PrefixExpression negationExpression= null; |
| ParenthesizedExpression parenthesizedExpression= null; |
| // check for case when cursor is on '!' before parentheses |
| if (covering instanceof PrefixExpression) { |
| PrefixExpression prefixExpression= (PrefixExpression) covering; |
| if ((prefixExpression.getOperator() == PrefixExpression.Operator.NOT) |
| && (prefixExpression.getOperand() instanceof ParenthesizedExpression)) { |
| negationExpression= prefixExpression; |
| parenthesizedExpression= (ParenthesizedExpression) prefixExpression.getOperand(); |
| } |
| } |
| // check for case when cursor is on parenthesized expression that is negated |
| if ((covering instanceof ParenthesizedExpression) |
| && (covering.getParent() instanceof PrefixExpression) |
| && (((PrefixExpression) covering.getParent()).getOperator() == PrefixExpression.Operator.NOT)) { |
| negationExpression= (PrefixExpression) covering.getParent(); |
| parenthesizedExpression= (ParenthesizedExpression) covering; |
| } |
| // |
| if (negationExpression == null) { |
| return false; |
| } |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| final AST ast= covering.getAST(); |
| final ASTRewrite rewrite= ASTRewrite.create(ast); |
| // prepared inversed expression |
| Expression inversedExpression= getInversedBooleanExpression(ast, |
| rewrite, |
| parenthesizedExpression.getExpression()); |
| // check, may be we should keep parentheses |
| boolean keepParentheses= false; |
| if (negationExpression.getParent() instanceof Expression) { |
| int parentPrecedence= getExpressionPrecedence((Expression) negationExpression.getParent()); |
| int inversedExpressionPrecedence= getExpressionPrecedence(inversedExpression); |
| keepParentheses= parentPrecedence < inversedExpressionPrecedence; |
| } |
| // replace negated expression with inversed one |
| if (keepParentheses) { |
| ParenthesizedExpression pe= ast.newParenthesizedExpression(); |
| pe.setExpression(inversedExpression); |
| rewrite.replace(negationExpression, pe, null); |
| } else { |
| rewrite.replace(negationExpression, inversedExpression, null); |
| } |
| // add correction proposal |
| String label= CorrectionMessages.AdvancedQuickAssistProcessor_pushNegationDown; |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| |
| private static Expression getBooleanExpression(ASTNode node) { |
| if (!(node instanceof Expression)) { |
| return null; |
| } |
| |
| // check if the node is a location where it can be negated |
| StructuralPropertyDescriptor locationInParent= node.getLocationInParent(); |
| if (locationInParent == QualifiedName.NAME_PROPERTY) { |
| node= node.getParent(); |
| locationInParent= node.getLocationInParent(); |
| } |
| while (locationInParent == ParenthesizedExpression.EXPRESSION_PROPERTY) { |
| node= node.getParent(); |
| locationInParent= node.getLocationInParent(); |
| } |
| Expression expression= (Expression) node; |
| if (!isBoolean(expression)) { |
| return null; |
| } |
| if (expression.getParent() instanceof InfixExpression) { |
| return expression; |
| } |
| if (locationInParent == Assignment.RIGHT_HAND_SIDE_PROPERTY |
| || locationInParent == IfStatement.EXPRESSION_PROPERTY |
| || locationInParent == WhileStatement.EXPRESSION_PROPERTY |
| || locationInParent == DoStatement.EXPRESSION_PROPERTY |
| || locationInParent == ReturnStatement.EXPRESSION_PROPERTY |
| || locationInParent == ForStatement.EXPRESSION_PROPERTY |
| || locationInParent == MethodInvocation.ARGUMENTS_PROPERTY |
| || locationInParent == ConstructorInvocation.ARGUMENTS_PROPERTY |
| || locationInParent == SuperMethodInvocation.ARGUMENTS_PROPERTY |
| || locationInParent == EnumConstantDeclaration.ARGUMENTS_PROPERTY |
| || locationInParent == SuperConstructorInvocation.ARGUMENTS_PROPERTY |
| || locationInParent == ClassInstanceCreation.ARGUMENTS_PROPERTY |
| || locationInParent == ConditionalExpression.EXPRESSION_PROPERTY |
| || locationInParent == PrefixExpression.OPERAND_PROPERTY) { |
| return expression; |
| } |
| return null; |
| } |
| |
| |
| |
| private static boolean getPullNegationUpProposals(IInvocationContext context, ASTNode covering, ArrayList coveredNodes, Collection resultingCollections) { |
| if (coveredNodes.size() != 1) { |
| return false; |
| } |
| // |
| ASTNode fullyCoveredNode= (ASTNode) coveredNodes.get(0); |
| |
| Expression expression= getBooleanExpression(fullyCoveredNode); |
| if (expression == null) { |
| return false; |
| } |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| AST ast= expression.getAST(); |
| final ASTRewrite rewrite= ASTRewrite.create(ast); |
| // prepared inversed expression |
| Expression inversedExpression= getInversedBooleanExpression(ast, rewrite, expression); |
| // prepare ParenthesizedExpression |
| ParenthesizedExpression parenthesizedExpression = ast.newParenthesizedExpression(); |
| parenthesizedExpression.setExpression(inversedExpression); |
| // prepare NOT prefix expression |
| PrefixExpression prefixExpression = ast.newPrefixExpression(); |
| prefixExpression.setOperator(PrefixExpression.Operator.NOT); |
| prefixExpression.setOperand(parenthesizedExpression); |
| // replace old expresson |
| rewrite.replace(expression, prefixExpression, null); |
| // add correction proposal |
| String label= CorrectionMessages.AdvancedQuickAssistProcessor_pullNegationUp; |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static boolean getJoinIfListInIfElseIfProposals(IInvocationContext context, |
| ASTNode covering, |
| ArrayList coveredNodes, |
| Collection resultingCollections) { |
| if (coveredNodes.isEmpty()) { |
| return false; |
| } |
| // check that we have more than one covered statement |
| if (coveredNodes.size() < 2) { |
| return false; |
| } |
| // check that all selected nodes are 'if' statements with only 'then' statement |
| for (Iterator I= coveredNodes.iterator(); I.hasNext();) { |
| ASTNode node= (ASTNode) I.next(); |
| if (!(node instanceof IfStatement)) { |
| return false; |
| } |
| IfStatement ifStatement= (IfStatement) node; |
| if (ifStatement.getElseStatement() != null) { |
| return false; |
| } |
| } |
| // ok, we could produce quick assist |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| final AST ast= covering.getAST(); |
| final ASTRewrite rewrite= ASTRewrite.create(ast); |
| // |
| IfStatement firstIfStatement= (IfStatement) coveredNodes.get(0); |
| IfStatement firstNewIfStatement= null; |
| // |
| IfStatement prevIfStatement= null; |
| for (Iterator I= coveredNodes.iterator(); I.hasNext();) { |
| IfStatement ifStatement= (IfStatement) I.next(); |
| // prepare new 'if' statement |
| IfStatement newIfStatement= ast.newIfStatement(); |
| newIfStatement.setExpression((Expression) rewrite.createMoveTarget(ifStatement.getExpression())); |
| // prepare 'then' statement and convert into block if needed |
| Statement thenStatement= (Statement) rewrite.createMoveTarget(ifStatement.getThenStatement()); |
| if (ifStatement.getThenStatement() instanceof IfStatement) { |
| IfStatement ifBodyStatement= (IfStatement) ifStatement.getThenStatement(); |
| if (ifBodyStatement.getElseStatement() == null) { |
| Block thenBlock= ast.newBlock(); |
| thenBlock.statements().add(thenStatement); |
| thenStatement= thenBlock; |
| } |
| } |
| newIfStatement.setThenStatement(thenStatement); |
| // |
| if (prevIfStatement != null) { |
| prevIfStatement.setElseStatement(newIfStatement); |
| rewrite.remove(ifStatement, null); |
| } else { |
| firstNewIfStatement= newIfStatement; |
| } |
| prevIfStatement= newIfStatement; |
| } |
| rewrite.replace(firstIfStatement, firstNewIfStatement, null); |
| // add correction proposal |
| String label= CorrectionMessages.AdvancedQuickAssistProcessor_joinIfSequence; |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static boolean getConvertSwitchToIfProposals(IInvocationContext context, |
| ASTNode covering, |
| Collection resultingCollections) { |
| if (!(covering instanceof SwitchStatement)) { |
| return false; |
| } |
| // ok, we could produce quick assist (if all 'case' statements end with 'break') |
| if (resultingCollections == null) { |
| return true; |
| } |
| // |
| final AST ast= covering.getAST(); |
| final ASTRewrite rewrite= ASTRewrite.create(ast); |
| // |
| SwitchStatement switchStatement= (SwitchStatement) covering; |
| IfStatement firstIfStatement= null; |
| IfStatement currentIfStatement= null; |
| Block currentBlock= null; |
| boolean hasStopAsLastExecutableStatement = false; |
| Block defaultBlock= null; |
| InfixExpression currentCondition= null; |
| boolean defaultFound= false; |
| int caseCount = 0; |
| |
| ArrayList allBlocks= new ArrayList(); |
| // |
| for (Iterator I= switchStatement.statements().iterator(); I.hasNext();) { |
| Statement statement= (Statement) I.next(); |
| if (statement instanceof SwitchCase) { |
| SwitchCase switchCase= (SwitchCase) statement; |
| caseCount++; |
| // special case: passthrough |
| if (currentBlock != null) { |
| if (!hasStopAsLastExecutableStatement) { |
| return false; |
| } |
| currentBlock= null; |
| } |
| // for 'default' we just will not create condition |
| if (switchCase.isDefault()) { |
| defaultFound= true; |
| if (currentCondition != null) { |
| // we can not convert one or more 'case' statements and 'default' nor in conditional if, nor in 'else' without code duplication |
| return false; |
| } |
| continue; |
| } |
| if (defaultFound) { |
| return false; |
| } |
| // prepare condition |
| InfixExpression switchCaseCondition= createSwitchCaseCondition(ast, rewrite, switchStatement, switchCase); |
| if (currentCondition == null) { |
| currentCondition= switchCaseCondition; |
| } else { |
| InfixExpression condition= ast.newInfixExpression(); |
| condition.setOperator(InfixExpression.Operator.CONDITIONAL_OR); |
| condition.setLeftOperand(currentCondition); |
| condition.setRightOperand(switchCaseCondition); |
| currentCondition= condition; |
| } |
| } else if (statement instanceof BreakStatement) { |
| currentBlock= null; |
| } else { |
| // ensure that current block exists as 'then' statement of 'if' |
| if (currentBlock == null) { |
| defaultFound= false; |
| if (currentCondition != null) { |
| IfStatement ifStatement; |
| if (firstIfStatement == null) { |
| firstIfStatement= ast.newIfStatement(); |
| ifStatement= firstIfStatement; |
| } else { |
| ifStatement= ast.newIfStatement(); |
| currentIfStatement.setElseStatement(ifStatement); |
| } |
| currentIfStatement= ifStatement; |
| ifStatement.setExpression(currentCondition); |
| currentCondition= null; |
| currentBlock= ast.newBlock(); |
| ifStatement.setThenStatement(currentBlock); |
| allBlocks.add(currentBlock); |
| } else { |
| // case for default: |
| defaultBlock= ast.newBlock(); |
| currentBlock= defaultBlock; |
| allBlocks.add(currentBlock); |
| // delay adding of default block |
| } |
| } |
| // add current statement in currect block |
| { |
| hasStopAsLastExecutableStatement = hasStopAsLastExecutableStatement(statement); |
| Statement copyStatement= copyStatementExceptBreak(ast, rewrite, statement); |
| |
| |
| currentBlock.statements().add(copyStatement); |
| } |
| } |
| } |
| // check, may be we have delayed default block |
| if (defaultBlock != null) { |
| currentIfStatement.setElseStatement(defaultBlock); |
| } |
| // remove unnecessary blocks in blocks |
| for (int i= 0; i < allBlocks.size(); i++) { |
| Block block= (Block) allBlocks.get(i); |
| List statements= block.statements(); |
| if (statements.size() == 1 && statements.get(0) instanceof Block) { |
| Block innerBlock= (Block) statements.remove(0); |
| block.getParent().setStructuralProperty(block.getLocationInParent(), innerBlock); |
| } |
| } |
| // replace 'switch' with single if-else-if statement |
| rewrite.replace(switchStatement, firstIfStatement, null); |
| // prepare label, specially for Daniel :-) |
| String label= CorrectionMessages.AdvancedQuickAssistProcessor_convertSwitchToIf; |
| |
| // add correction proposal |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, |
| context.getCompilationUnit(), |
| rewrite, |
| 1, |
| image); |
| resultingCollections.add(proposal); |
| return true; |
| } |
| private static InfixExpression createSwitchCaseCondition(AST ast, |
| ASTRewrite rewrite, |
| SwitchStatement switchStatement, |
| SwitchCase switchCase) { |
| InfixExpression condition= ast.newInfixExpression(); |
| condition.setOperator(InfixExpression.Operator.EQUALS); |
| // |
| Expression leftExpression= (Expression) rewrite.createCopyTarget(switchStatement.getExpression()); |
| condition.setLeftOperand(leftExpression); |
| // |
| Expression rightExpression= (Expression) rewrite.createCopyTarget(switchCase.getExpression()); |
| condition.setRightOperand(rightExpression); |
| // |
| return condition; |
| } |
| private static boolean hasStopAsLastExecutableStatement(Statement lastStatement) { |
| if ((lastStatement instanceof ReturnStatement) || (lastStatement instanceof BreakStatement)) { |
| return true; |
| } |
| if (lastStatement instanceof Block) { |
| Block block= (Block)lastStatement; |
| lastStatement = (Statement) block.statements().get(block.statements().size() - 1); |
| return hasStopAsLastExecutableStatement(lastStatement); |
| } |
| return false; |
| } |
| private static Statement copyStatementExceptBreak(AST ast, ASTRewrite rewrite, Statement source) { |
| if (source instanceof Block) { |
| Block block= (Block) source; |
| Block newBlock= ast.newBlock(); |
| for (Iterator I= block.statements().iterator(); I.hasNext();) { |
| Statement statement= (Statement) I.next(); |
| if (statement instanceof BreakStatement) { |
| continue; |
| } |
| newBlock.statements().add(copyStatementExceptBreak(ast, rewrite, statement)); |
| } |
| return newBlock; |
| } |
| return (Statement) rewrite.createMoveTarget(source); |
| } |
| } |