github.com/karrick/go@v0.0.0-20170817181416-d5b0ec858b37/src/cmd/vet/dead.go (about) 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 // 5 // Simplified dead code detector. Used for skipping certain checks 6 // on unreachable code (for instance, shift checks on arch-specific code). 7 // 8 package main 9 10 import ( 11 "go/ast" 12 "go/constant" 13 ) 14 15 // updateDead puts unreachable "if" and "case" nodes into f.dead. 16 func (f *File) updateDead(node ast.Node) { 17 if f.dead[node] { 18 // The node is already marked as dead. 19 return 20 } 21 22 switch stmt := node.(type) { 23 case *ast.IfStmt: 24 // "if" branch is dead if its condition evaluates 25 // to constant false. 26 v := f.pkg.types[stmt.Cond].Value 27 if v == nil { 28 return 29 } 30 if !constant.BoolVal(v) { 31 f.setDead(stmt.Body) 32 return 33 } 34 f.setDead(stmt.Else) 35 case *ast.SwitchStmt: 36 // Case clause with empty switch tag is dead if it evaluates 37 // to constant false. 38 if stmt.Tag == nil { 39 BodyLoopBool: 40 for _, stmt := range stmt.Body.List { 41 cc := stmt.(*ast.CaseClause) 42 if cc.List == nil { 43 // Skip default case. 44 continue 45 } 46 for _, expr := range cc.List { 47 v := f.pkg.types[expr].Value 48 if v == nil || constant.BoolVal(v) { 49 continue BodyLoopBool 50 } 51 } 52 f.setDead(cc) 53 } 54 return 55 } 56 57 // Case clause is dead if its constant value doesn't match 58 // the constant value from the switch tag. 59 // TODO: This handles integer comparisons only. 60 v := f.pkg.types[stmt.Tag].Value 61 if v == nil || v.Kind() != constant.Int { 62 return 63 } 64 tagN, ok := constant.Uint64Val(v) 65 if !ok { 66 return 67 } 68 BodyLoopInt: 69 for _, x := range stmt.Body.List { 70 cc := x.(*ast.CaseClause) 71 if cc.List == nil { 72 // Skip default case. 73 continue 74 } 75 for _, expr := range cc.List { 76 v := f.pkg.types[expr].Value 77 if v == nil { 78 continue BodyLoopInt 79 } 80 n, ok := constant.Uint64Val(v) 81 if !ok || tagN == n { 82 continue BodyLoopInt 83 } 84 } 85 f.setDead(cc) 86 } 87 } 88 } 89 90 // setDead marks the node and all the children as dead. 91 func (f *File) setDead(node ast.Node) { 92 dv := deadVisitor{ 93 f: f, 94 } 95 ast.Walk(dv, node) 96 } 97 98 type deadVisitor struct { 99 f *File 100 } 101 102 func (dv deadVisitor) Visit(node ast.Node) ast.Visitor { 103 if node == nil { 104 return nil 105 } 106 dv.f.dead[node] = true 107 return dv 108 }