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