in dotnet/CSharpSourceGraphExtraction/GraphBuilders/DataFlowGraphBuilder.cs [10:102]
public static void AddDataFlowEdges(SourceGraph sourceGraph, SyntaxNodeOrToken tokenOfInterest,
ICollection<SyntaxNodeOrToken> forbiddenNodes = null,
ICollection<Edge<SyntaxNodeOrToken, SourceGraphEdge>> addedEdges = null)
{
var semanticModel = sourceGraph.SemanticModel;
//There's nothing before the declaration, so we don't need to bother:
if (sourceGraph.VariableDeclarationNodes.Contains(tokenOfInterest))
{
return;
}
//We only ever need to visit each node once, so collect visited nodes here:
var visitedNodes = new HashSet<(SyntaxNodeOrToken, bool)>();
//Start from all predecessors of the token of interest:
var toVisit = new Stack<(SyntaxNodeOrToken node, bool haveFoundUse)>();
foreach (var (_, label, target) in sourceGraph.GetOutEdges(tokenOfInterest))
{
if (label != SourceGraphEdge.LastUsedVariable || (forbiddenNodes?.Contains(target) ?? false))
{
continue;
}
if (visitedNodes.Add((target, false)))
{
toVisit.Push((target, false));
}
}
var nodeOfInterest = tokenOfInterest.IsToken ? tokenOfInterest.AsToken().Parent : tokenOfInterest.AsNode();
ISymbol symbolToLookFor = nodeOfInterest != null ? semanticModel.GetSymbolInfo(nodeOfInterest).Symbol?.OriginalDefinition : null;
string nodeLabelToLookFor = tokenOfInterest.ToString();
while (toVisit.Count > 0)
{
var (node, haveFoundUse) = toVisit.Pop();
var nodeSyntaxNode = node.IsToken ? node.AsToken().Parent : node.AsNode();
var nodeSymbol = nodeSyntaxNode != null ? semanticModel.GetSymbolInfo(nodeSyntaxNode).Symbol?.OriginalDefinition : null;
bool matches;
if (symbolToLookFor == null || nodeSymbol == null)
{
// This may happen in cases where Roslyn doesn't have symbol info
// or when one of the nodes is a dummy node (and thus doesn't belong to the SyntaxTree)
matches = node.ToString().Equals(nodeLabelToLookFor);
}
else
{
matches = nodeSymbol.Equals(symbolToLookFor);
}
if (matches)
{
if (!haveFoundUse)
{
var lastUseEdge = new Edge<SyntaxNodeOrToken, SourceGraphEdge>(tokenOfInterest, SourceGraphEdge.LastUse, node);
if (sourceGraph.AddEdge(lastUseEdge))
{
addedEdges?.Add(lastUseEdge);
}
haveFoundUse = true;
}
if (sourceGraph.VariableWriteNodes.Contains(node))
{
var lastWriteEdge = new Edge<SyntaxNodeOrToken, SourceGraphEdge>(tokenOfInterest, SourceGraphEdge.LastWrite, node);
if (sourceGraph.AddEdge(lastWriteEdge))
{
addedEdges?.Add(lastWriteEdge);
}
//We are done with this path -- we found a use and a write!
continue;
}
//There's nothing before the declaration, so we don't need to bother to recurse further:
if (sourceGraph.VariableDeclarationNodes.Contains(node))
{
continue;
}
}
foreach (var (_, label, target) in sourceGraph.GetOutEdges(node))
{
if (label != SourceGraphEdge.LastUsedVariable || (forbiddenNodes?.Contains(target) ?? false))
{
continue;
}
if (visitedNodes.Add((target, haveFoundUse))) {
toVisit.Push((target, haveFoundUse));
}
}
}
}