1
2
3
4
5 package defers
6
7 import (
8 _ "embed"
9 "go/ast"
10
11 "golang.org/x/tools/go/analysis"
12 "golang.org/x/tools/go/analysis/passes/inspect"
13 "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
14 "golang.org/x/tools/go/ast/inspector"
15 "golang.org/x/tools/go/types/typeutil"
16 )
17
18
19 var doc string
20
21
22 var Analyzer = &analysis.Analyzer{
23 Name: "defers",
24 Requires: []*analysis.Analyzer{inspect.Analyzer},
25 URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/defers",
26 Doc: analysisutil.MustExtractDoc(doc, "defers"),
27 Run: run,
28 }
29
30 func run(pass *analysis.Pass) (interface{}, error) {
31 if !analysisutil.Imports(pass.Pkg, "time") {
32 return nil, nil
33 }
34
35 checkDeferCall := func(node ast.Node) bool {
36 switch v := node.(type) {
37 case *ast.CallExpr:
38 if analysisutil.IsFunctionNamed(typeutil.StaticCallee(pass.TypesInfo, v), "time", "Since") {
39 pass.Reportf(v.Pos(), "call to time.Since is not deferred")
40 }
41 case *ast.FuncLit:
42 return false
43 }
44 return true
45 }
46
47 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
48
49 nodeFilter := []ast.Node{
50 (*ast.DeferStmt)(nil),
51 }
52
53 inspect.Preorder(nodeFilter, func(n ast.Node) {
54 d := n.(*ast.DeferStmt)
55 ast.Inspect(d.Call, checkDeferCall)
56 })
57
58 return nil, nil
59 }
60
View as plain text