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