# go/analysis Framework

The `golang.org/x/tools/go/analysis` package is Go's standard framework for writing static analyzers. Every analyzer built with it can run standalone, integrate with `go vet`, or plug into golangci-lint.

## Structure

An analyzer is a struct with:

```go
var Analyzer = &analysis.Analyzer{
    Name:     "mycheck",
    Doc:      "checks for X",
    Requires: []*analysis.Analyzer{inspect.Analyzer},
    Run:      run,
}
```

The `Requires` field declares dependencies on other analyzers. The `inspect.Analyzer` is almost always required — it provides optimized AST traversal.

The `Run` function receives an `analysis.Pass` containing:
- `Fset` — file set for position information
- `Files` — parsed AST of the package
- `TypesInfo` — type checker results
- `ResultOf` — results from required analyzers
- `Report` — function to emit diagnostics

## AST walking

Rather than walking every node, use the inspector from `inspect.Analyzer`:

```go
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{(*ast.CallExpr)(nil)}
inspect.Preorder(nodeFilter, func(n ast.Node) {
    call := n.(*ast.CallExpr)
    // analyze the call
})
```

The filter makes traversal efficient — you only visit node types you care about.

## Type information

The `pass.TypesInfo` field gives access to Go's type checker results:

- `TypesInfo.Types[expr]` — type of any expression
- `TypesInfo.Uses[ident]` — what a name refers to
- `TypesInfo.Defs[ident]` — what a name defines
- `TypesInfo.ObjectOf(ident)` — the `types.Object` for an identifier

The `types.Object` is key for tracking variables. Two identifiers pointing to the same variable share the same object, so pointer equality works even across shadowing.

## Testing

The `analysistest` package makes testing straightforward:

```go
func TestMyCheck(t *testing.T) {
    testdata := analysistest.TestData()
    analysistest.Run(t, testdata, mycheck.Analyzer, "mypackage")
}
```

Test files use `// want` comments for expected diagnostics:

```go
x := badThing() // want "badThing is deprecated"
```

## Running

Standalone:
```go
func main() {
    singlechecker.Main(mycheck.Analyzer)
}
```

With go vet (requires registration in the Go toolchain).

With golangci-lint: add to `.golangci.yml` under `linters-settings`.

## Examples

- [[transactioncheck]] — detects database operations leaking outside transactions
- `errcheck` — detects unchecked errors
- `staticcheck` — comprehensive static analysis suite
- `nilness` — detects redundant nil checks and guaranteed nil dereferences
