FIR CFA: compute subgraph relationships automatically
No more `addSubGraph`. Also no more `owner` in graphs. ^KT-40526 Obsolete ^KT-40582 Obsolete
This commit is contained in:
@@ -67,10 +67,10 @@ digraph defaultArguments_kt {
|
|||||||
}
|
}
|
||||||
7 -> {8};
|
7 -> {8};
|
||||||
8 -> {9 16};
|
8 -> {9 16};
|
||||||
8 -> {16 16} [style=dashed];
|
8 -> {16} [style=dashed];
|
||||||
9 -> {10};
|
9 -> {10};
|
||||||
10 -> {11 20};
|
10 -> {11 20};
|
||||||
10 -> {20 20} [style=dashed];
|
10 -> {20} [style=dashed];
|
||||||
11 -> {12};
|
11 -> {12};
|
||||||
12 -> {13};
|
12 -> {13};
|
||||||
13 -> {14};
|
13 -> {14};
|
||||||
|
|||||||
+39
-39
@@ -426,14 +426,14 @@ digraph flowFromInplaceLambda2_kt {
|
|||||||
153 [label="Postponed enter to lambda"];
|
153 [label="Postponed enter to lambda"];
|
||||||
subgraph cluster_40 {
|
subgraph cluster_40 {
|
||||||
color=blue
|
color=blue
|
||||||
187 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
|
180 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
|
||||||
subgraph cluster_41 {
|
subgraph cluster_41 {
|
||||||
color=blue
|
color=blue
|
||||||
188 [label="Enter block"];
|
181 [label="Enter block"];
|
||||||
189 [label="Function call: R|/n|<R|kotlin/Nothing?|>()" style="filled" fillcolor=yellow];
|
182 [label="Function call: R|/n|<R|kotlin/Nothing?|>()" style="filled" fillcolor=yellow];
|
||||||
190 [label="Exit block"];
|
183 [label="Exit block"];
|
||||||
}
|
}
|
||||||
191 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
184 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
||||||
}
|
}
|
||||||
154 [label="Postponed exit from lambda"];
|
154 [label="Postponed exit from lambda"];
|
||||||
155 [label="Function call: R|kotlin/run|<R|kotlin/Nothing?|>(...)" style="filled" fillcolor=yellow];
|
155 [label="Function call: R|kotlin/run|<R|kotlin/Nothing?|>(...)" style="filled" fillcolor=yellow];
|
||||||
@@ -447,16 +447,16 @@ digraph flowFromInplaceLambda2_kt {
|
|||||||
160 [label="Postponed enter to lambda"];
|
160 [label="Postponed enter to lambda"];
|
||||||
subgraph cluster_43 {
|
subgraph cluster_43 {
|
||||||
color=blue
|
color=blue
|
||||||
180 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
|
185 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
|
||||||
subgraph cluster_44 {
|
subgraph cluster_44 {
|
||||||
color=blue
|
color=blue
|
||||||
181 [label="Enter block"];
|
186 [label="Enter block"];
|
||||||
182 [label="Const: Null(null)"];
|
187 [label="Const: Null(null)"];
|
||||||
183 [label="Assignment: R|<local>/p|"];
|
188 [label="Assignment: R|<local>/p|"];
|
||||||
184 [label="Function call: R|/n|<R|kotlin/Nothing?|>()" style="filled" fillcolor=yellow];
|
189 [label="Function call: R|/n|<R|kotlin/Nothing?|>()" style="filled" fillcolor=yellow];
|
||||||
185 [label="Exit block"];
|
190 [label="Exit block"];
|
||||||
}
|
}
|
||||||
186 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
191 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
||||||
}
|
}
|
||||||
161 [label="Postponed exit from lambda"];
|
161 [label="Postponed exit from lambda"];
|
||||||
162 [label="Function call: R|kotlin/run|<R|kotlin/Nothing?|>(...)" style="filled" fillcolor=yellow];
|
162 [label="Function call: R|kotlin/run|<R|kotlin/Nothing?|>(...)" style="filled" fillcolor=yellow];
|
||||||
@@ -518,9 +518,9 @@ digraph flowFromInplaceLambda2_kt {
|
|||||||
150 -> {151};
|
150 -> {151};
|
||||||
151 -> {152};
|
151 -> {152};
|
||||||
152 -> {153};
|
152 -> {153};
|
||||||
153 -> {155 187};
|
153 -> {155 180};
|
||||||
153 -> {154} [style=dotted];
|
153 -> {154} [style=dotted];
|
||||||
153 -> {187} [style=dashed];
|
153 -> {180} [style=dashed];
|
||||||
154 -> {155} [color=green];
|
154 -> {155} [color=green];
|
||||||
154 -> {171} [color=red];
|
154 -> {171} [color=red];
|
||||||
155 -> {156};
|
155 -> {156};
|
||||||
@@ -528,9 +528,9 @@ digraph flowFromInplaceLambda2_kt {
|
|||||||
157 -> {165};
|
157 -> {165};
|
||||||
158 -> {159};
|
158 -> {159};
|
||||||
159 -> {160};
|
159 -> {160};
|
||||||
160 -> {162 180};
|
160 -> {162 185};
|
||||||
160 -> {161} [style=dotted];
|
160 -> {161} [style=dotted];
|
||||||
160 -> {180} [style=dashed];
|
160 -> {185} [style=dashed];
|
||||||
161 -> {162} [color=green];
|
161 -> {162} [color=green];
|
||||||
161 -> {171} [color=red];
|
161 -> {171} [color=red];
|
||||||
162 -> {163};
|
162 -> {163};
|
||||||
@@ -557,14 +557,14 @@ digraph flowFromInplaceLambda2_kt {
|
|||||||
181 -> {182};
|
181 -> {182};
|
||||||
182 -> {183};
|
182 -> {183};
|
||||||
183 -> {184};
|
183 -> {184};
|
||||||
184 -> {185};
|
184 -> {154};
|
||||||
185 -> {186};
|
185 -> {186};
|
||||||
186 -> {161};
|
186 -> {187};
|
||||||
187 -> {188};
|
187 -> {188};
|
||||||
188 -> {189};
|
188 -> {189};
|
||||||
189 -> {190};
|
189 -> {190};
|
||||||
190 -> {191};
|
190 -> {191};
|
||||||
191 -> {154};
|
191 -> {161};
|
||||||
192 -> {193};
|
192 -> {193};
|
||||||
193 -> {194};
|
193 -> {194};
|
||||||
194 -> {195};
|
194 -> {195};
|
||||||
@@ -685,16 +685,16 @@ digraph flowFromInplaceLambda2_kt {
|
|||||||
240 [label="Postponed enter to lambda"];
|
240 [label="Postponed enter to lambda"];
|
||||||
subgraph cluster_59 {
|
subgraph cluster_59 {
|
||||||
color=blue
|
color=blue
|
||||||
271 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
|
264 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
|
||||||
subgraph cluster_60 {
|
subgraph cluster_60 {
|
||||||
color=blue
|
color=blue
|
||||||
272 [label="Enter block"];
|
265 [label="Enter block"];
|
||||||
273 [label="Access variable R|<local>/x|"];
|
266 [label="Access variable R|<local>/x|"];
|
||||||
274 [label="Type operator: (R|<local>/x| as R|kotlin/String|)"];
|
267 [label="Type operator: (R|<local>/x| as R|kotlin/String|)"];
|
||||||
275 [label="Function call: R|/n|<R|kotlin/Nothing?|>()" style="filled" fillcolor=yellow];
|
268 [label="Function call: R|/n|<R|kotlin/Nothing?|>()" style="filled" fillcolor=yellow];
|
||||||
276 [label="Exit block"];
|
269 [label="Exit block"];
|
||||||
}
|
}
|
||||||
277 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
270 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
||||||
}
|
}
|
||||||
241 [label="Postponed exit from lambda"];
|
241 [label="Postponed exit from lambda"];
|
||||||
242 [label="Function call: R|kotlin/run|<R|kotlin/Nothing?|>(...)" style="filled" fillcolor=yellow];
|
242 [label="Function call: R|kotlin/run|<R|kotlin/Nothing?|>(...)" style="filled" fillcolor=yellow];
|
||||||
@@ -708,16 +708,16 @@ digraph flowFromInplaceLambda2_kt {
|
|||||||
247 [label="Postponed enter to lambda"];
|
247 [label="Postponed enter to lambda"];
|
||||||
subgraph cluster_62 {
|
subgraph cluster_62 {
|
||||||
color=blue
|
color=blue
|
||||||
264 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
|
271 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
|
||||||
subgraph cluster_63 {
|
subgraph cluster_63 {
|
||||||
color=blue
|
color=blue
|
||||||
265 [label="Enter block"];
|
272 [label="Enter block"];
|
||||||
266 [label="Access variable R|<local>/x|"];
|
273 [label="Access variable R|<local>/x|"];
|
||||||
267 [label="Type operator: (R|<local>/x| as R|kotlin/String|)"];
|
274 [label="Type operator: (R|<local>/x| as R|kotlin/String|)"];
|
||||||
268 [label="Function call: R|/n|<R|kotlin/Nothing?|>()" style="filled" fillcolor=yellow];
|
275 [label="Function call: R|/n|<R|kotlin/Nothing?|>()" style="filled" fillcolor=yellow];
|
||||||
269 [label="Exit block"];
|
276 [label="Exit block"];
|
||||||
}
|
}
|
||||||
270 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
277 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
||||||
}
|
}
|
||||||
248 [label="Postponed exit from lambda"];
|
248 [label="Postponed exit from lambda"];
|
||||||
249 [label="Function call: R|kotlin/run|<R|kotlin/Nothing?|>(...)" style="filled" fillcolor=yellow];
|
249 [label="Function call: R|kotlin/run|<R|kotlin/Nothing?|>(...)" style="filled" fillcolor=yellow];
|
||||||
@@ -762,9 +762,9 @@ digraph flowFromInplaceLambda2_kt {
|
|||||||
237 -> {238};
|
237 -> {238};
|
||||||
238 -> {239};
|
238 -> {239};
|
||||||
239 -> {240};
|
239 -> {240};
|
||||||
240 -> {242 271};
|
240 -> {242 264};
|
||||||
240 -> {241} [style=dotted];
|
240 -> {241} [style=dotted];
|
||||||
240 -> {271} [style=dashed];
|
240 -> {264} [style=dashed];
|
||||||
241 -> {242} [color=green];
|
241 -> {242} [color=green];
|
||||||
241 -> {258} [color=red];
|
241 -> {258} [color=red];
|
||||||
242 -> {243};
|
242 -> {243};
|
||||||
@@ -772,9 +772,9 @@ digraph flowFromInplaceLambda2_kt {
|
|||||||
244 -> {252};
|
244 -> {252};
|
||||||
245 -> {246};
|
245 -> {246};
|
||||||
246 -> {247};
|
246 -> {247};
|
||||||
247 -> {249 264};
|
247 -> {249 271};
|
||||||
247 -> {248} [style=dotted];
|
247 -> {248} [style=dotted];
|
||||||
247 -> {264} [style=dashed];
|
247 -> {271} [style=dashed];
|
||||||
248 -> {249} [color=green];
|
248 -> {249} [color=green];
|
||||||
248 -> {258} [color=red];
|
248 -> {258} [color=red];
|
||||||
249 -> {250};
|
249 -> {250};
|
||||||
@@ -800,14 +800,14 @@ digraph flowFromInplaceLambda2_kt {
|
|||||||
267 -> {268};
|
267 -> {268};
|
||||||
268 -> {269};
|
268 -> {269};
|
||||||
269 -> {270};
|
269 -> {270};
|
||||||
270 -> {248};
|
270 -> {241};
|
||||||
271 -> {272};
|
271 -> {272};
|
||||||
272 -> {273};
|
272 -> {273};
|
||||||
273 -> {274};
|
273 -> {274};
|
||||||
274 -> {275};
|
274 -> {275};
|
||||||
275 -> {276};
|
275 -> {276};
|
||||||
276 -> {277};
|
276 -> {277};
|
||||||
277 -> {241};
|
277 -> {248};
|
||||||
278 -> {279};
|
278 -> {279};
|
||||||
279 -> {280};
|
279 -> {280};
|
||||||
280 -> {281};
|
280 -> {281};
|
||||||
|
|||||||
+1
-1
@@ -70,7 +70,7 @@ digraph lambdaInWhenBranch_kt {
|
|||||||
11 -> {12};
|
11 -> {12};
|
||||||
13 -> {14};
|
13 -> {14};
|
||||||
14 -> {15 17};
|
14 -> {15 17};
|
||||||
14 -> {17 17} [style=dashed];
|
14 -> {17} [style=dashed];
|
||||||
15 -> {16};
|
15 -> {16};
|
||||||
17 -> {18};
|
17 -> {18};
|
||||||
18 -> {19};
|
18 -> {19};
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ class ControlFlowAnalysisDiagnosticComponent(
|
|||||||
|
|
||||||
private fun analyze(declaration: FirControlFlowGraphOwner, context: CheckerContext) {
|
private fun analyze(declaration: FirControlFlowGraphOwner, context: CheckerContext) {
|
||||||
val graph = declaration.controlFlowGraphReference?.controlFlowGraph ?: return
|
val graph = declaration.controlFlowGraphReference?.controlFlowGraph ?: return
|
||||||
if (graph.owner != null) return
|
if (graph.isSubGraph) return
|
||||||
cfaCheckers.forEach { it.analyze(graph, reporter, context) }
|
cfaCheckers.forEach { it.analyze(graph, reporter, context) }
|
||||||
|
|
||||||
val (properties, capturedWrites) = LocalPropertyAndCapturedWriteCollector.collect(graph)
|
val (properties, capturedWrites) = LocalPropertyAndCapturedWriteCollector.collect(graph)
|
||||||
|
|||||||
+7
-24
@@ -50,7 +50,7 @@ class ControlFlowGraphBuilder {
|
|||||||
|
|
||||||
private val argumentListSplitNodes: Stack<SplitPostponedLambdasNode?> = stackOf()
|
private val argumentListSplitNodes: Stack<SplitPostponedLambdasNode?> = stackOf()
|
||||||
private val postponedAnonymousFunctionNodes =
|
private val postponedAnonymousFunctionNodes =
|
||||||
mutableMapOf<FirFunctionSymbol<*>, Pair<CFGNodeWithSubgraphs<*>, PostponedLambdaExitNode?>>()
|
mutableMapOf<FirFunctionSymbol<*>, Pair<CFGNode<*>, PostponedLambdaExitNode?>>()
|
||||||
private val postponedLambdaExits: Stack<MutableList<Pair<CFGNode<*>, EdgeKind>>> = stackOf()
|
private val postponedLambdaExits: Stack<MutableList<Pair<CFGNode<*>, EdgeKind>>> = stackOf()
|
||||||
|
|
||||||
private val loopConditionEnterNodes: NodeStorage<FirElement, LoopConditionEnterNode> = NodeStorage()
|
private val loopConditionEnterNodes: NodeStorage<FirElement, LoopConditionEnterNode> = NodeStorage()
|
||||||
@@ -134,16 +134,12 @@ class ControlFlowGraphBuilder {
|
|||||||
is FirConstructor -> "<init>"
|
is FirConstructor -> "<init>"
|
||||||
else -> throw IllegalArgumentException("Unknown function: ${function.render()}")
|
else -> throw IllegalArgumentException("Unknown function: ${function.render()}")
|
||||||
}
|
}
|
||||||
val graph = ControlFlowGraph(function, name, ControlFlowGraph.Kind.Function)
|
|
||||||
// function is local
|
|
||||||
val localFunctionNode = runIf(function.symbol.callableId.isLocal && currentGraph.kind.withBody) {
|
val localFunctionNode = runIf(function.symbol.callableId.isLocal && currentGraph.kind.withBody) {
|
||||||
currentGraph.addSubGraph(graph)
|
createLocalFunctionDeclarationNode(function).also { addNewSimpleNode(it) }
|
||||||
createLocalFunctionDeclarationNode(function).also {
|
|
||||||
addNewSimpleNode(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pushGraph(graph)
|
pushGraph(ControlFlowGraph(function, name, ControlFlowGraph.Kind.Function))
|
||||||
|
|
||||||
val enterNode = createFunctionEnterNode(function).also {
|
val enterNode = createFunctionEnterNode(function).also {
|
||||||
lastNodes.push(it)
|
lastNodes.push(it)
|
||||||
@@ -266,10 +262,6 @@ class ControlFlowGraphBuilder {
|
|||||||
assert(graph.exitNode == exitNode)
|
assert(graph.exitNode == exitNode)
|
||||||
|
|
||||||
val (splitNode, postponedExitNode) = postponedAnonymousFunctionNodes.remove(symbol)!!
|
val (splitNode, postponedExitNode) = postponedAnonymousFunctionNodes.remove(symbol)!!
|
||||||
splitNode.addSubGraph(graph)
|
|
||||||
// May not be the current graph: `select(run { run { generic() } }, 1)`
|
|
||||||
splitNode.owner.addSubGraph(graph)
|
|
||||||
|
|
||||||
val invocationKind = anonymousFunction.invocationKind
|
val invocationKind = anonymousFunction.invocationKind
|
||||||
if (postponedExitNode == null) {
|
if (postponedExitNode == null) {
|
||||||
// Postponed exit node was needed so we could create lambda->call edges without having the subgraph ready. If it
|
// Postponed exit node was needed so we could create lambda->call edges without having the subgraph ready. If it
|
||||||
@@ -411,7 +403,6 @@ class ControlFlowGraphBuilder {
|
|||||||
var prevInitPartNode: CFGNode<*>? = null
|
var prevInitPartNode: CFGNode<*>? = null
|
||||||
for (graph in calledInPlace) {
|
for (graph in calledInPlace) {
|
||||||
createPartOfClassInitializationNode(graph.declaration as FirControlFlowGraphOwner).also {
|
createPartOfClassInitializationNode(graph.declaration as FirControlFlowGraphOwner).also {
|
||||||
currentGraph.addSubGraph(graph)
|
|
||||||
addEdge(node, it, preferredKind = EdgeKind.CfgForward)
|
addEdge(node, it, preferredKind = EdgeKind.CfgForward)
|
||||||
addEdge(it, graph.enterNode, preferredKind = EdgeKind.CfgForward)
|
addEdge(it, graph.enterNode, preferredKind = EdgeKind.CfgForward)
|
||||||
node = graph.exitNode
|
node = graph.exitNode
|
||||||
@@ -435,10 +426,9 @@ class ControlFlowGraphBuilder {
|
|||||||
// println(x)
|
// println(x)
|
||||||
for (graph in calledLater) {
|
for (graph in calledLater) {
|
||||||
addEdge(exitNode, graph.enterNode, preferredKind = EdgeKind.CfgForward)
|
addEdge(exitNode, graph.enterNode, preferredKind = EdgeKind.CfgForward)
|
||||||
exitNode.addSubGraph(graph)
|
|
||||||
currentGraph.addSubGraph(graph)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exitNode.subGraphs = calledLater
|
||||||
return popGraph()
|
return popGraph()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,9 +445,7 @@ class ControlFlowGraphBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun exitLocalClass(klass: FirRegularClass): Pair<LocalClassExitNode, ControlFlowGraph> {
|
fun exitLocalClass(klass: FirRegularClass): Pair<LocalClassExitNode, ControlFlowGraph> {
|
||||||
val graph = exitClass(klass).also {
|
val graph = exitClass(klass)
|
||||||
currentGraph.addSubGraph(it)
|
|
||||||
}
|
|
||||||
val node = createLocalClassExitNode(klass).also {
|
val node = createLocalClassExitNode(klass).also {
|
||||||
addNewSimpleNodeIfPossible(it)
|
addNewSimpleNodeIfPossible(it)
|
||||||
}
|
}
|
||||||
@@ -475,9 +463,7 @@ class ControlFlowGraphBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun exitAnonymousObject(anonymousObject: FirAnonymousObject): Pair<AnonymousObjectExitNode, ControlFlowGraph> {
|
fun exitAnonymousObject(anonymousObject: FirAnonymousObject): Pair<AnonymousObjectExitNode, ControlFlowGraph> {
|
||||||
val graph = exitClass(anonymousObject).also {
|
val graph = exitClass(anonymousObject)
|
||||||
currentGraph.addSubGraph(it)
|
|
||||||
}
|
|
||||||
val enterNode = lastNodes.popOrNull()
|
val enterNode = lastNodes.popOrNull()
|
||||||
if (enterNode !is AnonymousObjectEnterNode) {
|
if (enterNode !is AnonymousObjectEnterNode) {
|
||||||
throw AssertionError("anonymous object exit should be preceded by anonymous object enter, but got $enterNode")
|
throw AssertionError("anonymous object exit should be preceded by anonymous object enter, but got $enterNode")
|
||||||
@@ -535,12 +521,9 @@ class ControlFlowGraphBuilder {
|
|||||||
popAndAddEdge(exitNode)
|
popAndAddEdge(exitNode)
|
||||||
val graph = popGraph()
|
val graph = popGraph()
|
||||||
require(exitNode == graph.exitNode)
|
require(exitNode == graph.exitNode)
|
||||||
val outerEnterNode = lastNode as EnterValueParameterNode
|
|
||||||
val outerExitNode = createExitValueParameterNode(valueParameter)
|
val outerExitNode = createExitValueParameterNode(valueParameter)
|
||||||
addNewSimpleNode(outerExitNode)
|
addNewSimpleNode(outerExitNode)
|
||||||
addEdge(exitNode, outerExitNode, propagateDeadness = false)
|
addEdge(exitNode, outerExitNode, propagateDeadness = false)
|
||||||
outerEnterNode.addSubGraph(graph)
|
|
||||||
currentGraph.addSubGraph(graph)
|
|
||||||
return Triple(exitNode, outerExitNode, graph)
|
return Triple(exitNode, outerExitNode, graph)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -154,7 +154,7 @@ class FirControlFlowGraphRenderVisitor(
|
|||||||
private fun initializeNodes(graph: ControlFlowGraph) {
|
private fun initializeNodes(graph: ControlFlowGraph) {
|
||||||
if (graph in allGraphs) return
|
if (graph in allGraphs) return
|
||||||
graph.collectNodes()
|
graph.collectNodes()
|
||||||
if (graph.owner == null) {
|
if (!graph.isSubGraph) {
|
||||||
topLevelGraphs += graph
|
topLevelGraphs += graph
|
||||||
}
|
}
|
||||||
allGraphs += graph
|
allGraphs += graph
|
||||||
|
|||||||
@@ -142,21 +142,12 @@ interface UnionNodeMarker
|
|||||||
// ----------------------------------- EnterNode for declaration with CFG -----------------------------------
|
// ----------------------------------- EnterNode for declaration with CFG -----------------------------------
|
||||||
|
|
||||||
sealed class CFGNodeWithSubgraphs<out E : FirElement>(owner: ControlFlowGraph, level: Int, id: Int) : CFGNode<E>(owner, level, id) {
|
sealed class CFGNodeWithSubgraphs<out E : FirElement>(owner: ControlFlowGraph, level: Int, id: Int) : CFGNode<E>(owner, level, id) {
|
||||||
private val _subGraphs = mutableListOf<ControlFlowGraph>()
|
abstract val subGraphs: List<ControlFlowGraph>
|
||||||
|
|
||||||
fun addSubGraph(graph: ControlFlowGraph){
|
|
||||||
_subGraphs += graph
|
|
||||||
}
|
|
||||||
|
|
||||||
open val subGraphs: List<ControlFlowGraph>
|
|
||||||
get() = _subGraphs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class CFGNodeWithCfgOwner<out E : FirControlFlowGraphOwner>(owner: ControlFlowGraph, level: Int, id: Int) : CFGNodeWithSubgraphs<E>(owner, level, id) {
|
sealed class CFGNodeWithCfgOwner<out E : FirControlFlowGraphOwner>(owner: ControlFlowGraph, level: Int, id: Int) : CFGNodeWithSubgraphs<E>(owner, level, id) {
|
||||||
override val subGraphs: List<ControlFlowGraph> by lazy {
|
final override val subGraphs: List<ControlFlowGraph>
|
||||||
fir.controlFlowGraphReference?.controlFlowGraph?.run(::addSubGraph)
|
get() = listOfNotNull(fir.controlFlowGraphReference?.controlFlowGraph)
|
||||||
super.subGraphs
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------- Named function -----------------------------------
|
// ----------------------------------- Named function -----------------------------------
|
||||||
@@ -222,6 +213,10 @@ class ExitValueParameterNode(owner: ControlFlowGraph, override val fir: FirValue
|
|||||||
|
|
||||||
class SplitPostponedLambdasNode(owner: ControlFlowGraph, override val fir: FirStatement, val lambdas: List<FirAnonymousFunction>, level: Int, id: Int)
|
class SplitPostponedLambdasNode(owner: ControlFlowGraph, override val fir: FirStatement, val lambdas: List<FirAnonymousFunction>, level: Int, id: Int)
|
||||||
: CFGNodeWithSubgraphs<FirStatement>(owner, level, id) {
|
: CFGNodeWithSubgraphs<FirStatement>(owner, level, id) {
|
||||||
|
|
||||||
|
override val subGraphs: List<ControlFlowGraph>
|
||||||
|
get() = lambdas.mapNotNull { it.controlFlowGraphReference?.controlFlowGraph }
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
|
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
|
||||||
return visitor.visitSplitPostponedLambdasNode(this, data)
|
return visitor.visitSplitPostponedLambdasNode(this, data)
|
||||||
}
|
}
|
||||||
@@ -240,6 +235,9 @@ class MergePostponedLambdaExitsNode(owner: ControlFlowGraph, override val fir: F
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AnonymousFunctionExpressionNode(owner: ControlFlowGraph, override val fir: FirAnonymousFunctionExpression, level: Int, id: Int) : CFGNodeWithSubgraphs<FirAnonymousFunctionExpression>(owner, level, id) {
|
class AnonymousFunctionExpressionNode(owner: ControlFlowGraph, override val fir: FirAnonymousFunctionExpression, level: Int, id: Int) : CFGNodeWithSubgraphs<FirAnonymousFunctionExpression>(owner, level, id) {
|
||||||
|
override val subGraphs: List<ControlFlowGraph>
|
||||||
|
get() = listOfNotNull(fir.anonymousFunction.controlFlowGraphReference?.controlFlowGraph)
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
|
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
|
||||||
return visitor.visitAnonymousFunctionExpressionNode(this, data)
|
return visitor.visitAnonymousFunctionExpressionNode(this, data)
|
||||||
}
|
}
|
||||||
@@ -266,6 +264,8 @@ class ClassExitNode(owner: ControlFlowGraph, override val fir: FirClass, level:
|
|||||||
owner.exitNode = this
|
owner.exitNode = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lateinit override var subGraphs: List<ControlFlowGraph>
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
|
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
|
||||||
return visitor.visitClassExitNode(this, data)
|
return visitor.visitClassExitNode(this, data)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-34
@@ -26,14 +26,14 @@ class ControlFlowGraph(val declaration: FirDeclaration?, val name: String, val k
|
|||||||
@set:CfgInternals
|
@set:CfgInternals
|
||||||
lateinit var exitNode: CFGNode<*>
|
lateinit var exitNode: CFGNode<*>
|
||||||
|
|
||||||
var owner: ControlFlowGraph? = null
|
val isSubGraph: Boolean
|
||||||
private set
|
get() = enterNode.previousNodes.isNotEmpty()
|
||||||
|
|
||||||
var state: State = State.Building
|
var state: State = State.Building
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private val _subGraphs: MutableList<ControlFlowGraph> = mutableListOf()
|
val subGraphs: List<ControlFlowGraph>
|
||||||
val subGraphs: List<ControlFlowGraph> get() = _subGraphs
|
get() = _nodes.flatMap { (it as? CFGNodeWithSubgraphs<*>)?.subGraphs ?: emptyList() }
|
||||||
|
|
||||||
@CfgInternals
|
@CfgInternals
|
||||||
fun complete() {
|
fun complete() {
|
||||||
@@ -50,15 +50,6 @@ class ControlFlowGraph(val declaration: FirDeclaration?, val name: String, val k
|
|||||||
_nodes.addAll(sortedNodes)
|
_nodes.addAll(sortedNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@CfgInternals
|
|
||||||
fun addSubGraph(graph: ControlFlowGraph) {
|
|
||||||
assert(graph.owner == null) {
|
|
||||||
"SubGraph already has owner"
|
|
||||||
}
|
|
||||||
graph.owner = this
|
|
||||||
_subGraphs += graph
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun assertState(state: State) {
|
private fun assertState(state: State) {
|
||||||
assert(this.state == state) {
|
assert(this.state == state) {
|
||||||
"This action can not be performed at $this state"
|
"This action can not be performed at $this state"
|
||||||
@@ -171,34 +162,16 @@ private fun ControlFlowGraph.orderNodes(): LinkedHashSet<CFGNode<*>> {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (!visitedNodes.add(node)) continue
|
if (!visitedNodes.add(node)) continue
|
||||||
val followingNodes = node.followingNodes
|
|
||||||
|
|
||||||
for (followingNode in followingNodes) {
|
// NOTE: this intentionally does not walk through subgraphs. If the only path from A to B
|
||||||
|
// is through a subgraph, add a dead edge between them to enforce ordering.
|
||||||
|
for (followingNode in node.followingNodes) {
|
||||||
if (followingNode.owner == this) {
|
if (followingNode.owner == this) {
|
||||||
if (followingNode !in visitedNodes) {
|
if (followingNode !in visitedNodes) {
|
||||||
stack.addFirst(followingNode)
|
stack.addFirst(followingNode)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
walkThrowSubGraphs(followingNode.owner, visitedNodes, stack)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return visitedNodes
|
return visitedNodes
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ControlFlowGraph.walkThrowSubGraphs(
|
|
||||||
otherGraph: ControlFlowGraph,
|
|
||||||
visitedNodes: Set<CFGNode<*>>,
|
|
||||||
stack: ArrayDeque<CFGNode<*>>
|
|
||||||
) {
|
|
||||||
if (otherGraph.owner != this) return
|
|
||||||
for (otherNode in otherGraph.exitNode.followingNodes) {
|
|
||||||
if (otherNode.owner == this) {
|
|
||||||
if (otherNode !in visitedNodes) {
|
|
||||||
stack.addFirst(otherNode)
|
|
||||||
}
|
|
||||||
} else if (otherNode.owner != otherGraph) {
|
|
||||||
walkThrowSubGraphs(otherNode.owner, visitedNodes, stack)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+27
-27
@@ -235,7 +235,7 @@ digraph kt44814_kt {
|
|||||||
71 -> {75} [color=green];
|
71 -> {75} [color=green];
|
||||||
50 -> {51};
|
50 -> {51};
|
||||||
51 -> {52 55};
|
51 -> {52 55};
|
||||||
51 -> {55 55} [style=dashed];
|
51 -> {55} [style=dashed];
|
||||||
52 -> {53};
|
52 -> {53};
|
||||||
53 -> {54};
|
53 -> {54};
|
||||||
55 -> {56};
|
55 -> {56};
|
||||||
@@ -576,20 +576,20 @@ digraph kt44814_kt {
|
|||||||
193 [label="Postponed enter to lambda [8]"];
|
193 [label="Postponed enter to lambda [8]"];
|
||||||
subgraph cluster_62 {
|
subgraph cluster_62 {
|
||||||
color=blue
|
color=blue
|
||||||
240 [label="Enter function anonymousFunction [9]" style="filled" fillcolor=red];
|
234 [label="Enter function anonymousFunction [9]" style="filled" fillcolor=red];
|
||||||
subgraph cluster_63 {
|
subgraph cluster_63 {
|
||||||
color=blue
|
color=blue
|
||||||
241 [label="Enter block [9]"];
|
235 [label="Enter block [9]"];
|
||||||
242 [label="Access variable R|<local>/it| [9]"];
|
236 [label="Access variable R|<local>/it| [9]"];
|
||||||
243 [label="Enter safe call [9]"];
|
237 [label="Enter safe call [9]"];
|
||||||
244 [label="Access variable R|/LighterASTNode.tokenType| [9]"];
|
238 [label="Access variable R|/LighterASTNode.tokenType| [9]"];
|
||||||
245 [label="Exit safe call [9]"];
|
239 [label="Exit safe call [9]"];
|
||||||
246 [label="Access qualifier /TokenType [9]"];
|
240 [label="Access qualifier /TokenType [9]"];
|
||||||
247 [label="Access variable R|/TokenType.Companion.MODIFIER_LIST| [9]"];
|
241 [label="Access variable R|/TokenType.Companion.MODIFIER_LIST| [9]"];
|
||||||
248 [label="Equality operator == [9]"];
|
242 [label="Equality operator == [9]"];
|
||||||
249 [label="Exit block [9]"];
|
243 [label="Exit block [9]"];
|
||||||
}
|
}
|
||||||
250 [label="Exit function anonymousFunction [9]" style="filled" fillcolor=red];
|
244 [label="Exit function anonymousFunction [9]" style="filled" fillcolor=red];
|
||||||
}
|
}
|
||||||
194 [label="Postponed exit from lambda [8]"];
|
194 [label="Postponed exit from lambda [8]"];
|
||||||
195 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...).R|kotlin/collections/find|<R|LighterASTNode?|>(...) [7]" style="filled" fillcolor=yellow];
|
195 [label="Function call: this@R|/FirModifierList.Companion.getModifierList|.R|/FirLightSourceElement.lighterASTNode|.R|/LighterASTNode.getChildren|(...).R|kotlin/collections/find|<R|LighterASTNode?|>(...) [7]" style="filled" fillcolor=yellow];
|
||||||
@@ -619,15 +619,15 @@ digraph kt44814_kt {
|
|||||||
216 [label="Postponed enter to lambda [7]"];
|
216 [label="Postponed enter to lambda [7]"];
|
||||||
subgraph cluster_65 {
|
subgraph cluster_65 {
|
||||||
color=blue
|
color=blue
|
||||||
234 [label="Enter function anonymousFunction [8]" style="filled" fillcolor=red];
|
245 [label="Enter function anonymousFunction [8]" style="filled" fillcolor=red];
|
||||||
subgraph cluster_66 {
|
subgraph cluster_66 {
|
||||||
color=blue
|
color=blue
|
||||||
235 [label="Enter block [8]"];
|
246 [label="Enter block [8]"];
|
||||||
236 [label="Access variable R|<local>/it| [9]"];
|
247 [label="Access variable R|<local>/it| [9]"];
|
||||||
237 [label="Function call: R|/FirModifierList.FirPsiModifierList.FirPsiModifierList|(...) [8]" style="filled" fillcolor=yellow];
|
248 [label="Function call: R|/FirModifierList.FirPsiModifierList.FirPsiModifierList|(...) [8]" style="filled" fillcolor=yellow];
|
||||||
238 [label="Exit block [8]"];
|
249 [label="Exit block [8]"];
|
||||||
}
|
}
|
||||||
239 [label="Exit function anonymousFunction [8]" style="filled" fillcolor=red];
|
250 [label="Exit function anonymousFunction [8]" style="filled" fillcolor=red];
|
||||||
}
|
}
|
||||||
217 [label="Postponed exit from lambda [7]"];
|
217 [label="Postponed exit from lambda [7]"];
|
||||||
218 [label="Function call: $subj$.R|kotlin/let|<R|KtModifierList|, R|FirModifierList.FirPsiModifierList|>(...) [6]" style="filled" fillcolor=yellow];
|
218 [label="Function call: $subj$.R|kotlin/let|<R|KtModifierList|, R|FirModifierList.FirPsiModifierList|>(...) [6]" style="filled" fillcolor=yellow];
|
||||||
@@ -792,8 +792,8 @@ digraph kt44814_kt {
|
|||||||
190 -> {191};
|
190 -> {191};
|
||||||
191 -> {192};
|
191 -> {192};
|
||||||
192 -> {193};
|
192 -> {193};
|
||||||
193 -> {194 195 240};
|
193 -> {194 195 234};
|
||||||
193 -> {240} [style=dashed];
|
193 -> {234} [style=dashed];
|
||||||
194 -> {195};
|
194 -> {195};
|
||||||
194 -> {193} [color=green style=dashed];
|
194 -> {193} [color=green style=dashed];
|
||||||
195 -> {196};
|
195 -> {196};
|
||||||
@@ -818,9 +818,9 @@ digraph kt44814_kt {
|
|||||||
213 -> {214};
|
213 -> {214};
|
||||||
214 -> {215 219};
|
214 -> {215 219};
|
||||||
215 -> {216};
|
215 -> {216};
|
||||||
216 -> {218 234};
|
216 -> {218 245};
|
||||||
216 -> {217} [style=dotted];
|
216 -> {217} [style=dotted];
|
||||||
216 -> {234} [style=dashed];
|
216 -> {245} [style=dashed];
|
||||||
217 -> {218} [color=green];
|
217 -> {218} [color=green];
|
||||||
217 -> {223} [color=red];
|
217 -> {223} [color=red];
|
||||||
218 -> {220};
|
218 -> {220};
|
||||||
@@ -841,21 +841,21 @@ digraph kt44814_kt {
|
|||||||
232 -> {233} [style=dotted];
|
232 -> {233} [style=dotted];
|
||||||
234 -> {235};
|
234 -> {235};
|
||||||
235 -> {236};
|
235 -> {236};
|
||||||
236 -> {237};
|
236 -> {237 239};
|
||||||
237 -> {238};
|
237 -> {238};
|
||||||
238 -> {239};
|
238 -> {239};
|
||||||
239 -> {217};
|
239 -> {240};
|
||||||
240 -> {241};
|
240 -> {241};
|
||||||
241 -> {242};
|
241 -> {242};
|
||||||
242 -> {243 245};
|
242 -> {243};
|
||||||
243 -> {244};
|
243 -> {244};
|
||||||
244 -> {245};
|
244 -> {194};
|
||||||
245 -> {246};
|
245 -> {246};
|
||||||
246 -> {247};
|
246 -> {247};
|
||||||
247 -> {248};
|
247 -> {248};
|
||||||
248 -> {249};
|
248 -> {249};
|
||||||
249 -> {250};
|
249 -> {250};
|
||||||
250 -> {194};
|
250 -> {217};
|
||||||
251 -> {252};
|
251 -> {252};
|
||||||
252 -> {253};
|
252 -> {253};
|
||||||
253 -> {254};
|
253 -> {254};
|
||||||
|
|||||||
Reference in New Issue
Block a user