A comprehensive AST-grep linting rule set for detecting common Go programming mistakes and anti-patterns. This project provides static analysis rules that catch problematic code before it reaches production.
This project implements 11 detection rules for Go mistakes using ast-grep, a powerful AST-based code search and linting tool. Each rule is defined as a YAML configuration file that describes a pattern to match, and includes comprehensive test cases to verify correctness.
AST-grep is a code pattern matcher that understands the Abstract Syntax Tree (AST) of your code. Instead of simple regex, it matches structural patterns.
Example rule (01-loop-var-capture.yml):
id: loop-var-capture
language: go
message: "Loop variable captured by goroutine; pass it as an argument or shadow it."
severity: warning
rule:
pattern: |
for $I := range $XS {
go func() { $$_ }()
}This catches the classic Go mistake of capturing loop variables in goroutines without passing them as arguments.
ast-grep-go/
├── rules/ # AST-grep rule definitions
│ ├── 01-loop-var-capture.yml
│ ├── 02-defer-in-loop.yml
│ └── ... (9 more rules)
├── rules_test/ # Test cases for each rule
│ ├── 01-loop-var-capture_test.go
│ ├── 02-defer-in-loop_test.go
│ └── ... (9 more test files)
├── ast-grep.yml # Main configuration (registers all rules)
├── Makefile # Commands for testing and linting
├── AGENTS.md # Developer instructions
└── README.md # This file
Install ast-grep:
npm install -g @ast-grep/cli
# or
brew install ast-grep # macOSVerify all rules detect violations correctly:
make testThis scans each rule's test file and ensures:
- All
BadUsage_*functions trigger the rule warning - All
GoodUsage_*functions do NOT trigger any warnings
Scan Go files for violations:
ast-grep scan your-file.go -r rules/
# or scan entire directory
ast-grep scan ./src -r rules/Output shows file, line, and rule ID for each violation:
rules_test/01-loop-var-capture_test.go:8:6: loop-var-capture
8 │ for i := range items {
9 │ go func() {
| ^^^^^^^^^^^^^^
10 │ }()
11 │ }
Pattern ID: loop-var-capture
Message: Loop variable captured by goroutine; pass it as an argument or shadow it.
# Scan files against rules
ast-grep scan <path> -r <rules-directory>
# Run a single rule
ast-grep scan file.go -r rules/01-loop-var-capture.yml
# Run with pattern directly
ast-grep run --pattern "for range" file.go
# Help
ast-grep --helpAST-grep patterns use wildcards to match code structure:
| Pattern | Meaning |
|---|---|
$VAR |
Named capture (single token) |
$$_ |
Match any single statement or expression |
$$ |
Match any multi-statement sequence |
Example:
# Matches: for X := range Y { ... any code ... go func() { ... any code ... }() ... }
for $I := range $XS {
$$_
go func() { $$_ }()
$$_
}This project uses Model Context Protocol (MCP) via Amp, enabling AI-assisted code analysis and rule creation.
When working in Amp with this codebase:
-
ast-grep MCP - Configured globally in
~/.config/amp/settings.jsonmcp__ast_grep__find_code- Find code matching patternsmcp__ast_grep__test_match_code_rule- Test rules before deploymentmcp__ast_grep__dump_syntax_tree- Debug AST structure
-
Documentation Search - Query project docs and AST-grep documentation
-
Free Mode - Free usage supported by advertisements (execute mode requires paid credits)
Test a new rule pattern:
mcp__ast_grep__test_match_code_rule:
code: "for i := range items { go func() { print(i) }() }"
yaml: "id: test-rule\nlanguage: go\nrule:\n pattern: for $_ := range $_ { go func() { $$_ }() }"
Find code matching a pattern:
mcp__ast_grep__find_code(pattern="defer $$_", project_folder="/path/to/code")
id: rule-id
language: go
message: "Clear description of what's wrong"
severity: warning
rule:
pattern: |
your_pattern_herepackage main
import "testing"
// BadUsage_Case1 should trigger the rule
func BadUsage_Case1(t *testing.T) {
// Code that SHOULD trigger the rule
// BUG: explanatory comment
}
// GoodUsage_Case1 should NOT trigger the rule
func GoodUsage_Case1(t *testing.T) {
// Code that should NOT trigger the rule
// OK: no issue here
}rules:
- ./rules/NN-rule-name.ymlmake test- Design the pattern - Understand what code structure to detect
- Test the pattern - Use
ast-grep run --patternto verify it matches - Create rule file - Write YAML rule with clear message
- Create test cases - Write
BadUsage_*andGoodUsage_*functions - Register rule - Add to
ast-grep.yml - Validate - Run
make testto ensure all cases work - Lint - Run
make linton real code to verify
Use ast-grep's debug output:
ast-grep run --pattern "your_pattern" test-file.goUnderstand what the AST looks like for your code:
ast-grep run --pattern "for _ := range _ { $$_ }" file.go --debug-astOr use the MCP tool in Amp:
mcp__ast_grep__dump_syntax_tree(code="your code", language="go", format="cst")
- Pattern-driven: All detection rules use AST patterns, not regex
- Tested: Every rule has comprehensive positive and negative test cases
- Consistent: All rules use
severity: warningfor uniform output - Documented: Each rule has a clear, actionable message
- Maintainable: YAML-based rules are readable and easy to update