Source file
src/go/parser/parser_test.go
1
2
3
4
5 package parser
6
7 import (
8 "fmt"
9 "go/ast"
10 "go/token"
11 "io/fs"
12 "reflect"
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 strings.Builder
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 func TestCommentGroups(t *testing.T) {
314 f, err := ParseFile(token.NewFileSet(), "", `
315 package p /* 1a */ /* 1b */ /* 1c */ // 1d
316 /* 2a
317 */
318 // 2b
319 const pi = 3.1415
320 /* 3a */ // 3b
321 /* 3c */ const e = 2.7182
322
323 // Example from go.dev/issue/3139
324 func ExampleCount() {
325 fmt.Println(strings.Count("cheese", "e"))
326 fmt.Println(strings.Count("five", "")) // before & after each rune
327 // Output:
328 // 3
329 // 5
330 }
331 `, ParseComments)
332 if err != nil {
333 t.Fatal(err)
334 }
335 expected := [][]string{
336 {"/* 1a */", "/* 1b */", "/* 1c */", "// 1d"},
337 {"/* 2a\n*/", "// 2b"},
338 {"/* 3a */", "// 3b", "/* 3c */"},
339 {"// Example from go.dev/issue/3139"},
340 {"// before & after each rune"},
341 {"// Output:", "// 3", "// 5"},
342 }
343 if len(f.Comments) != len(expected) {
344 t.Fatalf("got %d comment groups; expected %d", len(f.Comments), len(expected))
345 }
346 for i, exp := range expected {
347 got := f.Comments[i].List
348 if len(got) != len(exp) {
349 t.Errorf("got %d comments in group %d; expected %d", len(got), i, len(exp))
350 continue
351 }
352 for j, exp := range exp {
353 got := got[j].Text
354 if got != exp {
355 t.Errorf("got %q in group %d; expected %q", got, i, exp)
356 }
357 }
358 }
359 }
360
361 func getField(file *ast.File, fieldname string) *ast.Field {
362 parts := strings.Split(fieldname, ".")
363 for _, d := range file.Decls {
364 if d, ok := d.(*ast.GenDecl); ok && d.Tok == token.TYPE {
365 for _, s := range d.Specs {
366 if s, ok := s.(*ast.TypeSpec); ok && s.Name.Name == parts[0] {
367 if s, ok := s.Type.(*ast.StructType); ok {
368 for _, f := range s.Fields.List {
369 for _, name := range f.Names {
370 if name.Name == parts[1] {
371 return f
372 }
373 }
374 }
375 }
376 }
377 }
378 }
379 }
380 return nil
381 }
382
383
384 func commentText(c *ast.CommentGroup) string {
385 var buf strings.Builder
386 if c != nil {
387 for _, c := range c.List {
388 buf.WriteString(c.Text)
389 }
390 }
391 return buf.String()
392 }
393
394 func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line string) {
395 f := getField(file, fieldname)
396 if f == nil {
397 t.Fatalf("field not found: %s", fieldname)
398 }
399 if got := commentText(f.Doc); got != lead {
400 t.Errorf("got lead comment %q; expected %q", got, lead)
401 }
402 if got := commentText(f.Comment); got != line {
403 t.Errorf("got line comment %q; expected %q", got, line)
404 }
405 }
406
407 func TestLeadAndLineComments(t *testing.T) {
408 f, err := ParseFile(token.NewFileSet(), "", `
409 package p
410 type T struct {
411 /* F1 lead comment */
412 //
413 F1 int /* F1 */ // line comment
414 // F2 lead
415 // comment
416 F2 int // F2 line comment
417 // f3 lead comment
418 f3 int // f3 line comment
419
420 f4 int /* not a line comment */ ;
421 f5 int ; // f5 line comment
422 f6 int ; /* f6 line comment */
423 f7 int ; /*f7a*/ /*f7b*/ //f7c
424 }
425 `, ParseComments)
426 if err != nil {
427 t.Fatal(err)
428 }
429 checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
430 checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment")
431 checkFieldComments(t, f, "T.f3", "// f3 lead comment", "// f3 line comment")
432 checkFieldComments(t, f, "T.f4", "", "")
433 checkFieldComments(t, f, "T.f5", "", "// f5 line comment")
434 checkFieldComments(t, f, "T.f6", "", "/* f6 line comment */")
435 checkFieldComments(t, f, "T.f7", "", "/*f7a*//*f7b*///f7c")
436
437 ast.FileExports(f)
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 if getField(f, "T.f3") != nil {
441 t.Error("not expected to find T.f3")
442 }
443 }
444
445
446 func TestIssue9979(t *testing.T) {
447 for _, src := range []string{
448 "package p; func f() {;}",
449 "package p; func f() {L:}",
450 "package p; func f() {L:;}",
451 "package p; func f() {L:\n}",
452 "package p; func f() {L:\n;}",
453 "package p; func f() { ; }",
454 "package p; func f() { L: }",
455 "package p; func f() { L: ; }",
456 "package p; func f() { L: \n}",
457 "package p; func f() { L: \n; }",
458 } {
459 fset := token.NewFileSet()
460 f, err := ParseFile(fset, "", src, 0)
461 if err != nil {
462 t.Fatal(err)
463 }
464
465 var pos, end token.Pos
466 ast.Inspect(f, func(x ast.Node) bool {
467 switch s := x.(type) {
468 case *ast.BlockStmt:
469 pos, end = s.Pos()+1, s.End()-1
470 case *ast.LabeledStmt:
471 pos, end = s.Pos()+2, s.End()
472 case *ast.EmptyStmt:
473
474 if s.Pos() < pos || s.End() > end {
475 t.Errorf("%s: %T[%d, %d] not inside [%d, %d]", src, s, s.Pos(), s.End(), pos, end)
476 }
477
478 offs := fset.Position(s.Pos()).Offset
479 if ch := src[offs]; ch != ';' != s.Implicit {
480 want := "want ';'"
481 if s.Implicit {
482 want = "but ';' is implicit"
483 }
484 t.Errorf("%s: found %q at offset %d; %s", src, ch, offs, want)
485 }
486 }
487 return true
488 })
489 }
490 }
491
492 func TestFileStartEndPos(t *testing.T) {
493 const src = `// Copyright
494
495 //+build tag
496
497 // Package p doc comment.
498 package p
499
500 var lastDecl int
501
502 /* end of file */
503 `
504 fset := token.NewFileSet()
505 f, err := ParseFile(fset, "file.go", src, 0)
506 if err != nil {
507 t.Fatal(err)
508 }
509
510
511 if got, want := fset.Position(f.FileStart).String(), "file.go:1:1"; got != want {
512 t.Errorf("for File.FileStart, got %s, want %s", got, want)
513 }
514
515 if got, want := fset.Position(f.FileEnd).String(), "file.go:10:19"; got != want {
516 t.Errorf("for File.FileEnd, got %s, want %s", got, want)
517 }
518 }
519
520
521
522
523 func TestIncompleteSelection(t *testing.T) {
524 for _, src := range []string{
525 "package p; var _ = fmt.",
526 "package p; var _ = fmt.\ntype X int",
527 } {
528 fset := token.NewFileSet()
529 f, err := ParseFile(fset, "", src, 0)
530 if err == nil {
531 t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
532 continue
533 }
534
535 const wantErr = "expected selector or type assertion"
536 if !strings.Contains(err.Error(), wantErr) {
537 t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr)
538 }
539
540 var sel *ast.SelectorExpr
541 ast.Inspect(f, func(n ast.Node) bool {
542 if n, ok := n.(*ast.SelectorExpr); ok {
543 sel = n
544 }
545 return true
546 })
547 if sel == nil {
548 t.Error("found no *ast.SelectorExpr")
549 continue
550 }
551 const wantSel = "&{fmt _}"
552 if fmt.Sprint(sel) != wantSel {
553 t.Errorf("found selector %s, want %s", sel, wantSel)
554 continue
555 }
556 }
557 }
558
559 func TestLastLineComment(t *testing.T) {
560 const src = `package main
561 type x int // comment
562 `
563 fset := token.NewFileSet()
564 f, err := ParseFile(fset, "", src, ParseComments)
565 if err != nil {
566 t.Fatal(err)
567 }
568 comment := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.TypeSpec).Comment.List[0].Text
569 if comment != "// comment" {
570 t.Errorf("got %q, want %q", comment, "// comment")
571 }
572 }
573
574 var parseDepthTests = []struct {
575 name string
576 format string
577
578
579
580
581
582 parseMultiplier int
583
584
585 scope bool
586
587
588 scopeMultiplier int
589 }{
590
591
592
593 {name: "array", format: "package main; var x «[1]»int"},
594 {name: "slice", format: "package main; var x «[]»int"},
595 {name: "struct", format: "package main; var x «struct { X «int» }»", scope: true},
596 {name: "pointer", format: "package main; var x «*»int"},
597 {name: "func", format: "package main; var x «func()»int", scope: true},
598 {name: "chan", format: "package main; var x «chan »int"},
599 {name: "chan2", format: "package main; var x «<-chan »int"},
600 {name: "interface", format: "package main; var x «interface { M() «int» }»", scope: true, scopeMultiplier: 2},
601 {name: "map", format: "package main; var x «map[int]»int"},
602 {name: "slicelit", format: "package main; var x = []any{«[]any{«»}»}", parseMultiplier: 3},
603 {name: "arraylit", format: "package main; var x = «[1]any{«nil»}»", parseMultiplier: 3},
604 {name: "structlit", format: "package main; var x = «struct{x any}{«nil»}»", parseMultiplier: 3},
605 {name: "maplit", format: "package main; var x = «map[int]any{1:«nil»}»", parseMultiplier: 3},
606 {name: "element", format: "package main; var x = struct{x any}{x: «{«»}»}"},
607 {name: "dot", format: "package main; var x = «x.»x"},
608 {name: "index", format: "package main; var x = x«[1]»"},
609 {name: "slice", format: "package main; var x = x«[1:2]»"},
610 {name: "slice3", format: "package main; var x = x«[1:2:3]»"},
611 {name: "dottype", format: "package main; var x = x«.(any)»"},
612 {name: "callseq", format: "package main; var x = x«()»"},
613 {name: "methseq", format: "package main; var x = x«.m()»", parseMultiplier: 2},
614 {name: "binary", format: "package main; var x = «1+»1"},
615 {name: "binaryparen", format: "package main; var x = «1+(«1»)»", parseMultiplier: 2},
616 {name: "unary", format: "package main; var x = «^»1"},
617 {name: "addr", format: "package main; var x = «& »x"},
618 {name: "star", format: "package main; var x = «*»x"},
619 {name: "recv", format: "package main; var x = «<-»x"},
620 {name: "call", format: "package main; var x = «f(«1»)»", parseMultiplier: 2},
621 {name: "conv", format: "package main; var x = «(*T)(«1»)»", parseMultiplier: 2},
622 {name: "label", format: "package main; func main() { «Label:» }"},
623 {name: "if", format: "package main; func main() { «if true { «» }»}", parseMultiplier: 2, scope: true, scopeMultiplier: 2},
624 {name: "ifelse", format: "package main; func main() { «if true {} else » {} }", scope: true},
625 {name: "switch", format: "package main; func main() { «switch { default: «» }»}", scope: true, scopeMultiplier: 2},
626 {name: "typeswitch", format: "package main; func main() { «switch x.(type) { default: «» }» }", scope: true, scopeMultiplier: 2},
627 {name: "for0", format: "package main; func main() { «for { «» }» }", scope: true, scopeMultiplier: 2},
628 {name: "for1", format: "package main; func main() { «for x { «» }» }", scope: true, scopeMultiplier: 2},
629 {name: "for3", format: "package main; func main() { «for f(); g(); h() { «» }» }", scope: true, scopeMultiplier: 2},
630 {name: "forrange0", format: "package main; func main() { «for range x { «» }» }", scope: true, scopeMultiplier: 2},
631 {name: "forrange1", format: "package main; func main() { «for x = range z { «» }» }", scope: true, scopeMultiplier: 2},
632 {name: "forrange2", format: "package main; func main() { «for x, y = range z { «» }» }", scope: true, scopeMultiplier: 2},
633 {name: "go", format: "package main; func main() { «go func() { «» }()» }", parseMultiplier: 2, scope: true},
634 {name: "defer", format: "package main; func main() { «defer func() { «» }()» }", parseMultiplier: 2, scope: true},
635 {name: "select", format: "package main; func main() { «select { default: «» }» }", scope: true},
636 {name: "block", format: "package main; func main() { «{«»}» }", scope: true},
637 }
638
639
640
641 func split(x string) (pre, mid, post string) {
642 start, end := strings.Index(x, "«"), strings.LastIndex(x, "»")
643 if start < 0 || end < 0 {
644 return x, "", ""
645 }
646 return x[:start], x[start+len("«") : end], x[end+len("»"):]
647 }
648
649 func TestParseDepthLimit(t *testing.T) {
650 if testing.Short() {
651 t.Skip("test requires significant memory")
652 }
653 for _, tt := range parseDepthTests {
654 for _, size := range []string{"small", "big"} {
655 t.Run(tt.name+"/"+size, func(t *testing.T) {
656 n := maxNestLev + 1
657 if tt.parseMultiplier > 0 {
658 n /= tt.parseMultiplier
659 }
660 if size == "small" {
661
662
663
664
665
666 n -= 10
667 }
668
669 pre, mid, post := split(tt.format)
670 if strings.Contains(mid, "«") {
671 left, base, right := split(mid)
672 mid = strings.Repeat(left, n) + base + strings.Repeat(right, n)
673 } else {
674 mid = strings.Repeat(mid, n)
675 }
676 input := pre + mid + post
677
678 fset := token.NewFileSet()
679 _, err := ParseFile(fset, "", input, ParseComments|SkipObjectResolution)
680 if size == "small" {
681 if err != nil {
682 t.Errorf("ParseFile(...): %v (want success)", err)
683 }
684 } else {
685 expected := "exceeded max nesting depth"
686 if err == nil || !strings.HasSuffix(err.Error(), expected) {
687 t.Errorf("ParseFile(...) = _, %v, want %q", err, expected)
688 }
689 }
690 })
691 }
692 }
693 }
694
695 func TestScopeDepthLimit(t *testing.T) {
696 for _, tt := range parseDepthTests {
697 if !tt.scope {
698 continue
699 }
700 for _, size := range []string{"small", "big"} {
701 t.Run(tt.name+"/"+size, func(t *testing.T) {
702 n := maxScopeDepth + 1
703 if tt.scopeMultiplier > 0 {
704 n /= tt.scopeMultiplier
705 }
706 if size == "small" {
707
708
709
710
711
712 n -= 10
713 }
714
715 pre, mid, post := split(tt.format)
716 if strings.Contains(mid, "«") {
717 left, base, right := split(mid)
718 mid = strings.Repeat(left, n) + base + strings.Repeat(right, n)
719 } else {
720 mid = strings.Repeat(mid, n)
721 }
722 input := pre + mid + post
723
724 fset := token.NewFileSet()
725 _, err := ParseFile(fset, "", input, DeclarationErrors)
726 if size == "small" {
727 if err != nil {
728 t.Errorf("ParseFile(...): %v (want success)", err)
729 }
730 } else {
731 expected := "exceeded max scope depth during object resolution"
732 if err == nil || !strings.HasSuffix(err.Error(), expected) {
733 t.Errorf("ParseFile(...) = _, %v, want %q", err, expected)
734 }
735 }
736 })
737 }
738 }
739 }
740
741
742 func TestRangePos(t *testing.T) {
743 testcases := []string{
744 "package p; func _() { for range x {} }",
745 "package p; func _() { for i = range x {} }",
746 "package p; func _() { for i := range x {} }",
747 "package p; func _() { for k, v = range x {} }",
748 "package p; func _() { for k, v := range x {} }",
749 }
750
751 for _, src := range testcases {
752 fset := token.NewFileSet()
753 f, err := ParseFile(fset, src, src, 0)
754 if err != nil {
755 t.Fatal(err)
756 }
757
758 ast.Inspect(f, func(x ast.Node) bool {
759 switch s := x.(type) {
760 case *ast.RangeStmt:
761 pos := fset.Position(s.Range)
762 if pos.Offset != strings.Index(src, "range") {
763 t.Errorf("%s: got offset %v, want %v", src, pos.Offset, strings.Index(src, "range"))
764 }
765 }
766 return true
767 })
768 }
769 }
770
771
772 func TestIssue59180(t *testing.T) {
773 testcases := []string{
774 "package p\n//line :9223372036854775806\n\n//",
775 "package p\n//line :1:9223372036854775806\n\n//",
776 "package p\n//line file:9223372036854775806\n\n//",
777 }
778
779 for _, src := range testcases {
780 _, err := ParseFile(token.NewFileSet(), "", src, ParseComments)
781 if err == nil {
782 t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
783 }
784 }
785 }
786
787 func TestGoVersion(t *testing.T) {
788 fset := token.NewFileSet()
789 pkgs, err := ParseDir(fset, "./testdata/goversion", nil, 0)
790 if err != nil {
791 t.Fatal(err)
792 }
793
794 for _, p := range pkgs {
795 want := strings.ReplaceAll(p.Name, "_", ".")
796 if want == "none" {
797 want = ""
798 }
799 for _, f := range p.Files {
800 if f.GoVersion != want {
801 t.Errorf("%s: GoVersion = %q, want %q", fset.Position(f.Pos()), f.GoVersion, want)
802 }
803 }
804 }
805 }
806
807 func TestIssue57490(t *testing.T) {
808 src := `package p; func f() { var x struct`
809 fset := token.NewFileSet()
810 file, err := ParseFile(fset, "", src, 0)
811 if err == nil {
812 t.Fatalf("syntax error expected, but no error reported")
813 }
814
815
816
817 funcEnd := file.Decls[0].End()
818
819
820
821 tokFile := fset.File(file.Pos())
822 offset := tokFile.Offset(funcEnd)
823 if offset != tokFile.Size() {
824 t.Fatalf("offset = %d, want %d", offset, tokFile.Size())
825 }
826 }
827
828 func TestParseTypeParamsAsParenExpr(t *testing.T) {
829 const src = "package p; type X[A (B),] struct{}"
830
831 fset := token.NewFileSet()
832 f, err := ParseFile(fset, "test.go", src, ParseComments|SkipObjectResolution)
833 if err != nil {
834 t.Fatal(err)
835 }
836
837 typeParam := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.TypeSpec).TypeParams.List[0].Type
838 _, ok := typeParam.(*ast.ParenExpr)
839 if !ok {
840 t.Fatalf("typeParam is a %T; want: *ast.ParenExpr", typeParam)
841 }
842 }
843
844
845 func TestEmptyFileHasValidStartEnd(t *testing.T) {
846 for _, test := range []struct {
847 src string
848 want string
849 }{
850 {src: "", want: "0 1 1"},
851 {src: "package ", want: "0 1 9"},
852 {src: "package p", want: "1 1 10"},
853 {src: "type T int", want: "0 1 11"},
854 } {
855 fset := token.NewFileSet()
856 f, _ := ParseFile(fset, "a.go", test.src, 0)
857 got := fmt.Sprintf("%d %d %d", f.Pos(), f.FileStart, f.FileEnd)
858 if got != test.want {
859 t.Fatalf("src = %q: got %s, want %s", test.src, got, test.want)
860 }
861 }
862 }
863
864 func TestCommentGroupWithLineDirective(t *testing.T) {
865 const src = `package main
866 func test() {
867 //line a:15:1
868 //
869 }
870 `
871 fset := token.NewFileSet()
872 f, err := ParseFile(fset, "test.go", src, ParseComments|SkipObjectResolution)
873 if err != nil {
874 t.Fatal(err)
875 }
876
877 wantCommentGroups := []*ast.CommentGroup{
878 {
879 List: []*ast.Comment{
880 {
881 Slash: token.Pos(28),
882 Text: "//line a:15:1",
883 },
884 {
885 Slash: token.Pos(43),
886 Text: "//",
887 },
888 },
889 },
890 }
891
892 if !reflect.DeepEqual(f.Comments, wantCommentGroups) {
893 var got, want strings.Builder
894 ast.Fprint(&got, fset, f.Comments, nil)
895 ast.Fprint(&want, fset, wantCommentGroups, nil)
896 t.Fatalf("unexpected f.Comments got:\n%v\nwant:\n%v", got.String(), want.String())
897 }
898 }
899
View as plain text