+++ /dev/null
-// Copyright 2016 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.
-
-package cfg
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "testing"
-)
-
-const src = `package main
-
-import "log"
-
-func f1() {
- live()
- return
- dead()
-}
-
-func f2() {
- for {
- live()
- }
- dead()
-}
-
-func f3() {
- if true { // even known values are ignored
- return
- }
- for true { // even known values are ignored
- live()
- }
- for {
- live()
- }
- dead()
-}
-
-func f4(x int) {
- switch x {
- case 1:
- live()
- fallthrough
- case 2:
- live()
- log.Fatal()
- default:
- panic("oops")
- }
- dead()
-}
-
-func f4(ch chan int) {
- select {
- case <-ch:
- live()
- return
- default:
- live()
- panic("oops")
- }
- dead()
-}
-
-func f5(unknown bool) {
- for {
- if unknown {
- break
- }
- continue
- dead()
- }
- live()
-}
-
-func f6(unknown bool) {
-outer:
- for {
- for {
- break outer
- dead()
- }
- dead()
- }
- live()
-}
-
-func f7() {
- for {
- break nosuchlabel
- dead()
- }
- dead()
-}
-
-func f8() {
- select{}
- dead()
-}
-
-func f9(ch chan int) {
- select {
- case <-ch:
- return
- }
- dead()
-}
-
-func f10(ch chan int) {
- select {
- case <-ch:
- return
- dead()
- default:
- }
- live()
-}
-
-func f11() {
- goto; // mustn't crash
- dead()
-}
-
-`
-
-func TestDeadCode(t *testing.T) {
- // We'll use dead code detection to verify the CFG.
-
- fset := token.NewFileSet()
- f, err := parser.ParseFile(fset, "dummy.go", src, parser.Mode(0))
- if err != nil {
- t.Fatal(err)
- }
- for _, decl := range f.Decls {
- if decl, ok := decl.(*ast.FuncDecl); ok {
- g := New(decl.Body, mayReturn)
-
- // Print statements in unreachable blocks
- // (in order determined by builder).
- var buf bytes.Buffer
- for _, b := range g.Blocks {
- if !b.Live {
- for _, n := range b.Nodes {
- fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n))
- }
- }
- }
-
- // Check that the result contains "dead" at least once but not "live".
- if !bytes.Contains(buf.Bytes(), []byte("dead")) ||
- bytes.Contains(buf.Bytes(), []byte("live")) {
- t.Errorf("unexpected dead statements in function %s:\n%s",
- decl.Name.Name,
- &buf)
- t.Logf("control flow graph:\n%s", g.Format(fset))
- }
- }
- }
-}
-
-// A trivial mayReturn predicate that looks only at syntax, not types.
-func mayReturn(call *ast.CallExpr) bool {
- switch fun := call.Fun.(type) {
- case *ast.Ident:
- return fun.Name != "panic"
- case *ast.SelectorExpr:
- return fun.Sel.Name != "Fatal"
- }
- return true
-}