GoPLS Viewer

Home|gopls/go/analysis/passes/shift/dead.go
1// Copyright 2017 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
5package shift
6
7// Simplified dead code detector.
8// Used for skipping shift checks on unreachable arch-specific code.
9
10import (
11    "go/ast"
12    "go/constant"
13    "go/types"
14)
15
16// updateDead puts unreachable "if" and "case" nodes into dead.
17func updateDead(info *types.Infodead map[ast.Node]boolnode ast.Node) {
18    if dead[node] {
19        // The node is already marked as dead.
20        return
21    }
22
23    // setDead marks the node and all the children as dead.
24    setDead := func(n ast.Node) {
25        ast.Inspect(n, func(node ast.Nodebool {
26            if node != nil {
27                dead[node] = true
28            }
29            return true
30        })
31    }
32
33    switch stmt := node.(type) {
34    case *ast.IfStmt:
35        // "if" branch is dead if its condition evaluates
36        // to constant false.
37        v := info.Types[stmt.Cond].Value
38        if v == nil {
39            return
40        }
41        if !constant.BoolVal(v) {
42            setDead(stmt.Body)
43            return
44        }
45        if stmt.Else != nil {
46            setDead(stmt.Else)
47        }
48    case *ast.SwitchStmt:
49        // Case clause with empty switch tag is dead if it evaluates
50        // to constant false.
51        if stmt.Tag == nil {
52        BodyLoopBool:
53            for _stmt := range stmt.Body.List {
54                cc := stmt.(*ast.CaseClause)
55                if cc.List == nil {
56                    // Skip default case.
57                    continue
58                }
59                for _expr := range cc.List {
60                    v := info.Types[expr].Value
61                    if v == nil || v.Kind() != constant.Bool || constant.BoolVal(v) {
62                        continue BodyLoopBool
63                    }
64                }
65                setDead(cc)
66            }
67            return
68        }
69
70        // Case clause is dead if its constant value doesn't match
71        // the constant value from the switch tag.
72        // TODO: This handles integer comparisons only.
73        v := info.Types[stmt.Tag].Value
74        if v == nil || v.Kind() != constant.Int {
75            return
76        }
77        tagNok := constant.Uint64Val(v)
78        if !ok {
79            return
80        }
81    BodyLoopInt:
82        for _x := range stmt.Body.List {
83            cc := x.(*ast.CaseClause)
84            if cc.List == nil {
85                // Skip default case.
86                continue
87            }
88            for _expr := range cc.List {
89                v := info.Types[expr].Value
90                if v == nil {
91                    continue BodyLoopInt
92                }
93                nok := constant.Uint64Val(v)
94                if !ok || tagN == n {
95                    continue BodyLoopInt
96                }
97            }
98            setDead(cc)
99        }
100    }
101}
102
MembersX
updateDead.BlockStmt.RangeStmt_1881.x
updateDead.BlockStmt.RangeStmt_1881.BlockStmt.RangeStmt_2015.BlockStmt.v
updateDead.BlockStmt.BlockStmt.RangeStmt_1198.stmt
updateDead.BlockStmt.ok
updateDead.BlockStmt.BlockStmt.RangeStmt_1198.BlockStmt.RangeStmt_1344.BlockStmt.v
updateDead.BlockStmt.tagN
updateDead.BlockStmt.RangeStmt_1881.BlockStmt.RangeStmt_2015.BlockStmt.ok
updateDead.node
updateDead.BlockStmt.BlockStmt.RangeStmt_1198.BlockStmt.RangeStmt_1344.expr
updateDead.BlockStmt.v
updateDead.BlockStmt.RangeStmt_1881.BlockStmt.RangeStmt_2015.expr
types
updateDead
updateDead.info
updateDead.dead
updateDead.BlockStmt.RangeStmt_1881.BlockStmt.RangeStmt_2015.BlockStmt.n
ast
constant
Members
X