libgo: update to go1.9
[official-gcc.git] / libgo / go / go / parser / parser_test.go
blobfb35a88ba1aa5565614762df24193cb237584dff
1 // Copyright 2009 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 package parser
7 import (
8 "bytes"
9 "fmt"
10 "go/ast"
11 "go/token"
12 "os"
13 "strings"
14 "testing"
17 var validFiles = []string{
18 "parser.go",
19 "parser_test.go",
20 "error_test.go",
21 "short_test.go",
24 func TestParse(t *testing.T) {
25 for _, filename := range validFiles {
26 _, err := ParseFile(token.NewFileSet(), filename, nil, DeclarationErrors)
27 if err != nil {
28 t.Fatalf("ParseFile(%s): %v", filename, err)
33 func nameFilter(filename string) bool {
34 switch filename {
35 case "parser.go", "interface.go", "parser_test.go":
36 return true
37 case "parser.go.orig":
38 return true // permit but should be ignored by ParseDir
40 return false
43 func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) }
45 func TestParseDir(t *testing.T) {
46 path := "."
47 pkgs, err := ParseDir(token.NewFileSet(), path, dirFilter, 0)
48 if err != nil {
49 t.Fatalf("ParseDir(%s): %v", path, err)
51 if n := len(pkgs); n != 1 {
52 t.Errorf("got %d packages; want 1", n)
54 pkg := pkgs["parser"]
55 if pkg == nil {
56 t.Errorf(`package "parser" not found`)
57 return
59 if n := len(pkg.Files); n != 3 {
60 t.Errorf("got %d package files; want 3", n)
62 for filename := range pkg.Files {
63 if !nameFilter(filename) {
64 t.Errorf("unexpected package file: %s", filename)
69 func TestParseExpr(t *testing.T) {
70 // just kicking the tires:
71 // a valid arithmetic expression
72 src := "a + b"
73 x, err := ParseExpr(src)
74 if err != nil {
75 t.Errorf("ParseExpr(%q): %v", src, err)
77 // sanity check
78 if _, ok := x.(*ast.BinaryExpr); !ok {
79 t.Errorf("ParseExpr(%q): got %T, want *ast.BinaryExpr", src, x)
82 // a valid type expression
83 src = "struct{x *int}"
84 x, err = ParseExpr(src)
85 if err != nil {
86 t.Errorf("ParseExpr(%q): %v", src, err)
88 // sanity check
89 if _, ok := x.(*ast.StructType); !ok {
90 t.Errorf("ParseExpr(%q): got %T, want *ast.StructType", src, x)
93 // an invalid expression
94 src = "a + *"
95 if _, err := ParseExpr(src); err == nil {
96 t.Errorf("ParseExpr(%q): got no error", src)
99 // a valid expression followed by extra tokens is invalid
100 src = "a[i] := x"
101 if _, err := ParseExpr(src); err == nil {
102 t.Errorf("ParseExpr(%q): got no error", src)
105 // a semicolon is not permitted unless automatically inserted
106 src = "a + b\n"
107 if _, err := ParseExpr(src); err != nil {
108 t.Errorf("ParseExpr(%q): got error %s", src, err)
110 src = "a + b;"
111 if _, err := ParseExpr(src); err == nil {
112 t.Errorf("ParseExpr(%q): got no error", src)
115 // various other stuff following a valid expression
116 const validExpr = "a + b"
117 const anything = "dh3*#D)#_"
118 for _, c := range "!)]};," {
119 src := validExpr + string(c) + anything
120 if _, err := ParseExpr(src); err == nil {
121 t.Errorf("ParseExpr(%q): got no error", src)
125 // ParseExpr must not crash
126 for _, src := range valids {
127 ParseExpr(src)
131 func TestColonEqualsScope(t *testing.T) {
132 f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { x, y, z := x, y, z }`, 0)
133 if err != nil {
134 t.Fatal(err)
137 // RHS refers to undefined globals; LHS does not.
138 as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt)
139 for _, v := range as.Rhs {
140 id := v.(*ast.Ident)
141 if id.Obj != nil {
142 t.Errorf("rhs %s has Obj, should not", id.Name)
145 for _, v := range as.Lhs {
146 id := v.(*ast.Ident)
147 if id.Obj == nil {
148 t.Errorf("lhs %s does not have Obj, should", id.Name)
153 func TestVarScope(t *testing.T) {
154 f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { var x, y, z = x, y, z }`, 0)
155 if err != nil {
156 t.Fatal(err)
159 // RHS refers to undefined globals; LHS does not.
160 as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.DeclStmt).Decl.(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
161 for _, v := range as.Values {
162 id := v.(*ast.Ident)
163 if id.Obj != nil {
164 t.Errorf("rhs %s has Obj, should not", id.Name)
167 for _, id := range as.Names {
168 if id.Obj == nil {
169 t.Errorf("lhs %s does not have Obj, should", id.Name)
174 func TestObjects(t *testing.T) {
175 const src = `
176 package p
177 import fmt "fmt"
178 const pi = 3.14
179 type T struct{}
180 var x int
181 func f() { L: }
184 f, err := ParseFile(token.NewFileSet(), "", src, 0)
185 if err != nil {
186 t.Fatal(err)
189 objects := map[string]ast.ObjKind{
190 "p": ast.Bad, // not in a scope
191 "fmt": ast.Bad, // not resolved yet
192 "pi": ast.Con,
193 "T": ast.Typ,
194 "x": ast.Var,
195 "int": ast.Bad, // not resolved yet
196 "f": ast.Fun,
197 "L": ast.Lbl,
200 ast.Inspect(f, func(n ast.Node) bool {
201 if ident, ok := n.(*ast.Ident); ok {
202 obj := ident.Obj
203 if obj == nil {
204 if objects[ident.Name] != ast.Bad {
205 t.Errorf("no object for %s", ident.Name)
207 return true
209 if obj.Name != ident.Name {
210 t.Errorf("names don't match: obj.Name = %s, ident.Name = %s", obj.Name, ident.Name)
212 kind := objects[ident.Name]
213 if obj.Kind != kind {
214 t.Errorf("%s: obj.Kind = %s; want %s", ident.Name, obj.Kind, kind)
217 return true
221 func TestUnresolved(t *testing.T) {
222 f, err := ParseFile(token.NewFileSet(), "", `
223 package p
225 func f1a(int)
226 func f2a(byte, int, float)
227 func f3a(a, b int, c float)
228 func f4a(...complex)
229 func f5a(a s1a, b ...complex)
231 func f1b(*int)
232 func f2b([]byte, (int), *float)
233 func f3b(a, b *int, c []float)
234 func f4b(...*complex)
235 func f5b(a s1a, b ...[]complex)
237 type s1a struct { int }
238 type s2a struct { byte; int; s1a }
239 type s3a struct { a, b int; c float }
241 type s1b struct { *int }
242 type s2b struct { byte; int; *float }
243 type s3b struct { a, b *s3b; c []float }
244 `, 0)
245 if err != nil {
246 t.Fatal(err)
249 want := "int " + // f1a
250 "byte int float " + // f2a
251 "int float " + // f3a
252 "complex " + // f4a
253 "complex " + // f5a
255 "int " + // f1b
256 "byte int float " + // f2b
257 "int float " + // f3b
258 "complex " + // f4b
259 "complex " + // f5b
261 "int " + // s1a
262 "byte int " + // s2a
263 "int float " + // s3a
265 "int " + // s1a
266 "byte int float " + // s2a
267 "float " // s3a
269 // collect unresolved identifiers
270 var buf bytes.Buffer
271 for _, u := range f.Unresolved {
272 buf.WriteString(u.Name)
273 buf.WriteByte(' ')
275 got := buf.String()
277 if got != want {
278 t.Errorf("\ngot: %s\nwant: %s", got, want)
282 var imports = map[string]bool{
283 `"a"`: true,
284 "`a`": true,
285 `"a/b"`: true,
286 `"a.b"`: true,
287 `"m\x61th"`: true,
288 `"greek/αβ"`: true,
289 `""`: false,
291 // Each of these pairs tests both `` vs "" strings
292 // and also use of invalid characters spelled out as
293 // escape sequences and written directly.
294 // For example `"\x00"` tests import "\x00"
295 // while "`\x00`" tests import `<actual-NUL-byte>`.
296 `"\x00"`: false,
297 "`\x00`": false,
298 `"\x7f"`: false,
299 "`\x7f`": false,
300 `"a!"`: false,
301 "`a!`": false,
302 `"a b"`: false,
303 "`a b`": false,
304 `"a\\b"`: false,
305 "`a\\b`": false,
306 "\"`a`\"": false,
307 "`\"a\"`": false,
308 `"\x80\x80"`: false,
309 "`\x80\x80`": false,
310 `"\xFFFD"`: false,
311 "`\xFFFD`": false,
314 func TestImports(t *testing.T) {
315 for path, isValid := range imports {
316 src := fmt.Sprintf("package p; import %s", path)
317 _, err := ParseFile(token.NewFileSet(), "", src, 0)
318 switch {
319 case err != nil && isValid:
320 t.Errorf("ParseFile(%s): got %v; expected no error", src, err)
321 case err == nil && !isValid:
322 t.Errorf("ParseFile(%s): got no error; expected one", src)
327 func TestCommentGroups(t *testing.T) {
328 f, err := ParseFile(token.NewFileSet(), "", `
329 package p /* 1a */ /* 1b */ /* 1c */ // 1d
330 /* 2a
332 // 2b
333 const pi = 3.1415
334 /* 3a */ // 3b
335 /* 3c */ const e = 2.7182
337 // Example from issue 3139
338 func ExampleCount() {
339 fmt.Println(strings.Count("cheese", "e"))
340 fmt.Println(strings.Count("five", "")) // before & after each rune
341 // Output:
342 // 3
343 // 5
345 `, ParseComments)
346 if err != nil {
347 t.Fatal(err)
349 expected := [][]string{
350 {"/* 1a */", "/* 1b */", "/* 1c */", "// 1d"},
351 {"/* 2a\n*/", "// 2b"},
352 {"/* 3a */", "// 3b", "/* 3c */"},
353 {"// Example from issue 3139"},
354 {"// before & after each rune"},
355 {"// Output:", "// 3", "// 5"},
357 if len(f.Comments) != len(expected) {
358 t.Fatalf("got %d comment groups; expected %d", len(f.Comments), len(expected))
360 for i, exp := range expected {
361 got := f.Comments[i].List
362 if len(got) != len(exp) {
363 t.Errorf("got %d comments in group %d; expected %d", len(got), i, len(exp))
364 continue
366 for j, exp := range exp {
367 got := got[j].Text
368 if got != exp {
369 t.Errorf("got %q in group %d; expected %q", got, i, exp)
375 func getField(file *ast.File, fieldname string) *ast.Field {
376 parts := strings.Split(fieldname, ".")
377 for _, d := range file.Decls {
378 if d, ok := d.(*ast.GenDecl); ok && d.Tok == token.TYPE {
379 for _, s := range d.Specs {
380 if s, ok := s.(*ast.TypeSpec); ok && s.Name.Name == parts[0] {
381 if s, ok := s.Type.(*ast.StructType); ok {
382 for _, f := range s.Fields.List {
383 for _, name := range f.Names {
384 if name.Name == parts[1] {
385 return f
394 return nil
397 // Don't use ast.CommentGroup.Text() - we want to see exact comment text.
398 func commentText(c *ast.CommentGroup) string {
399 var buf bytes.Buffer
400 if c != nil {
401 for _, c := range c.List {
402 buf.WriteString(c.Text)
405 return buf.String()
408 func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line string) {
409 f := getField(file, fieldname)
410 if f == nil {
411 t.Fatalf("field not found: %s", fieldname)
413 if got := commentText(f.Doc); got != lead {
414 t.Errorf("got lead comment %q; expected %q", got, lead)
416 if got := commentText(f.Comment); got != line {
417 t.Errorf("got line comment %q; expected %q", got, line)
421 func TestLeadAndLineComments(t *testing.T) {
422 f, err := ParseFile(token.NewFileSet(), "", `
423 package p
424 type T struct {
425 /* F1 lead comment */
427 F1 int /* F1 */ // line comment
428 // F2 lead
429 // comment
430 F2 int // F2 line comment
431 // f3 lead comment
432 f3 int // f3 line comment
434 `, ParseComments)
435 if err != nil {
436 t.Fatal(err)
438 checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
439 checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment")
440 checkFieldComments(t, f, "T.f3", "// f3 lead comment", "// f3 line comment")
441 ast.FileExports(f)
442 checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
443 checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment")
444 if getField(f, "T.f3") != nil {
445 t.Error("not expected to find T.f3")
449 // TestIssue9979 verifies that empty statements are contained within their enclosing blocks.
450 func TestIssue9979(t *testing.T) {
451 for _, src := range []string{
452 "package p; func f() {;}",
453 "package p; func f() {L:}",
454 "package p; func f() {L:;}",
455 "package p; func f() {L:\n}",
456 "package p; func f() {L:\n;}",
457 "package p; func f() { ; }",
458 "package p; func f() { L: }",
459 "package p; func f() { L: ; }",
460 "package p; func f() { L: \n}",
461 "package p; func f() { L: \n; }",
463 fset := token.NewFileSet()
464 f, err := ParseFile(fset, "", src, 0)
465 if err != nil {
466 t.Fatal(err)
469 var pos, end token.Pos
470 ast.Inspect(f, func(x ast.Node) bool {
471 switch s := x.(type) {
472 case *ast.BlockStmt:
473 pos, end = s.Pos()+1, s.End()-1 // exclude "{", "}"
474 case *ast.LabeledStmt:
475 pos, end = s.Pos()+2, s.End() // exclude "L:"
476 case *ast.EmptyStmt:
477 // check containment
478 if s.Pos() < pos || s.End() > end {
479 t.Errorf("%s: %T[%d, %d] not inside [%d, %d]", src, s, s.Pos(), s.End(), pos, end)
481 // check semicolon
482 offs := fset.Position(s.Pos()).Offset
483 if ch := src[offs]; ch != ';' != s.Implicit {
484 want := "want ';'"
485 if s.Implicit {
486 want = "but ';' is implicit"
488 t.Errorf("%s: found %q at offset %d; %s", src, ch, offs, want)
491 return true
496 // TestIncompleteSelection ensures that an incomplete selector
497 // expression is parsed as a (blank) *ast.SelectorExpr, not a
498 // *ast.BadExpr.
499 func TestIncompleteSelection(t *testing.T) {
500 for _, src := range []string{
501 "package p; var _ = fmt.", // at EOF
502 "package p; var _ = fmt.\ntype X int", // not at EOF
504 fset := token.NewFileSet()
505 f, err := ParseFile(fset, "", src, 0)
506 if err == nil {
507 t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
508 continue
511 const wantErr = "expected selector or type assertion"
512 if !strings.Contains(err.Error(), wantErr) {
513 t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr)
516 var sel *ast.SelectorExpr
517 ast.Inspect(f, func(n ast.Node) bool {
518 if n, ok := n.(*ast.SelectorExpr); ok {
519 sel = n
521 return true
523 if sel == nil {
524 t.Error("found no *ast.SelectorExpr")
525 continue
527 const wantSel = "&{fmt _}"
528 if fmt.Sprint(sel) != wantSel {
529 t.Errorf("found selector %s, want %s", sel, wantSel)
530 continue
535 func TestLastLineComment(t *testing.T) {
536 const src = `package main
537 type x int // comment
539 fset := token.NewFileSet()
540 f, err := ParseFile(fset, "", src, ParseComments)
541 if err != nil {
542 t.Fatal(err)
544 comment := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.TypeSpec).Comment.List[0].Text
545 if comment != "// comment" {
546 t.Errorf("got %q, want %q", comment, "// comment")