Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / 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
5 package cfg
6
7 import (
8         "bytes"
9         "fmt"
10         "go/ast"
11         "go/parser"
12         "go/token"
13         "testing"
14 )
15
16 const src = `package main
17
18 import "log"
19
20 func f1() {
21         live()
22         return
23         dead()
24 }
25
26 func f2() {
27         for {
28                 live()
29         }
30         dead()
31 }
32
33 func 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
46 func 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
60 func 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
72 func f5(unknown bool) {
73         for {
74                 if unknown {
75                         break
76                 }
77                 continue
78                 dead()
79         }
80         live()
81 }
82
83 func f6(unknown bool) {
84 outer:
85         for {
86                 for {
87                         break outer
88                         dead()
89                 }
90                 dead()
91         }
92         live()
93 }
94
95 func f7() {
96         for {
97                 break nosuchlabel
98                 dead()
99         }
100         dead()
101 }
102
103 func f8() {
104         select{}
105         dead()
106 }
107
108 func f9(ch chan int) {
109         select {
110         case <-ch:
111                 return
112         }
113         dead()
114 }
115
116 func f10(ch chan int) {
117         select {
118         case <-ch:
119                 return
120                 dead()
121         default:
122         }
123         live()
124 }
125
126 func f11() {
127         goto; // mustn't crash
128         dead()
129 }
130
131 `
132
133 func TestDeadCode(t *testing.T) {
134         // We'll use dead code detection to verify the CFG.
135
136         fset := token.NewFileSet()
137         f, err := parser.ParseFile(fset, "dummy.go", src, parser.Mode(0))
138         if err != nil {
139                 t.Fatal(err)
140         }
141         for _, decl := range f.Decls {
142                 if decl, ok := decl.(*ast.FuncDecl); ok {
143                         g := New(decl.Body, mayReturn)
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(fset, n))
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.
169 func mayReturn(call *ast.CallExpr) bool {
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 }