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

103 lines
2.9 KiB
Go

package resolver
import (
"sort"
"github.com/zzet/gortex/internal/graph"
)
// flutterSetStateVia marks a synthesized Flutter setState→build reachability
// edge.
const flutterSetStateVia = "flutter.setstate"
// ResolveFlutterSetStateCalls is the framework-dispatch synthesizer for the
// Flutter widget re-build hop. `setState(() { … })` schedules the State's
// `build(...)` to re-run, but that hop is framework-internal — no static edge —
// so a flow dead-ends at setState even though everything `build` reaches is
// call-connected. This pass bridges it: for each State class that has a `build`
// method, it links every sibling method whose body calls `setState(` to that
// `build`. The setState call is the gate that keeps this to Flutter State
// classes — a plain class with a `build` method that never calls `setState`
// produces no edge.
//
// Over-approximation by design, full recompute and idempotent; edges ride at
// ast_inferred and carry synthesizer provenance. Returns the number of
// setState→build edges synthesized.
func ResolveFlutterSetStateCalls(g graph.Store) int {
if g == nil {
return 0
}
classByMethod := map[string]string{}
buildByClass := map[string]*graph.Node{}
for _, n := range nodesByKindsOrAll(g, graph.KindMethod) {
if n == nil {
continue
}
for _, e := range g.GetOutEdges(n.ID) {
if e == nil || e.Kind != graph.EdgeMemberOf {
continue
}
classByMethod[n.ID] = e.To
if n.Name == "build" {
buildByClass[e.To] = n
}
break
}
}
if len(buildByClass) == 0 {
return 0
}
var setStateMethods []*graph.Node
for _, n := range nodesByKindsOrAll(g, graph.KindMethod) {
if n == nil {
continue
}
build := buildByClass[classByMethod[n.ID]]
if build == nil || build.ID == n.ID {
continue
}
if !methodCallsSetState(g, n.ID) {
continue
}
setStateMethods = append(setStateMethods, n)
}
sort.Slice(setStateMethods, func(i, j int) bool {
return setStateMethods[i].ID < setStateMethods[j].ID
})
var batch []*graph.Edge
synthesized := 0
for _, m := range setStateMethods {
build := buildByClass[classByMethod[m.ID]]
batch = append(batch, flutterSetStateEdge(m, build, classByMethod[m.ID]))
synthesized++
}
for _, e := range batch {
g.AddEdge(e)
}
return synthesized
}
// flutterSetStateEdge builds one setState-method → build synthesized edge.
func flutterSetStateEdge(from, build *graph.Node, class string) *graph.Edge {
return &graph.Edge{
From: from.ID,
To: build.ID,
Kind: graph.EdgeCalls,
FilePath: from.FilePath,
Line: from.StartLine,
Confidence: 0.6,
ConfidenceLabel: graph.ConfidenceLabelFor(graph.EdgeCalls, 0.6),
Origin: graph.OriginASTInferred,
Meta: map[string]any{
"via": flutterSetStateVia,
"state_class": class,
MetaSynthesizedBy: SynthFlutterSetState,
MetaProvenance: ProvenanceHeuristic,
},
}
}