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