diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/SwitchBlockHighlightingModel.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/SwitchBlockHighlightingModel.java index 44b9569f2137..67fbd87e0116 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/SwitchBlockHighlightingModel.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/SwitchBlockHighlightingModel.java @@ -837,7 +837,7 @@ public class SwitchBlockHighlightingModel { addIllegalFallThroughError(currentElement, "invalid.case.label.combination", holder, alreadyFallThroughElements); break; } - if (containsPatternVariable(currentElement)) { + if (JavaPsiPatternUtil.containsPatternVariable(currentElement)) { if (existPattern || PsiTreeUtil.skipWhitespacesAndCommentsForward(switchLabelElement) instanceof PsiSwitchLabelStatement) { addIllegalFallThroughError(currentElement, "switch.illegal.fall.through.from", holder, alreadyFallThroughElements); break; @@ -884,7 +884,7 @@ public class SwitchBlockHighlightingModel { PsiCaseLabelElementList labelElementList = switchLabel.getCaseLabelElementList(); if (labelElementList == null) continue; List patternElements = ContainerUtil.filter(labelElementList.getElements(), - labelElement -> containsPatternVariable(labelElement)); + labelElement -> JavaPsiPatternUtil.containsPatternVariable(labelElement)); if (patternElements.isEmpty()) continue; PsiStatement prevStatement = PsiTreeUtil.getPrevSiblingOfType(firstSwitchLabelInGroup, PsiStatement.class); if (prevStatement == null) continue; @@ -896,28 +896,6 @@ public class SwitchBlockHighlightingModel { } } - private static boolean containsPatternVariable(@NotNull PsiCaseLabelElement element) { - if (element instanceof PsiPatternGuard patternGuard) { - return containsPatternVariable(patternGuard.getPattern()); - } - else if (element instanceof PsiGuardedPattern guardedPattern) { - return containsPatternVariable(guardedPattern.getPrimaryPattern()); - } - else if (element instanceof PsiTypeTestPattern typeTestPattern) { - return typeTestPattern.getPatternVariable() != null; - } - else if (element instanceof PsiParenthesizedPattern parenthesizedPattern) { - PsiPattern pattern = parenthesizedPattern.getPattern(); - return pattern != null && containsPatternVariable(pattern); - } - else if (element instanceof PsiDeconstructionPattern deconstructionPattern) { - return deconstructionPattern.getPatternVariable() != null || - ContainerUtil.exists(deconstructionPattern.getDeconstructionList().getDeconstructionComponents(), - pattern -> containsPatternVariable(pattern)); - } - return false; - } - /** * 14.11.1 Switch Blocks * To ensure the absence of unreachable statements, domination rules provide a possible order diff --git a/java/java-impl-inspections/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java b/java/java-impl-inspections/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java index bfca01e3d025..0a7df8c71ad4 100644 --- a/java/java-impl-inspections/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java +++ b/java/java-impl-inspections/src/com/intellij/codeInspection/DuplicateBranchesInSwitchInspection.java @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInspection; import com.intellij.codeInspection.util.InspectionMessage; @@ -6,10 +6,12 @@ import com.intellij.java.JavaBundle; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.JavaPsiPatternUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; @@ -95,7 +97,7 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo for (int index = 0; index < size; index++) { if (index != defaultIndex) { BranchBase branch = branches.get(index); - if (areDuplicates(defaultBranch, branch) && branch.myBranchType != BranchType.HAS_NULL) { + if (areDuplicates(defaultBranch, branch)) { isDuplicate[index] = isDuplicate[defaultIndex] = true; highlightDefaultDuplicate(branch); } @@ -115,8 +117,9 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo if (areDuplicates(branch, otherBranch)) { isDuplicate[otherIndex] = true; - if (canMerge(otherBranch, branch)) { - registerProblem(otherBranch, otherBranch.getCaseBranchMessage(), branch.newMergeCasesFix()); + LocalQuickFix fix = branch.newMergeCasesFix(otherBranch); + if (fix != null) { + registerProblem(otherBranch, otherBranch.getCaseBranchMessage(), fix); } } } @@ -124,21 +127,16 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo } } - private static boolean canMerge(@NotNull BranchBase duplicate, @NotNull BranchBase original) { - if (duplicate.myBranchType == BranchType.UNMERGEABLE || original.myBranchType == BranchType.UNMERGEABLE) { - return false; - } - if (duplicate.myBranchType == BranchType.TYPE_TEST_PATTERN ^ original.myBranchType == BranchType.TYPE_TEST_PATTERN) { - return true; - } - return duplicate.myBranchType != BranchType.TYPE_TEST_PATTERN; + private void highlightDefaultDuplicate(@NotNull BranchBase branch) { + LocalQuickFix deleteCaseFix = branch.newDeleteCaseFix(); + LocalQuickFix mergeWithDefaultFix = branch.newMergeWithDefaultFix(); + if (deleteCaseFix == null && mergeWithDefaultFix == null) return; + registerProblem(branch, branch.getDefaultBranchMessage(), deleteCaseFix, mergeWithDefaultFix); } - private void highlightDefaultDuplicate(@NotNull BranchBase branch) { - registerProblem(branch, branch.getDefaultBranchMessage(), branch.newDeleteCaseFix(), branch.newMergeWithDefaultFix()); - } - - private void registerProblem(@NotNull BranchBase duplicate, @NotNull @InspectionMessage String message, LocalQuickFix @NotNull ... fixes) { + private void registerProblem(@NotNull BranchBase duplicate, + @NotNull @InspectionMessage String message, + LocalQuickFix @NotNull ... fixes) { ProblemDescriptor descriptor = InspectionManager.getInstance(myHolder.getProject()) .createProblemDescriptor(duplicate.myStatements[0], duplicate.myStatements[duplicate.myStatements.length - 1], message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, @@ -252,7 +250,7 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo return branch; } - static boolean areDuplicates(@NotNull BranchBase branch, @NotNull BranchBase otherBranch) { + static boolean areDuplicates(@NotNull BranchBase branch, @NotNull BranchBase otherBranch) { if (branch.isSimpleExit() != otherBranch.isSimpleExit() || branch.canFallThrough() != otherBranch.canFallThrough() || branch.effectiveLength() != otherBranch.effectiveLength()) { @@ -346,6 +344,21 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo } } + /** + * Used to merge 'case null -> ...' with 'default -> ...' to get as a result 'case null, default -> ...' + */ + private static class MergeWithDefaultRuleFix extends MergeWithDefaultBranchFix { + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + RuleFixContext context = new RuleFixContext(); + if (context.prepare(descriptor.getStartElement(), BranchBase::isDefault)) { + context.copyCaseValues(true); + context.deleteRedundantComments(); + context.deleteRule(); + } + } + } + private static class DeleteRedundantBranchFix implements LocalQuickFix { @Nls(capitalization = Nls.Capitalization.Sentence) @@ -365,9 +378,19 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { BranchFixContext context = new BranchFixContext(); - if (context.prepare(descriptor.getStartElement(), Branch::isDefault)) { + if (context.prepare(descriptor.getStartElement(), BranchBase::isDefault)) { context.deleteBranchLabel(); - context.deleteStatements(); + if (!context.myBranchToDelete.hasSingleNullCase()) { + // case R(): + // case null: + // case S(): + // return 42; + // + // The 'default' case does not handle null values, so we cannot delete + // the 'case null:' and the 'return 42;' statement. However, + // we can delete the 'case R():' and 'case S():' statements." + context.deleteStatements(); + } } } } @@ -423,23 +446,34 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo PsiElement prevElement = PsiTreeUtil.skipWhitespacesAndCommentsBackward(myLabelToMergeWith); if (prevElement != null) moveTarget = prevElement; } - if (PsiUtil.isLanguageLevel14OrHigher(moveTarget) && moveTarget instanceof PsiSwitchLabelStatement) { - final PsiSwitchLabelStatement labelStatement = (PsiSwitchLabelStatement)moveTarget; - final PsiCaseLabelElementList caseLabelElementList = labelStatement.getCaseLabelElementList(); - assert caseLabelElementList != null; + if (PsiUtil.isLanguageLevel14OrHigher(moveTarget) && moveTarget instanceof PsiSwitchLabelStatement labelStatement && + myBranchToDelete.canCopyCaseValues() && !SwitchUtils.isCaseNull(labelStatement)) { for (PsiElement element : myBranchPrefixToMove) { - if (element instanceof PsiSwitchLabelStatement) { - final PsiSwitchLabelStatement statement = (PsiSwitchLabelStatement)element; - final PsiCaseLabelElementList list1 = RuleFixContext.getCaseLabelElementList(statement); - assert list1 != null; - for (PsiCaseLabelElement labelElement : list1.getElements()) { - caseLabelElementList.addAfter(labelElement, caseLabelElementList.getLastChild()); + if (element instanceof PsiSwitchLabelStatement statement) { + if (SwitchUtils.isCaseNull(statement) && myLabelToMergeWith.isDefaultCase()) { + copyCaseValues(statement, myLabelToMergeWith, true); + } + else { + copyCaseValues(statement, labelStatement, false); } } } } else { - moveTarget.getParent().addRangeAfter(firstElementToMove, lastElementToMove, moveTarget); + if (myBranchToMergeWith.isDefault()) { + for (PsiElement current = lastElementToMove; current != firstElementToMove; current = current.getPrevSibling()) { + if (current instanceof PsiWhiteSpace) continue; + if (current instanceof PsiSwitchLabelStatement labelStatement && SwitchUtils.isCaseNull(labelStatement)) { + copyCaseValues(labelStatement, myLabelToMergeWith, true); + } + else { + moveTarget.getParent().addAfter(current, moveTarget); + } + } + } + else { + moveTarget.getParent().addRangeAfter(firstElementToMove, lastElementToMove, moveTarget); + } } firstElementToMove.getParent().deleteChildRange(firstElementToMove, lastElementToMove); } @@ -495,18 +529,51 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo int size = toDelete.size(); if (size != 0) { for (int i = 0; i < size - 1; i++) { - tracker.delete(toDelete.get(i)); + deleteKeepingCaseNull(toDelete.get(i), tracker, false); } - tracker.deleteAndRestoreComments(toDelete.get(size - 1)); + deleteKeepingCaseNull(toDelete.get(size - 1), tracker, true); } } - } - public enum BranchType { - UNMERGEABLE, - TYPE_TEST_PATTERN, - HAS_NULL, - CONSTANT + /** + * Deletes the given PsiElement if it's not 'case null:'. The 'default' label does not handle null values, + * so 'case null' is not redundant and cannot be removed. + *

+ * We cannot get labels like 'case String s, null' or 'case "hello", null' here. + * + * @param element element to delete + * @param ct CommentTracker to use + * @param needRestoreComments if {@code true} {@link CommentTracker#deleteAndRestoreComments(PsiElement)} is called, + * {@link CommentTracker#delete(PsiElement)} otherwise + */ + private static void deleteKeepingCaseNull(@NotNull PsiElement element, @NotNull CommentTracker ct, boolean needRestoreComments) { + if (!(element instanceof PsiSwitchLabelStatement labelStatement) || !SwitchUtils.isCaseNull(labelStatement)) { + if (needRestoreComments) { + ct.delete(element); + } + else { + new CommentTracker().deleteAndRestoreComments(element); + } + } + } + + private static @Nullable PsiCaseLabelElementList getCaseLabelElementList(@NotNull PsiSwitchLabelStatement label) { + if (label.isDefaultCase()) { + PsiElementFactory factory = PsiElementFactory.getInstance(label.getProject()); + PsiSwitchLabelStatement labelStatement = (PsiSwitchLabelStatement)factory.createStatementFromText("case default:", null); + PsiSwitchLabelStatement newLabelStatement = (PsiSwitchLabelStatement)label.replace(labelStatement); + return newLabelStatement.getCaseLabelElementList(); + } + return label.getCaseLabelElementList(); + } + + private static void copyCaseValues(@NotNull PsiSwitchLabelStatement from, + @NotNull PsiSwitchLabelStatement to, + boolean mergeWithDefault) { + @Nullable PsiCaseLabelElementList fromCaseLabelElementList = getCaseLabelElementList(from); + @Nullable PsiCaseLabelElementList toCaseLabelElementList = getCaseLabelElementList(to); + DuplicateBranchesInSwitchInspection.copyCaseValues(fromCaseLabelElementList, toCaseLabelElementList, mergeWithDefault); + } } private static abstract class BranchBase { @@ -514,8 +581,8 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo protected final PsiStatement @NotNull [] myStatements; protected final String @NotNull [] myCommentTexts; private final boolean myIsDefault; - private final @NotNull BranchType myBranchType; private DuplicatesFinder myFinder; + protected final boolean myCanDeleteRedundantBranch; BranchBase(T @NotNull [] labels, PsiStatement @NotNull [] statements, String @NotNull [] commentTexts) { LOG.assertTrue(labels.length != 0, "labels.length"); @@ -524,37 +591,14 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo myLabel = labels[0]; myStatements = statements; myCommentTexts = commentTexts; - myIsDefault = ContainerUtil.exists(labels, SwitchUtils::hasOnlyDefaultCase); - myBranchType = getBranchType(labels); - } - - BranchType getBranchType(PsiSwitchLabelStatementBase @NotNull [] labels) { - boolean hasTypeTestPattern = false; - boolean hasNull = false; - for (PsiSwitchLabelStatementBase label : labels) { - PsiCaseLabelElementList labelElementList = label.getCaseLabelElementList(); - if (labelElementList == null) continue; - PsiCaseLabelElement[] elements = labelElementList.getElements(); - for (PsiCaseLabelElement element : elements) { - if (PsiTreeUtil.instanceOf(element, PsiGuardedPattern.class, PsiPatternGuard.class, PsiParenthesizedPattern.class, - PsiDeconstructionPattern.class)) { - return BranchType.UNMERGEABLE; - } - else if (element instanceof PsiTypeTestPattern) { - hasTypeTestPattern = true; - } - else if (ExpressionUtils.isNullLiteral(ObjectUtils.tryCast(element, PsiExpression.class))) { - hasNull = true; - } - } - } - if (hasTypeTestPattern) { - return BranchType.TYPE_TEST_PATTERN; - } - else if (hasNull) { - return BranchType.HAS_NULL; - } - return BranchType.CONSTANT; + myIsDefault = ContainerUtil.exists(labels, label -> label.isDefaultCase() || SwitchUtils.isCaseNullDefault(label)); + myCanDeleteRedundantBranch = labels.length > 1 || + !ContainerUtil.exists(labels, label -> { + PsiCaseLabelElementList list = label.getCaseLabelElementList(); + if (list == null) return false; + return ContainerUtil.exists(list.getElements(), element -> element instanceof PsiExpression expr && + ExpressionUtils.isNullLiteral(expr)); + }); } boolean isDefault() { @@ -570,6 +614,8 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo abstract boolean canFallThrough(); + abstract boolean canMergeBranch(); + int effectiveLength() { if (myStatements.length == 1 && myStatements[0] instanceof PsiBlockStatement) { return ((PsiBlockStatement)myStatements[0]).getCodeBlock().getStatementCount(); @@ -582,10 +628,12 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo } @Nullable - abstract LocalQuickFix newMergeCasesFix(); + abstract LocalQuickFix newMergeCasesFix(BranchBase otherBranch); + @Nullable abstract LocalQuickFix newDeleteCaseFix(); + @Nullable abstract LocalQuickFix newMergeWithDefaultFix(); @Nullable @@ -714,14 +762,23 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo private static final PsiSwitchLabelStatement[] EMPTY_LABELS_ARRAY = new PsiSwitchLabelStatement[0]; private final boolean myIsSimpleExit; private final boolean myCanFallThrough; + private final boolean myCanMergeBranch; + private final boolean myHasSingleNullCase; + private final boolean myCanCopyCaseValues; - Branch(PsiSwitchLabelStatement @NotNull [] labels, @NotNull List statementList, boolean hasImplicitBreak, String @NotNull [] comments) { + Branch(PsiSwitchLabelStatement @NotNull [] labels, + @NotNull List statementList, + boolean hasImplicitBreak, + String @NotNull [] comments) { super(labels, statementsWithoutTrailingBreak(statementList), comments); int lastIndex = statementList.size() - 1; PsiStatement lastStatement = statementList.get(lastIndex); myCanFallThrough = !hasImplicitBreak && ControlFlowUtils.statementMayCompleteNormally(lastStatement); myIsSimpleExit = lastIndex == 0 && isSimpleExit(lastStatement); + myCanMergeBranch = calculateCanMergeBranches(labels); + myHasSingleNullCase = ContainerUtil.exists(labels, SwitchUtils::isCaseNull); + myCanCopyCaseValues = ContainerUtil.all(labels, label -> Rule.calculateCanMergeBranches(label)); } @Override @@ -729,6 +786,35 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo return myCanFallThrough; } + private static boolean calculateCanMergeBranches(PsiSwitchLabelStatement @NotNull [] labels) { + boolean java20plus = PsiUtil.getLanguageLevel(labels[0]).isAtLeast(LanguageLevel.JDK_20_PREVIEW); + for (PsiSwitchLabelStatement label : labels) { + PsiCaseLabelElementList labelElementList = label.getCaseLabelElementList(); + if (labelElementList == null) continue; + PsiCaseLabelElement[] elements = labelElementList.getElements(); + for (PsiCaseLabelElement element : elements) { + if (PsiTreeUtil.instanceOf(element, PsiGuardedPattern.class, PsiPatternGuard.class) || + element instanceof PsiPattern && (!java20plus || JavaPsiPatternUtil.containsPatternVariable(element))) { + return false; + } + } + } + return true; + } + + @Override + boolean canMergeBranch() { + return myCanMergeBranch; + } + + boolean canCopyCaseValues() { + return myCanCopyCaseValues; + } + + boolean hasSingleNullCase() { + return myHasSingleNullCase; + } + @Override boolean isSimpleExit() { return myIsSimpleExit; @@ -736,19 +822,23 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo @Nullable @Override - LocalQuickFix newMergeCasesFix() { + LocalQuickFix newMergeCasesFix(BranchBase otherBranch) { + if (!otherBranch.canMergeBranch()) return null; String switchLabelText = getSwitchLabelText(); - return switchLabelText != null ? new MergeBranchesFix(switchLabelText) : null; + if (switchLabelText == null) return null; + return myCanMergeBranch ? new MergeBranchesFix(switchLabelText) : null; } + @Nullable @Override LocalQuickFix newMergeWithDefaultFix() { - return new MergeWithDefaultBranchFix(); + return myCanMergeBranch ? new MergeWithDefaultBranchFix() : null; } + @Nullable @Override LocalQuickFix newDeleteCaseFix() { - return new DeleteRedundantBranchFix(); + return myCanDeleteRedundantBranch ? new DeleteRedundantBranchFix() : null; } // 'switch' labels with comments and spaces @@ -855,10 +945,28 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo private static class Rule extends BranchBase { private final boolean myIsSimpleExit; + private final boolean myCanMergeBranches; + private final boolean myCanMergeWithDefaultBranch; Rule(@NotNull PsiSwitchLabeledRuleStatement rule, @NotNull PsiStatement body, String @NotNull [] commentTexts) { super(new PsiSwitchLabeledRuleStatement[]{rule}, new PsiStatement[]{body}, commentTexts); myIsSimpleExit = body instanceof PsiExpressionStatement || body instanceof PsiThrowStatement; + myCanMergeBranches = calculateCanMergeBranches(rule); + myCanMergeWithDefaultBranch = SwitchUtils.isCaseNull(rule); + } + + public static boolean calculateCanMergeBranches(@NotNull PsiSwitchLabelStatementBase rule) { + PsiCaseLabelElementList labelElementList = rule.getCaseLabelElementList(); + if (labelElementList == null) return false; + PsiCaseLabelElement[] elements = labelElementList.getElements(); + return !ContainerUtil.exists(elements, element -> element instanceof PsiPattern || + element instanceof PsiPatternGuard || + element instanceof PsiExpression expr && ExpressionUtils.isNullLiteral(expr)); + } + + @Override + boolean canMergeBranch() { + return myCanMergeBranches; } @Override @@ -873,19 +981,23 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo @Nullable @Override - LocalQuickFix newMergeCasesFix() { + LocalQuickFix newMergeCasesFix(BranchBase otherBranch) { + if (!otherBranch.canMergeBranch()) return null; String switchLabelText = getSwitchLabelText(); - return switchLabelText != null ? new MergeRulesFix(switchLabelText) : null; + if (switchLabelText == null) return null; + return myCanMergeBranches ? new MergeRulesFix(switchLabelText) : null; } + @Nullable @Override LocalQuickFix newMergeWithDefaultFix() { - return null; + return myCanMergeWithDefaultBranch ? new MergeWithDefaultRuleFix() : null; } + @Nullable @Override LocalQuickFix newDeleteCaseFix() { - return new DeleteRedundantRuleFix(); + return myCanDeleteRedundantBranch ? new DeleteRedundantRuleFix() : null; } } @@ -914,7 +1026,7 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { RuleFixContext context = new RuleFixContext(); if (context.prepare(descriptor.getStartElement(), rule -> mySwitchLabelText.equals(rule.getSwitchLabelText()))) { - context.copyCaseValues(); + context.copyCaseValues(false); context.deleteRedundantComments(); context.deleteRule(); } @@ -1023,24 +1135,25 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo redundantComments.forEach(PsiElement::delete); } - private static @Nullable PsiCaseLabelElementList getCaseLabelElementList(@NotNull PsiSwitchLabelStatementBase label) { - if (label.isDefaultCase()) { - PsiElementFactory factory = PsiElementFactory.getInstance(label.getProject()); - PsiSwitchLabelStatement labelStatement = (PsiSwitchLabelStatement)factory.createStatementFromText("case default", null); - PsiSwitchLabelStatement newLabelStatement = (PsiSwitchLabelStatement)label.getFirstChild().replace(labelStatement); - return newLabelStatement.getCaseLabelElementList(); + @Nullable PsiCaseLabelElementList getCaseLabelElementList(@NotNull PsiSwitchLabeledRuleStatement ruleStatement) { + if (ruleStatement.isDefaultCase()) { + PsiElementFactory factory = PsiElementFactory.getInstance(ruleStatement.getProject()); + PsiSwitchLabeledRuleStatement labelStatement = + (PsiSwitchLabeledRuleStatement)factory.createStatementFromText("case default->{}", null); + PsiStatement body = ruleStatement.getBody(); + if (body != null) { + Objects.requireNonNull(labelStatement.getBody()).replace(body); + } + PsiSwitchLabeledRuleStatement newLabelStatement = (PsiSwitchLabeledRuleStatement)ruleStatement.replace(labelStatement); + return newLabelStatement.getCaseLabelElementList(); + } + return ruleStatement.getCaseLabelElementList(); } - return label.getCaseLabelElementList(); - } - void copyCaseValues() { + void copyCaseValues(boolean mergeWithDefault) { @Nullable PsiCaseLabelElementList caseValuesToMergeWith = getCaseLabelElementList(myRuleToMergeWith.myLabel); @Nullable PsiCaseLabelElementList caseValuesToDelete = getCaseLabelElementList(myRuleToDelete.myLabel); - if (caseValuesToDelete != null && caseValuesToMergeWith != null) { - for (PsiCaseLabelElement caseValue : caseValuesToDelete.getElements()) { - caseValuesToMergeWith.addAfter(caseValue, caseValuesToMergeWith.getLastChild()); - } - } + DuplicateBranchesInSwitchInspection.copyCaseValues(caseValuesToDelete, caseValuesToMergeWith, mergeWithDefault); } void deleteRule() { @@ -1055,4 +1168,18 @@ public final class DuplicateBranchesInSwitchInspection extends LocalInspectionTo tracker.deleteAndRestoreComments(myRuleToDelete.myLabel); } } + + public static void copyCaseValues(@Nullable PsiCaseLabelElementList from, + @Nullable PsiCaseLabelElementList to, + boolean mergeWithDefault) { + if (from == null || to == null) return; + for (PsiCaseLabelElement caseValue : from.getElements()) { + if (mergeWithDefault) { + to.addBefore(caseValue, to.getFirstChild()); + } + else { + to.addAfter(caseValue, to.getLastChild()); + } + } + } } \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/util/JavaPsiPatternUtil.java b/java/java-psi-impl/src/com/intellij/psi/util/JavaPsiPatternUtil.java index 5674590b9ad9..39002b154508 100644 --- a/java/java-psi-impl/src/com/intellij/psi/util/JavaPsiPatternUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/util/JavaPsiPatternUtil.java @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.psi.util; import com.intellij.openapi.project.Project; @@ -9,6 +9,7 @@ import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.tree.IElementType; import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtils; +import com.intellij.util.containers.ContainerUtil; import one.util.streamex.StreamEx; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -160,6 +161,35 @@ public final class JavaPsiPatternUtil { } } + /** + * Checks if the pattern declares one or more pattern variables + * + * @param pattern pattern to check + * @return {@code true} if the pattern declares one or more pattern variables, {@code false} otherwise. + */ + @Contract(value = "null -> false", pure = true) + public static boolean containsPatternVariable(@Nullable PsiCaseLabelElement pattern) { + if (pattern instanceof PsiPatternGuard) { + return containsPatternVariable(((PsiPatternGuard)pattern).getPattern()); + } + else if (pattern instanceof PsiGuardedPattern) { + return containsPatternVariable(((PsiGuardedPattern)pattern).getPrimaryPattern()); + } + else if (pattern instanceof PsiTypeTestPattern) { + return ((PsiTypeTestPattern)pattern).getPatternVariable() != null; + } + else if (pattern instanceof PsiParenthesizedPattern) { + return containsPatternVariable(((PsiParenthesizedPattern)pattern).getPattern()); + } + else if (pattern instanceof PsiDeconstructionPattern) { + PsiDeconstructionPattern deconstructionPattern = (PsiDeconstructionPattern)pattern; + return deconstructionPattern.getPatternVariable() != null || + ContainerUtil.exists(deconstructionPattern.getDeconstructionList().getDeconstructionComponents(), + component -> containsPatternVariable(component)); + } + return false; + } + /** * @return type of variable in pattern, or null if pattern is incomplete */ diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/NullDuplicatesDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/NullDuplicatesDefault.java new file mode 100644 index 000000000000..db356a8521a1 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/NullDuplicatesDefault.java @@ -0,0 +1,9 @@ +class C { + void foo(String s) { + switch (s) { + case "blah blah blah", null -> bar("A"); + default -> bar("A"); + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullMergeWithPattern.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/NullDuplicatesPattern.java similarity index 67% rename from java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullMergeWithPattern.java rename to java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/NullDuplicatesPattern.java index 92b23d9a713f..61b75c82dde2 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullMergeWithPattern.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/NullDuplicatesPattern.java @@ -1,10 +1,9 @@ -// "Merge with 'case Number n'" "GENERIC_ERROR_OR_WARNING" class C { void foo(Object o) { switch (o) { case Number n -> bar("A"); case String s -> bar("B"); - case null -> bar("A"); + case null -> bar("A"); default -> bar("C"); } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforePatternMergeWithNull.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/PatternDuplicatesNull.java similarity index 66% rename from java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforePatternMergeWithNull.java rename to java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/PatternDuplicatesNull.java index 72fe2d259013..226c9e3d88f0 100644 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforePatternMergeWithNull.java +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitch/PatternDuplicatesNull.java @@ -1,10 +1,9 @@ -// "Merge with 'case null'" "GENERIC_ERROR_OR_WARNING" class C { void foo(Object o) { switch (o) { case null -> bar("A"); case String s -> bar("B"); - case Number n -> bar("A"); + case Number n -> bar("A"); default -> bar("C"); } } diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterCaseDefaultMergeWithNull.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterCaseDefaultMergeWithNull.java deleted file mode 100644 index a703e57d315d..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterCaseDefaultMergeWithNull.java +++ /dev/null @@ -1,10 +0,0 @@ -// "Merge with 'case null'" "GENERIC_ERROR_OR_WARNING" -class C { - void foo(Object o) { - switch (o) { - case null, default -> bar("A"); - case String s -> bar("B"); - } - } - void bar(String s){} -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterMergeNullWithDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterMergeNullWithDefault.java new file mode 100644 index 000000000000..fc170f6659dc --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterMergeNullWithDefault.java @@ -0,0 +1,9 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(Object o) { + switch (o) { + case String s -> {} + case null, default -> System.out.println("hello"); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateAfterCaseDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateAfterCaseDefaultMerge.java deleted file mode 100644 index 2bb9a8da4803..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateAfterCaseDefaultMerge.java +++ /dev/null @@ -1,8 +0,0 @@ -// "Merge with 'case default'" "true" -class Test { - void foo(String s) { - switch (s) { - case default, "hello", null, "42" -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateAfterDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateAfterDefaultMerge.java deleted file mode 100644 index b0b76246b761..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateAfterDefaultMerge.java +++ /dev/null @@ -1,8 +0,0 @@ -// "Merge with 'default'" "true" -class Test { - void foo(Object o) { - switch (o) { - case default, null -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateBeforeCaseDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateBeforeCaseDefaultMerge.java deleted file mode 100644 index 01c5b0eb7c23..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateBeforeCaseDefaultMerge.java +++ /dev/null @@ -1,8 +0,0 @@ -// "Merge with 'case null'" "true" -class Test { - void foo(Object o) { - switch (o) { - case null, default -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateBeforeDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateBeforeDefaultMerge.java deleted file mode 100644 index 01c5b0eb7c23..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullDuplicateBeforeDefaultMerge.java +++ /dev/null @@ -1,8 +0,0 @@ -// "Merge with 'case null'" "true" -class Test { - void foo(Object o) { - switch (o) { - case null, default -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullMergeWithCaseDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullMergeWithCaseDefault.java deleted file mode 100644 index 1794554554ee..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullMergeWithCaseDefault.java +++ /dev/null @@ -1,10 +0,0 @@ -// "Merge with 'case default'" "GENERIC_ERROR_OR_WARNING" -class C { - void foo(Object o) { - switch (o) { - case default, null -> bar("A"); - case String s -> bar("B"); - } - } - void bar(String s){} -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullMergeWithPattern.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullMergeWithPattern.java deleted file mode 100644 index fb0312c4b7c0..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterNullMergeWithPattern.java +++ /dev/null @@ -1,11 +0,0 @@ -// "Merge with 'case Number n'" "GENERIC_ERROR_OR_WARNING" -class C { - void foo(Object o) { - switch (o) { - case Number n, null -> bar("A"); - case String s -> bar("B"); - default -> bar("C"); - } - } - void bar(String s){} -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterPatternMergeWithNull.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterPatternMergeWithNull.java deleted file mode 100644 index 8d43f8824d1b..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/afterPatternMergeWithNull.java +++ /dev/null @@ -1,11 +0,0 @@ -// "Merge with 'case null'" "GENERIC_ERROR_OR_WARNING" -class C { - void foo(Object o) { - switch (o) { - case null, Number n -> bar("A"); - case String s -> bar("B"); - default -> bar("C"); - } - } - void bar(String s){} -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotDeleteRedundantBranch.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotDeleteRedundantBranch.java new file mode 100644 index 000000000000..41053aeac410 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotDeleteRedundantBranch.java @@ -0,0 +1,9 @@ +// "Delete redundant 'switch' branch" "false" +class Test { + void foo(Stirng s) { + switch (s) { + case null -> System.out.println(42); + default -> System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault1.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault1.java new file mode 100644 index 000000000000..0279d9d0fa39 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault1.java @@ -0,0 +1,9 @@ +// "Merge with the default 'switch' branch" "false" +class Test { + void foo(Object o) { + switch (o) { + case String s -> System.out.println("hello"); + default -> System.out.println("hello"); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault2.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault2.java new file mode 100644 index 000000000000..4d12cae7b31d --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault2.java @@ -0,0 +1,11 @@ +// "Merge with the default 'switch' branch" "false" +class Test { + record R() {} + + void foo(Object o) { + switch (o) { + case R() -> System.out.println("hello"); + default -> System.out.println("hello"); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault3.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault3.java new file mode 100644 index 000000000000..fd4f759ad8dd --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault3.java @@ -0,0 +1,9 @@ +// "Merge with the default 'switch' branch" "false" +class Test { + void foo(String s) { + switch (s) { + case "blah blah blah" -> System.out.println("hello"); + default -> System.out.println("hello"); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault4.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault4.java new file mode 100644 index 000000000000..a68ffaa3ac94 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCannotMergeWithDefault4.java @@ -0,0 +1,9 @@ +// "Merge with the default 'switch' branch" "false" +class Test { + void foo(String s) { + switch (s) { + case "blah blah blah" -> System.out.println("hello"); + case null, default -> System.out.println("hello"); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCaseDefaultMergeWithNull.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCaseDefaultMergeWithNull.java deleted file mode 100644 index bd5dfcb126a3..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeCaseDefaultMergeWithNull.java +++ /dev/null @@ -1,11 +0,0 @@ -// "Merge with 'case null'" "GENERIC_ERROR_OR_WARNING" -class C { - void foo(Object o) { - switch (o) { - case null -> bar("A"); - case String s -> bar("B"); - case default -> bar("A"); - } - } - void bar(String s){} -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeMergeNullWithDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeMergeNullWithDefault.java new file mode 100644 index 000000000000..ca8715adcb45 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeMergeNullWithDefault.java @@ -0,0 +1,10 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(Object o) { + switch (o) { + case null -> System.out.println("hello"); + case String s -> {} + default -> System.out.println("hello"); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterCaseDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterCaseDefaultDelete.java deleted file mode 100644 index 2b90e6654cd3..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterCaseDefaultDelete.java +++ /dev/null @@ -1,9 +0,0 @@ -// "Delete redundant 'switch' branch" "false" -class Test { - void foo(String s) { - switch (s) { - case default -> System.out.println("hello"); - case "hello", null, "42" -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterCaseDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterCaseDefaultMerge.java deleted file mode 100644 index 4a7b87766ea8..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterCaseDefaultMerge.java +++ /dev/null @@ -1,9 +0,0 @@ -// "Merge with 'case default'" "true" -class Test { - void foo(String s) { - switch (s) { - case default -> System.out.println("hello"); - case "hello", null, "42" -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterDefaultDelete.java deleted file mode 100644 index 45ad315a14b6..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterDefaultDelete.java +++ /dev/null @@ -1,9 +0,0 @@ -// "Delete redundant 'switch' branch" "false" -class Test { - void foo(Object o) { - switch (o) { - default -> System.out.println("hello"); - case null -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterDefaultMerge.java deleted file mode 100644 index 2811f05597e4..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateAfterDefaultMerge.java +++ /dev/null @@ -1,9 +0,0 @@ -// "Merge with 'default'" "true" -class Test { - void foo(Object o) { - switch (o) { - default -> System.out.println("hello"); - case null -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeCaseDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeCaseDefaultDelete.java deleted file mode 100644 index be2e140bef22..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeCaseDefaultDelete.java +++ /dev/null @@ -1,9 +0,0 @@ -// "Delete redundant 'switch' branch" "false" -class Test { - void foo(Object o) { - switch (o) { - case null -> System.out.println("hello"); - case default -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeCaseDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeCaseDefaultMerge.java deleted file mode 100644 index 0fca5fdab766..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeCaseDefaultMerge.java +++ /dev/null @@ -1,9 +0,0 @@ -// "Merge with 'case null'" "true" -class Test { - void foo(Object o) { - switch (o) { - case null -> System.out.println("hello"); - case default -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeDefaultDelete.java deleted file mode 100644 index 2a61ed2fd59c..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeDefaultDelete.java +++ /dev/null @@ -1,9 +0,0 @@ -// "Delete redundant 'switch' branch" "false" -class Test { - void foo(Object o) { - switch (o) { - case null -> System.out.println("hello"); - default -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeDefaultMerge.java deleted file mode 100644 index 02fb627dbd00..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullDuplicateBeforeDefaultMerge.java +++ /dev/null @@ -1,9 +0,0 @@ -// "Merge with 'case null'" "true" -class Test { - void foo(Object o) { - switch (o) { - case null -> System.out.println("hello"); - default -> System.out.println("hello"); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullMergeWithCaseDefault.java b/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullMergeWithCaseDefault.java deleted file mode 100644 index 21a057c82ee5..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInEnhancedSwitchFix/beforeNullMergeWithCaseDefault.java +++ /dev/null @@ -1,11 +0,0 @@ -// "Merge with 'case default'" "GENERIC_ERROR_OR_WARNING" -class C { - void foo(Object o) { - switch (o) { - case default -> bar("A"); - case String s -> bar("B"); - case null -> bar("A"); - } - } - void bar(String s){} -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NullDuplicatesPattern.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NullDuplicatesPattern.java new file mode 100644 index 000000000000..daa9ddea944e --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/NullDuplicatesPattern.java @@ -0,0 +1,19 @@ +class C { + void foo(Object o) { + switch (o) { + case Number n: + bar("A"); + break; + case String s: + bar("B"); + break; + case null: + bar("A"); + break; + default: + bar("C"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitch/PatternDuplicatesNull.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/PatternDuplicatesNull.java new file mode 100644 index 000000000000..04afe0709def --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitch/PatternDuplicatesNull.java @@ -0,0 +1,19 @@ +class C { + void foo(Object o) { + switch (o) { + case null: + bar("A"); + break; + case String s: + bar("B"); + break; + case Number n: + bar("A"); + break; + default: + bar("C"); + break; + } + } + void bar(String s){} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterCaseDefaultDuplicateNullMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterCaseDefaultDuplicateNullMerge.java deleted file mode 100644 index faabc60d8f7d..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterCaseDefaultDuplicateNullMerge.java +++ /dev/null @@ -1,10 +0,0 @@ -// "Merge with 'case null'" "true" -class Test { - void foo(Object o) { - switch (o) { - case null, default: - System.out.println(42); - break; - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDefaultDuplicateNullMerge1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDefaultDuplicateNullMerge1.java deleted file mode 100644 index faabc60d8f7d..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDefaultDuplicateNullMerge1.java +++ /dev/null @@ -1,10 +0,0 @@ -// "Merge with 'case null'" "true" -class Test { - void foo(Object o) { - switch (o) { - case null, default: - System.out.println(42); - break; - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDefaultDuplicateNullMerge2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDefaultDuplicateNullMerge2.java deleted file mode 100644 index 0b6999bd0516..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDefaultDuplicateNullMerge2.java +++ /dev/null @@ -1,11 +0,0 @@ -// "Merge with 'case "hello"'" "true" -class Test { - void foo(String o) { - switch (o) { - case "hello": - case null, default: - System.out.println(42); - break; - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch1.java new file mode 100644 index 000000000000..26f66209f3d3 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch1.java @@ -0,0 +1,13 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(String o) { + switch (o) { + case null: + System.out.println(42); + break; + default: + System.out.println(42); + break; + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch2.java new file mode 100644 index 000000000000..94c742bc2d73 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch2.java @@ -0,0 +1,12 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(String str) { + switch (str) { + case null: + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch3.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch3.java new file mode 100644 index 000000000000..282d3ea18aae --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch3.java @@ -0,0 +1,15 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + record R() {} + record S() {} + + void foo(Object obj) { + switch (obj) { + case null: + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch4.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch4.java new file mode 100644 index 000000000000..2a75f95ce34f --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch4.java @@ -0,0 +1,12 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + record R() {} + record S() {} + + void foo(Object obj) { + switch (obj) { + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch5.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch5.java new file mode 100644 index 000000000000..ed9287e75b9f --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch5.java @@ -0,0 +1,10 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(String o) { + switch (o) { + default: + System.out.println(42); + break; + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch6.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch6.java new file mode 100644 index 000000000000..890770dc3178 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterDeleteRedundantBranch6.java @@ -0,0 +1,11 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + record R() {} + + void foo(Object obj) { + switch (obj) { + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault1.java new file mode 100644 index 000000000000..d284fbbf427f --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault1.java @@ -0,0 +1,10 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(String str) { + switch (str) { + case "hello": + case null, default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault2.java new file mode 100644 index 000000000000..98aa3304a71f --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault2.java @@ -0,0 +1,11 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(String str) { + switch (str) { + case "hello": + case "blah blah blah": + case null, default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault3.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault3.java new file mode 100644 index 000000000000..4d6d65073da3 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault3.java @@ -0,0 +1,14 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + record R() {} + record S() {} + + void foo(Object obj) { + switch (obj) { + case R(): + case S(): + case null, default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault4.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault4.java new file mode 100644 index 000000000000..5e8386028a5c --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault4.java @@ -0,0 +1,9 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(Object o) { + switch (o) { + case null, default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault5.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault5.java new file mode 100644 index 000000000000..71d021145ac4 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterMergeWithDefault5.java @@ -0,0 +1,14 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + record R() {} + record S() {} + + void foo(Object obj) { + switch (obj) { + case R(): + case S(): + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterNullDuplicateCaseDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterNullDuplicateCaseDefaultMerge.java deleted file mode 100644 index b43b33bbe9fb..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterNullDuplicateCaseDefaultMerge.java +++ /dev/null @@ -1,10 +0,0 @@ -// "Merge with 'case default'" "true" -class Test { - void foo(Object o) { - switch (o) { - case default, null: - System.out.println(42); - break; - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterNullDuplicateDefaultMerge1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterNullDuplicateDefaultMerge1.java deleted file mode 100644 index c3c3cc0c57be..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterNullDuplicateDefaultMerge1.java +++ /dev/null @@ -1,11 +0,0 @@ -// "Merge with 'default'" "true" -class Test { - void foo(Object o) { - switch (o) { - case null: - default: - System.out.println(42); - break; - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterNullDuplicateDefaultMerge2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterNullDuplicateDefaultMerge2.java deleted file mode 100644 index 421c682cabfb..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/afterNullDuplicateDefaultMerge2.java +++ /dev/null @@ -1,12 +0,0 @@ -// "Merge with 'default'" "true" -class Test { - void foo(String o) { - switch (o) { - case null: - case "hello": - default: - System.out.println(42); - break; - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateBeforeDefaultDelete1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCannotDeleteRedundantBranch.java similarity index 100% rename from java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateBeforeDefaultDelete1.java rename to java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCannotDeleteRedundantBranch.java diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCannotMergeWithDefault1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCannotMergeWithDefault1.java new file mode 100644 index 000000000000..fc5e3fa7aa44 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCannotMergeWithDefault1.java @@ -0,0 +1,14 @@ +// "Merge with the default 'switch' branch" "false" +class Test { + record R() {} + + void foo(Object obj) { + switch (obj) { + case R r: + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCannotMergeWithDefault2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCannotMergeWithDefault2.java new file mode 100644 index 000000000000..01955cf4e336 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCannotMergeWithDefault2.java @@ -0,0 +1,14 @@ +// "Merge with the default 'switch' branch" "false" +class Test { + record R() {} + + void foo(Object obj) { + switch (obj) { + case R() when true: + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCaseDefaultDuplicateNullMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCaseDefaultDuplicateNullMerge.java deleted file mode 100644 index 1f82c9ef8cc3..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeCaseDefaultDuplicateNullMerge.java +++ /dev/null @@ -1,12 +0,0 @@ -// "Merge with 'case null'" "true" -class Test { - void foo(Object o) { - switch (o) { - case null: - System.out.println(42); - break; - case default: - System.out.println(42); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDefaultDuplicateNullMerge1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDefaultDuplicateNullMerge1.java deleted file mode 100644 index ee8a91bc95cf..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDefaultDuplicateNullMerge1.java +++ /dev/null @@ -1,12 +0,0 @@ -// "Merge with 'case null'" "true" -class Test { - void foo(Object o) { - switch (o) { - case null: - System.out.println(42); - break; - default: - System.out.println(42); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDefaultDuplicateNullMerge2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDefaultDuplicateNullMerge2.java deleted file mode 100644 index 87d15dd7c90f..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDefaultDuplicateNullMerge2.java +++ /dev/null @@ -1,14 +0,0 @@ -// "Merge with 'case "hello"'" "true" -class Test { - void foo(String o) { - switch (o) { - case "hello": - case null: - System.out.println(42); - break; - default: - System.out.println(42); - break; - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch1.java new file mode 100644 index 000000000000..2f81b01f0fa9 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch1.java @@ -0,0 +1,14 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(String o) { + switch (o) { + case "hello": + case null: + System.out.println(42); + break; + default: + System.out.println(42); + break; + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch2.java new file mode 100644 index 000000000000..82a901ed46e5 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch2.java @@ -0,0 +1,14 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(String str) { + switch (str) { + case null: + case "hello": + case "blah blah blah": + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch3.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch3.java new file mode 100644 index 000000000000..4730f271d26a --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch3.java @@ -0,0 +1,17 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + record R() {} + record S() {} + + void foo(Object obj) { + switch (obj) { + case R(): + case S(): + case null: + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch4.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch4.java new file mode 100644 index 000000000000..1f269f28a0e7 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch4.java @@ -0,0 +1,16 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + record R() {} + record S() {} + + void foo(Object obj) { + switch (obj) { + case R(): + case S(): + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch5.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch5.java new file mode 100644 index 000000000000..f343568dc342 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch5.java @@ -0,0 +1,14 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(String o) { + switch (o) { + case "hello": + case "bye": + System.out.println(42); + break; + default: + System.out.println(42); + break; + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch6.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch6.java new file mode 100644 index 000000000000..a5f1bd4f69d5 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeDeleteRedundantBranch6.java @@ -0,0 +1,14 @@ +// "Delete redundant 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + record R() {} + + void foo(Object obj) { + switch (obj) { + case R r: + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault1.java new file mode 100644 index 000000000000..3238f00508c6 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault1.java @@ -0,0 +1,13 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(String str) { + switch (str) { + case null: + case "hello": + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault2.java new file mode 100644 index 000000000000..036ddb2d5b7f --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault2.java @@ -0,0 +1,14 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(String str) { + switch (str) { + case null: + case "hello": + case "blah blah blah": + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault3.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault3.java new file mode 100644 index 000000000000..961a590ca421 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault3.java @@ -0,0 +1,17 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + record R() {} + record S() {} + + void foo(Object obj) { + switch (obj) { + case R(): + case S(): + case null: + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault4.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault4.java new file mode 100644 index 000000000000..fc08b9766f54 --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault4.java @@ -0,0 +1,12 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + void foo(Object o) { + switch (o) { + case null: + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault5.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault5.java new file mode 100644 index 000000000000..c074a778978d --- /dev/null +++ b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeMergeWithDefault5.java @@ -0,0 +1,16 @@ +// "Merge with the default 'switch' branch" "GENERIC_ERROR_OR_WARNING" +class Test { + record R() {} + record S() {} + + void foo(Object obj) { + switch (obj) { + case R(): + case S(): + System.out.println(42); + break; + default: + System.out.println(42); + } + } +} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateAfterCaseDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateAfterCaseDefaultDelete.java deleted file mode 100644 index d3381ae50d95..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateAfterCaseDefaultDelete.java +++ /dev/null @@ -1,12 +0,0 @@ -// "Delete redundant 'switch' branch" "false" -class Test { - void foo(Object o) { - switch (o) { - case default: - System.out.println(42); - break; - case null: - System.out.println(42); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateAfterDefaultDelete1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateAfterDefaultDelete1.java deleted file mode 100644 index 5a0c9f90abc5..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateAfterDefaultDelete1.java +++ /dev/null @@ -1,12 +0,0 @@ -// "Delete redundant 'switch' branch" "false" -class Test { - void foo(Object o) { - switch (o) { - default: - System.out.println(42); - break; - case null: - System.out.println(42); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateAfterDefaultDelete2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateAfterDefaultDelete2.java deleted file mode 100644 index 36b60720abc3..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateAfterDefaultDelete2.java +++ /dev/null @@ -1,13 +0,0 @@ -// "Delete redundant 'switch' branch" "false" -class Test { - void foo(String o) { - switch (o) { - default: - System.out.println(42); - break; - case null: - case "hello": - System.out.println(42); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateBeforeCaseDefaultDelete.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateBeforeCaseDefaultDelete.java deleted file mode 100644 index 2a85f1ec95d9..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateBeforeCaseDefaultDelete.java +++ /dev/null @@ -1,12 +0,0 @@ -// "Delete redundant 'switch' branch" "false" -class Test { - void foo(Object o) { - switch (o) { - case null: - System.out.println(42); - break; - case default: - System.out.println(42); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateBeforeDefaultDelete2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateBeforeDefaultDelete2.java deleted file mode 100644 index c495c6ce0962..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateBeforeDefaultDelete2.java +++ /dev/null @@ -1,14 +0,0 @@ -// "Delete redundant 'switch' branch" "false" -class Test { - void foo(String o) { - switch (o) { - case "hello": - case null: - System.out.println(42); - break; - default: - System.out.println(42); - break; - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateCaseDefaultMerge.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateCaseDefaultMerge.java deleted file mode 100644 index c7aaaa22bcd2..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateCaseDefaultMerge.java +++ /dev/null @@ -1,12 +0,0 @@ -// "Merge with 'case default'" "true" -class Test { - void foo(Object o) { - switch (o) { - case default: - System.out.println(42); - break; - case null: - System.out.println(42); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateDefaultMerge1.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateDefaultMerge1.java deleted file mode 100644 index 2a41ae2c6c7a..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateDefaultMerge1.java +++ /dev/null @@ -1,12 +0,0 @@ -// "Merge with 'default'" "true" -class Test { - void foo(Object o) { - switch (o) { - default: - System.out.println(42); - break; - case null: - System.out.println(42); - } - } -} diff --git a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateDefaultMerge2.java b/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateDefaultMerge2.java deleted file mode 100644 index 2645d8056107..000000000000 --- a/java/java-tests/testData/inspection/duplicateBranchesInSwitchFix/beforeNullDuplicateDefaultMerge2.java +++ /dev/null @@ -1,13 +0,0 @@ -// "Merge with 'default'" "true" -class Test { - void foo(String o) { - switch (o) { - default: - System.out.println(42); - break; - case null: - case "hello": - System.out.println(42); - } - } -} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInEnhancedSwitchFixTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInEnhancedSwitchFixTest.kt index 17a7d7d3062c..8fa03f85feb0 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInEnhancedSwitchFixTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInEnhancedSwitchFixTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.codeInspection import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase @@ -15,5 +15,5 @@ class DuplicateBranchesInEnhancedSwitchFixTest : LightQuickFixParameterizedTestC override fun getBasePath() = "/inspection/duplicateBranchesInEnhancedSwitchFix" - override fun getProjectDescriptor() = LightJavaCodeInsightFixtureTestCase.JAVA_17 + override fun getProjectDescriptor() = LightJavaCodeInsightFixtureTestCase.JAVA_20 } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInEnhancedSwitchTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInEnhancedSwitchTest.kt index 5c61f5e3891b..ed561e472114 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInEnhancedSwitchTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInEnhancedSwitchTest.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.codeInspection import com.intellij.JavaTestUtil @@ -37,6 +37,9 @@ class DuplicateBranchesInEnhancedSwitchTest : LightJavaCodeInsightFixtureTestCas fun testWhenClause1() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_19_PREVIEW) { doTest() } fun testWhenClause2() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_19_PREVIEW) { doTest() } fun testExpressionsWithComments() = doTest() + fun testNullDuplicatesPattern() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_20_PREVIEW) { doTest() } + fun testPatternDuplicatesNull() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_20_PREVIEW) { doTest() } + fun testNullDuplicatesDefault() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_19_PREVIEW) { doTest() } private fun doTest() { myFixture.enableInspections(DuplicateBranchesInSwitchInspection()) diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchFixTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchFixTest.kt index a9d27db497eb..ec6b05b8257a 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchFixTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchFixTest.kt @@ -1,9 +1,10 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.codeInspection import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase import com.intellij.codeInspection.DuplicateBranchesInSwitchInspection import com.intellij.codeInspection.LocalInspectionTool +import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase.JAVA_20 /** * @author Pavel.Dolgov @@ -13,4 +14,6 @@ class DuplicateBranchesInSwitchFixTest : LightQuickFixParameterizedTestCase() { override fun configureLocalInspectionTools(): Array = arrayOf(DuplicateBranchesInSwitchInspection()) override fun getBasePath() = "/inspection/duplicateBranchesInSwitchFix" + + override fun getProjectDescriptor() = JAVA_20 } \ 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 ac90db79a86b..cc9f316d8041 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DuplicateBranchesInSwitchTest.kt @@ -1,8 +1,10 @@ -// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.codeInspection import com.intellij.JavaTestUtil import com.intellij.codeInspection.DuplicateBranchesInSwitchInspection +import com.intellij.pom.java.LanguageLevel +import com.intellij.testFramework.IdeaTestUtil import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase /** @@ -43,6 +45,8 @@ class DuplicateBranchesInSwitchTest : LightJavaCodeInsightFixtureTestCase() { fun testAssignment() = doTest() fun testNoExceptionWhenFirstLabelIsMissing() = doTest() fun testUnresolvedQualifier() = doTest() + fun testNullDuplicatesPattern() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_20_PREVIEW) { doTest() } + fun testPatternDuplicatesNull() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_20_PREVIEW) { doTest() } private fun doTest() { myFixture.testHighlighting("${getTestName(false)}.java") diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SwitchUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SwitchUtils.java index f7a405df9d11..7ee6237bce4b 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SwitchUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SwitchUtils.java @@ -572,6 +572,35 @@ public final class SwitchUtils { labelElementList.getElements()[0] instanceof PsiDefaultCaseLabelElement; } + /** + * Checks if the label has the following form {@code 'case null'} + * + * @param label label to check + * @return {@code true} if the label has the following form {@code 'case null'}, {@code false} otherwise. + */ + public static boolean isCaseNull(@Nullable PsiSwitchLabelStatementBase label) { + if (label == null) return false; + PsiCaseLabelElementList labelElementList = label.getCaseLabelElementList(); + return labelElementList != null && + labelElementList.getElementCount() == 1 && + labelElementList.getElements()[0] instanceof PsiExpression expr && ExpressionUtils.isNullLiteral(expr); + } + + /** + * Checks if the label has the following form {@code 'case null, default'} + * + * @param label label to check + * @return {@code true} if the label has the following form {@code 'case null, default'}, {@code false} otherwise. + */ + public static boolean isCaseNullDefault(@Nullable PsiSwitchLabelStatementBase label) { + if (label == null) return false; + PsiCaseLabelElementList labelElementList = label.getCaseLabelElementList(); + return labelElementList != null && + labelElementList.getElementCount() == 2 && + labelElementList.getElements()[0] instanceof PsiExpression expr && ExpressionUtils.isNullLiteral(expr) && + labelElementList.getElements()[1] instanceof PsiDefaultCaseLabelElement; + } + /** * Checks if the given switch label statement contains a {@code default} case or a total pattern *