1
2
3
4
5
6
7
8 package types2_test
9
10 import (
11 "bytes"
12 "cmd/compile/internal/syntax"
13 "fmt"
14 "go/build"
15 "internal/testenv"
16 "os"
17 "path/filepath"
18 "runtime"
19 "strings"
20 "testing"
21 "time"
22
23 . "cmd/compile/internal/types2"
24 )
25
26 var stdLibImporter = defaultImporter()
27
28 func TestStdlib(t *testing.T) {
29 testenv.MustHaveGoBuild(t)
30
31 pkgCount := 0
32 duration := walkPkgDirs(filepath.Join(runtime.GOROOT(), "src"), func(dir string, filenames []string) {
33 typecheck(t, dir, filenames)
34 pkgCount++
35 }, t.Error)
36
37 if testing.Verbose() {
38 fmt.Println(pkgCount, "packages typechecked in", duration)
39 }
40 }
41
42
43
44
45
46
47 func firstComment(filename string) (first string) {
48 f, err := os.Open(filename)
49 if err != nil {
50 return ""
51 }
52 defer f.Close()
53
54
55 var buf [4 << 10]byte
56 n, _ := f.Read(buf[:])
57 src := bytes.NewBuffer(buf[:n])
58
59
60 defer func() {
61 if p := recover(); p != nil {
62 if s, ok := p.(string); ok {
63 first = s
64 }
65 }
66 }()
67
68 syntax.CommentsDo(src, func(_, _ uint, text string) {
69 if text[0] != '/' {
70 return
71 }
72
73
74 if text[1] == '*' {
75 text = text[:len(text)-2]
76 }
77 text = strings.TrimSpace(text[2:])
78
79 if strings.HasPrefix(text, "+build ") {
80 panic("skip")
81 }
82 if first == "" {
83 first = text
84 }
85
86 })
87
88 return
89 }
90
91 func testTestDir(t *testing.T, path string, ignore ...string) {
92 files, err := os.ReadDir(path)
93 if err != nil {
94 t.Fatal(err)
95 }
96
97 excluded := make(map[string]bool)
98 for _, filename := range ignore {
99 excluded[filename] = true
100 }
101
102 for _, f := range files {
103
104 if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
105 continue
106 }
107
108
109 expectErrors := false
110 filename := filepath.Join(path, f.Name())
111 goVersion := ""
112 if comment := firstComment(filename); comment != "" {
113 fields := strings.Fields(comment)
114 switch fields[0] {
115 case "skip", "compiledir":
116 continue
117 case "errorcheck":
118 expectErrors = true
119 for _, arg := range fields[1:] {
120 if arg == "-0" || arg == "-+" || arg == "-std" {
121
122
123
124
125 expectErrors = false
126 break
127 }
128 const prefix = "-lang="
129 if strings.HasPrefix(arg, prefix) {
130 goVersion = arg[len(prefix):]
131 }
132 }
133 }
134 }
135
136
137 if testing.Verbose() {
138 fmt.Println("\t", filename)
139 }
140 file, err := syntax.ParseFile(filename, nil, nil, 0)
141 if err == nil {
142 conf := Config{GoVersion: goVersion, Importer: stdLibImporter}
143 _, err = conf.Check(filename, []*syntax.File{file}, nil)
144 }
145
146 if expectErrors {
147 if err == nil {
148 t.Errorf("expected errors but found none in %s", filename)
149 }
150 } else {
151 if err != nil {
152 t.Error(err)
153 }
154 }
155 }
156 }
157
158 func TestStdTest(t *testing.T) {
159 testenv.MustHaveGoBuild(t)
160
161 if testing.Short() && testenv.Builder() == "" {
162 t.Skip("skipping in short mode")
163 }
164
165 testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
166 "cmplxdivide.go",
167 "directive.go",
168 "directive2.go",
169 "embedfunc.go",
170 "embedvers.go",
171 "linkname2.go",
172 "linkname3.go",
173 )
174 }
175
176 func TestStdFixed(t *testing.T) {
177 testenv.MustHaveGoBuild(t)
178
179 if testing.Short() && testenv.Builder() == "" {
180 t.Skip("skipping in short mode")
181 }
182
183 testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
184 "bug248.go", "bug302.go", "bug369.go",
185 "issue6889.go",
186 "issue11362.go",
187 "issue16369.go",
188 "issue18459.go",
189 "issue18882.go",
190 "issue20529.go",
191 "issue22200.go",
192 "issue22200b.go",
193 "issue25507.go",
194 "issue20780.go",
195 "issue42058a.go",
196 "issue42058b.go",
197 "issue48097.go",
198 "issue48230.go",
199 "issue49767.go",
200 "issue49814.go",
201 )
202 }
203
204 func TestStdKen(t *testing.T) {
205 testenv.MustHaveGoBuild(t)
206
207 testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
208 }
209
210
211 var excluded = map[string]bool{
212 "builtin": true,
213
214
215 "crypto/ed25519/internal/edwards25519/field/_asm": true,
216 }
217
218
219 func typecheck(t *testing.T, path string, filenames []string) {
220
221 var files []*syntax.File
222 for _, filename := range filenames {
223 errh := func(err error) { t.Error(err) }
224 file, err := syntax.ParseFile(filename, errh, nil, syntax.AllowGenerics)
225 if err != nil {
226 return
227 }
228
229 if testing.Verbose() {
230 if len(files) == 0 {
231 fmt.Println("package", file.PkgName.Value)
232 }
233 fmt.Println("\t", filename)
234 }
235
236 files = append(files, file)
237 }
238
239
240 conf := Config{
241 Error: func(err error) { t.Error(err) },
242 Importer: stdLibImporter,
243 }
244 info := Info{Uses: make(map[*syntax.Name]Object)}
245 conf.Check(path, files, &info)
246
247
248
249
250 errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0)
251 for id, obj := range info.Uses {
252 predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
253 if predeclared == (obj.Pkg() != nil) {
254 posn := id.Pos()
255 if predeclared {
256 t.Errorf("%s: predeclared object with package: %s", posn, obj)
257 } else {
258 t.Errorf("%s: user-defined object without package: %s", posn, obj)
259 }
260 }
261 }
262 }
263
264
265 func pkgFilenames(dir string) ([]string, error) {
266 ctxt := build.Default
267 ctxt.CgoEnabled = false
268 pkg, err := ctxt.ImportDir(dir, 0)
269 if err != nil {
270 if _, nogo := err.(*build.NoGoError); nogo {
271 return nil, nil
272 }
273 return nil, err
274 }
275 if excluded[pkg.ImportPath] {
276 return nil, nil
277 }
278 var filenames []string
279 for _, name := range pkg.GoFiles {
280 filenames = append(filenames, filepath.Join(pkg.Dir, name))
281 }
282 for _, name := range pkg.TestGoFiles {
283 filenames = append(filenames, filepath.Join(pkg.Dir, name))
284 }
285 return filenames, nil
286 }
287
288 func walkPkgDirs(dir string, pkgh func(dir string, filenames []string), errh func(args ...interface{})) time.Duration {
289 w := walker{time.Now(), 10 * time.Millisecond, pkgh, errh}
290 w.walk(dir)
291 return time.Since(w.start)
292 }
293
294 type walker struct {
295 start time.Time
296 dmax time.Duration
297 pkgh func(dir string, filenames []string)
298 errh func(args ...interface{})
299 }
300
301 func (w *walker) walk(dir string) {
302
303 if testing.Short() && time.Since(w.start) >= w.dmax {
304 return
305 }
306
307 files, err := os.ReadDir(dir)
308 if err != nil {
309 w.errh(err)
310 return
311 }
312
313
314
315 if dir != filepath.Join(runtime.GOROOT(), "src") {
316 files, err := pkgFilenames(dir)
317 if err != nil {
318 w.errh(err)
319 return
320 }
321 if files != nil {
322 w.pkgh(dir, files)
323 }
324 }
325
326
327 for _, f := range files {
328 if f.IsDir() && f.Name() != "testdata" {
329 w.walk(filepath.Join(dir, f.Name()))
330 }
331 }
332 }
333
View as plain text