From 3454ae7ca4730211c8808cf43e196c2ae4753ed1 Mon Sep 17 00:00:00 2001 From: Oleg Ivanov Date: Wed, 29 Jul 2020 17:43:37 +0300 Subject: [PATCH] [FIR] Add VariableStorage and flow on nodes into CFG reference --- .../dfa/FirControlFlowGraphReferenceImpl.kt | 13 ++++++-- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 30 ++++++++++++------- .../kotlin/fir/resolve/dfa/VariableStorage.kt | 8 ++--- .../FirDeclarationsResolveTransformer.kt | 8 ++--- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirControlFlowGraphReferenceImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirControlFlowGraphReferenceImpl.kt index 171f0efa22e..993091577b6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirControlFlowGraphReferenceImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirControlFlowGraphReferenceImpl.kt @@ -7,11 +7,15 @@ package org.jetbrains.kotlin.fir.resolve.dfa import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference +import org.jetbrains.kotlin.fir.resolve.dfa.cfg.CFGNode import org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirVisitor -class FirControlFlowGraphReferenceImpl(val controlFlowGraph: ControlFlowGraph) : FirControlFlowGraphReference() { +class FirControlFlowGraphReferenceImpl( + val controlFlowGraph: ControlFlowGraph, + val dataFlowInfo: DataFlowInfo? = null +) : FirControlFlowGraphReference() { override val source: FirSourceElement? get() = null override fun acceptChildren(visitor: FirVisitor, data: D) {} @@ -21,5 +25,10 @@ class FirControlFlowGraphReferenceImpl(val controlFlowGraph: ControlFlowGraph) : } } +class DataFlowInfo(val variableStorage: VariableStorage, val flowOnNodes: Map, Flow>) + val FirControlFlowGraphReference.controlFlowGraph: ControlFlowGraph? - get() = (this as? FirControlFlowGraphReferenceImpl)?.controlFlowGraph \ No newline at end of file + get() = (this as? FirControlFlowGraphReferenceImpl)?.controlFlowGraph + +val FirControlFlowGraphReference.dataFlowInfo: DataFlowInfo? + get() = (this as? FirControlFlowGraphReferenceImpl)?.dataFlowInfo \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index be51af3c55e..c1069f5751a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.contracts.description.ConeConstantReference import org.jetbrains.kotlin.fir.contracts.description.ConeReturnsEffectDeclaration import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.PersistentImplicitReceiverStack import org.jetbrains.kotlin.fir.resolve.ResolutionMode @@ -33,15 +34,21 @@ import org.jetbrains.kotlin.utils.addToStdlib.runIf class DataFlowAnalyzerContext( val graphBuilder: ControlFlowGraphBuilder, - val variableStorage: VariableStorage, - val flowOnNodes: MutableMap, FLOW>, + variableStorage: VariableStorage, + flowOnNodes: MutableMap, FLOW>, val variablesForWhenConditions: MutableMap ) { + var flowOnNodes = flowOnNodes + private set + var variableStorage = variableStorage + private set + fun reset() { graphBuilder.reset() - variableStorage.reset() - flowOnNodes.clear() variablesForWhenConditions.clear() + + variableStorage = variableStorage.clear() + flowOnNodes = mutableMapOf() } companion object { @@ -160,7 +167,7 @@ abstract class FirDataFlowAnalyzer( functionEnterNode.mergeIncomingFlow(shouldForkFlow = previousNode != null) } - fun exitFunction(function: FirFunction<*>): ControlFlowGraph { + fun exitFunction(function: FirFunction<*>): FirControlFlowGraphReference { if (function is FirAnonymousFunction) { return exitAnonymousFunction(function) } @@ -171,12 +178,13 @@ abstract class FirDataFlowAnalyzer( variableStorage.removeRealVariable(valueParameter.symbol) } } + val variableStorage = variableStorage + val flowOnNodes = context.flowOnNodes + if (graphBuilder.isTopLevel()) { - context.flowOnNodes.clear() - variableStorage.reset() - graphBuilder.reset() + context.reset() } - return graph + return FirControlFlowGraphReferenceImpl(graph, DataFlowInfo(variableStorage, flowOnNodes)) } // ----------------------------------- Anonymous function ----------------------------------- @@ -188,12 +196,12 @@ abstract class FirDataFlowAnalyzer( functionEnterNode.mergeIncomingFlow() } - private fun exitAnonymousFunction(anonymousFunction: FirAnonymousFunction): ControlFlowGraph { + private fun exitAnonymousFunction(anonymousFunction: FirAnonymousFunction): FirControlFlowGraphReference { val (functionExitNode, postponedLambdaExitNode, graph) = graphBuilder.exitAnonymousFunction(anonymousFunction) // TODO: questionable postponedLambdaExitNode?.mergeIncomingFlow() functionExitNode.mergeIncomingFlow() - return graph + return FirControlFlowGraphReferenceImpl(graph) } fun visitPostponedAnonymousFunction(anonymousFunction: FirAnonymousFunction) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt index 2ff918ac0f6..282732b54c1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt @@ -31,6 +31,8 @@ class VariableStorage(private val session: FirSession) { private val realVariables: MutableMap = HashMap() private val syntheticVariables: MutableMap = HashMap() + fun clear(): VariableStorage = VariableStorage(session) + fun getOrCreateRealVariableWithoutUnwrappingAlias(flow: Flow, symbol: AbstractFirBasedSymbol<*>, fir: FirElement): RealVariable { val realFir = fir.unwrapElement() val identifier = getIdentifierBySymbol(flow, symbol, realFir) @@ -139,12 +141,6 @@ class VariableStorage(private val session: FirSession) { syntheticVariables.remove(variable.fir) } - fun reset() { - counter = 0 - realVariables.clear() - syntheticVariables.clear() - } - @OptIn(ExperimentalContracts::class) fun AbstractFirBasedSymbol<*>?.isStable(originalFir: FirElement): Boolean { contract { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index bffe4c838ce..5a237acc072 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -521,8 +521,8 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor transformDeclarationContent(function, data).also { if (functionIsNotAnalyzed) { val result = it.single as FirFunction<*> - val controlFlowGraph = dataFlowAnalyzer.exitFunction(result) - result.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(controlFlowGraph)) + val controlFlowGraphReference = dataFlowAnalyzer.exitFunction(result) + result.replaceControlFlowGraphReference(controlFlowGraphReference) } } as CompositeTransformResult } @@ -593,8 +593,8 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor } } - val graph = dataFlowAnalyzer.exitFunction(constructor) - constructor.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(graph)) + val controlFlowGraphReference = dataFlowAnalyzer.exitFunction(constructor) + constructor.replaceControlFlowGraphReference(controlFlowGraphReference) constructor.compose() } }