Source file
src/go/parser/parser_test.go
1
2
3
4
5 package parser
6
7 import (
8 "bytes"
9 "fmt"
10 "go/ast"
11 "go/token"
12 "io/fs"
13 "strings"
14 "testing"
15 )
16
17 var validFiles = []string{
18 "parser.go",
19 "parser_test.go",
20 "error_test.go",
21 "short_test.go",
22 }
23
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)
29 }
30 }
31 }
32
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
39 }
40 return false
41 }
42
43 func dirFilter(f fs.FileInfo) bool { return nameFilter(f.Name()) }
44
45 func TestParseFile(t *testing.T) {
46 src := "package p\nvar _=s[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]"
47 _, err := ParseFile(token.NewFileSet(), "", src, 0)
48 if err == nil {
49 t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
50 }
51 }
52
53 func TestParseExprFrom(t *testing.T) {
54 src := "s[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]"
55 _, err := ParseExprFrom(token.NewFileSet(), "", src, 0)
56 if err == nil {
57 t.Errorf("ParseExprFrom(%s) succeeded unexpectedly", src)
58 }
59 }
60
61 func TestParseDir(t *testing.T) {
62 path := "."
63 pkgs, err := ParseDir(token.NewFileSet(), path, dirFilter, 0)
64 if err != nil {
65 t.Fatalf("ParseDir(%s): %v", path, err)
66 }
67 if n := len(pkgs); n != 1 {
68 t.Errorf("got %d packages; want 1", n)
69 }
70 pkg := pkgs["parser"]
71 if pkg == nil {
72 t.Errorf(`package "parser" not found`)
73 return
74 }
75 if n := len(pkg.Files); n != 3 {
76 t.Errorf("got %d package files; want 3", n)
77 }
78 for filename := range pkg.Files {
79 if !nameFilter(filename) {
80 t.Errorf("unexpected package file: %s", filename)
81 }
82 }
83 }
84
85 func TestIssue42951(t *testing.T) {
86 path := "./testdata/issue42951"
87 _, err := ParseDir(token.NewFileSet(), path, nil, 0)
88 if err != nil {
89 t.Errorf("ParseDir(%s): %v", path, err)
90 }
91 }
92
93 func TestParseExpr(t *testing.T) {
94
95
96 src := "a + b"
97 x, err := ParseExpr(src)
98 if err != nil {
99 t.Errorf("ParseExpr(%q): %v", src, err)
100 }
101
102 if _, ok := x.(*ast.BinaryExpr); !ok {
103 t.Errorf("ParseExpr(%q): got %T, want *ast.BinaryExpr", src, x)
104 }
105
106
107 src = "struct{x *int}"
108 x, err = ParseExpr(src)
109 if err != nil {
110 t.Errorf("ParseExpr(%q): %v", src, err)
111 }
112
113 if _, ok := x.(*ast.StructType); !ok {
114 t.Errorf("ParseExpr(%q): got %T, want *ast.StructType", src, x)
115 }
116
117
118 src = "a + *"
119 x, err = ParseExpr(src)
120 if err == nil {
121 t.Errorf("ParseExpr(%q): got no error", src)
122 }
123 if x == nil {
124 t.Errorf("ParseExpr(%q): got no (partial) result", src)
125 }
126 if _, ok := x.(*ast.BinaryExpr); !ok {
127 t.Errorf("ParseExpr(%q): got %T, want *ast.BinaryExpr", src, x)
128 }
129
130
131 src = "a[i] := x"
132 if _, err := ParseExpr(src); err == nil {
133 t.Errorf("ParseExpr(%q): got no error", src)
134 }
135
136
137 src = "a + b\n"
138 if _, err := ParseExpr(src); err != nil {
139 t.Errorf("ParseExpr(%q): got error %s", src, err)
140 }
141 src = "a + b;"
142 if _, err := ParseExpr(src); err == nil {
143 t.Errorf("ParseExpr(%q): got no error", src)
144 }
145
146
147 const validExpr = "a + b"
148 const anything = "dh3*#D)#_"
149 for _, c := range "!)]};," {
150 src := validExpr + string(c) + anything
151 if _, err := ParseExpr(src); err == nil {
152 t.Errorf("ParseExpr(%q): got no error", src)
153 }
154 }
155
156
157 for _, src := range valids {
158 ParseExpr(src)
159 }
160 }
161
162 func TestColonEqualsScope(t *testing.T) {
163 f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { x, y, z := x, y, z }`, 0)
164 if err != nil {
165 t.Fatal(err)
166 }
167
168
169 as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt)
170 for _, v := range as.Rhs {
171 id := v.(*ast.Ident)
172 if id.Obj != nil {
173 t.Errorf("rhs %s has Obj, should not", id.Name)
174 }
175 }
176 for _, v := range as.Lhs {
177 id := v.(*ast.Ident)
178 if id.Obj == nil {
179 t.Errorf("lhs %s does not have Obj, should", id.Name)
180 }
181 }
182 }
183
184 func TestVarScope(t *testing.T) {
185 f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { var x, y, z = x, y, z }`, 0)
186 if err != nil {
187 t.Fatal(err)
188 }
189
190
191 as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.DeclStmt).Decl.(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
192 for _, v := range as.Values {
193 id := v.(*ast.Ident)
194 if id.Obj != nil {
195 t.Errorf("rhs %s has Obj, should not", id.Name)
196 }
197 }
198 for _, id := range as.Names {
199 if id.Obj == nil {
200 t.Errorf("lhs %s does not have Obj, should", id.Name)
201 }
202 }
203 }
204
205 func TestObjects(t *testing.T) {
206 const src = `
207 package p
208 import fmt "fmt"
209 const pi = 3.14
210 type T struct{}
211 var x int
212 func f() { L: }
213 `
214
215 f, err := ParseFile(token.NewFileSet(), "", src, 0)
216 if err != nil {
217 t.Fatal(err)
218 }
219
220 objects := map[string]ast.ObjKind{
221 "p": ast.Bad,
222 "fmt": ast.Bad,
223 "pi": ast.Con,
224 "T": ast.Typ,
225 "x": ast.Var,
226 "int": ast.Bad,
227 "f": ast.Fun,
228 "L": ast.Lbl,
229 }
230
231 ast.Inspect(f, func(n ast.Node) bool {
232 if ident, ok := n.(*ast.Ident); ok {
233 obj := ident.Obj
234 if obj == nil {
235 if objects[ident.Name] != ast.Bad {
236 t.Errorf("no object for %s", ident.Name)
237 }
238 return true
239 }
240 if obj.Name != ident.Name {
241 t.Errorf("names don't match: obj.Name = %s, ident.Name = %s", obj.Name, ident.Name)
242 }
243 kind := objects[ident.Name]
244 if obj.Kind != kind {
245 t.Errorf("%s: obj.Kind = %s; want %s", ident.Name, obj.Kind, kind)
246 }
247 }
248 return true
249 })
250 }
251
252 func TestUnresolved(t *testing.T) {
253 f, err := ParseFile(token.NewFileSet(), "", `
254 package p
255 //
256 func f1a(int)
257 func f2a(byte, int, float)
258 func f3a(a, b int, c float)
259 func f4a(...complex)
260 func f5a(a s1a, b ...complex)
261 //
262 func f1b(*int)
263 func f2b([]byte, (int), *float)
264 func f3b(a, b *int, c []float)
265 func f4b(...*complex)
266 func f5b(a s1a, b ...[]complex)
267 //
268 type s1a struct { int }
269 type s2a struct { byte; int; s1a }
270 type s3a struct { a, b int; c float }
271 //
272 type s1b struct { *int }
273 type s2b struct { byte; int; *float }
274 type s3b struct { a, b *s3b; c []float }
275 `, 0)
276 if err != nil {
277 t.Fatal(err)
278 }
279
280 want := "int " +
281 "byte int float " +
282 "int float " +
283 "complex " +
284 "complex " +
285
286 "int " +
287 "byte int float " +
288 "int float " +
289 "complex " +
290 "complex " +
291
292 "int " +
293 "byte int " +
294 "int float " +
295
296 "int " +
297 "byte int float " +
298 "float "
299
300
301 var buf bytes.Buffer
302 for _, u := range f.Unresolved {
303 buf.WriteString(u.Name)
304 buf.WriteByte(' ')
305 }
306 got := buf.String()
307
308 if got != want {
309 t.Errorf("\ngot: %s\nwant: %s", got, want)
310 }
311 }
312
313 var imports = map[string]bool{
314 `"a"`: true,
315 "`a`": true,
316 `"a/b"`: true,
317 `"a.b"`: true,
318 `"m\x61th"`: true,
319 `"greek/αβ"`: true,
320 `""`: false,
321
322
323
324
325
326
327 `"\x00"`: false,
328 "`\x00`": false,
329 `"\x7f"`: false,
330 "`\x7f`": false,
331 `"a!"`: false,
332 "`a!`": false,
333 `"a b"`: false,
334 "`a b`": false,
335 `"a\\b"`: false,
336 "`a\\b`": false,
337 "\"`a`\"": false,
338 "`\"a\"`": false,
339 `"\x80\x80"`: false,
340 "`\x80\x80`": false,
341 `"\xFFFD"`: false,
342 "`\xFFFD`": false,
343 }
344
345 func TestImports(t *testing.T) {
346 for path, isValid := range imports {
347 src := fmt.Sprintf("package p; import %s", path)
348 _, err := ParseFile(token.NewFileSet(), "", src, 0)
349 switch {
350 case err != nil && isValid:
351 t.Errorf("ParseFile(%s): got %v; expected no error", src, err)
352 case err == nil && !isValid:
353 t.Errorf("ParseFile(%s): got no error; expected one", src)
354 }
355 }
356 }
357
358 func TestCommentGroups(t *testing.T) {
359 f, err := ParseFile(token.NewFileSet(), "", `
360 package p /* 1a */ /* 1b */ /* 1c */ // 1d
361 /* 2a
362 */
363 // 2b
364 const pi = 3.1415
365 /* 3a */ // 3b
366 /* 3c */ const e = 2.7182
367
368 // Example from issue 3139
369 func ExampleCount() {
370 fmt.Println(strings.Count("cheese", "e"))
371 fmt.Println(strings.Count("five", "")) // before & after each rune
372 // Output:
373 // 3
374 // 5
375 }
376 `, ParseComments)
377 if err != nil {
378 t.Fatal(err)
379 }
380 expected := [][]string{
381 {"/* 1a */", "/* 1b */", "/* 1c */", "// 1d"},
382 {"/* 2a\n*/", "// 2b"},
383 {"/* 3a */", "// 3b", "/* 3c */"},
384 {"// Example from issue 3139"},
385 {"// before & after each rune"},
386 {"// Output:", "// 3", "// 5"},
387 }
388 if len(f.Comments) != len(expected) {
389 t.Fatalf("got %d comment groups; expected %d", len(f.Comments), len(expected))
390 }
391 for i, exp := range expected {
392 got := f.Comments[i].List
393 if len(got) != len(exp) {
394 t.Errorf("got %d comments in group %d; expected %d", len(got), i, len(exp))
395 continue
396 }
397 for j, exp := range exp {
398 got := got[j].Text
399 if got != exp {
400 t.Errorf("got %q in group %d; expected %q", got, i, exp)
401 }
402 }
403 }
404 }
405
406 func getField(file *ast.File, fieldname string) *ast.Field {
407 parts := strings.Split(fieldname, ".")
408 for _, d := range file.Decls {
409 if d, ok := d.(*ast.GenDecl); ok && d.Tok == token.TYPE {
410 for _, s := range d.Specs {
411 if s, ok := s.(*ast.TypeSpec); ok && s.Name.Name == parts[0] {
412 if s, ok := s.Type.(*ast.StructType); ok {
413 for _, f := range s.Fields.List {
414 for _, name := range f.Names {
415 if name.Name == parts[1] {
416 return f
417 }
418 }
419 }
420 }
421 }
422 }
423 }
424 }
425 return nil
426 }
427
428
429 func commentText(c *ast.CommentGroup) string {
430 var buf bytes.Buffer
431 if c != nil {
432 for _, c := range c.List {
433 buf.WriteString(c.Text)
434 }
435 }
436 return buf.String()
437 }
438
439 func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line string) {
440 f := getField(file, fieldname)
441 if f == nil {
442 t.Fatalf("field not found: %s", fieldname)
443 }
444 if got := commentText(f.Doc); got != lead {
445 t.Errorf("got lead comment %q; expected %q", got, lead)
446 }
447 if got := commentText(f.Comment); got != line {
448 t.Errorf("got line comment %q; expected %q", got, line)
449 }
450 }
451
452 func TestLeadAndLineComments(t *testing.T) {
453 f, err := ParseFile(token.NewFileSet(), "", `
454 package p
455 type T struct {
456 /* F1 lead comment */
457 //
458 F1 int /* F1 */ // line comment
459 // F2 lead
460 // comment
461 F2 int // F2 line comment
462 // f3 lead comment
463 f3 int // f3 line comment
464 }
465 `, ParseComments)
466 if err != nil {
467 t.Fatal(err)
468 }
469 checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
470 checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment")
471 checkFieldComments(t, f, "T.f3", "// f3 lead comment", "// f3 line comment")
472 ast.FileExports(f)
473 checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
474 checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment")
475 if getField(f, "T.f3") != nil {
476 t.Error("not expected to find T.f3")
477 }
478 }
479
480
481 func TestIssue9979(t *testing.T) {
482 for _, src := range []string{
483 "package p; func f() {;}",
484 "package p; func f() {L:}",
485 "package p; func f() {L:;}",
486 "package p; func f() {L:\n}",
487 "package p; func f() {L:\n;}",
488 "package p; func f() { ; }",
489 "package p; func f() { L: }",
490 "package p; func f() { L: ; }",
491 "package p; func f() { L: \n}",
492 "package p; func f() { L: \n; }",
493 } {
494 fset := token.NewFileSet()
495 f, err := ParseFile(fset, "", src, 0)
496 if err != nil {
497 t.Fatal(err)
498 }
499
500 var pos, end token.Pos
501 ast.Inspect(f, func(x ast.Node) bool {
502 switch s := x.(type) {
503 case *ast.BlockStmt:
504 pos, end = s.Pos()+1, s.End()-1
505 case *ast.LabeledStmt:
506 pos, end = s.Pos()+2, s.End()
507 case *ast.EmptyStmt:
508
509 if s.Pos() < pos || s.End() > end {
510 t.Errorf("%s: %T[%d, %d] not inside [%d, %d]", src, s, s.Pos(), s.End(), pos, end)
511 }
512
513 offs := fset.Position(s.Pos()).Offset
514 if ch := src[offs]; ch != ';' != s.Implicit {
515 want := "want ';'"
516 if s.Implicit {
517 want = "but ';' is implicit"
518 }
519 t.Errorf("%s: found %q at offset %d; %s", src, ch, offs, want)
520 }
521 }
522 return true
523 })
524 }
525 }
526
527
528
529
530 func TestIncompleteSelection(t *testing.T) {
531 for _, src := range []string{
532 "package p; var _ = fmt.",
533 "package p; var _ = fmt.\ntype X int",
534 } {
535 fset := token.NewFileSet()
536 f, err := ParseFile(fset, "", src, 0)
537 if err == nil {
538 t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
539 continue
540 }
541
542 const wantErr = "expected selector or type assertion"
543 if !strings.Contains(err.Error(), wantErr) {
544 t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr)
545 }
546
547 var sel *ast.SelectorExpr
548 ast.Inspect(f, func(n ast.Node) bool {
549 if n, ok := n.(*ast.SelectorExpr); ok {
550 sel = n
551 }
552 return true
553 })
554 if sel == nil {
555 t.Error("found no *ast.SelectorExpr")
556 continue
557 }
558 const wantSel = "&{fmt _}"
559 if fmt.Sprint(sel) != wantSel {
560 t.Errorf("found selector %s, want %s", sel, wantSel)
561 continue
562 }
563 }
564 }
565
566 func TestLastLineComment(t *testing.T) {
567 const src = `package main
568 type x int // comment
569 `
570 fset := token.NewFileSet()
571 f, err := ParseFile(fset, "", src, ParseComments)
572 if err != nil {
573 t.Fatal(err)
574 }
575 comment := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.TypeSpec).Comment.List[0].Text
576 if comment != "// comment" {
577 t.Errorf("got %q, want %q", comment, "// comment")
578 }
579 }
580
View as plain text