diff options
author | Teddy Wing | 2023-05-14 21:21:06 +0200 |
---|---|---|
committer | Teddy Wing | 2023-05-14 21:26:36 +0200 |
commit | 6d91d473f24d6825170e494852b26ffc748fe542 (patch) | |
tree | b4d5ec4ca1f1a46390407b0023eebfe6232ca2b2 | |
parent | 27b71d7c8fdedca306885d078be5a35a39669907 (diff) | |
download | gocapturedrefrace-6d91d473f24d6825170e494852b26ffc748fe542.tar.bz2 |
Find `go` statements using Go analyzer
Build a basic Go analyser that finds `go` statements.
Currently testing this with:
$ go run ./cmd/gocapturedrefrace ./testdata/
Using the following tutorials as a guide:
* https://arslan.io/2019/06/13/using-go-analysis-to-write-a-custom-linter/
* https://scribe.rip/codex/writing-custom-linter-in-go-54ef6f8080
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | cmd/gocapturedrefrace/main.go | 10 | ||||
-rw-r--r-- | go.mod | 10 | ||||
-rw-r--r-- | go.sum | 7 | ||||
-rw-r--r-- | gocapturedrefrace.go | 45 | ||||
-rw-r--r-- | testdata/simple.go | 9 |
6 files changed, 82 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd1a426 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/private/ diff --git a/cmd/gocapturedrefrace/main.go b/cmd/gocapturedrefrace/main.go new file mode 100644 index 0000000..d637a38 --- /dev/null +++ b/cmd/gocapturedrefrace/main.go @@ -0,0 +1,10 @@ +package main + +import ( + "git.teddywing.com/gocapturedrefrace" + "golang.org/x/tools/go/analysis/singlechecker" +) + +func main() { + singlechecker.Main(gocapturedrefrace.Analyzer) +} @@ -0,0 +1,10 @@ +module git.teddywing.com/gocapturedrefrace + +go 1.20 + +require golang.org/x/tools v0.9.1 + +require ( + golang.org/x/mod v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect +) @@ -0,0 +1,7 @@ +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= diff --git a/gocapturedrefrace.go b/gocapturedrefrace.go new file mode 100644 index 0000000..762473b --- /dev/null +++ b/gocapturedrefrace.go @@ -0,0 +1,45 @@ +package gocapturedrefrace + +import ( + "bytes" + "go/ast" + "go/printer" + + "golang.org/x/tools/go/analysis" +) + +var Analyzer = &analysis.Analyzer{ + Name: "gocapturedrefrace", + Doc: "reports captured references in goroutine closures", + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + for _, file := range pass.Files { + ast.Inspect( + file, + func(node ast.Node) bool { + goStmt, ok := node.(*ast.GoStmt) + if !ok { + return true + } + + var printedNode bytes.Buffer + err := printer.Fprint(&printedNode, pass.Fset, goStmt) + if err != nil { + panic(err) + } + + pass.Reportf( + goStmt.Pos(), + "go statement found %q", + printedNode, + ) + + return true + }, + ) + } + + return nil, nil +} diff --git a/testdata/simple.go b/testdata/simple.go new file mode 100644 index 0000000..496be52 --- /dev/null +++ b/testdata/simple.go @@ -0,0 +1,9 @@ +package main + +func main() { + capturedReference := 0 + + go func() { + capturedReference += 1 + }() +} |