/// <summary> /// Exports a subset of the type graph in a form suitable for visualization. /// </summary> public GraphVizGraph ExportTypeGraph(Predicate <NullabilityNode> nodeFilter) { if (nodeFilter == null) { throw new ArgumentNullException("includeInGraph"); } GraphVizGraph graph = new GraphVizGraph { rankdir = "BT" }; List <NullabilityEdge> graphEdges = new List <NullabilityEdge>(); foreach (NullabilityNode node in typeSystem.AllNodes) { foreach (NullabilityEdge edge in node.IncomingEdges) { if (nodeFilter(edge.Source) || nodeFilter(edge.Target)) { graphEdges.Add(edge); } } } // Select nodes based on include filter IEnumerable <NullabilityNode> includedNodes = typeSystem.AllNodes.Where(n => nodeFilter(n)); // Add nodes necessary for selected edges includedNodes = includedNodes.Concat(graphEdges.Select(g => g.Source)).Concat(graphEdges.Select(g => g.Target)).Distinct(); var nodeIds = new Dictionary <NullabilityNode, string>(); foreach (NullabilityNode node in includedNodes) { string nodeId = $"n{nodeIds.Count}"; nodeIds.Add(node, nodeId); GraphVizNode gvNode = new GraphVizNode(nodeId) { label = node.Name, fontsize = 32 }; if (node is SpecialNullabilityNode) { gvNode.fontsize = 24; } else { gvNode.fontsize = 12; gvNode.margin = "0.05,0.05"; gvNode.height = 0; gvNode.shape = "box"; } if (node.Location != null) { gvNode.label += $"\n{node.Location.EndPosToString()}"; } //gvNode.label += $"\n{node.NullType}"; graph.AddNode(gvNode); } foreach (NullabilityEdge edge in graphEdges) { var gvEdge = new GraphVizEdge(nodeIds[edge.Source], nodeIds[edge.Target]); gvEdge.label = edge.Label; gvEdge.fontsize = 8; if (edge.IsError) { gvEdge.color = "red"; } else if (edge.Capacity == 0) { gvEdge.color = "yellow"; } graph.AddEdge(gvEdge); } return(graph); }
public void AddNode(GraphVizNode node) { nodes.Add(node); }