GoPLS Viewer

Home|gopls/go/cfg/cfg_test.go
1// Copyright 2016 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
5package cfg
6
7import (
8    "bytes"
9    "fmt"
10    "go/ast"
11    "go/parser"
12    "go/token"
13    "testing"
14)
15
16const src = `package main
17
18import "log"
19
20func f1() {
21    live()
22    return
23    dead()
24}
25
26func f2() {
27    for {
28        live()
29    }
30    dead()
31}
32
33func f3() {
34    if true { // even known values are ignored
35        return
36    }
37    for true { // even known values are ignored
38        live()
39    }
40    for {
41        live()
42    }
43    dead()
44}
45
46func f4(x int) {
47    switch x {
48    case 1:
49        live()
50        fallthrough
51    case 2:
52        live()
53        log.Fatal()
54    default:
55        panic("oops")
56    }
57    dead()
58}
59
60func f4(ch chan int) {
61    select {
62    case <-ch:
63        live()
64        return
65    default:
66        live()
67        panic("oops")
68    }
69    dead()
70}
71
72func f5(unknown bool) {
73    for {
74        if unknown {
75            break
76        }
77        continue
78        dead()
79    }
80    live()
81}
82
83func f6(unknown bool) {
84outer:
85    for {
86        for {
87            break outer
88            dead()
89        }
90        dead()
91    }
92    live()
93}
94
95func f7() {
96    for {
97        break nosuchlabel
98        dead()
99    }
100    dead()
101}
102
103func f8() {
104    select{}
105    dead()
106}
107
108func f9(ch chan int) {
109    select {
110    case <-ch:
111        return
112    }
113    dead()
114}
115
116func f10(ch chan int) {
117    select {
118    case <-ch:
119        return
120        dead()
121    default:
122    }
123    live()
124}
125
126func f11() {
127    goto; // mustn't crash
128    dead()
129}
130
131`
132
133func TestDeadCode(t *testing.T) {
134    // We'll use dead code detection to verify the CFG.
135
136    fset := token.NewFileSet()
137    ferr := parser.ParseFile(fset"dummy.go"srcparser.Mode(0))
138    if err != nil {
139        t.Fatal(err)
140    }
141    for _decl := range f.Decls {
142        if declok := decl.(*ast.FuncDecl); ok {
143            g := New(decl.BodymayReturn)
144
145            // Print statements in unreachable blocks
146            // (in order determined by builder).
147            var buf bytes.Buffer
148            for _b := range g.Blocks {
149                if !b.Live {
150                    for _n := range b.Nodes {
151                        fmt.Fprintf(&buf"\t%s\n"formatNode(fsetn))
152                    }
153                }
154            }
155
156            // Check that the result contains "dead" at least once but not "live".
157            if !bytes.Contains(buf.Bytes(), []byte("dead")) ||
158                bytes.Contains(buf.Bytes(), []byte("live")) {
159                t.Errorf("unexpected dead statements in function %s:\n%s",
160                    decl.Name.Name,
161                    &buf)
162                t.Logf("control flow graph:\n%s"g.Format(fset))
163            }
164        }
165    }
166}
167
168// A trivial mayReturn predicate that looks only at syntax, not types.
169func mayReturn(call *ast.CallExprbool {
170    switch fun := call.Fun.(type) {
171    case *ast.Ident:
172        return fun.Name != "panic"
173    case *ast.SelectorExpr:
174        return fun.Sel.Name != "Fatal"
175    }
176    return true
177}
178
MembersX
parser
TestDeadCode.RangeStmt_1482.BlockStmt.BlockStmt.RangeStmt_1704.b
src
TestDeadCode.fset
TestDeadCode.f
TestDeadCode.RangeStmt_1482.BlockStmt.BlockStmt.buf
testing
TestDeadCode
TestDeadCode.err
TestDeadCode.RangeStmt_1482.BlockStmt.BlockStmt.RangeStmt_1704.BlockStmt.BlockStmt.RangeStmt_1755.n
mayReturn
TestDeadCode.t
TestDeadCode.RangeStmt_1482.decl
TestDeadCode.RangeStmt_1482.BlockStmt.BlockStmt.g
mayReturn.call
Members
X