Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.cfa.util
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
// ------------------------------ Graph Traversal ------------------------------
enum class TraverseDirection {
Forward, Backward
}
fun ControlFlowGraph.traverse(
direction: TraverseDirection,
visitor: ControlFlowGraphVisitor<*, D>,
data: D
) {
for (node in getNodesInOrder(direction)) {
node.accept(visitor, data)
(node as? CFGNodeWithSubgraphs<*>)?.subGraphs?.forEach { it.traverse(direction, visitor, data) }
}
}
fun ControlFlowGraph.traverse(
direction: TraverseDirection,
visitor: ControlFlowGraphVisitorVoid
) {
traverse(direction, visitor, null)
}
// ---------------------- Path-sensitive data collection -----------------------
fun ControlFlowGraph.collectDataForNode(
direction: TraverseDirection,
initialInfo: I,
visitor: ControlFlowGraphVisitor>>,
visitSubGraphs: Boolean = true
): Map, I> {
val nodeMap = LinkedHashMap, I>()
val startNode = getEnterNode(direction)
nodeMap[startNode] = initialInfo
val changed = mutableMapOf, Boolean>()
do {
collectDataForNodeInternal(direction, initialInfo, visitor, nodeMap, changed, visitSubGraphs)
} while (changed.any { it.value })
return nodeMap
}
private fun ControlFlowGraph.collectDataForNodeInternal(
direction: TraverseDirection,
initialInfo: I,
visitor: ControlFlowGraphVisitor>>,
nodeMap: MutableMap, I>,
changed: MutableMap, Boolean>,
visitSubGraphs: Boolean = true
) {
val nodes = getNodesInOrder(direction)
for (node in nodes) {
if (visitSubGraphs && direction == TraverseDirection.Backward && node is CFGNodeWithSubgraphs<*>) {
node.subGraphs.forEach { it.collectDataForNodeInternal(direction, initialInfo, visitor, nodeMap, changed) }
}
val previousNodes = when (direction) {
TraverseDirection.Forward -> node.previousCfgNodes
TraverseDirection.Backward -> node.followingCfgNodes
}
// One noticeable different against the path-unaware version is, here, we pair the control-flow info with the label.
val previousData =
previousNodes.mapNotNull {
val k = when (direction) {
TraverseDirection.Forward -> node.incomingEdges[it]?.label ?: NormalPath
TraverseDirection.Backward -> node.outgoingEdges[it]?.label ?: NormalPath
}
val v = nodeMap[it] ?: return@mapNotNull null
k to v
}
val data = nodeMap[node]
val newData = node.accept(visitor, previousData)
val hasChanged = newData != data
changed[node] = hasChanged
if (hasChanged) {
nodeMap[node] = newData
}
if (visitSubGraphs && direction == TraverseDirection.Forward && node is CFGNodeWithSubgraphs<*>) {
node.subGraphs.forEach { it.collectDataForNodeInternal(direction, initialInfo, visitor, nodeMap, changed) }
}
}
}