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 	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 	v := f.pkg.types[y].Value
     51 	if v == nil {
     52 		return
     53 	}
     54 	amt, ok := constant.Int64Val(v)
     55 	if !ok {
     56 		return
     57 	}
     58 	t := f.pkg.types[x].Type
     59 	if t == nil {
     60 		return
     61 	}
     62 	b, ok := t.Underlying().(*types.Basic)
     63 	if !ok {
     64 		return
     65 	}
     66 	var size int64
     67 	var msg string
     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, types.Uintptr:
     78 		// These types may be as small as 32 bits, but no smaller.
     79 		size = 32
     80 		msg = "might be "
     81 	default:
     82 		return
     83 	}
     84 	if amt >= size {
     85 		ident := f.gofmt(x)
     86 		f.Badf(node.Pos(), "%s %stoo small for shift of %d", ident, msg, amt)
     87 	}
     88 }
     89