github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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  
    51  	v := f.pkg.types[y].Value
    52  	if v == nil {
    53  		return
    54  	}
    55  	amt, ok := constant.Int64Val(v)
    56  	if !ok {
    57  		return
    58  	}
    59  	t := f.pkg.types[x].Type
    60  	if t == nil {
    61  		return
    62  	}
    63  	b, ok := t.Underlying().(*types.Basic)
    64  	if !ok {
    65  		return
    66  	}
    67  	var size int64
    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:
    78  		size = uintBitSize
    79  	case types.Uintptr:
    80  		size = uintptrBitSize
    81  	default:
    82  		return
    83  	}
    84  	if amt >= size {
    85  		ident := f.gofmt(x)
    86  		f.Badf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt)
    87  	}
    88  }
    89  
    90  var (
    91  	uintBitSize    = 8 * archSizes.Sizeof(types.Typ[types.Uint])
    92  	uintptrBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uintptr])
    93  )