diff options
Diffstat (limited to 'contrib/linters.go')
-rw-r--r-- | contrib/linters.go | 69 |
1 files changed, 50 insertions, 19 deletions
diff --git a/contrib/linters.go b/contrib/linters.go index 7876cab6..41655a67 100644 --- a/contrib/linters.go +++ b/contrib/linters.go @@ -4,18 +4,36 @@ import ( "go/ast" "go/token" "go/types" + "reflect" "golang.org/x/tools/go/analysis" ) +type indirectCalls struct { + methods map[token.Pos]string + functions map[string]token.Pos +} + var PanicAnalyzer = &analysis.Analyzer{ - Name: "panic", - Doc: "finds goroutines that do not initialize the panic handler", - Run: runPanic, + Name: "panic", + Doc: "finds goroutines that do not initialize the panic handler", + Run: runPanic, + ResultType: reflect.TypeOf(&indirectCalls{}), +} + +var PanicIndirectAnalyzer = &analysis.Analyzer{ + Name: "panicindirect", + Doc: "finds functions called as goroutines that do not initialize the panic handler", + Run: runPanicIndirect, + Requires: []*analysis.Analyzer{PanicAnalyzer}, } func runPanic(pass *analysis.Pass) (interface{}, error) { - methods := make(map[token.Pos]string) + var calls indirectCalls + + calls.methods = make(map[token.Pos]string) + calls.functions = make(map[string]token.Pos) + for _, file := range pass.Files { ast.Inspect(file, func(n ast.Node) bool { g, ok := n.(*ast.GoStmt) @@ -38,11 +56,14 @@ func runPanic(pass *analysis.Pass) (interface{}, error) { if ok { f, ok := sel.Obj().(*types.Func) if ok { - methods[f.Pos()] = f.Name() + calls.methods[f.Pos()] = f.Name() } } case *ast.Ident: block = inlineFuncBody(e) + if block == nil { + calls.functions[e.Name] = e.NamePos + } } if block == nil { @@ -56,22 +77,28 @@ func runPanic(pass *analysis.Pass) (interface{}, error) { return true }) } + + return &calls, nil +} + +func runPanicIndirect(pass *analysis.Pass) (interface{}, error) { + calls := pass.ResultOf[PanicAnalyzer].(*indirectCalls) + for _, file := range pass.Files { - ast.Inspect(file, func(n ast.Node) bool { - f, ok := n.(*ast.FuncDecl) - if !ok { - return false - } - _, found := methods[f.Name.Pos()] - if !found { - return false - } - delete(methods, f.Name.Pos()) - if !isPanicHandlerInstall(f.Body.List[0]) { - pass.Report(panicDiag(f.Body.Pos())) + for _, decl := range file.Decls { + if f, ok := decl.(*ast.FuncDecl); ok { + if _, ok := calls.methods[f.Name.Pos()]; ok { + delete(calls.methods, f.Name.Pos()) + } else if _, ok := calls.functions[f.Name.Name]; ok { + delete(calls.functions, f.Name.Name) + } else { + continue + } + if !isPanicHandlerInstall(f.Body.List[0]) { + pass.Report(panicDiag(f.Body.Pos())) + } } - return false - }) + } } return nil, nil @@ -86,6 +113,9 @@ func panicDiag(pos token.Pos) analysis.Diagnostic { } func inlineFuncBody(s *ast.Ident) *ast.BlockStmt { + if s.Obj == nil || s.Obj.Decl == nil { + return nil + } d, ok := s.Obj.Decl.(*ast.AssignStmt) if !ok { return nil @@ -121,6 +151,7 @@ type analyzerPlugin struct{} func (*analyzerPlugin) GetAnalyzers() []*analysis.Analyzer { return []*analysis.Analyzer{ PanicAnalyzer, + PanicIndirectAnalyzer, } } |