/******************************************************************************* * Copyright (c) 2000, 2011 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]) * IBM Corporation - implementation *******************************************************************************/ package org.eclipse.che.ide.ext.java.jdt.internal.text.correction; import org.eclipse.che.ide.ext.java.jdt.Images; import org.eclipse.che.ide.ext.java.jdt.codeassistant.api.IProblemLocation; import org.eclipse.che.ide.ext.java.jdt.codeassistant.api.JavaCompletionProposal; import org.eclipse.che.ide.ext.java.jdt.core.NamingConventions; import org.eclipse.che.ide.ext.java.jdt.core.dom.AST; import org.eclipse.che.ide.ext.java.jdt.core.dom.ASTNode; import org.eclipse.che.ide.ext.java.jdt.core.dom.ASTVisitor; import org.eclipse.che.ide.ext.java.jdt.core.dom.AssertStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.Assignment; import org.eclipse.che.ide.ext.java.jdt.core.dom.Block; import org.eclipse.che.ide.ext.java.jdt.core.dom.BooleanLiteral; import org.eclipse.che.ide.ext.java.jdt.core.dom.BreakStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.CastExpression; import org.eclipse.che.ide.ext.java.jdt.core.dom.ChildListPropertyDescriptor; import org.eclipse.che.ide.ext.java.jdt.core.dom.ClassInstanceCreation; import org.eclipse.che.ide.ext.java.jdt.core.dom.CompilationUnit; import org.eclipse.che.ide.ext.java.jdt.core.dom.ConditionalExpression; import org.eclipse.che.ide.ext.java.jdt.core.dom.ConstructorInvocation; import org.eclipse.che.ide.ext.java.jdt.core.dom.ContinueStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.DoStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.EnumConstantDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.Expression; import org.eclipse.che.ide.ext.java.jdt.core.dom.ExpressionStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.ForStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.IBinding; import org.eclipse.che.ide.ext.java.jdt.core.dom.IMethodBinding; import org.eclipse.che.ide.ext.java.jdt.core.dom.ITypeBinding; import org.eclipse.che.ide.ext.java.jdt.core.dom.IVariableBinding; import org.eclipse.che.ide.ext.java.jdt.core.dom.IfStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.InfixExpression; import org.eclipse.che.ide.ext.java.jdt.core.dom.InfixExpression.Operator; import org.eclipse.che.ide.ext.java.jdt.core.dom.InstanceofExpression; import org.eclipse.che.ide.ext.java.jdt.core.dom.MethodDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.MethodInvocation; import org.eclipse.che.ide.ext.java.jdt.core.dom.Modifier; import org.eclipse.che.ide.ext.java.jdt.core.dom.Name; import org.eclipse.che.ide.ext.java.jdt.core.dom.ParenthesizedExpression; import org.eclipse.che.ide.ext.java.jdt.core.dom.PrefixExpression; import org.eclipse.che.ide.ext.java.jdt.core.dom.PrimitiveType; import org.eclipse.che.ide.ext.java.jdt.core.dom.QualifiedName; import org.eclipse.che.ide.ext.java.jdt.core.dom.ReturnStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.SimpleName; import org.eclipse.che.ide.ext.java.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.Statement; import org.eclipse.che.ide.ext.java.jdt.core.dom.StringLiteral; import org.eclipse.che.ide.ext.java.jdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.che.ide.ext.java.jdt.core.dom.SuperConstructorInvocation; import org.eclipse.che.ide.ext.java.jdt.core.dom.SuperMethodInvocation; import org.eclipse.che.ide.ext.java.jdt.core.dom.SwitchCase; import org.eclipse.che.ide.ext.java.jdt.core.dom.SwitchStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.Type; import org.eclipse.che.ide.ext.java.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.che.ide.ext.java.jdt.core.dom.VariableDeclarationStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.WhileStatement; import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ImportRewrite; import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext; import org.eclipse.che.ide.ext.java.jdt.core.dom.rewrite.ListRewrite; import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.ASTResolving; import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext; import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.StubUtility; import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.ASTNodes; import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.GenericVisitor; import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.LinkedNodeFinder; import org.eclipse.che.ide.ext.java.jdt.internal.corext.dom.NecessaryParenthesesChecker; import org.eclipse.che.ide.ext.java.jdt.internal.corext.fix.CleanUpConstants; import org.eclipse.che.ide.ext.java.jdt.internal.corext.fix.CleanUpOptions; import org.eclipse.che.ide.ext.java.jdt.internal.corext.fix.ExpressionsCleanUp; import org.eclipse.che.ide.ext.java.jdt.internal.corext.fix.ExpressionsFix; import org.eclipse.che.ide.ext.java.jdt.internal.corext.fix.IProposableFix; import org.eclipse.che.ide.ext.java.jdt.internal.corext.refactoring.code.Invocations; import org.eclipse.che.ide.ext.java.jdt.internal.corext.refactoring.code.OperatorPrecedence; import org.eclipse.che.ide.ext.java.jdt.internal.corext.refactoring.util.TightSourceRangeComputer; import org.eclipse.che.ide.ext.java.jdt.internal.text.correction.proposals.ASTRewriteCorrectionProposal; import org.eclipse.che.ide.ext.java.jdt.internal.text.correction.proposals.FixCorrectionProposal; import org.eclipse.che.ide.ext.java.jdt.internal.text.correction.proposals.LinkedCorrectionProposal; import org.eclipse.che.ide.ext.java.jdt.quickassist.api.InvocationContext; import org.eclipse.che.ide.runtime.CoreException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; /** */ public class AdvancedQuickAssistProcessor implements org.eclipse.che.ide.ext.java.jdt.quickassist.api.QuickAssistProcessor { 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(InvocationContext context) throws CoreException { ASTNode coveringNode = context.getCoveringNode(); if (coveringNode != null) { ArrayList<ASTNode> 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) || getRemoveExtraParenthesesProposals(context, coveringNode, coveredNodes, null) || getAddParanoidalParenthesesProposals(context, coveredNodes, null) || getAddParenthesesForExpressionProposals(context, coveringNode, 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, coveredNodes, null) || getJoinIfListInIfElseIfProposals(context, coveringNode, coveredNodes, null) || getConvertSwitchToIfProposals(context, coveringNode, null) || GetterSetterCorrectionSubProcessor.addGetterSetterProposal(context, coveringNode, null, 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 JavaCompletionProposal[] getAssists(InvocationContext context, IProblemLocation[] locations) throws CoreException { ASTNode coveringNode = context.getCoveringNode(); if (coveringNode != null) { ArrayList<ASTNode> coveredNodes = getFullyCoveredNodes(context, coveringNode); ArrayList<ICommandAccess> resultingCollections = new ArrayList<ICommandAccess>(); //quick assists that show up also if there is an error/warning getReplaceConditionalWithIfElseProposals(context, coveringNode, resultingCollections); if (QuickAssistProcessorImpl.noErrorsAtLocation(locations)) { getInverseIfProposals(context, coveringNode, resultingCollections); getIfReturnIntoIfElseAtEndOfVoidMethodProposals(context, coveringNode, resultingCollections); getInverseIfContinueIntoIfThenInLoopsProposals(context, coveringNode, resultingCollections); getInverseIfIntoContinueInLoopsProposals(context, coveringNode, resultingCollections); getInverseConditionProposals(context, coveringNode, coveredNodes, resultingCollections); getRemoveExtraParenthesesProposals(context, coveringNode, coveredNodes, resultingCollections); getAddParanoidalParenthesesProposals(context, coveredNodes, resultingCollections); getAddParenthesesForExpressionProposals(context, coveringNode, 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); getInverseLocalVariableProposals(context, coveringNode, resultingCollections); getPushNegationDownProposals(context, coveringNode, resultingCollections); getPullNegationUpProposals(context, coveredNodes, resultingCollections); getJoinIfListInIfElseIfProposals(context, coveringNode, coveredNodes, resultingCollections); getConvertSwitchToIfProposals(context, coveringNode, resultingCollections); GetterSetterCorrectionSubProcessor.addGetterSetterProposal(context, coveringNode, locations, resultingCollections); } return resultingCollections.toArray(new JavaCompletionProposal[resultingCollections.size()]); } return null; } private static boolean getIfReturnIntoIfElseAtEndOfVoidMethodProposals(InvocationContext context, ASTNode covering, Collection<ICommandAccess> resultingCollections) { if (!(covering instanceof IfStatement)) { return false; } IfStatement ifStatement = (IfStatement)covering; 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<Statement> 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<Statement> statements = coveringMetod.getBody().statements(); int ifIndex = statements.indexOf(ifStatement); if (ifIndex == -1) { return false; } // we could produce quick assist if (resultingCollections == null) { return true; } // AST ast = covering.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); // remove last 'return' in 'then' block ListRewrite listRewriter = rewrite.getListRewrite(thenBlock, (ChildListPropertyDescriptor)ifStatement.getLocationInParent()); listRewriter.remove(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 = 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.INSTANCE.AdvancedQuickAssistProcessor_convertToIfElse_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } private static boolean getInverseIfProposals(InvocationContext context, ASTNode covering, Collection<ICommandAccess> resultingCollections) { if (!(covering instanceof IfStatement)) { return false; } IfStatement ifStatement = (IfStatement)covering; if (ifStatement.getElseStatement() == null) { return false; } // we could produce quick assist if (resultingCollections == null) { return true; } // AST ast = covering.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); Statement thenStatement = ifStatement.getThenStatement(); Statement elseStatement = ifStatement.getElseStatement(); // prepare original nodes Expression inversedExpression = getInversedExpression(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.INSTANCE.AdvancedQuickAssistProcessor_inverseIf_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } private static boolean getInverseIfContinueIntoIfThenInLoopsProposals(InvocationContext context, ASTNode covering, Collection<ICommandAccess> resultingCollections) { if (!(covering instanceof IfStatement)) { return false; } IfStatement ifStatement = (IfStatement)covering; 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 = covering.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); // create inverted 'if' statement Expression inversedExpression = getInversedExpression(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.INSTANCE.AdvancedQuickAssistProcessor_inverseIfContinue_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } private static boolean getInverseIfIntoContinueInLoopsProposals(InvocationContext context, ASTNode covering, Collection<ICommandAccess> resultingCollections) { if (!(covering instanceof IfStatement)) { return false; } IfStatement ifStatement = (IfStatement)covering; 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; } // we could produce quick assist if (resultingCollections == null) { return true; } // AST ast = covering.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); // create inverted 'if' statement Expression inversedExpression = getInversedExpression(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<Statement> iter = getUnwrappedStatements(ifStatement.getThenStatement()).iterator(); iter .hasNext(); ) { Statement statement = iter.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<Statement> iter = getUnwrappedStatements(ifStatement.getThenStatement()).iterator(); iter .hasNext(); ) { Statement statement = iter.next(); listRewriter.insertLast(rewrite.createMoveTarget(statement), null); } } // add correction proposal String label = CorrectionMessages.INSTANCE.AdvancedQuickAssistProcessor_inverseIfToContinue_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } private static ArrayList<Statement> getUnwrappedStatements(Statement body) { ArrayList<Statement> statements = new ArrayList<Statement>(); if (body instanceof Block) { for (Iterator<Statement> iter = ((Block)body).statements().iterator(); iter.hasNext(); ) { Statement statement = iter.next(); statements.add(statement); } } else { statements.add(body); } return statements; } private static boolean getInverseConditionProposals(InvocationContext context, ASTNode covering, ArrayList<ASTNode> coveredNodes, Collection<ICommandAccess> 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<ASTNode> iter = coveredNodes.iterator(); iter.hasNext(); ) { ASTNode covered = iter.next(); Expression coveredExpression = getBooleanExpression(covered); if (coveredExpression != null) { Expression inversedExpression = getInversedExpression(rewrite, coveredExpression); rewrite.replace(coveredExpression, inversedExpression, null); hasChanges = true; } } // if (!hasChanges) { return false; } if (resultingCollections == null) { return true; } // add correction proposal String label = CorrectionMessages.INSTANCE.AdvancedQuickAssistProcessor_inverseConditions_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } private static Expression getInversedExpression(ASTRewrite rewrite, Expression expression) { return getInversedExpression(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 getInversedExpression(ASTRewrite rewrite, Expression expression, SimpleNameRenameProvider provider) { AST ast = rewrite.getAST(); // if (expression instanceof BooleanLiteral) { return ast.newBooleanLiteral(!((BooleanLiteral)expression).booleanValue()); } if (expression instanceof InfixExpression) { InfixExpression infixExpression = (InfixExpression)expression; InfixExpression.Operator operator = infixExpression.getOperator(); if (operator == InfixExpression.Operator.LESS) { return getInversedInfixExpression(rewrite, infixExpression, InfixExpression.Operator.GREATER_EQUALS, provider); } if (operator == InfixExpression.Operator.GREATER) { return getInversedInfixExpression(rewrite, infixExpression, InfixExpression.Operator.LESS_EQUALS, provider); } if (operator == InfixExpression.Operator.LESS_EQUALS) { return getInversedInfixExpression(rewrite, infixExpression, InfixExpression.Operator.GREATER, provider); } if (operator == InfixExpression.Operator.GREATER_EQUALS) { return getInversedInfixExpression(rewrite, infixExpression, InfixExpression.Operator.LESS, provider); } if (operator == InfixExpression.Operator.EQUALS) { return getInversedInfixExpression(rewrite, infixExpression, InfixExpression.Operator.NOT_EQUALS, provider); } if (operator == InfixExpression.Operator.NOT_EQUALS) { return getInversedInfixExpression(rewrite, infixExpression, InfixExpression.Operator.EQUALS, provider); } if (operator == InfixExpression.Operator.CONDITIONAL_AND) { return getInversedAndOrExpression(rewrite, infixExpression, InfixExpression.Operator.CONDITIONAL_OR, provider); } if (operator == InfixExpression.Operator.CONDITIONAL_OR) { return getInversedAndOrExpression(rewrite, infixExpression, InfixExpression.Operator.CONDITIONAL_AND, provider); } if (operator == InfixExpression.Operator.AND) { return getInversedAndOrExpression(rewrite, infixExpression, InfixExpression.Operator.OR, provider); } if (operator == InfixExpression.Operator.OR) { return getInversedAndOrExpression(rewrite, infixExpression, InfixExpression.Operator.AND, provider); } if (operator == InfixExpression.Operator.XOR) { return getInversedNotExpression(rewrite, expression, ast); } } if (expression instanceof PrefixExpression) { PrefixExpression prefixExpression = (PrefixExpression)expression; if (prefixExpression.getOperator() == PrefixExpression.Operator.NOT) { Expression operand = prefixExpression.getOperand(); if ((operand instanceof ParenthesizedExpression) && NecessaryParenthesesChecker.canRemoveParentheses(operand, expression.getParent(), expression.getLocationInParent())) { operand = ((ParenthesizedExpression)operand).getExpression(); } return getRenamedNameCopy(provider, rewrite, operand); } } if (expression instanceof InstanceofExpression) { return getInversedNotExpression(rewrite, expression, ast); } 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 getInversedExpression(rewrite, innerExpression, provider); } parenthesizedExpression = getParenthesizedExpression(ast, getInversedExpression(rewrite, innerExpression, provider)); return parenthesizedExpression; } if (expression instanceof ConditionalExpression) { ConditionalExpression conditionalExpression = (ConditionalExpression)expression; ConditionalExpression newExpression = ast.newConditionalExpression(); newExpression.setExpression((Expression)rewrite.createCopyTarget(conditionalExpression.getExpression())); newExpression.setThenExpression(getInversedExpression(rewrite, conditionalExpression.getThenExpression())); newExpression.setElseExpression(getInversedExpression(rewrite, conditionalExpression.getElseExpression())); return newExpression; } PrefixExpression prefixExpression = ast.newPrefixExpression(); prefixExpression.setOperator(PrefixExpression.Operator.NOT); Expression renamedNameCopy = getRenamedNameCopy(provider, rewrite, expression); if (NecessaryParenthesesChecker.needsParentheses(renamedNameCopy, prefixExpression, PrefixExpression.OPERAND_PROPERTY)) { renamedNameCopy = getParenthesizedExpression(ast, renamedNameCopy); } prefixExpression.setOperand(renamedNameCopy); return prefixExpression; } private static Expression getInversedNotExpression(ASTRewrite rewrite, Expression expression, AST ast) { PrefixExpression prefixExpression = ast.newPrefixExpression(); prefixExpression.setOperator(PrefixExpression.Operator.NOT); ParenthesizedExpression parenthesizedExpression = getParenthesizedExpression(ast, (Expression)rewrite.createCopyTarget(expression)); prefixExpression.setOperand(parenthesizedExpression); return prefixExpression; } private static boolean isBoolean(Expression expression) { ITypeBinding typeBinding = expression.resolveTypeBinding(); AST ast = expression.getAST(); return typeBinding == ast.resolveWellKnownType("boolean") //$NON-NLS-1$ || typeBinding == ast.resolveWellKnownType("java.lang.Boolean"); //$NON-NLS-1$ } private static Expression getInversedInfixExpression(ASTRewrite rewrite, InfixExpression expression, InfixExpression.Operator newOperator, SimpleNameRenameProvider provider) { InfixExpression newExpression = rewrite.getAST().newInfixExpression(); newExpression.setOperator(newOperator); newExpression.setLeftOperand(getRenamedNameCopy(provider, rewrite, expression.getLeftOperand())); newExpression.setRightOperand(getRenamedNameCopy(provider, rewrite, expression.getRightOperand())); return newExpression; } private static Expression parenthesizeIfRequired(Expression operand, int newOperatorPrecedence) { if (newOperatorPrecedence > OperatorPrecedence.getExpressionPrecedence(operand)) { return getParenthesizedExpression(operand.getAST(), operand); } return operand; } private static Expression getInversedAndOrExpression(ASTRewrite rewrite, InfixExpression infixExpression, Operator newOperator, SimpleNameRenameProvider provider) { InfixExpression newExpression = rewrite.getAST().newInfixExpression(); newExpression.setOperator(newOperator); int newOperatorPrecedence = OperatorPrecedence.getOperatorPrecedence(newOperator); // Expression leftOperand = getInversedExpression(rewrite, infixExpression.getLeftOperand(), provider); newExpression.setLeftOperand(parenthesizeIfRequired(leftOperand, newOperatorPrecedence)); Expression rightOperand = getInversedExpression(rewrite, infixExpression.getRightOperand(), provider); newExpression.setRightOperand(parenthesizeIfRequired(rightOperand, newOperatorPrecedence)); List<Expression> extraOperands = infixExpression.extendedOperands(); List<Expression> newExtraOperands = newExpression.extendedOperands(); for (int i = 0; i < extraOperands.size(); i++) { Expression extraOperand = getInversedExpression(rewrite, extraOperands.get(i), provider); newExtraOperands.add(parenthesizeIfRequired(extraOperand, newOperatorPrecedence)); } return newExpression; } private static boolean getRemoveExtraParenthesesProposals(InvocationContext context, ASTNode covering, ArrayList<ASTNode> coveredNodes, Collection<ICommandAccess> resultingCollections) { ArrayList<ASTNode> nodes; if (context.getSelectionLength() == 0 && covering instanceof ParenthesizedExpression) { nodes = new ArrayList<ASTNode>(); nodes.add(covering); } else { nodes = coveredNodes; } if (nodes.isEmpty()) return false; IProposableFix fix = ExpressionsFix.createRemoveUnnecessaryParenthesisFix(context.getASTRoot(), nodes.toArray(new ASTNode[nodes.size()]), context.getDocument()); if (fix == null) return false; if (resultingCollections == null) return true; Images image = Images.delete_obj; Map<String, String> options = new HashMap<String, String>(); options.put(CleanUpConstants.EXPRESSIONS_USE_PARENTHESES, CleanUpOptions.TRUE); options.put(CleanUpConstants.EXPRESSIONS_USE_PARENTHESES_NEVER, CleanUpOptions.TRUE); FixCorrectionProposal proposal = new FixCorrectionProposal(fix, new ExpressionsCleanUp(options), 1, image, context); resultingCollections.add(proposal); return true; } private static boolean getAddParanoidalParenthesesProposals(InvocationContext context, ArrayList<ASTNode> coveredNodes, Collection<ICommandAccess> resultingCollections) { IProposableFix fix = ExpressionsFix.createAddParanoidalParenthesisFix(context.getASTRoot(), coveredNodes.toArray(new ASTNode[coveredNodes.size()]), context.getDocument()); if (fix == null) return false; if (resultingCollections == null) return true; // add correction proposal Images image = Images.correction_cast; Map<String, String> options = new HashMap<String, String>(); options.put(CleanUpConstants.EXPRESSIONS_USE_PARENTHESES, CleanUpOptions.TRUE); options.put(CleanUpConstants.EXPRESSIONS_USE_PARENTHESES_ALWAYS, CleanUpOptions.TRUE); FixCorrectionProposal proposal = new FixCorrectionProposal(fix, new ExpressionsCleanUp(options), -9, image, context); resultingCollections.add(proposal); return true; } private static boolean getAddParenthesesForExpressionProposals(InvocationContext context, ASTNode coveringNode, Collection<ICommandAccess> resultingCollections) { ASTNode node; if (context.getSelectionLength() == 0) { node = coveringNode; while (node != null && !(node instanceof CastExpression) && !(node instanceof InfixExpression) && !(node instanceof InstanceofExpression) && !(node instanceof ConditionalExpression)) { node = node.getParent(); } } else { node = context.getCoveredNode(); } String label = null; if (node instanceof CastExpression) { label = CorrectionMessages.INSTANCE.UnresolvedElementsSubProcessor_missingcastbrackets_description(); } else if (node instanceof InstanceofExpression) { label = CorrectionMessages.INSTANCE.LocalCorrectionsSubProcessor_setparenteses_instanceof_description(); } else if (node instanceof InfixExpression) { InfixExpression infixExpression = (InfixExpression)node; label = CorrectionMessages.INSTANCE.LocalCorrectionsSubProcessor_setparenteses_description(infixExpression .getOperator().toString()); } else if (node instanceof ConditionalExpression) { label = CorrectionMessages.INSTANCE.AdvancedQuickAssistProcessor_putConditionalExpressionInParentheses(); } else { return false; } if (node.getParent() instanceof ParenthesizedExpression) return false; if (resultingCollections == null) return true; AST ast = node.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); ParenthesizedExpression parenthesizedExpression = ast.newParenthesizedExpression(); parenthesizedExpression.setExpression((Expression)rewrite.createCopyTarget(node)); rewrite.replace(node, parenthesizedExpression, null); Images image = Images.correction_cast; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, -10, context.getDocument(), image); resultingCollections.add(proposal); return true; } static ArrayList<ASTNode> getFullyCoveredNodes(InvocationContext context, ASTNode coveringNode) { final ArrayList<ASTNode> coveredNodes = new ArrayList<ASTNode>(); final int selectionBegin = context.getSelectionOffset(); final int selectionEnd = selectionBegin + context.getSelectionLength(); coveringNode.accept(new GenericVisitor() { @Override 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(InvocationContext context, ASTNode node, Collection<ICommandAccess> resultingCollections) { // if (!(node instanceof IfStatement)) { return false; } IfStatement ifStatement = (IfStatement)node; 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 = node.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); // create compound condition InfixExpression condition = ast.newInfixExpression(); condition.setOperator(InfixExpression.Operator.CONDITIONAL_AND); // prepare condition parts, add parentheses if needed Expression outerCondition = getParenthesizedExpressionIfNeeded(ast, rewrite, outerIf.getExpression(), condition, InfixExpression.LEFT_OPERAND_PROPERTY); Expression innerCondition = getParenthesizedExpressionIfNeeded(ast, rewrite, ifStatement.getExpression(), condition, InfixExpression.RIGHT_OPERAND_PROPERTY); 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.INSTANCE.AdvancedQuickAssistProcessor_joinWithOuter_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); } } // 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 = node.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); // create compound condition InfixExpression condition = ast.newInfixExpression(); condition.setOperator(InfixExpression.Operator.CONDITIONAL_AND); // prepare condition parts, add parentheses if needed Expression outerCondition = getParenthesizedExpressionIfNeeded(ast, rewrite, ifStatement.getExpression(), condition, InfixExpression.LEFT_OPERAND_PROPERTY); Expression innerCondition = getParenthesizedExpressionIfNeeded(ast, rewrite, innerIf.getExpression(), condition, InfixExpression.RIGHT_OPERAND_PROPERTY); 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.INSTANCE.AdvancedQuickAssistProcessor_joinWithInner_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); } } return true; } private static Expression getParenthesizedExpressionIfNeeded(AST ast, ASTRewrite rewrite, Expression expression, ASTNode parent, StructuralPropertyDescriptor locationInParent) { boolean addParentheses = NecessaryParenthesesChecker.needsParentheses(expression, parent, locationInParent); expression = (Expression)rewrite.createCopyTarget(expression); if (addParentheses) { return getParenthesizedExpression(ast, expression); } return expression; } private static ParenthesizedExpression getParenthesizedExpression(AST ast, Expression expression) { ParenthesizedExpression parenthesizedExpression = ast.newParenthesizedExpression(); parenthesizedExpression.setExpression(expression); return parenthesizedExpression; } public static boolean getSplitAndConditionProposals(InvocationContext context, ASTNode node, Collection<ICommandAccess> 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; // 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 conditions in outer IfStatement rewrite.set(ifStatement, IfStatement.EXPRESSION_PROPERTY, leftCondition, null); // prepare inner IfStatement IfStatement innerIf = ast.newIfStatement(); innerIf.setExpression(rightCondition); innerIf.setThenStatement((Statement)rewrite.createMoveTarget(ifStatement.getThenStatement())); Block innerBlock = ast.newBlock(); innerBlock.statements().add(innerIf); Statement elseStatement = ifStatement.getElseStatement(); if (elseStatement != null) { innerIf.setElseStatement((Statement)rewrite.createCopyTarget(elseStatement)); } // replace outer thenStatement rewrite.replace(ifStatement.getThenStatement(), innerBlock, null); // add correction proposal String label = CorrectionMessages.INSTANCE.AdvancedQuickAssistProcessor_splitAndCondition_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), 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<Expression> extended = infixExpression.extendedOperands(); for (int i = 0; i < extended.size(); i++) { left = right; right = extended.get(i); if (isSelectingOperator(left, right, offset, length)) { return ASTNodes.getExclusiveEnd(left); } } return -1; } private static boolean getJoinOrIfStatementsProposals(InvocationContext context, ASTNode covering, ArrayList<ASTNode> coveredNodes, Collection<ICommandAccess> 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<ASTNode> iter = coveredNodes.iterator(); iter.hasNext(); ) { ASTNode node = iter.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.getDocument().get(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<ASTNode> iter = coveredNodes.iterator(); iter.hasNext(); ) { IfStatement ifStatement = (IfStatement)iter.next(); if (thenStatement == null) thenStatement = (Statement)rewrite.createCopyTarget(ifStatement.getThenStatement()); if (condition == null) { condition = ast.newInfixExpression(); condition.setOperator(orOperator); condition.setLeftOperand(getParenthesizedExpressionIfNeeded(ast, rewrite, ifStatement.getExpression(), condition, InfixExpression.LEFT_OPERAND_PROPERTY)); } else if (!hasRightOperand) { condition.setRightOperand(getParenthesizedExpressionIfNeeded(ast, rewrite, ifStatement.getExpression(), condition, InfixExpression.RIGHT_OPERAND_PROPERTY)); hasRightOperand = true; } else { InfixExpression newCondition = ast.newInfixExpression(); newCondition.setOperator(orOperator); newCondition.setLeftOperand(condition); newCondition.setRightOperand(getParenthesizedExpressionIfNeeded(ast, rewrite, ifStatement.getExpression(), condition, InfixExpression.RIGHT_OPERAND_PROPERTY)); condition = newCondition; } } // prepare new IfStatement with OR'ed condition IfStatement newIf = ast.newIfStatement(); newIf.setExpression(condition); newIf.setThenStatement(thenStatement); // ListRewrite listRewriter = null; for (Iterator<ASTNode> iter = coveredNodes.iterator(); iter.hasNext(); ) { IfStatement ifStatement = (IfStatement)iter.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.INSTANCE.AdvancedQuickAssistProcessor_joinWithOr_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } public static boolean getSplitOrConditionProposals(InvocationContext context, ASTNode node, Collection<ICommandAccess> 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; // 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 rewrite.replace(ifStatement.getExpression(), leftCondition, null); IfStatement secondIf = ast.newIfStatement(); secondIf.setExpression(rightCondition); secondIf.setThenStatement((Statement)rewrite.createCopyTarget(ifStatement.getThenStatement())); Statement elseStatement = ifStatement.getElseStatement(); if (elseStatement == null) { rewrite.set(ifStatement, IfStatement.ELSE_STATEMENT_PROPERTY, secondIf, null); } else { rewrite.replace(elseStatement, secondIf, null); secondIf.setElseStatement((Statement)rewrite.createMoveTarget(elseStatement)); } // add correction proposal String label = CorrectionMessages.INSTANCE.AdvancedQuickAssistProcessor_splitOrCondition_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } private static boolean getInverseConditionalExpressionProposals(InvocationContext context, ASTNode covering, Collection<ICommandAccess> 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; // we could produce quick assist if (resultingCollections == null) { return true; } // AST ast = covering.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); // prepare new conditional expression ConditionalExpression newExpression = ast.newConditionalExpression(); newExpression.setExpression(getInversedExpression(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.INSTANCE.AdvancedQuickAssistProcessor_inverseConditionalExpression_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } private static boolean getExchangeInnerAndOuterIfConditionsProposals(InvocationContext context, ASTNode node, Collection<ICommandAccess> resultingCollections) { boolean result = false; // if (!(node instanceof IfStatement)) { return false; } IfStatement ifStatement = (IfStatement)node; 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 = node.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.INSTANCE.AdvancedQuickAssistProcessor_exchangeInnerAndOuterIfConditions_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), 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 = node.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.INSTANCE.AdvancedQuickAssistProcessor_exchangeInnerAndOuterIfConditions_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); result = true; } } return result; } private static boolean getExchangeOperandsProposals(InvocationContext context, ASTNode node, Collection<ICommandAccess> 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.NOT_EQUALS && operator != InfixExpression.Operator.LESS && operator != InfixExpression.Operator.LESS_EQUALS && operator != InfixExpression.Operator.GREATER && operator != InfixExpression.Operator.GREATER_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; } // 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(), false, operator); if (infixExpression.getRightOperand().getStartPosition() <= context.getSelectionOffset()) { leftExpression = combineOperands(rewrite, leftExpression, infixExpression.getRightOperand(), false, operator); } else { rightExpression = combineOperands(rewrite, rightExpression, infixExpression.getRightOperand(), false, operator); } for (Iterator<Expression> iter = currentExpression.extendedOperands().iterator(); iter.hasNext(); ) { Expression extendedOperand = iter.next(); if (extendedOperand.getStartPosition() <= context.getSelectionOffset()) { leftExpression = combineOperands(rewrite, leftExpression, extendedOperand, false, operator); } else { rightExpression = combineOperands(rewrite, rightExpression, extendedOperand, false, operator); } } if (NecessaryParenthesesChecker.needsParentheses(leftExpression, infixExpression, InfixExpression.RIGHT_OPERAND_PROPERTY)) { leftExpression = getParenthesizedExpression(ast, leftExpression); } if (NecessaryParenthesesChecker.needsParentheses(rightExpression, infixExpression, InfixExpression.LEFT_OPERAND_PROPERTY)) { rightExpression = getParenthesizedExpression(ast, rightExpression); } if (operator == InfixExpression.Operator.LESS) { operator = InfixExpression.Operator.GREATER; } else if (operator == InfixExpression.Operator.LESS_EQUALS) { operator = InfixExpression.Operator.GREATER_EQUALS; } else if (operator == InfixExpression.Operator.GREATER) { operator = InfixExpression.Operator.LESS; } else if (operator == InfixExpression.Operator.GREATER_EQUALS) { operator = InfixExpression.Operator.LESS_EQUALS; } // 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.INSTANCE.AdvancedQuickAssistProcessor_exchangeOperands_description(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), 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) */ private static void breakInfixOperationAtOperation(ASTRewrite rewrite, Expression expression, Operator operator, int operatorOffset, boolean removeParentheses, Expression[] res) { if (expression.getStartPosition() + expression.getLength() <= operatorOffset) { // add to the left res[0] = combineOperands(rewrite, res[0], expression, removeParentheses, operator); return; } if (operatorOffset <= expression.getStartPosition()) { // add to the right res[1] = combineOperands(rewrite, res[1], expression, removeParentheses, 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, removeParentheses, res); breakInfixOperationAtOperation(rewrite, infixExpression.getRightOperand(), operator, operatorOffset, removeParentheses, res); List<Expression> extended = infixExpression.extendedOperands(); for (int i = 0; i < extended.size(); i++) { breakInfixOperationAtOperation(rewrite, extended.get(i), operator, operatorOffset, removeParentheses, res); } } private static Expression combineOperands(ASTRewrite rewrite, Expression existing, Expression originalNode, boolean removeParentheses, Operator operator) { if (existing == null && removeParentheses) { while (originalNode instanceof ParenthesizedExpression) { originalNode = ((ParenthesizedExpression)originalNode).getExpression(); } } Expression newRight = (Expression)rewrite.createMoveTarget(originalNode); if (originalNode instanceof InfixExpression) { ((InfixExpression)newRight).setOperator(((InfixExpression)originalNode).getOperator()); } 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(InvocationContext context, ASTNode node, Collection<ICommandAccess> resultingCollections) { if (node instanceof IfStatement) { node = ((IfStatement)node).getExpression(); } else if (node instanceof WhileStatement) { node = ((WhileStatement)node).getExpression(); } else if (node instanceof Block) { List<Statement> statements = ((Block)node).statements(); if (statements.size() > 0) { if (context.getSelectionOffset() > statements.get(0).getStartPosition()) { return false; } } ASTNode parent = node.getParent(); Expression expression = null; if (parent instanceof IfStatement) { expression = ((IfStatement)parent).getExpression(); } else if (parent instanceof WhileStatement) { expression = ((WhileStatement)parent).getExpression(); } else { return false; } if (expression instanceof InstanceofExpression) { node = expression; } else { final ArrayList<InstanceofExpression> nodes = new ArrayList<InstanceofExpression>(); expression.accept(new ASTVisitor() { @Override public boolean visit(InstanceofExpression instanceofExpression) { nodes.add(instanceofExpression); return false; } }); if (nodes.size() != 1) { return false; } node = nodes.get(0); } } else { while (node != null && !(node instanceof InstanceofExpression) && !(node instanceof Statement)) { node = node.getParent(); } } 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; } // 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); // prepare correction proposal String label = CorrectionMessages.INSTANCE.AdvancedQuickAssistProcessor_castAndAssign(); Images image = Images.local_var; LinkedCorrectionProposal proposal = new LinkedCorrectionProposal(label, rewrite, 7, context.getDocument(), image); // prepare possible variable names List<String> excludedNames = Arrays.asList(ASTResolving.getUsedVariableNames(body)); String[] varNames = suggestLocalVariableNames(originalType.resolveBinding(), excludedNames); // 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<Statement> statements = newBlock.statements(); statements.add(vds); statements.add((Statement)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(ITypeBinding binding, List<String> excluded) { return StubUtility.getVariableNameSuggestions(NamingConventions.VK_LOCAL, binding, null, excluded); } private static boolean getPickOutStringProposals(InvocationContext context, ASTNode node, Collection<ICommandAccess> 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.INSTANCE.AdvancedQuickAssistProcessor_pickSelectedString(); Images image = Images.correction_change; LinkedCorrectionProposal proposal = new LinkedCorrectionProposal(label, rewrite, 1, context.getDocument(), 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<Statement> blockStatements = ((Block)statement).statements(); if (blockStatements.size() != 1) { return null; } return blockStatements.get(0); } return statement; } private static boolean getReplaceIfElseWithConditionalProposals(InvocationContext context, ASTNode node, Collection<ICommandAccess> 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; } // we could produce quick assist if (resultingCollections == null) { return true; } // AST ast = node.getAST(); ASTRewrite rewrite = ASTRewrite.create(ast); TightSourceRangeComputer sourceRangeComputer = new TightSourceRangeComputer(); sourceRangeComputer.addTightSourceNode(ifStatement); rewrite.setTargetSourceRangeComputer(sourceRangeComputer); String label = CorrectionMessages.INSTANCE.AdvancedQuickAssistProcessor_replaceIfWithConditional(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), 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(project)) // { // ITypeBinding thenBinding = thenExpression.resolveTypeBinding(); // ITypeBinding elseBinding = elseExpression.resolveTypeBinding(); // if (thenBinding != null && elseBinding != null && exprBinding != null // && !elseBinding.isAssignmentCompatible(thenBinding)) // { // CastExpression castException = ast.newCastExpression(); // ImportRewrite importRewrite = proposal.createImportRewrite(context.getASTRoot()); // ImportRewriteContext importRewriteContext = new ContextSensitiveImportRewriteContext(node, importRewrite); // castException.setType(importRewrite.addImport(exprBinding, ast, importRewriteContext)); // castException.setExpression(elseCopy); // elseCopy = castException; // } //TODO Java 7 // } // else if (JavaModelUtil.is17OrHigher(project)) // { // addExplicitTypeArgumentsIfNecessary(rewrite, proposal, thenExpression); // addExplicitTypeArgumentsIfNecessary(rewrite, proposal, elseExpression); // } 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 void addExplicitTypeArgumentsIfNecessary(ASTRewrite rewrite, ASTRewriteCorrectionProposal proposal, Expression invocation) { if (Invocations.isResolvedTypeInferredFromExpectedType(invocation)) { ITypeBinding[] typeArguments = Invocations.getInferredTypeArguments(invocation); if (typeArguments == null) return; ImportRewrite importRewrite = proposal.getImportRewrite(); if (importRewrite == null) { importRewrite = proposal.createImportRewrite((CompilationUnit)invocation.getRoot()); } ImportRewriteContext importRewriteContext = new ContextSensitiveImportRewriteContext(invocation, importRewrite); AST ast = invocation.getAST(); ListRewrite typeArgsRewrite = Invocations.getInferredTypeArgumentsRewrite(rewrite, invocation); for (int i = 0; i < typeArguments.length; i++) { Type typeArgumentNode = importRewrite.addImport(typeArguments[i], ast, importRewriteContext); typeArgsRewrite.insertLast(typeArgumentNode, null); } if (invocation instanceof MethodInvocation) { MethodInvocation methodInvocation = (MethodInvocation)invocation; Expression expression = methodInvocation.getExpression(); if (expression == null) { IMethodBinding methodBinding = methodInvocation.resolveMethodBinding(); if (methodBinding != null && Modifier.isStatic(methodBinding.getModifiers())) { expression = ast.newName(importRewrite.addImport(methodBinding.getDeclaringClass().getTypeDeclaration(), importRewriteContext)); } else { expression = ast.newThisExpression(); } rewrite.set(invocation, MethodInvocation.EXPRESSION_PROPERTY, expression, null); } } } } 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(InvocationContext context, ASTNode covering, Collection<ICommandAccess> resultingCollections) { ASTNode node = covering; while (!(node instanceof ConditionalExpression) && node instanceof Expression) { node = node.getParent(); } if (!(node instanceof ConditionalExpression)) { node = covering; while (node != null && !(node instanceof Statement)) { node = node.getParent(); } if (node instanceof VariableDeclarationStatement) { node = (ASTNode)(((VariableDeclarationStatement)node).fragments().get(0)); node = ((VariableDeclarationFragment)node).getInitializer(); } if (node instanceof ExpressionStatement) { node = ((ExpressionStatement)node).getExpression(); if (node instanceof Assignment) { node = ((Assignment)node).getRightHandSide(); } } if (node instanceof ReturnStatement) { node = ((ReturnStatement)node).getExpression(); } } if (!(node instanceof ConditionalExpression)) { return false; } covering = node; 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; // 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.INSTANCE.AdvancedQuickAssistProcessor_replaceConditionalWithIf(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } private static boolean getInverseLocalVariableProposals(InvocationContext context, ASTNode covering, Collection<ICommandAccess> 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; } // 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.INSTANCE.AdvancedQuickAssistProcessor_inverseBooleanVariable(); Images image = Images.correction_change; final String KEY_NAME = "name"; //$NON-NLS-1$ final LinkedCorrectionProposal proposal = new LinkedCorrectionProposal(label, rewrite, 1, context.getDocument(), image); // prepare new variable identifier final String oldIdentifier = coveringName.getIdentifier(); final String notString = CorrectionMessages.INSTANCE.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 = CorrectionMessages.INSTANCE.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<SimpleName> renamedNames = new HashSet<SimpleName>(); 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<SimpleName> overlapNames = new HashSet<SimpleName>(); 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 inverted 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 = getInversedExpression(rewrite, expression, provider); // if any name was not renamed during expression inverting, we can not already rename it, so fail to create assist for (Iterator<SimpleName> iter = overlapNames.iterator(); iter.hasNext(); ) { Object o = iter.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, getInversedExpression(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(InvocationContext context, ASTNode covering, Collection<ICommandAccess> 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 || (!(parenthesizedExpression.getExpression() instanceof InfixExpression) && !(parenthesizedExpression .getExpression() instanceof ConditionalExpression))) { return false; } // we could produce quick assist if (resultingCollections == null) { return true; } // final AST ast = covering.getAST(); final ASTRewrite rewrite = ASTRewrite.create(ast); // prepared inverted expression Expression inversedExpression = getInversedExpression(rewrite, parenthesizedExpression.getExpression()); // check, may be we should keep parentheses boolean keepParentheses = false; if (negationExpression.getParent() instanceof Expression) { int parentPrecedence = OperatorPrecedence.getExpressionPrecedence(((Expression)negationExpression.getParent())); int inversedExpressionPrecedence = OperatorPrecedence.getExpressionPrecedence(inversedExpression); keepParentheses = parentPrecedence > inversedExpressionPrecedence; } // replace negated expression with inverted 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.INSTANCE.AdvancedQuickAssistProcessor_pushNegationDown(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), 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 == AssertStatement.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(InvocationContext context, ArrayList<ASTNode> coveredNodes, Collection<ICommandAccess> resultingCollections) { if (coveredNodes.size() != 1) { return false; } // ASTNode fullyCoveredNode = coveredNodes.get(0); Expression expression = getBooleanExpression(fullyCoveredNode); if (expression == null || (!(expression instanceof InfixExpression) && !(expression instanceof ConditionalExpression))) { return false; } // we could produce quick assist if (resultingCollections == null) { return true; } // AST ast = expression.getAST(); final ASTRewrite rewrite = ASTRewrite.create(ast); // prepared inverted expression Expression inversedExpression = getInversedExpression(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 expression rewrite.replace(expression, prefixExpression, null); // add correction proposal String label = CorrectionMessages.INSTANCE.AdvancedQuickAssistProcessor_pullNegationUp(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } private static boolean getJoinIfListInIfElseIfProposals(InvocationContext context, ASTNode covering, ArrayList<ASTNode> coveredNodes, Collection<ICommandAccess> 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<ASTNode> iter = coveredNodes.iterator(); iter.hasNext(); ) { ASTNode node = iter.next(); if (!(node instanceof IfStatement)) { return false; } IfStatement ifStatement = (IfStatement)node; if (ifStatement.getElseStatement() != null) { return false; } } // 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<ASTNode> iter = coveredNodes.iterator(); iter.hasNext(); ) { IfStatement ifStatement = (IfStatement)iter.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.INSTANCE.AdvancedQuickAssistProcessor_joinIfSequence(); Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(label, rewrite, 1, context.getDocument(), image); resultingCollections.add(proposal); return true; } private static boolean getConvertSwitchToIfProposals(InvocationContext context, ASTNode covering, Collection<ICommandAccess> resultingCollections) { if (!(covering instanceof SwitchStatement)) { return false; } // 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); final ImportRewrite importRewrite = StubUtility.createImportRewrite(context.getDocument(), context.getASTRoot(), true); // SwitchStatement switchStatement = (SwitchStatement)covering; ITypeBinding expressionType = switchStatement.getExpression().resolveTypeBinding(); boolean isStringsInSwitch = expressionType != null && "java.lang.String".equals(expressionType.getQualifiedName()); //$NON-NLS-1$ IfStatement firstIfStatement = null; IfStatement currentIfStatement = null; Block currentBlock = null; boolean hasStopAsLastExecutableStatement = false; Block defaultBlock = null; Expression currentCondition = null; boolean defaultFound = false; ArrayList<Block> allBlocks = new ArrayList<Block>(); ImportRewriteContext importRewriteContext = new ContextSensitiveImportRewriteContext(ASTResolving.findParentBodyDeclaration(covering), importRewrite); for (Iterator<Statement> iter = switchStatement.statements().iterator(); iter.hasNext(); ) { Statement statement = iter.next(); if (statement instanceof SwitchCase) { SwitchCase switchCase = (SwitchCase)statement; // special case: pass through 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 Expression switchCaseCondition = createSwitchCaseCondition(ast, rewrite, importRewrite, importRewriteContext, switchStatement, switchCase, isStringsInSwitch); 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 { // 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 } } if (statement instanceof BreakStatement) { currentBlock = null; } else { // add current statement in current 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 = allBlocks.get(i); List<Statement> 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); // add correction proposal Images image = Images.correction_change; ASTRewriteCorrectionProposal proposal = new ASTRewriteCorrectionProposal(CorrectionMessages.INSTANCE.AdvancedQuickAssistProcessor_convertSwitchToIf(), rewrite, 1, context.getDocument(), image); proposal.setImportRewrite(importRewrite); resultingCollections.add(proposal); return true; } private static Expression createSwitchCaseCondition(AST ast, ASTRewrite rewrite, ImportRewrite importRewrite, ImportRewriteContext importRewriteContext, SwitchStatement switchStatement, SwitchCase switchCase, boolean isStringsInSwitch) { Expression expression = switchCase.getExpression(); if (isStringsInSwitch) { MethodInvocation methodInvocation = ast.newMethodInvocation(); methodInvocation.setExpression((Expression)rewrite.createCopyTarget(expression)); methodInvocation.setName(ast.newSimpleName("equals")); //$NON-NLS-1$ methodInvocation.arguments().add(rewrite.createCopyTarget(switchStatement.getExpression())); return methodInvocation; } else { InfixExpression condition = ast.newInfixExpression(); condition.setOperator(InfixExpression.Operator.EQUALS); Expression leftExpression = getParenthesizedExpressionIfNeeded(ast, rewrite, switchStatement.getExpression(), condition, InfixExpression.LEFT_OPERAND_PROPERTY); condition.setLeftOperand(leftExpression); Expression rightExpression = null; if (expression instanceof SimpleName && ((SimpleName)expression).resolveBinding() instanceof IVariableBinding) { IVariableBinding binding = (IVariableBinding)((SimpleName)expression).resolveBinding(); if (binding.isEnumConstant()) { String qualifiedName = importRewrite.addImport(binding.getDeclaringClass(), importRewriteContext) + '.' + binding.getName(); rightExpression = ast.newName(qualifiedName); } } if (rightExpression == null) { rightExpression = (Expression)rewrite.createCopyTarget(expression); } 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<Statement> iter = block.statements().iterator(); iter.hasNext(); ) { Statement statement = iter.next(); if (statement instanceof BreakStatement) { continue; } newBlock.statements().add(copyStatementExceptBreak(ast, rewrite, statement)); } return newBlock; } return (Statement)rewrite.createMoveTarget(source); } }