You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
golang.org/x/tools is the Go team's collection of supplementary tooling packages β most notably the go/analysis static-analysis framework, the AST inspector, the multichecker driver, and analysistest. In gh-aw it's used for exactly one purpose: building the project's suite of 23 custom linters that enforce internal code conventions, wired into a single binary via cmd/linters/main.go.
It's also our most recently updated direct dependency (repo pushed_at 2026-06-09), and the go/ast/inspector package is under active development right now β making this a timely review. π
Summary
Module: golang.org/x/toolsv0.45.0 (latest)
Files using it: 26 non-test .go files (+ 24 test files via analysistest)
Role: powers all 23 go/analysis linters
Status: β οΈ well-used, but three divergent traversal idioms and low autofix coverage
Key APIs Used: analysis.Analyzer / analysis.Pass / analysis.Diagnostic, multichecker.Main, inspector.Inspector (Preorder, WithStack, and the modern Root()/Cursor API), passes/inspect.Analyzer as a shared dependency.
The go/analysis framework is the canonical, stable foundation for Go static analysis, and gh-aw uses it idiomatically (one Analyzer per rule, inspect.Analyzer as a Requires dependency, multichecker.Main as the driver, analysistest golden tests).
Recent Updates
The go/ast/inspector package is actively evolving toward the Cursor API. Recent upstream commits add Cursor.ParentEdge{Kind,Index} methods β the commit message explicitly notes they're "obviating astutil.IsChildOf." The Cursor model (insp.Root(), cur.Enclosing, cur.Parent, cur.Children, cur.Preorder) is the maintainers' recommended modern replacement for WithStack and manual stack handling.
Best Practices
One focused Analyzer per rule; declare Requires: []*analysis.Analyzer{inspect.Analyzer} and read the shared *inspector.Inspector from pass.ResultOf.
Prefer the Cursor API over WithStack/manual stacks for enclosing-node queries.
Emit analysis.SuggestedFix where a fix is mechanical β multichecker exposes these via its built-in -fix flag for free.
Improvement Opportunities
π Quick Wins
De-duplicate inspector-extraction boilerplate. All 23 linters repeat the identical block:
insp, ok:=pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
if!ok {
returnnil, fmt.Errorf("inspect analyzer result has unexpected type %T", pass.ResultOf[inspect.Analyzer])
}
Extract one helper β e.g. astutil.Inspector(pass) (*inspector.Inspector, error) in pkg/linters/internal/astutil β and collapse 23 copies to a single call. Pure mechanical win, no behavior change.
β¨ Feature Opportunities
Add SuggestedFixes (autofix) to more linters. Only 2 of 23 analyzers (ctxbackground, execcommandwithoutcontext) currently emit analysis.SuggestedFix/analysis.TextEdit. Since the suite runs through multichecker.Main, adding fixes makes them available via the built-in -fix flag and editor integrations at no extra wiring cost. Good mechanical candidates: fprintlnsprintf, tolowerequalfold, lenstringzero. Pair each with analysistest.RunWithSuggestedFixes golden tests (already the established pattern in the 2 existing fixers).
π Best Practice Alignment
Standardize on the Cursor API. The suite currently mixes three idioms for the same task:
Idiom
Files
Notes
Modern insp.Root().Preorder(...) + cur.Enclosing(...)
In regexpcompileinfunction, the hand-written isInsideFunction(stack []ast.Node) loop is exactly what cur.Enclosing((*ast.FuncDecl)(nil), (*ast.FuncLit)(nil)) provides natively β migrating the two WithStack linters removes the manual push/pop boolean handling and aligns with where x/tools is heading.
π§ General Improvements
A short CONTRIBUTING/pkg/linters note pinning the canonical traversal idiom would stop new linters from reintroducing Preorder/WithStack divergence.
Centralizing the extraction helper makes any future inspect/inspector API shift a one-file change instead of a 23-file sweep.
Recommendations
(Low effort, high consistency) Extract the inspector-extraction helper into internal/astutil; refactor all 23 linters to use it.
(Medium effort, user-facing value) Add SuggestedFixes + RunWithSuggestedFixes tests to the mechanically-fixable linters, starting with fprintlnsprintf / tolowerequalfold / lenstringzero.
(Low effort, future-proofing) Migrate the two WithStack linters to the Cursor API and document it as the canonical idiom.
Next Steps
Open a focused PR for recommendation rejig docsΒ #1 (mechanical, easily reviewable).
Prototype an autofix on one linter to validate the RunWithSuggestedFixes workflow before fanning out.
Generated by Go Fan Module summary saved to: scratchpad/mods/golang-x-tools.md
πΉ Go Fan Report: golang.org/x/tools
Module Overview
golang.org/x/toolsis the Go team's collection of supplementary tooling packages β most notably thego/analysisstatic-analysis framework, the ASTinspector, themulticheckerdriver, andanalysistest. In gh-aw it's used for exactly one purpose: building the project's suite of 23 custom linters that enforce internal code conventions, wired into a single binary viacmd/linters/main.go.It's also our most recently updated direct dependency (repo
pushed_at2026-06-09), and thego/ast/inspectorpackage is under active development right now β making this a timely review. πSummary
golang.org/x/toolsv0.45.0 (latest).gofiles (+ 24 test files viaanalysistest)go/analysislintersCurrent Usage in gh-aw
cmd/linters/main.go+ sharedinternal/astutil)go/analysis(28),analysistest(24, tests),go/ast/inspector(23),passes/inspect(23),multichecker(1)analysis.Analyzer/analysis.Pass/analysis.Diagnostic,multichecker.Main,inspector.Inspector(Preorder,WithStack, and the modernRoot()/CursorAPI),passes/inspect.Analyzeras a shared dependency.The 23 linters in the suite
contextcancelnotdeferred, ctxbackground, errormessage, errstringmatch, excessivefuncparams, execcommandwithoutcontext, fileclosenotdeferred, fmterrorfnoverbs, fprintlnsprintf, jsonmarshalignoredeerror, largefunc, lenstringzero, manualmutexunlock, osexitinlibrary, ossetenvlibrary, panic-in-library-code, rawloginlib, regexpcompileinfunction, seenmapbool, sortslice, ssljson, strconvparseignorederror, tolowerequalfold, uncheckedtypeassertion
Research Findings
The
go/analysisframework is the canonical, stable foundation for Go static analysis, and gh-aw uses it idiomatically (oneAnalyzerper rule,inspect.Analyzeras aRequiresdependency,multichecker.Mainas the driver,analysistestgolden tests).Recent Updates
The
go/ast/inspectorpackage is actively evolving toward theCursorAPI. Recent upstream commits addCursor.ParentEdge{Kind,Index}methods β the commit message explicitly notes they're "obviating astutil.IsChildOf." TheCursormodel (insp.Root(),cur.Enclosing,cur.Parent,cur.Children,cur.Preorder) is the maintainers' recommended modern replacement forWithStackand manual stack handling.Best Practices
Analyzerper rule; declareRequires: []*analysis.Analyzer{inspect.Analyzer}and read the shared*inspector.Inspectorfrompass.ResultOf.CursorAPI overWithStack/manual stacks for enclosing-node queries.analysis.SuggestedFixwhere a fix is mechanical βmulticheckerexposes these via its built-in-fixflag for free.Improvement Opportunities
π Quick Wins
astutil.Inspector(pass) (*inspector.Inspector, error)inpkg/linters/internal/astutilβ and collapse 23 copies to a single call. Pure mechanical win, no behavior change.β¨ Feature Opportunities
SuggestedFixes(autofix) to more linters. Only 2 of 23 analyzers (ctxbackground,execcommandwithoutcontext) currently emitanalysis.SuggestedFix/analysis.TextEdit. Since the suite runs throughmultichecker.Main, adding fixes makes them available via the built-in-fixflag and editor integrations at no extra wiring cost. Good mechanical candidates:fprintlnsprintf,tolowerequalfold,lenstringzero. Pair each withanalysistest.RunWithSuggestedFixesgolden tests (already the established pattern in the 2 existing fixers).π Best Practice Alignment
Standardize on the
CursorAPI. The suite currently mixes three idioms for the same task:insp.Root().Preorder(...)+cur.Enclosing(...)ctxbackground,execcommandwithoutcontextinsp.WithStack(...)+ manualstack []ast.Nodescanregexpcompileinfunction,panic-in-library-codeinsp.Preorder(filter, func)In
regexpcompileinfunction, the hand-writtenisInsideFunction(stack []ast.Node)loop is exactly whatcur.Enclosing((*ast.FuncDecl)(nil), (*ast.FuncLit)(nil))provides natively β migrating the twoWithStacklinters removes the manual push/pop boolean handling and aligns with where x/tools is heading.π§ General Improvements
pkg/lintersnote pinning the canonical traversal idiom would stop new linters from reintroducingPreorder/WithStackdivergence.inspect/inspectorAPI shift a one-file change instead of a 23-file sweep.Recommendations
internal/astutil; refactor all 23 linters to use it.SuggestedFixes+RunWithSuggestedFixestests to the mechanically-fixable linters, starting withfprintlnsprintf/tolowerequalfold/lenstringzero.WithStacklinters to theCursorAPI and document it as the canonical idiom.Next Steps
RunWithSuggestedFixesworkflow before fanning out.Generated by Go Fan
Module summary saved to: scratchpad/mods/golang-x-tools.md
References: Β§27265473810