Skip to content

[go-fan] Go Module Review: golang.org/x/tools #53941

Description

@github-actions

Go Fan Report: golang.org/x/tools

Module Overview

golang.org/x/tools is the Go team extended tools module — the go/analysis static-analysis framework, go/ast/inspector, go/packages, the gopls language server, and assorted dev-tool packages (cover, txtar, etc). It is selected today because it is the most recently pushed direct dependency in go.mod (2026-08-18), and gh-aw builds an entire in-house static-analysis suite on top of it.

Current Usage in gh-aw

  • Files: 76 non-test .go files import it; 77 more _test.go files import it (mostly analysistest)
  • Version: v0.49.0 — this is also the latest tag of the module. Already fully up to date, no action needed there.
  • Key APIs used: analysis.Analyzer/analysis.Pass, pass.ReportRangef, analysis.TextEdit/SuggestedFix, inspector.Inspector, the modern inspector.Cursor iterator API, multichecker.Main, go/packages.Load, cover.ParseProfiles.
  • Import breakdown:
    • go/analysis — 81 files
    • go/analysis/analysistest — 67 files (unit tests for every custom linter)
    • go/ast/inspector — 13 files
    • gopls — 5 references (installed as an external binary via go install, not linked as a library — see pkg/workflow/lsp_manager.go)
    • go/analysis/passes/inspect — 3 files
    • go/packages — 2 files (.github/scripts/purelock/purity_scan.go)
    • go/analysis/multichecker — 1 file (cmd/linters/main.go)
    • cover — 1 file (pkg/linters/internal/coverage/coverage.go)

The centerpiece is pkg/linters/* — roughly 65 hand-written go/analysis analyzers (e.g. largefunc, deferinloop, httprespbodyclose, sortslice...) covering everything from resource-leak patterns to idiomatic stdlib usage, all wired together by a shared pkg/linters/internal/analyzerutil helper and driven by cmd/linters via multichecker.Main.

Research Findings

  • Repository: https://github.com/golang/tools — latest tag v0.49.0, pushed 2026-08-18, matching go.mod exactly.
  • gopls (versioned separately) is at v0.23.0 (released 2026-07-09).

Recent Updates

Steady maintenance releases on both the module and gopls; nothing breaking for the APIs gh-aw depends on. No migration work required.

Best Practices (from module docs)

  • Prefer the newer inspector.Cursor iterator API (Root().Preorder(...), cur.Enclosing(...), cur.Parent()) over the legacy callback-style Inspector.Preorder(filter, func(ast.Node)).
  • Declare shared pass dependencies via Analyzer.Requires instead of recomputing state per analyzer.
  • Test every analyzer with analysistest.Run against testdata/src/<pkg> fixtures.

gh-aw already follows all three of these: pkg/linters/internal/analyzerutil.go builds every analyzer via a shared New/NewAtPath constructor that declares Requires: []*analysis.Analyzer{inspect.Analyzer, nolint.Analyzer, filecheck.Analyzer}, its Preorder helper uses inspector.Cursor, and all ~65 analyzers have analysistest-based tests. 👍

Improvement Opportunities

🏃 Quick Wins

  • 46 of the ~65 analyzers already emit analysis.SuggestedFix edits (import add/remove, strings.Contains rewrites, byte/string round-trip fixes, etc.), but neither the golint-custom target in Makefile nor pkg/linters/README.md mentions the -fix flag that multichecker.Main supports out of the box. Documenting make golint-custom LINTER_FLAGS=-fix (or adding a golint-custom-fix target) would let contributors auto-apply nearly half of the linter fixes with zero new code.

✨ Feature Opportunities

  • cmd/linters/main.go drives everything through multichecker.Main, which reloads and fully re-type-checks the target package set (./cmd/... ./pkg/...) on every run. golang.org/x/tools/go/analysis/unitchecker exposes the same analysis.Analyzer set through the standard go vet -vettool= protocol. Swapping (or adding) a unitchecker-based entry point would let go vet -vettool=/tmp/gh-aw-linters ./... — or even plain go build/go test, which invoke vet automatically — piggyback on the Go build cache and only re-analyze changed packages. That gives the custom linters the same kind of incremental speedup golint-incremental already provides for golangci-lint, without any hand-rolled changed-file diffing.

📐 Best Practice Alignment

  • No gaps found — the shared analyzerutil/astutil helpers already track the modern Cursor-based traversal API and the Requires-based dependency pattern recommended by the x/tools maintainers. Worth calling out in review guidance for new analyzers so they keep using Cursor rather than reintroducing ast.Inspect callbacks.

🔧 General Improvements

  • None beyond the two items above — usage is thorough and idiomatic.

Recommendations

  1. Add -fix documentation/target for golint-custom (quick win, no code changes to analyzers).
  2. Evaluate a unitchecker-based driver alongside (or instead of) multichecker to unlock incremental, cache-aware analysis via go vet -vettool=.

Next Steps

  • File a follow-up task to prototype a cmd/linters-vettool (or flag-selected mode in cmd/linters) using unitchecker.Main and measure the wall-clock difference on a warm build cache vs. the current full-repo multichecker run.

Generated by Go Fan 🐹
Module summary saved to: scratchpad/mods/golang.org-x-tools.md

Generated by 🐹 Go Fan · agent · 193.2 AIC · ⌖ 5.01 AIC · ⊞ 7.8K ·

  • expires on Aug 20, 2026, 12:15 AM UTC-08:00

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions