@@ -24,6 +24,42 @@ type OutRelation struct {
2424// If includeExternal is true, all calls are included in the relations, including external module functions.
2525// We still defensively exclude relations that have zero called entries to preserve prior semantics unless includeExternal is true.
2626func BuildRelations (functions []FunctionInfo , includeExternal bool ) []OutRelation {
27+ // Build indices from the full set provided (sequential usage builds on the same set)
28+ funcMap , suffixMap := buildGlobalIndices (functions )
29+
30+ out := make ([]OutRelation , 0 , len (functions ))
31+ for _ , f := range functions {
32+ if len (f .Calls ) == 0 && ! includeExternal {
33+ continue // skip functions with no user-defined calls (previous behaviour)
34+ }
35+ rel := buildRelationForFunction (f , includeExternal , funcMap , suffixMap )
36+ if len (rel .Called ) > 0 || includeExternal {
37+ // Include the relation if it has calls OR if we're including all functions
38+ out = append (out , rel )
39+ }
40+ }
41+ return out
42+ }
43+
44+ // BuildRelationsIndexed builds relations for a subset of functions using indices built from a full set.
45+ // Useful for parallel processing where each worker processes a chunk but needs global resolution.
46+ func BuildRelationsIndexed (subset []FunctionInfo , includeExternal bool , fullIndex []FunctionInfo ) []OutRelation {
47+ funcMap , suffixMap := buildGlobalIndices (fullIndex )
48+ out := make ([]OutRelation , 0 , len (subset ))
49+ for _ , f := range subset {
50+ if len (f .Calls ) == 0 && ! includeExternal {
51+ continue
52+ }
53+ rel := buildRelationForFunction (f , includeExternal , funcMap , suffixMap )
54+ if len (rel .Called ) > 0 || includeExternal {
55+ out = append (out , rel )
56+ }
57+ }
58+ return out
59+ }
60+
61+ // buildGlobalIndices creates lookup maps for exact and suffix-based resolution.
62+ func buildGlobalIndices (functions []FunctionInfo ) (map [string ]FunctionInfo , map [string ]FunctionInfo ) {
2763 // index by name for quick lookup
2864 funcMap := make (map [string ]FunctionInfo , len (functions ))
2965 // Also create an index by suffix for external function matching
@@ -45,60 +81,54 @@ func BuildRelations(functions []FunctionInfo, includeExternal bool) []OutRelatio
4581 }
4682 }
4783 }
84+ return funcMap , suffixMap
85+ }
4886
49- out := make ([]OutRelation , 0 , len (functions ))
50- for _ , f := range functions {
51- if len (f .Calls ) == 0 && ! includeExternal {
52- continue // skip functions with no user-defined calls (previous behaviour)
53- }
54- rel := OutRelation {Name : f .Name , Line : f .Line , FilePath : f .FilePath }
55- for _ , cname := range f .Calls {
56- if cf , ok := funcMap [cname ]; ok {
57- // Function exists in our codebase (including external modules when scanned)
87+ // buildRelationForFunction builds OutRelation for a single function using provided indices.
88+ func buildRelationForFunction (f FunctionInfo , includeExternal bool , funcMap , suffixMap map [string ]FunctionInfo ) OutRelation {
89+ rel := OutRelation {Name : f .Name , Line : f .Line , FilePath : f .FilePath }
90+ for _ , cname := range f .Calls {
91+ if cf , ok := funcMap [cname ]; ok {
92+ // Function exists in our codebase (including external modules when scanned)
93+ rel .Called = append (rel .Called , OutCalled {Name : cf .Name , Line : cf .Line , FilePath : cf .FilePath })
94+ } else if includeExternal {
95+ // Try to match with external functions by suffix
96+ if cf , ok := suffixMap [cname ]; ok {
5897 rel .Called = append (rel .Called , OutCalled {Name : cf .Name , Line : cf .Line , FilePath : cf .FilePath })
59- } else if includeExternal {
60- // Try to match with external functions by suffix
61- if cf , ok := suffixMap [cname ]; ok {
62- rel .Called = append (rel .Called , OutCalled {Name : cf .Name , Line : cf .Line , FilePath : cf .FilePath })
63- } else {
64- // Try more flexible matching for method calls
65- matched := false
66- var matchedFunction FunctionInfo
98+ } else {
99+ // Try more flexible matching for method calls
100+ matched := false
101+ var matchedFunction FunctionInfo
102+
103+ // First try: exact suffix match with dot notation
104+ for fullName , cf := range funcMap {
105+ if strings .HasSuffix (fullName , "." + cname ) {
106+ rel .Called = append (rel .Called , OutCalled {Name : cf .Name , Line : cf .Line , FilePath : cf .FilePath })
107+ matched = true
108+ break
109+ }
110+ }
67111
68- // First try: exact suffix match with dot notation
112+ // Second try: if not matched, try partial matching
113+ if ! matched {
69114 for fullName , cf := range funcMap {
70- if strings .HasSuffix (fullName , "." + cname ) {
71- rel . Called = append ( rel . Called , OutCalled { Name : cf . Name , Line : cf . Line , FilePath : cf . FilePath })
115+ if strings .Contains (fullName , cname ) {
116+ matchedFunction = cf
72117 matched = true
73118 break
74119 }
75120 }
76-
77- // Second try: if not matched, try partial matching
78- if ! matched {
79- for fullName , cf := range funcMap {
80- if strings .Contains (fullName , cname ) {
81- matchedFunction = cf
82- matched = true
83- break
84- }
85- }
86- if matched {
87- rel .Called = append (rel .Called , OutCalled {Name : matchedFunction .Name , Line : matchedFunction .Line , FilePath : matchedFunction .FilePath })
88- }
121+ if matched {
122+ rel .Called = append (rel .Called , OutCalled {Name : matchedFunction .Name , Line : matchedFunction .Line , FilePath : matchedFunction .FilePath })
89123 }
124+ }
90125
91- if ! matched {
92- // External function call not found in scanned modules - include with placeholder info
93- rel .Called = append (rel .Called , OutCalled {Name : cname , Line : 0 , FilePath : "external" })
94- }
126+ if ! matched {
127+ // External function call not found in scanned modules - include with placeholder info
128+ rel .Called = append (rel .Called , OutCalled {Name : cname , Line : 0 , FilePath : "external" })
95129 }
96130 }
97131 }
98- if len (rel .Called ) > 0 || includeExternal {
99- // Include the relation if it has calls OR if we're including all functions
100- out = append (out , rel )
101- }
102132 }
103- return out
133+ return rel
104134}
0 commit comments