diff --git a/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java b/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java index 8ed065d2a406..71b36e8cafe9 100644 --- a/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Predicate; import static com.siyeh.ig.migration.TryWithIdenticalCatchesInspection.collectCommentTexts; import static com.siyeh.ig.migration.TryWithIdenticalCatchesInspection.getCommentText; @@ -54,28 +55,39 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { int size = branches.size(); if (size > 1) { boolean[] isDuplicate = new boolean[size]; + + int defaultIndex = ContainerUtil.indexOf(branches, Branch::isDefault); + if (defaultIndex >= 0) { + Branch defaultBranch = branches.get(defaultIndex); + for (int index = 0; index < size; index++) { + if (index != defaultIndex) { + Branch branch = branches.get(index); + if (areDuplicates(defaultBranch, branch)) { + isDuplicate[index] = isDuplicate[defaultIndex] = true; + highlightDefaultDuplicate(branch.myStatements); + } + } + } + } + for (int index = 0; index < size - 1; index++) { if (isDuplicate[index]) continue; + Branch branch = branches.get(index); for (int otherIndex = index + 1; otherIndex < size; otherIndex++) { - Branch branch = branches.get(index); + if (isDuplicate[otherIndex]) continue; Branch otherBranch = branches.get(otherIndex); if (areDuplicates(branch, otherBranch)) { isDuplicate[otherIndex] = true; - registerProblem(otherBranch.myStatements, branch.getSwitchLabelText()); - - if (!isDuplicate[index]) { - isDuplicate[index] = true; - registerProblem(branch.myStatements, null); - } + highlightDuplicate(otherBranch.myStatements, branch.getSwitchLabelText()); } } } } } - private void registerProblem(@NotNull PsiStatement[] statements, String switchLabelText) { + private void highlightDuplicate(@NotNull PsiStatement[] statements, String switchLabelText) { ProblemDescriptor descriptor = InspectionManager.getInstance(myHolder.getProject()) .createProblemDescriptor(statements[0], statements[statements.length - 1], InspectionsBundle.message("inspection.duplicate.branches.in.switch.message"), @@ -83,6 +95,15 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { switchLabelText != null ? new MergeBranchesFix(switchLabelText) : null); myHolder.registerProblem(descriptor); } + + private void highlightDefaultDuplicate(PsiStatement[] statements) { + ProblemDescriptor descriptor = InspectionManager.getInstance(myHolder.getProject()) + .createProblemDescriptor(statements[0], statements[statements.length - 1], + InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.message"), + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, myHolder.isOnTheFly(), + new DeleteRedundantBranchFix(), new MergeWithDefaultBranchFix()); + myHolder.registerProblem(descriptor); + } } @NotNull @@ -171,7 +192,7 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { @Contract("null -> false") private static boolean isBreakWithoutLabel(@Nullable PsiStatement statement) { - return statement instanceof PsiBreakStatement && ((PsiBreakStatement)statement).getLabelIdentifier() == null; + return statement instanceof PsiBreakStatement && ((PsiBreakStatement)statement).getLabelExpression() == null; } private static class MergeBranchesFix implements LocalQuickFix { @@ -197,53 +218,120 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - PsiElement startElement = descriptor.getStartElement(); + FixContext context = new FixContext(); + if (context.prepare(descriptor.getStartElement(), branch -> mySwitchLabelText.equals(branch.getSwitchLabelText()))) { + context.moveBranchLabel(); + context.deleteRedundantComments(); + context.deleteStatements(); + } + } + } + + private static class MergeWithDefaultBranchFix implements LocalQuickFix { + @Nls(capitalization = Nls.Capitalization.Sentence) + @NotNull + @Override + public String getFamilyName() { + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.merge.with.default.fix.name"); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + FixContext context = new FixContext(); + if (context.prepare(descriptor.getStartElement(), Branch::isDefault)) { + context.moveBranchLabel(); + context.deleteRedundantComments(); + context.deleteStatements(); + } + } + } + + private static class DeleteRedundantBranchFix implements LocalQuickFix { + @Nls(capitalization = Nls.Capitalization.Sentence) + @NotNull + @Override + public String getName() { + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.fix.name"); + } + + @Nls(capitalization = Nls.Capitalization.Sentence) + @NotNull + @Override + public String getFamilyName() { + return InspectionsBundle.message("inspection.duplicate.branches.in.switch.redundant.fix.family.name"); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + FixContext context = new FixContext(); + if (context.prepare(descriptor.getStartElement(), Branch::isDefault)) { + context.deleteBranchLabel(); + context.deleteStatements(); + } + } + } + + static class FixContext { + private Branch myBranchToDelete; + private Branch myBranchToMergeWith; + private List myBranchPrefixToMove; + private PsiSwitchLabelStatement myLabelToMergeWith; + private Set myCommentsToMergeWith; + private PsiElement myNextFromLabelToMergeWith; + + private boolean prepare(PsiElement startElement, Predicate shouldMergeWith) { PsiSwitchStatement switchStatement = PsiTreeUtil.getParentOfType(startElement, PsiSwitchStatement.class); - if (switchStatement == null) return; + if (switchStatement == null) return false; - Branch branchToDelete = null; List candidateBranches = null; for (List branches : collectSameLengthBranches(switchStatement)) { - branchToDelete = ContainerUtil.find(branches, branch -> branch.myStatements[0] == startElement); - if (branchToDelete != null) { + myBranchToDelete = ContainerUtil.find(branches, branch -> branch.myStatements[0] == startElement); + if (myBranchToDelete != null) { candidateBranches = branches; break; } } + if (myBranchToDelete == null || candidateBranches == null) return false; - if (branchToDelete == null) return; - - Branch branchToMergeWith = null; for (Branch branch : candidateBranches) { - if (mySwitchLabelText.equals(branch.getSwitchLabelText()) && areDuplicates(branchToDelete, branch)) { - branchToMergeWith = branch; + if (shouldMergeWith.test(branch) && areDuplicates(myBranchToDelete, branch)) { + myBranchToMergeWith = branch; break; } } - if (branchToMergeWith == null) return; + if (myBranchToMergeWith == null) return false; - List branchPrefixToMove = branchToDelete.getBranchPrefix(); - if (branchPrefixToMove.isEmpty()) return; + myBranchPrefixToMove = myBranchToDelete.getBranchPrefix(); + if (myBranchPrefixToMove.isEmpty()) return false; - PsiSwitchLabelStatement labelToMergeWith = - PsiTreeUtil.getPrevSiblingOfType(branchToMergeWith.myStatements[0], PsiSwitchLabelStatement.class); - if (labelToMergeWith == null) return; + myLabelToMergeWith = PsiTreeUtil.getPrevSiblingOfType(myBranchToMergeWith.myStatements[0], PsiSwitchLabelStatement.class); + if (myLabelToMergeWith == null) return false; - PsiElement oldNextElement = PsiTreeUtil.skipWhitespacesForward(labelToMergeWith); + myNextFromLabelToMergeWith = PsiTreeUtil.skipWhitespacesForward(myLabelToMergeWith); - PsiElement firstElementToMove = branchPrefixToMove.get(0); - PsiElement lastElementToMove = branchPrefixToMove.get(branchPrefixToMove.size() - 1); - labelToMergeWith.getParent().addRangeAfter(firstElementToMove, lastElementToMove, labelToMergeWith); + myCommentsToMergeWith = ContainerUtil.set(myBranchToMergeWith.myCommentTexts); + return true; + } + + void moveBranchLabel() { + PsiElement firstElementToMove = myBranchPrefixToMove.get(0); + PsiElement lastElementToMove = myBranchPrefixToMove.get(myBranchPrefixToMove.size() - 1); + + PsiElement moveTarget = myLabelToMergeWith; + if (myLabelToMergeWith.isDefaultCase()) { + PsiElement prevElement = PsiTreeUtil.skipWhitespacesAndCommentsBackward(myLabelToMergeWith); + if (prevElement != null) moveTarget = prevElement; + } + moveTarget.getParent().addRangeAfter(firstElementToMove, lastElementToMove, moveTarget); firstElementToMove.getParent().deleteChildRange(firstElementToMove, lastElementToMove); + } - Set commentsToMergeWith = ContainerUtil.set(branchToMergeWith.myCommentTexts); - deleteRedundantComments(labelToMergeWith.getNextSibling(), oldNextElement, commentsToMergeWith); - + void deleteStatements() { CommentTracker tracker = new CommentTracker(); - PsiStatement[] statementsToDelete = branchToDelete.getStatementsToDelete(); + PsiStatement[] statementsToDelete = myBranchToDelete.getStatementsToDelete(); for (PsiStatement statement : statementsToDelete) { PsiTreeUtil.processElements(statement, child -> { - if (isRedundantComment(commentsToMergeWith, child)) { + if (isRedundantComment(myCommentsToMergeWith, child)) { tracker.markUnchanged(child); } return true; @@ -255,13 +343,13 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { tracker.deleteAndRestoreComments(statementsToDelete[statementsToDelete.length - 1]); } - private static void deleteRedundantComments(@Nullable PsiElement startElement, - @Nullable PsiElement stopElement, - @NotNull Set existingComments) { + void deleteRedundantComments() { List redundantComments = new ArrayList<>(); - for (PsiElement element = startElement; element != null && element != stopElement; element = element.getNextSibling()) { + for (PsiElement element = myLabelToMergeWith.getNextSibling(); + element != null && element != myNextFromLabelToMergeWith; + element = element.getNextSibling()) { PsiTreeUtil.processElements(element, child -> { - if (isRedundantComment(existingComments, child)) { + if (isRedundantComment(myCommentsToMergeWith, child)) { redundantComments.add(child); } return true; @@ -278,11 +366,37 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } return false; } + + void deleteBranchLabel() { + List toDelete = new ArrayList<>(); + CommentTracker tracker = new CommentTracker(); + + for (PsiElement element : myBranchPrefixToMove) { + if (element instanceof PsiWhiteSpace) { + continue; + } + toDelete.add(element); + PsiTreeUtil.processElements(element, child -> { + if (isRedundantComment(myCommentsToMergeWith, child)) { + tracker.markUnchanged(child); + } + return true; + }); + } + int size = toDelete.size(); + if (size != 0) { + for (int i = 0; i < size - 1; i++) { + tracker.delete(toDelete.get(i)); + } + tracker.deleteAndRestoreComments(toDelete.get(size - 1)); + } + } } private static class Branch { private final PsiStatement[] myStatements; private final String[] myCommentTexts; + private final boolean myIsDefault; private final boolean myIsSimpleExit; private final boolean myCanFallThrough; @@ -298,6 +412,7 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } myStatements = statementList.toArray(PsiStatement.EMPTY_ARRAY); myCommentTexts = commentTexts; + myIsDefault = calculateIsDefault(statementList.get(0)); } @Nullable @@ -317,6 +432,10 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { return myStatements.length; } + boolean isDefault() { + return myIsDefault; + } + @Nullable String getSwitchLabelText() { PsiSwitchLabelStatement switchLabel = null; @@ -330,10 +449,12 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { if (switchLabel.isDefaultCase()) { return PsiKeyword.DEFAULT; } - //todo support multi-value label - PsiExpression value = switchLabel.getCaseValue(); - if (value != null) { - return PsiKeyword.CASE + ' ' + value.getText(); + PsiExpressionList caseValues = switchLabel.getCaseValues(); + if (caseValues != null) { + PsiExpression[] expressions = caseValues.getExpressions(); + if (expressions.length != 0) { + return PsiKeyword.CASE + ' ' + expressions[0].getText(); + } } } return null; @@ -346,7 +467,7 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { List getBranchPrefix() { List result = new ArrayList<>(); for (PsiElement element = myStatements[0].getPrevSibling(); - element != null && (element instanceof PsiSwitchLabelStatement || !(element instanceof PsiStatement)); + element != null && !isLeftBrace(element) && (element instanceof PsiSwitchLabelStatement || !(element instanceof PsiStatement)); element = element.getPrevSibling()) { result.add(element); } @@ -354,6 +475,10 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { return result; } + private static boolean isLeftBrace(PsiElement element) { + return element instanceof PsiJavaToken && JavaTokenType.LBRACE.equals(((PsiJavaToken)element).getTokenType()); + } + PsiStatement[] getStatementsToDelete() { PsiStatement nextStatement = PsiTreeUtil.getNextSiblingOfType(myStatements[myStatements.length - 1], PsiStatement.class); if (isBreakWithoutLabel(nextStatement)) { @@ -405,6 +530,17 @@ public class DuplicateBranchesInSwitchInspection extends LocalInspectionTool { } return false; } + + private static boolean calculateIsDefault(PsiStatement statement) { + for (PsiElement element = PsiTreeUtil.getPrevSiblingOfType(statement, PsiStatement.class); + element instanceof PsiSwitchLabelStatement; + element = PsiTreeUtil.getPrevSiblingOfType(element, PsiStatement.class)) { + if (((PsiSwitchLabelStatement)element).isDefaultCase()) { + return true; + } + } + return false; + } } private static class Comments { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java index cfe476ca502a..ab22f4bbd344 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/BreakAndReturnUnderIf.java @@ -2,11 +2,11 @@ class C { int foo(int n, boolean b) { switch (n) { case 1: - if(b) { + if(b) { return bar("A"); } else { break; - } + } case 2: if(b) { return bar("B"); diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java index 747300476ff8..1c33db404c4b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ComplexBranches.java @@ -2,12 +2,12 @@ class C { void foo(int n, boolean b) { switch (n) { case 1: - if(b) { + if(b) { bar("A"); } else { bar("z"); } - bar("o"); + bar("o"); break; case 2: if(b) { diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java index 535202a893aa..8b5f677511c1 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Continue.java @@ -4,8 +4,8 @@ class C { for (int i = 0; i < n; i++) { switch (i % 4) { case 1: - s += i; - continue; + s += i; + continue; case 2: continue; case 3: diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java new file mode 100644 index 000000000000..2e11cf08416c --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/DuplicateAfterDefault.java @@ -0,0 +1,16 @@ +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + default: + bar("A"); + break; + case 1: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java index 383d6d2bc5f1..c4fcf393799b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/FallThroughToBreak.java @@ -2,7 +2,7 @@ class C { void foo(int n) { switch (n) { case 1: - bar("A"); + bar("A"); case 2: break; case 3: diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java index 750a0039a93b..9b59d388f217 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/MethodCallInReturn.java @@ -4,7 +4,7 @@ enum T { int foo(T t) { switch (t) { case A: - return t.ordinal(); // comment 1 + return t.ordinal(); // comment 1 case B: return t.ordinal(); diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java index 7ddbeae2f69e..ba5a9b985323 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NoLastBreak.java @@ -2,7 +2,7 @@ class C { void foo(int n) { switch (n) { case 1: - bar("A"); + bar("A"); break; case 2: bar("B"); diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java index 6bbf73fb68d1..279d6f216b5c 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Return.java @@ -2,7 +2,7 @@ class C { String foo(int n) { switch (n) { case 1: - return "A"; + return "A"; case 2: return "B"; case 3: diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java index 3a3c7b7a4b31..c0cea839f630 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ReturnWithComments.java @@ -7,7 +7,7 @@ enum C { switch (c) { case ORIGINAL_CODE_WITH_COMMENT: /* comment 1 */ - return "A"; + return "A"; case THE_SAME_CODE_WITH_DIFFERENT_COMMENT: /* comment 2 */ return "A"; diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java index 862d7397ce08..9ea8da8ad9c3 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Simple.java @@ -2,7 +2,7 @@ class C { void foo(int n) { switch (n) { case 1: - bar("A"); + bar("A"); break; case 2: bar("B"); diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java index a1234a017856..a0f999f4ed9b 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicates.java @@ -2,7 +2,7 @@ class C { void foo(int n) { switch (n) { case 1: - bar("A"); + bar("A"); break; case 2: bar("B"); @@ -10,7 +10,7 @@ class C { case 3: bar("A"); break; - default: + case 4: bar("A"); break; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java new file mode 100644 index 000000000000..d5497c91382f --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/ThreeDuplicatesDefault.java @@ -0,0 +1,19 @@ +class C { + void foo(int n) { + switch (n) { + case 1: + bar("A"); + break; + case 2: + bar("B"); + break; + case 3: + bar("A"); + break; + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java index 96ac2f59385b..7021fa2adfd6 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/Throw.java @@ -2,7 +2,7 @@ class C { String foo(int n) { switch (n) { case 1: - throw new IllegalArgumentException("A"); + throw new IllegalArgumentException("A"); case 2: throw new IllegalStateException("A"); case 3: diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java index 0593989140fc..3396a9fb2a53 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/TwoCaseLabels.java @@ -3,7 +3,7 @@ class C { switch (n) { case 1: case 2: - bar("A"); + bar("A"); break; case 3: bar("A"); diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateAfterDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateAfterDefaultDelete.java new file mode 100644 index 000000000000..b7ef2ca09948 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateAfterDefaultDelete.java @@ -0,0 +1,16 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + default: + /*comment 2*/ + bar("A"); + break;/*comment 1*/ + /*comment 3*/ + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateAfterDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateAfterDefaultMerge.java new file mode 100644 index 000000000000..5cc6e1221fc2 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateAfterDefaultMerge.java @@ -0,0 +1,15 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + case 1: + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultDelete.java new file mode 100644 index 000000000000..8f98696713c2 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultDelete.java @@ -0,0 +1,14 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultDeleteAdjacent.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultDeleteAdjacent.java new file mode 100644 index 000000000000..8f98696713c2 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultDeleteAdjacent.java @@ -0,0 +1,14 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultMerge.java new file mode 100644 index 000000000000..5cc6e1221fc2 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultMerge.java @@ -0,0 +1,15 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + case 1: + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultMergeAdjacent.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultMergeAdjacent.java new file mode 100644 index 000000000000..5cc6e1221fc2 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDuplicateBeforeDefaultMergeAdjacent.java @@ -0,0 +1,15 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + case 1: + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterThreeDuplicates.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterThreeDuplicates.java index 7782028c39db..56846e0d59f1 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterThreeDuplicates.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterThreeDuplicates.java @@ -3,7 +3,7 @@ class C { void foo(int n) { switch (n) { case 1: - default: + case 4: bar("A"); break; case 2: diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterThreeDuplicatesDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterThreeDuplicatesDefaultMerge.java new file mode 100644 index 000000000000..ac9119227be0 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterThreeDuplicatesDefaultMerge.java @@ -0,0 +1,18 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + case 3: + bar("A"); + break; + case 1: + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateAfterDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateAfterDefaultDelete.java new file mode 100644 index 000000000000..5b873ab2b323 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateAfterDefaultDelete.java @@ -0,0 +1,21 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + default: + /*comment 2*/ + bar("A"); + break; + /*comment 1*/ + case 1: + /*comment 2*/ + bar("A"); + /*comment 3*/ + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateAfterDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateAfterDefaultMerge.java new file mode 100644 index 000000000000..5ffe82f39d79 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateAfterDefaultMerge.java @@ -0,0 +1,17 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + default: + bar("A"); + break; + case 1: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultDelete.java new file mode 100644 index 000000000000..d339e5ad3c97 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultDelete.java @@ -0,0 +1,17 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 1: + bar("A"); + break; + case 2: + bar("B"); + break; + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultDeleteAdjacent.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultDeleteAdjacent.java new file mode 100644 index 000000000000..d9605e9f8bf0 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultDeleteAdjacent.java @@ -0,0 +1,17 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + case 1: + bar("A"); + break; + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultMerge.java new file mode 100644 index 000000000000..de0abc85fc0b --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultMerge.java @@ -0,0 +1,17 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 1: + bar("A"); + break; + case 2: + bar("B"); + break; + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultMergeAdjacent.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultMergeAdjacent.java new file mode 100644 index 000000000000..831f208c6b92 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDuplicateBeforeDefaultMergeAdjacent.java @@ -0,0 +1,17 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 2: + bar("B"); + break; + case 1: + bar("A"); + break; + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeThreeDuplicates.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeThreeDuplicates.java index a00ed706276b..e834493c60cb 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeThreeDuplicates.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeThreeDuplicates.java @@ -11,7 +11,7 @@ class C { case 3: bar("A"); break; - default: + case 4: bar("A"); break; } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeThreeDuplicatesDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeThreeDuplicatesDefaultMerge.java new file mode 100644 index 000000000000..b4e19707a828 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeThreeDuplicatesDefaultMerge.java @@ -0,0 +1,20 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class C { + void foo(int n) { + switch (n) { + case 1: + bar("A"); + break; + case 2: + bar("B"); + break; + case 3: + bar("A"); + break; + default: + bar("A"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchTest.kt index 047f00213bbe..968a5a9358fe 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchTest.kt @@ -28,6 +28,8 @@ class DuplicateBranchesInSwitchTest : LightCodeInsightFixtureTestCase() { fun testNoLastBreak() = doTest() fun testFallThroughToBreak() = doTest() fun testThreeDuplicates() = doTest() + fun testThreeDuplicatesDefault() = doTest() + fun testDuplicateAfterDefault() = doTest() fun testTwoCaseLabels() = doTest() fun testComplexBranches() = doTest() fun testBreakWithLabel() = doTest() diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 2f9b576acf44..6757c8177cfe 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -1043,6 +1043,10 @@ inspection.duplicate.branches.in.switch.display.name=Duplicate branches in 'swit inspection.duplicate.branches.in.switch.message=Duplicate branch in 'switch' statement inspection.duplicate.branches.in.switch.fix.family.name=Merge duplicate branches of 'switch' statement inspection.duplicate.branches.in.switch.fix.name=Merge with ''{0}:'' +inspection.duplicate.branches.in.switch.redundant.message=Branch in 'switch' statement is a duplicate of the default branch +inspection.duplicate.branches.in.switch.redundant.fix.family.name=Delete redundant branches of 'switch' statement +inspection.duplicate.branches.in.switch.redundant.fix.name=Delete redundant 'switch' branch +inspection.duplicate.branches.in.switch.merge.with.default.fix.name=Merge with the default 'switch' branch inspection.switch.labeled.rule.can.be.code.block.display.name=Labeled switch rule can have code block inspection.switch.labeled.rule.can.be.code.block.expression.message=Labeled rule's result expression can be wrapped with code block