2424import org .eclipse .jdt .core .dom .AST ;
2525import org .eclipse .jdt .core .dom .ASTNode ;
2626import org .eclipse .jdt .core .dom .ASTVisitor ;
27+ import org .eclipse .jdt .core .dom .Assignment ;
2728import org .eclipse .jdt .core .dom .Block ;
2829import org .eclipse .jdt .core .dom .CastExpression ;
2930import org .eclipse .jdt .core .dom .CompilationUnit ;
31+ import org .eclipse .jdt .core .dom .Expression ;
32+ import org .eclipse .jdt .core .dom .ExpressionStatement ;
3033import org .eclipse .jdt .core .dom .IfStatement ;
3134import org .eclipse .jdt .core .dom .InfixExpression ;
3235import org .eclipse .jdt .core .dom .InfixExpression .Operator ;
@@ -142,55 +145,127 @@ public boolean visit(final InstanceofExpression visited) {
142145
143146 IfStatement ifStatement = (IfStatement ) currentNode .getParent ();
144147
148+ ResultCollector collector = new ResultCollector (visited );
145149 if (isPositiveCaseToAnalyze ) {
146- return maybeMatchPattern (visited , ifStatement .getThenStatement ());
150+ collector .collect (ifStatement .getThenStatement ());
151+ } else if (ifStatement .getElseStatement () != null ) {
152+ collector .collect (ifStatement .getElseStatement ());
153+ } else if (ASTNodes .fallsThrough (ifStatement .getThenStatement ())) {
154+ collector .collect (ASTNodes .getNextSibling (ifStatement ));
147155 }
148156
149- if (ifStatement .getElseStatement () != null ) {
150- return maybeMatchPattern (visited , ifStatement .getElseStatement ());
157+ if (collector .hasResult ()) {
158+ fResult .add (collector .build ());
159+ return false ;
151160 }
161+ return true ;
162+ }
163+
164+ static class ResultCollector {
165+ final InstanceofExpression visited ;
166+ SimpleName variableName ;
167+ final List <VariableDeclarationStatement > statementsToRemove = new ArrayList <>();
168+ final List <VariableDeclarationStatement > statementsToConvert = new ArrayList <>();
152169
153- if ( ASTNodes . fallsThrough ( ifStatement . getThenStatement ()) ) {
154- return maybeMatchPattern ( visited , ASTNodes . getNextSibling ( ifStatement )) ;
170+ ResultCollector ( InstanceofExpression visited ) {
171+ this . visited = visited ;
155172 }
156173
157- return true ;
158- }
174+ public PatternMatchingForInstanceofFixOperation build () {
175+ return new PatternMatchingForInstanceofFixOperation (visited , statementsToRemove , statementsToConvert , variableName );
176+ }
159177
160- private boolean maybeMatchPattern (final InstanceofExpression visited , final Statement conditionalStatements ) {
161- List <Statement > statements = ASTNodes .asList (conditionalStatements );
178+ private String getIdentifierName (Expression expression ) {
179+ if (expression instanceof SimpleName simpleName ) {
180+ return simpleName .getIdentifier ();
181+ }
182+ return null ;
183+ }
162184
163- if (! statements . isEmpty () ) {
164- VariableDeclarationStatement variableDeclarationExpression = ASTNodes . as ( statements . get ( 0 ), VariableDeclarationStatement . class );
165- VariableDeclarationFragment variableDeclarationFragment = ASTNodes . getUniqueFragment ( variableDeclarationExpression );
185+ boolean hasResult ( ) {
186+ return variableName != null && ! statementsToRemove . isEmpty ( );
187+ }
166188
167- if (variableDeclarationFragment != null
168- && Objects .equals (visited .getRightOperand ().resolveBinding (), variableDeclarationExpression .getType ().resolveBinding ())) {
169- CastExpression castExpression = ASTNodes .as (variableDeclarationFragment .getInitializer (), CastExpression .class );
189+ void addMatching (final VariableDeclarationStatement statement , final SimpleName name , boolean toConvert ) {
190+ if (this .variableName == null || this .variableName .getIdentifier ().equals (name .getIdentifier ())) {
191+ this .variableName = name ;
192+ if (toConvert ) {
193+ this .statementsToConvert .add (statement );
194+ } else {
195+ this .statementsToRemove .add (statement );
196+ }
197+ }
198+ }
170199
171- if (castExpression != null
172- && Objects .equals (visited .getRightOperand ().resolveBinding (), castExpression .getType ().resolveBinding ())
173- && ASTNodes .match (visited .getLeftOperand (), castExpression .getExpression ())
174- && ASTNodes .isPassive (visited .getLeftOperand ())) {
175- fResult .add (new PatternMatchingForInstanceofFixOperation (visited , variableDeclarationExpression , variableDeclarationFragment .getName ()));
176- return false ;
200+ boolean collect (final Statement conditionalStatements ) {
201+ List <Statement > statements = ASTNodes .asList (conditionalStatements );
202+ boolean convertToAssignment = false ;
203+
204+ if (!statements .isEmpty ()) {
205+ for (Statement statement : statements ) {
206+ if (statement instanceof ExpressionStatement expressionStatement ) {
207+ Assignment assignment = ASTNodes .as (expressionStatement .getExpression (), Assignment .class );
208+ if (assignment != null ) {
209+ if (Objects .equals (getIdentifierName (visited .getLeftOperand ()), getIdentifierName (assignment .getLeftHandSide ()))) {
210+ // The same variable is assigned, this can't be handled further, something like this:
211+ // if (x instanceof T) {
212+ // x = ...
213+ //
214+ return true ;
215+ }
216+ if (Objects .equals (getIdentifierName (variableName ), getIdentifierName (assignment .getLeftHandSide ()))) {
217+ // The same variable is assigned, this can't be handled further, something like this:
218+ // if (x instanceof T y) {
219+ // y = ...
220+ //
221+ return true ;
222+ }
223+ }
224+ }
225+ if (statement instanceof VariableDeclarationStatement variableDeclarationExpression ) {
226+ VariableDeclarationFragment variableDeclarationFragment = ASTNodes .getUniqueFragment (variableDeclarationExpression );
227+ if (variableDeclarationFragment != null
228+ && Objects .equals (visited .getRightOperand ().resolveBinding (), variableDeclarationExpression .getType ().resolveBinding ())) {
229+ CastExpression castExpression = ASTNodes .as (variableDeclarationFragment .getInitializer (), CastExpression .class );
230+
231+ if (castExpression != null
232+ && Objects .equals (visited .getRightOperand ().resolveBinding (), castExpression .getType ().resolveBinding ())
233+ && ASTNodes .match (visited .getLeftOperand (), castExpression .getExpression ())
234+ && ASTNodes .isPassive (visited .getLeftOperand ())) {
235+ addMatching (variableDeclarationExpression , variableDeclarationFragment .getName (), convertToAssignment );
236+ }
237+ }
238+ }
239+ if (statement instanceof IfStatement innerIf ) {
240+ if (collect (innerIf .getThenStatement ())) {
241+ convertToAssignment = true ;
242+ }
243+ if (innerIf .getElseStatement () != null ) {
244+ if (collect (innerIf .getElseStatement ())) {
245+ convertToAssignment = true ;
246+ }
247+ }
248+ }
177249 }
178250 }
251+ return false ;
179252 }
180253
181- return true ;
182254 }
255+
183256 }
184257 }
185258
186259 public static class PatternMatchingForInstanceofFixOperation extends CompilationUnitRewriteOperation {
187260 private final InstanceofExpression nodeToComplete ;
188- private final VariableDeclarationStatement statementToRemove ;
261+ private final List <VariableDeclarationStatement > statementsToRemove ;
262+ private final List <VariableDeclarationStatement > statementsToConvert ;
189263 private final SimpleName expressionToMove ;
190264
191- public PatternMatchingForInstanceofFixOperation (final InstanceofExpression nodeToComplete , final VariableDeclarationStatement statementToRemove , final SimpleName expressionToMove ) {
265+ public PatternMatchingForInstanceofFixOperation (final InstanceofExpression nodeToComplete , final List < VariableDeclarationStatement > statementsToRemove , final List < VariableDeclarationStatement > statementsToConvert , final SimpleName expressionToMove ) {
192266 this .nodeToComplete = nodeToComplete ;
193- this .statementToRemove = statementToRemove ;
267+ this .statementsToRemove = statementsToRemove ;
268+ this .statementsToConvert = statementsToConvert ;
194269 this .expressionToMove = expressionToMove ;
195270 }
196271
@@ -216,7 +291,7 @@ public SourceRange computeSourceRange(final ASTNode nodeWithComment) {
216291 SingleVariableDeclaration newSVDecl = ast .newSingleVariableDeclaration ();
217292 newSVDecl .setName (ASTNodes .createMoveTarget (rewrite , expressionToMove ));
218293 newSVDecl .setType (ASTNodes .createMoveTarget (rewrite , nodeToComplete .getRightOperand ()));
219- if (Modifier .isFinal (statementToRemove .getModifiers ())) {
294+ if (statementsToRemove . stream (). allMatch ( varDec -> Modifier .isFinal (varDec .getModifiers () ))) {
220295 newSVDecl .modifiers ().add (ast .newModifier (ModifierKeyword .fromFlagValue (Modifier .FINAL )));
221296 }
222297 if ((ast .apiLevel () == AST .JLS20 && ast .isPreviewEnabled ()) || ast .apiLevel () > AST .JLS20 ) {
@@ -229,12 +304,22 @@ public SourceRange computeSourceRange(final ASTNode nodeWithComment) {
229304
230305 ASTNodes .replaceButKeepComment (rewrite , nodeToComplete , newInstanceof , group );
231306
232- if (ASTNodes .canHaveSiblings (statementToRemove ) || statementToRemove .getLocationInParent () == IfStatement .ELSE_STATEMENT_PROPERTY ) {
233- ASTNodes .removeButKeepComment (rewrite , statementToRemove , group );
234- } else {
235- ASTNodes .replaceButKeepComment (rewrite , statementToRemove , ast .newBlock (), group );
307+ for (var statementToRemove : statementsToRemove ) {
308+ if (ASTNodes .canHaveSiblings (statementToRemove ) || statementToRemove .getLocationInParent () == IfStatement .ELSE_STATEMENT_PROPERTY ) {
309+ ASTNodes .removeButKeepComment (rewrite , statementToRemove , group );
310+ } else {
311+ ASTNodes .replaceButKeepComment (rewrite , statementToRemove , ast .newBlock (), group );
312+ }
313+ importRemover .registerRemovedNode (statementToRemove );
314+ }
315+ for (var statementToConvert : statementsToConvert ) {
316+ VariableDeclarationFragment fragment = ASTNodes .getUniqueFragment (statementToConvert );
317+ var assignment = ast .newAssignment ();
318+ assignment .setLeftHandSide ((Expression ) ASTNode .copySubtree (ast , fragment .getName ()));
319+ assignment .setRightHandSide ((Expression ) ASTNode .copySubtree (ast , fragment .getInitializer ()));
320+ var replacement = ast .newExpressionStatement (assignment );
321+ ASTNodes .replaceButKeepComment (rewrite , statementToConvert , replacement , group );
236322 }
237- importRemover .registerRemovedNode (statementToRemove );
238323 }
239324 }
240325
0 commit comments