go/analysis/passes/unreachable: split out of vet
Change-Id: Ibbc888ee86de1cc59392b258ec32d2aec3b9fbef Reviewed-on: https://go-review.googlesource.com/c/140837 Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
		
							parent
							
								
									088df9ca28
								
							
						
					
					
						commit
						afb03721b5
					
				| 
						 | 
					@ -137,7 +137,7 @@ func loadPackage(dir, pkgpath string) (*packages.Package, error) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Print errors but do not stop:
 | 
						// Print errors but do not stop:
 | 
				
			||||||
	// some Analyzers may be disposed to RunDespiteErrors
 | 
						// some Analyzers may be disposed to RunDespiteErrors.
 | 
				
			||||||
	packages.PrintErrors(pkgs)
 | 
						packages.PrintErrors(pkgs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(pkgs) != 1 {
 | 
						if len(pkgs) != 1 {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -1,41 +1,43 @@
 | 
				
			||||||
// +build ignore
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Copyright 2013 The Go Authors. All rights reserved.
 | 
					// Copyright 2013 The Go Authors. All rights reserved.
 | 
				
			||||||
// Use of this source code is governed by a BSD-style
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
// license that can be found in the LICENSE file.
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Check for syntactically unreachable code.
 | 
					package unreachable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package main
 | 
					// TODO(adonovan): use the new cfg package, which is more precise.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"go/ast"
 | 
						"go/ast"
 | 
				
			||||||
	"go/token"
 | 
						"go/token"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"golang.org/x/tools/go/analysis"
 | 
				
			||||||
 | 
						"golang.org/x/tools/go/analysis/passes/inspect"
 | 
				
			||||||
 | 
						"golang.org/x/tools/go/ast/inspector"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					var Analyzer = &analysis.Analyzer{
 | 
				
			||||||
	register("unreachable",
 | 
						Name: "unreachable",
 | 
				
			||||||
		"check for unreachable code",
 | 
						Doc: `check for unreachable code
 | 
				
			||||||
		checkUnreachable,
 | 
					
 | 
				
			||||||
		funcDecl, funcLit)
 | 
					The unreachable analyzer finds statements that execution can never reach
 | 
				
			||||||
 | 
					because they are preceded by an return statement, a call to panic, an
 | 
				
			||||||
 | 
					infinite loop, or similar constructs.`,
 | 
				
			||||||
 | 
						Requires:         []*analysis.Analyzer{inspect.Analyzer},
 | 
				
			||||||
 | 
						RunDespiteErrors: true,
 | 
				
			||||||
 | 
						Run:              run,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type deadState struct {
 | 
					func run(pass *analysis.Pass) (interface{}, error) {
 | 
				
			||||||
	f           *File
 | 
						inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
 | 
				
			||||||
	hasBreak    map[ast.Stmt]bool
 | 
					 | 
				
			||||||
	hasGoto     map[string]bool
 | 
					 | 
				
			||||||
	labels      map[string]ast.Stmt
 | 
					 | 
				
			||||||
	breakTarget ast.Stmt
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reachable bool
 | 
						nodeFilter := []ast.Node{
 | 
				
			||||||
 | 
							(*ast.FuncDecl)(nil),
 | 
				
			||||||
 | 
							(*ast.FuncLit)(nil),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						inspect.Preorder(nodeFilter, func(n ast.Node) {
 | 
				
			||||||
// checkUnreachable checks a function body for dead code.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// TODO(adonovan): use the new cfg package, which is more precise.
 | 
					 | 
				
			||||||
func checkUnreachable(f *File, node ast.Node) {
 | 
					 | 
				
			||||||
		var body *ast.BlockStmt
 | 
							var body *ast.BlockStmt
 | 
				
			||||||
	switch n := node.(type) {
 | 
							switch n := n.(type) {
 | 
				
			||||||
		case *ast.FuncDecl:
 | 
							case *ast.FuncDecl:
 | 
				
			||||||
			body = n.Body
 | 
								body = n.Body
 | 
				
			||||||
		case *ast.FuncLit:
 | 
							case *ast.FuncLit:
 | 
				
			||||||
| 
						 | 
					@ -44,18 +46,27 @@ func checkUnreachable(f *File, node ast.Node) {
 | 
				
			||||||
		if body == nil {
 | 
							if body == nil {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		d := &deadState{
 | 
							d := &deadState{
 | 
				
			||||||
		f:        f,
 | 
								pass:     pass,
 | 
				
			||||||
			hasBreak: make(map[ast.Stmt]bool),
 | 
								hasBreak: make(map[ast.Stmt]bool),
 | 
				
			||||||
			hasGoto:  make(map[string]bool),
 | 
								hasGoto:  make(map[string]bool),
 | 
				
			||||||
			labels:   make(map[string]ast.Stmt),
 | 
								labels:   make(map[string]ast.Stmt),
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		d.findLabels(body)
 | 
							d.findLabels(body)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		d.reachable = true
 | 
							d.reachable = true
 | 
				
			||||||
		d.findDead(body)
 | 
							d.findDead(body)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return nil, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type deadState struct {
 | 
				
			||||||
 | 
						pass        *analysis.Pass
 | 
				
			||||||
 | 
						hasBreak    map[ast.Stmt]bool
 | 
				
			||||||
 | 
						hasGoto     map[string]bool
 | 
				
			||||||
 | 
						labels      map[string]ast.Stmt
 | 
				
			||||||
 | 
						breakTarget ast.Stmt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reachable bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// findLabels gathers information about the labels defined and used by stmt
 | 
					// findLabels gathers information about the labels defined and used by stmt
 | 
				
			||||||
| 
						 | 
					@ -63,7 +74,7 @@ func checkUnreachable(f *File, node ast.Node) {
 | 
				
			||||||
func (d *deadState) findLabels(stmt ast.Stmt) {
 | 
					func (d *deadState) findLabels(stmt ast.Stmt) {
 | 
				
			||||||
	switch x := stmt.(type) {
 | 
						switch x := stmt.(type) {
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		d.f.Warnf(x.Pos(), "internal error in findLabels: unexpected statement %T", x)
 | 
							log.Fatalf("%s: internal error in findLabels: unexpected statement %T", d.pass.Fset.Position(x.Pos()), x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case *ast.AssignStmt,
 | 
						case *ast.AssignStmt,
 | 
				
			||||||
		*ast.BadStmt,
 | 
							*ast.BadStmt,
 | 
				
			||||||
| 
						 | 
					@ -175,14 +186,14 @@ func (d *deadState) findDead(stmt ast.Stmt) {
 | 
				
			||||||
		case *ast.EmptyStmt:
 | 
							case *ast.EmptyStmt:
 | 
				
			||||||
			// do not warn about unreachable empty statements
 | 
								// do not warn about unreachable empty statements
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			d.f.Bad(stmt.Pos(), "unreachable code")
 | 
								d.pass.Reportf(stmt.Pos(), "unreachable code")
 | 
				
			||||||
			d.reachable = true // silence error about next statement
 | 
								d.reachable = true // silence error about next statement
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch x := stmt.(type) {
 | 
						switch x := stmt.(type) {
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		d.f.Warnf(x.Pos(), "internal error in findDead: unexpected statement %T", x)
 | 
							log.Fatalf("%s: internal error in findDead: unexpected statement %T", d.pass.Fset.Position(x.Pos()), x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case *ast.AssignStmt,
 | 
						case *ast.AssignStmt,
 | 
				
			||||||
		*ast.BadStmt,
 | 
							*ast.BadStmt,
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					package unreachable_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"golang.org/x/tools/go/analysis/analysistest"
 | 
				
			||||||
 | 
						"golang.org/x/tools/go/analysis/passes/unreachable"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Test(t *testing.T) {
 | 
				
			||||||
 | 
						testdata := analysistest.TestData()
 | 
				
			||||||
 | 
						analysistest.Run(t, testdata, unreachable.Analyzer, "a")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue