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); }