/*******************************************************************************
* 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);
}
}