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();
}
}