1 // Copyright 2013 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.
5 // This file tests types.Check by using it to
6 // typecheck the standard library and tests.
31 pkgCount int // number of packages processed
34 // Use the same importer for all std lib tests to
35 // avoid repeated importing of the same packages.
37 // importer.Default panics for gccgo
38 // stdLibImporter = importer.Default()
39 stdLibImporter Importer
42 func TestStdlib(t *testing.T) {
43 testenv.MustHaveGoBuild(t)
46 walkDirs(t, filepath.Join(runtime.GOROOT(), "src"))
47 if testing.Verbose() {
48 fmt.Println(pkgCount, "packages typechecked in", time.Since(start))
52 // firstComment returns the contents of the first non-empty comment in
53 // the given file, "skip", or the empty string. No matter the present
54 // comments, if any of them contains a build tag, the result is always
55 // "skip". Only comments before the "package" token and within the first
56 // 4K of the file are considered.
57 func firstComment(filename string) string {
58 f, err := os.Open(filename)
64 var src [4 << 10]byte // read at most 4KB
65 n, _ := f.Read(src[:])
69 s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil /* ignore errors */, scanner.ScanComments)
71 _, tok, lit := s.Scan()
74 // remove trailing */ of multi-line comment
76 lit = lit[:len(lit)-2]
78 contents := strings.TrimSpace(lit[2:])
79 if strings.HasPrefix(contents, "+build ") {
83 first = contents // contents may be "" but that's ok
85 // continue as we may still see build tags
87 case token.PACKAGE, token.EOF:
93 func testTestDir(t *testing.T, path string, ignore ...string) {
94 t.Skip("skipping for gccgo")
96 files, err := ioutil.ReadDir(path)
101 excluded := make(map[string]bool)
102 for _, filename := range ignore {
103 excluded[filename] = true
106 fset := token.NewFileSet()
107 for _, f := range files {
108 // filter directory contents
109 if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
113 // get per-file instructions
114 expectErrors := false
115 filename := filepath.Join(path, f.Name())
116 if comment := firstComment(filename); comment != "" {
117 fields := strings.Fields(comment)
119 case "skip", "compiledir":
120 continue // ignore this file
123 for _, arg := range fields[1:] {
124 if arg == "-0" || arg == "-+" || arg == "-std" {
125 // Marked explicitly as not expected errors (-0),
126 // or marked as compiling runtime/stdlib, which is only done
127 // to trigger runtime/stdlib-only error output.
128 // In both cases, the code should typecheck.
136 // parse and type-check file
137 file, err := parser.ParseFile(fset, filename, nil, 0)
139 conf := Config{Importer: stdLibImporter}
140 _, err = conf.Check(filename, fset, []*ast.File{file}, nil)
145 t.Errorf("expected errors but found none in %s", filename)
155 func TestStdTest(t *testing.T) {
156 testenv.MustHaveGoBuild(t)
158 if testing.Short() && testenv.Builder() == "" {
159 t.Skip("skipping in short mode")
162 testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
163 "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
167 func TestStdFixed(t *testing.T) {
168 testenv.MustHaveGoBuild(t)
170 if testing.Short() && testenv.Builder() == "" {
171 t.Skip("skipping in short mode")
174 testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
175 "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
176 "issue6889.go", // gc-specific test
177 "issue7746.go", // large constants - consumes too much memory
178 "issue11362.go", // canonical import path check
179 "issue16369.go", // go/types handles this correctly - not an issue
180 "issue18459.go", // go/types doesn't check validity of //go:xxx directives
181 "issue18882.go", // go/types doesn't check validity of //go:xxx directives
182 "issue20232.go", // go/types handles larger constants than gc
183 "issue20529.go", // go/types does not have constraints on stack size
184 "issue22200.go", // go/types does not have constraints on stack size
185 "issue22200b.go", // go/types does not have constraints on stack size
186 "issue25507.go", // go/types does not have constraints on stack size
187 "issue20780.go", // go/types does not have constraints on stack size
188 "issue31747.go", // go/types does not have constraints on language level (-lang=go1.12) (see #31793)
189 "issue34329.go", // go/types does not have constraints on language level (-lang=go1.13) (see #31793)
190 "bug251.go", // issue #34333 which was exposed with fix for #34151
194 func TestStdKen(t *testing.T) {
195 testenv.MustHaveGoBuild(t)
197 testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
200 // Package paths of excluded packages.
201 var excluded = map[string]bool{
205 // typecheck typechecks the given package files.
206 func typecheck(t *testing.T, path string, filenames []string) {
207 t.Skip("skipping for gccgo")
209 fset := token.NewFileSet()
211 // parse package files
212 var files []*ast.File
213 for _, filename := range filenames {
214 file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
216 // the parser error may be a list of individual errors; report them all
217 if list, ok := err.(scanner.ErrorList); ok {
218 for _, err := range list {
227 if testing.Verbose() {
229 fmt.Println("package", file.Name.Name)
231 fmt.Println("\t", filename)
234 files = append(files, file)
237 // typecheck package files
239 Error: func(err error) { t.Error(err) },
240 Importer: stdLibImporter,
242 info := Info{Uses: make(map[*ast.Ident]Object)}
243 conf.Check(path, fset, files, &info)
246 // Perform checks of API invariants.
248 // All Objects have a package, except predeclared ones.
249 errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0) // (error).Error
250 for id, obj := range info.Uses {
251 predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
252 if predeclared == (obj.Pkg() != nil) {
253 posn := fset.Position(id.Pos())
255 t.Errorf("%s: predeclared object with package: %s", posn, obj)
257 t.Errorf("%s: user-defined object without package: %s", posn, obj)
263 // pkgFilenames returns the list of package filenames for the given directory.
264 func pkgFilenames(dir string) ([]string, error) {
265 ctxt := build.Default
266 ctxt.CgoEnabled = false
267 pkg, err := ctxt.ImportDir(dir, 0)
269 if _, nogo := err.(*build.NoGoError); nogo {
270 return nil, nil // no *.go files, not an error
274 if excluded[pkg.ImportPath] {
277 var filenames []string
278 for _, name := range pkg.GoFiles {
279 filenames = append(filenames, filepath.Join(pkg.Dir, name))
281 for _, name := range pkg.TestGoFiles {
282 filenames = append(filenames, filepath.Join(pkg.Dir, name))
284 return filenames, nil
287 // Note: Could use filepath.Walk instead of walkDirs but that wouldn't
288 // necessarily be shorter or clearer after adding the code to
289 // terminate early for -short tests.
291 func walkDirs(t *testing.T, dir string) {
292 // limit run time for short tests
293 if testing.Short() && time.Since(start) >= 10*time.Millisecond {
297 fis, err := ioutil.ReadDir(dir)
303 // typecheck package in directory
304 // but ignore files directly under $GOROOT/src (might be temporary test files).
305 if dir != filepath.Join(runtime.GOROOT(), "src") {
306 files, err := pkgFilenames(dir)
312 typecheck(t, dir, files)
316 // traverse subdirectories, but don't walk into testdata
317 for _, fi := range fis {
318 if fi.IsDir() && fi.Name() != "testdata" {
319 walkDirs(t, filepath.Join(dir, fi.Name()))