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

95 lines
3.6 KiB
Go

package indexer
import (
"os"
"strings"
"github.com/zzet/gortex/internal/graph"
)
// scopedGlobalPassesEnabled reports whether incremental reindex should scope
// the global inference passes (InferImplements / InferOverrides) to the
// changed-affected type set instead of re-running them over the whole graph.
// GORTEX_INDEX_SCOPED_GLOBAL_PASSES overrides the config key. ON by default.
func (idx *Indexer) scopedGlobalPassesEnabled() bool {
if v := os.Getenv("GORTEX_INDEX_SCOPED_GLOBAL_PASSES"); v != "" {
return v == "1" || strings.EqualFold(v, "true")
}
return idx.config.ScopedGlobalPassesEnabledOrDefault()
}
// affectedTypeSet computes the type/interface IDs whose inferred
// implements/override edges a set of changed (stale) files can affect:
// - every KindType / KindInterface the changed files define (their inferred
// out/in edges were dropped on eviction), and
// - the owning type of every KindMethod in a changed file (a method add/remove
// changes the type's method-set, which can newly satisfy / break an
// interface defined in an unchanged file).
//
// types is the full re-check set; ifaces is the subset of changed interfaces
// (every type must be re-checked against a changed interface). Re-checking
// every (type, interface) pair with an endpoint in these sets re-lands exactly
// the edges eviction dropped — add-parity with the full pass.
func (idx *Indexer) affectedTypeSet(graphPaths []string) (types, ifaces map[string]bool) {
types = map[string]bool{}
ifaces = map[string]bool{}
for _, p := range graphPaths {
for _, n := range idx.graph.GetFileNodes(p) {
if n == nil {
continue
}
switch n.Kind {
case graph.KindType, graph.KindInterface:
types[n.ID] = true
if n.Kind == graph.KindInterface {
ifaces[n.ID] = true
}
case graph.KindMethod:
for _, e := range idx.graph.GetOutEdges(n.ID) {
if e.Kind == graph.EdgeMemberOf {
types[e.To] = true
}
}
}
}
}
return types, ifaces
}
// staleFilesAffectDerivedEdges reports whether any stale file carries code
// structure (functions / methods / types / fields / …) that the capability
// and framework-dispatch synthesizers derive edges from. When every stale
// file is non-code — a README, a JSON/YAML config, a data file — those
// whole-graph passes cannot produce or change any edge, so the caller skips
// them (the doc/config-edit fast path). Sound by construction: a file with
// no structural nodes contributes no calls / reads / writes / dispatch
// sites, which is the only input those synthesizers read.
func (idx *Indexer) staleFilesAffectDerivedEdges(staleFiles []string) bool {
for _, p := range idx.graphFilePaths(staleFiles) {
for _, n := range idx.graph.GetFileNodes(p) {
if n != nil && isStructuralKind(n.Kind) {
return true
}
}
}
return false
}
// runScopedInferencePasses runs the implements/override inference passes scoped
// to the types/interfaces a set of stale files can affect. Returns false when
// scoping is disabled (caller should run the full passes). When nothing
// type/interface-shaped changed, the passes are skipped entirely (the common
// case for a function-body edit).
func (idx *Indexer) runScopedInferencePasses(staleFiles []string) bool {
if !idx.scopedGlobalPassesEnabled() {
return false
}
types, ifaces := idx.affectedTypeSet(idx.graphFilePaths(staleFiles))
if len(types) == 0 && len(ifaces) == 0 {
return true // no type/interface change → no inferred edges to re-derive
}
idx.resolver.InferImplementsScoped(types, ifaces)
idx.resolver.InferOverridesScoped(types)
return true
}