Bug 571942 - [cleanup & quickfix] Move "Pattern matching for instanceof"
cleanup to implement quickfix

Change-Id: I7a569e274058fee857b85a4ac40b6e1ee6014bb4
Signed-off-by: Fabrice Tiercelin <fabrice.tiercelin@yahoo.fr>
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/PatternMatchingForInstanceofCleanUpCore.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/PatternMatchingForInstanceofCleanUpCore.java
new file mode 100644
index 0000000..a1a4a53
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/PatternMatchingForInstanceofCleanUpCore.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.manipulation.CleanUpContextCore;
+import org.eclipse.jdt.core.manipulation.CleanUpRequirementsCore;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
+import org.eclipse.jdt.internal.corext.fix.PatternMatchingForInstanceofFixCore;
+import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
+
+public class PatternMatchingForInstanceofCleanUpCore extends AbstractCleanUpCore {
+	public PatternMatchingForInstanceofCleanUpCore(final Map<String, String> options) {
+		super(options);
+	}
+
+	public PatternMatchingForInstanceofCleanUpCore() {
+	}
+
+	@Override
+	public CleanUpRequirementsCore getRequirementsCore() {
+		return new CleanUpRequirementsCore(requireAST(), false, false, null);
+	}
+
+	public boolean requireAST() {
+		return isEnabled(CleanUpConstants.USE_PATTERN_MATCHING_FOR_INSTANCEOF);
+	}
+
+	@Override
+	public ICleanUpFixCore createFixCore(final CleanUpContextCore context) throws CoreException {
+		CompilationUnit compilationUnit= context.getAST();
+
+		if (compilationUnit == null
+				|| !isEnabled(CleanUpConstants.USE_PATTERN_MATCHING_FOR_INSTANCEOF)
+				|| !JavaModelUtil.is16OrHigher(compilationUnit.getJavaElement().getJavaProject())) {
+			return null;
+		}
+
+		return PatternMatchingForInstanceofFixCore.createCleanUp(compilationUnit);
+	}
+
+	@Override
+	public String[] getStepDescriptions() {
+		List<String> result= new ArrayList<>();
+
+		if (isEnabled(CleanUpConstants.USE_PATTERN_MATCHING_FOR_INSTANCEOF)) {
+			result.add(MultiFixMessages.PatternMatchingForInstanceofCleanup_description);
+		}
+
+		return result.toArray(new String[0]);
+	}
+
+	@Override
+	public String getPreview() {
+		if (isEnabled(CleanUpConstants.USE_PATTERN_MATCHING_FOR_INSTANCEOF)) {
+			return "" //$NON-NLS-1$
+					+ "if (object instanceof Integer i) {\n" //$NON-NLS-1$
+					+ "    return i.intValue();\n" //$NON-NLS-1$
+					+ "}\n\n"; //$NON-NLS-1$
+		}
+
+		return "" //$NON-NLS-1$
+				+ "if (object instanceof Integer) {\n" //$NON-NLS-1$
+				+ "    Integer i = (Integer) object;\n" //$NON-NLS-1$
+				+ "    return i.intValue();\n" //$NON-NLS-1$
+				+ "}\n"; //$NON-NLS-1$
+	}
+}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java
index 23888f2..d7b1a73 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java
@@ -157,6 +157,7 @@
 	public static String LambdaExpressionsFix_convert_to_anonymous_class_creation;
 	public static String LambdaExpressionsFix_convert_to_lambda_expression;
 	public static String LambdaExpressionsFix_convert_to_lambda_expression_removes_annotations;
+	public static String PatternMatchingForInstanceofFix_refactor;
 	public static String SwitchExpressionsFix_convert_to_switch_expression;
 	public static String SwitchFix_convert_if_to_switch;
 
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties
index d1e005f..9d8d205 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties
@@ -145,6 +145,7 @@
 LambdaExpressionsFix_convert_to_anonymous_class_creation=Convert to anonymous class creation
 LambdaExpressionsFix_convert_to_lambda_expression=Convert to lambda expression
 LambdaExpressionsFix_convert_to_lambda_expression_removes_annotations=Convert to lambda expression (removes annotations on method)
+PatternMatchingForInstanceofFix_refactor=Use pattern matching for instanceof
 SwitchExpressionsFix_convert_to_switch_expression=Convert to switch expression
 SwitchFix_convert_if_to_switch=Convert if/else if/else chain to switch
 TypeParametersFix_insert_inferred_type_arguments_description=Insert inferred type arguments
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/PatternMatchingForInstanceofFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/PatternMatchingForInstanceofFixCore.java
new file mode 100644
index 0000000..230946a
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/PatternMatchingForInstanceofFixCore.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.corext.fix;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.text.edits.TextEditGroup;
+
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.CastExpression;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.IfStatement;
+import org.eclipse.jdt.core.dom.InfixExpression;
+import org.eclipse.jdt.core.dom.InstanceofExpression;
+import org.eclipse.jdt.core.dom.PatternInstanceofExpression;
+import org.eclipse.jdt.core.dom.PrefixExpression;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+import org.eclipse.jdt.core.dom.Statement;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
+
+import org.eclipse.jdt.internal.ui.fix.MultiFixMessages;
+
+public class PatternMatchingForInstanceofFixCore extends CompilationUnitRewriteOperationsFixCore {
+	public static final class PatternMatchingForInstanceofFinder extends ASTVisitor {
+		private List<PatternMatchingForInstanceofFixOperation> fResult;
+
+		public PatternMatchingForInstanceofFinder(List<PatternMatchingForInstanceofFixOperation> ops) {
+			fResult= ops;
+		}
+
+		@Override
+		public boolean visit(final Block visited) {
+			InstanceofVisitor instanceofVisitor= new InstanceofVisitor(visited);
+			visited.accept(instanceofVisitor);
+			return instanceofVisitor.getResult();
+		}
+
+		final class InstanceofVisitor extends ASTVisitor {
+			private final Block startNode;
+			private boolean result= true;
+
+			public InstanceofVisitor(final Block startNode) {
+				this.startNode= startNode;
+			}
+
+			/**
+			 * @return The result
+			 */
+			public boolean getResult() {
+				return result;
+			}
+
+			@Override
+			public boolean visit(final Block visited) {
+				return startNode == visited;
+			}
+
+			@Override
+			public boolean visit(final InstanceofExpression visited) {
+				if (!ASTNodes.isPassive(visited.getLeftOperand())
+						|| visited.getRightOperand().resolveBinding() == null) {
+					return true;
+				}
+
+				boolean isPositiveCaseToAnalyze= true;
+				ASTNode currentNode= visited;
+
+				while (currentNode.getParent() != null
+						&& (!(currentNode.getParent() instanceof IfStatement)
+						|| currentNode.getLocationInParent() != IfStatement.EXPRESSION_PROPERTY)) {
+					switch (currentNode.getParent().getNodeType()) {
+						case ASTNode.PARENTHESIZED_EXPRESSION:
+							break;
+
+						case ASTNode.PREFIX_EXPRESSION:
+							if (!ASTNodes.hasOperator((PrefixExpression) currentNode.getParent(), PrefixExpression.Operator.NOT)) {
+								return true;
+							}
+
+							isPositiveCaseToAnalyze= !isPositiveCaseToAnalyze;
+							break;
+
+						case ASTNode.INFIX_EXPRESSION:
+							if (isPositiveCaseToAnalyze
+									? !ASTNodes.hasOperator((InfixExpression) currentNode.getParent(), InfixExpression.Operator.CONDITIONAL_AND, InfixExpression.Operator.AND)
+											: !ASTNodes.hasOperator((InfixExpression) currentNode.getParent(), InfixExpression.Operator.CONDITIONAL_OR, InfixExpression.Operator.OR)) {
+								return true;
+							}
+
+							break;
+
+						default:
+							return true;
+					}
+
+					currentNode= currentNode.getParent();
+				}
+
+				if (currentNode.getParent() == null) {
+					return true;
+				}
+
+				IfStatement ifStatement= (IfStatement) currentNode.getParent();
+
+				if (isPositiveCaseToAnalyze) {
+					return maybeMatchPattern(visited, ifStatement.getThenStatement());
+				}
+
+				if (ifStatement.getElseStatement() != null) {
+					return maybeMatchPattern(visited, ifStatement.getElseStatement());
+				}
+
+				if (ASTNodes.fallsThrough(ifStatement.getThenStatement())) {
+					return maybeMatchPattern(visited, ASTNodes.getNextSibling(ifStatement));
+				}
+
+				return true;
+			}
+
+			private boolean maybeMatchPattern(final InstanceofExpression visited, final Statement conditionalStatements) {
+				List<Statement> statements= ASTNodes.asList(conditionalStatements);
+
+				if (!statements.isEmpty()) {
+					VariableDeclarationStatement variableDeclarationExpression= ASTNodes.as(statements.get(0), VariableDeclarationStatement.class);
+					VariableDeclarationFragment variableDeclarationFragment= ASTNodes.getUniqueFragment(variableDeclarationExpression);
+
+					if (variableDeclarationFragment != null
+							&& Objects.equals(visited.getRightOperand().resolveBinding(), variableDeclarationExpression.getType().resolveBinding())) {
+						CastExpression castExpression= ASTNodes.as(variableDeclarationFragment.getInitializer(), CastExpression.class);
+
+						if (castExpression != null
+								&& Objects.equals(visited.getRightOperand().resolveBinding(), castExpression.getType().resolveBinding())
+								&& ASTNodes.match(visited.getLeftOperand(), castExpression.getExpression())
+								&& ASTNodes.isPassive(visited.getLeftOperand())) {
+							fResult.add(new PatternMatchingForInstanceofFixOperation(visited, variableDeclarationExpression, variableDeclarationFragment.getName()));
+							return false;
+						}
+					}
+				}
+
+				return true;
+			}
+		}
+	}
+
+	public static class PatternMatchingForInstanceofFixOperation extends CompilationUnitRewriteOperation {
+		private final InstanceofExpression nodeToComplete;
+		private final VariableDeclarationStatement statementToRemove;
+		private final SimpleName expressionToMove;
+
+		public PatternMatchingForInstanceofFixOperation(final InstanceofExpression nodeToComplete, final VariableDeclarationStatement statementToRemove, final SimpleName expressionToMove) {
+			this.nodeToComplete= nodeToComplete;
+			this.statementToRemove= statementToRemove;
+			this.expressionToMove= expressionToMove;
+		}
+
+		@Override
+		public void rewriteAST(final CompilationUnitRewrite cuRewrite, final LinkedProposalModelCore linkedModel) throws CoreException {
+			ASTRewrite rewrite= cuRewrite.getASTRewrite();
+			AST ast= cuRewrite.getRoot().getAST();
+			TextEditGroup group= createTextEditGroup(MultiFixMessages.PatternMatchingForInstanceofCleanup_description, cuRewrite);
+			rewrite.setTargetSourceRangeComputer(new TargetSourceRangeComputer() {
+				@Override
+				public SourceRange computeSourceRange(final ASTNode nodeWithComment) {
+					if (Boolean.TRUE.equals(nodeWithComment.getProperty(ASTNodes.UNTOUCH_COMMENT))) {
+						return new SourceRange(nodeWithComment.getStartPosition(), nodeWithComment.getLength());
+					}
+
+					return super.computeSourceRange(nodeWithComment);
+				}
+			});
+
+			PatternInstanceofExpression newInstanceof= ast.newPatternInstanceofExpression();
+			newInstanceof.setLeftOperand(ASTNodes.createMoveTarget(rewrite, nodeToComplete.getLeftOperand()));
+			SingleVariableDeclaration newSVDecl= ast.newSingleVariableDeclaration();
+			newSVDecl.setName(ASTNodes.createMoveTarget(rewrite, expressionToMove));
+			newSVDecl.setType(ASTNodes.createMoveTarget(rewrite, nodeToComplete.getRightOperand()));
+			newInstanceof.setRightOperand(newSVDecl);
+
+			ASTNodes.replaceButKeepComment(rewrite, nodeToComplete, newInstanceof, group);
+
+			if (ASTNodes.canHaveSiblings(statementToRemove) || statementToRemove.getLocationInParent() == IfStatement.ELSE_STATEMENT_PROPERTY) {
+				rewrite.remove(statementToRemove, group);
+			} else {
+				ASTNodes.replaceButKeepComment(rewrite, statementToRemove, ast.newBlock(), group);
+			}
+		}
+	}
+
+
+	public static ICleanUpFixCore createCleanUp(final CompilationUnit compilationUnit) {
+		List<PatternMatchingForInstanceofFixOperation> operations= new ArrayList<>();
+		PatternMatchingForInstanceofFinder finder= new PatternMatchingForInstanceofFinder(operations);
+		compilationUnit.accept(finder);
+
+		if (operations.isEmpty()) {
+			return null;
+		}
+
+		CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] ops= operations.toArray(new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[0]);
+		return new PatternMatchingForInstanceofFixCore(FixMessages.PatternMatchingForInstanceofFix_refactor, compilationUnit, ops);
+	}
+
+	protected PatternMatchingForInstanceofFixCore(final String name, final CompilationUnit compilationUnit, final CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] fixRewriteOperations) {
+		super(name, compilationUnit, fixRewriteOperations);
+	}
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/PatternMatchingForInstanceofCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/PatternMatchingForInstanceofCleanUp.java
index 970a6f4..bc175c7 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/PatternMatchingForInstanceofCleanUp.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/PatternMatchingForInstanceofCleanUp.java
@@ -14,271 +14,53 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.fix;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
 
-import org.eclipse.text.edits.TextEditGroup;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
 
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.dom.AST;
-import org.eclipse.jdt.core.dom.ASTNode;
-import org.eclipse.jdt.core.dom.ASTVisitor;
-import org.eclipse.jdt.core.dom.Block;
-import org.eclipse.jdt.core.dom.CastExpression;
-import org.eclipse.jdt.core.dom.CompilationUnit;
-import org.eclipse.jdt.core.dom.IfStatement;
-import org.eclipse.jdt.core.dom.InfixExpression;
-import org.eclipse.jdt.core.dom.InstanceofExpression;
-import org.eclipse.jdt.core.dom.PatternInstanceofExpression;
-import org.eclipse.jdt.core.dom.PrefixExpression;
-import org.eclipse.jdt.core.dom.SimpleName;
-import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
-import org.eclipse.jdt.core.dom.Statement;
-import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
-import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
-import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
-import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
-
-import org.eclipse.jdt.internal.corext.dom.ASTNodes;
-import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
-import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFix;
-import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFix.CompilationUnitRewriteOperation;
-import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
-import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
-import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
-
+import org.eclipse.jdt.ui.cleanup.CleanUpContext;
+import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
 import org.eclipse.jdt.ui.cleanup.CleanUpRequirements;
 import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
-import org.eclipse.jdt.ui.text.java.IProblemLocation;
 
 /**
  * A fix that uses pattern matching for the instanceof expression when possible.
  */
-public class PatternMatchingForInstanceofCleanUp extends AbstractMultiFix implements ICleanUpFix {
-	public PatternMatchingForInstanceofCleanUp() {
-		this(Collections.emptyMap());
+public class PatternMatchingForInstanceofCleanUp extends AbstractCleanUp {
+	private PatternMatchingForInstanceofCleanUpCore coreCleanUp= new PatternMatchingForInstanceofCleanUpCore();
+
+	public PatternMatchingForInstanceofCleanUp(final Map<String, String> options) {
+		setOptions(options);
 	}
 
-	public PatternMatchingForInstanceofCleanUp(Map<String, String> options) {
-		super(options);
+	public PatternMatchingForInstanceofCleanUp() {
+	}
+
+	@Override
+	public void setOptions(final CleanUpOptions options) {
+		coreCleanUp.setOptions(options);
 	}
 
 	@Override
 	public CleanUpRequirements getRequirements() {
-		boolean requireAST= isEnabled(CleanUpConstants.USE_PATTERN_MATCHING_FOR_INSTANCEOF);
-		return new CleanUpRequirements(requireAST, false, false, null);
+		return new CleanUpRequirements(coreCleanUp.getRequirementsCore());
+	}
+
+	@Override
+	public ICleanUpFix createFix(final CleanUpContext context) throws CoreException {
+		ICleanUpFixCore fixCore= coreCleanUp.createFixCore(context);
+		return fixCore != null ? new CleanUpFixWrapper(fixCore) : null;
 	}
 
 	@Override
 	public String[] getStepDescriptions() {
-		if (isEnabled(CleanUpConstants.USE_PATTERN_MATCHING_FOR_INSTANCEOF)) {
-			return new String[] { MultiFixMessages.PatternMatchingForInstanceofCleanup_description };
-		}
-
-		return new String[0];
+		return coreCleanUp.getStepDescriptions();
 	}
 
 	@Override
 	public String getPreview() {
-		if (isEnabled(CleanUpConstants.USE_PATTERN_MATCHING_FOR_INSTANCEOF)) {
-			return "" //$NON-NLS-1$
-					+ "if (object instanceof Integer i) {\n" //$NON-NLS-1$
-					+ "    return i.intValue();\n" //$NON-NLS-1$
-					+ "}\n\n"; //$NON-NLS-1$
-		}
-
-		return "" //$NON-NLS-1$
-				+ "if (object instanceof Integer) {\n" //$NON-NLS-1$
-				+ "    Integer i = (Integer) object;\n" //$NON-NLS-1$
-				+ "    return i.intValue();\n" //$NON-NLS-1$
-				+ "}\n"; //$NON-NLS-1$
-	}
-
-	@Override
-	protected ICleanUpFix createFix(CompilationUnit unit) throws CoreException {
-		if (!isEnabled(CleanUpConstants.USE_PATTERN_MATCHING_FOR_INSTANCEOF)
-				|| !JavaModelUtil.is16OrHigher(unit.getJavaElement().getJavaProject())) {
-			return null;
-		}
-
-		final List<CompilationUnitRewriteOperation> rewriteOperations= new ArrayList<>();
-
-		unit.accept(new ASTVisitor() {
-			@Override
-			public boolean visit(final Block visited) {
-				InstanceofVisitor instanceofVisitor= new InstanceofVisitor(visited);
-				visited.accept(instanceofVisitor);
-				return instanceofVisitor.getResult();
-			}
-
-			final class InstanceofVisitor extends ASTVisitor {
-				private final Block startNode;
-				private boolean result= true;
-
-				public InstanceofVisitor(final Block startNode) {
-					this.startNode= startNode;
-				}
-
-				/**
-				 * @return The result
-				 */
-				public boolean getResult() {
-					return result;
-				}
-
-				@Override
-				public boolean visit(final Block visited) {
-					return startNode == visited;
-				}
-
-				@Override
-				public boolean visit(final InstanceofExpression visited) {
-					if (!ASTNodes.isPassive(visited.getLeftOperand())
-							|| visited.getRightOperand().resolveBinding() == null) {
-						return true;
-					}
-
-					boolean isPositiveCaseToAnalyze= true;
-					ASTNode currentNode= visited;
-
-					while (currentNode.getParent() != null
-							&& (!(currentNode.getParent() instanceof IfStatement)
-							|| currentNode.getLocationInParent() != IfStatement.EXPRESSION_PROPERTY)) {
-						switch (currentNode.getParent().getNodeType()) {
-							case ASTNode.PARENTHESIZED_EXPRESSION:
-								break;
-
-							case ASTNode.PREFIX_EXPRESSION:
-								if (!ASTNodes.hasOperator((PrefixExpression) currentNode.getParent(), PrefixExpression.Operator.NOT)) {
-									return true;
-								}
-
-								isPositiveCaseToAnalyze= !isPositiveCaseToAnalyze;
-								break;
-
-							case ASTNode.INFIX_EXPRESSION:
-								if (isPositiveCaseToAnalyze
-										? !ASTNodes.hasOperator((InfixExpression) currentNode.getParent(), InfixExpression.Operator.CONDITIONAL_AND, InfixExpression.Operator.AND)
-												: !ASTNodes.hasOperator((InfixExpression) currentNode.getParent(), InfixExpression.Operator.CONDITIONAL_OR, InfixExpression.Operator.OR)) {
-									return true;
-								}
-
-								break;
-
-							default:
-								return true;
-						}
-
-						currentNode= currentNode.getParent();
-					}
-
-					if (currentNode.getParent() == null) {
-						return true;
-					}
-
-					IfStatement ifStatement= (IfStatement) currentNode.getParent();
-
-					if (isPositiveCaseToAnalyze) {
-						return maybeMatchPattern(visited, ifStatement.getThenStatement());
-					}
-
-					if (ifStatement.getElseStatement() != null) {
-						return maybeMatchPattern(visited, ifStatement.getElseStatement());
-					}
-
-					if (ASTNodes.fallsThrough(ifStatement.getThenStatement())) {
-						return maybeMatchPattern(visited, ASTNodes.getNextSibling(ifStatement));
-					}
-
-					return true;
-				}
-
-				private boolean maybeMatchPattern(final InstanceofExpression visited, final Statement conditionalStatements) {
-					List<Statement> statements= ASTNodes.asList(conditionalStatements);
-
-					if (!statements.isEmpty()) {
-						VariableDeclarationStatement variableDeclarationExpression= ASTNodes.as(statements.get(0), VariableDeclarationStatement.class);
-						VariableDeclarationFragment variableDeclarationFragment= ASTNodes.getUniqueFragment(variableDeclarationExpression);
-
-						if (variableDeclarationFragment != null
-								&& Objects.equals(visited.getRightOperand().resolveBinding(), variableDeclarationExpression.getType().resolveBinding())) {
-							CastExpression castExpression= ASTNodes.as(variableDeclarationFragment.getInitializer(), CastExpression.class);
-
-							if (castExpression != null
-									&& Objects.equals(visited.getRightOperand().resolveBinding(), castExpression.getType().resolveBinding())
-									&& ASTNodes.match(visited.getLeftOperand(), castExpression.getExpression())
-									&& ASTNodes.isPassive(visited.getLeftOperand())) {
-								rewriteOperations.add(new PatternMatchingForInstanceofOperation(visited, variableDeclarationExpression, variableDeclarationFragment.getName()));
-								return false;
-							}
-						}
-					}
-
-					return true;
-				}
-			}
-		});
-
-		if (rewriteOperations.isEmpty()) {
-			return null;
-		}
-
-		return new CompilationUnitRewriteOperationsFix(MultiFixMessages.PatternMatchingForInstanceofCleanup_description, unit,
-				rewriteOperations.toArray(new CompilationUnitRewriteOperation[0]));
-	}
-
-	@Override
-	public CompilationUnitChange createChange(IProgressMonitor progressMonitor) throws CoreException {
-		return null;
-	}
-
-	@Override
-	public boolean canFix(final ICompilationUnit compilationUnit, final IProblemLocation problem) {
-		return false;
-	}
-
-	@Override
-	protected ICleanUpFix createFix(final CompilationUnit unit, final IProblemLocation[] problems) throws CoreException {
-		return null;
-	}
-
-	private static class PatternMatchingForInstanceofOperation extends CompilationUnitRewriteOperation {
-		private final InstanceofExpression nodeToComplete;
-		private final VariableDeclarationStatement statementToRemove;
-		private final SimpleName expressionToMove;
-
-		public PatternMatchingForInstanceofOperation(final InstanceofExpression nodeToComplete, final VariableDeclarationStatement statementToRemove, final SimpleName expressionToMove) {
-			this.nodeToComplete= nodeToComplete;
-			this.statementToRemove= statementToRemove;
-			this.expressionToMove= expressionToMove;
-		}
-
-		@Override
-		public void rewriteAST(final CompilationUnitRewrite cuRewrite, final LinkedProposalModel linkedModel) throws CoreException {
-			ASTRewrite rewrite= cuRewrite.getASTRewrite();
-			AST ast= cuRewrite.getRoot().getAST();
-			TextEditGroup group= createTextEditGroup(MultiFixMessages.PatternMatchingForInstanceofCleanup_description, cuRewrite);
-
-			PatternInstanceofExpression newInstanceof= ast.newPatternInstanceofExpression();
-			newInstanceof.setLeftOperand(ASTNodes.createMoveTarget(rewrite, nodeToComplete.getLeftOperand()));
-			SingleVariableDeclaration newSVDecl= ast.newSingleVariableDeclaration();
-			newSVDecl.setName(ASTNodes.createMoveTarget(rewrite, expressionToMove));
-			newSVDecl.setType(ASTNodes.createMoveTarget(rewrite, nodeToComplete.getRightOperand()));
-			newInstanceof.setRightOperand(newSVDecl);
-
-			ASTNodes.replaceButKeepComment(rewrite, nodeToComplete, newInstanceof, group);
-
-			if (ASTNodes.canHaveSiblings(statementToRemove) || statementToRemove.getLocationInParent() == IfStatement.ELSE_STATEMENT_PROPERTY) {
-				rewrite.remove(statementToRemove, group);
-			} else {
-				ASTNodes.replaceButKeepComment(rewrite, statementToRemove, ast.newBlock(), group);
-			}
-		}
+		return coreCleanUp.getPreview();
 	}
 }