This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
betteralign is a Go static analysis tool (fork of fieldalignment) that detects structs using suboptimal memory layout and optionally rewrites them. It sorts struct fields by descending alignment, then minimizes GC pointer scan overhead.
The project uses Task as the build runner.
task test # run all tests
task build # regenerate, format, and build the binary
task lint # regenerate, format, and run golangci-lint
task fmt # format code with gci + gofumpt
task generate # regenerate match_generated.go, then fmt
task update # go get -u + tidyDirect Go commands:
go test ./... # run tests
go test -run TestApply # run a single test by name
go build ./cmd/betteralign # build without ldflagsLinting uses golangci-lint run --timeout 5m with config in .golangci.yml (v2 format). Formatters are gci and gofumpt (not plain gofmt).
betteralign(root) — the coreanalysis.Analyzer. Contains all alignment analysis logic, file I/O, and flag definitions.cmd/betteralign/— thin CLI wrapper. Wires up resource limits (automemlimit,automaxprocs), handles-V/--version, and callssinglechecker.Main(betteralign.Analyzer).
| File | Purpose |
|---|---|
betteralign.go |
Analyzer definition, run() entrypoint, DST-based rewrite, field sort (optimalOrder), GC size calculations (gcSizes) |
match_generated.go |
Generated — DFA matcher for // Code generated by … DO NOT EDIT. comments. Regenerate with task generate using the rec tool; do not edit by hand. |
cmd/betteralign/main.go |
Entry point; sets GOMAXPROCS and GOMEMLIMIT from cgroup/system |
cmd/betteralign/version.go |
Version string populated via -ldflags at build time |
- The
inspect.Analyzertraverses the AST;betteralignhooks intoPreorderon*ast.File,*ast.GenDecl, and*ast.StructTypenodes. - For each file, a DST decorator (
decorator.NewDecorator) is created to produce a parallel DST tree that preserves comment decorations. - Each struct is checked: if field order is not optimal,
pass.Reportemits a diagnostic and the reordered DST is serialized to a buffer (keyed by filename inapplyFixesFset). - After the pass, if
-applyis set, each buffer is atomically written to disk viagithub.com/google/renameio/v2/maybe(atomic on POSIX, best-effort on Windows).
Go's ast package does not associate comments with nodes (only stores byte offsets), so rewriting a single struct node loses all comments. DST clones the AST and attaches comment decorations to nodes. The trade-off: the whole file must be reprinted (not a partial edit), so SuggestedFixes is never populated, -fix is a no-op alias for -apply, and integration with golangci-lint is impossible.
Fields are sorted stably by:
- Zero-sized types first
- Higher alignment first
- Pointer-bearing types before pointer-free types
- Among pointer-bearing types, fewer trailing non-pointer bytes first (minimises GC ptrdata)
- Larger size first
// betteralign:ignoreinside a struct's opening brace — skip this struct entirely// betteralign:checkon thetypedeclaration — required when-opt_inflag is set
Tests live in betteralign_test.go (package betteralign_test) and use golang.org/x/tools/go/analysis/analysistest.
TestSuggestions— runs the analyzer ontestdata/src/aand checks that// wantannotations match reported diagnostics.TestApply— copiestestdata/src/a/*.goto a temp dir, runs with-apply, and compares results against*.go.goldenfiles usinggotest.tools/v3/golden.- Architecture-specific files (
a_amd64.go,a_arm64.go) are filtered at test time to only include the currentruntime.GOARCH. - Flag-specific tests cover
-exclude_dirs,-exclude_files, and-opt_inscenarios undertestdata/src/exclude/andtestdata/src/optin/.
When adding new test cases: add a .go file under testdata/src/a/ with // want annotations, and a corresponding .go.golden file with the expected post-apply output.