Home | History | Annotate | Download | only in vet
      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