项目文件夹

文件
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

142 行
4.1 KiB
Go

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
package resolver
import (
"sort"
"github.com/zzet/gortex/internal/graph"
)
// ginMiddlewareVia tags the synthesized dispatcher→handler edges.
const ginMiddlewareVia = "gin_middleware_chain"
// ginFanoutCap bounds the dispatcher×handler fan-out so a pathological repo
// (a custom chain plus hundreds of registered handlers) cannot explode the
// edge set.
const ginFanoutCap = 512
// ResolveGinMiddlewareCalls bridges a Gin middleware-chain dispatcher to the
// handlers it dispatches to. The Go extractor stamps gin_dispatcher=true on the
// method that invokes `c.handlers[idx](c)` (the indexed-slice indirection a
// call graph drops) and gin_handlers=[names] on each function that registers
// routes/middleware with `.GET`/`.Use`/`.Handle`. This pass resolves those
// names to their definitions and emits a tier-tagged dispatcher→handler call
// edge per pair, so request→handler reachability flows through get_call_chain
// where a same-file scanner sees a dead end. Gated on a dispatcher existing
// (so it is inert outside a Gin-style chain) and repo-scoped via
// sameDispatchBoundary (per the intra-process dispatch discipline).
func ResolveGinMiddlewareCalls(g graph.Store) int {
if g == nil {
return 0
}
var dispatchers []*graph.Node
var registrars []*graph.Node
nameIndex := map[string][]*graph.Node{}
for _, n := range nodesByKindsOrAll(g, graph.KindMethod, graph.KindFunction) {
if n == nil {
continue
}
nameIndex[n.Name] = append(nameIndex[n.Name], n)
if n.Meta == nil {
continue
}
if d, _ := n.Meta["gin_dispatcher"].(bool); d {
dispatchers = append(dispatchers, n)
}
if _, ok := n.Meta["gin_handlers"]; ok {
registrars = append(registrars, n)
}
}
// Gated on the dispatcher existing: no chain dispatcher in the graph means
// no Gin-style indirection to bridge.
if len(dispatchers) == 0 || len(registrars) == 0 {
return 0
}
// Collect the distinct handler names registered anywhere, deterministically.
handlerNames := map[string]bool{}
for _, r := range registrars {
for _, name := range ginHandlerNames(r.Meta["gin_handlers"]) {
handlerNames[name] = true
}
}
names := make([]string, 0, len(handlerNames))
for name := range handlerNames {
names = append(names, name)
}
sort.Strings(names)
sort.Slice(dispatchers, func(i, j int) bool { return dispatchers[i].ID < dispatchers[j].ID })
var batch []*graph.Edge
seen := map[string]bool{}
for _, d := range dispatchers {
for _, name := range names {
cands := nameIndex[name]
sort.Slice(cands, func(i, j int) bool { return cands[i].ID < cands[j].ID })
for _, h := range cands {
if h == nil || h.ID == d.ID {
continue
}
// Repo-scope: a dispatcher only reaches handlers in its own
// dispatch boundary (vendored Gin + app handlers in one repo).
if !sameDispatchBoundary(d, h) {
continue
}
key := d.ID + "\x00" + h.ID
if seen[key] {
continue
}
seen[key] = true
batch = append(batch, ginMiddlewareEdge(d, h))
if len(batch) >= ginFanoutCap {
break
}
}
}
}
for _, e := range batch {
g.AddEdge(e)
}
return len(batch)
}
// ginHandlerNames coerces the gin_handlers Meta value (stamped as []string,
// possibly []any after a serialization round-trip) into a name slice.
func ginHandlerNames(v any) []string {
switch t := v.(type) {
case []string:
return t
case []any:
out := make([]string, 0, len(t))
for _, e := range t {
if s, ok := e.(string); ok && s != "" {
out = append(out, s)
}
}
return out
}
return nil
}
// ginMiddlewareEdge builds one dispatcher→handler speculative call edge.
func ginMiddlewareEdge(from, to *graph.Node) *graph.Edge {
return &graph.Edge{
From: from.ID,
To: to.ID,
Kind: graph.EdgeCalls,
FilePath: from.FilePath,
Line: from.StartLine,
Confidence: 0.4,
ConfidenceLabel: graph.ConfidenceLabelFor(graph.EdgeCalls, 0.4),
Origin: graph.OriginSpeculative,
Meta: map[string]any{
"via": ginMiddlewareVia,
"speculative": true,
MetaSynthesizedBy: SynthGinMiddleware,
MetaProvenance: ProvenanceHeuristic,
},
}
}