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 "strings"
13 "testing"
14 )
15
16 var validFiles = []string{
17 "parser.go",
18 "parser_test.go",
19 "error_test.go",
20 "short_test.go",
21 }
22
23 func TestParse(t *testing.T) {
24 for _, filename := range validFiles {
25 _, err := ParseFile(token.NewFileSet(), filename, nil, DeclarationErrors)
26 if err != nil {
27 t.Fatalf("ParseFile(%s): %v", filename, err)
28 }
29 }
30 }
31
32 func nameFilter(filename string) bool {
33 switch filename {
34 case "parser.go", "interface.go", "parser_test.go":
35 return true
36 case "parser.go.orig":
37 return true
38 }
39 return false
40 }
41
42 func dirFilter(f fs.FileInfo) bool { return nameFilter(f.Name()) }
43
44 func TestParseFile(t *testing.T) {
45 src := "package p\nvar _=s[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]"
46 _, err := ParseFile(token.NewFileSet(), "", src, 0)
47 if err == nil {
48 t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
49 }
50 }
51
52 func TestParseExprFrom(t *testing.T) {
53 src := "s[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]"
54 _, err := ParseExprFrom(token.NewFileSet(), "", src, 0)
55 if err == nil {
56 t.Errorf("ParseExprFrom(%s) succeeded unexpectedly", src)
57 }
58 }
59
60 func TestParseDir(t *testing.T) {
61 path := "."
62 pkgs, err := ParseDir(token.NewFileSet(), path, dirFilter, 0)
63 if err != nil {
64 t.Fatalf("ParseDir(%s): %v", path, err)
65 }
66 if n := len(pkgs); n != 1 {
67 t.Errorf("got %d packages; want 1", n)
68 }
69 pkg := pkgs["parser"]
70 if pkg == nil {
71 t.Errorf(`package "parser" not found`)
72 return
73 }
74 if n := len(pkg.Files); n != 3 {
75 t.Errorf("got %d package files; want 3", n)
76 }
77 for filename := range pkg.Files {
78 if !nameFilter(filename) {
79 t.Errorf("unexpected package file: %s", filename)
80 }
81 }
82 }
83
84 func TestIssue42951(t *testing.T) {
85 path := "./testdata/issue42951"
86 _, err := ParseDir(token.NewFileSet(), path, nil, 0)
87 if err != nil {
88 t.Errorf("ParseDir(%s): %v", path, err)
89 }
90 }
91
92 func TestParseExpr(t *testing.T) {
93
94
95 src := "a + b"
96 x, err := ParseExpr(src)
97 if err != nil {
98 t.Errorf("ParseExpr(%q): %v", src, err)
99 }
100
101 if _, ok := x.(*ast.BinaryExpr); !ok {
102 t.Errorf("ParseExpr(%q): got %T, want *ast.BinaryExpr", src, x)
103 }
104
105
106 src = "struct{x *int}"
107 x, err = ParseExpr(src)
108 if err != nil {
109 t.Errorf("ParseExpr(%q): %v", src, err)
110 }
111
112 if _, ok := x.(*ast.StructType); !ok {
113 t.Errorf("ParseExpr(%q): got %T, want *ast.StructType", src, x)
114 }
115
116
117 src = "a + *"
118 x, err = ParseExpr(src)
119 if err == nil {
120 t.Errorf("ParseExpr(%q): got no error", src)
121 }
122 if x == nil {
123 t.Errorf("ParseExpr(%q): got no (partial) result", src)
124 }
125 if _, ok := x.(*ast.BinaryExpr); !ok {
126 t.Errorf("ParseExpr(%q): got %T, want *ast.BinaryExpr", src, x)
127 }
128
129
130 src = "a[i] := x"
131 if _, err := ParseExpr(src); err == nil {
132 t.Errorf("ParseExpr(%q): got no error", src)
133 }
134
135
136 src = "a + b\n"
137 if _, err := ParseExpr(src); err != nil {
138 t.Errorf("ParseExpr(%q): got error %s", src, err)
139 }
140 src = "a + b;"
141 if _, err := ParseExpr(src); err == nil {
142 t.Errorf("ParseExpr(%q): got no error", src)
143 }
144
145
146 const validExpr = "a + b"
147 const anything = "dh3*#D)#_"
148 for _, c := range "!)]};," {
149 src := validExpr + string(c) + anything
150 if _, err := ParseExpr(src); err == nil {
151 t.Errorf("ParseExpr(%q): got no error", src)
152 }
153 }
154
155
156 for _, src := range valids {
157 ParseExpr(src)
158 }
159 }
160
161 func TestColonEqualsScope(t *testing.T) {
162 f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { x, y, z := x, y, z }`, 0)
163 if err != nil {
164 t.Fatal(err)
165 }
166
167
168 as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt)
169 for _, v := range as.Rhs {
170 id := v.(*ast.Ident)
171 if id.Obj != nil {
172 t.Errorf("rhs %s has Obj, should not", id.Name)
173 }
174 }
175 for _, v := range as.Lhs {
176 id := v.(*ast.Ident)
177 if id.Obj == nil {
178 t.Errorf("lhs %s does not have Obj, should", id.Name)
179 }
180 }
181 }
182
183 func TestVarScope(t *testing.T) {
184 f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { var x, y, z = x, y, z }`, 0)
185 if err != nil {
186 t.Fatal(err)
187 }
188
189
190 as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.DeclStmt).Decl.(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
191 for _, v := range as.Values {
192 id := v.(*ast.Ident)
193 if id.Obj != nil {
194 t.Errorf("rhs %s has Obj, should not", id.Name)
195 }
196 }
197 for _, id := range as.Names {
198 if id.Obj == nil {
199 t.Errorf("lhs %s does not have Obj, should", id.Name)
200 }
201 }
202 }
203
204 func TestObjects(t *testing.T) {
205 const src = `
206 package p
207 import fmt "fmt"
208 const pi = 3.14
209 type T struct{}
210 var x int
211 func f() { L: }
212 `
213
214 f, err := ParseFile(token.NewFileSet(), "", src, 0)
215 if err != nil {
216 t.Fatal(err)
217 }
218
219 objects := map[string]ast.ObjKind{
220 "p": ast.Bad,
221 "fmt": ast.Bad,
222 "pi": ast.Con,
223 "T": ast.Typ,
224 "x": ast.Var,
225 "int": ast.Bad,
226 "f": ast.Fun,
227 "L": ast.Lbl,
228 }
229
230 ast.Inspect(f, func(n ast.Node) bool {
231 if ident, ok := n.(*ast.Ident); ok {
232 obj := ident.Obj
233 if obj == nil {
234 if objects[ident.Name] != ast.Bad {
235 t.Errorf("no object for %s", ident.Name)
236 }
237 return true
238 }
239 if obj.Name != ident.Name {
240 t.Errorf("names don't match: obj.Name = %s, ident.Name = %s", obj.Name, ident.Name)
241 }
242 kind := objects[ident.Name]
243 if obj.Kind != kind {
244 t.Errorf("%s: obj.Kind = %s; want %s", ident.Name, obj.Kind, kind)
245 }
246 }
247 return true
248 })
249 }
250
251 func TestUnresolved(t *testing.T) {
252 f, err := ParseFile(token.NewFileSet(), "", `
253 package p
254 //
255 func f1a(int)
256 func f2a(byte, int, float)
257 func f3a(a, b int, c float)
258 func f4a(...complex)
259 func f5a(a s1a, b ...complex)
260 //
261 func f1b(*int)
262 func f2b([]byte, (int), *float)
263 func f3b(a, b *int, c []float)
264 func f4b(...*complex)
265 func f5b(a s1a, b ...[]complex)
266 //
267 type s1a struct { int }
268 type s2a struct { byte; int; s1a }
269 type s3a struct { a, b int; c float }
270 //
271 type s1b struct { *int }
272 type s2b struct { byte; int; *float }
273 type s3b struct { a, b *s3b; c []float }
274 `, 0)
275 if err != nil {
276 t.Fatal(err)
277 }
278
279 want := "int " +
280 "byte int float " +
281 "int float " +
282 "complex " +
283 "complex " +
284
285 "int " +
286 "byte int float " +
287 "int float " +
288 "complex " +
289 "complex " +
290
291 "int " +
292 "byte int " +
293 "int float " +
294
295 "int " +
296 "byte int float " +
297 "float "
298
299
300 var buf strings.Builder
301 for _, u := range f.Unresolved {
302 buf.WriteString(u.Name)
303 buf.WriteByte(' ')
304 }
305 got := buf.String()
306
307 if got != want {
308 t.Errorf("\ngot: %s\nwant: %s", got, want)
309 }
310 }
311
312 func TestCommentGroups(t *testing.T) {
313 f, err := ParseFile(token.NewFileSet(), "", `
314 package p /* 1a */ /* 1b */ /* 1c */ // 1d
315 /* 2a
316 */
317 // 2b
318 const pi = 3.1415
319 /* 3a */ // 3b
320 /* 3c */ const e = 2.7182
321
322 // Example from go.dev/issue/3139
323 func ExampleCount() {
324 fmt.Println(strings.Count("cheese", "e"))
325 fmt.Println(strings.Count("five", "")) // before & after each rune
326 // Output:
327 // 3
328 // 5
329 }
330 `, ParseComments)
331 if err != nil {
332 t.Fatal(err)
333 }
334 expected := [][]string{
335 {"/* 1a */", "/* 1b */", "/* 1c */", "// 1d"},
336 {"/* 2a\n*/", "// 2b"},
337 {"/* 3a */", "// 3b", "/* 3c */"},
338 {"// Example from go.dev/issue/3139"},
339 {"// before & after each rune"},
340 {"// Output:", "// 3", "// 5"},
341 }
342 if len(f.Comments) != len(expected) {
343 t.Fatalf("got %d comment groups; expected %d", len(f.Comments), len(expected))
344 }
345 for i, exp := range expected {
346 got := f.Comments[i].List
347 if len(got) != len(exp) {
348 t.Errorf("got %d comments in group %d; expected %d", len(got), i, len(exp))
349 continue
350 }
351 for j, exp := range exp {
352 got := got[j].Text
353 if got != exp {
354 t.Errorf("got %q in group %d; expected %q", got, i, exp)
355 }
356 }
357 }
358 }
359
360 func getField(file *ast.File, fieldname string) *ast.Field {
361 parts := strings.Split(fieldname, ".")
362 for _, d := range file.Decls {
363 if d, ok := d.(*ast.GenDecl); ok && d.Tok == token.TYPE {
364 for _, s := range d.Specs {
365 if s, ok := s.(*ast.TypeSpec); ok && s.Name.Name == parts[0] {
366 if s, ok := s.Type.(*ast.StructType); ok {
367 for _, f := range s.Fields.List {
368 for _, name := range f.Names {
369 if name.Name == parts[1] {
370 return f
371 }
372 }
373 }
374 }
375 }
376 }
377 }
378 }
379 return nil
380 }
381
382
383 func commentText(c *ast.CommentGroup) string {
384 var buf strings.Builder
385 if c != nil {
386 for _, c := range c.List {
387 buf.WriteString(c.Text)
388 }
389 }
390 return buf.String()
391 }
392
393 func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line string) {
394 f := getField(file, fieldname)
395 if f == nil {
396 t.Fatalf("field not found: %s", fieldname)
397 }
398 if got := commentText(f.Doc); got != lead {
399 t.Errorf("got lead comment %q; expected %q", got, lead)
400 }
401 if got := commentText(f.Comment); got != line {
402 t.Errorf("got line comment %q; expected %q", got, line)
403 }
404 }
405
406 func TestLeadAndLineComments(t *testing.T) {
407 f, err := ParseFile(token.NewFileSet(), "", `
408 package p
409 type T struct {
410 /* F1 lead comment */
411 //
412 F1 int /* F1 */ // line comment
413 // F2 lead
414 // comment
415 F2 int // F2 line comment
416 // f3 lead comment
417 f3 int // f3 line comment
418
419 f4 int /* not a line comment */ ;
420 f5 int ; // f5 line comment
421 f6 int ; /* f6 line comment */
422 f7 int ; /*f7a*/ /*f7b*/ //f7c
423 }
424 `, ParseComments)
425 if err != nil {
426 t.Fatal(err)
427 }
428 checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
429 checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment")
430 checkFieldComments(t, f, "T.f3", "// f3 lead comment", "// f3 line comment")
431 checkFieldComments(t, f, "T.f4", "", "")
432 checkFieldComments(t, f, "T.f5", "", "// f5 line comment")
433 checkFieldComments(t, f, "T.f6", "", "/* f6 line comment */")
434 checkFieldComments(t, f, "T.f7", "", "/*f7a*//*f7b*///f7c")
435
436 ast.FileExports(f)
437 checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
438 checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment")
439 if getField(f, "T.f3") != nil {
440 t.Error("not expected to find T.f3")
441 }
442 }
443
444
445 func TestIssue9979(t *testing.T) {
446 for _, src := range []string{
447 "package p; func f() {;}",
448 "package p; func f() {L:}",
449 "package p; func f() {L:;}",
450 "package p; func f() {L:\n}",
451 "package p; func f() {L:\n;}",
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 } {
458 fset := token.NewFileSet()
459 f, err := ParseFile(fset, "", src, 0)
460 if err != nil {
461 t.Fatal(err)
462 }
463
464 var pos, end token.Pos
465 ast.Inspect(f, func(x ast.Node) bool {
466 switch s := x.(type) {
467 case *ast.BlockStmt:
468 pos, end = s.Pos()+1, s.End()-1
469 case *ast.LabeledStmt:
470 pos, end = s.Pos()+2, s.End()
471 case *ast.EmptyStmt:
472
473 if s.Pos() < pos || s.End() > end {
474 t.Errorf("%s: %T[%d, %d] not inside [%d, %d]", src, s, s.Pos(), s.End(), pos, end)
475 }
476
477 offs := fset.Position(s.Pos()).Offset
478 if ch := src[offs]; ch != ';' != s.Implicit {
479 want := "want ';'"
480 if s.Implicit {
481 want = "but ';' is implicit"
482 }
483 t.Errorf("%s: found %q at offset %d; %s", src, ch, offs, want)
484 }
485 }
486 return true
487 })
488 }
489 }
490
491 func TestFileStartEndPos(t *testing.T) {
492 const src = `// Copyright
493
494 //+build tag
495
496 // Package p doc comment.
497 package p
498
499 var lastDecl int
500
501 /* end of file */
502 `
503 fset := token.NewFileSet()
504 f, err := ParseFile(fset, "file.go", src, 0)
505 if err != nil {
506 t.Fatal(err)
507 }
508
509
510 if got, want := fset.Position(f.FileStart).String(), "file.go:1:1"; got != want {
511 t.Errorf("for File.FileStart, got %s, want %s", got, want)
512 }
513
514 if got, want := fset.Position(f.FileEnd).String(), "file.go:10:19"; got != want {
515 t.Errorf("for File.FileEnd, got %s, want %s", got, want)
516 }
517 }
518
519
520
521
522 func TestIncompleteSelection(t *testing.T) {
523 for _, src := range []string{
524 "package p; var _ = fmt.",
525 "package p; var _ = fmt.\ntype X int",
526 } {
527 fset := token.NewFileSet()
528 f, err := ParseFile(fset, "", src, 0)
529 if err == nil {
530 t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
531 continue
532 }
533
534 const wantErr = "expected selector or type assertion"
535 if !strings.Contains(err.Error(), wantErr) {
536 t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr)
537 }
538
539 var sel *ast.SelectorExpr
540 ast.Inspect(f, func(n ast.Node) bool {
541 if n, ok := n.(*ast.SelectorExpr); ok {
542 sel = n
543 }
544 return true
545 })
546 if sel == nil {
547 t.Error("found no *ast.SelectorExpr")
548 continue
549 }
550 const wantSel = "&{fmt _}"
551 if fmt.Sprint(sel) != wantSel {
552 t.Errorf("found selector %s, want %s", sel, wantSel)
553 continue
554 }
555 }
556 }
557
558 func TestLastLineComment(t *testing.T) {
559 const src = `package main
560 type x int // comment
561 `
562 fset := token.NewFileSet()
563 f, err := ParseFile(fset, "", src, ParseComments)
564 if err != nil {
565 t.Fatal(err)
566 }
567 comment := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.TypeSpec).Comment.List[0].Text
568 if comment != "// comment" {
569 t.Errorf("got %q, want %q", comment, "// comment")
570 }
571 }
572
573 var parseDepthTests = []struct {
574 name string
575 format string
576
577
578
579
580
581 parseMultiplier int
582
583
584 scope bool
585
586
587 scopeMultiplier int
588 }{
589
590
591
592 {name: "array", format: "package main; var x «[1]»int"},
593 {name: "slice", format: "package main; var x «[]»int"},
594 {name: "struct", format: "package main; var x «struct { X «int» }»", scope: true},
595 {name: "pointer", format: "package main; var x «*»int"},
596 {name: "func", format: "package main; var x «func()»int", scope: true},
597 {name: "chan", format: "package main; var x «chan »int"},
598 {name: "chan2", format: "package main; var x «<-chan »int"},
599 {name: "interface", format: "package main; var x «interface { M() «int» }»", scope: true, scopeMultiplier: 2},
600 {name: "map", format: "package main; var x «map[int]»int"},
601 {name: "slicelit", format: "package main; var x = []any{«[]any{«»}»}", parseMultiplier: 3},
602 {name: "arraylit", format: "package main; var x = «[1]any{«nil»}»", parseMultiplier: 3},
603 {name: "structlit", format: "package main; var x = «struct{x any}{«nil»}»", parseMultiplier: 3},
604 {name: "maplit", format: "package main; var x = «map[int]any{1:«nil»}»", parseMultiplier: 3},
605 {name: "element", format: "package main; var x = struct{x any}{x: «{«»}»}"},
606 {name: "dot", format: "package main; var x = «x.»x"},
607 {name: "index", format: "package main; var x = x«[1]»"},
608 {name: "slice", format: "package main; var x = x«[1:2]»"},
609 {name: "slice3", format: "package main; var x = x«[1:2:3]»"},
610 {name: "dottype", format: "package main; var x = x«.(any)»"},
611 {name: "callseq", format: "package main; var x = x«()»"},
612 {name: "methseq", format: "package main; var x = x«.m()»", parseMultiplier: 2},
613 {name: "binary", format: "package main; var x = «1+»1"},
614 {name: "binaryparen", format: "package main; var x = «1+(«1»)»", parseMultiplier: 2},
615 {name: "unary", format: "package main; var x = «^»1"},
616 {name: "addr", format: "package main; var x = «& »x"},
617 {name: "star", format: "package main; var x = «*»x"},
618 {name: "recv", format: "package main; var x = «<-»x"},
619 {name: "call", format: "package main; var x = «f(«1»)»", parseMultiplier: 2},
620 {name: "conv", format: "package main; var x = «(*T)(«1»)»", parseMultiplier: 2},
621 {name: "label", format: "package main; func main() { «Label:» }"},
622 {name: "if", format: "package main; func main() { «if true { «» }»}", parseMultiplier: 2, scope: true, scopeMultiplier: 2},
623 {name: "ifelse", format: "package main; func main() { «if true {} else » {} }", scope: true},
624 {name: "switch", format: "package main; func main() { «switch { default: «» }»}", scope: true, scopeMultiplier: 2},
625 {name: "typeswitch", format: "package main; func main() { «switch x.(type) { default: «» }» }", scope: true, scopeMultiplier: 2},
626 {name: "for0", format: "package main; func main() { «for { «» }» }", scope: true, scopeMultiplier: 2},
627 {name: "for1", format: "package main; func main() { «for x { «» }» }", scope: true, scopeMultiplier: 2},
628 {name: "for3", format: "package main; func main() { «for f(); g(); h() { «» }» }", scope: true, scopeMultiplier: 2},
629 {name: "forrange0", format: "package main; func main() { «for range x { «» }» }", scope: true, scopeMultiplier: 2},
630 {name: "forrange1", format: "package main; func main() { «for x = range z { «» }» }", scope: true, scopeMultiplier: 2},
631 {name: "forrange2", format: "package main; func main() { «for x, y = range z { «» }» }", scope: true, scopeMultiplier: 2},
632 {name: "go", format: "package main; func main() { «go func() { «» }()» }", parseMultiplier: 2, scope: true},
633 {name: "defer", format: "package main; func main() { «defer func() { «» }()» }", parseMultiplier: 2, scope: true},
634 {name: "select", format: "package main; func main() { «select { default: «» }» }", scope: true},
635 }
636
637
638
639 func split(x string) (pre, mid, post string) {
640 start, end := strings.Index(x, "«"), strings.LastIndex(x, "»")
641 if start < 0 || end < 0 {
642 return x, "", ""
643 }
644 return x[:start], x[start+len("«") : end], x[end+len("»"):]
645 }
646
647 func TestParseDepthLimit(t *testing.T) {
648 if testing.Short() {
649 t.Skip("test requires significant memory")
650 }
651 for _, tt := range parseDepthTests {
652 for _, size := range []string{"small", "big"} {
653 t.Run(tt.name+"/"+size, func(t *testing.T) {
654 n := maxNestLev + 1
655 if tt.parseMultiplier > 0 {
656 n /= tt.parseMultiplier
657 }
658 if size == "small" {
659
660
661
662
663
664 n -= 10
665 }
666
667 pre, mid, post := split(tt.format)
668 if strings.Contains(mid, "«") {
669 left, base, right := split(mid)
670 mid = strings.Repeat(left, n) + base + strings.Repeat(right, n)
671 } else {
672 mid = strings.Repeat(mid, n)
673 }
674 input := pre + mid + post
675
676 fset := token.NewFileSet()
677 _, err := ParseFile(fset, "", input, ParseComments|SkipObjectResolution)
678 if size == "small" {
679 if err != nil {
680 t.Errorf("ParseFile(...): %v (want success)", err)
681 }
682 } else {
683 expected := "exceeded max nesting depth"
684 if err == nil || !strings.HasSuffix(err.Error(), expected) {
685 t.Errorf("ParseFile(...) = _, %v, want %q", err, expected)
686 }
687 }
688 })
689 }
690 }
691 }
692
693 func TestScopeDepthLimit(t *testing.T) {
694 for _, tt := range parseDepthTests {
695 if !tt.scope {
696 continue
697 }
698 for _, size := range []string{"small", "big"} {
699 t.Run(tt.name+"/"+size, func(t *testing.T) {
700 n := maxScopeDepth + 1
701 if tt.scopeMultiplier > 0 {
702 n /= tt.scopeMultiplier
703 }
704 if size == "small" {
705
706
707
708
709
710 n -= 10
711 }
712
713 pre, mid, post := split(tt.format)
714 if strings.Contains(mid, "«") {
715 left, base, right := split(mid)
716 mid = strings.Repeat(left, n) + base + strings.Repeat(right, n)
717 } else {
718 mid = strings.Repeat(mid, n)
719 }
720 input := pre + mid + post
721
722 fset := token.NewFileSet()
723 _, err := ParseFile(fset, "", input, DeclarationErrors)
724 if size == "small" {
725 if err != nil {
726 t.Errorf("ParseFile(...): %v (want success)", err)
727 }
728 } else {
729 expected := "exceeded max scope depth during object resolution"
730 if err == nil || !strings.HasSuffix(err.Error(), expected) {
731 t.Errorf("ParseFile(...) = _, %v, want %q", err, expected)
732 }
733 }
734 })
735 }
736 }
737 }
738
739
740 func TestRangePos(t *testing.T) {
741 testcases := []string{
742 "package p; func _() { for range x {} }",
743 "package p; func _() { for i = range x {} }",
744 "package p; func _() { for i := range x {} }",
745 "package p; func _() { for k, v = range x {} }",
746 "package p; func _() { for k, v := range x {} }",
747 }
748
749 for _, src := range testcases {
750 fset := token.NewFileSet()
751 f, err := ParseFile(fset, src, src, 0)
752 if err != nil {
753 t.Fatal(err)
754 }
755
756 ast.Inspect(f, func(x ast.Node) bool {
757 switch s := x.(type) {
758 case *ast.RangeStmt:
759 pos := fset.Position(s.Range)
760 if pos.Offset != strings.Index(src, "range") {
761 t.Errorf("%s: got offset %v, want %v", src, pos.Offset, strings.Index(src, "range"))
762 }
763 }
764 return true
765 })
766 }
767 }
768
769
770 func TestIssue59180(t *testing.T) {
771 testcases := []string{
772 "package p\n//line :9223372036854775806\n\n//",
773 "package p\n//line :1:9223372036854775806\n\n//",
774 "package p\n//line file:9223372036854775806\n\n//",
775 }
776
777 for _, src := range testcases {
778 _, err := ParseFile(token.NewFileSet(), "", src, ParseComments)
779 if err == nil {
780 t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
781 }
782 }
783 }
784
785 func TestGoVersion(t *testing.T) {
786 fset := token.NewFileSet()
787 pkgs, err := ParseDir(fset, "./testdata/goversion", nil, 0)
788 if err != nil {
789 t.Fatal(err)
790 }
791
792 for _, p := range pkgs {
793 want := strings.ReplaceAll(p.Name, "_", ".")
794 if want == "none" {
795 want = ""
796 }
797 for _, f := range p.Files {
798 if f.GoVersion != want {
799 t.Errorf("%s: GoVersion = %q, want %q", fset.Position(f.Pos()), f.GoVersion, want)
800 }
801 }
802 }
803 }
804
805 func TestIssue57490(t *testing.T) {
806 src := `package p; func f() { var x struct`
807 fset := token.NewFileSet()
808 file, err := ParseFile(fset, "", src, 0)
809 if err == nil {
810 t.Fatalf("syntax error expected, but no error reported")
811 }
812
813
814
815 funcEnd := file.Decls[0].End()
816
817
818
819 tokFile := fset.File(file.Pos())
820 offset := tokFile.Offset(funcEnd)
821 if offset != tokFile.Size() {
822 t.Fatalf("offset = %d, want %d", offset, tokFile.Size())
823 }
824 }
825
826 func TestParseTypeParamsAsParenExpr(t *testing.T) {
827 const src = "package p; type X[A (B),] struct{}"
828
829 fset := token.NewFileSet()
830 f, err := ParseFile(fset, "test.go", src, ParseComments|SkipObjectResolution)
831 if err != nil {
832 t.Fatal(err)
833 }
834
835 typeParam := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.TypeSpec).TypeParams.List[0].Type
836 _, ok := typeParam.(*ast.ParenExpr)
837 if !ok {
838 t.Fatalf("typeParam is a %T; want: *ast.ParenExpr", typeParam)
839 }
840 }
841
842
843 func TestEmptyFileHasValidStartEnd(t *testing.T) {
844 for _, test := range []struct {
845 src string
846 want string
847 }{
848 {src: "", want: "0 1 1"},
849 {src: "package ", want: "0 1 9"},
850 {src: "package p", want: "1 1 10"},
851 {src: "type T int", want: "0 1 11"},
852 } {
853 fset := token.NewFileSet()
854 f, _ := ParseFile(fset, "a.go", test.src, 0)
855 got := fmt.Sprintf("%d %d %d", f.Pos(), f.FileStart, f.FileEnd)
856 if got != test.want {
857 t.Fatalf("src = %q: got %s, want %s", test.src, got, test.want)
858 }
859 }
860 }
861
View as plain text