From 440cf7888460aa4d691c15c3dfe358465a1e59fb Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Fri, 6 Nov 2020 07:11:31 -0800 Subject: [PATCH] FIR CFG: add more uncaught exception paths --- .../testData/resolve/cfg/complex.dot | 3 ++- .../inplaceLambdaInControlFlowExpressions.dot | 3 ++- .../resolve/cfg/propertiesAndInitBlocks.dot | 3 ++- .../testData/resolve/cfg/tryCatch.dot | 15 ++++++++++----- .../resolve/dfa/cfg/ControlFlowGraphBuilder.kt | 16 +++++++++++++--- .../flowInlining/nestedTryCatchFinally.fir.kt | 6 +++--- .../flowInlining/nestedTryCatchs.fir.kt | 2 +- .../flowInlining/tryCatchFinally.fir.kt | 2 +- 8 files changed, 34 insertions(+), 16 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolve/cfg/complex.dot b/compiler/fir/analysis-tests/testData/resolve/cfg/complex.dot index b8f895f5301..fe0c1fe4a1e 100644 --- a/compiler/fir/analysis-tests/testData/resolve/cfg/complex.dot +++ b/compiler/fir/analysis-tests/testData/resolve/cfg/complex.dot @@ -159,7 +159,8 @@ digraph complex_kt { 28 -> {29}; 29 -> {30}; 30 -> {38 31}; - 31 -> {54 32}; + 31 -> {32}; + 31 -> {54} [label=onUncaughtException]; 32 -> {33}; 33 -> {34}; 34 -> {35}; diff --git a/compiler/fir/analysis-tests/testData/resolve/cfg/inplaceLambdaInControlFlowExpressions.dot b/compiler/fir/analysis-tests/testData/resolve/cfg/inplaceLambdaInControlFlowExpressions.dot index b80016f4cb4..e9de33a5a30 100644 --- a/compiler/fir/analysis-tests/testData/resolve/cfg/inplaceLambdaInControlFlowExpressions.dot +++ b/compiler/fir/analysis-tests/testData/resolve/cfg/inplaceLambdaInControlFlowExpressions.dot @@ -177,7 +177,8 @@ digraph inplaceLambdaInControlFlowExpressions_kt { 44 -> {45}; 45 -> {46}; 46 -> {52 47}; - 47 -> {56 48}; + 47 -> {48}; + 47 -> {56} [label=onUncaughtException]; 48 -> {49}; 49 -> {50}; 50 -> {51}; diff --git a/compiler/fir/analysis-tests/testData/resolve/cfg/propertiesAndInitBlocks.dot b/compiler/fir/analysis-tests/testData/resolve/cfg/propertiesAndInitBlocks.dot index 5979ab952e7..0969a5fbcef 100644 --- a/compiler/fir/analysis-tests/testData/resolve/cfg/propertiesAndInitBlocks.dot +++ b/compiler/fir/analysis-tests/testData/resolve/cfg/propertiesAndInitBlocks.dot @@ -315,7 +315,8 @@ digraph propertiesAndInitBlocks_kt { 88 -> {89}; 89 -> {90}; 90 -> {96 91}; - 91 -> {102 92}; + 91 -> {92}; + 91 -> {96} [label=onUncaughtException]; 92 -> {93}; 93 -> {94}; 94 -> {95}; diff --git a/compiler/fir/analysis-tests/testData/resolve/cfg/tryCatch.dot b/compiler/fir/analysis-tests/testData/resolve/cfg/tryCatch.dot index 29923e13cfb..d39a20b3769 100644 --- a/compiler/fir/analysis-tests/testData/resolve/cfg/tryCatch.dot +++ b/compiler/fir/analysis-tests/testData/resolve/cfg/tryCatch.dot @@ -63,13 +63,15 @@ digraph tryCatch_kt { 6 -> {7}; 7 -> {8}; 8 -> {21 15 9}; - 9 -> {23 10}; + 9 -> {10}; + 9 -> {23} [label=onUncaughtException]; 10 -> {11}; 11 -> {12}; 12 -> {13}; 13 -> {14}; 14 -> {21}; - 15 -> {23 16}; + 15 -> {16}; + 15 -> {23} [label=onUncaughtException]; 16 -> {17}; 17 -> {18}; 18 -> {19}; @@ -124,7 +126,8 @@ digraph tryCatch_kt { 29 -> {30}; 30 -> {31}; 31 -> {37 32}; - 32 -> {40 33}; + 32 -> {33}; + 32 -> {40} [label=onUncaughtException]; 33 -> {34}; 34 -> {35}; 35 -> {36}; @@ -295,7 +298,8 @@ digraph tryCatch_kt { 78 -> {79}; 79 -> {80}; 80 -> {97 91 81}; - 81 -> {102 82}; + 81 -> {82}; + 81 -> {102} [label=onUncaughtException]; 82 -> {83}; 83 -> {87}; 83 -> {84} [style=dotted]; @@ -306,7 +310,8 @@ digraph tryCatch_kt { 88 -> {89}; 89 -> {90}; 90 -> {102}; - 91 -> {102 92}; + 91 -> {92}; + 91 -> {102} [label=onUncaughtException]; 92 -> {93}; 93 -> {94} [style=dotted]; 93 -> {43} [color=green style=dashed]; diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index 3701074b859..e322c34ef36 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -541,6 +541,7 @@ class ControlFlowGraphBuilder { fun exitJump(jump: FirJump<*>): JumpNode { val node = createJumpNode(jump) + // TODO: if within `try` with `finally`, don't go to the target directly. val nextNode = when (jump) { is FirReturnExpression -> exitTargetsForReturn[jump.target.labeledElement.symbol] is FirContinueExpression -> loopEnterNodes[jump.target.labeledElement] @@ -793,8 +794,6 @@ class ControlFlowGraphBuilder { catchNodeStorage.push(catchNode) // a flow where an exception of interest is thrown and caught before executing any of try-main block. addEdge(enterTryExpressionNode, catchNode) - // TODO: Should go to the finally block w/ a label, and exit to the exit target w/ the same label. - addEdge(catchNode, exitTargetsForTry.top()) } levelCounter++ @@ -816,6 +815,7 @@ class ControlFlowGraphBuilder { val finallyEnterNode = finallyEnterNodes.topOrNull() // NB: Check the level to avoid adding an edge to the finally block at an upper level. if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) { + // TODO: in case of return/throw in try main block, we need a unique label. addEdge(node, finallyEnterNode) } else { addEdge(node, tryExitNodes.top()) @@ -828,6 +828,14 @@ class ControlFlowGraphBuilder { val tryMainExitNode = tryMainExitNodes.top() // a flow where an exception of interest is thrown and caught after executing all of try-main block. addEdge(tryMainExitNode, it) + val finallyEnterNode = finallyEnterNodes.topOrNull() + // a flow where an uncaught exception is thrown before executing any of catch clause. + // NB: Check the level to avoid adding an edge to the finally block at an upper level. + if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) { + addEdge(it, finallyEnterNode, label = UncaughtExceptionPath) + } else { + addEdge(it, exitTargetsForTry.top(), label = UncaughtExceptionPath) + } lastNodes.push(it) levelCounter++ } @@ -840,6 +848,7 @@ class ControlFlowGraphBuilder { val finallyEnterNode = finallyEnterNodes.topOrNull() // NB: Check the level to avoid adding an edge to the finally block at an upper level. if (finallyEnterNode != null && finallyEnterNode.level == levelCounter + 1) { + // TODO: in case of return/rethrow in catch clause, we need a unique label. addEdge(it, finallyEnterNode, propagateDeadness = false) } else { addEdge(it, tryExitNodes.top(), propagateDeadness = false) @@ -861,6 +870,7 @@ class ControlFlowGraphBuilder { addEdge(it, tryExitNode) // a flow that exits to the exit target while there was an uncaught exception. addEdge(it, exitTargetsForTry.top(), label = UncaughtExceptionPath) + // TODO: differentiate flows that return/(re)throw in try main block or catch clauses. } } @@ -1255,4 +1265,4 @@ class ControlFlowGraphBuilder { } -fun FirDeclaration?.isLocalClassOrAnonymousObject() = ((this as? FirRegularClass)?.isLocal == true) || this is FirAnonymousObject \ No newline at end of file +fun FirDeclaration?.isLocalClassOrAnonymousObject() = ((this as? FirRegularClass)?.isLocal == true) || this is FirAnonymousObject diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/nestedTryCatchFinally.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/nestedTryCatchFinally.fir.kt index d7d436c9b87..80f20d5ba69 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/nestedTryCatchFinally.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/nestedTryCatchFinally.fir.kt @@ -62,7 +62,7 @@ fun innerFinallyInitializes() { } // Properly initialized - x.inc() + x.inc() } catch (e: java.lang.Exception) { log() } @@ -87,12 +87,12 @@ fun innerFinallyInitializesOuterRethrows() { } // Properly initialized - x.inc() + x.inc() } catch (e: java.lang.Exception) { log() throw e } // Guaranteed to be initialized because all catch-clauses are rethrowing - x.inc() + x.inc() } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/nestedTryCatchs.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/nestedTryCatchs.fir.kt index 40b40cd4c83..20b4846bdb2 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/nestedTryCatchs.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/nestedTryCatchs.fir.kt @@ -43,5 +43,5 @@ fun innerTryCatchInitializes() { x = 42 } // Here x=I because outer try-catch either exited normally (x=I) or catched exception (x=I, with reassingment, though) - x.inc() + x.inc() } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/tryCatchFinally.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/tryCatchFinally.fir.kt index 2b1f4f23c98..c62c45b5a24 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/tryCatchFinally.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/contracts/controlflow/flowInlining/tryCatchFinally.fir.kt @@ -30,5 +30,5 @@ fun innerTryCatchFinally() { } } - x.inc() + x.inc() } \ No newline at end of file