-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathCodeGraphExtensions.cs
More file actions
130 lines (113 loc) · 4.62 KB
/
CodeGraphExtensions.cs
File metadata and controls
130 lines (113 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
namespace CodeGraph.Graph;
/// <summary>
/// Set of basic algorithms to build for higher algorithms
/// </summary>
public static class CodeGraphExtensions
{
public static CodeGraph Clone(this CodeGraph originalCodeGraph)
{
return originalCodeGraph.Clone(null, null);
}
/// <summary>
/// Clones the given code graph.
/// Relationships and code element can be filtered to generate sub graphs.
/// If no code element list is given (null) all code elements are returned.
/// </summary>
public static CodeGraph Clone(this CodeGraph originalCodeGraph, Func<Relationship, bool>? relationshipFilter,
HashSet<string>? codeElementIds)
{
List<CodeElement> includedOriginalElements;
if (codeElementIds is null)
{
includedOriginalElements = originalCodeGraph.Nodes.Values.ToList();
}
else
{
includedOriginalElements = originalCodeGraph.Nodes.Values
.Where(n => codeElementIds.Contains(n.Id))
.ToList();
}
var clonedCodeStructure = new CodeGraph();
// First pass: Create all elements without setting relationships
foreach (var originalElement in includedOriginalElements)
{
var clonedElement = CloneElement(originalElement);
clonedCodeStructure.Nodes[clonedElement.Id] = clonedElement;
}
// Second pass: Set relationships (parent / child / relationships)
foreach (var originalElement in includedOriginalElements)
{
var clonedElement = clonedCodeStructure.Nodes[originalElement.Id];
// Set parent
if (originalElement.Parent != null)
{
// Note that we may lose the parent!
var parent = clonedCodeStructure.TryGetCodeElement(originalElement.Parent?.Id);
clonedElement.Parent = parent;
}
// Set children
foreach (var originalChild in originalElement.Children)
{
var clonedChild = clonedCodeStructure.TryGetCodeElement(originalChild.Id);
if (clonedChild is null)
{
continue;
}
clonedElement.Children.Add(clonedChild);
}
// Set relationships
foreach (var originalRelationship in originalElement.Relationships)
{
if (relationshipFilter == null || relationshipFilter(originalRelationship))
{
if (clonedCodeStructure.Nodes.ContainsKey(originalRelationship.TargetId))
{
var clonedRelationship = new Relationship(
clonedElement.Id,
originalRelationship.TargetId,
originalRelationship.Type,
originalRelationship.Attributes
);
clonedRelationship.SourceLocations.AddRange(originalRelationship.SourceLocations);
clonedElement.Relationships.Add(clonedRelationship);
}
}
}
}
return clonedCodeStructure;
}
private static CodeElement CloneElement(CodeElement originalElement)
{
return originalElement.CloneSimple();
}
/// <summary>
/// Returns a subgraph with only the included elements and their associated relationships.
/// </summary>
public static CodeGraph SubGraphOf(this CodeGraph graph, HashSet<string> includedElements)
{
return graph.Clone(IncludeRelationship, includedElements);
bool IncludeRelationship(Relationship relationship)
{
return includedElements.Contains(relationship.SourceId) && includedElements.Contains(relationship.TargetId);
}
}
/// <summary>
/// Returns a subgraph with the root element and all children and associated relationships
/// </summary>
public static CodeGraph SubGraphOf(this CodeGraph graph, CodeElement rootElement)
{
var includedElements = rootElement.GetChildrenIncludingSelf();
return SubGraphOf(graph, includedElements);
}
public static HashSet<string> DeleteCodeElementAndAllChildren(this CodeGraph graph, string codeElementIds)
{
var element = graph.TryGetCodeElement(codeElementIds);
if (element is null)
{
return [];
}
var elementIdsToRemove = element.GetChildrenIncludingSelf().ToHashSet();
graph.RemoveCodeElements(elementIdsToRemove);
return elementIdsToRemove;
}
}