mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
DeleteSwitchLabelFix: delete unreachable switch branch
Fixes IDEA-199692 Quickfix to delete unreachable switch branch reported by "constant conditions & exceptions"
This commit is contained in:
+3
-5
@@ -8,10 +8,7 @@ import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.dataFlow.DataFlowInstructionVisitor.ConstantResult;
|
||||
import com.intellij.codeInspection.dataFlow.NullabilityProblemKind.NullabilityProblem;
|
||||
import com.intellij.codeInspection.dataFlow.fix.RedundantInstanceofFix;
|
||||
import com.intellij.codeInspection.dataFlow.fix.ReplaceWithConstantValueFix;
|
||||
import com.intellij.codeInspection.dataFlow.fix.ReplaceWithObjectsEqualsFix;
|
||||
import com.intellij.codeInspection.dataFlow.fix.SimplifyToAssignmentFix;
|
||||
import com.intellij.codeInspection.dataFlow.fix.*;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.*;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaConstValue;
|
||||
import com.intellij.codeInspection.nullable.NullableStuffInspectionBase;
|
||||
@@ -693,7 +690,8 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool
|
||||
else if (psiAnchor instanceof PsiSwitchLabelStatement) {
|
||||
if (falseSet.contains(instruction)) {
|
||||
holder.registerProblem(psiAnchor,
|
||||
InspectionsBundle.message("dataflow.message.unreachable.switch.label"));
|
||||
InspectionsBundle.message("dataflow.message.unreachable.switch.label"),
|
||||
new DeleteSwitchLabelFix((PsiSwitchLabelStatement)psiAnchor));
|
||||
}
|
||||
}
|
||||
else if (psiAnchor != null && !isFlagCheck(psiAnchor)) {
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
// Copyright 2000-2018 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.
|
||||
package com.intellij.codeInspection.dataFlow.fix;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.ControlFlowUtils;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class DeleteSwitchLabelFix implements LocalQuickFix {
|
||||
private final String myName;
|
||||
private final boolean myBranch;
|
||||
|
||||
public DeleteSwitchLabelFix(PsiSwitchLabelStatement label) {
|
||||
myName = Objects.requireNonNull(label.getCaseValue()).getText();
|
||||
PsiStatement nextStatement = PsiTreeUtil.getNextSiblingOfType(label, PsiStatement.class);
|
||||
if (nextStatement instanceof PsiSwitchLabelStatement) {
|
||||
myBranch = false;
|
||||
}
|
||||
else {
|
||||
PsiStatement prevStatement = PsiTreeUtil.getPrevSiblingOfType(label, PsiStatement.class);
|
||||
myBranch = prevStatement == null || !ControlFlowUtils.statementMayCompleteNormally(prevStatement);
|
||||
}
|
||||
}
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myBranch ?
|
||||
"Remove switch branch '" + myName + "'" :
|
||||
"Remove switch label '" + myName + "'";
|
||||
}
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Remove switch label";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiSwitchLabelStatement label = PsiTreeUtil.getNonStrictParentOfType(descriptor.getStartElement(), PsiSwitchLabelStatement.class);
|
||||
if (label == null) return;
|
||||
if (myBranch) {
|
||||
PsiCodeBlock scope = ObjectUtils.tryCast(label.getParent(), PsiCodeBlock.class);
|
||||
if (scope == null) return;
|
||||
PsiSwitchLabelStatement nextLabel = PsiTreeUtil.getNextSiblingOfType(label, PsiSwitchLabelStatement.class);
|
||||
PsiElement stopAt = nextLabel == null ? scope.getRBrace() : nextLabel;
|
||||
while(true) {
|
||||
PsiStatement next = PsiTreeUtil.getNextSiblingOfType(nextLabel, PsiStatement.class);
|
||||
if (!(next instanceof PsiSwitchLabelStatement)) break;
|
||||
nextLabel = (PsiSwitchLabelStatement)next;
|
||||
}
|
||||
int end = nextLabel == null ? -1 : nextLabel.getTextOffset();
|
||||
List<PsiElement> toDelete = new ArrayList<>();
|
||||
List<PsiDeclarationStatement> declarations = new ArrayList<>();
|
||||
for (PsiElement e = label.getNextSibling(); e != stopAt; e = e.getNextSibling()) {
|
||||
if (e instanceof PsiDeclarationStatement && nextLabel != null) {
|
||||
PsiDeclarationStatement declaration = (PsiDeclarationStatement)e;
|
||||
PsiElement[] elements = declaration.getDeclaredElements();
|
||||
boolean declarationIsReused = Stream.of(elements).anyMatch(
|
||||
element -> !ReferencesSearch.search(element, new LocalSearchScope(scope))
|
||||
.forEach(ref -> ref.getElement().getTextOffset() < end));
|
||||
if (declarationIsReused) {
|
||||
StreamEx.of(elements).select(PsiVariable.class).map(PsiVariable::getInitializer).nonNull().into(toDelete);
|
||||
declarations.add(declaration);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
toDelete.add(e);
|
||||
}
|
||||
CommentTracker ct = new CommentTracker();
|
||||
toDelete.stream().filter(PsiElement::isValid).forEach(ct::delete);
|
||||
for (PsiDeclarationStatement declaration : declarations) {
|
||||
scope.addAfter(declaration, nextLabel);
|
||||
declaration.delete();
|
||||
}
|
||||
ct.insertCommentsBefore(label);
|
||||
}
|
||||
new CommentTracker().deleteAndRestoreComments(label);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Remove switch branch '"baz"'" "true"
|
||||
class Main {
|
||||
public void test() {
|
||||
switch ("foo") {
|
||||
case "qux":
|
||||
case "bar":
|
||||
class Foo {}
|
||||
int i;
|
||||
i = 2;
|
||||
System.out.println("hello"+new Foo()+i);
|
||||
//oops
|
||||
default:
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Remove switch label '"qux"'" "true"
|
||||
class Main {
|
||||
public void test() {
|
||||
switch ("foo") {
|
||||
case "baz":
|
||||
int i = 1;
|
||||
class Foo {}
|
||||
System.out.println(i);
|
||||
break;
|
||||
/*comment*/
|
||||
case "bar":
|
||||
i = 2;
|
||||
System.out.println("hello"+new Foo()+i);
|
||||
//oops
|
||||
default:
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Remove switch label '"bar"'" "true"
|
||||
class Main {
|
||||
public void test() {
|
||||
switch ("foo") {
|
||||
case "baz":
|
||||
int i = 1;
|
||||
class Foo {}
|
||||
System.out.println(i);
|
||||
break;
|
||||
case "qux":
|
||||
// comment
|
||||
i = 2;
|
||||
System.out.println("hello"+new Foo()+i);
|
||||
//oops
|
||||
default:
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Remove switch branch '"bar"'" "true"
|
||||
class Main {
|
||||
public void test() {
|
||||
switch ("foo") {
|
||||
case "baz":
|
||||
System.out.println("foo");
|
||||
break;
|
||||
//oops
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Remove switch branch '"baz"'" "true"
|
||||
class Main {
|
||||
public void test() {
|
||||
switch ("foo") {
|
||||
case "<caret>baz":
|
||||
int i = 1;
|
||||
class Foo {}
|
||||
System.out.println(i);
|
||||
break;
|
||||
case "qux":
|
||||
case "bar":
|
||||
i = 2;
|
||||
System.out.println("hello"+new Foo()+i);
|
||||
//oops
|
||||
default:
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Remove switch label '"qux"'" "true"
|
||||
class Main {
|
||||
public void test() {
|
||||
switch ("foo") {
|
||||
case "baz":
|
||||
int i = 1;
|
||||
class Foo {}
|
||||
System.out.println(i);
|
||||
break;
|
||||
case "<caret>qux" /*comment*/:
|
||||
case "bar":
|
||||
i = 2;
|
||||
System.out.println("hello"+new Foo()+i);
|
||||
//oops
|
||||
default:
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// "Remove switch label '"bar"'" "true"
|
||||
class Main {
|
||||
public void test() {
|
||||
switch ("foo") {
|
||||
case "baz":
|
||||
int i = 1;
|
||||
class Foo {}
|
||||
System.out.println(i);
|
||||
break;
|
||||
case "qux":
|
||||
case "<caret>bar" // comment
|
||||
:
|
||||
i = 2;
|
||||
System.out.println("hello"+new Foo()+i);
|
||||
//oops
|
||||
default:
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// "Remove switch branch '"bar"'" "true"
|
||||
class Main {
|
||||
public void test() {
|
||||
switch ("foo") {
|
||||
case "baz":
|
||||
System.out.println("foo");
|
||||
break;
|
||||
case "<caret>bar":
|
||||
int i = 2;
|
||||
class Foo {}
|
||||
System.out.println("hello"+new Foo()+i);
|
||||
//oops
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// Copyright 2000-2018 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.
|
||||
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.LightCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class DeleteSwitchLabelFixTest extends LightQuickFixParameterizedTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new DataFlowInspection()};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return LightCodeInsightFixtureTestCase.JAVA_8;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/deleteSwitchLabel";
|
||||
}
|
||||
}
|
||||
+1
@@ -65,6 +65,7 @@ import org.junit.runners.Suite;
|
||||
StreamFilterNotNullFixTest.class,
|
||||
RedundantInstanceofFixTest.class,
|
||||
ReplaceComputeWithComputeIfPresentFixTest.class,
|
||||
DeleteSwitchLabelFixTest.class,
|
||||
})
|
||||
public class DataFlowInspectionTestSuite {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user