mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-intentions] UnwrapSwitchLabelFix: rewrite record pattern support
IJ-CR-27938 IDEA-297387 GitOrigin-RevId: d275fd7a37d6b4e955cdc654bd676cb9048601be
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f29fd2e1f4
commit
7615667adc
+146
-158
@@ -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<PsiSwitchLabelStatementBase> 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<PsiLocalVariable> variables = Collections.emptyList();
|
||||
PsiStatement body = labelStatement instanceof PsiSwitchLabeledRuleStatement ruleStatement ? ruleStatement.getBody() : null;
|
||||
List<PsiLocalVariable> 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<PsiLocalVariable> 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<PsiReference> 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<PsiLocalVariable> variables = createVariables(label, switchExpression, ruleBody);
|
||||
List<PsiLocalVariable> 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 <code>switchBlock</code> 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<PsiLocalVariable> createVariables(@NotNull PsiCaseLabelElement label,
|
||||
@NotNull PsiSwitchBlock switchBlock,
|
||||
@NotNull PsiElement body) {
|
||||
if (!(label instanceof PsiPattern)) return Collections.emptyList();
|
||||
private static List<PsiLocalVariable> 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<PsiLocalVariable> 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<PsiPattern> myPatterns;
|
||||
private final @NotNull PsiElement myBody;
|
||||
|
||||
protected VariablesCreator(@NotNull PsiPattern label,
|
||||
@NotNull PsiType selectorType,
|
||||
@NotNull String selectorText,
|
||||
@NotNull Iterator<PsiPattern> patterns, @NotNull PsiElement body) {
|
||||
myLabel = label;
|
||||
mySelectorText = selectorText;
|
||||
mySelectorType = selectorType;
|
||||
myPatterns = patterns;
|
||||
myBody = body;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SmartList<PsiLocalVariable> createVariables() {
|
||||
JBIterable<PsiReferenceExpression> 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<PsiLocalVariable> 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<PsiReferenceExpression> 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<PsiRecordComponent> 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<PsiLocalVariable> collectVariables(@NotNull PsiDeconstructionPattern pattern,
|
||||
@NotNull PsiLocalVariable variable,
|
||||
@NotNull PsiElement context,
|
||||
@NotNull List<PsiLocalVariable> 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 <code>variable</code> to be added
|
||||
* @param variableParent parent for both <code>variable</code> and <code>variableSibling</code>.
|
||||
* Mostly used to detect a conflict and to add <code>variable</code> 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());
|
||||
|
||||
+4
-4
@@ -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;
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -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 <caret>String ss && ss.length() <= 3 -> 1;
|
||||
case "fsd" -> 2;
|
||||
case default -> 3;
|
||||
};
|
||||
}
|
||||
int test() {
|
||||
return switch (s) {
|
||||
case <caret>String ss && ss.length() <= 3 -> 1;
|
||||
case "fsd" -> 2;
|
||||
case default -> 3;
|
||||
};
|
||||
}
|
||||
}
|
||||
+10
@@ -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) {}
|
||||
}
|
||||
+10
@@ -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) {}
|
||||
}
|
||||
+14
@@ -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) { }
|
||||
+16
@@ -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) { }
|
||||
+8
@@ -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() {}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Remove unreachable branches" "true"
|
||||
class Test {
|
||||
void test(EmptyBox box) {
|
||||
System.out.println(box);
|
||||
}
|
||||
|
||||
record EmptyBox() {}
|
||||
}
|
||||
+8
@@ -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() {}
|
||||
}
|
||||
+23
@@ -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() {}
|
||||
}
|
||||
+9
@@ -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) {}
|
||||
}
|
||||
+10
@@ -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) {}
|
||||
}
|
||||
+11
@@ -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) {}
|
||||
}
|
||||
+11
@@ -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) {}
|
||||
}
|
||||
+8
@@ -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) {}
|
||||
}
|
||||
+10
@@ -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) {}
|
||||
}
|
||||
-13
@@ -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) {
|
||||
}
|
||||
}
|
||||
+8
@@ -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) {}
|
||||
}
|
||||
+10
@@ -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) {}
|
||||
}
|
||||
+16
@@ -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<caret>:
|
||||
System.out.println(42);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
record Point(double x, double y) {}
|
||||
record Rect(Point point1, Point point2) {}
|
||||
}
|
||||
+16
@@ -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))<caret>:
|
||||
System.out.println(42);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
record Point(double x, double y) {}
|
||||
record Rect(Point point1, Point point2) {}
|
||||
}
|
||||
+16
@@ -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)<caret>))) -> System.out.println(x);
|
||||
default -> { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record X(X x) { }
|
||||
+20
@@ -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<caret>(X(X(X(X x5)) x3)) x1 -> {
|
||||
System.out.println(x1);
|
||||
System.out.println(x3);
|
||||
System.out.println(x5);
|
||||
}
|
||||
default -> { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record X(X x) { }
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Remove unreachable branches" "true"
|
||||
class Test {
|
||||
void test(EmptyBox box) {
|
||||
switch (box) {
|
||||
case Empty<caret>Box() when true -> {
|
||||
System.out.println("Fill it up and send it back");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record EmptyBox() {}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Remove unreachable branches" "true"
|
||||
class Test {
|
||||
void test(EmptyBox box) {
|
||||
switch (box) {
|
||||
case Empt<caret>yBox() emptyBox when true -> {
|
||||
System.out.println(emptyBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record EmptyBox() {}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Remove unreachable branches" "true"
|
||||
class Test {
|
||||
void test(EmptyBox box) {
|
||||
switch (box) {
|
||||
case Empty<caret>Box() emptyBox when true -> {
|
||||
System.out.println("Fill it up and send it back");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record EmptyBox() {}
|
||||
}
|
||||
+26
@@ -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 R<caret>ec(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() {}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Remove unreachable branches" "true"
|
||||
class Test {
|
||||
void test(R r) {
|
||||
switch (r) {
|
||||
case R(int i, String s)<caret> rec when true:
|
||||
System.out.println(s + i);
|
||||
System.out.println(rec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
record R(int i, String s) {}
|
||||
}
|
||||
+15
@@ -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)<caret> rec when true:
|
||||
System.out.println(s + i);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
record R(int i, String s) {}
|
||||
}
|
||||
+16
@@ -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)<caret> rec when true:
|
||||
rec = new R(42, "hello");
|
||||
System.out.println(s + i);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
record R(int i, String s) {}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Remove unreachable branches" "true"
|
||||
class Test {
|
||||
void test(R r) {
|
||||
switch (r) {
|
||||
case R(int i, String s)<caret> rec when true:
|
||||
rec = new R(42, "hello");
|
||||
System.out.println(s + i);
|
||||
System.out.println(rec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
record R(int i, String s) {}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Remove unreachable branches" "true"
|
||||
class Test {
|
||||
void test(R r) {
|
||||
switch (r) {
|
||||
case R(int i, String s)<caret> rec when true:
|
||||
System.out.println(s + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
record R(int i, String s) {}
|
||||
}
|
||||
+15
@@ -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)<caret> rec when true:
|
||||
System.out.println(s + i);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
record R(int i, String s) {}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
// "Remove unreachable branches" "true"
|
||||
class Test {
|
||||
void test(R r) {
|
||||
switch (r) {
|
||||
case R(int i, String str, double ignored)<caret> -> {
|
||||
System.out.println(i);
|
||||
i = 42;
|
||||
System.out.println(str + i);
|
||||
}
|
||||
case R ignored when false -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record R(int i, String s, double ignored) {
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Remove unreachable branches" "true"
|
||||
class Test {
|
||||
void test(R r) {
|
||||
switch (r) {
|
||||
case R(int i, String s)<caret> when true:
|
||||
System.out.println(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
record R(int i, String s) {}
|
||||
}
|
||||
+13
@@ -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)<caret> when true:
|
||||
System.out.println(i + s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
record R(int i, String s) {}
|
||||
}
|
||||
-27
@@ -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";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user