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