Home | History | Annotate | Download | only in vet
      1 // Copyright 2013 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package main
      6 
      7 import (
      8 	"go/ast"
      9 	"go/token"
     10 )
     11 
     12 func init() {
     13 	register("atomic",
     14 		"check for common mistaken usages of the sync/atomic package",
     15 		checkAtomicAssignment,
     16 		assignStmt)
     17 }
     18 
     19 // checkAtomicAssignment walks the assignment statement checking for common
     20 // mistaken usage of atomic package, such as: x = atomic.AddUint64(&x, 1)
     21 func checkAtomicAssignment(f *File, node ast.Node) {
     22 	n := node.(*ast.AssignStmt)
     23 	if len(n.Lhs) != len(n.Rhs) {
     24 		return
     25 	}
     26 
     27 	for i, right := range n.Rhs {
     28 		call, ok := right.(*ast.CallExpr)
     29 		if !ok {
     30 			continue
     31 		}
     32 		sel, ok := call.Fun.(*ast.SelectorExpr)
     33 		if !ok {
     34 			continue
     35 		}
     36 		pkg, ok := sel.X.(*ast.Ident)
     37 		if !ok || pkg.Name != "atomic" {
     38 			continue
     39 		}
     40 
     41 		switch sel.Sel.Name {
     42 		case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
     43 			f.checkAtomicAddAssignment(n.Lhs[i], call)
     44 		}
     45 	}
     46 }
     47 
     48 // checkAtomicAddAssignment walks the atomic.Add* method calls checking for assigning the return value
     49 // to the same variable being used in the operation
     50 func (f *File) checkAtomicAddAssignment(left ast.Expr, call *ast.CallExpr) {
     51 	if len(call.Args) != 2 {
     52 		return
     53 	}
     54 	arg := call.Args[0]
     55 	broken := false
     56 
     57 	if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
     58 		broken = f.gofmt(left) == f.gofmt(uarg.X)
     59 	} else if star, ok := left.(*ast.StarExpr); ok {
     60 		broken = f.gofmt(star.X) == f.gofmt(arg)
     61 	}
     62 
     63 	if broken {
     64 		f.Bad(left.Pos(), "direct assignment to atomic value")
     65 	}
     66 }
     67