Skip to content

Commit 99aeaa6

Browse files
committed
Performance optimization
1 parent 43dd8ff commit 99aeaa6

File tree

3 files changed

+47
-47
lines changed

3 files changed

+47
-47
lines changed

CSharpCodeAnalyst/Areas/GraphArea/GraphViewModel.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ private void FindIncomingCalls(CodeElement method)
647647

648648
// Use the node from the original graph
649649
var callee = _explorer.FindIncomingCalls(method.Id);
650-
AddToGraph(callee.Methods, callee.Calls);
650+
AddToGraph(callee.Elements, callee.Relationships);
651651
}
652652

653653
internal void FindIncomingCallsRecursive(CodeElement method)
@@ -659,7 +659,7 @@ internal void FindIncomingCallsRecursive(CodeElement method)
659659

660660
var callers =
661661
_explorer.FindIncomingCallsRecursive(method.Id);
662-
AddToGraph(callers.Methods, callers.Calls);
662+
AddToGraph(callers.Elements, callers.Relationships);
663663
}
664664

665665

@@ -695,7 +695,7 @@ private void FindOutgoingCalls(CodeElement? method)
695695
}
696696

697697
var callers = _explorer.FindOutgoingCalls(method.Id);
698-
AddToGraph(callers.Methods, callers.Calls);
698+
AddToGraph(callers.Elements, callers.Relationships);
699699
}
700700

701701
private static bool IsCallable(CodeElement? method)

CSharpCodeAnalyst/Exploration/CodeGraphExplorer.cs

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ public class CodeGraphExplorer : ICodeGraphExplorer
1111
public void LoadCodeGraph(CodeGraph graph)
1212
{
1313
_codeGraph = graph;
14-
15-
// Clear all cached data
1614
}
1715

1816
public List<CodeElement> GetElements(List<string> ids)
@@ -148,30 +146,30 @@ public IEnumerable<Relationship> FindAllRelationships(HashSet<string> ids)
148146
return GetRelationships(d => ids.Contains(d.SourceId) && ids.Contains(d.TargetId));
149147
}
150148

151-
public Invocation FindIncomingCalls(string id)
149+
public SearchResult FindIncomingCalls(string id)
152150
{
153151
ArgumentNullException.ThrowIfNull(id);
154152

155153
if (_codeGraph is null || !_codeGraph.Nodes.TryGetValue(id, out var method))
156154
{
157-
return new Invocation([], []);
155+
return new SearchResult([], []);
158156
}
159157

160158
var allCalls = GetRelationships(d => d.Type == RelationshipType.Calls);
161159
var calls = allCalls.Where(call => call.TargetId == method.Id).ToArray();
162160
var methods = calls.Select(d => _codeGraph.Nodes[d.SourceId]);
163161

164-
return new Invocation(methods, calls);
162+
return new SearchResult(methods, calls);
165163
}
166164

167165

168-
public Invocation FindIncomingCallsRecursive(string id)
166+
public SearchResult FindIncomingCallsRecursive(string id)
169167
{
170168
ArgumentNullException.ThrowIfNull(id);
171169

172170
if (_codeGraph is null || !_codeGraph.Nodes.TryGetValue(id, out var method))
173171
{
174-
return new Invocation([], []);
172+
return new SearchResult([], []);
175173
}
176174

177175
var processingQueue = new Queue<CodeElement>();
@@ -203,7 +201,7 @@ public Invocation FindIncomingCallsRecursive(string id)
203201
}
204202
}
205203

206-
return new Invocation(foundMethods, foundCalls);
204+
return new SearchResult(foundMethods, foundCalls);
207205
}
208206

209207

@@ -395,7 +393,6 @@ public SearchResult FindFullInheritanceTree(string id)
395393
{
396394
var typeToAnalyze = processingQueue.Dequeue();
397395
if (!processed.Add(typeToAnalyze.Id))
398-
// Since we evaluate both direction in one iteration, an already processed node is added again.
399396
{
400397
continue;
401398
}
@@ -457,19 +454,19 @@ d.Type is RelationshipType.Overrides or RelationshipType.Inherits or Relationshi
457454
}
458455

459456

460-
public Invocation FindOutgoingCalls(string id)
457+
public SearchResult FindOutgoingCalls(string id)
461458
{
462459
ArgumentNullException.ThrowIfNull(id);
463460

464461
if (_codeGraph is null || !_codeGraph.Nodes.TryGetValue(id, out var method))
465462
{
466-
return new Invocation([], []);
463+
return new SearchResult([], []);
467464
}
468465

469466
var calls = method.Relationships
470467
.Where(d => d.Type == RelationshipType.Calls).ToList();
471468
var methods = calls.Select(m => _codeGraph.Nodes[m.TargetId]).ToList();
472-
return new Invocation(methods, calls);
469+
return new SearchResult(methods, calls);
473470
}
474471

475472
public SearchResult FindOutgoingRelationships(string id)
@@ -520,48 +517,42 @@ public SearchResult FindGapsInHierarchy(HashSet<string> knownIds)
520517
return new SearchResult(elements, []);
521518
}
522519

520+
521+
// Alternative implementation
523522
private HashSet<string> FillGapsInHierarchy(HashSet<string> knownIds)
524523
{
525-
HashSet<string> newElementsIds = [];
526-
var existing = knownIds.ToArray();
527-
for (var i = 0; i < existing.Length; i++)
524+
var added = new HashSet<string>();
525+
if (_codeGraph is null)
528526
{
529-
// We hit each pair twice so we walk only one direction here.
530-
var possibleChild = _codeGraph!.Nodes[existing[i]];
527+
return added;
528+
}
531529

532-
for (var j = 0; j < existing.Length; j++)
530+
foreach (var id in knownIds)
531+
{
532+
if (!_codeGraph.Nodes.TryGetValue(id, out var current))
533533
{
534-
if (i == j)
535-
{
536-
continue;
537-
}
538-
539-
var possibleParent = _codeGraph.Nodes[existing[j]];
534+
continue; // Skip invalid Id
535+
}
540536

541-
// Only search for missing gaps if we have an ancestor relationship
542-
if (!possibleChild.IsChildOf(possibleParent))
537+
// Walk up until we reach a parent already known or run out.
538+
while (current.Parent is not null && !knownIds.Contains(current.Parent.Id))
539+
{
540+
if (added.Add(current.Parent.Id))
543541
{
544-
continue;
542+
current = current.Parent;
545543
}
546-
547-
// Don't override possible child while climbing up.
548-
var currentChild = possibleChild;
549-
while (currentChild.Parent != null && currentChild.Id != possibleParent.Id)
544+
else
550545
{
551-
var parent = currentChild.Parent;
552-
if (!knownIds.Contains(parent.Id))
553-
{
554-
newElementsIds.Add(parent.Id);
555-
}
556-
557-
currentChild = parent;
546+
// Already added
547+
current = current.Parent;
558548
}
559549
}
560550
}
561551

562-
return newElementsIds;
552+
return added;
563553
}
564554

555+
565556
/// <summary>
566557
/// Returns all forbidden calls within the hierarchy.
567558
/// </summary>
@@ -735,6 +726,15 @@ void Collect(CodeElement c)
735726
}
736727
}
737728

738-
public record struct SearchResult(IEnumerable<CodeElement> Elements, IEnumerable<Relationship> Relationships);
729+
public record struct SearchResult
730+
{
731+
public SearchResult(IEnumerable<CodeElement> elements, IEnumerable<Relationship> relationships)
732+
{
733+
// Ensure query is executed only once
734+
Elements = elements.ToList();
735+
Relationships = relationships.ToList();
736+
}
739737

740-
public record struct Invocation(IEnumerable<CodeElement> Methods, IEnumerable<Relationship> Calls);
738+
public IEnumerable<CodeElement> Elements { get; set; }
739+
public IEnumerable<Relationship> Relationships { get; set; }
740+
}

CSharpCodeAnalyst/Exploration/ICodeGraphExplorer.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ namespace CSharpCodeAnalyst.Exploration;
44

55
public interface ICodeGraphExplorer
66
{
7-
Invocation FindIncomingCalls(string id);
8-
Invocation FindOutgoingCalls(string id);
7+
SearchResult FindIncomingCalls(string id);
8+
SearchResult FindOutgoingCalls(string id);
99

1010
/// <summary>
1111
/// Follows all incoming calls recursively.
1212
/// </summary>
13-
Invocation FindIncomingCallsRecursive(string id);
13+
SearchResult FindIncomingCallsRecursive(string id);
1414

1515
/// <summary>
1616
/// Traces back callers of the given method. Includes also abstractions and their callers

0 commit comments

Comments
 (0)