[FIR] Add renderer to .dot for control flow graph tests

This commit is contained in:
Dmitriy Novozhilov
2019-08-23 11:21:10 +03:00
parent 2e501e0f97
commit b4a4d4d709
16 changed files with 1411 additions and 34 deletions
@@ -38,7 +38,8 @@ class Flow(
to: DataFlowVariable,
transform: ((UnapprovedFirDataFlowInfo) -> UnapprovedFirDataFlowInfo)? = null
): Flow {
if (isFrozen) copyForBuilding().copyNotApprovedFacts(from, to)
if (isFrozen)
return copyForBuilding().copyNotApprovedFacts(from, to, transform)
var facts = if (from.isSynthetic) {
notApprovedFacts.removeAll(from)
} else {
@@ -22,8 +22,11 @@ import org.jetbrains.kotlin.utils.DFS
private const val INDENT = " "
private const val DEAD = "[DEAD]"
fun ControlFlowGraph.renderToStringBuilder(builder: StringBuilder) {
val sortedNodes: List<CFGNode<*>> = DFS.topologicalOrder(
fun List<CFGNode<*>>.indicesMap(): Map<CFGNode<*>, Int> = mapIndexed { i, node -> node to i }.toMap()
fun ControlFlowGraph.sortNodes(): List<CFGNode<*>> {
return DFS.topologicalOrder(
nodes
) {
val result = if (it !is WhenBranchConditionExitNode || it.followingNodes.size < 2) {
@@ -33,9 +36,12 @@ fun ControlFlowGraph.renderToStringBuilder(builder: StringBuilder) {
}
result
}
}
fun ControlFlowGraph.renderToStringBuilder(builder: StringBuilder) {
val sortedNodes = sortNodes()
val indices = sortedNodes.mapIndexed { i, node -> node to i }.toMap()
val indices = sortedNodes.indicesMap()
val notVisited = sortedNodes.toMutableSet()
val maxLineNumberSize = sortedNodes.size.toString().length
@@ -0,0 +1,200 @@
digraph binaryOperations_kt {
subgraph test_1 {
0 [shape=box label="Enter function test_1"];
1 [shape=box label="Enter block"];
2 [shape=box label="Enter when"];
3 [shape=box label="Enter when branch condition "];
4 [shape=box label="Enter ||"];
5 [shape=box label="Access variable R|<local>/b1|"];
6 [shape=box label="Exit left part of ||"];
7 [shape=box label="Access variable R|<local>/b2|"];
8 [shape=box label="Exit ||"];
9 [shape=box label="Exit when branch condition"];
10 [shape=box label="Enter block"];
11 [shape=box label="Const: Int(1)"];
12 [shape=box label="Exit block"];
13 [shape=box label="Exit when branch result"];
14 [shape=box label="Enter when branch condition else"];
15 [shape=box label="Exit when branch condition"];
16 [shape=box label="Enter block"];
17 [shape=box label="Exit block"];
18 [shape=box label="Exit when branch result"];
19 [shape=box label="Exit when"];
20 [shape=box label="Exit block"];
21 [shape=box label="Exit function test_1"];
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {4};
4 -> {5 8};
5 -> {8 6};
6 -> {7};
7 -> {8};
8 -> {9};
9 -> {10 14};
10 -> {11};
11 -> {12};
12 -> {13};
13 -> {19};
14 -> {15};
15 -> {16};
16 -> {17};
17 -> {18};
18 -> {19};
19 -> {20};
20 -> {21};
}
subgraph test_2 {
22 [shape=box label="Enter function test_2"];
23 [shape=box label="Enter block"];
24 [shape=box label="Enter when"];
25 [shape=box label="Enter when branch condition "];
26 [shape=box label="Enter &&"];
27 [shape=box label="Access variable R|<local>/b1|"];
28 [shape=box label="Access variable R|<local>/b2|"];
29 [shape=box label="Exit &&"];
30 [shape=box label="Exit when branch condition"];
31 [shape=box label="Enter block"];
32 [shape=box label="Const: Int(1)"];
33 [shape=box label="Exit block"];
34 [shape=box label="Exit when branch result"];
35 [shape=box label="Enter when branch condition else"];
36 [shape=box label="Exit when branch condition"];
37 [shape=box label="Enter block"];
38 [shape=box label="Exit block"];
39 [shape=box label="Exit when branch result"];
40 [shape=box label="Exit when"];
41 [shape=box label="Exit block"];
42 [shape=box label="Exit function test_2"];
22 -> {23};
23 -> {24};
24 -> {25};
25 -> {26};
26 -> {27};
27 -> {29 28};
28 -> {29};
29 -> {30};
30 -> {31 35};
31 -> {32};
32 -> {33};
33 -> {34};
34 -> {40};
35 -> {36};
36 -> {37};
37 -> {38};
38 -> {39};
39 -> {40};
40 -> {41};
41 -> {42};
}
subgraph test_3 {
43 [shape=box label="Enter function test_3"];
44 [shape=box label="Enter block"];
45 [shape=box label="Enter when"];
46 [shape=box label="Enter when branch condition "];
47 [shape=box label="Enter ||"];
48 [shape=box label="Enter &&"];
49 [shape=box label="Access variable R|<local>/b1|"];
50 [shape=box label="Access variable R|<local>/b2|"];
51 [shape=box label="Exit &&"];
52 [shape=box label="Exit left part of ||"];
53 [shape=box label="Access variable R|<local>/b3|"];
54 [shape=box label="Exit ||"];
55 [shape=box label="Exit when branch condition"];
56 [shape=box label="Enter block"];
57 [shape=box label="Const: Int(1)"];
58 [shape=box label="Exit block"];
59 [shape=box label="Exit when branch result"];
60 [shape=box label="Enter when branch condition else"];
61 [shape=box label="Exit when branch condition"];
62 [shape=box label="Enter block"];
63 [shape=box label="Exit block"];
64 [shape=box label="Exit when branch result"];
65 [shape=box label="Exit when"];
66 [shape=box label="Exit block"];
67 [shape=box label="Exit function test_3"];
43 -> {44};
44 -> {45};
45 -> {46};
46 -> {47};
47 -> {48 54};
48 -> {49};
49 -> {51 50};
50 -> {51};
51 -> {54 52};
52 -> {53};
53 -> {54};
54 -> {55};
55 -> {56 60};
56 -> {57};
57 -> {58};
58 -> {59};
59 -> {65};
60 -> {61};
61 -> {62};
62 -> {63};
63 -> {64};
64 -> {65};
65 -> {66};
66 -> {67};
}
subgraph test_4 {
68 [shape=box label="Enter function test_4"];
69 [shape=box label="Enter block"];
70 [shape=box label="Enter when"];
71 [shape=box label="Enter when branch condition "];
72 [shape=box label="Enter ||"];
73 [shape=box label="Access variable R|<local>/b1|"];
74 [shape=box label="Exit left part of ||"];
75 [shape=box label="Enter &&"];
76 [shape=box label="Access variable R|<local>/b2|"];
77 [shape=box label="Access variable R|<local>/b3|"];
78 [shape=box label="Exit &&"];
79 [shape=box label="Exit ||"];
80 [shape=box label="Exit when branch condition"];
81 [shape=box label="Enter block"];
82 [shape=box label="Const: Int(1)"];
83 [shape=box label="Exit block"];
84 [shape=box label="Exit when branch result"];
85 [shape=box label="Enter when branch condition else"];
86 [shape=box label="Exit when branch condition"];
87 [shape=box label="Enter block"];
88 [shape=box label="Exit block"];
89 [shape=box label="Exit when branch result"];
90 [shape=box label="Exit when"];
91 [shape=box label="Exit block"];
92 [shape=box label="Exit function test_4"];
68 -> {69};
69 -> {70};
70 -> {71};
71 -> {72};
72 -> {73 79};
73 -> {79 74};
74 -> {75};
75 -> {76};
76 -> {78 77};
77 -> {78};
78 -> {79};
79 -> {80};
80 -> {81 85};
81 -> {82};
82 -> {83};
83 -> {84};
84 -> {90};
85 -> {86};
86 -> {87};
87 -> {88};
88 -> {89};
89 -> {90};
90 -> {91};
91 -> {92};
}
}
@@ -0,0 +1,94 @@
digraph complex_kt {
subgraph fetchPluginReleaseDate {
0 [shape=box label="Enter function fetchPluginReleaseDate"];
1 [shape=box label="Enter block"];
2 [shape=box label="Const: String(https://plugins.jetbrains.com/api/plugins/)"];
3 [shape=box label="Access variable R|<local>/pluginId|"];
4 [shape=box label="Access variable <Unresolved name: idString>#"];
5 [shape=box label="Const: String(/updates?version=)"];
6 [shape=box label="Access variable R|<local>/version|"];
7 [shape=box label="Variable declaration: lval url: R|kotlin/String|"];
8 [shape=box label="Try expression enter"];
9 [shape=box label="Try main block enter"];
10 [shape=box label="Enter block"];
11 [shape=box label="Access variable <Unresolved name: HttpRequests>#"];
12 [shape=box label="Access variable R|<local>/url|"];
13 [shape=box label="Function call: <Unresolved name: HttpRequests>#.<Unresolved name: request>#(R|<local>/url|)"];
14 [shape=box label="Function call: <Unresolved name: HttpRequests>#.<Unresolved name: request>#(R|<local>/url|).<Unresolved name: connect>#(<L> = connect@fun <implicit>.<anonymous>(): <implicit> {
GsonBuilder#().create#().fromJson#(it#.inputStream#.reader#(), <getClass>(Array#<R|class error: Symbol not found, for `PluginDTO`|>()).java#)
}
)"];
15 [shape=box label="Exit block"];
16 [shape=box label="Try main block exit"];
17 [shape=box label="Catch enter"];
18 [shape=box label="Enter block"];
19 [shape=box label="Const: String(Can't parse json response)"];
20 [shape=box label="Access variable R|<local>/syntaxException|"];
21 [shape=box label="Function call: <Unresolved name: ResponseParseException>#(String(Can't parse json response), R|<local>/syntaxException|)"];
22 [shape=box label="Throw: throw <Unresolved name: ResponseParseException>#(String(Can't parse json response), R|<local>/syntaxException|)"];
23 [shape=box label="Stub[DEAD]"];
24 [shape=box label="Exit block[DEAD]"];
25 [shape=box label="Catch exit[DEAD]"];
26 [shape=box label="Catch enter"];
27 [shape=box label="Enter block"];
28 [shape=box label="Access variable R|<local>/ioException|"];
29 [shape=box label="Function call: <Unresolved name: IOException>#(R|<local>/ioException|)"];
30 [shape=box label="Throw: throw <Unresolved name: IOException>#(R|<local>/ioException|)"];
31 [shape=box label="Stub[DEAD]"];
32 [shape=box label="Exit block[DEAD]"];
33 [shape=box label="Catch exit[DEAD]"];
34 [shape=box label="Try expression exit"];
35 [shape=box label="Variable declaration: lval pluginDTOs: R|kotlin/Array<class error: Symbol not found, for `PluginDTO`>|"];
36 [shape=box label="Exit block"];
37 [shape=box label="Enter annotation"];
38 [shape=box label="Access variable <Unresolved name: IOException>#"];
39 [shape=box label="Access variable <Unresolved name: ResponseParseException>#"];
40 [shape=box label="Exit annotation"];
41 [shape=box label="Exit function fetchPluginReleaseDate"];
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {4};
4 -> {5};
5 -> {6};
6 -> {7};
7 -> {8};
8 -> {9};
9 -> {41 26 17 10};
10 -> {11};
11 -> {12};
12 -> {13};
13 -> {14};
14 -> {15};
15 -> {16};
16 -> {34};
17 -> {41 18};
18 -> {19};
19 -> {20};
20 -> {21};
21 -> {22};
22 -> {41};
22 -> {23} [style=dotted];
23 -> {24} [style=dotted];
24 -> {25} [style=dotted];
25 -> {34} [style=dotted];
26 -> {41 27};
27 -> {28};
28 -> {29};
29 -> {30};
30 -> {41};
30 -> {31} [style=dotted];
31 -> {32} [style=dotted];
32 -> {33} [style=dotted];
33 -> {34} [style=dotted];
34 -> {35};
35 -> {36};
36 -> {37};
37 -> {38};
38 -> {39};
39 -> {40};
40 -> {41};
}
}
+45 -20
View File
@@ -1,21 +1,46 @@
0: Enter function "foo" -> 1
0: Enter function "fetchPluginReleaseDate" -> 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|<local>/x| -> 17 | <- 15
17: Const: Int(1) -> 18 | <- 16
18: Function call: R|<local>/x|.R|kotlin/Int.plus|(Int(1)) -> 19 | <- 17
19: Exit block -> 20 | <- 18
20: Exit function "foo" -> | <- 3, 8, 10, 19
2: Const: String(https://plugins.jetbrains.com/api/plugins/) -> 3 | <- 1
3: Access variable R|<local>/pluginId| -> 4 | <- 2
4: Access variable <Unresolved name: idString># -> 5 | <- 3
5: Const: String(/updates?version=) -> 6 | <- 4
6: Access variable R|<local>/version| -> 7 | <- 5
7: Variable declaration: lval url: R|kotlin/String| -> 8 | <- 6
8: Try expression enter -> 9 | <- 7
9: Try main block enter -> 10, 17, 26, 41 | <- 8
10: Enter block -> 11 | <- 9
11: Access variable <Unresolved name: HttpRequests># -> 12 | <- 10
12: Access variable R|<local>/url| -> 13 | <- 11
13: Function call: <Unresolved name: HttpRequests>#.<Unresolved name: request>#(R|<local>/url|) -> 14 | <- 12
14: Function call: <Unresolved name: HttpRequests>#.<Unresolved name: request>#(R|<local>/url|).<Unresolved name: connect>#(<L> = connect@fun <implicit>.<anonymous>(): <implicit> {
GsonBuilder#().create#().fromJson#(it#.inputStream#.reader#(), <getClass>(Array#<R|class error: Symbol not found, for `PluginDTO`|>()).java#)
}
) -> 15 | <- 13
15: Exit block -> 16 | <- 14
16: Try main block exit -> 34 | <- 15
17: Catch enter -> 18, 41 | <- 9
18: Enter block -> 19 | <- 17
19: Const: String(Can't parse json response) -> 20 | <- 18
20: Access variable R|<local>/syntaxException| -> 21 | <- 19
21: Function call: <Unresolved name: ResponseParseException>#(String(Can't parse json response), R|<local>/syntaxException|) -> 22 | <- 20
22: Throw: throw <Unresolved name: ResponseParseException>#(String(Can't parse json response), R|<local>/syntaxException|) -> 23[DEAD], 41 | <- 21
23: Stub[DEAD] -> 24 | <- 22
24: Exit block[DEAD] -> 25 | <- 23
25: Catch exit[DEAD] -> 34 | <- 24
26: Catch enter -> 27, 41 | <- 9
27: Enter block -> 28 | <- 26
28: Access variable R|<local>/ioException| -> 29 | <- 27
29: Function call: <Unresolved name: IOException>#(R|<local>/ioException|) -> 30 | <- 28
30: Throw: throw <Unresolved name: IOException>#(R|<local>/ioException|) -> 31[DEAD], 41 | <- 29
31: Stub[DEAD] -> 32 | <- 30
32: Exit block[DEAD] -> 33 | <- 31
33: Catch exit[DEAD] -> 34 | <- 32
34: Try expression exit -> 35 | <- 16, 25[DEAD], 33[DEAD]
35: Variable declaration: lval pluginDTOs: R|kotlin/Array<class error: Symbol not found, for `PluginDTO`>| -> 36 | <- 34
36: Exit block -> 37 | <- 35
37: Enter annotation -> 38 | <- 36
38: Access variable <Unresolved name: IOException># -> 39 | <- 37
39: Access variable <Unresolved name: ResponseParseException># -> 40 | <- 38
40: Exit annotation -> 41 | <- 39
41: Exit function "fetchPluginReleaseDate" -> | <- 9, 17, 22, 26, 30, 40
+17
View File
@@ -0,0 +1,17 @@
FILE: complex.kt
@R|kotlin/jvm/Throws|(<getClass>(<Unresolved name: IOException>#), <getClass>(<Unresolved name: ResponseParseException>#)) public final fun fetchPluginReleaseDate(pluginId: R|class error: Symbol not found, for `PluginId`|, version: R|kotlin/String|, channel: R|kotlin/String?|): R|class error: Symbol not found, for `LocalDate?`| {
lval url: R|kotlin/String| = <strcat>(String(https://plugins.jetbrains.com/api/plugins/), R|<local>/pluginId|.<Unresolved name: idString>#, String(/updates?version=), R|<local>/version|)
lval pluginDTOs: R|kotlin/Array<class error: Symbol not found, for `PluginDTO`>| = try {
<Unresolved name: HttpRequests>#.<Unresolved name: request>#(R|<local>/url|).<Unresolved name: connect>#(<L> = connect@fun <implicit>.<anonymous>(): <implicit> {
GsonBuilder#().create#().fromJson#(it#.inputStream#.reader#(), <getClass>(Array#<R|class error: Symbol not found, for `PluginDTO`|>()).java#)
}
)
}
catch (ioException: R|class error: Symbol not found, for `JsonIOException`|) {
throw <Unresolved name: IOException>#(R|<local>/ioException|)
}
catch (syntaxException: R|class error: Symbol not found, for `JsonSyntaxException`|) {
throw <Unresolved name: ResponseParseException>#(String(Can't parse json response), R|<local>/syntaxException|)
}
}
@@ -0,0 +1,2 @@
digraph initBlock_kt {
}
+192
View File
@@ -0,0 +1,192 @@
digraph jumps_kt {
subgraph test_1 {
0 [shape=box label="Enter function test_1"];
1 [shape=box label="Enter block"];
2 [shape=box label="Enter when"];
3 [shape=box label="Enter when branch condition "];
4 [shape=box label="Access variable R|<local>/x|"];
5 [shape=box label="Const: Null(null)"];
6 [shape=box label="Operator =="];
7 [shape=box label="Exit when branch condition"];
8 [shape=box label="Enter block"];
9 [shape=box label="Function call: R|kotlin/KotlinNullPointerException.KotlinNullPointerException|()"];
10 [shape=box label="Throw: throw R|kotlin/KotlinNullPointerException.KotlinNullPointerException|()"];
11 [shape=box label="Stub[DEAD]"];
12 [shape=box label="Exit block[DEAD]"];
13 [shape=box label="Exit when branch result[DEAD]"];
14 [shape=box label="Enter when branch condition else"];
15 [shape=box label="Exit when branch condition"];
16 [shape=box label="Enter block"];
17 [shape=box label="Access variable R|<local>/x|"];
18 [shape=box label="Exit block"];
19 [shape=box label="Exit when branch result"];
20 [shape=box label="Exit when"];
21 [shape=box label="Variable declaration: lval y: R|kotlin/Int|"];
22 [shape=box label="Access variable R|<local>/y|"];
23 [shape=box label="Function call: R|<local>/y|.R|kotlin/Int.inc|()"];
24 [shape=box label="Exit block"];
25 [shape=box label="Exit function test_1"];
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {4};
4 -> {5};
5 -> {6};
6 -> {7};
7 -> {8 14};
8 -> {9};
9 -> {10};
10 -> {25};
10 -> {11} [style=dotted];
11 -> {12} [style=dotted];
12 -> {13} [style=dotted];
13 -> {20} [style=dotted];
14 -> {15};
15 -> {16};
16 -> {17};
17 -> {18};
18 -> {19};
19 -> {20};
20 -> {21};
21 -> {22};
22 -> {23};
23 -> {24};
24 -> {25};
}
subgraph test_2 {
26 [shape=box label="Enter function test_2"];
27 [shape=box label="Enter block"];
28 [shape=box label="Enter when"];
29 [shape=box label="Enter when branch condition "];
30 [shape=box label="Access variable R|<local>/x|"];
31 [shape=box label="Const: Null(null)"];
32 [shape=box label="Operator =="];
33 [shape=box label="Exit when branch condition"];
34 [shape=box label="Enter block"];
35 [shape=box label="Access variable R|<local>/x|"];
36 [shape=box label="Exit block"];
37 [shape=box label="Exit when branch result"];
38 [shape=box label="Enter when branch condition else"];
39 [shape=box label="Exit when branch condition"];
40 [shape=box label="Enter block"];
41 [shape=box label="Access variable R|<local>/x|"];
42 [shape=box label="Exit block"];
43 [shape=box label="Exit when branch result"];
44 [shape=box label="Exit when"];
45 [shape=box label="Variable declaration: lval y: R|kotlin/Int?|"];
46 [shape=box label="Access variable R|<local>/y|"];
47 [shape=box label="Function call: R|<local>/y|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()"];
48 [shape=box label="Exit block"];
49 [shape=box label="Exit function test_2"];
26 -> {27};
27 -> {28};
28 -> {29};
29 -> {30};
30 -> {31};
31 -> {32};
32 -> {33};
33 -> {34 38};
34 -> {35};
35 -> {36};
36 -> {37};
37 -> {44};
38 -> {39};
39 -> {40};
40 -> {41};
41 -> {42};
42 -> {43};
43 -> {44};
44 -> {45};
45 -> {46};
46 -> {47};
47 -> {48};
48 -> {49};
}
subgraph test_3 {
50 [shape=box label="Enter function test_3"];
51 [shape=box label="Enter block"];
52 [shape=box label="Enter while loop"];
53 [shape=box label="Enter loop condition"];
54 [shape=box label="Const: Boolean(true)"];
55 [shape=box label="Exit loop condition"];
56 [shape=box label="Enter loop block"];
57 [shape=box label="Enter block"];
58 [shape=box label="Access variable R|<local>/x|"];
59 [shape=box label="Type operator: x as Int"];
60 [shape=box label="Jump: break@@@[Boolean(true)] "];
61 [shape=box label="Stub[DEAD]"];
62 [shape=box label="Exit block[DEAD]"];
63 [shape=box label="Exit loop block[DEAD]"];
64 [shape=box label="Exit whileloop"];
65 [shape=box label="Access variable R|<local>/x|"];
66 [shape=box label="Function call: R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()"];
67 [shape=box label="Exit block"];
68 [shape=box label="Exit function test_3"];
50 -> {51};
51 -> {52};
52 -> {53};
53 -> {54};
54 -> {55};
55 -> {64 56};
56 -> {57};
57 -> {58};
58 -> {59};
59 -> {60};
60 -> {64};
60 -> {61} [style=dotted];
61 -> {62} [style=dotted];
62 -> {63} [style=dotted];
63 -> {53} [style=dotted];
64 -> {65};
65 -> {66};
66 -> {67};
67 -> {68};
}
subgraph test_4 {
69 [shape=box label="Enter function test_4"];
70 [shape=box label="Enter block"];
71 [shape=box label="Enter do-while loop"];
72 [shape=box label="Enter loop block"];
73 [shape=box label="Enter block"];
74 [shape=box label="Access variable R|<local>/x|"];
75 [shape=box label="Type operator: x as int"];
76 [shape=box label="Jump: break@@@[Boolean(true)] "];
77 [shape=box label="Stub[DEAD]"];
78 [shape=box label="Exit block[DEAD]"];
79 [shape=box label="Exit loop block[DEAD]"];
80 [shape=box label="Enter loop condition[DEAD]"];
81 [shape=box label="Const: Boolean(true)[DEAD]"];
82 [shape=box label="Exit loop condition[DEAD]"];
83 [shape=box label="Exit do-whileloop[DEAD]"];
84 [shape=box label="Access variable R|<local>/x|[DEAD]"];
85 [shape=box label="Function call: R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()[DEAD]"];
86 [shape=box label="Exit block[DEAD]"];
87 [shape=box label="Exit function test_4[DEAD]"];
69 -> {70};
70 -> {71};
71 -> {72};
72 -> {73};
73 -> {74};
74 -> {75};
75 -> {76};
76 -> {83 77} [style=dotted];
77 -> {78} [style=dotted];
78 -> {79} [style=dotted];
79 -> {80} [style=dotted];
80 -> {81} [style=dotted];
81 -> {82} [style=dotted];
82 -> {72 83} [style=dotted];
83 -> {84} [style=dotted];
84 -> {85} [style=dotted];
85 -> {86} [style=dotted];
86 -> {87} [style=dotted];
}
}
+2 -2
View File
@@ -19,9 +19,9 @@
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
21: Variable declaration: lval y: R|kotlin/Int| -> 22 | <- 20
22: Access variable R|<local>/y| -> 23 | <- 21
23: Function call: R|<local>/y|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#() -> 24 | <- 22
23: Function call: R|<local>/y|.R|kotlin/Int.inc|() -> 24 | <- 22
24: Exit block -> 25 | <- 23
25: Exit function "test_1" -> | <- 10, 24
+2 -2
View File
@@ -1,6 +1,6 @@
FILE: jumps.kt
public final fun test_1(x: R|kotlin/Int?|): R|kotlin/Unit| {
lval y: R|kotlin/Int?| = when () {
lval y: R|kotlin/Int| = when () {
==(R|<local>/x|, Null(null)) -> {
throw R|kotlin/KotlinNullPointerException.KotlinNullPointerException|()
}
@@ -9,7 +9,7 @@ FILE: jumps.kt
}
}
R|<local>/y|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()
R|<local>/y|.R|kotlin/Int.inc|()
}
public final fun test_2(x: R|kotlin/Int?|): R|kotlin/Unit| {
lval y: R|kotlin/Int?| = when () {
+141
View File
@@ -0,0 +1,141 @@
digraph loops_kt {
subgraph testWhile {
0 [shape=box label="Enter function testWhile"];
1 [shape=box label="Enter block"];
2 [shape=box label="Enter while loop"];
3 [shape=box label="Enter loop condition"];
4 [shape=box label="Access variable R|<local>/b|"];
5 [shape=box label="Exit loop condition"];
6 [shape=box label="Enter loop block"];
7 [shape=box label="Enter block"];
8 [shape=box label="Access variable R|<local>/x|"];
9 [shape=box label="Type operator: x is String"];
10 [shape=box label="Variable declaration: lval y: R|kotlin/Boolean|"];
11 [shape=box label="Exit block"];
12 [shape=box label="Exit loop block"];
13 [shape=box label="Exit whileloop"];
14 [shape=box label="Access variable R|<local>/x|"];
15 [shape=box label="Type operator: x is String"];
16 [shape=box label="Exit block"];
17 [shape=box label="Exit function testWhile"];
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {4};
4 -> {5};
5 -> {13 6};
6 -> {7};
7 -> {8};
8 -> {9};
9 -> {10};
10 -> {11};
11 -> {12};
12 -> {3};
13 -> {14};
14 -> {15};
15 -> {16};
16 -> {17};
}
subgraph testDoWhile {
18 [shape=box label="Enter function testDoWhile"];
19 [shape=box label="Enter block"];
20 [shape=box label="Enter do-while loop"];
21 [shape=box label="Enter loop block"];
22 [shape=box label="Enter block"];
23 [shape=box label="Access variable R|<local>/x|"];
24 [shape=box label="Type operator: x is String"];
25 [shape=box label="Variable declaration: lval y: R|kotlin/Boolean|"];
26 [shape=box label="Exit block"];
27 [shape=box label="Exit loop block"];
28 [shape=box label="Enter loop condition"];
29 [shape=box label="Access variable R|<local>/b|"];
30 [shape=box label="Exit loop condition"];
31 [shape=box label="Exit do-whileloop"];
32 [shape=box label="Access variable R|<local>/x|"];
33 [shape=box label="Type operator: x is String"];
34 [shape=box label="Exit block"];
35 [shape=box label="Exit function testDoWhile"];
18 -> {19};
19 -> {20};
20 -> {21};
21 -> {22};
22 -> {23};
23 -> {24};
24 -> {25};
25 -> {26};
26 -> {27};
27 -> {28};
28 -> {29};
29 -> {30};
30 -> {21 31};
31 -> {32};
32 -> {33};
33 -> {34};
34 -> {35};
}
subgraph testFor {
36 [shape=box label="Enter function testFor"];
37 [shape=box label="Enter block"];
38 [shape=box label="Const: Int(0)"];
39 [shape=box label="Const: Int(5)"];
40 [shape=box label="Function call: Int(0).R|kotlin/Int.rangeTo|(Int(5))"];
41 [shape=box label="Variable declaration: lval <range>: R|kotlin/ranges/IntRange|"];
42 [shape=box label="Access variable R|<local>/<range>|"];
43 [shape=box label="Function call: R|<local>/<range>|.R|kotlin/ranges/IntProgression.iterator|()"];
44 [shape=box label="Variable declaration: lval <iterator>: R|kotlin/collections/IntIterator|"];
45 [shape=box label="Enter while loop"];
46 [shape=box label="Enter loop condition"];
47 [shape=box label="Access variable R|<local>/<iterator>|"];
48 [shape=box label="Function call: R|<local>/<iterator>|.R|FakeOverride<kotlin/collections/Iterator.hasNext: R|kotlin/Boolean|>|()"];
49 [shape=box label="Exit loop condition"];
50 [shape=box label="Enter loop block"];
51 [shape=box label="Enter block"];
52 [shape=box label="Access variable R|<local>/<iterator>|"];
53 [shape=box label="Function call: R|<local>/<iterator>|.R|kotlin/collections/IntIterator.next|()"];
54 [shape=box label="Variable declaration: lval i: R|kotlin/Int|"];
55 [shape=box label="Access variable R|<local>/x|"];
56 [shape=box label="Type operator: x is String"];
57 [shape=box label="Variable declaration: lval y: R|kotlin/Boolean|"];
58 [shape=box label="Exit block"];
59 [shape=box label="Exit loop block"];
60 [shape=box label="Exit whileloop"];
61 [shape=box label="Access variable R|<local>/x|"];
62 [shape=box label="Type operator: x is String"];
63 [shape=box label="Exit block"];
64 [shape=box label="Exit function testFor"];
36 -> {37};
37 -> {38};
38 -> {39};
39 -> {40};
40 -> {41};
41 -> {42};
42 -> {43};
43 -> {44};
44 -> {45};
45 -> {46};
46 -> {47};
47 -> {48};
48 -> {49};
49 -> {60 50};
50 -> {51};
51 -> {52};
52 -> {53};
53 -> {54};
54 -> {55};
55 -> {56};
56 -> {57};
57 -> {58};
58 -> {59};
59 -> {46};
60 -> {61};
61 -> {62};
62 -> {63};
63 -> {64};
}
}
@@ -0,0 +1,216 @@
digraph propertiesAndInitBlocks_kt {
subgraph run {
0 [shape=box label="Enter function run"];
1 [shape=box label="Enter block"];
2 [shape=box label="Function call: R|<local>/block|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()"];
3 [shape=box label="Exit block"];
4 [shape=box label="Exit function run"];
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {4};
}
subgraph val_x1 {
5 [shape=box label="Enter property"];
6 [shape=box label="Const: Int(1)"];
7 [shape=box label="Exit property"];
5 -> {6};
6 -> {7};
}
subgraph <getter> {
8 [shape=box label="Enter function getter"];
9 [shape=box label="Enter block"];
10 [shape=box label="Const: Int(1)"];
11 [shape=box label="Jump: ^ Int(1)"];
12 [shape=box label="Stub[DEAD]"];
13 [shape=box label="Exit block[DEAD]"];
14 [shape=box label="Exit function getter[DEAD]"];
8 -> {9};
9 -> {10};
10 -> {11};
11 -> {14 12} [style=dotted];
12 -> {13} [style=dotted];
13 -> {14} [style=dotted];
}
subgraph <setter> {
15 [shape=box label="Enter function setter"];
16 [shape=box label="Enter block"];
17 [shape=box label="Const: Int(1)"];
18 [shape=box label="Assignmenet: F|/x2|"];
19 [shape=box label="Exit block"];
20 [shape=box label="Exit function setter"];
15 -> {16};
16 -> {17};
17 -> {18};
18 -> {19};
19 -> {20};
}
subgraph val_x2 {
21 [shape=box label="Enter property"];
22 [shape=box label="Const: Int(1)"];
23 [shape=box label="Exit property"];
21 -> {22};
22 -> {23};
}
subgraph <anonymous> {
24 [shape=box label="Enter init block"];
25 [shape=box label="Enter block"];
26 [shape=box label="Function call: <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()"];
27 [shape=box label="Throw: throw <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()"];
28 [shape=box label="Stub[DEAD]"];
29 [shape=box label="Const: Int(1)[DEAD]"];
30 [shape=box label="Exit block[DEAD]"];
31 [shape=box label="Exit init block[DEAD]"];
32 [shape=box label="Enter function anonymousFunction"];
33 [shape=box label="Enter block"];
34 [shape=box label="Function call: <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()"];
35 [shape=box label="Throw: throw <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()"];
36 [shape=box label="Stub[DEAD]"];
37 [shape=box label="Exit block[DEAD]"];
38 [shape=box label="Exit function anonymousFunction[DEAD]"];
24 -> {25};
25 -> {26};
26 -> {27};
27 -> {31 28} [style=dotted];
28 -> {29} [style=dotted];
29 -> {30} [style=dotted];
30 -> {31} [style=dotted];
32 -> {33};
33 -> {34};
34 -> {35};
35 -> {38 36} [style=dotted];
36 -> {37} [style=dotted];
37 -> {38} [style=dotted];
}
subgraph foo {
39 [shape=box label="Enter function foo"];
40 [shape=box label="Enter block"];
41 [shape=box label="Const: Int(1)"];
42 [shape=box label="Const: Int(1)"];
43 [shape=box label="Function call: Int(1).R|kotlin/Int.plus|(Int(1))"];
44 [shape=box label="Variable declaration: lval c: R|kotlin/Int|"];
45 [shape=box label="Function call: <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()"];
46 [shape=box label="Throw: throw <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()"];
47 [shape=box label="Stub[DEAD]"];
48 [shape=box label="Exit block[DEAD]"];
49 [shape=box label="Exit function foo[DEAD]"];
39 -> {40};
40 -> {41};
41 -> {42};
42 -> {43};
43 -> {44};
44 -> {45};
45 -> {46};
46 -> {49 47} [style=dotted];
47 -> {48} [style=dotted];
48 -> {49} [style=dotted];
}
subgraph <getter> {
50 [shape=box label="Enter init block"];
51 [shape=box label="Enter block"];
52 [shape=box label="Function call: <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()"];
53 [shape=box label="Throw: throw <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()"];
54 [shape=box label="Stub[DEAD]"];
55 [shape=box label="Exit block[DEAD]"];
56 [shape=box label="Exit init block[DEAD]"];
57 [shape=box label="Enter function getter"];
58 [shape=box label="Enter block"];
59 [shape=box label="Exit block"];
60 [shape=box label="Exit function getter"];
50 -> {51};
51 -> {52};
52 -> {53};
53 -> {56 54} [style=dotted];
54 -> {55} [style=dotted];
55 -> {56} [style=dotted];
57 -> {58};
58 -> {59};
59 -> {60};
}
subgraph val_x3 {
61 [shape=box label="Enter property"];
62 [shape=box label="Function call: R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| {
local final fun foo(): R|kotlin/Unit| {
lval c: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(1))
throw <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()
}
local final class LocalClass : R|kotlin/Any| {
public constructor(): R|LocalClass| {
super<R|kotlin/Any|>()
}
init {
throw <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()
Int(1)
}
}
throw <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()
}
)"];
63 [shape=box label="Exit property"];
61 -> {62};
62 -> {63};
}
subgraph val_x4 {
64 [shape=box label="Enter property"];
65 [shape=box label="Try expression enter"];
66 [shape=box label="Try main block enter"];
67 [shape=box label="Enter block"];
68 [shape=box label="Const: Int(1)"];
69 [shape=box label="Exit block"];
70 [shape=box label="Try main block exit"];
71 [shape=box label="Enter finally"];
72 [shape=box label="Enter block"];
73 [shape=box label="Const: Int(0)"];
74 [shape=box label="Exit block"];
75 [shape=box label="Exit finally"];
76 [shape=box label="Catch enter"];
77 [shape=box label="Enter block"];
78 [shape=box label="Const: Int(2)"];
79 [shape=box label="Exit block"];
80 [shape=box label="Catch exit"];
81 [shape=box label="Try expression exit"];
82 [shape=box label="Exit property"];
64 -> {65};
65 -> {66};
66 -> {82 76 71 67};
67 -> {68};
68 -> {69};
69 -> {70};
70 -> {81};
71 -> {72};
72 -> {73};
73 -> {74};
74 -> {75};
75 -> {81};
76 -> {82 77};
77 -> {78};
78 -> {79};
79 -> {80};
80 -> {81};
81 -> {82};
}
}
@@ -0,0 +1,38 @@
digraph simple_kt {
subgraph foo {
0 [shape=box label="Enter function foo"];
1 [shape=box label="Enter block"];
2 [shape=box label="Exit block"];
3 [shape=box label="Exit function foo"];
0 -> {1};
1 -> {2};
2 -> {3};
}
subgraph test {
4 [shape=box label="Enter function test"];
5 [shape=box label="Enter block"];
6 [shape=box label="Const: Int(1)"];
7 [shape=box label="Variable declaration: lval x: R|kotlin/Int|"];
8 [shape=box label="Access variable R|<local>/x|"];
9 [shape=box label="Const: Int(1)"];
10 [shape=box label="Function call: R|<local>/x|.R|kotlin/Int.plus|(Int(1))"];
11 [shape=box label="Variable declaration: lval y: R|kotlin/Int|"];
12 [shape=box label="Function call: R|/foo|()"];
13 [shape=box label="Exit block"];
14 [shape=box label="Exit function test"];
4 -> {5};
5 -> {6};
6 -> {7};
7 -> {8};
8 -> {9};
9 -> {10};
10 -> {11};
11 -> {12};
12 -> {13};
13 -> {14};
}
}
@@ -0,0 +1,233 @@
digraph tryCatch_kt {
subgraph test_1 {
0 [shape=box label="Enter function test_1"];
1 [shape=box label="Enter block"];
2 [shape=box label="Try expression enter"];
3 [shape=box label="Try main block enter"];
4 [shape=box label="Enter block"];
5 [shape=box label="Const: Int(1)"];
6 [shape=box label="Variable declaration: lval x: R|kotlin/Int|"];
7 [shape=box label="Exit block"];
8 [shape=box label="Try main block exit"];
9 [shape=box label="Catch enter"];
10 [shape=box label="Enter block"];
11 [shape=box label="Const: Int(3)"];
12 [shape=box label="Variable declaration: lval z: R|kotlin/Int|"];
13 [shape=box label="Exit block"];
14 [shape=box label="Catch exit"];
15 [shape=box label="Catch enter"];
16 [shape=box label="Enter block"];
17 [shape=box label="Const: Int(2)"];
18 [shape=box label="Variable declaration: lval y: R|kotlin/Int|"];
19 [shape=box label="Exit block"];
20 [shape=box label="Catch exit"];
21 [shape=box label="Try expression exit"];
22 [shape=box label="Exit block"];
23 [shape=box label="Exit function test_1"];
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {23 15 9 4};
4 -> {5};
5 -> {6};
6 -> {7};
7 -> {8};
8 -> {21};
9 -> {23 10};
10 -> {11};
11 -> {12};
12 -> {13};
13 -> {14};
14 -> {21};
15 -> {23 16};
16 -> {17};
17 -> {18};
18 -> {19};
19 -> {20};
20 -> {21};
21 -> {22};
22 -> {23};
}
subgraph test_2 {
24 [shape=box label="Enter function test_2"];
25 [shape=box label="Enter block"];
26 [shape=box label="Try expression enter"];
27 [shape=box label="Try main block enter"];
28 [shape=box label="Enter block"];
29 [shape=box label="Const: Int(1)"];
30 [shape=box label="Exit block"];
31 [shape=box label="Try main block exit"];
32 [shape=box label="Catch enter"];
33 [shape=box label="Enter block"];
34 [shape=box label="Const: Int(2)"];
35 [shape=box label="Exit block"];
36 [shape=box label="Catch exit"];
37 [shape=box label="Try expression exit"];
38 [shape=box label="Variable declaration: lval x: R|kotlin/Int|"];
39 [shape=box label="Exit block"];
40 [shape=box label="Exit function test_2"];
24 -> {25};
25 -> {26};
26 -> {27};
27 -> {40 32 28};
28 -> {29};
29 -> {30};
30 -> {31};
31 -> {37};
32 -> {40 33};
33 -> {34};
34 -> {35};
35 -> {36};
36 -> {37};
37 -> {38};
38 -> {39};
39 -> {40};
}
subgraph test_3 {
41 [shape=box label="Enter function test_3"];
42 [shape=box label="Enter block"];
43 [shape=box label="Enter while loop"];
44 [shape=box label="Enter loop condition"];
45 [shape=box label="Const: Boolean(true)"];
46 [shape=box label="Exit loop condition"];
47 [shape=box label="Enter loop block"];
48 [shape=box label="Enter block"];
49 [shape=box label="Try expression enter"];
50 [shape=box label="Try main block enter"];
51 [shape=box label="Enter block"];
52 [shape=box label="Enter when"];
53 [shape=box label="Enter when branch condition "];
54 [shape=box label="Access variable R|<local>/b|"];
55 [shape=box label="Exit when branch condition"];
56 [shape=box label="Enter block"];
57 [shape=box label="Jump: ^test_3 Unit"];
58 [shape=box label="Stub[DEAD]"];
59 [shape=box label="Exit block[DEAD]"];
60 [shape=box label="Exit when branch result[DEAD]"];
61 [shape=box label="Enter when branch condition else"];
62 [shape=box label="Exit when branch condition"];
63 [shape=box label="Enter block"];
64 [shape=box label="Exit block"];
65 [shape=box label="Exit when branch result"];
66 [shape=box label="Exit when"];
67 [shape=box label="Const: Int(1)"];
68 [shape=box label="Variable declaration: lval x: R|kotlin/Int|"];
69 [shape=box label="Enter when"];
70 [shape=box label="Enter when branch condition "];
71 [shape=box label="Access variable R|<local>/b|"];
72 [shape=box label="Function call: R|<local>/b|.R|kotlin/Boolean.not|()"];
73 [shape=box label="Exit when branch condition"];
74 [shape=box label="Enter block"];
75 [shape=box label="Jump: break@@@[Boolean(true)] "];
76 [shape=box label="Stub[DEAD]"];
77 [shape=box label="Exit block[DEAD]"];
78 [shape=box label="Exit when branch result[DEAD]"];
79 [shape=box label="Enter when branch condition else"];
80 [shape=box label="Exit when branch condition"];
81 [shape=box label="Enter block"];
82 [shape=box label="Exit block"];
83 [shape=box label="Exit when branch result"];
84 [shape=box label="Exit when"];
85 [shape=box label="Exit block"];
86 [shape=box label="Try main block exit"];
87 [shape=box label="Catch enter"];
88 [shape=box label="Enter block"];
89 [shape=box label="Jump: break@@@[Boolean(true)] "];
90 [shape=box label="Stub[DEAD]"];
91 [shape=box label="Exit block[DEAD]"];
92 [shape=box label="Catch exit[DEAD]"];
93 [shape=box label="Catch enter"];
94 [shape=box label="Enter block"];
95 [shape=box label="Jump: continue@@@[Boolean(true)] "];
96 [shape=box label="Stub[DEAD]"];
97 [shape=box label="Exit block[DEAD]"];
98 [shape=box label="Catch exit[DEAD]"];
99 [shape=box label="Try expression exit"];
100 [shape=box label="Const: Int(2)"];
101 [shape=box label="Variable declaration: lval y: R|kotlin/Int|"];
102 [shape=box label="Exit block"];
103 [shape=box label="Exit loop block"];
104 [shape=box label="Exit whileloop"];
105 [shape=box label="Const: Int(3)"];
106 [shape=box label="Variable declaration: lval z: R|kotlin/Int|"];
107 [shape=box label="Exit block"];
108 [shape=box label="Exit function test_3"];
41 -> {42};
42 -> {43};
43 -> {44};
44 -> {45};
45 -> {46};
46 -> {104 47};
47 -> {48};
48 -> {49};
49 -> {50};
50 -> {108 93 87 51};
51 -> {52};
52 -> {53};
53 -> {54};
54 -> {55};
55 -> {56 61};
56 -> {57};
57 -> {108};
57 -> {58} [style=dotted];
58 -> {59} [style=dotted];
59 -> {60} [style=dotted];
60 -> {66} [style=dotted];
61 -> {62};
62 -> {63};
63 -> {64};
64 -> {65};
65 -> {66};
66 -> {67};
67 -> {68};
68 -> {69};
69 -> {70};
70 -> {71};
71 -> {72};
72 -> {73};
73 -> {74 79};
74 -> {75};
75 -> {104};
75 -> {76} [style=dotted];
76 -> {77} [style=dotted];
77 -> {78} [style=dotted];
78 -> {84} [style=dotted];
79 -> {80};
80 -> {81};
81 -> {82};
82 -> {83};
83 -> {84};
84 -> {85};
85 -> {86};
86 -> {99};
87 -> {108 88};
88 -> {89};
89 -> {104};
89 -> {90} [style=dotted];
90 -> {91} [style=dotted];
91 -> {92} [style=dotted];
92 -> {99} [style=dotted];
93 -> {108 94};
94 -> {95};
95 -> {44};
95 -> {96} [style=dotted];
96 -> {97} [style=dotted];
97 -> {98} [style=dotted];
98 -> {99} [style=dotted];
99 -> {100};
100 -> {101};
101 -> {102};
102 -> {103};
103 -> {44};
104 -> {105};
105 -> {106};
106 -> {107};
107 -> {108};
}
}
+147
View File
@@ -0,0 +1,147 @@
digraph when_kt {
subgraph test_1 {
0 [shape=box label="Enter function test_1"];
1 [shape=box label="Enter block"];
2 [shape=box label="Enter when"];
3 [shape=box label="Enter when branch condition "];
4 [shape=box label="Access variable R|<local>/x|"];
5 [shape=box label="Const: Int(1)"];
6 [shape=box label="Operator =="];
7 [shape=box label="Exit when branch condition"];
8 [shape=box label="Enter block"];
9 [shape=box label="Const: Int(10)"];
10 [shape=box label="Exit block"];
11 [shape=box label="Exit when branch result"];
12 [shape=box label="Enter when branch condition "];
13 [shape=box label="Access variable R|<local>/x|"];
14 [shape=box label="Const: Int(2)"];
15 [shape=box label="Function call: R|<local>/x|.R|kotlin/Int.rem|(Int(2))"];
16 [shape=box label="Const: Int(0)"];
17 [shape=box label="Operator =="];
18 [shape=box label="Exit when branch condition"];
19 [shape=box label="Enter block"];
20 [shape=box label="Const: Int(20)"];
21 [shape=box label="Exit block"];
22 [shape=box label="Exit when branch result"];
23 [shape=box label="Enter when branch condition "];
24 [shape=box label="Const: Int(1)"];
25 [shape=box label="Const: Int(1)"];
26 [shape=box label="Function call: Int(1).R|kotlin/Int.minus|(Int(1))"];
27 [shape=box label="Const: Int(0)"];
28 [shape=box label="Operator =="];
29 [shape=box label="Exit when branch condition"];
30 [shape=box label="Enter block"];
31 [shape=box label="Jump: ^test_1 Unit"];
32 [shape=box label="Stub[DEAD]"];
33 [shape=box label="Exit block[DEAD]"];
34 [shape=box label="Exit when branch result[DEAD]"];
35 [shape=box label="Enter when branch condition else"];
36 [shape=box label="Exit when branch condition"];
37 [shape=box label="Enter block"];
38 [shape=box label="Const: Int(5)"];
39 [shape=box label="Exit block"];
40 [shape=box label="Exit when branch result"];
41 [shape=box label="Exit when"];
42 [shape=box label="Variable declaration: lval y: R|kotlin/Int|"];
43 [shape=box label="Exit block"];
44 [shape=box label="Exit function test_1"];
0 -> {1};
1 -> {2};
2 -> {3};
3 -> {4};
4 -> {5};
5 -> {6};
6 -> {7};
7 -> {8 12};
8 -> {9};
9 -> {10};
10 -> {11};
11 -> {41};
12 -> {13};
13 -> {14};
14 -> {15};
15 -> {16};
16 -> {17};
17 -> {18};
18 -> {19 23};
19 -> {20};
20 -> {21};
21 -> {22};
22 -> {41};
23 -> {24};
24 -> {25};
25 -> {26};
26 -> {27};
27 -> {28};
28 -> {29};
29 -> {30 35};
30 -> {31};
31 -> {44};
31 -> {32} [style=dotted];
32 -> {33} [style=dotted];
33 -> {34} [style=dotted];
34 -> {41} [style=dotted];
35 -> {36};
36 -> {37};
37 -> {38};
38 -> {39};
39 -> {40};
40 -> {41};
41 -> {42};
42 -> {43};
43 -> {44};
}
subgraph test_2 {
45 [shape=box label="Enter function test_2"];
46 [shape=box label="Enter block"];
47 [shape=box label="Enter when"];
48 [shape=box label="Enter when branch condition "];
49 [shape=box label="Enter &&"];
50 [shape=box label="Access variable R|<local>/x|"];
51 [shape=box label="Type operator: x is A"];
52 [shape=box label="Access variable R|<local>/x|"];
53 [shape=box label="Type operator: x is B"];
54 [shape=box label="Exit &&"];
55 [shape=box label="Exit when branch condition"];
56 [shape=box label="Enter block"];
57 [shape=box label="Access variable R|<local>/x|"];
58 [shape=box label="Type operator: x is A"];
59 [shape=box label="Exit block"];
60 [shape=box label="Exit when branch result"];
61 [shape=box label="Enter when branch condition else"];
62 [shape=box label="Exit when branch condition"];
63 [shape=box label="Enter block"];
64 [shape=box label="Exit block"];
65 [shape=box label="Exit when branch result"];
66 [shape=box label="Exit when"];
67 [shape=box label="Exit block"];
68 [shape=box label="Exit function test_2"];
45 -> {46};
46 -> {47};
47 -> {48};
48 -> {49};
49 -> {50};
50 -> {51};
51 -> {54 52};
52 -> {53};
53 -> {54};
54 -> {55};
55 -> {56 61};
56 -> {57};
57 -> {58};
58 -> {59};
59 -> {60};
60 -> {66};
61 -> {62};
62 -> {63};
63 -> {64};
64 -> {65};
65 -> {66};
66 -> {67};
67 -> {68};
}
}
@@ -8,7 +8,7 @@ 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.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
@@ -25,18 +25,83 @@ abstract class AbstractFirCfgBuildingTest : AbstractFirResolveTestCase() {
}
fun checkCfg(path: String, firFiles: List<FirFile>) {
val firFileDump = StringBuilder().also { firFiles.first().accept(FirControlFlowGraphRenderVisitor(it), null) }.toString()
val expectedPath = path.replace(".kt", ".cfg.txt")
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump)
val simpleBuilder = StringBuilder()
val dotBuilder = StringBuilder()
firFiles.first().accept(FirControlFlowGraphRenderVisitor(simpleBuilder, dotBuilder), null)
val dotCfgDump = dotBuilder.toString()
val dotExpectedPath = path.replace(".kt", ".cfg.dot")
KotlinTestUtils.assertEqualsToFile(File(dotExpectedPath), dotCfgDump)
}
private class FirControlFlowGraphRenderVisitor(private val builder: StringBuilder) : FirVisitorVoid() {
private class FirControlFlowGraphRenderVisitor(
private val simpleBuilder: StringBuilder,
private val dotBuilder: StringBuilder
) : FirVisitorVoid() {
private var indexOffset = 0
override fun visitFile(file: FirFile) {
dotBuilder.appendln("digraph ${file.name.replace(".", "_")} {")
super.visitFile(file)
dotBuilder.appendln("}")
}
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitControlFlowGraphReference(controlFlowGraphReference: FirControlFlowGraphReference) {
(controlFlowGraphReference as? FirControlFlowGraphReferenceImpl)?.controlFlowGraph?.renderToStringBuilder(builder)
val controlFlowGraph = (controlFlowGraphReference as? FirControlFlowGraphReferenceImpl)?.controlFlowGraph ?: return
controlFlowGraph.renderToStringBuilder(simpleBuilder)
indexOffset = controlFlowGraph.dotRenderToStringBuilder(dotBuilder, indexOffset)
dotBuilder.appendln()
}
}
}
private const val EDGE = " -> "
private const val INDENT = " "
fun ControlFlowGraph.dotRenderToStringBuilder(builder: StringBuilder, indexOffset: Int): Int {
with(builder) {
val sortedNodes = sortNodes()
val indices = sortedNodes.indicesMap().mapValues { (_, index) -> index + indexOffset }
appendln("subgraph ${name.replace(" ", "_")} {")
fun CFGNode<*>.splitEdges(): Pair<List<CFGNode<*>>, List<CFGNode<*>>> =
if (isDead) emptyList<CFGNode<*>>() to followingNodes
else followingNodes.filter { !it.isDead } to followingNodes.filter { it.isDead }
sortedNodes.forEach {
append(INDENT)
append(indices.getValue(it))
appendln(" [shape=box label=\"${it.render().replace("\"", "")}\"];")
}
appendln()
sortedNodes.forEachIndexed { i, node ->
if (node.followingNodes.isEmpty()) return@forEachIndexed
val (aliveEdges, deadEdges) = node.splitEdges()
fun renderEdges(edges: List<CFGNode<*>>, isDead: Boolean) {
if (edges.isEmpty()) return
append(INDENT)
append(i + indexOffset)
append(EDGE)
append(edges.joinToString(prefix = "{", postfix = "}", separator = " ") { indices.getValue(it).toString() })
if (isDead) {
append(" [style=dotted]")
}
appendln(";")
}
renderEdges(aliveEdges, false)
renderEdges(deadEdges, true)
}
appendln("}")
return indexOffset + sortedNodes.size
}
}