]> Cypherpunks repositories - gostls13.git/commitdiff
go/parser, go/ast: correctly take into account presence of } in block
authorRobert Griesemer <gri@golang.org>
Tue, 22 Oct 2019 00:01:14 +0000 (17:01 -0700)
committerRobert Griesemer <gri@golang.org>
Mon, 28 Oct 2019 20:47:07 +0000 (20:47 +0000)
Correctly track whether the closing } of a block (or a function body)
is present or not in the AST and report correct End() positions in
each case.

There are more cases like this but this CL addresses an immediate
issue and sets a precedent for how to fix similar cases if a need
arises.

Fixes #33649.

Change-Id: Id6662ddaac09f3c15f8003edc9275fe2b0c41c78
Reviewed-on: https://go-review.googlesource.com/c/go/+/202581
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
src/go/ast/ast.go
src/go/ast/issues_test.go [new file with mode: 0644]
src/go/parser/parser.go

index d8f6f668cc47e97d8e96158f6548319754c97e55..9e1da35287216d7c0bc7e8f3b3b7fdee4306858e 100644 (file)
@@ -634,7 +634,7 @@ type (
        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.
@@ -757,7 +757,15 @@ func (s *BranchStmt) End() token.Pos {
        }
        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()
diff --git a/src/go/ast/issues_test.go b/src/go/ast/issues_test.go
new file mode 100644 (file)
index 0000000..788c557
--- /dev/null
@@ -0,0 +1,42 @@
+// 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())
+               }
+       }
+}
index 3a468d096bca58a5191b9acb3d3ab55a6ec4675e..beb563f25fb6d993ed3e7e7f4734c1312307b9d0 100644 (file)
@@ -397,6 +397,18 @@ func (p *parser) expect(tok token.Token) token.Pos {
        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.
 //
@@ -1082,7 +1094,7 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
        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}
 }
@@ -1096,7 +1108,7 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
        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}
 }