[java-highlighting] IDEA-202570 Unreachable statement inspection should highlight whole switch expression

Also, fixed unreachable statement highlighting in different cases

GitOrigin-RevId: 20b28272b51c77e3413e1ca143222d35199728bd
This commit is contained in:
Tagir Valeev
2021-12-07 18:19:30 +07:00
committed by intellij-monorepo-bot
parent ae33969db0
commit 325edf9af2
10 changed files with 172 additions and 27 deletions

View File

@@ -91,7 +91,14 @@ public final class HighlightControlFlowUtil {
PsiElement keyword = null;
if (unreachableStatement instanceof PsiIfStatement ||
unreachableStatement instanceof PsiSwitchBlock ||
unreachableStatement instanceof PsiLoopStatement) {
unreachableStatement instanceof PsiLoopStatement ||
unreachableStatement instanceof PsiThrowStatement ||
unreachableStatement instanceof PsiReturnStatement ||
unreachableStatement instanceof PsiYieldStatement ||
unreachableStatement instanceof PsiTryStatement ||
unreachableStatement instanceof PsiSynchronizedStatement ||
unreachableStatement instanceof PsiAssertStatement ||
unreachableStatement instanceof PsiLabeledStatement) {
keyword = unreachableStatement.getFirstChild();
}
final PsiElement element = keyword != null ? keyword : unreachableStatement;

View File

@@ -1152,7 +1152,9 @@ public final class ControlFlowUtil {
PsiElement element = myFlow.getElement(i);
final PsiElement unreachableParent = getUnreachableExpressionParent(element);
if (unreachableParent != null) return unreachableParent;
if (unreachableParent != null) {
return correctUnreachableStatement(unreachableParent);
}
if (element == null || !PsiUtil.isStatement(element)) continue;
if (element.getParent() instanceof PsiExpression) continue;
@@ -1179,6 +1181,25 @@ public final class ControlFlowUtil {
return null;
}
private static PsiElement correctUnreachableStatement(PsiElement statement) {
if (!(statement instanceof PsiStatement)) return statement;
while (true) {
PsiElement parent = statement.getParent();
if (parent instanceof PsiDoWhileStatement || parent instanceof PsiLabeledStatement) {
statement = parent;
continue;
}
if (parent instanceof PsiCodeBlock && PsiTreeUtil.getPrevSiblingOfType(statement, PsiStatement.class) == null) {
PsiElement grandParent = parent.getParent();
if (grandParent instanceof PsiBlockStatement) {
statement = grandParent;
continue;
}
}
return statement;
}
}
@Nullable
private static PsiElement getUnreachableExpressionParent(@Nullable PsiElement element) {
if (element instanceof PsiExpression) {
@@ -1186,12 +1207,32 @@ public final class ControlFlowUtil {
while (expression != null) {
final PsiElement parent = expression.getParent();
if (parent instanceof PsiExpressionStatement) {
return getUnreachableStatementParent(parent);
final PsiElement grandParent = parent.getParent();
if (grandParent instanceof PsiForStatement) {
if (((PsiForStatement)grandParent).getInitialization() == parent) {
return grandParent;
}
return null;
}
return parent;
}
if (parent instanceof PsiLocalVariable && ((PsiLocalVariable)parent).getInitializer() == expression) {
PsiElement grandParent = parent.getParent();
if (grandParent instanceof PsiDeclarationStatement) return grandParent;
if (grandParent instanceof PsiResourceList && grandParent.getParent() instanceof PsiTryStatement) {
return grandParent.getParent();
}
return null;
}
if (parent instanceof PsiIfStatement && ((PsiIfStatement)parent).getCondition() == expression ||
parent instanceof PsiSwitchBlock && ((PsiSwitchBlock)parent).getExpression() == expression ||
parent instanceof PsiWhileStatement && ((PsiWhileStatement)parent).getCondition() == expression ||
parent instanceof PsiForeachStatement && ((PsiForeachStatement)parent).getIteratedValue() == expression) {
parent instanceof PsiForeachStatement && ((PsiForeachStatement)parent).getIteratedValue() == expression ||
parent instanceof PsiReturnStatement && ((PsiReturnStatement)parent).getReturnValue() == expression ||
parent instanceof PsiYieldStatement && ((PsiYieldStatement)parent).getExpression() == expression ||
parent instanceof PsiThrowStatement && ((PsiThrowStatement)parent).getException() == expression ||
parent instanceof PsiSynchronizedStatement && ((PsiSynchronizedStatement)parent).getLockExpression() == expression ||
parent instanceof PsiAssertStatement && ((PsiAssertStatement)parent).getAssertCondition() == expression) {
return parent;
}
if (parent instanceof PsiExpression) {

View File

@@ -137,8 +137,42 @@ class WithCondition {
while (b);
}
void testDoWhile3(boolean b) {
return;
<error descr="Unreachable statement">do</error> {
if(b) {
System.out.println("x");
}
} while(true);
}
void testDoWhile4() {
return;
<error descr="Unreachable statement">do</error> do do do {
System.out.println("pchela letela");
} while(true); while(true); while(true); while(true);
}
void testIfLabeled(boolean b) {
return;
<error descr="Unreachable statement">LABEL</error>:
if (b == true) {
break LABEL;
}
}
void testDoIfLabeled(boolean b) {
return;
<error descr="Unreachable statement">do</error> {
LABEL:
if (b == true) {
break LABEL;
}
} while(true);
}
int testReturn() {
return 1;
<error descr="Unreachable statement">return 2;</error>
<error descr="Unreachable statement">return</error> 2;
}
}

View File

@@ -16,16 +16,16 @@ interface ii {}
int f1() throws Exception {
return 2;
<error descr="Unreachable statement">return 5;</error>
<error descr="Unreachable statement">return</error> 5;
}
int f2(int i) throws Exception {
if (i==2) return 2;
throw new Exception();
<error descr="Unreachable statement">return 5;</error>
<error descr="Unreachable statement">return</error> 5;
}
int f3(int i) throws Exception {
for (;;) return 2;
<error descr="Unreachable statement">return 5;</error>
<error descr="Unreachable statement">return</error> 5;
}
int f4(int i) throws Exception {
try {
@@ -34,7 +34,7 @@ interface ii {}
} finally {
if (i==6) return 9;
}
<error descr="Unreachable statement">return 5;</error>
<error descr="Unreachable statement">return</error> 5;
}
void f5()
@@ -75,7 +75,7 @@ interface ii {}
for (;;) {
if (e==null) {
return;
<error descr="Unreachable statement">throw e;</error>
<error descr="Unreachable statement">throw</error> e;
}
}
}
@@ -94,7 +94,7 @@ interface ii {}
void test() {
int i;
return;
<error descr="Unreachable statement">assert i == i;</error>
<error descr="Unreachable statement">assert</error> i == i;
}
}

View File

@@ -10,15 +10,15 @@ class Bar {
}
void m() {
while (T == "a") {
<error descr="Unreachable statement">f();</error>
}
while (T == "a") <error descr="Unreachable statement">{
f();
}</error>
}
void m01() {
while (T != "") {
<error descr="Unreachable statement">f();</error>
}
while (T != "") <error descr="Unreachable statement">{
f();
}</error>
}
void m1() {
@@ -29,9 +29,9 @@ class Bar {
}
void m2() {
while (T != T) {
<error descr="Unreachable statement">f();</error>
}
while (T != T) <error descr="Unreachable statement">{
f();
}</error>
}
void m3() {

View File

@@ -0,0 +1,62 @@
public class DeadCode {
private static String m1(int n) {
return "";
<error descr="Unreachable statement">return</error> switch (1) {
default -> "x";
};
}
private static String m2(int n) {
return "";
<error descr="Unreachable statement">int x = switch (1) {
default -> 0;
};</error>
}
private static String m3(int n) {
int x;
return "";
<error descr="Unreachable statement">x = switch (1) {
default -> 0;
};</error>
}
private static String m4(int n) {
return "";
<error descr="Unreachable statement">throw</error> switch (1) {
default -> new RuntimeException();
};
}
private static String m5(int n) {
return "";
<error descr="Unreachable statement">try</error> (AutoCloseable x = switch(1) {default -> () -> {};}) {} catch (Exception e) {
e.printStackTrace();
}
}
private static String m6(int n) {
return "";
<error descr="Unreachable statement">synchronized</error> (switch(1) {default -> "";}) {
System.out.println("");
}
}
private static String m7(int n) {
return "";
<error descr="Unreachable statement">if</error>(switch (1) {default -> true;}) {}
}
private static String m8(int n) {
return switch (n) {
default:
yield "x";
<error descr="Unreachable statement">yield</error> switch(1) { default -> ""; };
};
}
private static String m9() {
return "";
<error descr="Unreachable statement">assert</error> switch(1) {default -> true;};
}
}

View File

@@ -47,7 +47,7 @@ class C {
void endlessLoopInBranchWithValueBreak(String arg) {
int result = switch (arg) {
case "one" -> { while(true); <error descr="Unreachable statement">yield 1;</error>}
case "one" -> { while(true); <error descr="Unreachable statement">yield</error> 1;}
default -> 0;
};
System.out.println(result);

View File

@@ -1,8 +1,8 @@
class Test {
public static void test() {
for(int a = 1; <warning descr="Condition is always false">fal<caret>se</warning>; System.out.println("Just anything here: will not be executed anyways")) {
<error descr="Unreachable statement">System.out.println("Hello");</error>
}
for(int a = 1; <warning descr="Condition is always false">fal<caret>se</warning>; System.out.println("Just anything here: will not be executed anyways")) <error descr="Unreachable statement">{
System.out.println("Hello");
}</error>
}
}

View File

@@ -1,8 +1,8 @@
class Test {
public static void test() {
while ((<warning descr="Condition is always false">fa<caret>lse</warning>)) {
<error descr="Unreachable statement">System.out.println();</error>
}
while ((<warning descr="Condition is always false">fa<caret>lse</warning>)) <error descr="Unreachable statement">{
System.out.println();
}</error>
}
}

View File

@@ -20,6 +20,7 @@ class JavaSwitchExpressionsHighlightingTest : LightJavaCodeInsightFixtureTestCas
fun testSwitchExpressionHasResult() = doTest()
fun testYieldStatements() = doTest()
fun testAssignToFinalInSwitchExpression() = doTest()
fun testDeadCode() = doTest()
fun testRedundantCastInSwitchBranch() {
myFixture.enableInspections(RedundantCastInspection())
doTest()