...
Run Format

Source file src/cmd/vet/dead.go

Documentation: cmd/vet

  // 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 || 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
  }
  

View as plain text