mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-10 13:17:09 +07:00
Java: Extend control flow analysis to support enhanced switch & switch expression, including break-with-value (IDEA-202131)
This commit is contained in:
@@ -397,7 +397,9 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
@Override
|
||||
public void visitBreakStatement(PsiBreakStatement statement) {
|
||||
startElement(statement);
|
||||
PsiStatement exitedStatement = statement.findExitedStatement();
|
||||
generateExpressionInstructions(statement.getValueExpression());
|
||||
|
||||
PsiElement exitedStatement = statement.findExitedElement();
|
||||
if (exitedStatement != null) {
|
||||
callFinallyBlocksOnExit(exitedStatement);
|
||||
|
||||
@@ -419,7 +421,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
private void callFinallyBlocksOnExit(PsiStatement exitedStatement) {
|
||||
private void callFinallyBlocksOnExit(PsiElement exitedStatement) {
|
||||
for (final ListIterator<FinallyBlockSubroutine> it = myFinallyBlocks.listIterator(myFinallyBlocks.size()); it.hasPrevious(); ) {
|
||||
final FinallyBlockSubroutine finallyBlockSubroutine = it.previous();
|
||||
PsiElement finallyBlock = finallyBlockSubroutine.getElement();
|
||||
@@ -503,13 +505,8 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
|
||||
private void processVariable(@NotNull PsiVariable element) {
|
||||
final PsiExpression initializer = element.getInitializer();
|
||||
if (initializer != null) {
|
||||
myStartStatementStack.pushStatement(initializer, false);
|
||||
myEndStatementStack.pushStatement(initializer, false);
|
||||
initializer.accept(this);
|
||||
myStartStatementStack.popStatement();
|
||||
myEndStatementStack.popStatement();
|
||||
}
|
||||
generateExpressionInstructions(initializer);
|
||||
|
||||
if (element instanceof PsiLocalVariable && initializer != null ||
|
||||
element instanceof PsiField) {
|
||||
if (element instanceof PsiLocalVariable && !myPolicy.isLocalVariableAccepted((PsiLocalVariable)element)) return;
|
||||
@@ -839,13 +836,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
startElement(statement);
|
||||
PsiExpression caseValue = statement.getCaseValue();
|
||||
|
||||
if (caseValue != null) {
|
||||
myStartStatementStack.pushStatement(caseValue, false);
|
||||
myEndStatementStack.pushStatement(caseValue, false);
|
||||
caseValue.accept(this);
|
||||
myStartStatementStack.popStatement();
|
||||
myEndStatementStack.popStatement();
|
||||
}
|
||||
generateExpressionInstructions(caseValue);
|
||||
|
||||
finishElement(statement);
|
||||
}
|
||||
@@ -857,11 +848,8 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
|
||||
if (caseValues != null) {
|
||||
for (PsiExpression caseValue : caseValues.getExpressions()) {
|
||||
myStartStatementStack.pushStatement(caseValue, false);
|
||||
myEndStatementStack.pushStatement(caseValue, false);
|
||||
caseValue.accept(this);
|
||||
myStartStatementStack.popStatement();
|
||||
myEndStatementStack.popStatement();
|
||||
ProgressManager.checkCanceled();
|
||||
generateExpressionInstructions(caseValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1321,6 +1309,13 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
PsiExpression[] expressions = list.getExpressions();
|
||||
for (final PsiExpression expression : expressions) {
|
||||
ProgressManager.checkCanceled();
|
||||
generateExpressionInstructions(expression);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateExpressionInstructions(@Nullable PsiExpression expression) {
|
||||
if (expression != null) {
|
||||
// handle short circuit
|
||||
myStartStatementStack.pushStatement(expression, false);
|
||||
myEndStatementStack.pushStatement(expression, false);
|
||||
|
||||
|
||||
+72
@@ -105,4 +105,76 @@ class C {
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
static class FinalFieldSwitchExpression {
|
||||
final String s = switch ((int)Math.random()) {
|
||||
case 1 -> "a";
|
||||
default -> "?";
|
||||
};
|
||||
{
|
||||
System.out.println(s);
|
||||
}
|
||||
}
|
||||
|
||||
static class FinalFieldValueBreakSwitchExpression {
|
||||
final String s = switch ((int)Math.random()) {
|
||||
case 1: break "a";
|
||||
default: break "?";
|
||||
};
|
||||
{
|
||||
System.out.println(s);
|
||||
}
|
||||
}
|
||||
|
||||
void finalVariableSwitchExpression(String s) {
|
||||
final int n = switch (s) {
|
||||
case "a" -> 1;
|
||||
default -> 0;
|
||||
};
|
||||
System.out.println(n);
|
||||
}
|
||||
|
||||
void finalVariableValueBreakSwitchExpression(String s) {
|
||||
final int n = switch (s) {
|
||||
case "a": break 1;
|
||||
default: break 0;
|
||||
};
|
||||
System.out.println(n);
|
||||
}
|
||||
|
||||
void definitelyAssignedInSwitchExpression(String s) {
|
||||
int n;
|
||||
int x = switch (s) {
|
||||
case "a" -> n = 1;
|
||||
default -> n = 0;
|
||||
};
|
||||
System.out.println(n);
|
||||
}
|
||||
|
||||
void notDefinitelyAssignedInSwitchExpression(String s) {
|
||||
int n;
|
||||
int x = switch (s) {
|
||||
case "a" -> n = 1;
|
||||
default -> 0;
|
||||
};
|
||||
System.out.println(<error descr="Variable 'n' might not have been initialized">n</error>);
|
||||
}
|
||||
|
||||
void definitelyAssignedInSwitchExpressionValueBreak(String s) {
|
||||
int n;
|
||||
int x = switch (s) {
|
||||
case "a": break n = 1;
|
||||
default: break n = 0;
|
||||
};
|
||||
System.out.println(n);
|
||||
}
|
||||
|
||||
void notDefinitelyAssignedInSwitchExpressionValueBreak(String s) {
|
||||
int n;
|
||||
int x = switch (s) {
|
||||
case "a": break n = 1;
|
||||
default: break 0;
|
||||
};
|
||||
System.out.println(<error descr="Variable 'n' might not have been initialized">n</error>);
|
||||
}
|
||||
}
|
||||
+17
-30
@@ -45,41 +45,13 @@ class C {
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/* todo
|
||||
void endlessLoopInBranchWithValue(String arg) {
|
||||
void endlessLoopInBranchWithValueBreak(String arg) {
|
||||
int result = switch (arg) {
|
||||
case "one" -> { while(true); break 1;}
|
||||
case "one" -> { while(true); <error descr="Unreachable statement">break 1;</error>}
|
||||
default -> 0;
|
||||
};
|
||||
System.out.println(result);
|
||||
}
|
||||
*/
|
||||
|
||||
static class FinalFieldSwitchExpression {
|
||||
final String s = switch ((int)Math.random()) {
|
||||
case 1 -> "a";
|
||||
default -> "?";
|
||||
};
|
||||
{
|
||||
System.out.println(s);
|
||||
}
|
||||
}
|
||||
|
||||
void finalVariableSwitchExpression(String s) {
|
||||
final int n = switch (s) {
|
||||
case "a" -> 1;
|
||||
default -> 0;
|
||||
};
|
||||
System.out.println(n);
|
||||
}
|
||||
|
||||
void notDefinitelyAssigned(String s) {
|
||||
int n;
|
||||
switch (s) {
|
||||
case "a" -> n = 1;
|
||||
}
|
||||
System.out.println(<error descr="Variable 'n' might not have been initialized">n</error>);
|
||||
}
|
||||
|
||||
int returnBeforeEnhancedSwitchStatement(String s) {
|
||||
return 2;
|
||||
@@ -129,6 +101,21 @@ class C {
|
||||
int bar(int i) throws Exception { return i; }
|
||||
}
|
||||
|
||||
static class ValueBreakSwitchExpressionReturnedFromTry {
|
||||
int foo(String s) throws Exception {
|
||||
try {
|
||||
return switch (s) {
|
||||
case "a": break bar(1);
|
||||
default: break bar(0);
|
||||
};
|
||||
} finally {
|
||||
System.out.println("b");
|
||||
}
|
||||
<error descr="Unreachable statement">System.out.println("c");</error>
|
||||
}
|
||||
int bar(int i) throws Exception { return i; }
|
||||
}
|
||||
|
||||
static class SwitchStatementReturnsFromTry {
|
||||
int foo(String s) throws Exception {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user