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