FIR CFA: attach method graphs to class exit node

Even for non-local classes. This ensures that the CFG edges in this case
will only go to a subgraph, not to an unrelated graph.
This commit is contained in:
pyos
2022-12-09 13:22:17 +01:00
committed by Dmitriy Novozhilov
parent aadea0e26f
commit 74758278d7
47 changed files with 1245 additions and 1181 deletions
@@ -426,6 +426,7 @@ class ControlFlowGraphBuilder {
var prevInitPartNode: CFGNode<*>? = null
for (declaration in klass.declarations) {
val graph = when (declaration) {
// TODO: property accessors?
is FirProperty -> declaration.controlFlowGraphReference?.controlFlowGraph
is FirField -> declaration.controlFlowGraphReference?.controlFlowGraph
is FirAnonymousInitializer -> declaration.controlFlowGraphReference?.controlFlowGraph
@@ -446,6 +447,23 @@ class ControlFlowGraphBuilder {
addEdge(node, exitNode, preferredKind = EdgeKind.CfgForward)
if (prevInitPartNode != null) addEdge(prevInitPartNode!!, exitNode, preferredKind = EdgeKind.DeadForward)
exitNode.updateDeadStatus()
// TODO: Here we're assuming that the methods are called after the object is constructed, which is really not true
// (init blocks can call them). But FE1.0 did so too, hence the following code compiles and prints 0:
// val x: Int
// object {
// fun bar() = x
// init { x = bar() }
// }
// println(x)
for (declaration in klass.declarations) {
if (declaration !is FirFunction) continue
val graph = declaration.controlFlowGraphReference?.controlFlowGraph ?: continue
addEdge(exitNode, graph.enterNode, preferredKind = EdgeKind.CfgForward)
exitNode.addSubGraph(graph)
currentGraph.addSubGraph(graph)
}
return popGraph()
}
@@ -468,7 +486,6 @@ class ControlFlowGraphBuilder {
val node = createLocalClassExitNode(klass).also {
addNewSimpleNodeIfPossible(it)
}
visitLocalClassFunctions(klass, node)
addEdge(node, graph.enterNode, preferredKind = EdgeKind.CfgForward)
return node to graph
}
@@ -497,15 +514,6 @@ class ControlFlowGraphBuilder {
addEdge(graph.exitNode, exitNode, preferredKind = EdgeKind.CfgForward)
}
addEdge(enterNode, exitNode, preferredKind = EdgeKind.DfgForward)
// TODO: Here we're assuming that the methods are called after the object is constructed, which is really not true
// (init blocks can call them). But FE1.0 did so too, hence the following code compiles and prints 0:
// val x: Int
// object {
// fun bar() = x
// init { x = bar() }
// }
// println(x)
visitLocalClassFunctions(anonymousObject, exitNode)
lastNodes.push(exitNode)
return exitNode to graph
}
@@ -532,17 +540,6 @@ class ControlFlowGraphBuilder {
}
}
private fun visitLocalClassFunctions(klass: FirClass, node: CFGNodeWithSubgraphs<*>) {
klass.declarations.filterIsInstance<FirFunction>().forEach { function ->
val functionGraph = function.controlFlowGraphReference?.controlFlowGraph
if (functionGraph != null && functionGraph.owner == null) {
addEdge(node, functionGraph.enterNode, preferredKind = EdgeKind.CfgForward)
node.addSubGraph(functionGraph)
currentGraph.addSubGraph(functionGraph)
}
}
}
// ----------------------------------- Value parameters (and it's defaults) -----------------------------------
fun enterValueParameter(valueParameter: FirValueParameter): EnterDefaultArgumentsNode? {