🐹 Go Fan Report: golang.org/x/tools
Module Overview
golang.org/x/tools (v0.48.0) is the Go team's static-analysis and tooling library. In gh-aw it is the backbone of the custom linter suite: 49 analyzers built on go/analysis, go/analysis/passes/inspect, go/ast/inspector, wired via go/analysis/multichecker, and tested with go/analysis/analysistest. It's also the install source for gopls in pkg/workflow/lsp_manager.go. It was the most recently updated direct dependency (pushed 2026-07-14), so it earned today's round-robin slot.
Current Usage in gh-aw
- Files: 49 analyzer packages under
pkg/linters/*, plus cmd/linters/main.go and shared helpers in pkg/linters/internal/{astutil,nolint,filecheck}.
- Import count: ~50 non-test files import
golang.org/x/tools/....
- Key APIs used:
analysis.Analyzer / analysis.Pass, passes/inspect, ast/inspector (modern cursor API: Root().Preorder, cur.Enclosing), multichecker.Main, analysistest.Run / RunWithSuggestedFixes, analysis.SuggestedFix + TextEdit.
Research Findings
gh-aw is on the latest tag (v0.48.0) and the usage is genuinely idiomatic and current:
- Adopts the newer
inspector.Cursor API (Enclosing, Preorder over cursors) rather than the legacy inspector.WithStack.
- Each
Analyzer sets Name, Doc, and the modern URL field, and declares Requires: []*analysis.Analyzer{inspect.Analyzer} so the AST inspector is built once per package and shared — exactly the framework's intended reuse pattern.
Recent Updates
Nothing in the v0.34→v0.48 range forces changes here; the code already tracks the cursor-based inspector API introduced across those releases.
Best Practices
The go/analysis design centers on: (1) small single-purpose analyzers, (2) sharing expensive work via Requires/ResultOf, (3) analysistest golden-file verification of fixes, (4) rich Diagnostic metadata (Category, URL, SuggestedFix). gh-aw already nails (1)–(3).
Improvement Opportunities
🏃 Quick Wins
- Set
Diagnostic.Category. No analyzer currently sets it. Populating Category (e.g. the analyzer name) lets -json output, editors, and CI group/filter diagnostics. Low effort via a small pass.Report(analysis.Diagnostic{Category: Name, ...}) helper.
✨ Feature Opportunities
- Skip generated files using
ast.IsGenerated(file) (go/ast, Go 1.21+), mirroring the existing filecheck.IsTestFile guard. gh-aw generates Go code, and analyzers can currently flag those files, adding noise.
- Optional
unitchecker/singlechecker entrypoint so individual analyzers can run under go vet -vettool, complementing multichecker.Main.
📐 Best Practice Alignment
- Share the nolint index via
ResultOf. 48 of 49 analyzers each call nolint.BuildLineIndex(pass, name), which re-scans every comment in every file — once per analyzer. The framework is built to avoid exactly this: promote it to a tiny nolintindex.Analyzer that returns a map[file]map[line]map[name]struct{} computed once per package, list it in each analyzer's Requires, and read it from pass.ResultOf — the same mechanism already used for inspect.Analyzer. This turns O(analyzers × comments) into O(comments) and removes duplicated scanning logic. (Marginal runtime cost is modest next to type-checking, but it is the idiomatic pattern and a nice cleanup.)
🔧 General Improvements
- Fix-emitting analyzers are already exemplary: all 15 use
RunWithSuggestedFixes with .golden files. No gap found there — worth keeping as the bar for new analyzers.
Recommendations
- (Medium) Introduce a shared
nolintindex analyzer consumed via Requires/ResultOf; migrate the 48 callers off per-analyzer BuildLineIndex.
- (Low) Add
ast.IsGenerated skipping alongside filecheck.IsTestFile in a shared guard.
- (Low) Set
Diagnostic.Category on emitted diagnostics for better downstream grouping.
Next Steps
- Prototype
pkg/linters/internal/nolintindex and convert 2–3 analyzers as a pattern, then sweep the rest.
- Extend the shared file guard to cover generated files; add a testdata case.
Generated by Go Fan
Module summary saved to: scratchpad/mods/golang.org-x-tools.md
Generated by 🐹 Go Fan · 151.1 AIC · ⌖ 14.2 AIC · ⊞ 7.3K · ◷
🐹 Go Fan Report: golang.org/x/tools
Module Overview
golang.org/x/tools(v0.48.0) is the Go team's static-analysis and tooling library. In gh-aw it is the backbone of the custom linter suite: 49 analyzers built ongo/analysis,go/analysis/passes/inspect,go/ast/inspector, wired viago/analysis/multichecker, and tested withgo/analysis/analysistest. It's also the install source forgoplsinpkg/workflow/lsp_manager.go. It was the most recently updated direct dependency (pushed 2026-07-14), so it earned today's round-robin slot.Current Usage in gh-aw
pkg/linters/*, pluscmd/linters/main.goand shared helpers inpkg/linters/internal/{astutil,nolint,filecheck}.golang.org/x/tools/....analysis.Analyzer/analysis.Pass,passes/inspect,ast/inspector(modern cursor API:Root().Preorder,cur.Enclosing),multichecker.Main,analysistest.Run/RunWithSuggestedFixes,analysis.SuggestedFix+TextEdit.Research Findings
gh-aw is on the latest tag (v0.48.0) and the usage is genuinely idiomatic and current:
inspector.CursorAPI (Enclosing,Preorderover cursors) rather than the legacyinspector.WithStack.AnalyzersetsName,Doc, and the modernURLfield, and declaresRequires: []*analysis.Analyzer{inspect.Analyzer}so the AST inspector is built once per package and shared — exactly the framework's intended reuse pattern.Recent Updates
Nothing in the v0.34→v0.48 range forces changes here; the code already tracks the cursor-based inspector API introduced across those releases.
Best Practices
The
go/analysisdesign centers on: (1) small single-purpose analyzers, (2) sharing expensive work viaRequires/ResultOf, (3)analysistestgolden-file verification of fixes, (4) richDiagnosticmetadata (Category,URL,SuggestedFix). gh-aw already nails (1)–(3).Improvement Opportunities
🏃 Quick Wins
Diagnostic.Category. No analyzer currently sets it. PopulatingCategory(e.g. the analyzer name) lets-jsonoutput, editors, and CI group/filter diagnostics. Low effort via a smallpass.Report(analysis.Diagnostic{Category: Name, ...})helper.✨ Feature Opportunities
ast.IsGenerated(file)(go/ast, Go 1.21+), mirroring the existingfilecheck.IsTestFileguard. gh-aw generates Go code, and analyzers can currently flag those files, adding noise.unitchecker/singlecheckerentrypoint so individual analyzers can run undergo vet -vettool, complementingmultichecker.Main.📐 Best Practice Alignment
ResultOf. 48 of 49 analyzers each callnolint.BuildLineIndex(pass, name), which re-scans every comment in every file — once per analyzer. The framework is built to avoid exactly this: promote it to a tinynolintindex.Analyzerthat returns amap[file]map[line]map[name]struct{}computed once per package, list it in each analyzer'sRequires, and read it frompass.ResultOf— the same mechanism already used forinspect.Analyzer. This turns O(analyzers × comments) into O(comments) and removes duplicated scanning logic. (Marginal runtime cost is modest next to type-checking, but it is the idiomatic pattern and a nice cleanup.)🔧 General Improvements
RunWithSuggestedFixeswith.goldenfiles. No gap found there — worth keeping as the bar for new analyzers.Recommendations
nolintindexanalyzer consumed viaRequires/ResultOf; migrate the 48 callers off per-analyzerBuildLineIndex.ast.IsGeneratedskipping alongsidefilecheck.IsTestFilein a shared guard.Diagnostic.Categoryon emitted diagnostics for better downstream grouping.Next Steps
pkg/linters/internal/nolintindexand convert 2–3 analyzers as a pattern, then sweep the rest.Generated by Go Fan
Module summary saved to: scratchpad/mods/golang.org-x-tools.md