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 )