mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 21:11:28 +07:00
Java control flow: Detect unreachable code when a break or continue in the try block is overridden in the finally block of the same try statement (IDEA-35597)
This commit is contained in:
@@ -412,6 +412,8 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
startElement(statement);
|
||||
PsiStatement exitedStatement = statement.findExitedStatement();
|
||||
if (exitedStatement != null) {
|
||||
callFinallyBlocksOnExit(exitedStatement);
|
||||
|
||||
final Instruction instruction;
|
||||
final PsiElement finallyBlock = findEnclosingFinallyBlockElement(statement, exitedStatement);
|
||||
final int finallyStartOffset = finallyBlock == null ? -1 : myCurrentFlow.getStartOffset(finallyBlock);
|
||||
@@ -430,6 +432,18 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
private void callFinallyBlocksOnExit(PsiStatement exitedStatement) {
|
||||
for (final ListIterator<PsiElement> it = myFinallyBlocks.listIterator(myFinallyBlocks.size()); it.hasPrevious(); ) {
|
||||
final PsiElement finallyBlock = it.previous();
|
||||
final PsiElement enclosingTryStatement = finallyBlock.getParent();
|
||||
if (enclosingTryStatement == null || !PsiTreeUtil.isAncestor(exitedStatement, enclosingTryStatement, false)) {
|
||||
break;
|
||||
}
|
||||
myCurrentFlow.addInstruction(new CallInstruction(0, 0, myStack));
|
||||
addElementOffsetLater(finallyBlock, true);
|
||||
}
|
||||
}
|
||||
|
||||
private PsiElement findEnclosingFinallyBlockElement(@NotNull PsiElement sourceElement, @Nullable PsiElement jumpElement) {
|
||||
PsiElement element = sourceElement;
|
||||
while (element != null && !(element instanceof PsiFile)) {
|
||||
@@ -451,21 +465,14 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
PsiStatement continuedStatement = statement.findContinuedStatement();
|
||||
if (continuedStatement != null) {
|
||||
PsiElement body = null;
|
||||
if (continuedStatement instanceof PsiForStatement) {
|
||||
body = ((PsiForStatement)continuedStatement).getBody();
|
||||
}
|
||||
else if (continuedStatement instanceof PsiWhileStatement) {
|
||||
body = ((PsiWhileStatement)continuedStatement).getBody();
|
||||
}
|
||||
else if (continuedStatement instanceof PsiDoWhileStatement) {
|
||||
body = ((PsiDoWhileStatement)continuedStatement).getBody();
|
||||
}
|
||||
else if (continuedStatement instanceof PsiForeachStatement) {
|
||||
body = ((PsiForeachStatement)continuedStatement).getBody();
|
||||
if (continuedStatement instanceof PsiLoopStatement) {
|
||||
body = ((PsiLoopStatement)continuedStatement).getBody();
|
||||
}
|
||||
if (body == null) {
|
||||
body = myCodeFragment;
|
||||
}
|
||||
callFinallyBlocksOnExit(continuedStatement);
|
||||
|
||||
final Instruction instruction;
|
||||
final PsiElement finallyBlock = findEnclosingFinallyBlockElement(statement, continuedStatement);
|
||||
final int finallyStartOffset = finallyBlock == null ? -1 : myCurrentFlow.getStartOffset(finallyBlock);
|
||||
|
||||
@@ -452,4 +452,18 @@ class CompoundAssign {
|
||||
<error descr="Variable 'i' might not have been initialized">i</error> += i = 2;
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
|
||||
class BreakAndFinally {
|
||||
void f() {
|
||||
final int i;
|
||||
t:
|
||||
try {
|
||||
break t;
|
||||
}
|
||||
finally {
|
||||
i = 1;
|
||||
}
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
@@ -402,3 +402,69 @@ class Good3 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class ContinueFromFinally {
|
||||
void foo() {
|
||||
while (true) {
|
||||
try {
|
||||
break;
|
||||
} finally {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
<error descr="Unreachable statement">System.out.println();</error>
|
||||
}
|
||||
}
|
||||
|
||||
class BreakFromNestedTry {
|
||||
void foo() {
|
||||
outer:
|
||||
{
|
||||
inner:
|
||||
try {
|
||||
try {
|
||||
break inner;
|
||||
} finally {
|
||||
System.out.println();
|
||||
}
|
||||
} finally {
|
||||
break outer;
|
||||
}
|
||||
<error descr="Unreachable statement">System.out.println();</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BreakFromNestedFinally {
|
||||
void foo() {
|
||||
outer:
|
||||
{
|
||||
inner:
|
||||
try {
|
||||
try {
|
||||
} finally {
|
||||
break inner;
|
||||
}
|
||||
} finally {
|
||||
break outer;
|
||||
}
|
||||
<error descr="Unreachable statement">System.out.println();</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ContinueFromTry {
|
||||
void foo() {
|
||||
outer:
|
||||
{
|
||||
do {
|
||||
try {
|
||||
continue;
|
||||
} finally {
|
||||
break outer;
|
||||
}
|
||||
} while (false);
|
||||
<error descr="Unreachable statement">System.out.println();</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user