| /******************************************************************************* |
| * Copyright (c) 2000, 2012 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Konstantin Scheglov (scheglov_ke@nlmk.ru) - initial API and implementation |
| * (reports 71244 & 74746: New Quick Assist's [quick assist]) |
| * IBM Corporation - implementation |
| *******************************************************************************/ |
| package org.eclipse.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.dom.StatementRewrite; |
| 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.ui.text.java.correction.ASTRewriteCorrectionProposal; |
| import org.eclipse.jdt.ui.text.java.correction.ICommandAccess; |
| |
| import org.eclipse.jdt.internal.ui.JavaPluginImages; |
| import org.eclipse.jdt.internal.ui.fix.ExpressionsCleanUp; |
| 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$ |
| 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); |
| |
| Expression switchExpression= switchStatement.getExpression(); |
| Name varName; |
| VariableDeclarationStatement variableDeclarationStatement= null; |
| if (switchExpression instanceof Name) { |
| varName= (Name) switchExpression; |
| } else { |
| // Switch expression could have side effects, see bug 252040 |
| VariableDeclarationFragment variableDeclarationFragment= ast.newVariableDeclarationFragment(); |
| String[] varNames= StubUtility.getVariableNameSuggestions(NamingConventions.VK_LOCAL, context.getCompilationUnit().getJavaProject(), expressionType, switchExpression, null); |
| varName= ast.newSimpleName(varNames[0]); |
| variableDeclarationFragment.setName((SimpleName) varName); |
| variableDeclarationFragment.setStructuralProperty(VariableDeclarationFragment.INITIALIZER_PROPERTY, rewrite.createCopyTarget(switchExpression)); |
| |
| variableDeclarationStatement= ast.newVariableDeclarationStatement(variableDeclarationFragment); |
| Type type= importRewrite.addImport(expressionType, ast, importRewriteContext); |
| variableDeclarationStatement.setType(type); |
| } |
| |
| 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, varName, 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); |
| } |
| } |
| |
| if (variableDeclarationStatement == null) { |
| // replace 'switch' with single if-else-if statement |
| rewrite.replace(switchStatement, firstIfStatement, null); |
| } else { |
| new StatementRewrite(rewrite, new ASTNode[] { switchStatement }).replace(new ASTNode[] { variableDeclarationStatement, firstIfStatement }, null); |
| } |
| |
| // add correction proposal |
| Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
| ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(CorrectionMessages.AdvancedQuickAssistProcessor_convertSwitchToIf, 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, Name switchExpression, |
| 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.createStringPlaceholder(switchExpression.getFullyQualifiedName(), ASTNode.QUALIFIED_NAME)); |
| return methodInvocation; |
| } else { |
| InfixExpression condition= ast.newInfixExpression(); |
| condition.setOperator(InfixExpression.Operator.EQUALS); |
| condition.setLeftOperand((Expression) rewrite.createStringPlaceholder(switchExpression.getFullyQualifiedName(), ASTNode.QUALIFIED_NAME)); |
| |
| 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); |
| } |
| } |