You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

atomic.go 1.9KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package rule
  2. import (
  3. "go/ast"
  4. "go/token"
  5. "go/types"
  6. "github.com/mgechev/revive/lint"
  7. )
  8. // AtomicRule lints given else constructs.
  9. type AtomicRule struct{}
  10. // Apply applies the rule to given file.
  11. func (r *AtomicRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
  12. var failures []lint.Failure
  13. walker := atomic{
  14. pkgTypesInfo: file.Pkg.TypesInfo,
  15. onFailure: func(failure lint.Failure) {
  16. failures = append(failures, failure)
  17. },
  18. }
  19. ast.Walk(walker, file.AST)
  20. return failures
  21. }
  22. // Name returns the rule name.
  23. func (r *AtomicRule) Name() string {
  24. return "atomic"
  25. }
  26. type atomic struct {
  27. pkgTypesInfo *types.Info
  28. onFailure func(lint.Failure)
  29. }
  30. func (w atomic) Visit(node ast.Node) ast.Visitor {
  31. n, ok := node.(*ast.AssignStmt)
  32. if !ok {
  33. return w
  34. }
  35. if len(n.Lhs) != len(n.Rhs) {
  36. return nil // skip assignment sub-tree
  37. }
  38. if len(n.Lhs) == 1 && n.Tok == token.DEFINE {
  39. return nil // skip assignment sub-tree
  40. }
  41. for i, right := range n.Rhs {
  42. call, ok := right.(*ast.CallExpr)
  43. if !ok {
  44. continue
  45. }
  46. sel, ok := call.Fun.(*ast.SelectorExpr)
  47. if !ok {
  48. continue
  49. }
  50. pkgIdent, _ := sel.X.(*ast.Ident)
  51. if w.pkgTypesInfo != nil {
  52. pkgName, ok := w.pkgTypesInfo.Uses[pkgIdent].(*types.PkgName)
  53. if !ok || pkgName.Imported().Path() != "sync/atomic" {
  54. continue
  55. }
  56. }
  57. switch sel.Sel.Name {
  58. case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
  59. left := n.Lhs[i]
  60. if len(call.Args) != 2 {
  61. continue
  62. }
  63. arg := call.Args[0]
  64. broken := false
  65. if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
  66. broken = gofmt(left) == gofmt(uarg.X)
  67. } else if star, ok := left.(*ast.StarExpr); ok {
  68. broken = gofmt(star.X) == gofmt(arg)
  69. }
  70. if broken {
  71. w.onFailure(lint.Failure{
  72. Confidence: 1,
  73. Failure: "direct assignment to atomic value",
  74. Node: n,
  75. })
  76. }
  77. }
  78. }
  79. return w
  80. }