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 } 83