diff --git a/analyzer/analyzer.go b/analyzer/analyzer.go index fbac199..465cce2 100644 --- a/analyzer/analyzer.go +++ b/analyzer/analyzer.go @@ -22,18 +22,27 @@ func run(pass *analysis.Pass) (interface{}, error) { // only filter function defintions nodeFilter := []ast.Node{ (*ast.FuncDecl)(nil), + (*ast.FuncLit)(nil), } inspector.Preorder(nodeFilter, func(node ast.Node) { - funcDecl := node.(*ast.FuncDecl) + var funcResults *ast.FieldList + + switch n := node.(type) { + case *ast.FuncLit: + funcResults = n.Type.Results + case *ast.FuncDecl: + funcResults = n.Type.Results + default: + return + } - results := funcDecl.Type.Results // no return values - if results == nil { + if funcResults == nil { return } - resultsList := results.List + resultsList := funcResults.List for _, p := range resultsList { if len(p.Names) == 0 { @@ -42,7 +51,7 @@ func run(pass *analysis.Pass) (interface{}, error) { } for _, n := range p.Names { - pass.Reportf(node.Pos(), "named return %s (%s) found in function %s", n.Name, types.ExprString(p.Type), funcDecl.Name.Name) + pass.Reportf(node.Pos(), "named return %q with type %q found", n.Name, types.ExprString(p.Type)) } } }) diff --git a/testdata/src/p/p.go b/testdata/src/p/p.go index 8b6e582..4a3006a 100644 --- a/testdata/src/p/p.go +++ b/testdata/src/p/p.go @@ -1,5 +1,7 @@ package main +import "fmt" + type asdf struct { test string } @@ -8,14 +10,84 @@ func noParams() { return } -func argl(i string, a, b int) (ret1 string, ret2 interface{}, ret3, ret4 int, ret5 asdf) { // want "named return ret1" "named return ret2" "named return ret3" "named return ret4" "named return ret5" - return "", nil, 1, 2, asdf{} +var c = func() { + return +} + +var d = func() error { + return nil +} + +var e = func() (err error) { // want `named return "err" with type "error" found` + err = nil + return +} + +var ( + f = func() { + return + } + + g = func() error { + return nil + } + + h = func() (err error) { // want `named return "err" with type "error" found` + err = nil + return + } +) + +// this should not match as the implementation does not need named parameters (see below) +type funcDefintion func(arg1, arg2 interface{}) (num int, err error) + +func funcDefintionImpl(arg1, arg2 interface{}) (int, error) { + return 0, nil +} + +func funcDefintionImpl2(arg1, arg2 interface{}) (num int, err error) { // want `named return "num" with type "int" found` `named return "err" with type "error" found` + return 0, nil +} + +var funcVar = func() (msg string) { // want `named return "msg" with type "string" found` + msg = "c" + return msg +} + +func test() { + a := funcVar() + _ = a + + var function funcDefintion + function = funcDefintionImpl + i, err := function("", "") + _ = i + _ = err + function = funcDefintionImpl2 + i, err = function("", "") + _ = i + _ = err } func good(i string) string { return i } +func bad(i string, a, b int) (ret1 string, ret2 interface{}, ret3, ret4 int, ret5 asdf) { // want `named return "ret1" with type "string" found` `named return "ret2" with type "interface{}" found` `named return "ret3" with type "int" found` `named return "ret4" with type "int" found` `named return "ret5" with type "asdf" found` + x := "dummy" + return fmt.Sprintf("%s", x), nil, 1, 2, asdf{} +} + +func bad2() (msg string, err error) { // want `named return "msg" with type "string" found` `named return "err" with type "error" found` + msg = "" + err = nil + return +} + func myLog(format string, args ...interface{}) { return } + +type obj struct{} + +func (o *obj) func1() (err error) { return nil } // want `named return "err" with type "error" found`