From 7615667adcc63670b5467a7983c7d8f3af1964e5 Mon Sep 17 00:00:00 2001 From: "Andrey.Cherkasov" Date: Mon, 17 Oct 2022 16:41:29 +0400 Subject: [PATCH] [java-intentions] UnwrapSwitchLabelFix: rewrite record pattern support IJ-CR-27938 IDEA-297387 GitOrigin-RevId: d275fd7a37d6b4e955cdc654bd676cb9048601be --- .../impl/quickfix/UnwrapSwitchLabelFix.java | 304 +++++++++--------- .../afterUnwrapPatternNoConflict4.java | 8 +- .../beforeUnwrapPatternNoConflict4.java | 16 +- .../afterAllVariablesUnused1.java | 10 + .../afterAllVariablesUnused2.java | 10 + .../afterDeepNesting1.java | 14 + .../afterDeepNesting2.java | 16 + .../afterEmptyRecord1.java | 8 + .../afterEmptyRecord2.java | 8 + .../afterEmptyRecord3.java | 8 + .../afterRecordComponentCast.java | 23 ++ .../deleteSwitchLabel19/afterSimple1.java | 9 + .../deleteSwitchLabel19/afterSimple2.java | 10 + .../afterTopLevelVarReassigned1.java | 11 + .../afterTopLevelVarReassigned2.java | 11 + .../afterTopLevelVarUnused1.java | 8 + .../afterTopLevelVarUnused2.java | 10 + .../afterUnwrapDeconstructionPattern.java | 13 - .../afterWithoutTopLevelVar1.java | 8 + .../afterWithoutTopLevelVar2.java | 10 + .../beforeAllVariablesUnused1.java | 16 + .../beforeAllVariablesUnused2.java | 16 + .../beforeDeepNesting1.java | 16 + .../beforeDeepNesting2.java | 20 ++ .../beforeEmptyRecord1.java | 12 + .../beforeEmptyRecord2.java | 12 + .../beforeEmptyRecord3.java | 12 + .../beforeRecordComponentCast.java | 26 ++ .../deleteSwitchLabel19/beforeSimple1.java | 13 + .../deleteSwitchLabel19/beforeSimple2.java | 15 + .../beforeTopLevelVarReassigned1.java | 16 + .../beforeTopLevelVarReassigned2.java | 14 + .../beforeTopLevelVarUnused1.java | 12 + .../beforeTopLevelVarUnused2.java | 15 + .../beforeUnwrapDeconstructionPattern.java | 17 - .../beforeWithoutTopLevelVar1.java | 12 + .../beforeWithoutTopLevelVar2.java | 13 + .../quickFix/DeleteSwitchLabelFix19Test.java | 27 -- 38 files changed, 572 insertions(+), 227 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterAllVariablesUnused1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterAllVariablesUnused2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterDeepNesting1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterDeepNesting2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord3.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterRecordComponentCast.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterSimple1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterSimple2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarReassigned1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarReassigned2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarUnused1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarUnused2.java delete mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterUnwrapDeconstructionPattern.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterWithoutTopLevelVar1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterWithoutTopLevelVar2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeAllVariablesUnused1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeAllVariablesUnused2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeDeepNesting1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeDeepNesting2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord3.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeRecordComponentCast.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeSimple1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeSimple2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarReassigned1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarReassigned2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarUnused1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarUnused2.java delete mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeUnwrapDeconstructionPattern.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeWithoutTopLevelVar1.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeWithoutTopLevelVar2.java delete mode 100644 java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/DeleteSwitchLabelFix19Test.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/UnwrapSwitchLabelFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/UnwrapSwitchLabelFix.java index ff960aa6fc6d..6eb550b821e1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/UnwrapSwitchLabelFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/UnwrapSwitchLabelFix.java @@ -1,4 +1,4 @@ -// 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-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.daemon.impl.quickfix; import com.intellij.codeInsight.BlockUtils; @@ -9,23 +9,21 @@ import com.intellij.codeInspection.dataFlow.fix.DeleteSwitchLabelFix; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.impl.PsiImplUtil; +import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.JavaPsiPatternUtil; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.util.CommonJavaInlineUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.JBIterable; import com.siyeh.ig.psiutils.*; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; +import java.util.*; public class UnwrapSwitchLabelFix implements LocalQuickFix { @Nls(capitalization = Nls.Capitalization.Sentence) @@ -45,8 +43,8 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix { if (block == null) return; List labels = PsiTreeUtil.getChildrenOfTypeAsList(block.getBody(), PsiSwitchLabelStatementBase.class); boolean shouldKeepDefault = block instanceof PsiSwitchExpression && - !(labelStatement instanceof PsiSwitchLabeledRuleStatement && - ((PsiSwitchLabeledRuleStatement)labelStatement).getBody() instanceof PsiExpressionStatement); + !(labelStatement instanceof PsiSwitchLabeledRuleStatement ruleStatement && + ruleStatement.getBody() instanceof PsiExpressionStatement); for (PsiSwitchLabelStatementBase otherLabel : labels) { if (otherLabel == labelStatement) continue; if (!shouldKeepDefault || !SwitchUtils.isDefaultLabel(otherLabel)) { @@ -69,17 +67,18 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix { if (labelElementList != null) { for (PsiCaseLabelElement labelElement : labelElementList.getElements()) { if (labelElement instanceof PsiDefaultCaseLabelElement) continue; - new CommentTracker().deleteAndRestoreComments(labelElement); } + new CommentTracker().deleteAndRestoreComments(labelElement); + } } } private static void tryUnwrap(@NotNull PsiSwitchLabelStatementBase labelStatement, @NotNull PsiCaseLabelElement label, @NotNull PsiSwitchBlock block) { - if (block instanceof PsiSwitchStatement) { + if (block instanceof PsiSwitchStatement switchStatement) { BreakConverter converter = BreakConverter.from(block); if (converter == null) return; converter.process(); - unwrapStatement(labelStatement, label, (PsiSwitchStatement)block); + unwrapStatement(labelStatement, label, switchStatement); } else { unwrapExpression((PsiSwitchExpression)block, label); @@ -89,21 +88,18 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix { private static void unwrapStatement(@NotNull PsiSwitchLabelStatementBase labelStatement, @NotNull PsiCaseLabelElement label, @NotNull PsiSwitchStatement switchStatement) { PsiCodeBlock block = switchStatement.getBody(); - PsiStatement body = - labelStatement instanceof PsiSwitchLabeledRuleStatement ? ((PsiSwitchLabeledRuleStatement)labelStatement).getBody() : null; - List variables = Collections.emptyList(); + PsiStatement body = labelStatement instanceof PsiSwitchLabeledRuleStatement ruleStatement ? ruleStatement.getBody() : null; + List variables; if (body == null) { - if (block != null) { - variables = createVariables(label, switchStatement, block); - } + variables = block != null ? collectVariables(label, switchStatement) : Collections.emptyList(); new CommentTracker().deleteAndRestoreComments(labelStatement); } - else if (body instanceof PsiBlockStatement) { - variables = createVariables(label, switchStatement, body); - block = ((PsiBlockStatement)body).getCodeBlock(); + else if (body instanceof PsiBlockStatement blockStatement) { + variables = collectVariables(label, switchStatement); + block = blockStatement.getCodeBlock(); } else { - variables = createVariables(label, switchStatement, body); + variables = collectVariables(label, switchStatement); new CommentTracker().replaceAndRestoreComments(labelStatement, body); } PsiCodeBlock parent = ObjectUtils.tryCast(switchStatement.getParent(), PsiCodeBlock.class); @@ -114,27 +110,53 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix { ct.insertCommentsBefore(switchStatement); PsiElement firstElementAdded = BlockUtils.inlineCodeBlock(switchStatement, block); if (firstElementAdded != null) { - for (PsiLocalVariable variable : variables) { - addVariable(variable, firstElementAdded, parent); - } + variables.replaceAll(variable -> addVariable(variable, firstElementAdded, parent)); + inline(variables, parent); } } else if (block != null) { + PsiBlockStatement element = (PsiBlockStatement)ct.replaceAndRestoreComments(switchStatement, ct.text(block)); if (!variables.isEmpty()) { - PsiStatement firstStatement = ArrayUtil.getFirstElement(block.getStatements()); + PsiStatement firstStatement = ArrayUtil.getFirstElement(element.getCodeBlock().getStatements()); if (firstStatement != null) { - for (PsiLocalVariable variable : variables) { - block.addBefore(variable, firstStatement); - } + PsiCodeBlock variableParent = element.getCodeBlock(); + variables.replaceAll(variable -> addVariable(variable, firstStatement, variableParent)); + inline(variables, variableParent); } } - ct.replaceAndRestoreComments(switchStatement, ct.text(block)); } else { ct.deleteAndRestoreComments(switchStatement); } } + private static void inline(@NotNull List variables, @NotNull PsiElement variableParent) { + if (variables.isEmpty()) return; + var inlineUtil = CommonJavaInlineUtil.getInstance(); + for (int i = variables.size() - 1; i > 0; i--) { + inline(variables.get(i), inlineUtil); + } + PsiLocalVariable firstVariable = variables.get(0); + if (VariableAccessUtils.isLocalVariableCopy(firstVariable)) { + inline(firstVariable, inlineUtil); + } + else if (!VariableAccessUtils.variableIsUsed(firstVariable, variableParent)) { + firstVariable.delete(); + } + } + + private static void inline(@NotNull PsiLocalVariable variable, @NotNull CommonJavaInlineUtil inlineUtil) { + final PsiExpression initializer = variable.getInitializer(); + assert initializer != null; + final Collection references = ReferencesSearch.search(variable).findAll(); + for (PsiReference reference : references) { + inlineUtil.inlineVariable(variable, initializer, (PsiJavaCodeReferenceElement)reference, null); + } + if (!VariableAccessUtils.variableIsAssigned(variable)) { + variable.delete(); + } + } + /** * Unwraps switch expression if it consists of single expression-branch; does nothing otherwise * @@ -148,12 +170,11 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix { PsiCodeBlock body = switchExpression.getBody(); if (body == null) return; PsiStatement[] statements = body.getStatements(); - if (statements.length != 1 || !(statements[0] instanceof PsiSwitchLabeledRuleStatement)) return; - PsiSwitchLabeledRuleStatement rule = (PsiSwitchLabeledRuleStatement)statements[0]; + if (statements.length != 1 || !(statements[0] instanceof PsiSwitchLabeledRuleStatement rule)) return; PsiStatement ruleBody = rule.getBody(); - if (!(ruleBody instanceof PsiExpressionStatement)) return; + if (!(ruleBody instanceof PsiExpressionStatement expressionStatement)) return; if (label == null) { - new CommentTracker().replaceAndRestoreComments(switchExpression, ((PsiExpressionStatement)ruleBody).getExpression()); + new CommentTracker().replaceAndRestoreComments(switchExpression, expressionStatement.getExpression()); return; } CodeBlockSurrounder surrounder = CodeBlockSurrounder.forExpression(switchExpression); @@ -164,151 +185,112 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix { ruleBody = rule.getBody(); if (ruleBody == null) return; label = Objects.requireNonNull(rule.getCaseLabelElementList()).getElements()[0]; - List variables = createVariables(label, switchExpression, ruleBody); + List variables = collectVariables(label, switchExpression); if (variables.isEmpty()) { new CommentTracker().replaceAndRestoreComments(switchExpression, ((PsiExpressionStatement)ruleBody).getExpression()); surroundResult.collapse(); return; } new CommentTracker().replaceAndRestoreComments(switchExpression, ((PsiExpressionStatement)ruleBody).getExpression()); - for (PsiLocalVariable variable : variables) { - addVariable(variable, surroundResult.getAnchor(), surroundResult.getAnchor().getParent()); - } + variables.replaceAll(variable -> addVariable(variable, surroundResult.getAnchor(), surroundResult.getAnchor().getParent())); + inline(variables, surroundResult.getAnchor().getParent()); } } /** * @param label a switch label element * @param switchBlock a considered switch block - * @param body a body of either switch labeled rule if switchBlock consists of labeled rules, - * or a body of the entire switch statement * @return a list of local variables extracted from a pattern variable if it's possible and necessary. - * If a pattern variable type is not total for selector type, a type cast expression will be created then. */ @NotNull - private static List createVariables(@NotNull PsiCaseLabelElement label, - @NotNull PsiSwitchBlock switchBlock, - @NotNull PsiElement body) { - if (!(label instanceof PsiPattern)) return Collections.emptyList(); + private static List collectVariables(@NotNull PsiCaseLabelElement label, + @NotNull PsiSwitchBlock switchBlock) { + PsiPrimaryPattern pattern = JavaPsiPatternUtil.getTypedPattern(label); + if (pattern == null) return Collections.emptyList(); + PsiType type = JavaPsiPatternUtil.getPatternType(pattern); + if (type == null) return Collections.emptyList(); PsiExpression selector = switchBlock.getExpression(); if (selector == null) return Collections.emptyList(); PsiType selectorType = selector.getType(); if (selectorType == null) return Collections.emptyList(); - String selectorText = selector.getText(); - VariablesCreator variablesCreator; - if (label instanceof PsiDeconstructionPattern) { - variablesCreator = new DeconstructionPatternVariablesCreator((PsiDeconstructionPattern)label, selectorType, selectorText, body); - if (!variablesCreator.myPatterns.hasNext()) return Collections.emptyList(); + PsiPatternVariable topLevelVariable = JavaPsiPatternUtil.getPatternVariable(pattern); + String declarationStatementText = type.getPresentableText() + " "; + if (topLevelVariable != null) { + declarationStatementText += topLevelVariable.getName() + "="; } else { - variablesCreator = new PatternVariablesCreator((PsiPattern)label, selectorType, selectorText, body); + VariableNameGenerator generator = new VariableNameGenerator(switchBlock, VariableKind.LOCAL_VARIABLE); + String newVarName = generator.byType(JavaPsiPatternUtil.getPatternType(label)).generate(true); + declarationStatementText += newVarName + "="; } - return variablesCreator.createVariables(); + if (!JavaPsiPatternUtil.isTotalForType(pattern, selectorType)) { + declarationStatementText += "(" + type.getPresentableText() + ")"; + } + declarationStatementText += selector.getText() + ";"; + PsiLocalVariable newVariable = createVariable(declarationStatementText, label); + if (pattern instanceof PsiDeconstructionPattern deconstructionPattern) { + PsiFile copy = (PsiFile)switchBlock.getContainingFile().copy(); + PsiElement contextCopy = PsiTreeUtil.findSameElementInCopy(switchBlock.getParent(), copy); + contextCopy.add(newVariable); + ArrayList list = new ArrayList<>(); + list.add(newVariable); + return collectVariables(deconstructionPattern, newVariable, contextCopy, list); + } + return new SmartList<>(newVariable); } - abstract static class VariablesCreator { - - private final @NotNull PsiPattern myLabel; - protected final @NotNull String mySelectorText; - protected final @NotNull PsiType mySelectorType; - protected final @NotNull Iterator myPatterns; - private final @NotNull PsiElement myBody; - - protected VariablesCreator(@NotNull PsiPattern label, - @NotNull PsiType selectorType, - @NotNull String selectorText, - @NotNull Iterator patterns, @NotNull PsiElement body) { - myLabel = label; - mySelectorText = selectorText; - mySelectorType = selectorType; - myPatterns = patterns; - myBody = body; - } - - @NotNull - public SmartList createVariables() { - JBIterable bodyTraverser = SyntaxTraverser.psiTraverser(myBody).filter(PsiReferenceExpression.class); - PsiSwitchLabelStatementBase labelStatement = PsiTreeUtil.getParentOfType(myLabel, PsiSwitchLabelStatementBase.class); - if (labelStatement instanceof PsiSwitchLabelStatement) { - bodyTraverser = - bodyTraverser.filter(expr -> PsiTreeUtil.getParentOfType(expr, PsiSwitchLabelStatementBase.class) != labelStatement); - } - SmartList result = new SmartList<>(); - while (myPatterns.hasNext()) { - PsiPatternVariable patternVar = JavaPsiPatternUtil.getPatternVariable(myPatterns.next()); - PsiLocalVariable variable = createVariable(myLabel, bodyTraverser, patternVar); - ContainerUtil.addIfNotNull(result, variable); - } - return result; - } - - @Nullable - private PsiLocalVariable createVariable(@NotNull PsiCaseLabelElement label, - @NotNull JBIterable bodyTraverser, - @Nullable PsiPatternVariable patternVar) { - if (patternVar == null) return null; - if (bodyTraverser.find(expr -> expr.resolve() == patternVar) == null) return null; - String declarationStatementText = Objects.requireNonNull(patternVar.getPattern()).getText() + "=" + getVariableAssigment(patternVar); - return (PsiLocalVariable)((PsiDeclarationStatement)JavaPsiFacade.getInstance(label.getProject()).getParserFacade() - .createStatementFromText(declarationStatementText, label)).getDeclaredElements()[0]; - } - - @NotNull - abstract String getVariableAssigment(PsiPatternVariable patternVar); - } - - static class DeconstructionPatternVariablesCreator extends VariablesCreator { - private final @NotNull Iterator myRecordComponents; - - DeconstructionPatternVariablesCreator(@NotNull PsiDeconstructionPattern pattern, - @NotNull PsiType selectorType, - @NotNull String selectorText, - @NotNull PsiElement body) { - super(pattern, selectorType, selectorText, ContainerUtil.iterate(getDeconstructionComponents(pattern)), body); - PsiClass aClass = ((PsiClassType)selectorType).resolve(); - if (aClass != null) { - PsiRecordComponent[] recordComponents = aClass.getRecordComponents(); - if (getDeconstructionComponents(pattern).length == recordComponents.length) { - myRecordComponents = ContainerUtil.iterate(recordComponents); - return; - } - } - myPatterns.forEachRemaining((ignore) -> {}); - myRecordComponents = Collections.emptyIterator(); - } - - private static @NotNull PsiPattern @NotNull [] getDeconstructionComponents(@NotNull PsiDeconstructionPattern pattern) { - return pattern.getDeconstructionList().getDeconstructionComponents(); - } - - @Override - @NotNull - String getVariableAssigment(PsiPatternVariable ignore) { - return mySelectorText + "." + myRecordComponents.next().getName() + "();"; - } - } - - static class PatternVariablesCreator extends VariablesCreator { - - PatternVariablesCreator(@NotNull PsiPattern pattern, - @NotNull PsiType selectorType, - @NotNull String selectorText, - @NotNull PsiElement body) { - super(pattern, selectorType, selectorText, Collections.singleton(pattern).iterator(), body); - } - - @Override - @NotNull - String getVariableAssigment(PsiPatternVariable patternVar) { - String typeCastIfNeeded; - if (!JavaPsiPatternUtil.isTotalForType(patternVar.getPattern(), mySelectorType)) { - typeCastIfNeeded = "(" + patternVar.getTypeElement().getType().getPresentableText() + ")"; + /** + * @param pattern record pattern for which component variables are extracted + * @param variable variable already extracted for the record pattern under consideration + * @param context record patterns may not have variables, so it is necessary to generate variable names for such patterns. + * To avoid naming conflicts, this context will be used and extracted variables will be added to it + * @param result the list to collect all extracted variables + * @return a list of local variables extracted from a pattern variable if it's possible and necessary + */ + private static List collectVariables(@NotNull PsiDeconstructionPattern pattern, + @NotNull PsiLocalVariable variable, + @NotNull PsiElement context, + @NotNull List result) { + PsiClassType classType = ObjectUtils.tryCast(pattern.getTypeElement().getType(), PsiClassType.class); + if (classType == null) return Collections.emptyList(); + PsiClass aClass = classType.resolve(); + if (aClass == null) return Collections.emptyList(); + PsiRecordComponent[] components = aClass.getRecordComponents(); + PsiPattern[] deconstructionComponents = pattern.getDeconstructionList().getDeconstructionComponents(); + if (components.length != deconstructionComponents.length) return Collections.emptyList(); + for (int i = 0; i < deconstructionComponents.length; i++) { + PsiPattern deconstructionComponent = deconstructionComponents[i]; + PsiPatternVariable patternVariable = JavaPsiPatternUtil.getPatternVariable(deconstructionComponent); + if (patternVariable == null && !(deconstructionComponent instanceof PsiDeconstructionPattern)) return Collections.emptyList(); + PsiType type = JavaPsiPatternUtil.getPatternType(deconstructionComponent); + if (type == null) return Collections.emptyList(); + String declarationStatementText = type.getPresentableText() + " "; + if (patternVariable != null) { + declarationStatementText += patternVariable.getName() + "="; } else { - typeCastIfNeeded = ""; + VariableNameGenerator generator = new VariableNameGenerator(context, VariableKind.LOCAL_VARIABLE); + String newVarName = generator.byType(type).generate(true); + declarationStatementText += newVarName + "="; + } + if (!JavaPsiPatternUtil.isTotalForType(deconstructionComponent, components[i].getType())) { + declarationStatementText += "(" + type.getPresentableText() + ")"; + } + declarationStatementText += variable.getName() + "." + components[i].getName() + "();"; + PsiLocalVariable newVariable = createVariable(declarationStatementText, pattern); + context.add(newVariable); + result.add(newVariable); + if (deconstructionComponent instanceof PsiDeconstructionPattern deconstructionPattern) { + collectVariables(deconstructionPattern, newVariable, context, result); } - return typeCastIfNeeded + mySelectorText + ";"; } + return result; + } + + private static @NotNull PsiLocalVariable createVariable(@NotNull String declarationStatementText, @NotNull PsiElement context) { + PsiJavaParserFacade facade = JavaPsiFacade.getInstance(context.getProject()).getParserFacade(); + PsiDeclarationStatement statement = (PsiDeclarationStatement)facade.createStatementFromText(declarationStatementText, context); + return (PsiLocalVariable)statement.getDeclaredElements()[0]; } /** @@ -319,21 +301,27 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix { * @param variableSibling is used as anchor for variable to be added * @param variableParent parent for both variable and variableSibling. * Mostly used to detect a conflict and to add variable as a child. + * @return the element which was actually added */ - private static void addVariable(@NotNull PsiLocalVariable variable, @NotNull PsiElement variableSibling, @NotNull PsiElement variableParent) { + private static @NotNull PsiLocalVariable addVariable(@NotNull PsiLocalVariable variable, + @NotNull PsiElement variableSibling, + @NotNull PsiElement variableParent) { boolean hasConflictingDeclaration = hasConflictingDeclaration(variable, variableParent); PsiStatement declaration = JavaPsiFacade.getInstance(variableSibling.getProject()).getParserFacade() .createStatementFromText(variable.getText(), variableSibling); variable = (PsiLocalVariable)((PsiDeclarationStatement)variableParent.addBefore(declaration, variableSibling)).getDeclaredElements()[0]; - if (!hasConflictingDeclaration) return; - String newVarName = JavaCodeStyleManager.getInstance(variableParent.getProject()) - .suggestUniqueVariableName(variable.getName(), variableParent, true); - for (PsiReference ref : VariableAccessUtils.getVariableReferences(variable, variableParent)) { - ref.handleElementRename(newVarName); + if (hasConflictingDeclaration) { + String newVarName = JavaCodeStyleManager.getInstance(variableParent.getProject()) + .suggestUniqueVariableName(variable.getName(), variableParent, true); + for (PsiReference ref : VariableAccessUtils.getVariableReferences(variable, variableParent)) { + ref.handleElementRename(newVarName); + } + variable.setName(newVarName); } - variable.setName(newVarName); + return variable; } + private static boolean hasConflictingDeclaration(@NotNull PsiLocalVariable variable, @NotNull PsiElement context) { return !JavaCodeStyleManager.getInstance(context.getProject()).suggestUniqueVariableName(variable.getName(), context, true) .equals(variable.getName()); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel/afterUnwrapPatternNoConflict4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel/afterUnwrapPatternNoConflict4.java index 32b54edf3b65..e86ebe6c3627 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel/afterUnwrapPatternNoConflict4.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel/afterUnwrapPatternNoConflict4.java @@ -1,8 +1,8 @@ // "Remove unreachable branches" "true-preview" class Test { - final String s = "abc"; + final String s = "abc"; - int test() { - return 1; - } + int test() { + return 1; + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel/beforeUnwrapPatternNoConflict4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel/beforeUnwrapPatternNoConflict4.java index e1e062b67845..241cc136aa5c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel/beforeUnwrapPatternNoConflict4.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel/beforeUnwrapPatternNoConflict4.java @@ -1,12 +1,12 @@ // "Remove unreachable branches" "true-preview" class Test { - final String s = "abc"; + final String s = "abc"; - int test() { - return switch (s) { - case String ss && ss.length() <= 3 -> 1; - case "fsd" -> 2; - case default -> 3; - }; - } + int test() { + return switch (s) { + case String ss && ss.length() <= 3 -> 1; + case "fsd" -> 2; + case default -> 3; + }; + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterAllVariablesUnused1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterAllVariablesUnused1.java new file mode 100644 index 000000000000..f926d4258912 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterAllVariablesUnused1.java @@ -0,0 +1,10 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof Rect)) return; + System.out.println(42); + } + + record Point(double x, double y) {} + record Rect(Point point1, Point point2) {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterAllVariablesUnused2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterAllVariablesUnused2.java new file mode 100644 index 000000000000..f926d4258912 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterAllVariablesUnused2.java @@ -0,0 +1,10 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof Rect)) return; + System.out.println(42); + } + + record Point(double x, double y) {} + record Rect(Point point1, Point point2) {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterDeepNesting1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterDeepNesting1.java new file mode 100644 index 000000000000..4854a220fd78 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterDeepNesting1.java @@ -0,0 +1,14 @@ +// "Remove unreachable branches" "true" +class Test { + void foo(Object obj) { + switch (obj) { + case X x -> { } + default -> { return; } + } + + X x1 = (X) obj; + System.out.println(x1.x().x().x().x()); + } +} + +record X(X x) { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterDeepNesting2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterDeepNesting2.java new file mode 100644 index 000000000000..43e010cc8782 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterDeepNesting2.java @@ -0,0 +1,16 @@ +// "Remove unreachable branches" "true" +class Test { + void foo(Object obj) { + switch (obj) { + case X x -> { } + default -> { return; } + } + + X x1 = (X) obj; + System.out.println(x1); + System.out.println(x1.x().x()); + System.out.println(x1.x().x().x().x()); + } +} + +record X(X x) { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord1.java new file mode 100644 index 000000000000..9f1815e90b8c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord1.java @@ -0,0 +1,8 @@ +// "Remove unreachable branches" "true" +class Test { + void test(EmptyBox box) { + System.out.println("Fill it up and send it back"); + } + + record EmptyBox() {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord2.java new file mode 100644 index 000000000000..232f99ed3d75 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord2.java @@ -0,0 +1,8 @@ +// "Remove unreachable branches" "true" +class Test { + void test(EmptyBox box) { + System.out.println(box); + } + + record EmptyBox() {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord3.java new file mode 100644 index 000000000000..9f1815e90b8c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterEmptyRecord3.java @@ -0,0 +1,8 @@ +// "Remove unreachable branches" "true" +class Test { + void test(EmptyBox box) { + System.out.println("Fill it up and send it back"); + } + + record EmptyBox() {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterRecordComponentCast.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterRecordComponentCast.java new file mode 100644 index 000000000000..c93cf3bba851 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterRecordComponentCast.java @@ -0,0 +1,23 @@ +// "Remove unreachable branches" "true" +class Test { + void foo(Rec rec) { + switch (rec) { + case Rec(A a) -> a.doA(); + default -> { return; } + } + + ((A) ((Rec) rec).i()).doA(); + } +} + +record Rec(I i) {} + +interface I {} + +class A implements I { + void doA() {} +} + +class B implements I { + void doB() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterSimple1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterSimple1.java new file mode 100644 index 000000000000..788304b2cc57 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterSimple1.java @@ -0,0 +1,9 @@ +// "Remove unreachable branches" "true" +class Test { + void test(R r) { + System.out.println(r.s() + r.i()); + System.out.println(r); + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterSimple2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterSimple2.java new file mode 100644 index 000000000000..fe36e77210f3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterSimple2.java @@ -0,0 +1,10 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof R)) return; + R rec = (R) obj; + System.out.println(rec.s() + rec.i()); + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarReassigned1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarReassigned1.java new file mode 100644 index 000000000000..8d9389b65ba8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarReassigned1.java @@ -0,0 +1,11 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof R)) return; + R rec = (R) obj; + rec = new R(42, "hello"); + System.out.println(rec.s() + rec.i()); + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarReassigned2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarReassigned2.java new file mode 100644 index 000000000000..60e0d77c2296 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarReassigned2.java @@ -0,0 +1,11 @@ +// "Remove unreachable branches" "true" +class Test { + void test(R r) { + R rec = r; + rec = new R(42, "hello"); + System.out.println(rec.s() + rec.i()); + System.out.println(rec); + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarUnused1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarUnused1.java new file mode 100644 index 000000000000..e49f3a423226 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarUnused1.java @@ -0,0 +1,8 @@ +// "Remove unreachable branches" "true" +class Test { + void test(R r) { + System.out.println(r.s() + r.i()); + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarUnused2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarUnused2.java new file mode 100644 index 000000000000..fe36e77210f3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterTopLevelVarUnused2.java @@ -0,0 +1,10 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof R)) return; + R rec = (R) obj; + System.out.println(rec.s() + rec.i()); + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterUnwrapDeconstructionPattern.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterUnwrapDeconstructionPattern.java deleted file mode 100644 index f6d91679257c..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterUnwrapDeconstructionPattern.java +++ /dev/null @@ -1,13 +0,0 @@ -// "Remove unreachable branches" "true" -class Test { - void test(R r) { - int i = r.i(); - String str = r.s(); - System.out.println(i); - i = 42; - System.out.println(str + i); - } - - record R(int i, String s, double ignored) { - } -} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterWithoutTopLevelVar1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterWithoutTopLevelVar1.java new file mode 100644 index 000000000000..f3f3994f9aab --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterWithoutTopLevelVar1.java @@ -0,0 +1,8 @@ +// "Remove unreachable branches" "true" +class Test { + void test(R r) { + System.out.println(r.s()); + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterWithoutTopLevelVar2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterWithoutTopLevelVar2.java new file mode 100644 index 000000000000..e0547b2be093 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/afterWithoutTopLevelVar2.java @@ -0,0 +1,10 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof R)) return; + R r = (R) obj; + System.out.println(r.i() + r.s()); + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeAllVariablesUnused1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeAllVariablesUnused1.java new file mode 100644 index 000000000000..2b94c66b759c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeAllVariablesUnused1.java @@ -0,0 +1,16 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof Rect)) return; + switch (obj) { + case Rect(Point(double x1, double y1), Point(double x2, double y2)) rec: + System.out.println(42); + break; + default: + break; + } + } + + record Point(double x, double y) {} + record Rect(Point point1, Point point2) {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeAllVariablesUnused2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeAllVariablesUnused2.java new file mode 100644 index 000000000000..12d90bdaffd7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeAllVariablesUnused2.java @@ -0,0 +1,16 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof Rect)) return; + switch (obj) { + case Rect(Point(double x1, double y1) point1, Point(double x2, double y2)): + System.out.println(42); + break; + default: + break; + } + } + + record Point(double x, double y) {} + record Rect(Point point1, Point point2) {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeDeepNesting1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeDeepNesting1.java new file mode 100644 index 000000000000..ea6b49be6014 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeDeepNesting1.java @@ -0,0 +1,16 @@ +// "Remove unreachable branches" "true" +class Test { + void foo(Object obj) { + switch (obj) { + case X x -> { } + default -> { return; } + } + + switch (obj) { + case X(X(X(X(X x)))) -> System.out.println(x); + default -> { } + } + } +} + +record X(X x) { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeDeepNesting2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeDeepNesting2.java new file mode 100644 index 000000000000..f60ed29828da --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeDeepNesting2.java @@ -0,0 +1,20 @@ +// "Remove unreachable branches" "true" +class Test { + void foo(Object obj) { + switch (obj) { + case X x -> { } + default -> { return; } + } + + switch (obj) { + case X(X(X(X(X x5)) x3)) x1 -> { + System.out.println(x1); + System.out.println(x3); + System.out.println(x5); + } + default -> { } + } + } +} + +record X(X x) { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord1.java new file mode 100644 index 000000000000..c753f480a65f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord1.java @@ -0,0 +1,12 @@ +// "Remove unreachable branches" "true" +class Test { + void test(EmptyBox box) { + switch (box) { + case EmptyBox() when true -> { + System.out.println("Fill it up and send it back"); + } + } + } + + record EmptyBox() {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord2.java new file mode 100644 index 000000000000..a00ada3911b7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord2.java @@ -0,0 +1,12 @@ +// "Remove unreachable branches" "true" +class Test { + void test(EmptyBox box) { + switch (box) { + case EmptyBox() emptyBox when true -> { + System.out.println(emptyBox); + } + } + } + + record EmptyBox() {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord3.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord3.java new file mode 100644 index 000000000000..7316d5eebb9d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeEmptyRecord3.java @@ -0,0 +1,12 @@ +// "Remove unreachable branches" "true" +class Test { + void test(EmptyBox box) { + switch (box) { + case EmptyBox() emptyBox when true -> { + System.out.println("Fill it up and send it back"); + } + } + } + + record EmptyBox() {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeRecordComponentCast.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeRecordComponentCast.java new file mode 100644 index 000000000000..2b378e5939de --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeRecordComponentCast.java @@ -0,0 +1,26 @@ +// "Remove unreachable branches" "true" +class Test { + void foo(Rec rec) { + switch (rec) { + case Rec(A a) -> a.doA(); + default -> { return; } + } + + switch (rec) { + case Rec(A a) when true -> a.doA(); + default -> {} + } + } +} + +record Rec(I i) {} + +interface I {} + +class A implements I { + void doA() {} +} + +class B implements I { + void doB() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeSimple1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeSimple1.java new file mode 100644 index 000000000000..ece84ae8b6e4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeSimple1.java @@ -0,0 +1,13 @@ +// "Remove unreachable branches" "true" +class Test { + void test(R r) { + switch (r) { + case R(int i, String s) rec when true: + System.out.println(s + i); + System.out.println(rec); + break; + } + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeSimple2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeSimple2.java new file mode 100644 index 000000000000..ca285933470b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeSimple2.java @@ -0,0 +1,15 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof R)) return; + switch (obj) { + case R(int i, String s) rec when true: + System.out.println(s + i); + break; + default: + break; + } + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarReassigned1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarReassigned1.java new file mode 100644 index 000000000000..fd212bcfea5e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarReassigned1.java @@ -0,0 +1,16 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof R)) return; + switch (obj) { + case R(int i, String s) rec when true: + rec = new R(42, "hello"); + System.out.println(s + i); + break; + default: + break; + } + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarReassigned2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarReassigned2.java new file mode 100644 index 000000000000..8cd741657557 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarReassigned2.java @@ -0,0 +1,14 @@ +// "Remove unreachable branches" "true" +class Test { + void test(R r) { + switch (r) { + case R(int i, String s) rec when true: + rec = new R(42, "hello"); + System.out.println(s + i); + System.out.println(rec); + break; + } + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarUnused1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarUnused1.java new file mode 100644 index 000000000000..eb61dddf2afc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarUnused1.java @@ -0,0 +1,12 @@ +// "Remove unreachable branches" "true" +class Test { + void test(R r) { + switch (r) { + case R(int i, String s) rec when true: + System.out.println(s + i); + break; + } + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarUnused2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarUnused2.java new file mode 100644 index 000000000000..ca285933470b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeTopLevelVarUnused2.java @@ -0,0 +1,15 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof R)) return; + switch (obj) { + case R(int i, String s) rec when true: + System.out.println(s + i); + break; + default: + break; + } + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeUnwrapDeconstructionPattern.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeUnwrapDeconstructionPattern.java deleted file mode 100644 index f5f7724c2a7c..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeUnwrapDeconstructionPattern.java +++ /dev/null @@ -1,17 +0,0 @@ -// "Remove unreachable branches" "true" -class Test { - void test(R r) { - switch (r) { - case R(int i, String str, double ignored) -> { - System.out.println(i); - i = 42; - System.out.println(str + i); - } - case R ignored when false -> { - } - } - } - - record R(int i, String s, double ignored) { - } -} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeWithoutTopLevelVar1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeWithoutTopLevelVar1.java new file mode 100644 index 000000000000..c773e2463e07 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeWithoutTopLevelVar1.java @@ -0,0 +1,12 @@ +// "Remove unreachable branches" "true" +class Test { + void test(R r) { + switch (r) { + case R(int i, String s) when true: + System.out.println(s); + break; + } + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeWithoutTopLevelVar2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeWithoutTopLevelVar2.java new file mode 100644 index 000000000000..564a4cd09bc9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19/beforeWithoutTopLevelVar2.java @@ -0,0 +1,13 @@ +// "Remove unreachable branches" "true" +class Test { + void test(Object obj) { + if (!(obj instanceof R)) return; + switch (obj) { + case R(int i, String s) when true: + System.out.println(i + s); + break; + } + } + + record R(int i, String s) {} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/DeleteSwitchLabelFix19Test.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/DeleteSwitchLabelFix19Test.java deleted file mode 100644 index 8de35ceb0438..000000000000 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/DeleteSwitchLabelFix19Test.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.intellij.java.codeInsight.daemon.quickFix; - -import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase; -import com.intellij.codeInspection.LocalInspectionTool; -import com.intellij.codeInspection.dataFlow.DataFlowInspection; -import com.intellij.testFramework.LightProjectDescriptor; -import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; -import org.jetbrains.annotations.NotNull; - -public class DeleteSwitchLabelFix19Test extends LightQuickFixParameterizedTestCase { - @Override - protected LocalInspectionTool @NotNull [] configureLocalInspectionTools() { - return new LocalInspectionTool[]{new DataFlowInspection()}; - } - - @NotNull - @Override - protected LightProjectDescriptor getProjectDescriptor() { - return LightJavaCodeInsightFixtureTestCase.JAVA_19; - } - - @Override - protected String getBasePath() { - return "/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel19"; - } -}