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{Importer: stdLibImporter}
144 SetGoVersion(&conf, goVersion)
145 _, err = conf.Check(filename, fset, []*ast.File{file}, nil)
146 }
147
148 if expectErrors {
149 if err == nil {
150 t.Errorf("expected errors but found none in %s", filename)
151 }
152 } else {
153 if err != nil {
154 t.Error(err)
155 }
156 }
157 }
158 }
159
160 func TestStdTest(t *testing.T) {
161 testenv.MustHaveGoBuild(t)
162
163 if testing.Short() && testenv.Builder() == "" {
164 t.Skip("skipping in short mode")
165 }
166
167 testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
168 "cmplxdivide.go",
169 "directive.go",
170 "embedfunc.go",
171 "embedvers.go",
172 "linkname2.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 "bug251.go",
196 "issue42058a.go",
197 "issue42058b.go",
198 )
199 }
200
201 func TestStdKen(t *testing.T) {
202 testenv.MustHaveGoBuild(t)
203
204 testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
205 }
206
207
208 var excluded = map[string]bool{
209 "builtin": true,
210
211
212 "crypto/ed25519/internal/edwards25519/field/_asm": true,
213 }
214
215
216 func typecheck(t *testing.T, path string, filenames []string) {
217 fset := token.NewFileSet()
218
219
220 var files []*ast.File
221 for _, filename := range filenames {
222 file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
223 if err != nil {
224
225 if list, ok := err.(scanner.ErrorList); ok {
226 for _, err := range list {
227 t.Error(err)
228 }
229 return
230 }
231 t.Error(err)
232 return
233 }
234
235 if testing.Verbose() {
236 if len(files) == 0 {
237 fmt.Println("package", file.Name.Name)
238 }
239 fmt.Println("\t", filename)
240 }
241
242 files = append(files, file)
243 }
244
245
246 conf := Config{
247 Error: func(err error) { t.Error(err) },
248 Importer: stdLibImporter,
249 }
250 info := Info{Uses: make(map[*ast.Ident]Object)}
251 conf.Check(path, fset, files, &info)
252
253
254
255
256 errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0)
257 for id, obj := range info.Uses {
258 predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
259 if predeclared == (obj.Pkg() != nil) {
260 posn := fset.Position(id.Pos())
261 if predeclared {
262 t.Errorf("%s: predeclared object with package: %s", posn, obj)
263 } else {
264 t.Errorf("%s: user-defined object without package: %s", posn, obj)
265 }
266 }
267 }
268 }
269
270
271 func pkgFilenames(dir string) ([]string, error) {
272 ctxt := build.Default
273 ctxt.CgoEnabled = false
274 pkg, err := ctxt.ImportDir(dir, 0)
275 if err != nil {
276 if _, nogo := err.(*build.NoGoError); nogo {
277 return nil, nil
278 }
279 return nil, err
280 }
281 if excluded[pkg.ImportPath] {
282 return nil, nil
283 }
284 var filenames []string
285 for _, name := range pkg.GoFiles {
286 filenames = append(filenames, filepath.Join(pkg.Dir, name))
287 }
288 for _, name := range pkg.TestGoFiles {
289 filenames = append(filenames, filepath.Join(pkg.Dir, name))
290 }
291 return filenames, nil
292 }
293
294 func walkPkgDirs(dir string, pkgh func(dir string, filenames []string), errh func(args ...interface{})) time.Duration {
295 w := walker{time.Now(), 10 * time.Millisecond, pkgh, errh}
296 w.walk(dir)
297 return time.Since(w.start)
298 }
299
300 type walker struct {
301 start time.Time
302 dmax time.Duration
303 pkgh func(dir string, filenames []string)
304 errh func(args ...interface{})
305 }
306
307 func (w *walker) walk(dir string) {
308
309 if testing.Short() && time.Since(w.start) >= w.dmax {
310 return
311 }
312
313 files, err := os.ReadDir(dir)
314 if err != nil {
315 w.errh(err)
316 return
317 }
318
319
320
321 if dir != filepath.Join(runtime.GOROOT(), "src") {
322 files, err := pkgFilenames(dir)
323 if err != nil {
324 w.errh(err)
325 return
326 }
327 if files != nil {
328 w.pkgh(dir, files)
329 }
330 }
331
332
333 for _, f := range files {
334 if f.IsDir() && f.Name() != "testdata" {
335 w.walk(filepath.Join(dir, f.Name()))
336 }
337 }
338 }
339
View as plain text