Files
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

107 lines
3.4 KiB
Go

package resolver
import (
"strings"
"github.com/zzet/gortex/internal/graph"
)
// DjangoDescriptorResolver is a claiming resolver for Django's named
// descriptor dispatch — an attribute reference the static graph cannot
// resolve because it names a runtime descriptor, not a declared method.
// The flagship case is `self._iterable_class(self)` inside a QuerySet:
// `_iterable_class` is a class attribute (default `ModelIterable`), and
// iterating its instance runs `ModelIterable.__iter__`. This resolver
// claims those residual `_iterable_class` references and binds them to the
// iterable class's `__iter__`, keyed by class names present in the graph.
type DjangoDescriptorResolver struct{}
// djangoDescriptorVocab is the set of Django descriptor attribute names this
// resolver claims. Kept tight so the pre-filter only sees its own framework
// vocabulary.
var djangoDescriptorVocab = map[string]bool{
"_iterable_class": true,
}
// djangoDefaultIterableClass is Django's default QuerySet._iterable_class.
const djangoDefaultIterableClass = "ModelIterable"
func (DjangoDescriptorResolver) Name() string { return SynthDjangoDescriptor }
// Claims reports whether the edge references a Django descriptor name.
func (DjangoDescriptorResolver) Claims(e *graph.Edge) bool {
if e == nil {
return false
}
return djangoDescriptorVocab[djangoRefName(e.To)]
}
// Resolve rebinds a claimed `_iterable_class` reference to the iterable
// class's `__iter__` method — the class named by the QuerySet's
// django_iterable_class hint, else Django's default ModelIterable.
func (DjangoDescriptorResolver) Resolve(g graph.Store, e *graph.Edge) bool {
if g == nil || e == nil || djangoRefName(e.To) != "_iterable_class" {
return false
}
iterableClass := djangoIterableClassFor(g, e.From)
if iterableClass == "" {
iterableClass = djangoDefaultIterableClass
}
target := djangoFindIterMethod(g, iterableClass)
if target == nil {
return false
}
oldTo := e.To
e.To = target.ID
e.Origin = graph.OriginASTInferred
e.Confidence = 0.7
e.ConfidenceLabel = graph.ConfidenceLabelFor(graph.EdgeCalls, 0.7)
StampSynthesized(e, SynthDjangoDescriptor)
g.ReindexEdges([]graph.EdgeReindex{{Edge: e, OldTo: oldTo}})
return true
}
// djangoRefName extracts the bare attribute name from an unresolved target
// id, stripping the `unresolved::` prefix and any `*.` method marker.
func djangoRefName(to string) string {
if !graph.IsUnresolvedTarget(to) {
return ""
}
return strings.TrimPrefix(graph.UnresolvedName(to), "*.")
}
// djangoIterableClassFor returns the iterable-class name hinted on the class
// enclosing the reference's source method, or "".
func djangoIterableClassFor(g graph.Store, fromID string) string {
n := g.GetNode(fromID)
if n == nil || n.Meta == nil {
return ""
}
recv, _ := n.Meta["receiver"].(string)
if recv == "" {
return ""
}
for _, c := range g.FindNodesByName(recv) {
if c == nil || c.Kind != graph.KindType || c.Meta == nil {
continue
}
if ic, _ := c.Meta["django_iterable_class"].(string); ic != "" {
return ic
}
}
return ""
}
// djangoFindIterMethod returns the `__iter__` method of the named class.
func djangoFindIterMethod(g graph.Store, className string) *graph.Node {
for _, n := range g.FindNodesByName("__iter__") {
if n == nil || n.Kind != graph.KindMethod || n.Meta == nil {
continue
}
if recv, _ := n.Meta["receiver"].(string); recv == className {
return n
}
}
return nil
}