@@ -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+ }
0 commit comments