public static AnalysisResults Run(
            SolcSourceInfo[] sourcesList,
            SolcBytecodeInfo[] byteCodeData)
        {
            // Parses the ast tree json for all the sources, and creates a dictionary with the source file index/ID as the key.
            var(astDict, fullNodeArray) = AstHelper.IndexAstNodes(sourcesList);

            // source node lists by their source code range length (shortest / most precise lengths first)
            foreach (var arr in astDict.Values)
            {
                Array.Sort(arr, (a, b) => a.SourceRange.Length - b.SourceRange.Length);
            }

            // AST nodes matching entries in the evm.bytecode.sourcemap output from solc.
            // These are source code ranges that are executing during deployment of a contract - such as the constructor function.
            var sourceMapNodes = new List <AstNode>();

            // AST nodes matching entries in the evm.bytecodeDeployed.sourcemap output from solc.
            // These are source code ranges that can be executed by transactions and calls to a deployed contract.
            var sourceMapDeployedNodes = new List <AstNode>();

            // Dictionary of all parsed sourcemap entries.
            var sourceMaps = new Dictionary <(string FileName, string ContractName, string BytecodeHash), (SourceMapEntry[] nonDeployed, SourceMapEntry[] deployed)>();

            foreach (var entry in byteCodeData)
            {
                var sourceMapEntriesNonDeployed = new List <SourceMapEntry>();
                var sourceMapEntriesDeployed    = new List <SourceMapEntry>();

                // Match evm.bytecode.sourcemap entries to ast nodes.
                if (!string.IsNullOrEmpty(entry.SourceMap))
                {
                    var(sourceMapItems, matchedNodes) = ParseSourceMap(entry.SourceMap, astDict);
                    sourceMapEntriesNonDeployed.AddRange(sourceMapItems);
                    sourceMapNodes.AddRange(matchedNodes);
                }

                // Match evm.bytecodeDeployed.sourcemap entries to ast nodes.
                if (!string.IsNullOrEmpty(entry.SourceMapDeployed))
                {
                    var(sourceMapItems, matchedNodes) = ParseSourceMap(entry.SourceMapDeployed, astDict);
                    sourceMapEntriesDeployed.AddRange(sourceMapItems);
                    sourceMapDeployedNodes.AddRange(matchedNodes);
                }

                if (sourceMapEntriesNonDeployed.Count == 0 && sourceMapEntriesDeployed.Count == 0)
                {
                    continue;
                }

                sourceMaps.Add((entry.FilePath, entry.ContractName, entry.BytecodeHash), (sourceMapEntriesNonDeployed.ToArray(), sourceMapEntriesDeployed.ToArray()));
            }

            // Get nodes with duplicates filtered out, and the useless/harmful node types fitlered out
            var nodeLists = new
            {
                SourceMapNodes         = AstHelper.GetNodesNotOfTypes(sourcesList, sourceMapNodes, FilterNodeTypes).Distinct().ToArray(),
                SourceMapDeployedNodes = AstHelper.GetNodesNotOfTypes(sourcesList, sourceMapDeployedNodes, FilterNodeTypes).Distinct().ToArray(),
                AllActiveNodes         = AstHelper.GetNodesOfTypes(sourcesList, fullNodeArray, InterestNodeTypes).Distinct().ToArray(),
                FunctionNodes          = GetFunctionNodesWithActiveCode(sourcesList, fullNodeArray).ToArray()
            };

#if DEBUG_AST
            // Get node lists with the subsets filtered out
            var uniqueSubsetFiltered = new {
                SourceMapNodes         = AstHelper.RemoveSubsets(nodeLists.SourceMapNodes),
                SourceMapDeployedNodes = AstHelper.RemoveSubsets(nodeLists.SourceMapDeployedNodes),
                AllActiveNodes         = AstHelper.RemoveSubsets(nodeLists.AllActiveNodes),
            };

            // Get node lists with the superset nodes filtered out
            var uniqueSupersetFiltered = new {
                SourceMapNodes         = AstHelper.RemoveSupersets(nodeLists.SourceMapNodes),
                SourceMapDeployedNodes = AstHelper.RemoveSupersets(nodeLists.SourceMapDeployedNodes),
                AllActiveNodes         = AstHelper.RemoveSupersets(nodeLists.AllActiveNodes)
            };


            // Get the node types for the various node lists
            var nodeTypes = new {
                SourceMapNodes = nodeLists.SourceMapNodes.Select(s => s.NodeType).Distinct().OrderBy(s => s).ToArray(),
                SourceMapNodesSubsetFiltered   = uniqueSubsetFiltered.SourceMapNodes.Select(s => s.NodeType).Distinct().OrderBy(s => s).ToArray(),
                SourceMapNodesSupersetFiltered = uniqueSupersetFiltered.SourceMapNodes.Select(s => s.NodeType).Distinct().OrderBy(s => s).ToArray(),

                SourceMapDeployedNodes = nodeLists.SourceMapDeployedNodes.Select(s => s.NodeType).Distinct().OrderBy(s => s).ToArray(),
                SourceMapDeployedNodesSubsetFiltered   = uniqueSubsetFiltered.SourceMapDeployedNodes.Select(s => s.NodeType).Distinct().OrderBy(s => s).ToArray(),
                SourceMapDeployedNodesSupersetFiltered = uniqueSupersetFiltered.SourceMapDeployedNodes.Select(s => s.NodeType).Distinct().OrderBy(s => s).ToArray(),

                AllActiveNodes = nodeLists.AllActiveNodes.Select(s => s.NodeType).Distinct().OrderBy(s => s).ToArray(),
                AllActiveNodesSubsetFiltered   = uniqueSubsetFiltered.AllActiveNodes.Select(s => s.NodeType).Distinct().OrderBy(s => s).ToArray(),
                AllActiveNodesSupersetFiltered = uniqueSupersetFiltered.AllActiveNodes.Select(s => s.NodeType).Distinct().OrderBy(s => s).ToArray(),
            };
#endif

            // Create our combined list.
            var combinedSourceMapNodes = nodeLists.SourceMapDeployedNodes.Concat(nodeLists.SourceMapNodes).Distinct().ToArray();

            // Find any nodes that represent active code but are not found in nodes that correspond to source map entries.
            var unreachableNodes = nodeLists.AllActiveNodes.Where(a => !combinedSourceMapNodes.Any(b => b.SourceRange.Contains(a.SourceRange))).ToArray();


            // Check if each node is a branch to add to our branch nodes list.
            List <(AstNode, BranchType)> branchNodes = new List <(AstNode, BranchType)>();

            foreach (var node in fullNodeArray)
            {
                // Obtain our branch type
                BranchType branchType = GetNodeBranchType(node);

                // If it's not a branch, we skip it
                if (branchType == BranchType.None)
                {
                    continue;
                }

                // Add it to our list
                branchNodes.Add((node, branchType));
            }

            // Create our initial analysis results.
            var analysisResults = new AnalysisResults
            {
                FullNodeList     = fullNodeArray,
                ReachableNodes   = combinedSourceMapNodes,
                AllActiveNodes   = nodeLists.AllActiveNodes,
                UnreachableNodes = unreachableNodes,
                BranchNodes      = branchNodes.ToArray(),
                FunctionNode     = nodeLists.FunctionNodes,
                SourceMaps       = sourceMaps
            };

            // Return our analysis results
            return(analysisResults);
        }