aboutsummaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/linters.go69
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,
}
}