Go Struct Analyzer — Development Guide¶
Developer documentation and contributor guide for the Go Struct Analyzer VS Code extension.
Prerequisites¶
- Go 1.21+ (for the LSP server)
- Node.js 22+ (for the VS Code extension)
- VS Code (for extension development)
Quick Start¶
Press F5 in VS Code to launch an Extension Development Host window with the extension loaded.
Project Structure¶
| Directory/File | Purpose |
|---|---|
cmd/gsa-lsp/ |
CLI entry point (analyze, lsp, version subcommands) |
internal/analysis/ |
Types, layout (size/align/ptrdata), analyzer (go/packages), optimizer (fieldalignment sort) |
internal/lsp/ |
Protocol types, JSON-RPC server, all LSP method handlers |
internal/version/ |
Ldflags version variables |
src/extension.ts |
VS Code extension entry — LSP client + inline annotations |
Makefile |
Build, test, lint, preflight targets |
test_go_file.go |
Validation structs (BadLayout, GoodLayout, ComplexStruct, ArrayExample) |
test_go_edge-cases.go |
Edge cases (generics, embedded, tags, comments, composite types) |
Development Workflow¶
Build¶
make build # Go binary + TypeScript (full build)
make build-go # gsa-lsp binary only
make build-ts # TypeScript only
Test¶
Lint and Format¶
make lint # golangci-lint (Go)
make vet # go vet (Go)
make fmt # gofmt (Go)
make preflight # vet → fmt → lint → test
Run the LSP Server¶
make build-go
./gsa-lsp analyze test_go_file.go # CLI analysis (JSON)
echo '...' | ./gsa-lsp lsp # LSP mode (stdin/stdout)
VS Code Extension Development¶
make build— compile everything- Press
F5in VS Code to launch Extension Development Host - Open any
.gofile to see features in action - Check Output panel (View → Output, select "Go Struct Analyzer") for LSP logs
Changes to src/extension.ts require a rebuild (make build-ts) and reload of the Extension Development Host.
Changes to internal/ Go code require make build-go (or make build) and reload.
Go Module¶
The Go code lives under cmd/gsa-lsp/ and internal/:
LSP Server Architecture¶
- JSON-RPC 2.0 over stdin/stdout with Content-Length headers
- File analysis triggers on
didOpen/didSave - Supports:
initialize,shutdown,textDocument/hover,textDocument/codeLens,textDocument/codeAction,textDocument/didOpen/didChange/didSave/didClose,textDocument/publishDiagnostics,$/structData - The
$/structDatacustom request returns the rawAnalysisResultfor inline annotations
Validation¶
Against fieldalignment¶
The Go backend uses go/types.SizesFor() and a ptrdata() algorithm matching gcSizes.ptrdata():
# Verify sizing
./gsa-lsp analyze test_go_file.go | python3 -m json.tool
# Compare against go-crap structs
./gsa-lsp analyze /path/to/go-crap/internal/coverage/scanner.go
Known correct values:
- Scanner struct: 40 bytes → 32 bytes (matches fieldalignment "40 ptr bytes → 32")
- Options struct: 80 bytes → 72 bytes (matches fieldalignment "80 ptr bytes → 72")
Manual VS Code Validation¶
- [ ] Open
test_go_file.goin Extension Development Host - [ ] Hover over each struct — verify sizes match
./gsa-lsp analyze test_go_file.go - [ ] Code lens shows correct sizes
- [ ] Diagnostics fire for sub-optimal structs (BadLayout, not GoodLayout)
- [ ] Quick fix offered for BadLayout, not for GoodLayout
- [ ] Tags, comments, indentation preserved after reorder
- [ ]
$/structDataprovides correct data (inline annotations render)
Architecture Notes¶
Go Memory Alignment¶
- Each field aligns to its natural boundary (size, capped at pointer size)
- Struct alignment is the largest field alignment
- Struct size is padded to a multiple of its alignment
Architecture-Dependent Sizes¶
| Type | amd64/arm64 | 386/arm |
|---|---|---|
| pointer | 8 bytes | 4 bytes |
int/uint |
8 bytes | 4 bytes |
uintptr |
8 bytes | 4 bytes |
GC Pointer Types¶
These contain pointers and affect GC scan range:
*T(pointers)string(data pointer)[]T(slice header pointer)map[K]V(map header pointer)chan T(channel header pointer)func(...)(function pointer)interface{}/ named interfaces (two pointers: type + data)
Field Reorder Sort Order¶
Matches fieldalignment exactly:
- Zero-sized fields first
- Descending alignment
- Pointer-bearing before pointer-free (same alignment)
- Trailing non-pointer: ascending size then ascending name
- Trailing pointer: ascending size then ascending name
Adding New Features¶
- New LSP method: add handler in
internal/lsp/handler.go, register inserver.go'shandleRequestswitch - New analysis capability: extend
internal/analysis/— types, layout, analyzer - New VS Code feature: if LSP-providable, add to language server; otherwise add to
src/extension.ts - New setting: add to
package.json→contributes.configuration.properties
Pull Request Process¶
- Fork the repository
- Create a feature branch:
git checkout -b feat/my-feature - Make changes following code style
- Run
make preflight(vet → fmt → lint → test) - Validate against test Go files
- Submit a PR with clear description of what, why, and testing performed
PR Checklist¶
- [ ] Code follows style guidelines
- [ ]
make preflightpasses - [ ] Manual testing done in Extension Development Host
- [ ] Validated against
test_go_file.goandtest_go_edge-cases.go - [ ] No debug output left in production code
- [ ]
package.jsonversion unchanged (maintainer handles versions)
Zed Extension¶
An experimental Zed extension lives at editors/zed/. Install as a dev extension:
zed: install dev extension→ point toeditors/zed/gsa-lspmust be onPATH(make install)
The extension registers gsa-lsp as an additional language server for Go, running alongside gopls. See editors/zed/README.md.
Version and Release¶
Semver increment guide for PR authors:
- Patch (2.0.3 → 2.0.4): Bug fixes, doc updates
- Minor (2.0.3 → 2.1.0): New features, backward-compatible
- Major (2.0.3 → 3.0.0): Breaking changes
Building for Local Installation¶
Generates a .vsix file installable via VS Code's "Install from VSIX" option.
Questions?¶
Open an issue at https://github.com/padiazg/go-struct-analyzer/issues