diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java index 785fda10afc..593066ffffa 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java @@ -1026,6 +1026,22 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfa") + @TestDataPath("$PROJECT_ROOT") + public class Cfa { + @Test + public void testAllFilesPresentInCfa() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/cfa"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("initializationInTry.kt") + public void testInitializationInTry() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index f1596a2dadb..b8b29b9f30a 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -881,6 +881,24 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract } } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfa") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Cfa extends AbstractLazyBodyIsNotTouchedTilContractsPhaseTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCfa() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/cfa"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @TestMetadata("initializationInTry.kt") + public void testInitializationInTry() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.kt"); + } + } + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.dot b/compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.dot new file mode 100644 index 00000000000..d6e1e47bac3 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.dot @@ -0,0 +1,177 @@ +digraph initializationInTry_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function getNullableString" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + 2 [label="Const: Null(null)"]; + 3 [label="Jump: ^getNullableString Null(null)"]; + 4 [label="Stub" style="filled" fillcolor=gray]; + 5 [label="Exit block" style="filled" fillcolor=gray]; + } + 6 [label="Exit function getNullableString" style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {6}; + 3 -> {4} [style=dotted]; + 4 -> {5} [style=dotted]; + 5 -> {6} [style=dotted]; + + subgraph cluster_2 { + color=red + 7 [label="Enter function takeNullableString" style="filled" fillcolor=red]; + subgraph cluster_3 { + color=blue + 8 [label="Enter block"]; + 9 [label="Exit block"]; + } + 10 [label="Exit function takeNullableString" style="filled" fillcolor=red]; + } + 7 -> {8}; + 8 -> {9}; + 9 -> {10}; + + subgraph cluster_4 { + color=red + 11 [label="Enter function test_1" style="filled" fillcolor=red]; + subgraph cluster_5 { + color=blue + 12 [label="Enter block"]; + 13 [label="Variable declaration: lval x: R|kotlin/String?|"]; + subgraph cluster_6 { + color=blue + 14 [label="Try expression enter"]; + subgraph cluster_7 { + color=blue + 15 [label="Try main block enter"]; + subgraph cluster_8 { + color=blue + 16 [label="Enter block"]; + 17 [label="Function call: R|/getNullableString|()"]; + 18 [label="Check not null: R|/getNullableString|()!!"]; + 19 [label="Variable declaration: lval y: R|kotlin/String|"]; + 20 [label="Function call: R|/getNullableString|()"]; + 21 [label="Assignment: R|/x|"]; + 22 [label="Exit block"]; + } + 23 [label="Try main block exit"]; + } + subgraph cluster_9 { + color=blue + 24 [label="Enter finally"]; + subgraph cluster_10 { + color=blue + 25 [label="Enter block"]; + 26 [label="Access qualifier kotlin/Unit"]; + 27 [label="Exit block"]; + } + 28 [label="Exit finally"]; + } + 29 [label="Try expression exit"]; + } + 30 [label="Access variable R|/x|"]; + 31 [label="Function call: R|/takeNullableString|(...)"]; + 32 [label="Exit block"]; + } + 33 [label="Exit function test_1" style="filled" fillcolor=red]; + } + 11 -> {12}; + 12 -> {13}; + 13 -> {14}; + 14 -> {15}; + 14 -> {24} [label=onUncaughtException]; + 15 -> {16}; + 16 -> {17}; + 17 -> {18}; + 18 -> {19}; + 19 -> {20}; + 20 -> {21}; + 21 -> {22}; + 22 -> {23}; + 23 -> {24}; + 24 -> {25}; + 25 -> {26}; + 26 -> {27}; + 27 -> {28}; + 28 -> {29}; + 28 -> {33} [label=onUncaughtException]; + 29 -> {30}; + 30 -> {31}; + 31 -> {32}; + 32 -> {33}; + + subgraph cluster_11 { + color=red + 34 [label="Enter function test_2" style="filled" fillcolor=red]; + subgraph cluster_12 { + color=blue + 35 [label="Enter block"]; + 36 [label="Variable declaration: lval x: R|kotlin/String?|"]; + subgraph cluster_13 { + color=blue + 37 [label="Try expression enter"]; + subgraph cluster_14 { + color=blue + 38 [label="Try main block enter"]; + subgraph cluster_15 { + color=blue + 39 [label="Enter block"]; + 40 [label="Function call: R|/getNullableString|()"]; + 41 [label="Variable declaration: lval y: R|kotlin/String?|"]; + 42 [label="Function call: R|/getNullableString|()"]; + 43 [label="Assignment: R|/x|"]; + 44 [label="Exit block"]; + } + 45 [label="Try main block exit"]; + } + subgraph cluster_16 { + color=blue + 46 [label="Enter finally"]; + subgraph cluster_17 { + color=blue + 47 [label="Enter block"]; + 48 [label="Access qualifier kotlin/Unit"]; + 49 [label="Exit block"]; + } + 50 [label="Exit finally"]; + } + 51 [label="Try expression exit"]; + } + 52 [label="Access variable R|/x|"]; + 53 [label="Function call: R|/takeNullableString|(...)"]; + 54 [label="Exit block"]; + } + 55 [label="Exit function test_2" style="filled" fillcolor=red]; + } + 34 -> {35}; + 35 -> {36}; + 36 -> {37}; + 37 -> {38}; + 37 -> {46} [label=onUncaughtException]; + 38 -> {39}; + 39 -> {40}; + 40 -> {41}; + 41 -> {42}; + 42 -> {43}; + 43 -> {44}; + 44 -> {45}; + 45 -> {46}; + 46 -> {47}; + 47 -> {48}; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 50 -> {55} [label=onUncaughtException]; + 51 -> {52}; + 52 -> {53}; + 53 -> {54}; + 54 -> {55}; + +} diff --git a/compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.fir.txt b/compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.fir.txt new file mode 100644 index 00000000000..50b123642c0 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.fir.txt @@ -0,0 +1,30 @@ +FILE: initializationInTry.kt + public final fun getNullableString(): R|kotlin/String?| { + ^getNullableString Null(null) + } + public final fun takeNullableString(s: R|kotlin/String?|): R|kotlin/Unit| { + } + public final fun test_1(): R|kotlin/Unit| { + lval x: R|kotlin/String?| + try { + lval y: R|kotlin/String| = R|/getNullableString|()!! + R|/x| = R|/getNullableString|() + } + finally { + Q|kotlin/Unit| + } + + R|/takeNullableString|(R|/x|) + } + public final fun test_2(): R|kotlin/Unit| { + lval x: R|kotlin/String?| + try { + lval y: R|kotlin/String?| = R|/getNullableString|() + R|/x| = R|/getNullableString|() + } + finally { + Q|kotlin/Unit| + } + + R|/takeNullableString|(R|/x|) + } diff --git a/compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.kt b/compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.kt new file mode 100644 index 00000000000..a0ffc040edd --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.kt @@ -0,0 +1,30 @@ +// DUMP_CFG + +fun getNullableString(): String? = null +fun takeNullableString(s: String?) {} + +fun test_1() { + val x: String? + + try { + val y = getNullableString()!! // 3 + x = getNullableString() + } finally { + Unit + } + + takeNullableString(x) +} + +fun test_2() { + val x: String? + + try { + val y = getNullableString() + x = getNullableString() + } finally { + Unit + } + + takeNullableString(x) +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index e21584e79ec..430355b5857 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -1026,6 +1026,22 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfa") + @TestDataPath("$PROJECT_ROOT") + public class Cfa { + @Test + public void testAllFilesPresentInCfa() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/cfa"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("initializationInTry.kt") + public void testInitializationInTry() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index 9082426e5e3..8170e4aa96c 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -1026,6 +1026,22 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos } } + @Nested + @TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfa") + @TestDataPath("$PROJECT_ROOT") + public class Cfa { + @Test + public void testAllFilesPresentInCfa() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/cfa"), Pattern.compile("^([^.]+)\\.kt$"), null, true); + } + + @Test + @TestMetadata("initializationInTry.kt") + public void testInitializationInTry() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/cfa/initializationInTry.kt"); + } + } + @Nested @TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg") @TestDataPath("$PROJECT_ROOT") 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 6fb92032da1..6b9fae56057 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 @@ -44,7 +44,6 @@ class ControlFlowGraphBuilder { get() = lastNodes.top() var levelCounter: Int = 0 - private set private val modes: Stack = stackOf(Mode.TopLevel) private val mode: Mode get() = modes.top() @@ -1147,6 +1146,7 @@ class ControlFlowGraphBuilder { checkNotNullCall: FirCheckNotNullCall, callCompleted: Boolean ): Pair { + levelCounter-- val node = createCheckNotNullCallNode(checkNotNullCall) if (checkNotNullCall.resultType.isNothing) { addNodeThatReturnsNothing(node)