...
1
2
3
4
5 package atomic
6
7 import (
8 _ "embed"
9 "go/ast"
10 "go/token"
11
12 "golang.org/x/tools/go/analysis"
13 "golang.org/x/tools/go/analysis/passes/inspect"
14 "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
15 "golang.org/x/tools/go/ast/inspector"
16 "golang.org/x/tools/go/types/typeutil"
17 )
18
19
20 var doc string
21
22 var Analyzer = &analysis.Analyzer{
23 Name: "atomic",
24 Doc: analysisutil.MustExtractDoc(doc, "atomic"),
25 URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomic",
26 Requires: []*analysis.Analyzer{inspect.Analyzer},
27 RunDespiteErrors: true,
28 Run: run,
29 }
30
31 func run(pass *analysis.Pass) (interface{}, error) {
32 if !analysisutil.Imports(pass.Pkg, "sync/atomic") {
33 return nil, nil
34 }
35
36 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
37
38 nodeFilter := []ast.Node{
39 (*ast.AssignStmt)(nil),
40 }
41 inspect.Preorder(nodeFilter, func(node ast.Node) {
42 n := node.(*ast.AssignStmt)
43 if len(n.Lhs) != len(n.Rhs) {
44 return
45 }
46 if len(n.Lhs) == 1 && n.Tok == token.DEFINE {
47 return
48 }
49
50 for i, right := range n.Rhs {
51 call, ok := right.(*ast.CallExpr)
52 if !ok {
53 continue
54 }
55 fn := typeutil.StaticCallee(pass.TypesInfo, call)
56 if analysisutil.IsFunctionNamed(fn, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") {
57 checkAtomicAddAssignment(pass, n.Lhs[i], call)
58 }
59 }
60 })
61 return nil, nil
62 }
63
64
65
66
67 func checkAtomicAddAssignment(pass *analysis.Pass, left ast.Expr, call *ast.CallExpr) {
68 if len(call.Args) != 2 {
69 return
70 }
71 arg := call.Args[0]
72 broken := false
73
74 gofmt := func(e ast.Expr) string { return analysisutil.Format(pass.Fset, e) }
75
76 if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
77 broken = gofmt(left) == gofmt(uarg.X)
78 } else if star, ok := left.(*ast.StarExpr); ok {
79 broken = gofmt(star.X) == gofmt(arg)
80 }
81
82 if broken {
83 pass.ReportRangef(left, "direct assignment to atomic value")
84 }
85 }
86
View as plain text