diff --git a/internal/codeguard/checks/design/design_change_impact.go b/internal/codeguard/checks/design/design_change_impact.go index 0a677dd..033fec3 100644 --- a/internal/codeguard/checks/design/design_change_impact.go +++ b/internal/codeguard/checks/design/design_change_impact.go @@ -29,8 +29,9 @@ func changeImpactFindings(env support.Context, graphs []targetModuleGraph) []cor entries := make([]core.ChangeImpactEntry, 0) findings := make([]core.Finding, 0) for _, item := range graphs { + reverse := item.graph.reverseDependencies() for _, changed := range env.ChangedFiles { - entry, ok := changeImpactEntry(item, changed) + entry, ok := changeImpactEntry(item, reverse, changed) if !ok { continue } @@ -46,12 +47,12 @@ func changeImpactFindings(env support.Context, graphs []targetModuleGraph) []cor return findings } -func changeImpactEntry(item targetModuleGraph, changed string) (core.ChangeImpactEntry, bool) { +func changeImpactEntry(item targetModuleGraph, reverse map[string][]string, changed string) (core.ChangeImpactEntry, bool) { module, ok := item.graph.fileToModule[filepath.ToSlash(changed)] if !ok { return core.ChangeImpactEntry{}, false } - dependents := item.graph.transitiveDependents(module) + dependents := support.TransitiveDependents(reverse, module) return core.ChangeImpactEntry{ Target: item.target.Name, Language: item.graph.language, diff --git a/internal/codeguard/checks/design/design_dependency_graph.go b/internal/codeguard/checks/design/design_dependency_graph.go index 1990b5e..66a0215 100644 --- a/internal/codeguard/checks/design/design_dependency_graph.go +++ b/internal/codeguard/checks/design/design_dependency_graph.go @@ -1,10 +1,6 @@ package design -import ( - "sort" - - "github.com/devr-tools/codeguard/internal/codeguard/checks/support" -) +import "sort" // moduleGraph is a language-neutral module import graph used for cycle, // god-module, and change-impact analysis across languages. @@ -118,14 +114,15 @@ func (g *moduleGraph) fanCounts() (map[string]int, map[string]int) { return fanOut, fanIn } -// transitiveDependents returns every module that reaches the given module -// through one or more import edges, sorted by name. -func (g *moduleGraph) transitiveDependents(module string) []string { +// reverseDependencies builds the reverse adjacency list shared by change-impact +// traversals. Callers should build it once after graph construction rather than +// rebuilding it for every changed module. +func (g *moduleGraph) reverseDependencies() map[string][]string { reverse := make(map[string][]string, len(g.modules)) for from, node := range g.modules { for _, edge := range node.edges { reverse[edge.to] = append(reverse[edge.to], from) } } - return support.TransitiveDependents(reverse, module) + return reverse }