private static IEnumerable <VariableDeclaration> AggregateFunctionVariablesInfo(
            FunctionDeclaration functionDeclaration,
            INodeInfoExtractor infoExtractor)
        {
            var variables = new HashSet <VariableDeclaration>(functionDeclaration.Parameters);
            var queue     = new Queue <Node>();

            queue.Enqueue(functionDeclaration.Body);
            while (queue.Count > 0)
            {
                var node = queue.Dequeue();
                if (node is FunctionDeclaration)
                {
                    continue;
                }

                variables.UnionWith(infoExtractor.ExtractInfo(node));
                foreach (var child in node.Children())
                {
                    queue.Enqueue(child);
                }
            }

            return(variables);
        }
        TransitiveCallClosure(
            ICallGraphGenerator callGraphGenerator,
            Node root,
            INodeInfoExtractor variablesExtractor)
        {
            var callGraph        = callGraphGenerator.BuildCallGraph(root);
            var callGraphClosure = callGraph.TransitiveClosure();

            return(AggregateFunctionDeclarations(root).ToDictionary(fun => fun, function =>
            {
                var rootVariables = AggregateFunctionVariablesInfo(function, variablesExtractor);
                var closureVariables = callGraphClosure[function]
                                       .SelectMany(foo => AggregateFunctionVariablesInfo(foo, variablesExtractor));
                return (IReadOnlyCollection <VariableDeclaration>)rootVariables.Concat(closureVariables).ToList();
            }));
        }
        private static NodeVariableAccessMapping AggregateNodeVariableInfo(
            Node root,
            FunctionVariableAccessMapping infoPerFunction,
            INodeInfoExtractor infoExtractor)
        {
            var result = root.Children()
                         .SelectMany(child => AggregateNodeVariableInfo(child, infoPerFunction, infoExtractor))
                         .ToDictionary(x => x.Key, x => x.Value);

            var descendantsDeclarations = root is FunctionDeclaration
                ? new List <VariableDeclaration>()
                : root.Children().SelectMany(child => result[child]);

            var callDeclarations = (root is FunctionCall call && infoPerFunction.ContainsKey(call.Declaration))
                ? infoPerFunction[call.Declaration]
                : new List <VariableDeclaration>();

            result[root] = new HashSet <VariableDeclaration>(
                infoExtractor.ExtractInfo(root)
                .Concat(descendantsDeclarations)
                .Concat(callDeclarations));
            return(result);
        }