diff options
author | Teddy Wing | 2023-05-21 21:12:19 +0200 |
---|---|---|
committer | Teddy Wing | 2023-05-21 21:12:19 +0200 |
commit | 5637c27b828e63fa459d3b124400bc135d1c95df (patch) | |
tree | 4db3e32ffa2a65d2416a2b1ebd4958eead9f8987 | |
parent | 63a5452af97b6173fb17f754ce7ca3bce8e9729d (diff) | |
download | godefererr-5637c27b828e63fa459d3b124400bc135d1c95df.tar.bz2 |
Check whether returned name matches defer error name
Ensure the name of the returned error variable matches the name of the
error variable assigned in the `defer` statement.
-rw-r--r-- | defererr.go | 39 | ||||
-rw-r--r-- | testdata/signature.go | 15 |
2 files changed, 50 insertions, 4 deletions
diff --git a/defererr.go b/defererr.go index 4d1ba6b..0305dd8 100644 --- a/defererr.go +++ b/defererr.go @@ -33,6 +33,7 @@ func run(pass *analysis.Pass) (interface{}, error) { type functionState struct { firstErrorDeferEndPos token.Pos + deferErrorVar *ast.Ident } func newFunctionState() *functionState { @@ -176,8 +177,8 @@ func checkFunctions(pass *analysis.Pass, node ast.Node) { // TODO: Get returnStmt.Results[error index from function result signature] // If not variable and name not [error variable name from defer], report diagnostic - returnError := returnStmt.Results[errorReturnIndex] - t := pass.TypesInfo.Types[returnError] + returnErrorExpr := returnStmt.Results[errorReturnIndex] + t := pass.TypesInfo.Types[returnErrorExpr] fmt.Printf("returnStmt value type: %#v\n", t) fmt.Printf("returnStmt type type: %#v\n", t.Type) @@ -188,8 +189,34 @@ func checkFunctions(pass *analysis.Pass, node ast.Node) { return true } - fmt.Printf("returnError: %#v\n", returnError) - if returnError.Name == x { + // Or, we want to compare with the error declared in the function signature. + fmt.Printf("returnError: %#v\n", returnErrorExpr) + + returnErrorIdent, ok := returnErrorExpr.(*ast.Ident) + if !ok { + return true + } + + if returnErrorIdent.Name == fState.deferErrorVar.Name { + fmt.Printf( + "names: return:%#v : defer:%#v\n", + returnErrorIdent.Name, + fState.deferErrorVar.Name, + ) + } + + if returnErrorIdent.Name != fState.deferErrorVar.Name { + fmt.Printf( + "names: return:%#v : defer:%#v\n", + returnErrorIdent.Name, + fState.deferErrorVar.Name, + ) + + pass.Reportf( + returnErrorIdent.Pos(), + "does not return '%s'", + fState.deferErrorVar, + ) } return true @@ -289,6 +316,10 @@ func checkErrorAssignedInDefer( } } + if len(errorReturnField.Names) > 0 { + fState.deferErrorVar = errorReturnField.Names[0] + } + // Maybe don't report the error if it was declared in the closure using a GenDecl? -> We already don't. Should test for these things. if !isErrorNameInReturnSignature { diff --git a/testdata/signature.go b/testdata/signature.go index c839934..a87501e 100644 --- a/testdata/signature.go +++ b/testdata/signature.go @@ -30,6 +30,21 @@ func doesDeclareErrInSignature() (err error) { return nil // want "does not return 'err'" } +func returnsOtherVariable() (err error) { + err = nil + if err != nil { + return err + } + + defer func() { + err = errors.New("defer error") + }() + + err2 := errors.New("returned error") + + return err2 // want "does not return 'err'" +} + func good() (err error) { err = nil if err != nil { |