From 6b4e95ec52cdb0d692b943105fde5b6d7686363f Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 22 Aug 2019 14:47:57 +0300 Subject: [PATCH] [FIR] Add tests for control flow graph building --- .../resolve/cfg/binaryOperations.cfg.txt | 97 +++++++++++++++ .../testData/resolve/cfg/binaryOperations.kt | 23 ++++ .../testData/resolve/cfg/binaryOperations.txt | 41 +++++++ .../testData/resolve/cfg/complex.cfg.txt | 21 ++++ .../resolve/testData/resolve/cfg/complex.kt | 31 +++++ .../testData/resolve/cfg/initBlock.cfg.txt | 0 .../resolve/testData/resolve/cfg/initBlock.kt | 13 ++ .../testData/resolve/cfg/initBlock.txt | 23 ++++ .../testData/resolve/cfg/jumps.cfg.txt | 92 ++++++++++++++ .../fir/resolve/testData/resolve/cfg/jumps.kt | 33 +++++ .../resolve/testData/resolve/cfg/jumps.txt | 41 +++++++ .../testData/resolve/cfg/loops.cfg.txt | 68 +++++++++++ .../fir/resolve/testData/resolve/cfg/loops.kt | 20 ++++ .../resolve/testData/resolve/cfg/loops.txt | 25 ++++ .../cfg/propertiesAndInitBlocks.cfg.txt | 113 ++++++++++++++++++ .../resolve/cfg/propertiesAndInitBlocks.kt | 42 +++++++ .../resolve/cfg/propertiesAndInitBlocks.txt | 58 +++++++++ .../testData/resolve/cfg/simple.cfg.txt | 17 +++ .../resolve/testData/resolve/cfg/simple.kt | 7 ++ .../resolve/testData/resolve/cfg/simple.txt | 8 ++ .../testData/resolve/cfg/tryCatch.cfg.txt | 112 +++++++++++++++++ .../resolve/testData/resolve/cfg/tryCatch.kt | 33 +++++ .../resolve/testData/resolve/cfg/tryCatch.txt | 55 +++++++++ .../resolve/testData/resolve/cfg/when.cfg.txt | 71 +++++++++++ .../fir/resolve/testData/resolve/cfg/when.kt | 17 +++ .../fir/resolve/testData/resolve/cfg/when.txt | 32 +++++ .../kotlin/fir/AbstractFirCfgBuildingTest.kt | 42 +++++++ .../kotlin/fir/AbstractFirResolveTestCase.kt | 15 ++- .../fir/FirCfgBuildingTestGenerated.java | 76 ++++++++++++ .../fir/FirResolveTestCaseGenerated.java | 2 +- .../generators/tests/GenerateCompilerTests.kt | 12 +- 31 files changed, 1229 insertions(+), 11 deletions(-) create mode 100644 compiler/fir/resolve/testData/resolve/cfg/binaryOperations.cfg.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/binaryOperations.kt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/binaryOperations.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/complex.cfg.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/complex.kt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/initBlock.cfg.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/initBlock.kt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/initBlock.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/jumps.cfg.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/jumps.kt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/jumps.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/loops.cfg.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/loops.kt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/loops.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.cfg.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.kt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/simple.cfg.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/simple.kt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/simple.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/tryCatch.cfg.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/tryCatch.kt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/tryCatch.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/when.cfg.txt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/when.kt create mode 100644 compiler/fir/resolve/testData/resolve/cfg/when.txt create mode 100644 compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirCfgBuildingTest.kt create mode 100644 compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java diff --git a/compiler/fir/resolve/testData/resolve/cfg/binaryOperations.cfg.txt b/compiler/fir/resolve/testData/resolve/cfg/binaryOperations.cfg.txt new file mode 100644 index 00000000000..27a9fe71e68 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/binaryOperations.cfg.txt @@ -0,0 +1,97 @@ + 0: Enter function "test_1" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter when -> 3 | <- 1 + 3: Enter when branch condition -> 4 | <- 2 + 4: Enter || -> 5, 8 | <- 3 + 5: Access variable R|/b1| -> 6, 8 | <- 4 + 6: Exit left part of || -> 7 | <- 5 + 7: Access variable R|/b2| -> 8 | <- 6 + 8: Exit || -> 9 | <- 4, 5, 7 + 9: Exit when branch condition -> 10, 14 | <- 8 +10: Enter block -> 11 | <- 9 +11: Const: Int(1) -> 12 | <- 10 +12: Exit block -> 13 | <- 11 +13: Exit when branch result -> 19 | <- 12 +14: Enter when branch condition "else" -> 15 | <- 9 +15: Exit when branch condition -> 16 | <- 14 +16: Enter block -> 17 | <- 15 +17: Exit block -> 18 | <- 16 +18: Exit when branch result -> 19 | <- 17 +19: Exit when -> 20 | <- 13, 18 +20: Exit block -> 21 | <- 19 +21: Exit function "test_1" -> | <- 20 + + 0: Enter function "test_2" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter when -> 3 | <- 1 + 3: Enter when branch condition -> 4 | <- 2 + 4: Enter && -> 5 | <- 3 + 5: Access variable R|/b1| -> 6, 7 | <- 4 + 6: Access variable R|/b2| -> 7 | <- 5 + 7: Exit && -> 8 | <- 5, 6 + 8: Exit when branch condition -> 9, 13 | <- 7 + 9: Enter block -> 10 | <- 8 +10: Const: Int(1) -> 11 | <- 9 +11: Exit block -> 12 | <- 10 +12: Exit when branch result -> 18 | <- 11 +13: Enter when branch condition "else" -> 14 | <- 8 +14: Exit when branch condition -> 15 | <- 13 +15: Enter block -> 16 | <- 14 +16: Exit block -> 17 | <- 15 +17: Exit when branch result -> 18 | <- 16 +18: Exit when -> 19 | <- 12, 17 +19: Exit block -> 20 | <- 18 +20: Exit function "test_2" -> | <- 19 + + 0: Enter function "test_3" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter when -> 3 | <- 1 + 3: Enter when branch condition -> 4 | <- 2 + 4: Enter || -> 5, 11 | <- 3 + 5: Enter && -> 6 | <- 4 + 6: Access variable R|/b1| -> 7, 8 | <- 5 + 7: Access variable R|/b2| -> 8 | <- 6 + 8: Exit && -> 9, 11 | <- 6, 7 + 9: Exit left part of || -> 10 | <- 8 +10: Access variable R|/b3| -> 11 | <- 9 +11: Exit || -> 12 | <- 4, 8, 10 +12: Exit when branch condition -> 13, 17 | <- 11 +13: Enter block -> 14 | <- 12 +14: Const: Int(1) -> 15 | <- 13 +15: Exit block -> 16 | <- 14 +16: Exit when branch result -> 22 | <- 15 +17: Enter when branch condition "else" -> 18 | <- 12 +18: Exit when branch condition -> 19 | <- 17 +19: Enter block -> 20 | <- 18 +20: Exit block -> 21 | <- 19 +21: Exit when branch result -> 22 | <- 20 +22: Exit when -> 23 | <- 16, 21 +23: Exit block -> 24 | <- 22 +24: Exit function "test_3" -> | <- 23 + + 0: Enter function "test_4" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter when -> 3 | <- 1 + 3: Enter when branch condition -> 4 | <- 2 + 4: Enter || -> 5, 11 | <- 3 + 5: Access variable R|/b1| -> 6, 11 | <- 4 + 6: Exit left part of || -> 7 | <- 5 + 7: Enter && -> 8 | <- 6 + 8: Access variable R|/b2| -> 9, 10 | <- 7 + 9: Access variable R|/b3| -> 10 | <- 8 +10: Exit && -> 11 | <- 8, 9 +11: Exit || -> 12 | <- 4, 5, 10 +12: Exit when branch condition -> 13, 17 | <- 11 +13: Enter block -> 14 | <- 12 +14: Const: Int(1) -> 15 | <- 13 +15: Exit block -> 16 | <- 14 +16: Exit when branch result -> 22 | <- 15 +17: Enter when branch condition "else" -> 18 | <- 12 +18: Exit when branch condition -> 19 | <- 17 +19: Enter block -> 20 | <- 18 +20: Exit block -> 21 | <- 19 +21: Exit when branch result -> 22 | <- 20 +22: Exit when -> 23 | <- 16, 21 +23: Exit block -> 24 | <- 22 +24: Exit function "test_4" -> | <- 23 + diff --git a/compiler/fir/resolve/testData/resolve/cfg/binaryOperations.kt b/compiler/fir/resolve/testData/resolve/cfg/binaryOperations.kt new file mode 100644 index 00000000000..60a3c7599f5 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/binaryOperations.kt @@ -0,0 +1,23 @@ +fun test_1(b1: Boolean, b2: Boolean) { + if (b1 || b2) { + 1 + } +} + +fun test_2(b1: Boolean, b2: Boolean) { + if (b1 && b2) { + 1 + } +} + +fun test_3(b1: Boolean, b2: Boolean, b3: Boolean) { + if (b1 && b2 || b3) { + 1 + } +} + +fun test_4(b1: Boolean, b2: Boolean, b3: Boolean) { + if (b1 || b2 && b3) { + 1 + } +} diff --git a/compiler/fir/resolve/testData/resolve/cfg/binaryOperations.txt b/compiler/fir/resolve/testData/resolve/cfg/binaryOperations.txt new file mode 100644 index 00000000000..ecb1fffd8cc --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/binaryOperations.txt @@ -0,0 +1,41 @@ +FILE: binaryOperations.kt + public final fun test_1(b1: R|kotlin/Boolean|, b2: R|kotlin/Boolean|): R|kotlin/Unit| { + when () { + R|/b1| || R|/b2| -> { + Int(1) + } + else -> { + } + } + + } + public final fun test_2(b1: R|kotlin/Boolean|, b2: R|kotlin/Boolean|): R|kotlin/Unit| { + when () { + R|/b1| && R|/b2| -> { + Int(1) + } + else -> { + } + } + + } + public final fun test_3(b1: R|kotlin/Boolean|, b2: R|kotlin/Boolean|, b3: R|kotlin/Boolean|): R|kotlin/Unit| { + when () { + R|/b1| && R|/b2| || R|/b3| -> { + Int(1) + } + else -> { + } + } + + } + public final fun test_4(b1: R|kotlin/Boolean|, b2: R|kotlin/Boolean|, b3: R|kotlin/Boolean|): R|kotlin/Unit| { + when () { + R|/b1| || R|/b2| && R|/b3| -> { + Int(1) + } + else -> { + } + } + + } diff --git a/compiler/fir/resolve/testData/resolve/cfg/complex.cfg.txt b/compiler/fir/resolve/testData/resolve/cfg/complex.cfg.txt new file mode 100644 index 00000000000..2f13e13e782 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/complex.cfg.txt @@ -0,0 +1,21 @@ +0: Enter function "foo" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Try expression enter -> 3 | <- 1 + 3: Try main block enter -> 4, 8, 20 | <- 2 + 4: Enter block -> 5 | <- 3 + 5: Const: Int(1) -> 6 | <- 4 + 6: Exit block -> 7 | <- 5 + 7: Try main block exit -> 14 | <- 6 + 8: Catch enter -> 9, 20 | <- 3 + 9: Enter block -> 10 | <- 8 +10: Jump: ^foo Unit -> 11[DEAD], 20 | <- 9 +11: Stub[DEAD] -> 12 | <- 10 +12: Exit block[DEAD] -> 13 | <- 11 +13: Catch exit[DEAD] -> 14 | <- 12 +14: Try expression exit -> 15 | <- 7, 13[DEAD] +15: Variable declaration: lval x: R|kotlin/Int| -> 16 | <- 14 +16: Access variable R|/x| -> 17 | <- 15 +17: Const: Int(1) -> 18 | <- 16 +18: Function call: R|/x|.R|kotlin/Int.plus|(Int(1)) -> 19 | <- 17 +19: Exit block -> 20 | <- 18 +20: Exit function "foo" -> | <- 3, 8, 10, 19 diff --git a/compiler/fir/resolve/testData/resolve/cfg/complex.kt b/compiler/fir/resolve/testData/resolve/cfg/complex.kt new file mode 100644 index 00000000000..be4242e5d7a --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/complex.kt @@ -0,0 +1,31 @@ +@Throws(IOException::class, ResponseParseException::class) +fun fetchPluginReleaseDate(pluginId: PluginId, version: String, channel: String?): LocalDate? { + val url = "https://plugins.jetbrains.com/api/plugins/${pluginId.idString}/updates?version=$version" + + val pluginDTOs: Array = try { + HttpRequests.request(url).connect { + GsonBuilder().create().fromJson(it.inputStream.reader(), Array::class.java) + } + } catch (ioException: JsonIOException) { + throw IOException(ioException) + } catch (syntaxException: JsonSyntaxException) { + throw ResponseParseException("Can't parse json response", syntaxException) + } + +// val selectedPluginDTO = pluginDTOs +// .firstOrNull { +// it.listed && it.approve && (it.channel == channel || (it.channel == "" && channel == null)) +// } +// ?: return null +// +// val dateString = selectedPluginDTO.cdate ?: throw ResponseParseException("Empty cdate") +// +// return try { +// val dateLong = dateString.toLong() +// Instant.ofEpochMilli(dateLong).atZone(ZoneOffset.UTC).toLocalDate() +// } catch (e: NumberFormatException) { +// throw ResponseParseException("Can't parse long date", e) +// } catch (e: DateTimeException) { +// throw ResponseParseException("Can't convert to date", e) +// } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/cfg/initBlock.cfg.txt b/compiler/fir/resolve/testData/resolve/cfg/initBlock.cfg.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/compiler/fir/resolve/testData/resolve/cfg/initBlock.kt b/compiler/fir/resolve/testData/resolve/cfg/initBlock.kt new file mode 100644 index 00000000000..1c4c7748d0b --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/initBlock.kt @@ -0,0 +1,13 @@ +class Foo { + init { + val x = 1 + } +} + +class Bar { + init { + val x = 1 + throw Exception() + val y = 2 + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/cfg/initBlock.txt b/compiler/fir/resolve/testData/resolve/cfg/initBlock.txt new file mode 100644 index 00000000000..209507fb919 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/initBlock.txt @@ -0,0 +1,23 @@ +FILE: initBlock.kt + public final class Foo : R|kotlin/Any| { + public constructor(): R|Foo| { + super() + } + + init { + lval x: R|kotlin/Int| = Int(1) + } + + } + public final class Bar : R|kotlin/Any| { + public constructor(): R|Bar| { + super() + } + + init { + lval x: R|kotlin/Int| = Int(1) + throw #() + lval y: R|kotlin/Int| = Int(2) + } + + } diff --git a/compiler/fir/resolve/testData/resolve/cfg/jumps.cfg.txt b/compiler/fir/resolve/testData/resolve/cfg/jumps.cfg.txt new file mode 100644 index 00000000000..e06fffa33a9 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/jumps.cfg.txt @@ -0,0 +1,92 @@ + 0: Enter function "test_1" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter when -> 3 | <- 1 + 3: Enter when branch condition -> 4 | <- 2 + 4: Access variable R|/x| -> 5 | <- 3 + 5: Const: Null(null) -> 6 | <- 4 + 6: Operator == -> 7 | <- 5 + 7: Exit when branch condition -> 8, 14 | <- 6 + 8: Enter block -> 9 | <- 7 + 9: Function call: R|kotlin/KotlinNullPointerException.KotlinNullPointerException|() -> 10 | <- 8 +10: Throw: throw R|kotlin/KotlinNullPointerException.KotlinNullPointerException|() -> 11[DEAD], 25 | <- 9 +11: Stub[DEAD] -> 12 | <- 10 +12: Exit block[DEAD] -> 13 | <- 11 +13: Exit when branch result[DEAD] -> 20 | <- 12 +14: Enter when branch condition "else" -> 15 | <- 7 +15: Exit when branch condition -> 16 | <- 14 +16: Enter block -> 17 | <- 15 +17: Access variable R|/x| -> 18 | <- 16 +18: Exit block -> 19 | <- 17 +19: Exit when branch result -> 20 | <- 18 +20: Exit when -> 21 | <- 13[DEAD], 19 +21: Variable declaration: lval y: R|kotlin/Int?| -> 22 | <- 20 +22: Access variable R|/y| -> 23 | <- 21 +23: Function call: R|/y|.#() -> 24 | <- 22 +24: Exit block -> 25 | <- 23 +25: Exit function "test_1" -> | <- 10, 24 + + 0: Enter function "test_2" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter when -> 3 | <- 1 + 3: Enter when branch condition -> 4 | <- 2 + 4: Access variable R|/x| -> 5 | <- 3 + 5: Const: Null(null) -> 6 | <- 4 + 6: Operator == -> 7 | <- 5 + 7: Exit when branch condition -> 8, 12 | <- 6 + 8: Enter block -> 9 | <- 7 + 9: Access variable R|/x| -> 10 | <- 8 +10: Exit block -> 11 | <- 9 +11: Exit when branch result -> 18 | <- 10 +12: Enter when branch condition "else" -> 13 | <- 7 +13: Exit when branch condition -> 14 | <- 12 +14: Enter block -> 15 | <- 13 +15: Access variable R|/x| -> 16 | <- 14 +16: Exit block -> 17 | <- 15 +17: Exit when branch result -> 18 | <- 16 +18: Exit when -> 19 | <- 11, 17 +19: Variable declaration: lval y: R|kotlin/Int?| -> 20 | <- 18 +20: Access variable R|/y| -> 21 | <- 19 +21: Function call: R|/y|.#() -> 22 | <- 20 +22: Exit block -> 23 | <- 21 +23: Exit function "test_2" -> | <- 22 + + 0: Enter function "test_3" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter while loop -> 3 | <- 1 + 3: Enter loop condition -> 4 | <- 2, 13[DEAD] + 4: Const: Boolean(true) -> 5 | <- 3 + 5: Exit loop condition -> 6, 14 | <- 4 + 6: Enter loop block -> 7 | <- 5 + 7: Enter block -> 8 | <- 6 + 8: Access variable R|/x| -> 9 | <- 7 + 9: Type operator: "x as Int" -> 10 | <- 8 +10: Jump: break@@@[Boolean(true)] -> 11[DEAD], 14 | <- 9 +11: Stub[DEAD] -> 12 | <- 10 +12: Exit block[DEAD] -> 13 | <- 11 +13: Exit loop block[DEAD] -> 3 | <- 12 +14: Exit whileloop -> 15 | <- 5, 10 +15: Access variable R|/x| -> 16 | <- 14 +16: Function call: R|/x|.#() -> 17 | <- 15 +17: Exit block -> 18 | <- 16 +18: Exit function "test_3" -> | <- 17 + + 0: Enter function "test_4" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter do-while loop -> 3 | <- 1 + 3: Enter loop block -> 4 | <- 2, 13[DEAD] + 4: Enter block -> 5 | <- 3 + 5: Access variable R|/x| -> 6 | <- 4 + 6: Type operator: "x as int" -> 7 | <- 5 + 7: Jump: break@@@[Boolean(true)] -> 8[DEAD], 14[DEAD] | <- 6 + 8: Stub[DEAD] -> 9 | <- 7 + 9: Exit block[DEAD] -> 10 | <- 8 +10: Exit loop block[DEAD] -> 11 | <- 9 +11: Enter loop condition[DEAD] -> 12 | <- 10 +12: Const: Boolean(true)[DEAD] -> 13 | <- 11 +13: Exit loop condition[DEAD] -> 3, 14 | <- 12 +14: Exit do-whileloop[DEAD] -> 15 | <- 7, 13 +15: Access variable R|/x|[DEAD] -> 16 | <- 14 +16: Function call: R|/x|.#()[DEAD] -> 17 | <- 15 +17: Exit block[DEAD] -> 18 | <- 16 +18: Exit function "test_4"[DEAD] -> | <- 17 + diff --git a/compiler/fir/resolve/testData/resolve/cfg/jumps.kt b/compiler/fir/resolve/testData/resolve/cfg/jumps.kt new file mode 100644 index 00000000000..7c073e5afd7 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/jumps.kt @@ -0,0 +1,33 @@ +fun test_1(x: Int?) { + val y = if (x == null) { + throw KotlinNullPointerException() + } else { + x + } + y.inc() +} + +fun test_2(x: Int?) { + val y = if (x == null) { + x + } else { + x + } + y.inc() +} + +fun test_3(x: Int?) { + while (true) { + x as Int + break + } + x.inc() +} + +fun test_4(x: Int?) { + do { + x as int + break + } while (true) + x.inc() +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/cfg/jumps.txt b/compiler/fir/resolve/testData/resolve/cfg/jumps.txt new file mode 100644 index 00000000000..01a60bbdbe0 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/jumps.txt @@ -0,0 +1,41 @@ +FILE: jumps.kt + public final fun test_1(x: R|kotlin/Int?|): R|kotlin/Unit| { + lval y: R|kotlin/Int?| = when () { + ==(R|/x|, Null(null)) -> { + throw R|kotlin/KotlinNullPointerException.KotlinNullPointerException|() + } + else -> { + R|/x| + } + } + + R|/y|.#() + } + public final fun test_2(x: R|kotlin/Int?|): R|kotlin/Unit| { + lval y: R|kotlin/Int?| = when () { + ==(R|/x|, Null(null)) -> { + R|/x| + } + else -> { + R|/x| + } + } + + R|/y|.#() + } + public final fun test_3(x: R|kotlin/Int?|): R|kotlin/Unit| { + while(Boolean(true)) { + (R|/x| as R|kotlin/Int|) + break@@@[Boolean(true)] + } + + R|/x|.#() + } + public final fun test_4(x: R|kotlin/Int?|): R|kotlin/Unit| { + do { + (R|/x| as R|class error: Symbol not found, for `int`|) + break@@@[Boolean(true)] + } + while(Boolean(true)) + R|/x|.#() + } diff --git a/compiler/fir/resolve/testData/resolve/cfg/loops.cfg.txt b/compiler/fir/resolve/testData/resolve/cfg/loops.cfg.txt new file mode 100644 index 00000000000..b6adb057b90 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/loops.cfg.txt @@ -0,0 +1,68 @@ + 0: Enter function "testWhile" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter while loop -> 3 | <- 1 + 3: Enter loop condition -> 4 | <- 2, 12 + 4: Access variable R|/b| -> 5 | <- 3 + 5: Exit loop condition -> 6, 13 | <- 4 + 6: Enter loop block -> 7 | <- 5 + 7: Enter block -> 8 | <- 6 + 8: Access variable R|/x| -> 9 | <- 7 + 9: Type operator: "x is String" -> 10 | <- 8 +10: Variable declaration: lval y: R|kotlin/Boolean| -> 11 | <- 9 +11: Exit block -> 12 | <- 10 +12: Exit loop block -> 3 | <- 11 +13: Exit whileloop -> 14 | <- 5 +14: Access variable R|/x| -> 15 | <- 13 +15: Type operator: "x is String" -> 16 | <- 14 +16: Exit block -> 17 | <- 15 +17: Exit function "testWhile" -> | <- 16 + + 0: Enter function "testDoWhile" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter do-while loop -> 3 | <- 1 + 3: Enter loop block -> 4 | <- 2, 12 + 4: Enter block -> 5 | <- 3 + 5: Access variable R|/x| -> 6 | <- 4 + 6: Type operator: "x is String" -> 7 | <- 5 + 7: Variable declaration: lval y: R|kotlin/Boolean| -> 8 | <- 6 + 8: Exit block -> 9 | <- 7 + 9: Exit loop block -> 10 | <- 8 +10: Enter loop condition -> 11 | <- 9 +11: Access variable R|/b| -> 12 | <- 10 +12: Exit loop condition -> 3, 13 | <- 11 +13: Exit do-whileloop -> 14 | <- 12 +14: Access variable R|/x| -> 15 | <- 13 +15: Type operator: "x is String" -> 16 | <- 14 +16: Exit block -> 17 | <- 15 +17: Exit function "testDoWhile" -> | <- 16 + + 0: Enter function "testFor" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Const: Int(0) -> 3 | <- 1 + 3: Const: Int(5) -> 4 | <- 2 + 4: Function call: Int(0).R|kotlin/Int.rangeTo|(Int(5)) -> 5 | <- 3 + 5: Variable declaration: lval : R|kotlin/ranges/IntRange| -> 6 | <- 4 + 6: Access variable R|/| -> 7 | <- 5 + 7: Function call: R|/|.R|kotlin/ranges/IntProgression.iterator|() -> 8 | <- 6 + 8: Variable declaration: lval : R|kotlin/collections/IntIterator| -> 9 | <- 7 + 9: Enter while loop -> 10 | <- 8 +10: Enter loop condition -> 11 | <- 9, 23 +11: Access variable R|/| -> 12 | <- 10 +12: Function call: R|/|.R|FakeOverride|() -> 13 | <- 11 +13: Exit loop condition -> 14, 24 | <- 12 +14: Enter loop block -> 15 | <- 13 +15: Enter block -> 16 | <- 14 +16: Access variable R|/| -> 17 | <- 15 +17: Function call: R|/|.R|kotlin/collections/IntIterator.next|() -> 18 | <- 16 +18: Variable declaration: lval i: R|kotlin/Int| -> 19 | <- 17 +19: Access variable R|/x| -> 20 | <- 18 +20: Type operator: "x is String" -> 21 | <- 19 +21: Variable declaration: lval y: R|kotlin/Boolean| -> 22 | <- 20 +22: Exit block -> 23 | <- 21 +23: Exit loop block -> 10 | <- 22 +24: Exit whileloop -> 25 | <- 13 +25: Access variable R|/x| -> 26 | <- 24 +26: Type operator: "x is String" -> 27 | <- 25 +27: Exit block -> 28 | <- 26 +28: Exit function "testFor" -> | <- 27 + diff --git a/compiler/fir/resolve/testData/resolve/cfg/loops.kt b/compiler/fir/resolve/testData/resolve/cfg/loops.kt new file mode 100644 index 00000000000..a939f97fe25 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/loops.kt @@ -0,0 +1,20 @@ +fun testWhile(b: Boolean, x: Any?) { + while (b) { + val y = x is String + } + x is String +} + +fun testDoWhile(b: Boolean, x: Any?) { + do { + val y = x is String + } while (b) + x is String +} + +fun testFor(x: Any?) { + for (i in 0..5) { + val y = x is String + } + x is String +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/cfg/loops.txt b/compiler/fir/resolve/testData/resolve/cfg/loops.txt new file mode 100644 index 00000000000..f13ada73e89 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/loops.txt @@ -0,0 +1,25 @@ +FILE: loops.kt + public final fun testWhile(b: R|kotlin/Boolean|, x: R|kotlin/Any?|): R|kotlin/Unit| { + while(R|/b|) { + lval y: R|kotlin/Boolean| = (R|/x| is R|kotlin/String|) + } + + (R|/x| is R|kotlin/String|) + } + public final fun testDoWhile(b: R|kotlin/Boolean|, x: R|kotlin/Any?|): R|kotlin/Unit| { + do { + lval y: R|kotlin/Boolean| = (R|/x| is R|kotlin/String|) + } + while(R|/b|) + (R|/x| is R|kotlin/String|) + } + public final fun testFor(x: R|kotlin/Any?|): R|kotlin/Unit| { + lval : R|kotlin/ranges/IntRange| = Int(0).R|kotlin/Int.rangeTo|(Int(5)) + lval : R|kotlin/collections/IntIterator| = R|/|.R|kotlin/ranges/IntProgression.iterator|() + while(R|/|.R|FakeOverride|()) { + lval i: R|kotlin/Int| = R|/|.R|kotlin/collections/IntIterator.next|() + lval y: R|kotlin/Boolean| = (R|/x| is R|kotlin/String|) + } + + (R|/x| is R|kotlin/String|) + } diff --git a/compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.cfg.txt b/compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.cfg.txt new file mode 100644 index 00000000000..1790f860cc9 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.cfg.txt @@ -0,0 +1,113 @@ +0: Enter function "run" -> 1 +1: Enter block -> 2 | <- 0 +2: Function call: R|/block|.R|FakeOverride|() -> 3 | <- 1 +3: Exit block -> 4 | <- 2 +4: Exit function "run" -> | <- 3 + +0: Enter property -> 1 +1: Const: Int(1) -> 2 | <- 0 +2: Exit property -> | <- 1 + +0: Enter function "getter" -> 1 +1: Enter block -> 2 | <- 0 +2: Const: Int(1) -> 3 | <- 1 +3: Jump: ^ Int(1) -> 4[DEAD], 6[DEAD] | <- 2 +4: Stub[DEAD] -> 5 | <- 3 +5: Exit block[DEAD] -> 6 | <- 4 +6: Exit function "getter"[DEAD] -> | <- 3, 5 + +0: Enter function "setter" -> 1 +1: Enter block -> 2 | <- 0 +2: Const: Int(1) -> 3 | <- 1 +3: Assignmenet: F|/x2| -> 4 | <- 2 +4: Exit block -> 5 | <- 3 +5: Exit function "setter" -> | <- 4 + +0: Enter property -> 1 +1: Const: Int(1) -> 2 | <- 0 +2: Exit property -> | <- 1 + + 0: Enter init block -> 1 + 1: Enter block -> 2 | <- 0 + 2: Function call: #() -> 3 | <- 1 + 3: Throw: throw #() -> 4[DEAD], 7[DEAD] | <- 2 + 4: Stub[DEAD] -> 5 | <- 3 + 5: Const: Int(1)[DEAD] -> 6 | <- 4 + 6: Exit block[DEAD] -> 7 | <- 5 + 7: Exit init block[DEAD] -> | <- 3, 6 + 8: Enter function "anonymousFunction" -> 9 + 9: Enter block -> 10 | <- 8 +10: Function call: #() -> 11 | <- 9 +11: Throw: throw #() -> 12[DEAD], 14[DEAD] | <- 10 +12: Stub[DEAD] -> 13 | <- 11 +13: Exit block[DEAD] -> 14 | <- 12 +14: Exit function "anonymousFunction"[DEAD] -> | <- 11, 13 + + 0: Enter function "foo" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Const: Int(1) -> 3 | <- 1 + 3: Const: Int(1) -> 4 | <- 2 + 4: Function call: Int(1).R|kotlin/Int.plus|(Int(1)) -> 5 | <- 3 + 5: Variable declaration: lval c: R|kotlin/Int| -> 6 | <- 4 + 6: Function call: #() -> 7 | <- 5 + 7: Throw: throw #() -> 8[DEAD], 10[DEAD] | <- 6 + 8: Stub[DEAD] -> 9 | <- 7 + 9: Exit block[DEAD] -> 10 | <- 8 +10: Exit function "foo"[DEAD] -> | <- 7, 9 + + 0: Enter init block -> 1 + 1: Enter block -> 2 | <- 0 + 2: Function call: #() -> 3 | <- 1 + 3: Throw: throw #() -> 4[DEAD], 6[DEAD] | <- 2 + 4: Stub[DEAD] -> 5 | <- 3 + 5: Exit block[DEAD] -> 6 | <- 4 + 6: Exit init block[DEAD] -> | <- 3, 5 + 7: Enter function "getter" -> 8 + 8: Enter block -> 9 | <- 7 + 9: Exit block -> 10 | <- 8 +10: Exit function "getter" -> | <- 9 + +0: Enter property -> 1 +1: Function call: R|/run|( = run@fun (): R|kotlin/Unit| { + local final fun foo(): R|kotlin/Unit| { + lval c: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(1)) + throw #() + } + + local final class LocalClass : R|kotlin/Any| { + public constructor(): R|LocalClass| { + super() + } + + init { + throw #() + Int(1) + } + + } + + throw #() +} +) -> 2 | <- 0 +2: Exit property -> | <- 1 + + 0: Enter property -> 1 + 1: Try expression enter -> 2 | <- 0 + 2: Try main block enter -> 3, 7, 12, 18 | <- 1 + 3: Enter block -> 4 | <- 2 + 4: Const: Int(1) -> 5 | <- 3 + 5: Exit block -> 6 | <- 4 + 6: Try main block exit -> 17 | <- 5 + 7: Enter finally -> 8 | <- 2 + 8: Enter block -> 9 | <- 7 + 9: Const: Int(0) -> 10 | <- 8 +10: Exit block -> 11 | <- 9 +11: Exit finally -> 17 | <- 10 +12: Catch enter -> 13, 18 | <- 2 +13: Enter block -> 14 | <- 12 +14: Const: Int(2) -> 15 | <- 13 +15: Exit block -> 16 | <- 14 +16: Catch exit -> 17 | <- 15 +17: Try expression exit -> 18 | <- 6, 11, 16 +18: Exit property -> | <- 2, 12, 17 + diff --git a/compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.kt b/compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.kt new file mode 100644 index 00000000000..6ae6c3a2029 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.kt @@ -0,0 +1,42 @@ +fun run(block: () -> Unit) { + block() +} + +val x1 = 1 + +var x2: Int = 1 + get() = 1 + set(value) { + field = 1 + } + +val x3 = run { + fun foo() { + val c = 1 + 1 + throw Exception() + } + + class LocalClass { + init { + throw Exception() + 1 + } + } + + throw Exception() +} + get() { + class LocalClass { + init { + throw Exception() + } + } + } + +val x4 = try { + 1 +} catch (e: Exception) { + 2 +} finally { + 0 +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.txt b/compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.txt new file mode 100644 index 00000000000..19e8e72b211 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.txt @@ -0,0 +1,58 @@ +FILE: propertiesAndInitBlocks.kt + public final fun run(block: R|kotlin/Function0|): R|kotlin/Unit| { + R|/block|.R|FakeOverride|() + } + public final val x1: R|kotlin/Int| = Int(1) + public get(): R|kotlin/Int| + public final var x2: R|kotlin/Int| = Int(1) + public get(): R|kotlin/Int| { + ^ Int(1) + } + public set(value: R|kotlin/Int|): R|kotlin/Unit| { + F|/x2| = Int(1) + } + public final val x3: R|kotlin/Unit| = R|/run|( = run@fun (): R|kotlin/Unit| { + local final fun foo(): R|kotlin/Unit| { + lval c: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(1)) + throw #() + } + + local final class LocalClass : R|kotlin/Any| { + public constructor(): R|LocalClass| { + super() + } + + init { + throw #() + Int(1) + } + + } + + throw #() + } + ) + public get(): R|kotlin/Unit| { + local final class LocalClass : R|kotlin/Any| { + public constructor(): R|LocalClass| { + super() + } + + init { + throw #() + } + + } + + } + public final val x4: R|kotlin/Int| = try { + Int(1) + } + catch (e: R|kotlin/Exception|) { + Int(2) + } + finally { + Int(0) + } + + public get(): R|kotlin/Int| diff --git a/compiler/fir/resolve/testData/resolve/cfg/simple.cfg.txt b/compiler/fir/resolve/testData/resolve/cfg/simple.cfg.txt new file mode 100644 index 00000000000..98224f6350d --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/simple.cfg.txt @@ -0,0 +1,17 @@ +0: Enter function "foo" -> 1 +1: Enter block -> 2 | <- 0 +2: Exit block -> 3 | <- 1 +3: Exit function "foo" -> | <- 2 + + 0: Enter function "test" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Const: Int(1) -> 3 | <- 1 + 3: Variable declaration: lval x: R|kotlin/Int| -> 4 | <- 2 + 4: Access variable R|/x| -> 5 | <- 3 + 5: Const: Int(1) -> 6 | <- 4 + 6: Function call: R|/x|.R|kotlin/Int.plus|(Int(1)) -> 7 | <- 5 + 7: Variable declaration: lval y: R|kotlin/Int| -> 8 | <- 6 + 8: Function call: R|/foo|() -> 9 | <- 7 + 9: Exit block -> 10 | <- 8 +10: Exit function "test" -> | <- 9 + diff --git a/compiler/fir/resolve/testData/resolve/cfg/simple.kt b/compiler/fir/resolve/testData/resolve/cfg/simple.kt new file mode 100644 index 00000000000..17e3f2774b4 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/simple.kt @@ -0,0 +1,7 @@ +fun foo() {} + +fun test() { + val x = 1 + val y = x + 1 + foo() +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/cfg/simple.txt b/compiler/fir/resolve/testData/resolve/cfg/simple.txt new file mode 100644 index 00000000000..b9854a8c3b9 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/simple.txt @@ -0,0 +1,8 @@ +FILE: simple.kt + public final fun foo(): R|kotlin/Unit| { + } + public final fun test(): R|kotlin/Unit| { + lval x: R|kotlin/Int| = Int(1) + lval y: R|kotlin/Int| = R|/x|.R|kotlin/Int.plus|(Int(1)) + R|/foo|() + } diff --git a/compiler/fir/resolve/testData/resolve/cfg/tryCatch.cfg.txt b/compiler/fir/resolve/testData/resolve/cfg/tryCatch.cfg.txt new file mode 100644 index 00000000000..42ee6b77b17 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/tryCatch.cfg.txt @@ -0,0 +1,112 @@ + 0: Enter function "test_1" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Try expression enter -> 3 | <- 1 + 3: Try main block enter -> 4, 9, 15, 23 | <- 2 + 4: Enter block -> 5 | <- 3 + 5: Const: Int(1) -> 6 | <- 4 + 6: Variable declaration: lval x: R|kotlin/Int| -> 7 | <- 5 + 7: Exit block -> 8 | <- 6 + 8: Try main block exit -> 21 | <- 7 + 9: Catch enter -> 10, 23 | <- 3 +10: Enter block -> 11 | <- 9 +11: Const: Int(3) -> 12 | <- 10 +12: Variable declaration: lval z: R|kotlin/Int| -> 13 | <- 11 +13: Exit block -> 14 | <- 12 +14: Catch exit -> 21 | <- 13 +15: Catch enter -> 16, 23 | <- 3 +16: Enter block -> 17 | <- 15 +17: Const: Int(2) -> 18 | <- 16 +18: Variable declaration: lval y: R|kotlin/Int| -> 19 | <- 17 +19: Exit block -> 20 | <- 18 +20: Catch exit -> 21 | <- 19 +21: Try expression exit -> 22 | <- 8, 14, 20 +22: Exit block -> 23 | <- 21 +23: Exit function "test_1" -> | <- 3, 9, 15, 22 + + 0: Enter function "test_2" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Try expression enter -> 3 | <- 1 + 3: Try main block enter -> 4, 8, 16 | <- 2 + 4: Enter block -> 5 | <- 3 + 5: Const: Int(1) -> 6 | <- 4 + 6: Exit block -> 7 | <- 5 + 7: Try main block exit -> 13 | <- 6 + 8: Catch enter -> 9, 16 | <- 3 + 9: Enter block -> 10 | <- 8 +10: Const: Int(2) -> 11 | <- 9 +11: Exit block -> 12 | <- 10 +12: Catch exit -> 13 | <- 11 +13: Try expression exit -> 14 | <- 7, 12 +14: Variable declaration: lval x: R|kotlin/Int| -> 15 | <- 13 +15: Exit block -> 16 | <- 14 +16: Exit function "test_2" -> | <- 3, 8, 15 + + 0: Enter function "test_3" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter while loop -> 3 | <- 1 + 3: Enter loop condition -> 4 | <- 2, 54, 62 + 4: Const: Boolean(true) -> 5 | <- 3 + 5: Exit loop condition -> 6, 63 | <- 4 + 6: Enter loop block -> 7 | <- 5 + 7: Enter block -> 8 | <- 6 + 8: Try expression enter -> 9 | <- 7 + 9: Try main block enter -> 10, 46, 52, 67 | <- 8 +10: Enter block -> 11 | <- 9 +11: Enter when -> 12 | <- 10 +12: Enter when branch condition -> 13 | <- 11 +13: Access variable R|/b| -> 14 | <- 12 +14: Exit when branch condition -> 15, 20 | <- 13 +15: Enter block -> 16 | <- 14 +16: Jump: ^test_3 Unit -> 17[DEAD], 67 | <- 15 +17: Stub[DEAD] -> 18 | <- 16 +18: Exit block[DEAD] -> 19 | <- 17 +19: Exit when branch result[DEAD] -> 25 | <- 18 +20: Enter when branch condition "else" -> 21 | <- 14 +21: Exit when branch condition -> 22 | <- 20 +22: Enter block -> 23 | <- 21 +23: Exit block -> 24 | <- 22 +24: Exit when branch result -> 25 | <- 23 +25: Exit when -> 26 | <- 19[DEAD], 24 +26: Const: Int(1) -> 27 | <- 25 +27: Variable declaration: lval x: R|kotlin/Int| -> 28 | <- 26 +28: Enter when -> 29 | <- 27 +29: Enter when branch condition -> 30 | <- 28 +30: Access variable R|/b| -> 31 | <- 29 +31: Function call: R|/b|.R|kotlin/Boolean.not|() -> 32 | <- 30 +32: Exit when branch condition -> 33, 38 | <- 31 +33: Enter block -> 34 | <- 32 +34: Jump: break@@@[Boolean(true)] -> 35[DEAD], 63 | <- 33 +35: Stub[DEAD] -> 36 | <- 34 +36: Exit block[DEAD] -> 37 | <- 35 +37: Exit when branch result[DEAD] -> 43 | <- 36 +38: Enter when branch condition "else" -> 39 | <- 32 +39: Exit when branch condition -> 40 | <- 38 +40: Enter block -> 41 | <- 39 +41: Exit block -> 42 | <- 40 +42: Exit when branch result -> 43 | <- 41 +43: Exit when -> 44 | <- 37[DEAD], 42 +44: Exit block -> 45 | <- 43 +45: Try main block exit -> 58 | <- 44 +46: Catch enter -> 47, 67 | <- 9 +47: Enter block -> 48 | <- 46 +48: Jump: break@@@[Boolean(true)] -> 49[DEAD], 63 | <- 47 +49: Stub[DEAD] -> 50 | <- 48 +50: Exit block[DEAD] -> 51 | <- 49 +51: Catch exit[DEAD] -> 58 | <- 50 +52: Catch enter -> 53, 67 | <- 9 +53: Enter block -> 54 | <- 52 +54: Jump: continue@@@[Boolean(true)] -> 3, 55[DEAD] | <- 53 +55: Stub[DEAD] -> 56 | <- 54 +56: Exit block[DEAD] -> 57 | <- 55 +57: Catch exit[DEAD] -> 58 | <- 56 +58: Try expression exit -> 59 | <- 45, 51[DEAD], 57[DEAD] +59: Const: Int(2) -> 60 | <- 58 +60: Variable declaration: lval y: R|kotlin/Int| -> 61 | <- 59 +61: Exit block -> 62 | <- 60 +62: Exit loop block -> 3 | <- 61 +63: Exit whileloop -> 64 | <- 5, 34, 48 +64: Const: Int(3) -> 65 | <- 63 +65: Variable declaration: lval z: R|kotlin/Int| -> 66 | <- 64 +66: Exit block -> 67 | <- 65 +67: Exit function "test_3" -> | <- 9, 16, 46, 52, 66 + diff --git a/compiler/fir/resolve/testData/resolve/cfg/tryCatch.kt b/compiler/fir/resolve/testData/resolve/cfg/tryCatch.kt new file mode 100644 index 00000000000..66cd1bcef0b --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/tryCatch.kt @@ -0,0 +1,33 @@ +fun test_1() { + try { + val x = 1 + } catch (e: RuntimeException) { + val y = 2 + } catch (e: Exception) { + val z = 3 + } +} + +fun test_2() { + val x = try { + 1 + } catch (e: Exception) { + 2 + } +} + +fun test_3(b: Boolean) { + while (true) { + try { + if (b) return + val x = 1 + if (!b) break + } catch (e: Exception) { + continue + } catch (e: RuntimeException) { + break + } + val y = 2 + } + val z = 3 +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/cfg/tryCatch.txt b/compiler/fir/resolve/testData/resolve/cfg/tryCatch.txt new file mode 100644 index 00000000000..c0d35202922 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/tryCatch.txt @@ -0,0 +1,55 @@ +FILE: tryCatch.kt + public final fun test_1(): R|kotlin/Unit| { + try { + lval x: R|kotlin/Int| = Int(1) + } + catch (e: R|kotlin/RuntimeException|) { + lval y: R|kotlin/Int| = Int(2) + } + catch (e: R|kotlin/Exception|) { + lval z: R|kotlin/Int| = Int(3) + } + + } + public final fun test_2(): R|kotlin/Unit| { + lval x: R|kotlin/Int| = try { + Int(1) + } + catch (e: R|kotlin/Exception|) { + Int(2) + } + + } + public final fun test_3(b: R|kotlin/Boolean|): R|kotlin/Unit| { + while(Boolean(true)) { + try { + when () { + R|/b| -> { + ^test_3 Unit + } + else -> { + } + } + + lval x: R|kotlin/Int| = Int(1) + when () { + R|/b|.R|kotlin/Boolean.not|() -> { + break@@@[Boolean(true)] + } + else -> { + } + } + + } + catch (e: R|kotlin/Exception|) { + continue@@@[Boolean(true)] + } + catch (e: R|kotlin/RuntimeException|) { + break@@@[Boolean(true)] + } + + lval y: R|kotlin/Int| = Int(2) + } + + lval z: R|kotlin/Int| = Int(3) + } diff --git a/compiler/fir/resolve/testData/resolve/cfg/when.cfg.txt b/compiler/fir/resolve/testData/resolve/cfg/when.cfg.txt new file mode 100644 index 00000000000..d0c1a470c56 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/when.cfg.txt @@ -0,0 +1,71 @@ + 0: Enter function "test_1" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter when -> 3 | <- 1 + 3: Enter when branch condition -> 4 | <- 2 + 4: Access variable R|/x| -> 5 | <- 3 + 5: Const: Int(1) -> 6 | <- 4 + 6: Operator == -> 7 | <- 5 + 7: Exit when branch condition -> 8, 12 | <- 6 + 8: Enter block -> 9 | <- 7 + 9: Const: Int(10) -> 10 | <- 8 +10: Exit block -> 11 | <- 9 +11: Exit when branch result -> 41 | <- 10 +12: Enter when branch condition -> 13 | <- 7 +13: Access variable R|/x| -> 14 | <- 12 +14: Const: Int(2) -> 15 | <- 13 +15: Function call: R|/x|.R|kotlin/Int.rem|(Int(2)) -> 16 | <- 14 +16: Const: Int(0) -> 17 | <- 15 +17: Operator == -> 18 | <- 16 +18: Exit when branch condition -> 19, 23 | <- 17 +19: Enter block -> 20 | <- 18 +20: Const: Int(20) -> 21 | <- 19 +21: Exit block -> 22 | <- 20 +22: Exit when branch result -> 41 | <- 21 +23: Enter when branch condition -> 24 | <- 18 +24: Const: Int(1) -> 25 | <- 23 +25: Const: Int(1) -> 26 | <- 24 +26: Function call: Int(1).R|kotlin/Int.minus|(Int(1)) -> 27 | <- 25 +27: Const: Int(0) -> 28 | <- 26 +28: Operator == -> 29 | <- 27 +29: Exit when branch condition -> 30, 35 | <- 28 +30: Enter block -> 31 | <- 29 +31: Jump: ^test_1 Unit -> 32[DEAD], 44 | <- 30 +32: Stub[DEAD] -> 33 | <- 31 +33: Exit block[DEAD] -> 34 | <- 32 +34: Exit when branch result[DEAD] -> 41 | <- 33 +35: Enter when branch condition "else" -> 36 | <- 29 +36: Exit when branch condition -> 37 | <- 35 +37: Enter block -> 38 | <- 36 +38: Const: Int(5) -> 39 | <- 37 +39: Exit block -> 40 | <- 38 +40: Exit when branch result -> 41 | <- 39 +41: Exit when -> 42 | <- 11, 22, 34[DEAD], 40 +42: Variable declaration: lval y: R|kotlin/Int| -> 43 | <- 41 +43: Exit block -> 44 | <- 42 +44: Exit function "test_1" -> | <- 31, 43 + + 0: Enter function "test_2" -> 1 + 1: Enter block -> 2 | <- 0 + 2: Enter when -> 3 | <- 1 + 3: Enter when branch condition -> 4 | <- 2 + 4: Enter && -> 5 | <- 3 + 5: Access variable R|/x| -> 6 | <- 4 + 6: Type operator: "x is A" -> 7, 9 | <- 5 + 7: Access variable R|/x| -> 8 | <- 6 + 8: Type operator: "x is B" -> 9 | <- 7 + 9: Exit && -> 10 | <- 6, 8 +10: Exit when branch condition -> 11, 16 | <- 9 +11: Enter block -> 12 | <- 10 +12: Access variable R|/x| -> 13 | <- 11 +13: Type operator: "x is A" -> 14 | <- 12 +14: Exit block -> 15 | <- 13 +15: Exit when branch result -> 21 | <- 14 +16: Enter when branch condition "else" -> 17 | <- 10 +17: Exit when branch condition -> 18 | <- 16 +18: Enter block -> 19 | <- 17 +19: Exit block -> 20 | <- 18 +20: Exit when branch result -> 21 | <- 19 +21: Exit when -> 22 | <- 15, 20 +22: Exit block -> 23 | <- 21 +23: Exit function "test_2" -> | <- 22 + diff --git a/compiler/fir/resolve/testData/resolve/cfg/when.kt b/compiler/fir/resolve/testData/resolve/cfg/when.kt new file mode 100644 index 00000000000..478098e3817 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/when.kt @@ -0,0 +1,17 @@ +fun test_1(x: Int) { + val y = when { + x == 1 -> 10 + x % 2 == 0 -> 20 + 1 - 1 == 0 -> return + else -> 5 + } +} + +interface A +interface B + +fun test_2(x: Any?) { + if (x is A && x is B) { + x is A + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/cfg/when.txt b/compiler/fir/resolve/testData/resolve/cfg/when.txt new file mode 100644 index 00000000000..47a9c7deb71 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/cfg/when.txt @@ -0,0 +1,32 @@ +FILE: when.kt + public final fun test_1(x: R|kotlin/Int|): R|kotlin/Unit| { + lval y: R|kotlin/Int| = when () { + ==(R|/x|, Int(1)) -> { + Int(10) + } + ==(R|/x|.R|kotlin/Int.rem|(Int(2)), Int(0)) -> { + Int(20) + } + ==(Int(1).R|kotlin/Int.minus|(Int(1)), Int(0)) -> { + ^test_1 Unit + } + else -> { + Int(5) + } + } + + } + public abstract interface A : R|kotlin/Any| { + } + public abstract interface B : R|kotlin/Any| { + } + public final fun test_2(x: R|kotlin/Any?|): R|kotlin/Unit| { + when () { + (R|/x| is R|A|) && (R|/x| is R|B|) -> { + (R|/x| is R|A|) + } + else -> { + } + } + + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirCfgBuildingTest.kt b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirCfgBuildingTest.kt new file mode 100644 index 00000000000..c4e689e0e9e --- /dev/null +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirCfgBuildingTest.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir + +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference +import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl +import org.jetbrains.kotlin.fir.resolve.dfa.cfg.renderToStringBuilder +import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid +import org.jetbrains.kotlin.test.ConfigurationKind +import org.jetbrains.kotlin.test.KotlinTestUtils +import java.io.File + +abstract class AbstractFirCfgBuildingTest : AbstractFirResolveTestCase() { + override val configurationKind: ConfigurationKind + get() = ConfigurationKind.ALL + + override fun doTest(path: String) { + val firFiles = processInputFile(path) + checkCfg(path, firFiles) + checkFir(path, firFiles) + } + + fun checkCfg(path: String, firFiles: List) { + val firFileDump = StringBuilder().also { firFiles.first().accept(FirControlFlowGraphRenderVisitor(it), null) }.toString() + val expectedPath = path.replace(".kt", ".cfg.txt") + KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump) + } + + private class FirControlFlowGraphRenderVisitor(private val builder: StringBuilder) : FirVisitorVoid() { + override fun visitElement(element: FirElement) { + element.acceptChildren(this) + } + + override fun visitControlFlowGraphReference(controlFlowGraphReference: FirControlFlowGraphReference) { + (controlFlowGraphReference as? FirControlFlowGraphReferenceImpl)?.controlFlowGraph?.renderToStringBuilder(builder) + } + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveTestCase.kt b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveTestCase.kt index 70b8cc62a3a..a3fd03f7d5c 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveTestCase.kt +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/AbstractFirResolveTestCase.kt @@ -19,8 +19,10 @@ import org.jetbrains.kotlin.test.KotlinTestUtils import java.io.File abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCase() { + open val configurationKind: ConfigurationKind get() = ConfigurationKind.JDK_NO_RUNTIME + override fun createEnvironment(): KotlinCoreEnvironment { - return createEnvironmentWithMockJdk(ConfigurationKind.JDK_NO_RUNTIME) + return createEnvironmentWithMockJdk(configurationKind) } private fun doCreateAndProcessFir(ktFiles: List): List { @@ -46,8 +48,7 @@ abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCas } } - - fun doTest(path: String) { + protected fun processInputFile(path: String): List { val file = File(path) val allFiles = listOf(file) + file.parentFile.listFiles { sibling -> @@ -66,8 +67,14 @@ abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCas KotlinTestUtils.createFile(name, text, project) } - val firFiles = doCreateAndProcessFir(ktFiles) + return doCreateAndProcessFir(ktFiles) + } + open fun doTest(path: String) { + checkFir(path, processInputFile(path)) + } + + fun checkFir(path: String, firFiles: List) { val firFileDump = StringBuilder().also { firFiles.first().accept(FirRenderer(it), null) }.toString() val expectedPath = path.replace(".kt", ".txt") KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump) diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java new file mode 100644 index 00000000000..c618bbe61ca --- /dev/null +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirCfgBuildingTestGenerated.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/fir/resolve/testData/resolve/cfg") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class FirCfgBuildingTestGenerated extends AbstractFirCfgBuildingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInCfg() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve/cfg"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("binaryOperations.kt") + public void testBinaryOperations() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/binaryOperations.kt"); + } + + @TestMetadata("complex.kt") + public void testComplex() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/complex.kt"); + } + + @TestMetadata("initBlock.kt") + public void testInitBlock() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/initBlock.kt"); + } + + @TestMetadata("jumps.kt") + public void testJumps() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/jumps.kt"); + } + + @TestMetadata("loops.kt") + public void testLoops() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/loops.kt"); + } + + @TestMetadata("propertiesAndInitBlocks.kt") + public void testPropertiesAndInitBlocks() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/propertiesAndInitBlocks.kt"); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/simple.kt"); + } + + @TestMetadata("tryCatch.kt") + public void testTryCatch() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/tryCatch.kt"); + } + + @TestMetadata("when.kt") + public void testWhen() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/cfg/when.kt"); + } +} diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java index 3768150d57a..71c1c7f8e08 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseGenerated.java @@ -26,7 +26,7 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase { } public void testAllFilesPresentInResolve() throws Exception { - KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true, "stdlib"); + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true, "stdlib", "cfg"); } @TestMetadata("cast.kt") diff --git a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt index 55f0f11c514..78a789b12dd 100644 --- a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt +++ b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt @@ -17,11 +17,7 @@ import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.defaultConstructor.AbstractDefaultArgumentsReflectionTest import org.jetbrains.kotlin.codegen.flags.AbstractWriteFlagsTest import org.jetbrains.kotlin.codegen.ir.* -import org.jetbrains.kotlin.fir.AbstractFirDiagnosticsSmokeTest -import org.jetbrains.kotlin.fir.AbstractFirLoadCompiledKotlin -import org.jetbrains.kotlin.fir.AbstractFir2IrTextTest -import org.jetbrains.kotlin.fir.AbstractFirResolveTestCase -import org.jetbrains.kotlin.fir.AbstractFirResolveTestCaseWithStdlib +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase import org.jetbrains.kotlin.fir.java.AbstractFirTypeEnhancementTest import org.jetbrains.kotlin.fir.java.AbstractOwnFirTypeEnhancementTest @@ -443,12 +439,16 @@ fun main(args: Array) { testGroup("compiler/fir/resolve/tests", "compiler/fir/resolve/testData") { testClass { - model("resolve", pattern = KT_WITHOUT_DOTS_IN_NAME, excludeDirs = listOf("stdlib")) + model("resolve", pattern = KT_WITHOUT_DOTS_IN_NAME, excludeDirs = listOf("stdlib", "cfg")) } testClass { model("resolve/stdlib", pattern = KT_WITHOUT_DOTS_IN_NAME) } + + testClass { + model("resolve/cfg", pattern = KT_WITHOUT_DOTS_IN_NAME) + } } testGroup("compiler/fir/resolve/tests", "compiler/testData") {