public void RemoveSameClasses() { var handledNodes = new HashSet <ICallGraphNode>(Nodes.Count); var processingNodes = new Queue <(ICallGraphNode, ICallGraphNode)>(); EntryNodes.Clear(); Nodes.Clear(); var roots = Roots.Values; Roots = new Dictionary <MethodUniqueSignature, ICallGraphNode>(); foreach (var rootNode in roots) { // we keep all parents of root(s) if (!handledNodes.Add(rootNode)) { continue; } var mappedRootNode = new CallInfoNode(rootNode.Info); Roots.Add(mappedRootNode.MethodSignature, mappedRootNode); Nodes.Add(mappedRootNode.MethodSignature, mappedRootNode); if (rootNode.InNodes.Count == 0 && !EntryNodes.ContainsKey(mappedRootNode.MethodSignature)) { EntryNodes.Add(mappedRootNode.MethodSignature, mappedRootNode); } foreach (var inNode in rootNode.InNodes) { var mappedNode = new CallInfoNode(inNode.Info); mappedRootNode.InNodes.Add(mappedNode); mappedNode.OutNodes.Add(mappedRootNode); if (!Nodes.ContainsKey(mappedNode.MethodSignature)) { Nodes.Add(mappedNode.MethodSignature, mappedNode); if (inNode.InNodes.Count == 0) { if (!EntryNodes.ContainsKey(mappedNode.MethodSignature)) { EntryNodes.Add(mappedNode.MethodSignature, mappedNode); } } else { processingNodes.Enqueue((inNode, mappedNode)); } } } } // and keep only different classes for other parents while (processingNodes.Count > 0) { var(node, mappedNode) = processingNodes.Dequeue(); if (!handledNodes.Add(node)) { continue; } var mappedInNodes = new HashSet <ICallGraphNode>(mappedNode.InNodes); foreach (var inNode in node.InNodes) { var classSignature = new MethodUniqueSignature(inNode.MethodSignature.ToClassName()); if (Nodes.TryGetValue(classSignature, out var mappedInNode)) { if (mappedInNode != mappedNode && mappedInNodes.Add(mappedInNode)) { mappedInNode.OutNodes.Add(mappedNode); } } else { mappedInNode = new CallInfoNode(new CallInfo( 0, null, inNode.AssemblyInfo, classSignature, inNode.IsPublic, null)); mappedInNodes.Add(mappedInNode); mappedInNode.OutNodes.Add(mappedNode); Nodes.Add(mappedInNode.MethodSignature, mappedInNode); } if (inNode.InNodes.Count == 0) { if (!EntryNodes.ContainsKey(mappedInNode.MethodSignature)) { EntryNodes.Add(mappedInNode.MethodSignature, mappedInNode); } } else { processingNodes.Enqueue((inNode, mappedInNode)); } } if (mappedNode.InNodes.Count != mappedInNodes.Count) { mappedNode.InNodes.Clear(); mappedNode.InNodes.AddRange(mappedInNodes); } } }
public void RemoveNonPublicMiddleNodes() { var cache = new Dictionary <ICallGraphNode, List <ICallGraphNode> >(); var processingNodes = new HashSet <ICallGraphNode>(EntryNodes.Values); while (processingNodes.Count > 0) { var node = processingNodes.First(); processingNodes.Remove(node); for (var i = node.OutNodes.Count - 1; i >= 0; i--) { var outNode = node.OutNodes[i]; if (outNode.OutNodes.Count == 0) { continue; } if (outNode.IsPublic) { processingNodes.Add(outNode); continue; } node.OutNodes.RemoveAt(i); var publicNodes = FindPublicOutNodes(outNode); node.OutNodes.AddRange(publicNodes); foreach (var graphNode in publicNodes) { processingNodes.Add(graphNode); } } for (var i = node.InNodes.Count - 1; i >= 0; i--) { var inNode = node.InNodes[i]; if (!inNode.IsPublic && !EntryNodes.ContainsKey(inNode.MethodSignature)) { node.InNodes.RemoveAt(i); } } } List <ICallGraphNode> FindPublicOutNodes(ICallGraphNode node) { if (cache.TryGetValue(node, out var result)) { return(result); } result = new List <ICallGraphNode>(); foreach (var outNode in node.OutNodes) { if (outNode.IsPublic || outNode.OutNodes.Count == 0) { result.Add(outNode); } else { result.AddRange(FindPublicOutNodes(outNode)); } } if (node.InNodes.Count > 1) { cache.Add(node, result); } Nodes.Remove(node.MethodSignature); return(result); } }