github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/vet/shift.go (about)

     1  // Copyright 2014 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  /*
     6  This file contains the code to check for suspicious shifts.
     7  */
     8  
     9  package main
    10  
    11  import (
    12  	"go/ast"
    13  	"go/constant"
    14  	"go/token"
    15  	"go/types"
    16  )
    17  
    18  func init() {
    19  	register("shift",
    20  		"check for useless shifts",
    21  		checkShift,
    22  		binaryExpr, assignStmt)
    23  }
    24  
    25  func checkShift(f *File, node ast.Node) {
    26  	switch node := node.(type) {
    27  	case *ast.BinaryExpr:
    28  		if node.Op == token.SHL || node.Op == token.SHR {
    29  			checkLongShift(f, node, node.X, node.Y)
    30  		}
    31  	case *ast.AssignStmt:
    32  		if len(node.Lhs) != 1 || len(node.Rhs) != 1 {
    33  			return
    34  		}
    35  		if node.Tok == token.SHL_ASSIGN || node.Tok == token.SHR_ASSIGN {
    36  			checkLongShift(f, node, node.Lhs[0], node.Rhs[0])
    37  		}
    38  	}
    39  }
    40  
    41  // checkLongShift checks if shift or shift-assign operations shift by more than
    42  // the length of the underlying variable.
    43  func checkLongShift(f *File, node ast.Node, x, y ast.Expr) {
    44  	v := f.pkg.types[y].Value
    45  	if v == nil {
    46  		return
    47  	}
    48  	amt, ok := constant.Int64Val(v)
    49  	if !ok {
    50  		return
    51  	}
    52  	t := f.pkg.types[x].Type
    53  	if t == nil {
    54  		return
    55  	}
    56  	b, ok := t.Underlying().(*types.Basic)
    57  	if !ok {
    58  		return
    59  	}
    60  	var size int64
    61  	var msg string
    62  	switch b.Kind() {
    63  	case types.Uint8, types.Int8:
    64  		size = 8
    65  	case types.Uint16, types.Int16:
    66  		size = 16
    67  	case types.Uint32, types.Int32:
    68  		size = 32
    69  	case types.Uint64, types.Int64:
    70  		size = 64
    71  	case types.Int, types.Uint, types.Uintptr:
    72  		// These types may be as small as 32 bits, but no smaller.
    73  		size = 32
    74  		msg = "might be "
    75  	default:
    76  		return
    77  	}
    78  	if amt >= size {
    79  		ident := f.gofmt(x)
    80  		f.Badf(node.Pos(), "%s %stoo small for shift of %d", ident, msg, amt)
    81  	}
    82  }