mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java: Detect potential dangling 'else' in "code block contains single statement" inspection (IDEA-174415)
This commit is contained in:
+40
-1
@@ -98,7 +98,7 @@ public class SingleStatementInBlockInspection extends BaseInspection {
|
||||
protected boolean isApplicable(PsiStatement body) {
|
||||
if (body instanceof PsiBlockStatement) {
|
||||
final PsiStatement[] statements = ((PsiBlockStatement)body).getCodeBlock().getStatements();
|
||||
if (statements.length == 1 && !(statements[0] instanceof PsiDeclarationStatement)) {
|
||||
if (statements.length == 1 && !(statements[0] instanceof PsiDeclarationStatement) && !isDanglingElseProblem(statements[0], body)) {
|
||||
final PsiFile file = body.getContainingFile();
|
||||
//this inspection doesn't work in JSP files, as it can't tell about tags
|
||||
// inside the braces
|
||||
@@ -125,6 +125,45 @@ public class SingleStatementInBlockInspection extends BaseInspection {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* See JLS paragraphs 14.5, 14.9
|
||||
*/
|
||||
private static boolean isDanglingElseProblem(@Nullable PsiStatement statement, @NotNull PsiStatement outerStatement) {
|
||||
return hasShortIf(statement) && hasPotentialDanglingElse(outerStatement);
|
||||
}
|
||||
|
||||
private static boolean hasShortIf(@Nullable PsiStatement statement) {
|
||||
if (statement instanceof PsiIfStatement) {
|
||||
final PsiStatement elseBranch = ((PsiIfStatement)statement).getElseBranch();
|
||||
return elseBranch == null || hasShortIf(elseBranch);
|
||||
}
|
||||
if (statement instanceof PsiLabeledStatement) {
|
||||
return hasShortIf(((PsiLabeledStatement)statement).getStatement());
|
||||
}
|
||||
if (statement instanceof PsiWhileStatement || statement instanceof PsiForStatement || statement instanceof PsiForeachStatement) {
|
||||
return hasShortIf(((PsiLoopStatement)statement).getBody());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasPotentialDanglingElse(@NotNull PsiStatement statement) {
|
||||
final PsiElement parent = statement.getParent();
|
||||
if (parent instanceof PsiIfStatement) {
|
||||
final PsiIfStatement ifStatement = (PsiIfStatement)parent;
|
||||
if (ifStatement.getThenBranch() == statement && ifStatement.getElseBranch() != null) {
|
||||
return true;
|
||||
}
|
||||
return hasPotentialDanglingElse(ifStatement);
|
||||
}
|
||||
if (parent instanceof PsiLabeledStatement ||
|
||||
parent instanceof PsiWhileStatement ||
|
||||
parent instanceof PsiForStatement ||
|
||||
parent instanceof PsiForeachStatement) {
|
||||
return hasPotentialDanglingElse((PsiStatement)parent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SingleStatementInBlockFix extends InspectionGadgetsFix {
|
||||
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
class T {
|
||||
|
||||
void f(String[] a) {
|
||||
for (String s : a) {
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
if (a.length == 0) {
|
||||
System.out.println("no");
|
||||
} else {
|
||||
System.out.println(a.length);
|
||||
}
|
||||
|
||||
if (a.length == 0) {
|
||||
System.out.println("no");
|
||||
}
|
||||
|
||||
if (a.length == 0) {
|
||||
} else {
|
||||
System.out.println(a.length);
|
||||
}
|
||||
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
System.out.println(a[i]);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
do {
|
||||
System.out.println(a[j++]);
|
||||
}
|
||||
while (j < a.length);
|
||||
|
||||
int k = 0;
|
||||
while (k < a.length) {
|
||||
System.out.println(a[k++]);
|
||||
}
|
||||
}
|
||||
|
||||
void ff(String[] a) {
|
||||
if (a.length != 0) {
|
||||
for (String arg : a) {
|
||||
if (arg.length() > 1) {
|
||||
for (int i = 0; i < arg.length(); i++) {
|
||||
System.out.println(arg.charAt(i));
|
||||
}
|
||||
} else {
|
||||
System.out.println(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println("no");
|
||||
}
|
||||
}
|
||||
|
||||
void decl(String[] a) {
|
||||
if (a.length == 1) {
|
||||
String t = a[0];
|
||||
}
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
String t = a[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>4</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'for' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>8</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'if' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>10</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'else' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>14</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'if' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>19</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'else' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>23</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'for' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>28</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'do' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>34</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'while' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>40</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'if' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>41</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'for' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>42</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'if' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>43</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'for' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>46</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'else' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>SingleStatement.java</file>
|
||||
<line>50</line>
|
||||
<problem_class>Code block contains single statement</problem_class>
|
||||
<description>'else' contains single statement</description>
|
||||
</problem>
|
||||
|
||||
</problems>
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
class T {
|
||||
|
||||
void f(String[] a) {
|
||||
<warning descr="'for' contains single statement">for</warning> (String s : a) {
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
<warning descr="'if' contains single statement">if</warning> (a.length == 0) {
|
||||
System.out.println("no");
|
||||
} <warning descr="'else' contains single statement">else</warning> {
|
||||
System.out.println(a.length);
|
||||
}
|
||||
|
||||
<warning descr="'if' contains single statement">if</warning> (a.length == 0) {
|
||||
System.out.println("no");
|
||||
}
|
||||
|
||||
if (a.length == 0) {
|
||||
} <warning descr="'else' contains single statement">else</warning> {
|
||||
System.out.println(a.length);
|
||||
}
|
||||
|
||||
<warning descr="'for' contains single statement">for</warning> (int i = 0; i < a.length; i++) {
|
||||
System.out.println(a[i]);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
<warning descr="'do' contains single statement">do</warning> {
|
||||
System.out.println(a[j++]);
|
||||
}
|
||||
while (j < a.length);
|
||||
|
||||
int k = 0;
|
||||
<warning descr="'while' contains single statement">while</warning> (k < a.length) {
|
||||
System.out.println(a[k++]);
|
||||
}
|
||||
}
|
||||
|
||||
void nested(String[] a) {
|
||||
<warning descr="'if' contains single statement">if</warning> (a.length != 0) {
|
||||
<warning descr="'for' contains single statement">for</warning> (String arg : a) {
|
||||
<warning descr="'if' contains single statement">if</warning> (arg.length() > 1) {
|
||||
<warning descr="'for' contains single statement">for</warning> (int i = 0; i < arg.length(); i++) {
|
||||
System.out.println(arg.charAt(i));
|
||||
}
|
||||
} <warning descr="'else' contains single statement">else</warning> {
|
||||
System.out.println(0);
|
||||
}
|
||||
}
|
||||
} <warning descr="'else' contains single statement">else</warning> {
|
||||
System.out.println("no");
|
||||
}
|
||||
}
|
||||
|
||||
void decl(String[] a) {
|
||||
if (a.length == 1) {
|
||||
String t = a[0];
|
||||
}
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
String t = a[i];
|
||||
}
|
||||
}
|
||||
|
||||
void labeled(String[] a) {
|
||||
OuterIf:
|
||||
<warning descr="'if' contains single statement">if</warning> (a != null) {
|
||||
OuterFor:
|
||||
<warning descr="'for' contains single statement">for</warning> (String s : a) {
|
||||
InnerFor:
|
||||
<warning descr="'for' contains single statement">for</warning> (int i = 0; i < s.length(); i++) {
|
||||
InnerIf:
|
||||
<warning descr="'if' contains single statement">if</warning> (s.charAt(i) == ' ') {
|
||||
break OuterFor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void danglingElse(Object[] a) {
|
||||
if (a != null) {
|
||||
if (a.length != 0)
|
||||
System.out.println(a[0]);
|
||||
}
|
||||
else
|
||||
System.out.println("null");
|
||||
}
|
||||
|
||||
void noDanglingElse(Object[] a) {
|
||||
<warning descr="'if' contains single statement">if</warning> (a != null) {
|
||||
if (a.length != 0)
|
||||
System.out.println(a[0]);
|
||||
else
|
||||
System.out.println("empty");
|
||||
}
|
||||
else
|
||||
System.out.println("null");
|
||||
}
|
||||
|
||||
void danglingElseNestedIfChain(Object[] a) {
|
||||
if (a != null) {
|
||||
if (a.length != 0)
|
||||
if(a[0] != null)
|
||||
System.out.println(a[0]);
|
||||
}
|
||||
else
|
||||
System.out.println("null");
|
||||
}
|
||||
|
||||
void danglingElseNestedIfElse(Object[] a) {
|
||||
if (a != null) {
|
||||
if (a.length != 0)
|
||||
if (a[0] != null)
|
||||
System.out.println(a[0]);
|
||||
else
|
||||
System.out.println("missing");
|
||||
}
|
||||
else
|
||||
System.out.println("null");
|
||||
}
|
||||
|
||||
void noDanglingElseNestedIf(Object[] a) {
|
||||
<warning descr="'if' contains single statement">if</warning> (a != null) {
|
||||
if (a.length != 0)
|
||||
if (a[0] != null)
|
||||
System.out.println(a[0]);
|
||||
else
|
||||
System.out.println("missing");
|
||||
else
|
||||
System.out.println("empty");
|
||||
}
|
||||
else
|
||||
System.out.println("null");
|
||||
}
|
||||
|
||||
void danglingElseWithLoop(Object[] a) {
|
||||
if (a != null) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != null)
|
||||
System.out.println(a[i]);
|
||||
}
|
||||
else
|
||||
System.out.println("null");
|
||||
}
|
||||
|
||||
void noDanglingElseWithLoop(Object[] a) {
|
||||
<warning descr="'if' contains single statement">if</warning> (a != null) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] != null)
|
||||
System.out.println(a[i]);
|
||||
else
|
||||
System.out.println("missing");
|
||||
}
|
||||
else
|
||||
System.out.println("null");
|
||||
}
|
||||
|
||||
public int danglingElseWithTwoLoops(Object[] a, Object o) {
|
||||
if (o == null) {
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (a[i] == null)
|
||||
return i;
|
||||
} else
|
||||
for (int i = 0; i < a.length; i++)
|
||||
if (o.equals(a[i]))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
+10
-4
@@ -15,13 +15,19 @@
|
||||
*/
|
||||
package com.siyeh.ig.style;
|
||||
|
||||
import com.siyeh.ig.IGInspectionTestCase;
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.siyeh.ig.LightInspectionTestCase;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class SingleStatementInBlockInspectionTest extends IGInspectionTestCase {
|
||||
public void test() {
|
||||
doTest("com/siyeh/igtest/style/single_statement_block", new SingleStatementInBlockInspection());
|
||||
public class SingleStatementInBlockInspectionTest extends LightInspectionTestCase {
|
||||
public void testSingleStatement() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspection() {
|
||||
return new SingleStatementInBlockInspection();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user