Files
zzet--gortex/internal/resolver/react_native_native_pairing.go
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

133 lines
4.0 KiB
Go

package resolver
import (
"sort"
"github.com/zzet/gortex/internal/graph"
)
// rnNativePairVia marks a synthesized iOS↔Android native-implementation pairing
// edge.
const rnNativePairVia = "rn.native.pair"
// ResolveReactNativeNativePairing is the framework-dispatch synthesizer that
// links the two native implementations of a classic React Native module. A
// module is implemented twice — once on iOS (Objective-C / Swift,
// RCT_EXPORT_METHOD) and once on Android (Java / Kotlin, @ReactMethod) — and
// both extractors stamp the same rn_module + rn_method on their method nodes.
// For each (module, method) implemented on both platforms this pass
// synthesizes a pair of EdgeReferences edges (one each way) between the iOS and
// Android method, so navigating from one platform's implementation surfaces the
// other — the parallel-implementation relationship the static call graph can't
// see because the two sides never call each other.
//
// Only cross-platform pairs are linked (iOS↔Android); two implementations on
// the same platform are not paired. Full recompute and idempotent: edges are
// re-derived from the rn metadata, graph.AddEdge dedupes by key, and
// graph.EvictFile drops the pairing when either side's file is reindexed. Edges
// ride at ast_inferred and carry synthesizer provenance.
//
// Returns the number of cross-platform method pairs linked.
func ResolveReactNativeNativePairing(g graph.Store) int {
if g == nil {
return 0
}
type modKey struct{ module, method string }
nativeByKey := map[modKey][]*graph.Node{}
for _, n := range nodesByKindsOrAll(g, graph.KindMethod) {
if n == nil || n.Meta == nil {
continue
}
mod, _ := n.Meta["rn_module"].(string)
meth, _ := n.Meta["rn_method"].(string)
if mod == "" || meth == "" {
continue
}
nativeByKey[modKey{mod, meth}] = append(nativeByKey[modKey{mod, meth}], n)
}
if len(nativeByKey) == 0 {
return 0
}
keys := make([]modKey, 0, len(nativeByKey))
for k := range nativeByKey {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
if keys[i].module != keys[j].module {
return keys[i].module < keys[j].module
}
return keys[i].method < keys[j].method
})
var batch []*graph.Edge
paired := 0
for _, k := range keys {
impls := nativeByKey[k]
for i := 0; i < len(impls); i++ {
for j := i + 1; j < len(impls); j++ {
a, b := impls[i], impls[j]
if a.ID == "" || b.ID == "" || a.ID == b.ID {
continue
}
if !rnDifferentPlatform(a.Language, b.Language) {
continue
}
batch = append(batch,
rnNativePairEdge(a, b, k.module, k.method),
rnNativePairEdge(b, a, k.module, k.method),
)
paired++
}
}
}
for _, e := range batch {
g.AddEdge(e)
}
return paired
}
// rnNativePairEdge builds one direction of the cross-platform pairing.
func rnNativePairEdge(from, to *graph.Node, module, method string) *graph.Edge {
return &graph.Edge{
From: from.ID,
To: to.ID,
Kind: graph.EdgeReferences,
FilePath: from.FilePath,
Line: from.StartLine,
Confidence: 0.6,
ConfidenceLabel: graph.ConfidenceLabelFor(graph.EdgeReferences, 0.6),
Origin: graph.OriginASTInferred,
Meta: map[string]any{
"via": rnNativePairVia,
"rn_module": module,
"rn_method": method,
"native_platform": rnPlatform(to.Language),
MetaSynthesizedBy: SynthReactNativePair,
MetaProvenance: ProvenanceHeuristic,
},
}
}
// rnPlatform maps a native language to the React Native platform it
// implements: ios (Objective-C / Swift) or android (Java / Kotlin); "" for
// anything else.
func rnPlatform(lang string) string {
switch lang {
case "objc", "swift":
return "ios"
case "java", "kotlin":
return "android"
}
return ""
}
// rnDifferentPlatform reports whether two native languages implement opposite
// React Native platforms, so only iOS↔Android pairs are linked.
func rnDifferentPlatform(a, b string) bool {
pa, pb := rnPlatform(a), rnPlatform(b)
return pa != "" && pb != "" && pa != pb
}