diff options
-rw-r--r-- | defererr.go | 61 | ||||
-rw-r--r-- | defererr_test.go | 14 | ||||
-rw-r--r-- | go.mod | 10 | ||||
-rw-r--r-- | go.sum | 7 | ||||
-rw-r--r-- | testdata/signature.go | 18 |
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, ".") +} @@ -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 +) @@ -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'" +} |