github.com/karrick/go@v0.0.0-20170817181416-d5b0ec858b37/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  	if f.dead[node] {
    27  		// Skip shift checks on unreachable nodes.
    28  		return
    29  	}
    30  
    31  	switch node := node.(type) {
    32  	case *ast.BinaryExpr:
    33  		if node.Op == token.SHL || node.Op == token.SHR {
    34  			checkLongShift(f, node, node.X, node.Y)
    35  		}
    36  	case *ast.AssignStmt:
    37  		if len(node.Lhs) != 1 || len(node.Rhs) != 1 {
    38  			return
    39  		}
    40  		if node.Tok == token.SHL_ASSIGN || node.Tok == token.SHR_ASSIGN {
    41  			checkLongShift(f, node, node.Lhs[0], node.Rhs[0])
    42  		}
    43  	}
    44  }
    45  
    46  // checkLongShift checks if shift or shift-assign operations shift by more than
    47  // the length of the underlying variable.
    48  func checkLongShift(f *File, node ast.Node, x, y ast.Expr) {
    49  	if f.pkg.types[x].Value != nil {
    50  		// Ignore shifts of constants.
    51  		// These are frequently used for bit-twiddling tricks
    52  		// like ^uint(0) >> 63 for 32/64 bit detection and compatibility.
    53  		return
    54  	}
    55  
    56  	v := f.pkg.types[y].Value
    57  	if v == nil {
    58  		return
    59  	}
    60  	amt, ok := constant.Int64Val(v)
    61  	if !ok {
    62  		return
    63  	}
    64  	t := f.pkg.types[x].Type
    65  	if t == nil {
    66  		return
    67  	}
    68  	b, ok := t.Underlying().(*types.Basic)
    69  	if !ok {
    70  		return
    71  	}
    72  	var size int64
    73  	switch b.Kind() {
    74  	case types.Uint8, types.Int8:
    75  		size = 8
    76  	case types.Uint16, types.Int16:
    77  		size = 16
    78  	case types.Uint32, types.Int32:
    79  		size = 32
    80  	case types.Uint64, types.Int64:
    81  		size = 64
    82  	case types.Int, types.Uint:
    83  		size = uintBitSize
    84  	case types.Uintptr:
    85  		size = uintptrBitSize
    86  	default:
    87  		return
    88  	}
    89  	if amt >= size {
    90  		ident := f.gofmt(x)
    91  		f.Badf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt)
    92  	}
    93  }
    94  
    95  var (
    96  	uintBitSize    = 8 * archSizes.Sizeof(types.Typ[types.Uint])
    97  	uintptrBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uintptr])
    98  )