diff options
author | Teddy Wing | 2023-05-18 04:52:21 +0200 |
---|---|---|
committer | Teddy Wing | 2023-05-18 04:52:21 +0200 |
commit | 75c1da0c3f0a1245e0b1a2775245d85a831eee47 (patch) | |
tree | 07802ac7d3996ec1585c30b5ceb14ca32d36d49c /gocapturedrefrace.go | |
parent | 3e2c455312e3558f6793b6f526c37820e8fe2afd (diff) | |
download | gocapturedrefrace-75c1da0c3f0a1245e0b1a2775245d85a831eee47.tar.bz2 |
Use `passes/inspect` to find `go` statements
I originally thought that I could save on the two additional
`ast.Inspect` calls in this file by using the `passes/inspect` library,
but it doesn't replace those calls. It seems to help more when you have
multiple analysers to run at once. Not sure how much it helps us here.
Diffstat (limited to 'gocapturedrefrace.go')
-rw-r--r-- | gocapturedrefrace.go | 76 |
1 files changed, 40 insertions, 36 deletions
diff --git a/gocapturedrefrace.go b/gocapturedrefrace.go index 1404f78..a3c1699 100644 --- a/gocapturedrefrace.go +++ b/gocapturedrefrace.go @@ -25,55 +25,59 @@ import ( "go/types" "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" ) var version = "0.0.1" var Analyzer = &analysis.Analyzer{ - Name: "gocapturedrefrace", - Doc: "reports captured references in goroutine closures", - Run: run, + Name: "gocapturedrefrace", + Doc: "reports captured references in goroutine closures", + Run: run, + Requires: []*analysis.Analyzer{inspect.Analyzer}, } func run(pass *analysis.Pass) (interface{}, error) { - // TODO: Since we're calling ast.Inspect a bunch of times, maybe it's worthwhile using passes/inspect now. - for _, file := range pass.Files { - ast.Inspect( - file, - func(node ast.Node) bool { - // Find `go` statements. - goStmt, ok := node.(*ast.GoStmt) - if !ok { - return true - } + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - // Look for a function literal after the `go` statement. - funcLit, ok := goStmt.Call.Fun.(*ast.FuncLit) - if !ok { - return true - } + nodeFilter := []ast.Node{ + (*ast.GoStmt)(nil), + } - // Inspect closure argument list. - for _, arg := range funcLit.Type.Params.List { - // Report reference arguments. - _, ok := arg.Type.(*ast.StarExpr) - if !ok { - continue - } - - pass.Reportf( - arg.Pos(), - "reference %s in goroutine closure", - arg.Names[0], - ) + inspect.Preorder( + nodeFilter, + func(node ast.Node) { + // Find `go` statements. + goStmt, ok := node.(*ast.GoStmt) + if !ok { + return + } + + // Look for a function literal after the `go` statement. + funcLit, ok := goStmt.Call.Fun.(*ast.FuncLit) + if !ok { + return + } + + // Inspect closure argument list. + for _, arg := range funcLit.Type.Params.List { + // Report reference arguments. + _, ok := arg.Type.(*ast.StarExpr) + if !ok { + continue } - checkClosure(pass, funcLit) + pass.Reportf( + arg.Pos(), + "reference %s in goroutine closure", + arg.Names[0], + ) + } - return true - }, - ) - } + checkClosure(pass, funcLit) + }, + ) return nil, nil } |