aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeddy Wing2023-05-18 21:31:58 +0200
committerTeddy Wing2023-05-18 21:31:58 +0200
commit5fd2ef0221f0737127f524554a872e118b178416 (patch)
treef7ed26650c98c83f93846177f8da22093bde7144
parentb8fde7555016618d1a9a4625c24af537e09de103 (diff)
downloadgodefererr-5fd2ef0221f0737127f524554a872e118b178416.tar.bz2
Ideas for an analyser for returning errors from defer
Still working out how to traverse the AST to be able to see the objects I need.
-rw-r--r--defererr.go61
-rw-r--r--defererr_test.go14
-rw-r--r--go.mod10
-rw-r--r--go.sum7
-rw-r--r--testdata/signature.go18
5 files changed, 110 insertions, 0 deletions
diff --git a/defererr.go b/defererr.go
new file mode 100644
index 0000000..d512cbf
--- /dev/null
+++ b/defererr.go
@@ -0,0 +1,61 @@
+// TODO: doc
+package defererr
+
+import (
+ "fmt"
+ "go/ast"
+
+ "golang.org/x/tools/go/analysis"
+)
+
+var Analyzer = &analysis.Analyzer{
+ Name: "defererr",
+ Doc: "reports issues returning errors from defer",
+ Run: run,
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ // TODO: Find defer closure
+ // Does it set error defined in outer scope?
+ // Does outer scope declare error variable in signature?
+ // Is err variable returned after closure?
+
+ for _, file := range pass.Files {
+ ast.Inspect(
+ file,
+ func(node ast.Node) bool {
+ deferStmt, ok := node.(*ast.DeferStmt)
+ if !ok {
+ return true
+ }
+
+ // Look for a function literal after the `defer` statement.
+ funcLit, ok := deferStmt.Call.Fun.(*ast.FuncLit)
+ if !ok {
+ return true
+ }
+
+ funcScope := pass.TypesInfo.Scopes[funcLit.Type]
+
+ // Try to find the function where the defer is defined. Note, defer can be defined in an inner block.
+ funcType, ok := funcScope.Parent().(*ast.FuncType)
+ if !ok {
+ return true
+ }
+ fmt.Printf("func: %#v\n", funcType)
+
+ if funcLit.Type.Results == nil {
+ return true
+ }
+
+ for _, returnVal := range funcLit.Type.Results.List {
+ fmt.Printf("returnVal: %#v\n", returnVal)
+ }
+
+ return true
+ },
+ )
+ }
+
+ return nil, nil
+}
diff --git a/defererr_test.go b/defererr_test.go
new file mode 100644
index 0000000..a94b3b9
--- /dev/null
+++ b/defererr_test.go
@@ -0,0 +1,14 @@
+package defererr_test
+
+import (
+ "testing"
+
+ "golang.org/x/tools/go/analysis/analysistest"
+ "gopkg.teddywing.com/defererr"
+)
+
+func Test(t *testing.T) {
+ testdata := analysistest.TestData()
+
+ analysistest.Run(t, testdata, defererr.Analyzer, ".")
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..61d0b34
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,10 @@
+module gopkg.teddywing.com/defererr
+
+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
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..cf10794
--- /dev/null
+++ b/go.sum
@@ -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/testdata/signature.go b/testdata/signature.go
new file mode 100644
index 0000000..17cfd0b
--- /dev/null
+++ b/testdata/signature.go
@@ -0,0 +1,18 @@
+package main
+
+import "errors"
+
+func declareErrInSignature() error { // want "return signature should be '(err error)'"
+ var err error // Should use variable declared in signature
+
+ err = nil
+ if err != nil {
+ return err
+ }
+
+ defer func() {
+ err = errors.New("defer error")
+ }()
+
+ return nil // want "does not return 'err'"
+}