Skip to content

Latest commit

 

History

History
81 lines (56 loc) · 4.39 KB

File metadata and controls

81 lines (56 loc) · 4.39 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

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.

Commands

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 + tidy

Direct Go commands:

go test ./...              # run tests
go test -run TestApply     # run a single test by name
go build ./cmd/betteralign # build without ldflags

Linting uses golangci-lint run --timeout 5m with config in .golangci.yml (v2 format). Formatters are gci and gofumpt (not plain gofmt).

Architecture

Package layout

  • betteralign (root) — the core analysis.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 calls singlechecker.Main(betteralign.Analyzer).

Key files

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

Analysis pipeline

  1. The inspect.Analyzer traverses the AST; betteralign hooks into Preorder on *ast.File, *ast.GenDecl, and *ast.StructType nodes.
  2. For each file, a DST decorator (decorator.NewDecorator) is created to produce a parallel DST tree that preserves comment decorations.
  3. Each struct is checked: if field order is not optimal, pass.Report emits a diagnostic and the reordered DST is serialized to a buffer (keyed by filename in applyFixesFset).
  4. After the pass, if -apply is set, each buffer is atomically written to disk via github.com/google/renameio/v2/maybe (atomic on POSIX, best-effort on Windows).

Why DST instead of SuggestedFixes

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.

Field sort order (optimalOrder)

Fields are sorted stably by:

  1. Zero-sized types first
  2. Higher alignment first
  3. Pointer-bearing types before pointer-free types
  4. Among pointer-bearing types, fewer trailing non-pointer bytes first (minimises GC ptrdata)
  5. Larger size first

Magic comment annotations

  • // betteralign:ignore inside a struct's opening brace — skip this struct entirely
  • // betteralign:check on the type declaration — required when -opt_in flag is set

Testing

Tests live in betteralign_test.go (package betteralign_test) and use golang.org/x/tools/go/analysis/analysistest.

  • TestSuggestions — runs the analyzer on testdata/src/a and checks that // want annotations match reported diagnostics.
  • TestApply — copies testdata/src/a/*.go to a temp dir, runs with -apply, and compares results against *.go.golden files using gotest.tools/v3/golden.
  • Architecture-specific files (a_amd64.go, a_arm64.go) are filtered at test time to only include the current runtime.GOARCH.
  • Flag-specific tests cover -exclude_dirs, -exclude_files, and -opt_in scenarios under testdata/src/exclude/ and testdata/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.