1717import java .lang .reflect .Modifier ;
1818import java .util .ArrayList ;
1919import java .util .Collections ;
20+ import java .util .HashSet ;
2021import java .util .Iterator ;
2122import java .util .List ;
23+ import java .util .Set ;
2224
2325import org .eclipse .core .runtime .CoreException ;
2426
4446import org .eclipse .jdt .core .dom .ITypeBinding ;
4547import org .eclipse .jdt .core .dom .IVariableBinding ;
4648import org .eclipse .jdt .core .dom .IfStatement ;
49+ import org .eclipse .jdt .core .dom .InfixExpression ;
50+ import org .eclipse .jdt .core .dom .InfixExpression .Operator ;
4751import org .eclipse .jdt .core .dom .Modifier .ModifierKeyword ;
4852import org .eclipse .jdt .core .dom .Name ;
53+ import org .eclipse .jdt .core .dom .NullLiteral ;
4954import org .eclipse .jdt .core .dom .PatternInstanceofExpression ;
5055import org .eclipse .jdt .core .dom .ReturnStatement ;
5156import org .eclipse .jdt .core .dom .SimpleName ;
@@ -113,6 +118,7 @@ public void setPatternNameUsed(boolean value) {
113118 }
114119
115120 private List <CompilationUnitRewriteOperation > fResult ;
121+ private Set <IfStatement > ifsProcessed = new HashSet <>();
116122
117123 public SwitchStatementsFinder (List <CompilationUnitRewriteOperation > ops ) {
118124 fResult = ops ;
@@ -129,6 +135,9 @@ final class SeveralIfVisitor extends ASTVisitor {
129135
130136 @ Override
131137 public boolean visit (final IfStatement visited ) {
138+ if (ifsProcessed .contains (visited )) {
139+ return false ;
140+ }
132141 TypeVariable variable = extractVariableAndValues (visited );
133142
134143 if (variable == null ) {
@@ -147,8 +156,13 @@ public boolean visit(final IfStatement visited) {
147156 IfStatement currentNode = ifStatement ;
148157
149158 while (ASTNodes .isSameVariable (switchExpression , variable .name )) {
150- cases .add (new SwitchCaseSection (variable .getTypePattern (), variable .isPatternNameUsed (),
151- ASTNodes .asList (currentNode .getThenStatement ())));
159+ if (variable .getTypePattern () == null ) {
160+ cases .add (new NullSwitchCaseSection (variable .getTypePattern (), variable .isPatternNameUsed (),
161+ ASTNodes .asList (currentNode .getThenStatement ())));
162+ } else {
163+ cases .add (new SwitchCaseSection (variable .getTypePattern (), variable .isPatternNameUsed (),
164+ ASTNodes .asList (currentNode .getThenStatement ())));
165+ }
152166
153167 if (!ASTNodes .fallsThrough (currentNode .getThenStatement ())) {
154168 isFallingThrough = false ;
@@ -184,6 +198,7 @@ public boolean visit(final IfStatement visited) {
184198 private boolean maybeReplaceWithSwitchStatement (final List <IfStatement > ifStatements , final Expression switchExpression ,
185199 final List <SwitchCaseSection > cases , final Statement remainingStatement ) {
186200 if (switchExpression != null && cases .size () > 2 ) {
201+ ifsProcessed .addAll (ifStatements );
187202 PatternToSwitchExpressionOperation op = getOperation (ifStatements , switchExpression , cases , remainingStatement );
188203 if (op != null ) {
189204 fResult .add (op );
@@ -339,15 +354,17 @@ private TypeVariable extractVariableAndValues(final Statement statement) {
339354 CompilationUnit cu = (CompilationUnit ) ifStmt .getRoot ();
340355 if (JavaModelUtil .is22OrHigher (cu .getJavaElement ().getJavaProject ())) {
341356 TypePattern pattern = result .getTypePattern ();
342- VariableDeclaration vd = pattern .getPatternVariable2 ();
343- SimpleName name = vd .getName ();
344- IBinding binding = name .resolveBinding ();
345- NameUsedVisitor visitor = new NameUsedVisitor (binding );
346- try {
347- ifStmt .getThenStatement ().accept (visitor );
348- result .setPatternNameUsed (false );
349- } catch (AbortSearchException e ) {
350- result .setPatternNameUsed (true );
357+ if (pattern != null ) {
358+ VariableDeclaration vd = pattern .getPatternVariable2 ();
359+ SimpleName name = vd .getName ();
360+ IBinding binding = name .resolveBinding ();
361+ NameUsedVisitor visitor = new NameUsedVisitor (binding );
362+ try {
363+ ifStmt .getThenStatement ().accept (visitor );
364+ result .setPatternNameUsed (false );
365+ } catch (AbortSearchException e ) {
366+ result .setPatternNameUsed (true );
367+ }
351368 }
352369 }
353370 return result ;
@@ -363,6 +380,9 @@ private TypeVariable extractVariableAndValues(final Expression expression) {
363380 return extractVariableAndValuesFromPatternExpression (pattern );
364381 }
365382
383+ if (expression instanceof InfixExpression infix && infix .getOperator () == Operator .EQUALS ) {
384+ return extractVariableAndValuesFromInfixExpression (infix );
385+ }
366386 return null ;
367387 }
368388
@@ -374,6 +394,14 @@ private TypeVariable extractVariableAndValuesFromPatternExpression(final Pattern
374394 return null ;
375395 }
376396
397+ private TypeVariable extractVariableAndValuesFromInfixExpression (InfixExpression infix ) {
398+ if (infix .getLeftOperand () instanceof NullLiteral ) {
399+ return new TypeVariable (infix .getRightOperand (), null );
400+ } else if (infix .getRightOperand () instanceof NullLiteral ) {
401+ return new TypeVariable (infix .getLeftOperand (), null );
402+ }
403+ return null ;
404+ }
377405 }
378406 }
379407
@@ -413,15 +441,21 @@ public SourceRange computeSourceRange(final ASTNode nodeWithComment) {
413441
414442 switchStatement .setExpression ((Expression ) rewrite .createCopyTarget (switchExpression ));
415443
444+ boolean haveNullCase = false ;
416445 for (SwitchCaseSection aCase : cases ) {
417- addCaseWithStatements (rewrite , importRewrite , ast , switchStatement , aCase .typePattern , aCase .isNameUsed , aCase .statements );
446+ if (aCase instanceof NullSwitchCaseSection ) {
447+ addCaseWithStatements (rewrite , importRewrite , ast , switchStatement , aCase .typePattern , true , false , aCase .isNameUsed , aCase .statements );
448+ haveNullCase = true ;
449+ } else {
450+ addCaseWithStatements (rewrite , importRewrite , ast , switchStatement , aCase .typePattern , false , haveNullCase , aCase .isNameUsed , aCase .statements );
451+ }
418452 }
419453
420454 if (remainingStatement != null ) {
421455 remainingStatement .setProperty (UNTOUCH_COMMENT_PROPERTY , Boolean .TRUE );
422- addCaseWithStatements (rewrite , importRewrite , ast , switchStatement , null , false , ASTNodes .asList (remainingStatement ));
456+ addCaseWithStatements (rewrite , importRewrite , ast , switchStatement , null , false , haveNullCase , false , ASTNodes .asList (remainingStatement ));
423457 } else {
424- addCaseWithStatements (rewrite , importRewrite , ast , switchStatement , null , false , Collections .emptyList ());
458+ addCaseWithStatements (rewrite , importRewrite , ast , switchStatement , null , false , haveNullCase , false , Collections .emptyList ());
425459 }
426460
427461 for (int i = 0 ; i < ifStatements .size () - 1 ; i ++) {
@@ -434,6 +468,8 @@ public SourceRange computeSourceRange(final ASTNode nodeWithComment) {
434468 private void addCaseWithStatements (final ASTRewrite rewrite , final ImportRewrite importRewrite ,
435469 final AST ast , final SwitchStatement switchStatement ,
436470 final TypePattern caseValueOrNullForDefault ,
471+ final boolean isNullCase ,
472+ final boolean haveNullCase ,
437473 final boolean isNameUsed ,
438474 final List <Statement > innerStatements ) {
439475 List <Statement > switchStatements = switchStatement .statements ();
@@ -467,8 +503,12 @@ private void addCaseWithStatements(final ASTRewrite rewrite, final ImportRewrite
467503 } else {
468504 SwitchCase newSwitchCase = ast .newSwitchCase ();
469505 newSwitchCase .setSwitchLabeledRule (true );
470- newSwitchCase .expressions ().add (ast .newNullLiteral ());
471- newSwitchCase .expressions ().add (ast .newCaseDefaultExpression ());
506+ if (!haveNullCase ) {
507+ newSwitchCase .expressions ().add (ast .newNullLiteral ());
508+ }
509+ if (!isNullCase && !haveNullCase ) {
510+ newSwitchCase .expressions ().add (ast .newCaseDefaultExpression ());
511+ }
472512 switchStatements .add (newSwitchCase );
473513 }
474514
@@ -541,6 +581,7 @@ public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore
541581 newSwitchExpression .setExpression (newSwitchExpressionExpression );
542582
543583 // build switch expression
584+ boolean haveNullCase = false ;
544585 for (SwitchCaseSection switchCaseSection : cases ) {
545586 List <Statement > oldStatements = switchCaseSection .statements ;
546587 SwitchCase switchCase = null ;
@@ -549,11 +590,15 @@ public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore
549590 newSwitchCase .setSwitchLabeledRule (true );
550591 switchCase = newSwitchCase ;
551592 if (switchCaseSection .typePattern == null ) {
552- // for the empty pattern, create a null/default case
553- Expression nullExpression = ast .newNullLiteral ();
554- Expression defaultExpression = ast .newCaseDefaultExpression ();
555- switchCase .expressions ().add (nullExpression );
556- switchCase .expressions ().add (defaultExpression );
593+ if (!haveNullCase ) {
594+ Expression nullExpression = ast .newNullLiteral ();
595+ switchCase .expressions ().add (nullExpression );
596+ }
597+ if (!(switchCaseSection instanceof NullSwitchCaseSection ) && !haveNullCase ) {
598+ Expression defaultExpression = ast .newCaseDefaultExpression ();
599+ switchCase .expressions ().add (defaultExpression );
600+ }
601+ haveNullCase = true ;
557602 } else {
558603 Expression oldExpression = switchCaseSection .typePattern ;
559604 Expression newExpression = (Expression )rewrite .createCopyTarget (oldExpression );
@@ -683,7 +728,9 @@ public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore
683728 rewrite .replace (ifStatements .get (0 ), newExpressionStatement , group );
684729 }
685730 for (int i = 1 ; i < ifStatements .size (); ++i ) {
686- rewrite .remove (ifStatements .get (i ), group );
731+ if (ifStatements .get (i ).getLocationInParent () != IfStatement .ELSE_STATEMENT_PROPERTY ) {
732+ rewrite .remove (ifStatements .get (i ), group );
733+ }
687734 }
688735 }
689736
@@ -733,14 +780,25 @@ protected PatternInstanceofToSwitchFixCore(final String name, final CompilationU
733780 super (name , compilationUnit , fixRewriteOperations );
734781 }
735782
783+ /**
784+ * Represents a null switch case section
785+ */
786+ private static class NullSwitchCaseSection extends SwitchCaseSection {
787+ private NullSwitchCaseSection (final TypePattern typePattern ,
788+ final boolean isNameUsed ,
789+ final List <Statement > statements ) {
790+ super (typePattern , isNameUsed , statements );
791+ }
792+ }
793+
736794 /**
737795 * Represents a switch case section (cases + statements).
738796 * <p>
739797 * It can represent a switch case to build (when converting if else if
740798 * statements), or existing switch cases when representing the structure of a
741799 * whole switch.
742800 */
743- private static final class SwitchCaseSection {
801+ private static class SwitchCaseSection {
744802 /**
745803 * Must resolve to constant values. Used when representing switch cases to
746804 * build.
@@ -758,6 +816,7 @@ private static final class SwitchCaseSection {
758816 * Used for if statements, only constant expressions are used.
759817 *
760818 * @param typePattern The type pattern
819+ * @param isNameUsed Whether or not the instanceof variable name is used in statements
761820 * @param statements The statements
762821 */
763822 private SwitchCaseSection (final TypePattern typePattern ,
0 commit comments