BlockStmt struct {
Lbrace token.Pos // position of "{"
List []Stmt
- Rbrace token.Pos // position of "}"
+ Rbrace token.Pos // position of "}", if any (may be absent due to syntax error)
}
// An IfStmt node represents an if statement.
}
return token.Pos(int(s.TokPos) + len(s.Tok.String()))
}
-func (s *BlockStmt) End() token.Pos { return s.Rbrace + 1 }
+func (s *BlockStmt) End() token.Pos {
+ if s.Rbrace.IsValid() {
+ return s.Rbrace + 1
+ }
+ if n := len(s.List); n > 0 {
+ return s.List[n-1].End()
+ }
+ return s.Lbrace + 1
+}
func (s *IfStmt) End() token.Pos {
if s.Else != nil {
return s.Else.End()
--- /dev/null
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ast_test
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "testing"
+)
+
+func TestIssue33649(t *testing.T) {
+ for _, src := range []string{
+ `package p; func _()`,
+ `package p; func _() {`,
+ `package p; func _() { _ = 0`,
+ `package p; func _() { _ = 0 }`,
+ } {
+ fset := token.NewFileSet()
+ f, _ := parser.ParseFile(fset, "", src, parser.AllErrors)
+ if f == nil {
+ panic("invalid test setup: parser didn't return an AST")
+ }
+
+ // find corresponding token.File
+ var tf *token.File
+ fset.Iterate(func(f *token.File) bool {
+ tf = f
+ return true
+ })
+ tfEnd := tf.Base() + tf.Size()
+
+ fd := f.Decls[len(f.Decls)-1].(*ast.FuncDecl)
+ fdEnd := int(fd.End())
+
+ if fdEnd != tfEnd {
+ t.Errorf("%q: got fdEnd = %d; want %d (base = %d, size = %d)", src, fdEnd, tfEnd, tf.Base(), tf.Size())
+ }
+ }
+}
return pos
}
+// expect2 is like expect, but it returns an invalid position
+// if the expected token is not found.
+func (p *parser) expect2(tok token.Token) (pos token.Pos) {
+ if p.tok == tok {
+ pos = p.pos
+ } else {
+ p.errorExpected(pos, "'"+tok.String()+"'")
+ }
+ p.next() // make progress
+ return
+}
+
// expectClosing is like expect but provides a better error message
// for the common case of a missing comma before a newline.
//
list := p.parseStmtList()
p.closeLabelScope()
p.closeScope()
- rbrace := p.expect(token.RBRACE)
+ rbrace := p.expect2(token.RBRACE)
return &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
}
p.openScope()
list := p.parseStmtList()
p.closeScope()
- rbrace := p.expect(token.RBRACE)
+ rbrace := p.expect2(token.RBRACE)
return &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
}