PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/third_party/gofrontend/libgo/go/go/parser/parser_test.go

http://github.com/axw/llgo
Go | 533 lines | 463 code | 39 blank | 31 comment | 125 complexity | c15cca8b63d96d3e55f2e12955f39a14 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT
  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. package parser
  5. import (
  6. "bytes"
  7. "fmt"
  8. "go/ast"
  9. "go/token"
  10. "os"
  11. "strings"
  12. "testing"
  13. )
  14. var validFiles = []string{
  15. "parser.go",
  16. "parser_test.go",
  17. "error_test.go",
  18. "short_test.go",
  19. }
  20. func TestParse(t *testing.T) {
  21. for _, filename := range validFiles {
  22. _, err := ParseFile(token.NewFileSet(), filename, nil, DeclarationErrors)
  23. if err != nil {
  24. t.Fatalf("ParseFile(%s): %v", filename, err)
  25. }
  26. }
  27. }
  28. func nameFilter(filename string) bool {
  29. switch filename {
  30. case "parser.go", "interface.go", "parser_test.go":
  31. return true
  32. case "parser.go.orig":
  33. return true // permit but should be ignored by ParseDir
  34. }
  35. return false
  36. }
  37. func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) }
  38. func TestParseDir(t *testing.T) {
  39. path := "."
  40. pkgs, err := ParseDir(token.NewFileSet(), path, dirFilter, 0)
  41. if err != nil {
  42. t.Fatalf("ParseDir(%s): %v", path, err)
  43. }
  44. if n := len(pkgs); n != 1 {
  45. t.Errorf("got %d packages; want 1", n)
  46. }
  47. pkg := pkgs["parser"]
  48. if pkg == nil {
  49. t.Errorf(`package "parser" not found`)
  50. return
  51. }
  52. if n := len(pkg.Files); n != 3 {
  53. t.Errorf("got %d package files; want 3", n)
  54. }
  55. for filename := range pkg.Files {
  56. if !nameFilter(filename) {
  57. t.Errorf("unexpected package file: %s", filename)
  58. }
  59. }
  60. }
  61. func TestParseExpr(t *testing.T) {
  62. // just kicking the tires:
  63. // a valid arithmetic expression
  64. src := "a + b"
  65. x, err := ParseExpr(src)
  66. if err != nil {
  67. t.Errorf("ParseExpr(%q): %v", src, err)
  68. }
  69. // sanity check
  70. if _, ok := x.(*ast.BinaryExpr); !ok {
  71. t.Errorf("ParseExpr(%q): got %T, want *ast.BinaryExpr", src, x)
  72. }
  73. // a valid type expression
  74. src = "struct{x *int}"
  75. x, err = ParseExpr(src)
  76. if err != nil {
  77. t.Errorf("ParseExpr(%q): %v", src, err)
  78. }
  79. // sanity check
  80. if _, ok := x.(*ast.StructType); !ok {
  81. t.Errorf("ParseExpr(%q): got %T, want *ast.StructType", src, x)
  82. }
  83. // an invalid expression
  84. src = "a + *"
  85. if _, err := ParseExpr(src); err == nil {
  86. t.Errorf("ParseExpr(%q): got no error", src)
  87. }
  88. // a valid expression followed by extra tokens is invalid
  89. src = "a[i] := x"
  90. if _, err := ParseExpr(src); err == nil {
  91. t.Errorf("ParseExpr(%q): got no error", src)
  92. }
  93. // a semicolon is not permitted unless automatically inserted
  94. src = "a + b\n"
  95. if _, err := ParseExpr(src); err != nil {
  96. t.Errorf("ParseExpr(%q): got error %s", src, err)
  97. }
  98. src = "a + b;"
  99. if _, err := ParseExpr(src); err == nil {
  100. t.Errorf("ParseExpr(%q): got no error", src)
  101. }
  102. // various other stuff following a valid expression
  103. const validExpr = "a + b"
  104. const anything = "dh3*#D)#_"
  105. for _, c := range "!)]};," {
  106. src := validExpr + string(c) + anything
  107. if _, err := ParseExpr(src); err == nil {
  108. t.Errorf("ParseExpr(%q): got no error", src)
  109. }
  110. }
  111. // ParseExpr must not crash
  112. for _, src := range valids {
  113. ParseExpr(src)
  114. }
  115. }
  116. func TestColonEqualsScope(t *testing.T) {
  117. f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { x, y, z := x, y, z }`, 0)
  118. if err != nil {
  119. t.Fatal(err)
  120. }
  121. // RHS refers to undefined globals; LHS does not.
  122. as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt)
  123. for _, v := range as.Rhs {
  124. id := v.(*ast.Ident)
  125. if id.Obj != nil {
  126. t.Errorf("rhs %s has Obj, should not", id.Name)
  127. }
  128. }
  129. for _, v := range as.Lhs {
  130. id := v.(*ast.Ident)
  131. if id.Obj == nil {
  132. t.Errorf("lhs %s does not have Obj, should", id.Name)
  133. }
  134. }
  135. }
  136. func TestVarScope(t *testing.T) {
  137. f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { var x, y, z = x, y, z }`, 0)
  138. if err != nil {
  139. t.Fatal(err)
  140. }
  141. // RHS refers to undefined globals; LHS does not.
  142. as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.DeclStmt).Decl.(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
  143. for _, v := range as.Values {
  144. id := v.(*ast.Ident)
  145. if id.Obj != nil {
  146. t.Errorf("rhs %s has Obj, should not", id.Name)
  147. }
  148. }
  149. for _, id := range as.Names {
  150. if id.Obj == nil {
  151. t.Errorf("lhs %s does not have Obj, should", id.Name)
  152. }
  153. }
  154. }
  155. func TestObjects(t *testing.T) {
  156. const src = `
  157. package p
  158. import fmt "fmt"
  159. const pi = 3.14
  160. type T struct{}
  161. var x int
  162. func f() { L: }
  163. `
  164. f, err := ParseFile(token.NewFileSet(), "", src, 0)
  165. if err != nil {
  166. t.Fatal(err)
  167. }
  168. objects := map[string]ast.ObjKind{
  169. "p": ast.Bad, // not in a scope
  170. "fmt": ast.Bad, // not resolved yet
  171. "pi": ast.Con,
  172. "T": ast.Typ,
  173. "x": ast.Var,
  174. "int": ast.Bad, // not resolved yet
  175. "f": ast.Fun,
  176. "L": ast.Lbl,
  177. }
  178. ast.Inspect(f, func(n ast.Node) bool {
  179. if ident, ok := n.(*ast.Ident); ok {
  180. obj := ident.Obj
  181. if obj == nil {
  182. if objects[ident.Name] != ast.Bad {
  183. t.Errorf("no object for %s", ident.Name)
  184. }
  185. return true
  186. }
  187. if obj.Name != ident.Name {
  188. t.Errorf("names don't match: obj.Name = %s, ident.Name = %s", obj.Name, ident.Name)
  189. }
  190. kind := objects[ident.Name]
  191. if obj.Kind != kind {
  192. t.Errorf("%s: obj.Kind = %s; want %s", ident.Name, obj.Kind, kind)
  193. }
  194. }
  195. return true
  196. })
  197. }
  198. func TestUnresolved(t *testing.T) {
  199. f, err := ParseFile(token.NewFileSet(), "", `
  200. package p
  201. //
  202. func f1a(int)
  203. func f2a(byte, int, float)
  204. func f3a(a, b int, c float)
  205. func f4a(...complex)
  206. func f5a(a s1a, b ...complex)
  207. //
  208. func f1b(*int)
  209. func f2b([]byte, (int), *float)
  210. func f3b(a, b *int, c []float)
  211. func f4b(...*complex)
  212. func f5b(a s1a, b ...[]complex)
  213. //
  214. type s1a struct { int }
  215. type s2a struct { byte; int; s1a }
  216. type s3a struct { a, b int; c float }
  217. //
  218. type s1b struct { *int }
  219. type s2b struct { byte; int; *float }
  220. type s3b struct { a, b *s3b; c []float }
  221. `, 0)
  222. if err != nil {
  223. t.Fatal(err)
  224. }
  225. want := "int " + // f1a
  226. "byte int float " + // f2a
  227. "int float " + // f3a
  228. "complex " + // f4a
  229. "complex " + // f5a
  230. //
  231. "int " + // f1b
  232. "byte int float " + // f2b
  233. "int float " + // f3b
  234. "complex " + // f4b
  235. "complex " + // f5b
  236. //
  237. "int " + // s1a
  238. "byte int " + // s2a
  239. "int float " + // s3a
  240. //
  241. "int " + // s1a
  242. "byte int float " + // s2a
  243. "float " // s3a
  244. // collect unresolved identifiers
  245. var buf bytes.Buffer
  246. for _, u := range f.Unresolved {
  247. buf.WriteString(u.Name)
  248. buf.WriteByte(' ')
  249. }
  250. got := buf.String()
  251. if got != want {
  252. t.Errorf("\ngot: %s\nwant: %s", got, want)
  253. }
  254. }
  255. var imports = map[string]bool{
  256. `"a"`: true,
  257. "`a`": true,
  258. `"a/b"`: true,
  259. `"a.b"`: true,
  260. `"m\x61th"`: true,
  261. `"greek/αβ"`: true,
  262. `""`: false,
  263. // Each of these pairs tests both `` vs "" strings
  264. // and also use of invalid characters spelled out as
  265. // escape sequences and written directly.
  266. // For example `"\x00"` tests import "\x00"
  267. // while "`\x00`" tests import `<actual-NUL-byte>`.
  268. `"\x00"`: false,
  269. "`\x00`": false,
  270. `"\x7f"`: false,
  271. "`\x7f`": false,
  272. `"a!"`: false,
  273. "`a!`": false,
  274. `"a b"`: false,
  275. "`a b`": false,
  276. `"a\\b"`: false,
  277. "`a\\b`": false,
  278. "\"`a`\"": false,
  279. "`\"a\"`": false,
  280. `"\x80\x80"`: false,
  281. "`\x80\x80`": false,
  282. `"\xFFFD"`: false,
  283. "`\xFFFD`": false,
  284. }
  285. func TestImports(t *testing.T) {
  286. for path, isValid := range imports {
  287. src := fmt.Sprintf("package p; import %s", path)
  288. _, err := ParseFile(token.NewFileSet(), "", src, 0)
  289. switch {
  290. case err != nil && isValid:
  291. t.Errorf("ParseFile(%s): got %v; expected no error", src, err)
  292. case err == nil && !isValid:
  293. t.Errorf("ParseFile(%s): got no error; expected one", src)
  294. }
  295. }
  296. }
  297. func TestCommentGroups(t *testing.T) {
  298. f, err := ParseFile(token.NewFileSet(), "", `
  299. package p /* 1a */ /* 1b */ /* 1c */ // 1d
  300. /* 2a
  301. */
  302. // 2b
  303. const pi = 3.1415
  304. /* 3a */ // 3b
  305. /* 3c */ const e = 2.7182
  306. // Example from issue 3139
  307. func ExampleCount() {
  308. fmt.Println(strings.Count("cheese", "e"))
  309. fmt.Println(strings.Count("five", "")) // before & after each rune
  310. // Output:
  311. // 3
  312. // 5
  313. }
  314. `, ParseComments)
  315. if err != nil {
  316. t.Fatal(err)
  317. }
  318. expected := [][]string{
  319. {"/* 1a */", "/* 1b */", "/* 1c */", "// 1d"},
  320. {"/* 2a\n*/", "// 2b"},
  321. {"/* 3a */", "// 3b", "/* 3c */"},
  322. {"// Example from issue 3139"},
  323. {"// before & after each rune"},
  324. {"// Output:", "// 3", "// 5"},
  325. }
  326. if len(f.Comments) != len(expected) {
  327. t.Fatalf("got %d comment groups; expected %d", len(f.Comments), len(expected))
  328. }
  329. for i, exp := range expected {
  330. got := f.Comments[i].List
  331. if len(got) != len(exp) {
  332. t.Errorf("got %d comments in group %d; expected %d", len(got), i, len(exp))
  333. continue
  334. }
  335. for j, exp := range exp {
  336. got := got[j].Text
  337. if got != exp {
  338. t.Errorf("got %q in group %d; expected %q", got, i, exp)
  339. }
  340. }
  341. }
  342. }
  343. func getField(file *ast.File, fieldname string) *ast.Field {
  344. parts := strings.Split(fieldname, ".")
  345. for _, d := range file.Decls {
  346. if d, ok := d.(*ast.GenDecl); ok && d.Tok == token.TYPE {
  347. for _, s := range d.Specs {
  348. if s, ok := s.(*ast.TypeSpec); ok && s.Name.Name == parts[0] {
  349. if s, ok := s.Type.(*ast.StructType); ok {
  350. for _, f := range s.Fields.List {
  351. for _, name := range f.Names {
  352. if name.Name == parts[1] {
  353. return f
  354. }
  355. }
  356. }
  357. }
  358. }
  359. }
  360. }
  361. }
  362. return nil
  363. }
  364. // Don't use ast.CommentGroup.Text() - we want to see exact comment text.
  365. func commentText(c *ast.CommentGroup) string {
  366. var buf bytes.Buffer
  367. if c != nil {
  368. for _, c := range c.List {
  369. buf.WriteString(c.Text)
  370. }
  371. }
  372. return buf.String()
  373. }
  374. func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line string) {
  375. f := getField(file, fieldname)
  376. if f == nil {
  377. t.Fatalf("field not found: %s", fieldname)
  378. }
  379. if got := commentText(f.Doc); got != lead {
  380. t.Errorf("got lead comment %q; expected %q", got, lead)
  381. }
  382. if got := commentText(f.Comment); got != line {
  383. t.Errorf("got line comment %q; expected %q", got, line)
  384. }
  385. }
  386. func TestLeadAndLineComments(t *testing.T) {
  387. f, err := ParseFile(token.NewFileSet(), "", `
  388. package p
  389. type T struct {
  390. /* F1 lead comment */
  391. //
  392. F1 int /* F1 */ // line comment
  393. // F2 lead
  394. // comment
  395. F2 int // F2 line comment
  396. // f3 lead comment
  397. f3 int // f3 line comment
  398. }
  399. `, ParseComments)
  400. if err != nil {
  401. t.Fatal(err)
  402. }
  403. checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
  404. checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment")
  405. checkFieldComments(t, f, "T.f3", "// f3 lead comment", "// f3 line comment")
  406. ast.FileExports(f)
  407. checkFieldComments(t, f, "T.F1", "/* F1 lead comment *///", "/* F1 */// line comment")
  408. checkFieldComments(t, f, "T.F2", "// F2 lead// comment", "// F2 line comment")
  409. if getField(f, "T.f3") != nil {
  410. t.Error("not expected to find T.f3")
  411. }
  412. }
  413. // TestIssue9979 verifies that empty statements are contained within their enclosing blocks.
  414. func TestIssue9979(t *testing.T) {
  415. for _, src := range []string{
  416. "package p; func f() {;}",
  417. "package p; func f() {L:}",
  418. "package p; func f() {L:;}",
  419. "package p; func f() {L:\n}",
  420. "package p; func f() {L:\n;}",
  421. "package p; func f() { ; }",
  422. "package p; func f() { L: }",
  423. "package p; func f() { L: ; }",
  424. "package p; func f() { L: \n}",
  425. "package p; func f() { L: \n; }",
  426. } {
  427. fset := token.NewFileSet()
  428. f, err := ParseFile(fset, "", src, 0)
  429. if err != nil {
  430. t.Fatal(err)
  431. }
  432. var pos, end token.Pos
  433. ast.Inspect(f, func(x ast.Node) bool {
  434. switch s := x.(type) {
  435. case *ast.BlockStmt:
  436. pos, end = s.Pos()+1, s.End()-1 // exclude "{", "}"
  437. case *ast.LabeledStmt:
  438. pos, end = s.Pos()+2, s.End() // exclude "L:"
  439. case *ast.EmptyStmt:
  440. // check containment
  441. if s.Pos() < pos || s.End() > end {
  442. t.Errorf("%s: %T[%d, %d] not inside [%d, %d]", src, s, s.Pos(), s.End(), pos, end)
  443. }
  444. // check semicolon
  445. offs := fset.Position(s.Pos()).Offset
  446. if ch := src[offs]; ch != ';' != s.Implicit {
  447. want := "want ';'"
  448. if s.Implicit {
  449. want = "but ';' is implicit"
  450. }
  451. t.Errorf("%s: found %q at offset %d; %s", src, ch, offs, want)
  452. }
  453. }
  454. return true
  455. })
  456. }
  457. }
  458. // TestIncompleteSelection ensures that an incomplete selector
  459. // expression is parsed as a (blank) *ast.SelectorExpr, not a
  460. // *ast.BadExpr.
  461. func TestIncompleteSelection(t *testing.T) {
  462. for _, src := range []string{
  463. "package p; var _ = fmt.", // at EOF
  464. "package p; var _ = fmt.\ntype X int", // not at EOF
  465. } {
  466. fset := token.NewFileSet()
  467. f, err := ParseFile(fset, "", src, 0)
  468. if err == nil {
  469. t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
  470. continue
  471. }
  472. const wantErr = "expected selector or type assertion"
  473. if !strings.Contains(err.Error(), wantErr) {
  474. t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr)
  475. }
  476. var sel *ast.SelectorExpr
  477. ast.Inspect(f, func(n ast.Node) bool {
  478. if n, ok := n.(*ast.SelectorExpr); ok {
  479. sel = n
  480. }
  481. return true
  482. })
  483. if sel == nil {
  484. t.Error("found no *ast.SelectorExpr")
  485. continue
  486. }
  487. const wantSel = "&{fmt _}"
  488. if fmt.Sprint(sel) != wantSel {
  489. t.Errorf("found selector %s, want %s", sel, wantSel)
  490. continue
  491. }
  492. }
  493. }