FIR CFA: do not remove provideDelegate subgraphs when rolling back
The receiver of the provideDelegate call is the same FirExpression as the delegate itself, so there's only one copy of the nodes in the first place; trying to remove subgraphs completely detaches objects inside it from the parent graph, which is not great for checkers. Note that currently if provideDelegate is not selected, there will be a stray FunctionCallExit node in the control flow graph. This commit *does not change that*. It has been there for a while. Don't @ me. I'll try to fix that. No promises.
This commit is contained in:
@@ -143,10 +143,6 @@ abstract class FirDataFlowAnalyzer(
|
||||
returnExpressionsOfAnonymousFunctionOrNull(function)
|
||||
?: error("anonymous function ${function.render()} not analyzed")
|
||||
|
||||
fun dropSubgraphFromCall(call: FirFunctionCall) {
|
||||
graphBuilder.dropSubgraphFromCall(call)
|
||||
}
|
||||
|
||||
// ----------------------------------- Named function -----------------------------------
|
||||
|
||||
fun enterFunction(function: FirFunction) {
|
||||
|
||||
-28
@@ -1381,34 +1381,6 @@ class ControlFlowGraphBuilder {
|
||||
lastNodes.reset()
|
||||
}
|
||||
|
||||
fun dropSubgraphFromCall(call: FirFunctionCall) {
|
||||
val graphs = mutableListOf<ControlFlowGraph>()
|
||||
|
||||
call.acceptChildren(object : FirDefaultVisitor<Unit, Any?>() {
|
||||
override fun visitElement(element: FirElement, data: Any?) {
|
||||
element.acceptChildren(this, null)
|
||||
}
|
||||
|
||||
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Any?) {
|
||||
anonymousFunction.controlFlowGraphReference?.accept(this, null)
|
||||
}
|
||||
|
||||
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?) {
|
||||
anonymousObject.controlFlowGraphReference?.accept(this, null)
|
||||
}
|
||||
|
||||
override fun visitControlFlowGraphReference(controlFlowGraphReference: FirControlFlowGraphReference, data: Any?) {
|
||||
val graph = controlFlowGraphReference.controlFlowGraph ?: return
|
||||
if (graph.owner == null) return
|
||||
graphs += graph
|
||||
}
|
||||
}, null)
|
||||
|
||||
for (graph in graphs) {
|
||||
currentGraph.removeSubGraph(graph)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------- Edge utils -----------------------------------
|
||||
|
||||
private fun addNewSimpleNode(node: CFGNode<*>, isDead: Boolean = false) {
|
||||
|
||||
+2
-3
@@ -336,6 +336,8 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
|
||||
val provideDelegateCall = wrappedDelegateExpression.delegateProvider as FirFunctionCall
|
||||
|
||||
// Resolve call for provideDelegate, without completion
|
||||
// TODO: this generates some nodes in the control flow graph which we don't want if we
|
||||
// end up not selecting this option.
|
||||
provideDelegateCall.transformSingle(this, ResolutionMode.ContextIndependent)
|
||||
|
||||
// If we got successful candidate for provideDelegate, let's select it
|
||||
@@ -365,9 +367,6 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
|
||||
return provideDelegateCall
|
||||
}
|
||||
|
||||
// Otherwise, rollback
|
||||
(provideDelegateCall as? FirFunctionCall)?.let { dataFlowAnalyzer.dropSubgraphFromCall(it) }
|
||||
|
||||
// Select delegate expression otherwise
|
||||
return delegateExpression
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user