github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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  	if f.pkg.types[x].Value != nil {
    45  		// Ignore shifts of constants.
    46  		// These are frequently used for bit-twiddling tricks
    47  		// like ^uint(0) >> 63 for 32/64 bit detection and compatibility.
    48  		return
    49  	}
    50  	v := f.pkg.types[y].Value
    51  	if v == nil {
    52  		return
    53  	}
    54  	amt, ok := constant.Int64Val(v)
    55  	if !ok {
    56  		return
    57  	}
    58  	t := f.pkg.types[x].Type
    59  	if t == nil {
    60  		return
    61  	}
    62  	b, ok := t.Underlying().(*types.Basic)
    63  	if !ok {
    64  		return
    65  	}
    66  	var size int64
    67  	var msg string
    68  	switch b.Kind() {
    69  	case types.Uint8, types.Int8:
    70  		size = 8
    71  	case types.Uint16, types.Int16:
    72  		size = 16
    73  	case types.Uint32, types.Int32:
    74  		size = 32
    75  	case types.Uint64, types.Int64:
    76  		size = 64
    77  	case types.Int, types.Uint, types.Uintptr:
    78  		// These types may be as small as 32 bits, but no smaller.
    79  		size = 32
    80  		msg = "might be "
    81  	default:
    82  		return
    83  	}
    84  	if amt >= size {
    85  		ident := f.gofmt(x)
    86  		f.Badf(node.Pos(), "%s %stoo small for shift of %d", ident, msg, amt)
    87  	}
    88  }