@@ -119,7 +119,30 @@ func resolveImplementsTargets(allFacts []facts.Fact, fileModules map[string]bool
119119 reexports := buildReexportIndex (allFacts , pkgDirs )
120120 symbols := make (map [string ]bool )
121121 byShortName := make (map [string ][]string )
122+ importedByFile := make (map [string ]map [string ]string )
122123 for i := range allFacts {
124+ if allFacts [i ].Kind == facts .KindDependency && allFacts [i ].Props ["from" ] == true {
125+ var module string
126+ for _ , rel := range allFacts [i ].Relations {
127+ if rel .Kind == facts .RelImports {
128+ module = rel .Target
129+ break
130+ }
131+ }
132+ if module != "" {
133+ if importedByFile [allFacts [i ].File ] == nil {
134+ importedByFile [allFacts [i ].File ] = make (map [string ]string )
135+ }
136+ for local , imported := range stringMapProp (allFacts [i ].Props , "bindings" ) {
137+ target := module + "." + imported
138+ if previous , exists := importedByFile [allFacts [i ].File ][local ]; exists && previous != target {
139+ importedByFile [allFacts [i ].File ][local ] = ""
140+ } else {
141+ importedByFile [allFacts [i ].File ][local ] = target
142+ }
143+ }
144+ }
145+ }
123146 if allFacts [i ].Kind != facts .KindSymbol {
124147 continue
125148 }
@@ -131,6 +154,11 @@ func resolveImplementsTargets(allFacts []facts.Fact, fileModules map[string]bool
131154 }
132155 byShortName [short ] = append (byShortName [short ], name )
133156 }
157+ for i := range allFacts {
158+ if allFacts [i ].Kind == facts .KindDependency && allFacts [i ].Props != nil {
159+ delete (allFacts [i ].Props , "bindings" )
160+ }
161+ }
134162
135163 for i := range allFacts {
136164 f := & allFacts [i ]
@@ -151,6 +179,12 @@ func resolveImplementsTargets(allFacts []facts.Fact, fileModules map[string]bool
151179 }
152180 continue
153181 }
182+ if imported := importedByFile [f.File ][rel.Target ]; imported != "" {
183+ if resolved , keep := resolveDottedTarget (imported , fileIdx , topPkgs , fileDir (f .File ), reexports , symbols ); keep && symbols [resolved ] {
184+ rel .Target = resolved
185+ }
186+ continue
187+ }
154188 candidates := byShortName [rel .Target ]
155189 if len (candidates ) == 1 {
156190 rel .Target = candidates [0 ]
@@ -288,6 +322,23 @@ func stringSliceProp(props map[string]any, key string) []string {
288322 return nil
289323}
290324
325+ func stringMapProp (props map [string ]any , key string ) map [string ]string {
326+ out := make (map [string ]string )
327+ switch v := props [key ].(type ) {
328+ case map [string ]string :
329+ for k , value := range v {
330+ out [k ] = value
331+ }
332+ case map [string ]any :
333+ for k , value := range v {
334+ if s , ok := value .(string ); ok {
335+ out [k ] = s
336+ }
337+ }
338+ }
339+ return out
340+ }
341+
291342// resolveDottedTarget maps a dotted call target ("a.b.c.sym") to a canonical slash
292343// symbol name when its module prefix resolves to an internal file or to a package
293344// that re-exports the symbol, keeps it dotted when the prefix is internal but
0 commit comments