private static void CopySubgraphAroundHole()

in DataExtraction/SourceGraphExtractionUtils/GraphDataExtractor.cs [686:755]


        private static void CopySubgraphAroundHole(
            SourceGraph sourceGraph,
            IEnumerable<SyntaxNodeOrToken> targetNodes,
            ISet<SyntaxNodeOrToken> forbiddenNodes,
            SourceGraph resultGraph,
            int numSymbolsAddedSoFar = 0)
        {
            var allowedNodes = new HashSet<SyntaxNodeOrToken>(sourceGraph.Nodes.Where(n => !forbiddenNodes.Contains(n)));

            /// <summary>
            /// Filter edges that are "active" in the output graph.
            ///
            /// The current implementation allows all edges except from the GuardedBy[Negation].
            /// GuardedBy[Negation] edges are inlcuded only if the label of the source node
            /// is in the set of identifiers of the descendants of the target node.
            /// </summary>
            bool IsActiveEdge(Edge<SyntaxNodeOrToken, SourceGraphEdge> edge)
            {
                if (edge.Label != SourceGraphEdge.GuardedBy && edge.Label != SourceGraphEdge.GuardedByNegation)
                {
                    return true;
                }

                var sourceNodeLabel = edge.Source.ToString();
                if (edge.Target.IsToken)
                {
                    return edge.Target.ToString().Equals(sourceNodeLabel);
                }

                // If our target token (the only element of forbidden nodes at this point) is a descendant of the target,
                // we are considering a slot inside a condition. In that case, keep all GuardedBy edges.
                if (edge.Target.AsNode().DescendantTokens().Any(token => forbiddenNodes.Contains(token)))
                {
                    return true;
                }

                return edge.Target.AsNode().DescendantTokens()
                                           .Where(t => allowedNodes.Contains(t))
                                           .Any(t => t.ToString().Equals(sourceNodeLabel));
            }

            var nodesToSyntaxRemainingBudget = new Dictionary<SyntaxNodeOrToken, int>();
            foreach (var targetNode in targetNodes)
            {
                GetReachableNodes(sourceGraph, OnlySyntaxEdgesCost, MAX_SYNTAX_BUDGET, targetNode, allowedNodes, nodesToSyntaxRemainingBudget, IsActiveEdge);
            }

            var nodesToDataflowRemainingBudget = new Dictionary<SyntaxNodeOrToken, int>();
            foreach (var targetNode in targetNodes)
            {
                GetReachableNodes(sourceGraph, OnlyDataflowEdgesCost, MAX_DATAFLOW_BUDGET, targetNode, nodesToSyntaxRemainingBudget.Keys, nodesToDataflowRemainingBudget, IsActiveEdge);
                // This ensures that all targetNodes appear in the nodesToDataflowRemainingBudget
                nodesToDataflowRemainingBudget[targetNode] = MAX_DATAFLOW_BUDGET + MAX_SYNTAX_BUDGET;
            }

            // Order the nodes by cost so that nodes smaller cost are reached first.
            foreach (var node in nodesToDataflowRemainingBudget.Keys.OrderByDescending(n => nodesToDataflowRemainingBudget[n]))
            {
                foreach (var edge in sourceGraph.GetOutEdges(node))
                {
                    if (edge.Label == SourceGraphEdge.LastUsedVariable) continue;
                    if (resultGraph.CountNodes > MAX_NUM_NODES_PER_GRAPH + ADDITIONAL_NODES_PER_CANDIDATE_SYMBOL * numSymbolsAddedSoFar &&
                        !(resultGraph.ContainsNode(node) && resultGraph.ContainsNode(edge.Target))) continue;
                    if (nodesToDataflowRemainingBudget.ContainsKey(edge.Target) && !forbiddenNodes.Contains(node) && !forbiddenNodes.Contains(edge.Target))
                    {
                        resultGraph.AddEdge(node, edge.Label, edge.Target);
                    }
                }
            }
        }