blob: 77022f12df2b9260abcea992a06eea9b2f7ebc74 [file] [log] [blame]
/*******************************************************************************
* 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
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* 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.jdt.internal.ui.text.correction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.graphics.Image;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.NamingConventions;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.AssertStatement;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BooleanLiteral;
import org.eclipse.jdt.core.dom.BreakStatement;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ConditionalExpression;
import org.eclipse.jdt.core.dom.ConstructorInvocation;
import org.eclipse.jdt.core.dom.ContinueStatement;
import org.eclipse.jdt.core.dom.DoStatement;
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.ForStatement;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
import org.eclipse.jdt.core.dom.InstanceofExpression;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
import org.eclipse.jdt.core.dom.PrefixExpression;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
import org.eclipse.jdt.core.dom.SwitchCase;
import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.core.dom.WhileStatement;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
import org.eclipse.jdt.internal.corext.dom.NecessaryParenthesesChecker;
import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
import org.eclipse.jdt.internal.corext.fix.ExpressionsFix;
import org.eclipse.jdt.internal.corext.fix.IProposableFix;
import org.eclipse.jdt.internal.corext.refactoring.code.Invocations;
import org.eclipse.jdt.internal.corext.refactoring.code.OperatorPrecedence;
import org.eclipse.jdt.internal.corext.refactoring.util.TightSourceRangeComputer;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
import org.eclipse.jdt.ui.text.java.IInvocationContext;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.IProblemLocation;
import org.eclipse.jdt.ui.text.java.IQuickAssistProcessor;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.fix.ExpressionsCleanUp;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ASTRewriteCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.FixCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedCorrectionProposal;
/**
*/
public class AdvancedQuickAssistProcessor implements IQuickAssistProcessor {
public AdvancedQuickAssistProcessor() {
super();
}
/* (non-Javadoc)
* @see org.eclipse.jdt.internal.ui.text.correction.IAssistProcessor#hasAssists(org.eclipse.jdt.internal.ui.text.correction.IAssistContext)
*/
public boolean hasAssists(IInvocationContext context) throws CoreException {
ASTNode coveringNode= context.getCoveringNode();
if (coveringNode != null) {
ArrayList<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 IJavaCompletionProposal[] getAssists(IInvocationContext 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 (QuickAssistProcessor.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 IJavaCompletionProposal[resultingCollections.size()]);
}
return null;
}
private static boolean getIfReturnIntoIfElseAtEndOfVoidMethodProposals(IInvocationContext 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.AdvancedQuickAssistProcessor_convertToIfElse_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static boolean getInverseIfProposals(IInvocationContext context, ASTNode covering, Collection<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.AdvancedQuickAssistProcessor_inverseIf_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static boolean getInverseIfContinueIntoIfThenInLoopsProposals(IInvocationContext context, ASTNode covering, Collection<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.AdvancedQuickAssistProcessor_inverseIfContinue_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static boolean getInverseIfIntoContinueInLoopsProposals(IInvocationContext context, ASTNode covering, Collection<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.AdvancedQuickAssistProcessor_inverseIfToContinue_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static ArrayList<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(IInvocationContext 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.AdvancedQuickAssistProcessor_inverseConditions_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static Expression 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(IInvocationContext 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()]));
if (fix == null)
return false;
if (resultingCollections == null)
return true;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_REMOVE);
Map<String, String> options= new Hashtable<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(IInvocationContext context, ArrayList<ASTNode> coveredNodes, Collection<ICommandAccess> resultingCollections) {
IProposableFix fix= ExpressionsFix.createAddParanoidalParenthesisFix(context.getASTRoot(), coveredNodes.toArray(new ASTNode[coveredNodes.size()]));
if (fix == null)
return false;
if (resultingCollections == null)
return true;
// add correction proposal
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CAST);
Map<String, String> options= new Hashtable<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(IInvocationContext 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.UnresolvedElementsSubProcessor_missingcastbrackets_description;
} else if (node instanceof InstanceofExpression) {
label= CorrectionMessages.LocalCorrectionsSubProcessor_setparenteses_instanceof_description;
} else if (node instanceof InfixExpression) {
InfixExpression infixExpression= (InfixExpression)node;
label= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_setparenteses_description, infixExpression.getOperator().toString());
} else if (node instanceof ConditionalExpression) {
label= CorrectionMessages.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);
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CAST);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, -10, image);
resultingCollections.add(proposal);
return true;
}
static ArrayList<ASTNode> getFullyCoveredNodes(IInvocationContext 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(IInvocationContext 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.AdvancedQuickAssistProcessor_joinWithOuter_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, 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.AdvancedQuickAssistProcessor_joinWithInner_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
}
}
return true;
}
private static Expression 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(IInvocationContext 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.AdvancedQuickAssistProcessor_splitAndCondition_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static boolean isSelectingOperator(ASTNode n1, ASTNode n2, int offset, int length) {
// between the nodes
if (offset + length <= n2.getStartPosition() && offset >= ASTNodes.getExclusiveEnd(n1)) {
return true;
}
// or exactly select the node (but not with infix expressions)
if (n1.getStartPosition() == offset && ASTNodes.getExclusiveEnd(n2) == offset + length) {
if (n1 instanceof InfixExpression || n2 instanceof InfixExpression) {
return false;
}
return true;
}
return false;
}
private static int isOperatorSelected(InfixExpression infixExpression, int offset, int length) {
ASTNode left= infixExpression.getLeftOperand();
ASTNode right= infixExpression.getRightOperand();
if (isSelectingOperator(left, right, offset, length)) {
return ASTNodes.getExclusiveEnd(left);
}
List<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(IInvocationContext 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.getCompilationUnit().getBuffer().getText(thenStatement.getStartPosition(), thenStatement.getLength());
if (commonThenSource == null) {
commonThenSource= thenSource;
} else {
if (!commonThenSource.equals(thenSource))
return false;
}
} catch (Throwable e) {
return false;
}
}
if (resultingCollections == null) {
return true;
}
//
final AST ast= covering.getAST();
final ASTRewrite rewrite= ASTRewrite.create(ast);
// prepare OR'ed condition
InfixExpression condition= null;
boolean hasRightOperand= false;
Statement thenStatement= null;
for (Iterator<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.AdvancedQuickAssistProcessor_joinWithOr_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
public static boolean getSplitOrConditionProposals(IInvocationContext 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.AdvancedQuickAssistProcessor_splitOrCondition_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static boolean getInverseConditionalExpressionProposals(IInvocationContext context, ASTNode covering, Collection<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.AdvancedQuickAssistProcessor_inverseConditionalExpression_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static boolean getExchangeInnerAndOuterIfConditionsProposals(IInvocationContext context, ASTNode node, Collection<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.AdvancedQuickAssistProcessor_exchangeInnerAndOuterIfConditions_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
result= true;
}
}
// case when current IfStatement has another IfStatement as sole child
{
IfStatement innerIf= null;
if (ifStatement.getThenStatement() instanceof IfStatement) {
innerIf= (IfStatement) ifStatement.getThenStatement();
} else if (ifStatement.getThenStatement() instanceof Block) {
Block block= (Block) ifStatement.getThenStatement();
if (block.statements().size() == 1 && block.statements().get(0) instanceof IfStatement) {
innerIf= (IfStatement) block.statements().get(0);
}
}
if (innerIf != null && innerIf.getElseStatement() == null) {
if (resultingCollections == null) {
return true;
}
//
AST ast= 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.AdvancedQuickAssistProcessor_exchangeInnerAndOuterIfConditions_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
result= true;
}
}
return result;
}
private static boolean getExchangeOperandsProposals(IInvocationContext context, ASTNode node, Collection<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.AdvancedQuickAssistProcessor_exchangeOperands_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
/*
* Breaks an infix operation with possible extended operators at the given operator and returns the new left and right operands.
* a & b & c -> [[a' & b' ] & c' ] (c' == copy of c)
*/
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(IInvocationContext 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);
ICompilationUnit cu= context.getCompilationUnit();
// prepare correction proposal
String label= CorrectionMessages.AdvancedQuickAssistProcessor_castAndAssign;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_LOCAL);
LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, cu, rewrite, 7, image);
// prepare possible variable names
List<String> excludedNames= Arrays.asList(ASTResolving.getUsedVariableNames(body));
String[] varNames= suggestLocalVariableNames(cu, 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(ICompilationUnit cu, ITypeBinding binding, List<String> excluded) {
return StubUtility.getVariableNameSuggestions(NamingConventions.VK_LOCAL, cu.getJavaProject(), binding, null, excluded);
}
private static boolean getPickOutStringProposals(IInvocationContext 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.AdvancedQuickAssistProcessor_pickSelectedString;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
proposal.addLinkedPosition(rewrite.track(centerLiteral), true, "CENTER_STRING"); //$NON-NLS-1$
resultingCollections.add(proposal);
return true;
}
private static Statement getSingleStatement(Statement statement) {
if (statement instanceof Block) {
List<Statement> blockStatements= ((Block) statement).statements();
if (blockStatements.size() != 1) {
return null;
}
return blockStatements.get(0);
}
return statement;
}
private static boolean getReplaceIfElseWithConditionalProposals(IInvocationContext 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.AdvancedQuickAssistProcessor_replaceIfWithConditional;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
// prepare conditional expression
ConditionalExpression conditionalExpression= ast.newConditionalExpression();
Expression conditionCopy= (Expression) rewrite.createCopyTarget(ifStatement.getExpression());
conditionalExpression.setExpression(conditionCopy);
Expression thenCopy= (Expression) rewrite.createCopyTarget(thenExpression);
Expression elseCopy= (Expression) rewrite.createCopyTarget(elseExpression);
IJavaProject project= context.getCompilationUnit().getJavaProject();
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;
}
} 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(IInvocationContext 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.AdvancedQuickAssistProcessor_replaceConditionalWithIf;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static boolean getInverseLocalVariableProposals(IInvocationContext context, ASTNode covering, Collection<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.AdvancedQuickAssistProcessor_inverseBooleanVariable;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
final String KEY_NAME= "name"; //$NON-NLS-1$
final LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
// prepare new variable identifier
final String oldIdentifier= coveringName.getIdentifier();
final String notString= Messages.format(CorrectionMessages.AdvancedQuickAssistProcessor_negatedVariableName, ""); //$NON-NLS-1$
final String newIdentifier;
if (oldIdentifier.startsWith(notString)) {
int notLength= notString.length();
if (oldIdentifier.length() > notLength) {
newIdentifier= Character.toLowerCase(oldIdentifier.charAt(notLength)) + oldIdentifier.substring(notLength + 1);
} else {
newIdentifier= oldIdentifier;
}
} else {
newIdentifier= Messages.format(CorrectionMessages.AdvancedQuickAssistProcessor_negatedVariableName, Character.toUpperCase(oldIdentifier.charAt(0)) + oldIdentifier.substring(1));
}
//
proposal.addLinkedPositionProposal(KEY_NAME, newIdentifier, null);
proposal.addLinkedPositionProposal(KEY_NAME, oldIdentifier, null);
// iterate over linked nodes and replace variable references with negated reference
final HashSet<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(IInvocationContext 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.AdvancedQuickAssistProcessor_pushNegationDown;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static Expression getBooleanExpression(ASTNode node) {
if (!(node instanceof Expression)) {
return null;
}
// check if the node is a location where it can be negated
StructuralPropertyDescriptor locationInParent= node.getLocationInParent();
if (locationInParent == QualifiedName.NAME_PROPERTY) {
node= node.getParent();
locationInParent= node.getLocationInParent();
}
while (locationInParent == ParenthesizedExpression.EXPRESSION_PROPERTY) {
node= node.getParent();
locationInParent= node.getLocationInParent();
}
Expression expression= (Expression) node;
if (!isBoolean(expression)) {
return null;
}
if (expression.getParent() instanceof InfixExpression) {
return expression;
}
if (locationInParent == Assignment.RIGHT_HAND_SIDE_PROPERTY || locationInParent == IfStatement.EXPRESSION_PROPERTY
|| locationInParent == WhileStatement.EXPRESSION_PROPERTY || locationInParent == DoStatement.EXPRESSION_PROPERTY
|| locationInParent == ReturnStatement.EXPRESSION_PROPERTY || locationInParent == ForStatement.EXPRESSION_PROPERTY
|| locationInParent == 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(IInvocationContext 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.AdvancedQuickAssistProcessor_pullNegationUp;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static boolean getJoinIfListInIfElseIfProposals(IInvocationContext context, ASTNode covering, ArrayList<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.AdvancedQuickAssistProcessor_joinIfSequence;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, image);
resultingCollections.add(proposal);
return true;
}
private static boolean getConvertSwitchToIfProposals(IInvocationContext context, ASTNode covering, Collection<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.getASTRoot(), true);
//
SwitchStatement switchStatement= (SwitchStatement) covering;
ITypeBinding expressionType= switchStatement.getExpression().resolveTypeBinding();
boolean isStringsInSwitch= expressionType != null && "java.lang.String".equals(expressionType.getQualifiedName()); //$NON-NLS-1$
String label= isStringsInSwitch ? CorrectionMessages.AdvancedQuickAssistProcessor_convertSwitchToIfRemovingNullCheck : CorrectionMessages.AdvancedQuickAssistProcessor_convertSwitchToIf;
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
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 1, 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);
}
}