github.com/AndrienkoAleksandr/go@v0.0.19/src/go/parser/parser_test.go (about) 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 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 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 #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 }