]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgo/go/go/types/stdlib_test.go
libgo: update to Go1.14beta1
[thirdparty/gcc.git] / libgo / go / go / types / stdlib_test.go
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.
4
5 // This file tests types.Check by using it to
6 // typecheck the standard library and tests.
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 "io/ioutil"
20 "os"
21 "path/filepath"
22 "runtime"
23 "strings"
24 "testing"
25 "time"
26
27 . "go/types"
28 )
29
30 var (
31 pkgCount int // number of packages processed
32 start time.Time
33
34 // Use the same importer for all std lib tests to
35 // avoid repeated importing of the same packages.
36
37 // importer.Default panics for gccgo
38 // stdLibImporter = importer.Default()
39 stdLibImporter Importer
40 )
41
42 func TestStdlib(t *testing.T) {
43 testenv.MustHaveGoBuild(t)
44
45 start = time.Now()
46 walkDirs(t, filepath.Join(runtime.GOROOT(), "src"))
47 if testing.Verbose() {
48 fmt.Println(pkgCount, "packages typechecked in", time.Since(start))
49 }
50 }
51
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)
59 if err != nil {
60 return ""
61 }
62 defer f.Close()
63
64 var src [4 << 10]byte // read at most 4KB
65 n, _ := f.Read(src[:])
66
67 var first string
68 var s scanner.Scanner
69 s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil /* ignore errors */, scanner.ScanComments)
70 for {
71 _, tok, lit := s.Scan()
72 switch tok {
73 case token.COMMENT:
74 // remove trailing */ of multi-line comment
75 if lit[1] == '*' {
76 lit = lit[:len(lit)-2]
77 }
78 contents := strings.TrimSpace(lit[2:])
79 if strings.HasPrefix(contents, "+build ") {
80 return "skip"
81 }
82 if first == "" {
83 first = contents // contents may be "" but that's ok
84 }
85 // continue as we may still see build tags
86
87 case token.PACKAGE, token.EOF:
88 return first
89 }
90 }
91 }
92
93 func testTestDir(t *testing.T, path string, ignore ...string) {
94 t.Skip("skipping for gccgo")
95
96 files, err := ioutil.ReadDir(path)
97 if err != nil {
98 t.Fatal(err)
99 }
100
101 excluded := make(map[string]bool)
102 for _, filename := range ignore {
103 excluded[filename] = true
104 }
105
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()] {
110 continue
111 }
112
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)
118 switch fields[0] {
119 case "skip", "compiledir":
120 continue // ignore this file
121 case "errorcheck":
122 expectErrors = true
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.
129 expectErrors = false
130 break
131 }
132 }
133 }
134 }
135
136 // parse and type-check file
137 file, err := parser.ParseFile(fset, filename, nil, 0)
138 if err == nil {
139 conf := Config{Importer: stdLibImporter}
140 _, err = conf.Check(filename, fset, []*ast.File{file}, nil)
141 }
142
143 if expectErrors {
144 if err == nil {
145 t.Errorf("expected errors but found none in %s", filename)
146 }
147 } else {
148 if err != nil {
149 t.Error(err)
150 }
151 }
152 }
153 }
154
155 func TestStdTest(t *testing.T) {
156 testenv.MustHaveGoBuild(t)
157
158 if testing.Short() && testenv.Builder() == "" {
159 t.Skip("skipping in short mode")
160 }
161
162 testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
163 "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
164 )
165 }
166
167 func TestStdFixed(t *testing.T) {
168 testenv.MustHaveGoBuild(t)
169
170 if testing.Short() && testenv.Builder() == "" {
171 t.Skip("skipping in short mode")
172 }
173
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
191 )
192 }
193
194 func TestStdKen(t *testing.T) {
195 testenv.MustHaveGoBuild(t)
196
197 testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
198 }
199
200 // Package paths of excluded packages.
201 var excluded = map[string]bool{
202 "builtin": true,
203 }
204
205 // typecheck typechecks the given package files.
206 func typecheck(t *testing.T, path string, filenames []string) {
207 t.Skip("skipping for gccgo")
208
209 fset := token.NewFileSet()
210
211 // parse package files
212 var files []*ast.File
213 for _, filename := range filenames {
214 file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
215 if err != nil {
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 {
219 t.Error(err)
220 }
221 return
222 }
223 t.Error(err)
224 return
225 }
226
227 if testing.Verbose() {
228 if len(files) == 0 {
229 fmt.Println("package", file.Name.Name)
230 }
231 fmt.Println("\t", filename)
232 }
233
234 files = append(files, file)
235 }
236
237 // typecheck package files
238 conf := Config{
239 Error: func(err error) { t.Error(err) },
240 Importer: stdLibImporter,
241 }
242 info := Info{Uses: make(map[*ast.Ident]Object)}
243 conf.Check(path, fset, files, &info)
244 pkgCount++
245
246 // Perform checks of API invariants.
247
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())
254 if predeclared {
255 t.Errorf("%s: predeclared object with package: %s", posn, obj)
256 } else {
257 t.Errorf("%s: user-defined object without package: %s", posn, obj)
258 }
259 }
260 }
261 }
262
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)
268 if err != nil {
269 if _, nogo := err.(*build.NoGoError); nogo {
270 return nil, nil // no *.go files, not an error
271 }
272 return nil, err
273 }
274 if excluded[pkg.ImportPath] {
275 return nil, nil
276 }
277 var filenames []string
278 for _, name := range pkg.GoFiles {
279 filenames = append(filenames, filepath.Join(pkg.Dir, name))
280 }
281 for _, name := range pkg.TestGoFiles {
282 filenames = append(filenames, filepath.Join(pkg.Dir, name))
283 }
284 return filenames, nil
285 }
286
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.
290
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 {
294 return
295 }
296
297 fis, err := ioutil.ReadDir(dir)
298 if err != nil {
299 t.Error(err)
300 return
301 }
302
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)
307 if err != nil {
308 t.Error(err)
309 return
310 }
311 if files != nil {
312 typecheck(t, dir, files)
313 }
314 }
315
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()))
320 }
321 }
322 }