aadea0e26f
Interpretation: a graph A is a subgraph of B if information available at nodes of A depends on the paths taken in B. For example, local classes are subgraphs of a graph in which they are declared, and members of those classes are subgraphs of the local class itself - because these members can reference captured values. Consequences: * if graph G is a subgraph of node N, then G is a subgraph of N's owner; * `ControlFlowAnalysisDiagnosticComponent` will only visit root graphs; * `graph.traverse` will ignore subgraph boundaries, as if all subgraphs are inlined into one huge root graph; * if a control flow checker needs information from a declaration to which a graph is attached, it must look at subgraphs explicitly. For example, consider the `callsInPlace` checker. When a function has a `callsInPlace` contract and a local declaration, the checker must visit that local declaration to ensure it does not capture the allegedly called-in-place argument - hence `graph.traverse` will look at the nodes. However, the local declaration can also be a function with its own `callsInPlace` contracts, so the checker should also run for it in isolation. If that sounds quadratic, that's because unfortunately it is.
165 lines
5.2 KiB
Plaintext
Vendored
165 lines
5.2 KiB
Plaintext
Vendored
digraph functionCallBound_kt {
|
|
graph [nodesep=3]
|
|
node [shape=box penwidth=2]
|
|
edge [penwidth=2]
|
|
|
|
subgraph cluster_0 {
|
|
color=red
|
|
0 [label="Enter function <init>" style="filled" fillcolor=red];
|
|
1 [label="Delegated constructor call: super<R|kotlin/Any|>()" style="filled" fillcolor=yellow];
|
|
2 [label="Exit function <init>" style="filled" fillcolor=red];
|
|
}
|
|
0 -> {1};
|
|
1 -> {2};
|
|
|
|
subgraph cluster_1 {
|
|
color=red
|
|
3 [label="Enter class Base" style="filled" fillcolor=red];
|
|
4 [label="Exit class Base" style="filled" fillcolor=red];
|
|
}
|
|
3 -> {4} [color=green];
|
|
|
|
subgraph cluster_2 {
|
|
color=red
|
|
5 [label="Enter function <init>" style="filled" fillcolor=red];
|
|
6 [label="Delegated constructor call: super<R|Base|>()" style="filled" fillcolor=yellow];
|
|
7 [label="Exit function <init>" style="filled" fillcolor=red];
|
|
}
|
|
5 -> {6};
|
|
6 -> {7};
|
|
|
|
subgraph cluster_3 {
|
|
color=red
|
|
11 [label="Enter class Sub" style="filled" fillcolor=red];
|
|
12 [label="Part of class initialization"];
|
|
subgraph cluster_4 {
|
|
color=blue
|
|
8 [label="Enter property" style="filled" fillcolor=red];
|
|
9 [label="Access variable R|<local>/data|"];
|
|
10 [label="Exit property" style="filled" fillcolor=red];
|
|
}
|
|
13 [label="Exit class Sub" style="filled" fillcolor=red];
|
|
}
|
|
11 -> {12} [color=green];
|
|
12 -> {8} [color=green];
|
|
12 -> {13} [style=dotted];
|
|
12 -> {8} [style=dashed];
|
|
8 -> {9};
|
|
9 -> {10};
|
|
10 -> {13} [color=green];
|
|
|
|
subgraph cluster_5 {
|
|
color=red
|
|
14 [label="Enter function isOk" style="filled" fillcolor=red];
|
|
subgraph cluster_6 {
|
|
color=blue
|
|
15 [label="Enter block"];
|
|
16 [label="Const: Boolean(true)"];
|
|
17 [label="Jump: ^isOk Boolean(true)"];
|
|
18 [label="Stub" style="filled" fillcolor=gray];
|
|
19 [label="Exit block" style="filled" fillcolor=gray];
|
|
}
|
|
20 [label="Exit function isOk" style="filled" fillcolor=red];
|
|
}
|
|
14 -> {15};
|
|
15 -> {16};
|
|
16 -> {17};
|
|
17 -> {20};
|
|
17 -> {18} [style=dotted];
|
|
18 -> {19} [style=dotted];
|
|
19 -> {20} [style=dotted];
|
|
|
|
subgraph cluster_7 {
|
|
color=red
|
|
21 [label="Enter function check" style="filled" fillcolor=red];
|
|
subgraph cluster_8 {
|
|
color=blue
|
|
22 [label="Enter block"];
|
|
subgraph cluster_9 {
|
|
color=blue
|
|
23 [label="Enter when"];
|
|
subgraph cluster_10 {
|
|
color=blue
|
|
24 [label="Enter when branch condition "];
|
|
25 [label="Access variable R|<local>/base|"];
|
|
26 [label="Type operator: (R|<local>/base| as? R|Sub|)"];
|
|
27 [label="Enter safe call"];
|
|
28 [label="Function call: $subj$.R|/isOk|()" style="filled" fillcolor=yellow];
|
|
29 [label="Exit safe call"];
|
|
30 [label="Const: Boolean(true)"];
|
|
31 [label="Equality operator =="];
|
|
32 [label="Exit when branch condition"];
|
|
}
|
|
subgraph cluster_11 {
|
|
color=blue
|
|
33 [label="Enter when branch condition else"];
|
|
34 [label="Exit when branch condition"];
|
|
}
|
|
35 [label="Enter when branch result"];
|
|
subgraph cluster_12 {
|
|
color=blue
|
|
36 [label="Enter block"];
|
|
37 [label="Access variable R|<local>/base|"];
|
|
38 [label="Exit block"];
|
|
}
|
|
39 [label="Exit when branch result"];
|
|
40 [label="Enter when branch result"];
|
|
subgraph cluster_13 {
|
|
color=blue
|
|
41 [label="Enter block"];
|
|
42 [label="Access variable R|<local>/base|"];
|
|
43 [label="Smart cast: R|<local>/base|"];
|
|
44 [label="Access variable R|/Sub.data|"];
|
|
45 [label="Exit block"];
|
|
}
|
|
46 [label="Exit when branch result"];
|
|
47 [label="Exit when"];
|
|
}
|
|
48 [label="Jump: ^check when () {
|
|
==((R|<local>/base| as? R|Sub|)?.{ $subj$.R|/isOk|() }, Boolean(true)) -> {
|
|
R|<local>/base|.R|/Sub.data|
|
|
}
|
|
else -> {
|
|
R|<local>/base|
|
|
}
|
|
}
|
|
"];
|
|
49 [label="Stub" style="filled" fillcolor=gray];
|
|
50 [label="Exit block" style="filled" fillcolor=gray];
|
|
}
|
|
51 [label="Exit function check" style="filled" fillcolor=red];
|
|
}
|
|
21 -> {22};
|
|
22 -> {23};
|
|
23 -> {24};
|
|
24 -> {25};
|
|
25 -> {26};
|
|
26 -> {27 29};
|
|
27 -> {28};
|
|
28 -> {29};
|
|
29 -> {30};
|
|
30 -> {31};
|
|
31 -> {32};
|
|
32 -> {33 40};
|
|
33 -> {34};
|
|
34 -> {35};
|
|
35 -> {36};
|
|
36 -> {37};
|
|
37 -> {38};
|
|
38 -> {39};
|
|
39 -> {47};
|
|
40 -> {41};
|
|
41 -> {42};
|
|
42 -> {43};
|
|
43 -> {44};
|
|
44 -> {45};
|
|
45 -> {46};
|
|
46 -> {47};
|
|
47 -> {48};
|
|
48 -> {51};
|
|
48 -> {49} [style=dotted];
|
|
49 -> {50} [style=dotted];
|
|
50 -> {51} [style=dotted];
|
|
|
|
}
|