| // Copyright 2017 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 | // | 
 | // Simplified dead code detector. Used for skipping certain checks | 
 | // on unreachable code (for instance, shift checks on arch-specific code). | 
 |  | 
 | package main | 
 |  | 
 | import ( | 
 | 	"go/ast" | 
 | 	"go/constant" | 
 | ) | 
 |  | 
 | // updateDead puts unreachable "if" and "case" nodes into f.dead. | 
 | func (f *File) updateDead(node ast.Node) { | 
 | 	if f.dead[node] { | 
 | 		// The node is already marked as dead. | 
 | 		return | 
 | 	} | 
 |  | 
 | 	switch stmt := node.(type) { | 
 | 	case *ast.IfStmt: | 
 | 		// "if" branch is dead if its condition evaluates | 
 | 		// to constant false. | 
 | 		v := f.pkg.types[stmt.Cond].Value | 
 | 		if v == nil { | 
 | 			return | 
 | 		} | 
 | 		if !constant.BoolVal(v) { | 
 | 			f.setDead(stmt.Body) | 
 | 			return | 
 | 		} | 
 | 		f.setDead(stmt.Else) | 
 | 	case *ast.SwitchStmt: | 
 | 		// Case clause with empty switch tag is dead if it evaluates | 
 | 		// to constant false. | 
 | 		if stmt.Tag == nil { | 
 | 		BodyLoopBool: | 
 | 			for _, stmt := range stmt.Body.List { | 
 | 				cc := stmt.(*ast.CaseClause) | 
 | 				if cc.List == nil { | 
 | 					// Skip default case. | 
 | 					continue | 
 | 				} | 
 | 				for _, expr := range cc.List { | 
 | 					v := f.pkg.types[expr].Value | 
 | 					if v == nil || v.Kind() != constant.Bool || constant.BoolVal(v) { | 
 | 						continue BodyLoopBool | 
 | 					} | 
 | 				} | 
 | 				f.setDead(cc) | 
 | 			} | 
 | 			return | 
 | 		} | 
 |  | 
 | 		// Case clause is dead if its constant value doesn't match | 
 | 		// the constant value from the switch tag. | 
 | 		// TODO: This handles integer comparisons only. | 
 | 		v := f.pkg.types[stmt.Tag].Value | 
 | 		if v == nil || v.Kind() != constant.Int { | 
 | 			return | 
 | 		} | 
 | 		tagN, ok := constant.Uint64Val(v) | 
 | 		if !ok { | 
 | 			return | 
 | 		} | 
 | 	BodyLoopInt: | 
 | 		for _, x := range stmt.Body.List { | 
 | 			cc := x.(*ast.CaseClause) | 
 | 			if cc.List == nil { | 
 | 				// Skip default case. | 
 | 				continue | 
 | 			} | 
 | 			for _, expr := range cc.List { | 
 | 				v := f.pkg.types[expr].Value | 
 | 				if v == nil { | 
 | 					continue BodyLoopInt | 
 | 				} | 
 | 				n, ok := constant.Uint64Val(v) | 
 | 				if !ok || tagN == n { | 
 | 					continue BodyLoopInt | 
 | 				} | 
 | 			} | 
 | 			f.setDead(cc) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // setDead marks the node and all the children as dead. | 
 | func (f *File) setDead(node ast.Node) { | 
 | 	dv := deadVisitor{ | 
 | 		f: f, | 
 | 	} | 
 | 	ast.Walk(dv, node) | 
 | } | 
 |  | 
 | type deadVisitor struct { | 
 | 	f *File | 
 | } | 
 |  | 
 | func (dv deadVisitor) Visit(node ast.Node) ast.Visitor { | 
 | 	if node == nil { | 
 | 		return nil | 
 | 	} | 
 | 	dv.f.dead[node] = true | 
 | 	return dv | 
 | } |