aboutsummaryrefslogtreecommitdiffstats
path: root/gocapturedrefrace.go
diff options
context:
space:
mode:
authorTeddy Wing2023-05-18 04:52:21 +0200
committerTeddy Wing2023-05-18 04:52:21 +0200
commit75c1da0c3f0a1245e0b1a2775245d85a831eee47 (patch)
tree07802ac7d3996ec1585c30b5ceb14ca32d36d49c /gocapturedrefrace.go
parent3e2c455312e3558f6793b6f526c37820e8fe2afd (diff)
downloadgocapturedrefrace-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.go76
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
}