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