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