]> Cypherpunks.ru repositories - gostls13.git/blob - src/go/parser/parser_test.go
go/parser: better error messages for incorrect type parameter list
[gostls13.git] / src / go / parser / parser_test.go
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.
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 // permit but should be ignored by ParseDir
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         // just kicking the tires:
94         // a valid arithmetic expression
95         src := "a + b"
96         x, err := ParseExpr(src)
97         if err != nil {
98                 t.Errorf("ParseExpr(%q): %v", src, err)
99         }
100         // sanity check
101         if _, ok := x.(*ast.BinaryExpr); !ok {
102                 t.Errorf("ParseExpr(%q): got %T, want *ast.BinaryExpr", src, x)
103         }
104
105         // a valid type expression
106         src = "struct{x *int}"
107         x, err = ParseExpr(src)
108         if err != nil {
109                 t.Errorf("ParseExpr(%q): %v", src, err)
110         }
111         // sanity check
112         if _, ok := x.(*ast.StructType); !ok {
113                 t.Errorf("ParseExpr(%q): got %T, want *ast.StructType", src, x)
114         }
115
116         // an invalid expression
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         // a valid expression followed by extra tokens is invalid
130         src = "a[i] := x"
131         if _, err := ParseExpr(src); err == nil {
132                 t.Errorf("ParseExpr(%q): got no error", src)
133         }
134
135         // a semicolon is not permitted unless automatically inserted
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         // various other stuff following a valid expression
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         // ParseExpr must not crash
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         // RHS refers to undefined globals; LHS does not.
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         // RHS refers to undefined globals; LHS does not.
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, // not in a scope
221                 "fmt": ast.Bad, // not resolved yet
222                 "pi":  ast.Con,
223                 "T":   ast.Typ,
224                 "x":   ast.Var,
225                 "int": ast.Bad, // not resolved yet
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 " + // f1a
280                 "byte int float " + // f2a
281                 "int float " + // f3a
282                 "complex " + // f4a
283                 "complex " + // f5a
284                 //
285                 "int " + // f1b
286                 "byte int float " + // f2b
287                 "int float " + // f3b
288                 "complex " + // f4b
289                 "complex " + // f5b
290                 //
291                 "int " + // s1a
292                 "byte int " + // s2a
293                 "int float " + // s3a
294                 //
295                 "int " + // s1a
296                 "byte int float " + // s2a
297                 "float " // s3a
298
299         // collect unresolved identifiers
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 // Don't use ast.CommentGroup.Text() - we want to see exact comment text.
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 // TestIssue9979 verifies that empty statements are contained within their enclosing blocks.
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 // exclude "{", "}"
469                         case *ast.LabeledStmt:
470                                 pos, end = s.Pos()+2, s.End() // exclude "L:"
471                         case *ast.EmptyStmt:
472                                 // check containment
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                                 // check semicolon
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         // File{Start,End} spans the entire file, not just the declarations.
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         // The end position is the newline at the end of the /* end of file */ line.
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 // TestIncompleteSelection ensures that an incomplete selector
520 // expression is parsed as a (blank) *ast.SelectorExpr, not a
521 // *ast.BadExpr.
522 func TestIncompleteSelection(t *testing.T) {
523         for _, src := range []string{
524                 "package p; var _ = fmt.",             // at EOF
525                 "package p; var _ = fmt.\ntype X int", // not at EOF
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         // multiplier is used when a single statement may result in more than one
577         // change in the depth level, for instance "1+(..." produces a BinaryExpr
578         // followed by a UnaryExpr, which increments the depth twice. The test
579         // case comment explains which nodes are triggering the multiple depth
580         // changes.
581         parseMultiplier int
582         // scope is true if we should also test the statement for the resolver scope
583         // depth limit.
584         scope bool
585         // scopeMultiplier does the same as parseMultiplier, but for the scope
586         // depths.
587         scopeMultiplier int
588 }{
589         // The format expands the part inside « » many times.
590         // A second set of brackets nested inside the first stops the repetition,
591         // so that for example «(«1»)» expands to (((...((((1))))...))).
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}, // Scopes: InterfaceType, FuncType
600         {name: "map", format: "package main; var x «map[int]»int"},
601         {name: "slicelit", format: "package main; var x = «[]any{«»}»", parseMultiplier: 2},             // Parser nodes: UnaryExpr, CompositeLit
602         {name: "arraylit", format: "package main; var x = «[1]any{«nil»}»", parseMultiplier: 2},         // Parser nodes: UnaryExpr, CompositeLit
603         {name: "structlit", format: "package main; var x = «struct{x any}{«nil»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit
604         {name: "maplit", format: "package main; var x = «map[int]any{1:«nil»}»", parseMultiplier: 2},    // Parser nodes: CompositeLit, KeyValueExpr
605         {name: "dot", format: "package main; var x = «x.»x"},
606         {name: "index", format: "package main; var x = x«[1]»"},
607         {name: "slice", format: "package main; var x = x«[1:2]»"},
608         {name: "slice3", format: "package main; var x = x«[1:2:3]»"},
609         {name: "dottype", format: "package main; var x = x«.(any)»"},
610         {name: "callseq", format: "package main; var x = x«()»"},
611         {name: "methseq", format: "package main; var x = x«.m()»", parseMultiplier: 2}, // Parser nodes: SelectorExpr, CallExpr
612         {name: "binary", format: "package main; var x = «1+»1"},
613         {name: "binaryparen", format: "package main; var x = «1+(«1»)»", parseMultiplier: 2}, // Parser nodes: BinaryExpr, ParenExpr
614         {name: "unary", format: "package main; var x = «^»1"},
615         {name: "addr", format: "package main; var x = «& »x"},
616         {name: "star", format: "package main; var x = «*»x"},
617         {name: "recv", format: "package main; var x = «<-»x"},
618         {name: "call", format: "package main; var x = «f(«1»)»", parseMultiplier: 2},    // Parser nodes: Ident, CallExpr
619         {name: "conv", format: "package main; var x = «(*T)(«1»)»", parseMultiplier: 2}, // Parser nodes: ParenExpr, CallExpr
620         {name: "label", format: "package main; func main() { «Label:» }"},
621         {name: "if", format: "package main; func main() { «if true { «» }»}", parseMultiplier: 2, scope: true, scopeMultiplier: 2}, // Parser nodes: IfStmt, BlockStmt. Scopes: IfStmt, BlockStmt
622         {name: "ifelse", format: "package main; func main() { «if true {} else » {} }", scope: true},
623         {name: "switch", format: "package main; func main() { «switch { default: «» }»}", scope: true, scopeMultiplier: 2},               // Scopes: TypeSwitchStmt, CaseClause
624         {name: "typeswitch", format: "package main; func main() { «switch x.(type) { default: «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: TypeSwitchStmt, CaseClause
625         {name: "for0", format: "package main; func main() { «for { «» }» }", scope: true, scopeMultiplier: 2},                            // Scopes: ForStmt, BlockStmt
626         {name: "for1", format: "package main; func main() { «for x { «» }» }", scope: true, scopeMultiplier: 2},                          // Scopes: ForStmt, BlockStmt
627         {name: "for3", format: "package main; func main() { «for f(); g(); h() { «» }» }", scope: true, scopeMultiplier: 2},              // Scopes: ForStmt, BlockStmt
628         {name: "forrange0", format: "package main; func main() { «for range x { «» }» }", scope: true, scopeMultiplier: 2},               // Scopes: RangeStmt, BlockStmt
629         {name: "forrange1", format: "package main; func main() { «for x = range z { «» }» }", scope: true, scopeMultiplier: 2},           // Scopes: RangeStmt, BlockStmt
630         {name: "forrange2", format: "package main; func main() { «for x, y = range z { «» }» }", scope: true, scopeMultiplier: 2},        // Scopes: RangeStmt, BlockStmt
631         {name: "go", format: "package main; func main() { «go func() { «» }()» }", parseMultiplier: 2, scope: true},                      // Parser nodes: GoStmt, FuncLit
632         {name: "defer", format: "package main; func main() { «defer func() { «» }()» }", parseMultiplier: 2, scope: true},                // Parser nodes: DeferStmt, FuncLit
633         {name: "select", format: "package main; func main() { «select { default: «» }» }", scope: true},
634 }
635
636 // split splits pre«mid»post into pre, mid, post.
637 // If the string does not have that form, split returns x, "", "".
638 func split(x string) (pre, mid, post string) {
639         start, end := strings.Index(x, "«"), strings.LastIndex(x, "»")
640         if start < 0 || end < 0 {
641                 return x, "", ""
642         }
643         return x[:start], x[start+len("«") : end], x[end+len("»"):]
644 }
645
646 func TestParseDepthLimit(t *testing.T) {
647         if testing.Short() {
648                 t.Skip("test requires significant memory")
649         }
650         for _, tt := range parseDepthTests {
651                 for _, size := range []string{"small", "big"} {
652                         t.Run(tt.name+"/"+size, func(t *testing.T) {
653                                 n := maxNestLev + 1
654                                 if tt.parseMultiplier > 0 {
655                                         n /= tt.parseMultiplier
656                                 }
657                                 if size == "small" {
658                                         // Decrease the number of statements by 10, in order to check
659                                         // that we do not fail when under the limit. 10 is used to
660                                         // provide some wiggle room for cases where the surrounding
661                                         // scaffolding syntax adds some noise to the depth that changes
662                                         // on a per testcase basis.
663                                         n -= 10
664                                 }
665
666                                 pre, mid, post := split(tt.format)
667                                 if strings.Contains(mid, "«") {
668                                         left, base, right := split(mid)
669                                         mid = strings.Repeat(left, n) + base + strings.Repeat(right, n)
670                                 } else {
671                                         mid = strings.Repeat(mid, n)
672                                 }
673                                 input := pre + mid + post
674
675                                 fset := token.NewFileSet()
676                                 _, err := ParseFile(fset, "", input, ParseComments|SkipObjectResolution)
677                                 if size == "small" {
678                                         if err != nil {
679                                                 t.Errorf("ParseFile(...): %v (want success)", err)
680                                         }
681                                 } else {
682                                         expected := "exceeded max nesting depth"
683                                         if err == nil || !strings.HasSuffix(err.Error(), expected) {
684                                                 t.Errorf("ParseFile(...) = _, %v, want %q", err, expected)
685                                         }
686                                 }
687                         })
688                 }
689         }
690 }
691
692 func TestScopeDepthLimit(t *testing.T) {
693         for _, tt := range parseDepthTests {
694                 if !tt.scope {
695                         continue
696                 }
697                 for _, size := range []string{"small", "big"} {
698                         t.Run(tt.name+"/"+size, func(t *testing.T) {
699                                 n := maxScopeDepth + 1
700                                 if tt.scopeMultiplier > 0 {
701                                         n /= tt.scopeMultiplier
702                                 }
703                                 if size == "small" {
704                                         // Decrease the number of statements by 10, in order to check
705                                         // that we do not fail when under the limit. 10 is used to
706                                         // provide some wiggle room for cases where the surrounding
707                                         // scaffolding syntax adds some noise to the depth that changes
708                                         // on a per testcase basis.
709                                         n -= 10
710                                 }
711
712                                 pre, mid, post := split(tt.format)
713                                 if strings.Contains(mid, "«") {
714                                         left, base, right := split(mid)
715                                         mid = strings.Repeat(left, n) + base + strings.Repeat(right, n)
716                                 } else {
717                                         mid = strings.Repeat(mid, n)
718                                 }
719                                 input := pre + mid + post
720
721                                 fset := token.NewFileSet()
722                                 _, err := ParseFile(fset, "", input, DeclarationErrors)
723                                 if size == "small" {
724                                         if err != nil {
725                                                 t.Errorf("ParseFile(...): %v (want success)", err)
726                                         }
727                                 } else {
728                                         expected := "exceeded max scope depth during object resolution"
729                                         if err == nil || !strings.HasSuffix(err.Error(), expected) {
730                                                 t.Errorf("ParseFile(...) = _, %v, want %q", err, expected)
731                                         }
732                                 }
733                         })
734                 }
735         }
736 }
737
738 // proposal go.dev/issue/50429
739 func TestRangePos(t *testing.T) {
740         testcases := []string{
741                 "package p; func _() { for range x {} }",
742                 "package p; func _() { for i = range x {} }",
743                 "package p; func _() { for i := range x {} }",
744                 "package p; func _() { for k, v = range x {} }",
745                 "package p; func _() { for k, v := range x {} }",
746         }
747
748         for _, src := range testcases {
749                 fset := token.NewFileSet()
750                 f, err := ParseFile(fset, src, src, 0)
751                 if err != nil {
752                         t.Fatal(err)
753                 }
754
755                 ast.Inspect(f, func(x ast.Node) bool {
756                         switch s := x.(type) {
757                         case *ast.RangeStmt:
758                                 pos := fset.Position(s.Range)
759                                 if pos.Offset != strings.Index(src, "range") {
760                                         t.Errorf("%s: got offset %v, want %v", src, pos.Offset, strings.Index(src, "range"))
761                                 }
762                         }
763                         return true
764                 })
765         }
766 }
767
768 // TestIssue59180 tests that line number overflow doesn't cause an infinite loop.
769 func TestIssue59180(t *testing.T) {
770         testcases := []string{
771                 "package p\n//line :9223372036854775806\n\n//",
772                 "package p\n//line :1:9223372036854775806\n\n//",
773                 "package p\n//line file:9223372036854775806\n\n//",
774         }
775
776         for _, src := range testcases {
777                 _, err := ParseFile(token.NewFileSet(), "", src, ParseComments)
778                 if err == nil {
779                         t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
780                 }
781         }
782 }
783
784 func TestGoVersion(t *testing.T) {
785         fset := token.NewFileSet()
786         pkgs, err := ParseDir(fset, "./testdata/goversion", nil, 0)
787         if err != nil {
788                 t.Fatal(err)
789         }
790
791         for _, p := range pkgs {
792                 want := strings.ReplaceAll(p.Name, "_", ".")
793                 if want == "none" {
794                         want = ""
795                 }
796                 for _, f := range p.Files {
797                         if f.GoVersion != want {
798                                 t.Errorf("%s: GoVersion = %q, want %q", fset.Position(f.Pos()), f.GoVersion, want)
799                         }
800                 }
801         }
802 }