Skip to content

Commit 6f903a8

Browse files
committed
Improvements
- Recognize access to properties - Follow incoming calls recursive - Add parents for marked elements
1 parent 5652a43 commit 6f903a8

File tree

14 files changed

+399
-172
lines changed

14 files changed

+399
-172
lines changed

CSharpCodeAnalyst/App.xaml.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,6 @@ protected override void OnStartup(StartupEventArgs e)
5858
// Context-sensitive help triggered in the graph, handled in the main view model
5959
messaging.Subscribe<QuickInfoUpdate>(viewModel.HandleUpdateQuickInfo);
6060

61-
// Adding parent container triggered in graph, handled in the tree view model
62-
// Sends back a AddNodeToGraphRequest.
63-
messaging.Subscribe<AddParentContainerRequest>(treeViewModel.HandleAddParentContainerRequest);
64-
6561
messaging.Subscribe<CycleCalculationComplete>(cycleViewModel.HandleCycleCalculationComplete);
6662

6763
messaging.Subscribe<DeleteFromModelRequest>(viewModel.HandleDeleteFromModel);

CSharpCodeAnalyst/Common/AddParentContainerRequest.cs

Lines changed: 0 additions & 6 deletions
This file was deleted.

CSharpCodeAnalyst/Exploration/CodeGraphExplorer.cs

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

55
public class CodeGraphExplorer : ICodeGraphExplorer
66
{
7+
private List<Dependency> _allDependencies = [];
78
private CodeGraph? _codeGraph;
89

910
public void LoadCodeGraph(CodeGraph graph)
1011
{
1112
_codeGraph = graph;
13+
14+
// Clear all cached data
15+
_allDependencies = [];
1216
}
1317

1418
public List<CodeElement> GetElements(List<string> ids)
@@ -33,6 +37,28 @@ public List<CodeElement> GetElements(List<string> ids)
3337
return elements;
3438
}
3539

40+
public SearchResult FindParents(List<string> ids)
41+
{
42+
if (_codeGraph is null)
43+
{
44+
return new SearchResult([], []);
45+
}
46+
47+
var parents = new HashSet<CodeElement>();
48+
foreach (var id in ids)
49+
{
50+
if (_codeGraph.Nodes.TryGetValue(id, out var element))
51+
{
52+
if (element.Parent is not null)
53+
{
54+
parents.Add(element.Parent);
55+
}
56+
}
57+
}
58+
59+
return new SearchResult(parents, []);
60+
}
61+
3662
/// <summary>
3763
/// Returns all dependencies that link the given nodes (ids).
3864
/// </summary>
@@ -62,13 +88,14 @@ public Invocation FindIncomingCalls(string id)
6288

6389
var method = _codeGraph.Nodes[id];
6490

65-
var callDependencies = GetCallDependencies();
66-
var calls = callDependencies.Where(call => call.TargetId == method.Id).ToArray();
91+
var allCalls = GetDependencies(d => d.Type == DependencyType.Calls);
92+
var calls = allCalls.Where(call => call.TargetId == method.Id).ToArray();
6793
var methods = calls.Select(d => _codeGraph.Nodes[d.SourceId]);
6894

6995
return new Invocation(methods, calls);
7096
}
7197

98+
7299
public Invocation FindIncomingCallsRecursive(string id)
73100
{
74101
ArgumentNullException.ThrowIfNull(id);
@@ -83,10 +110,10 @@ public Invocation FindIncomingCallsRecursive(string id)
83110
var processingQueue = new Queue<CodeElement>();
84111
processingQueue.Enqueue(method);
85112

86-
var allCalls = new HashSet<Dependency>();
87-
var allMethods = new HashSet<CodeElement>();
113+
var foundCalls = new HashSet<Dependency>();
114+
var foundMethods = new HashSet<CodeElement>();
88115

89-
var callDependencies = GetCallDependencies();
116+
var allCalls = GetDependencies(d => d.Type == DependencyType.Calls);
90117

91118
var processed = new HashSet<string>();
92119
while (processingQueue.Any())
@@ -97,19 +124,74 @@ public Invocation FindIncomingCallsRecursive(string id)
97124
continue;
98125
}
99126

100-
var calls = callDependencies.Where(call => call.TargetId == element.Id).ToArray();
101-
allCalls.UnionWith(calls);
127+
var calls = allCalls.Where(call => call.TargetId == element.Id).ToArray();
128+
foundCalls.UnionWith(calls);
102129

103130
var methods = calls.Select(d => _codeGraph.Nodes[d.SourceId]).ToArray();
104-
allMethods.UnionWith(methods);
131+
foundMethods.UnionWith(methods);
105132

106133
foreach (var methodToExplore in methods)
107134
{
108135
processingQueue.Enqueue(_codeGraph.Nodes[methodToExplore.Id]);
109136
}
110137
}
111138

112-
return new Invocation(allMethods, allCalls);
139+
return new Invocation(foundMethods, foundCalls);
140+
}
141+
142+
143+
public SearchResult FollowIncomingCallsRecursive(string id)
144+
{
145+
ArgumentNullException.ThrowIfNull(id);
146+
147+
if (_codeGraph is null)
148+
{
149+
return new SearchResult([], []);
150+
}
151+
152+
var allImplementsAndOverrides =
153+
GetDependencies(d => d.Type is DependencyType.Implements or DependencyType.Overrides);
154+
var allCalls = GetDependencies(d => d.Type == DependencyType.Calls);
155+
156+
var method = _codeGraph.Nodes[id];
157+
158+
var processingQueue = new Queue<CodeElement>();
159+
processingQueue.Enqueue(method);
160+
161+
var foundDependencies = new HashSet<Dependency>();
162+
var foundElements = new HashSet<CodeElement>();
163+
164+
165+
var processed = new HashSet<string>();
166+
while (processingQueue.Any())
167+
{
168+
var element = processingQueue.Dequeue();
169+
if (!processed.Add(element.Id))
170+
{
171+
continue;
172+
}
173+
174+
// Calls
175+
var calls = allCalls.Where(call => call.TargetId == element.Id).ToArray();
176+
foundDependencies.UnionWith(calls);
177+
var callSources = calls.Select(d => _codeGraph.Nodes[d.SourceId]).ToHashSet();
178+
foundElements.UnionWith(callSources);
179+
180+
// Abstractions. Sometimes the abstractions is called.
181+
var abstractions = allImplementsAndOverrides.Where(d => d.SourceId == element.Id).ToArray();
182+
foundDependencies.UnionWith(abstractions);
183+
var abstractionTargets = abstractions.Select(d => _codeGraph.Nodes[d.TargetId]).ToHashSet();
184+
foundElements.UnionWith(abstractionTargets);
185+
186+
// Follow new leads
187+
var methodsToExplore = abstractionTargets.Union(callSources);
188+
foreach (var methodToExplore in methodsToExplore)
189+
{
190+
processingQueue.Enqueue(_codeGraph.Nodes[methodToExplore.Id]);
191+
}
192+
}
193+
194+
return new SearchResult(foundElements, foundDependencies);
113195
}
114196

115197
/// <summary>
@@ -264,18 +346,24 @@ public SearchResult FindIncomingDependencies(string id)
264346
return new SearchResult(elements, dependencies);
265347
}
266348

267-
private List<Dependency> GetCallDependencies()
349+
private List<Dependency> GetCachedDependencies()
268350
{
269351
if (_codeGraph is null)
270352
{
271353
return [];
272354
}
273355

274-
var callDependencies = _codeGraph.Nodes.Values
275-
.SelectMany(node => node.Dependencies)
276-
.Where(d => d.Type == DependencyType.Calls)
277-
.ToList();
278-
return callDependencies;
356+
if (_allDependencies.Count == 0)
357+
{
358+
_allDependencies = _codeGraph.GetAllDependencies().ToList();
359+
}
360+
361+
return _allDependencies;
362+
}
363+
364+
private List<Dependency> GetDependencies(Func<Dependency, bool> filter)
365+
{
366+
return GetCachedDependencies().Where(filter).ToList();
279367
}
280368

281369
private HashSet<Dependency> FindInheritsAndImplementsRelationships()

CSharpCodeAnalyst/Exploration/ICodeGraphExplorer.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,17 @@ public interface ICodeGraphExplorer
66
{
77
Invocation FindIncomingCalls(string id);
88
Invocation FindOutgoingCalls(string id);
9+
10+
/// <summary>
11+
/// Follows all incoming calls recursively.
12+
/// </summary>
913
Invocation FindIncomingCallsRecursive(string id);
14+
15+
/// <summary>
16+
/// Traces back callers of the given method. Includes also abstractions and their callers
17+
/// </summary>
18+
SearchResult FollowIncomingCallsRecursive(string id);
19+
1020
SearchResult FindFullInheritanceTree(string id);
1121

1222
/// <summary>
@@ -28,4 +38,5 @@ public interface ICodeGraphExplorer
2838
SearchResult FindIncomingDependencies(string id);
2939
void LoadCodeGraph(CodeGraph graph);
3040
List<CodeElement> GetElements(List<string> ids);
41+
SearchResult FindParents(List<string> ids);
3142
}

CSharpCodeAnalyst/GraphArea/DependencyGraphViewer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ private void RefreshGraph()
296296
{
297297
if (_msaglViewer != null)
298298
{
299-
var graph = _msaglBuilder.CreateGraphFromCodeStructure(_clonedCodeGraph, _presentationState,
299+
var graph = _msaglBuilder.CreateGraph(_clonedCodeGraph, _presentationState,
300300
_showFlatGraph);
301301

302302
_renderOption.Apply(graph);

0 commit comments

Comments
 (0)