GoPLS Viewer

Home|gopls/go/analysis/passes/shift/shift.go
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// Package shift defines an Analyzer that checks for shifts that exceed
6// the width of an integer.
7package shift
8
9// TODO(adonovan): integrate with ctrflow (CFG-based) dead code analysis. May
10// have impedance mismatch due to its (non-)treatment of constant
11// expressions (such as runtime.GOARCH=="386").
12
13import (
14    "go/ast"
15    "go/constant"
16    "go/token"
17    "go/types"
18    "math"
19
20    "golang.org/x/tools/go/analysis"
21    "golang.org/x/tools/go/analysis/passes/inspect"
22    "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
23    "golang.org/x/tools/go/ast/inspector"
24    "golang.org/x/tools/internal/typeparams"
25)
26
27const Doc = "check for shifts that equal or exceed the width of the integer"
28
29var Analyzer = &analysis.Analyzer{
30    Name:     "shift",
31    Doc:      Doc,
32    Requires: []*analysis.Analyzer{inspect.Analyzer},
33    Run:      run,
34}
35
36func run(pass *analysis.Pass) (interface{}, error) {
37    inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
38
39    // Do a complete pass to compute dead nodes.
40    dead := make(map[ast.Node]bool)
41    nodeFilter := []ast.Node{
42        (*ast.IfStmt)(nil),
43        (*ast.SwitchStmt)(nil),
44    }
45    inspect.Preorder(nodeFilter, func(n ast.Node) {
46        // TODO(adonovan): move updateDead into this file.
47        updateDead(pass.TypesInfodeadn)
48    })
49
50    nodeFilter = []ast.Node{
51        (*ast.AssignStmt)(nil),
52        (*ast.BinaryExpr)(nil),
53    }
54    inspect.Preorder(nodeFilter, func(node ast.Node) {
55        if dead[node] {
56            // Skip shift checks on unreachable nodes.
57            return
58        }
59
60        switch node := node.(type) {
61        case *ast.BinaryExpr:
62            if node.Op == token.SHL || node.Op == token.SHR {
63                checkLongShift(passnodenode.Xnode.Y)
64            }
65        case *ast.AssignStmt:
66            if len(node.Lhs) != 1 || len(node.Rhs) != 1 {
67                return
68            }
69            if node.Tok == token.SHL_ASSIGN || node.Tok == token.SHR_ASSIGN {
70                checkLongShift(passnodenode.Lhs[0], node.Rhs[0])
71            }
72        }
73    })
74    return nilnil
75}
76
77// checkLongShift checks if shift or shift-assign operations shift by more than
78// the length of the underlying variable.
79func checkLongShift(pass *analysis.Passnode ast.Nodexy ast.Expr) {
80    if pass.TypesInfo.Types[x].Value != nil {
81        // Ignore shifts of constants.
82        // These are frequently used for bit-twiddling tricks
83        // like ^uint(0) >> 63 for 32/64 bit detection and compatibility.
84        return
85    }
86
87    v := pass.TypesInfo.Types[y].Value
88    if v == nil {
89        return
90    }
91    amtok := constant.Int64Val(v)
92    if !ok {
93        return
94    }
95    t := pass.TypesInfo.Types[x].Type
96    if t == nil {
97        return
98    }
99    var structuralTypes []types.Type
100    switch t := t.(type) {
101    case *typeparams.TypeParam:
102        termserr := typeparams.StructuralTerms(t)
103        if err != nil {
104            return // invalid type
105        }
106        for _term := range terms {
107            structuralTypes = append(structuralTypesterm.Type())
108        }
109    default:
110        structuralTypes = append(structuralTypest)
111    }
112    sizes := make(map[int64]struct{})
113    for _t := range structuralTypes {
114        size := 8 * pass.TypesSizes.Sizeof(t)
115        sizes[size] = struct{}{}
116    }
117    minSize := int64(math.MaxInt64)
118    for size := range sizes {
119        if size < minSize {
120            minSize = size
121        }
122    }
123    if amt >= minSize {
124        ident := analysisutil.Format(pass.Fsetx)
125        qualifier := ""
126        if len(sizes) > 1 {
127            qualifier = "may be "
128        }
129        pass.ReportRangef(node"%s (%s%d bits) too small for shift of %d"identqualifierminSizeamt)
130    }
131}
132
MembersX
checkLongShift.node
checkLongShift.RangeStmt_2986.t
checkLongShift.RangeStmt_3126.size
run.pass
checkLongShift.minSize
checkLongShift.v
checkLongShift.BlockStmt.ident
analysisutil
run.nodeFilter
checkLongShift.amt
checkLongShift.ok
checkLongShift.structuralTypes
checkLongShift.BlockStmt.terms
checkLongShift.sizes
analysis
math
inspect
typeparams
run
checkLongShift.x
checkLongShift.y
checkLongShift.t
token
checkLongShift.BlockStmt.qualifier
checkLongShift.BlockStmt.err
checkLongShift.pass
inspector
run.dead
checkLongShift
checkLongShift.BlockStmt.RangeStmt_2799.term
Doc
Members
X