4
4
5
5
namespace CSharpCodeAnalyst . Exploration ;
6
6
7
+ internal class Context
8
+ {
9
+ public HashSet < string > Remember { get ; } = [ ] ;
10
+
11
+ public HashSet < string > BlockedAbstraction { get ; } = [ ] ;
12
+
13
+ public Context Clone ( )
14
+ {
15
+ var clone = new Context ( ) ;
16
+ return clone ;
17
+ }
18
+ }
19
+
7
20
public class CodeGraphExplorer : ICodeGraphExplorer
8
21
{
9
22
private List < Relationship > _allRelationships = [ ] ;
@@ -194,9 +207,8 @@ public SearchResult FollowIncomingCallsHeuristically(string id)
194
207
195
208
var method = _codeGraph . Nodes [ id ] ;
196
209
197
- var restriction = new FollowIncomingCallsRestriction ( ) ;
198
- var processingQueue = new PriorityQueue < CodeElement , int > ( ) ;
199
- processingQueue . Enqueue ( method , 0 ) ; // Start with the initial method, priority 0
210
+ var processingQueue = new PriorityQueue < ( CodeElement , Context ) , int > ( ) ;
211
+ processingQueue . Enqueue ( ( method , new Context ( ) ) , 0 ) ; // Start with the initial method, priority 0
200
212
201
213
var foundRelationships = new HashSet < Relationship > ( ) ;
202
214
var foundElements = new HashSet < CodeElement > ( ) ;
@@ -210,12 +222,13 @@ public SearchResult FollowIncomingCallsHeuristically(string id)
210
222
{
211
223
// 0 = highest priority
212
224
213
- var element = processingQueue . Dequeue ( ) ;
225
+ var ( element , context ) = processingQueue . Dequeue ( ) ;
214
226
if ( ! processed . Add ( element . Id ) )
215
227
{
216
228
continue ;
217
229
}
218
230
231
+ var currentContext = context . Clone ( ) ;
219
232
220
233
if ( element . ElementType == CodeElementType . Event )
221
234
{
@@ -224,14 +237,14 @@ public SearchResult FollowIncomingCallsHeuristically(string id)
224
237
foundRelationships . UnionWith ( specializations ) ;
225
238
var specializedSources = specializations . Select ( d => _codeGraph . Nodes [ d . SourceId ] ) . ToHashSet ( ) ;
226
239
foundElements . UnionWith ( specializedSources ) ;
227
- AddToProcessingQueue ( specializedSources , 0 ) ;
240
+ AddToProcessingQueue ( specializedSources , currentContext , 0 ) ;
228
241
229
242
// Add all methods that invoke the event
230
243
var invokes = allInvokes . Where ( call => call . TargetId == element . Id ) . ToArray ( ) ;
231
244
foundRelationships . UnionWith ( invokes ) ;
232
245
var invokeSources = invokes . Select ( d => _codeGraph . Nodes [ d . SourceId ] ) . ToHashSet ( ) ;
233
246
foundElements . UnionWith ( invokeSources ) ;
234
- AddToProcessingQueue ( invokeSources , 2 ) ;
247
+ AddToProcessingQueue ( invokeSources , currentContext , 2 ) ;
235
248
}
236
249
237
250
if ( element . ElementType == CodeElementType . Method )
@@ -243,53 +256,43 @@ public SearchResult FollowIncomingCallsHeuristically(string id)
243
256
foundRelationships . UnionWith ( abstractions ) ;
244
257
var abstractionTargets = abstractions . Select ( d => _codeGraph . Nodes [ d . TargetId ] ) . ToHashSet ( ) ;
245
258
foundElements . UnionWith ( abstractionTargets ) ;
246
- restriction . BlockeBaseCalls . UnionWith ( abstractionTargets . Select ( t => t . Id ) ) ;
247
- AddToProcessingQueue ( abstractionTargets , 0 ) ;
259
+ AddToProcessingQueue ( abstractionTargets , currentContext , 0 ) ;
248
260
249
261
250
262
// Add Events that are handled by this method (priority 1).
251
263
var handles = allHandles . Where ( h => h . SourceId == element . Id ) . ToArray ( ) ;
252
264
foundRelationships . UnionWith ( handles ) ;
253
265
var events = handles . Select ( h => _codeGraph . Nodes [ h . TargetId ] ) . ToHashSet ( ) ;
254
266
foundElements . UnionWith ( events ) ;
255
- AddToProcessingQueue ( events , 1 ) ;
256
-
267
+ AddToProcessingQueue ( events , currentContext , 1 ) ;
268
+
257
269
258
270
// 3. Calls (priority 2)
259
- var calls = allCalls . Where ( call => call . TargetId == element . Id && IsAllowedCall ( call ) ) . ToArray ( ) ;
271
+ var calls = allCalls . Where ( call => call . TargetId == element . Id && IsAllowedCall ( call , currentContext ) ) . ToArray ( ) ;
260
272
foundRelationships . UnionWith ( calls ) ;
261
273
var callSources = calls
262
274
. Select ( d => _codeGraph . Nodes [ d . SourceId ] )
263
275
. ToHashSet ( ) ;
264
276
foundElements . UnionWith ( callSources ) ;
265
- AddToProcessingQueue ( callSources , 2 ) ;
277
+ AddToProcessingQueue ( callSources , currentContext , 2 ) ;
266
278
}
267
279
}
268
280
269
281
return new SearchResult ( foundElements , foundRelationships ) ;
270
282
271
- void AddToProcessingQueue ( IEnumerable < CodeElement > elementsToExplore , int priority )
283
+ void AddToProcessingQueue ( IEnumerable < CodeElement > elementsToExplore , Context context , int priority )
272
284
{
273
285
foreach ( var elementToExplore in elementsToExplore )
274
286
{
275
- processingQueue . Enqueue ( _codeGraph . Nodes [ elementToExplore . Id ] , priority ) ;
287
+ processingQueue . Enqueue ( ( _codeGraph . Nodes [ elementToExplore . Id ] , context ) , priority ) ;
276
288
}
277
289
}
278
-
279
- bool IsAllowedCall ( Relationship call )
280
- {
281
- if ( restriction . BlockeBaseCalls . Contains ( call . TargetId ) )
282
- {
283
- var allow = ! IsCallToOwnBase ( call ) ;
284
- if ( ! allow )
285
- {
286
- var sourceName = _codeGraph . Nodes [ call . SourceId ] . FullName ;
287
- var targetName = _codeGraph . Nodes [ call . TargetId ] . FullName ;
288
- Trace . WriteLine ( $ "Removed: { sourceName } -> { targetName } ") ;
289
- }
290
290
291
- return allow ;
292
- }
291
+ bool IsAllowedCall ( Relationship call , Context context )
292
+ {
293
+ var sourceName = _codeGraph . Nodes [ call . SourceId ] . FullName ;
294
+ var targetName = _codeGraph . Nodes [ call . TargetId ] . FullName ;
295
+ Trace . WriteLine ( $ "Removed: { sourceName } -> { targetName } ") ;
293
296
294
297
return true ;
295
298
}
@@ -341,7 +344,7 @@ public SearchResult FindFullInheritanceTree(string id)
341
344
}
342
345
}
343
346
344
- // Find sub-classes recursive
347
+ // Find subclasses recursively
345
348
processingQueue . Enqueue ( type ) ;
346
349
processed . Clear ( ) ;
347
350
while ( processingQueue . Any ( ) )
@@ -532,13 +535,12 @@ private class FollowIncomingCallsRestriction
532
535
/// This is because the method may be indirectly called by the interface.
533
536
/// If we proceed we may also find calls the base. But this is the wrong direction for the path we follow.
534
537
/// So if we followed an abstraction we block the base call to this abstraction
535
- ///
536
538
/// <code>
537
539
/// class Base
538
540
/// {
539
541
/// protected virtual void Foo() {}
540
542
/// }
541
- ///
543
+ ///
542
544
/// class Derived : Base
543
545
/// {
544
546
/// // We start following here!
@@ -548,11 +550,10 @@ private class FollowIncomingCallsRestriction
548
550
/// }
549
551
/// }
550
552
/// </code>
551
- ///
552
553
/// Hashset of target ids of base methods.
553
554
/// </summary>
554
555
public HashSet < string > BlockeBaseCalls { get ; } = [ ] ;
555
-
556
+
556
557
public HashSet < string > BlockedAbstraction { get ; } = [ ] ;
557
558
}
558
559
}
0 commit comments