Commit 5ce9fde8 authored by Robert Griesemer's avatar Robert Griesemer

go/ast, go/parser: correct End() position for *ast.EmptyStmt

- added a new field ast.EmptyStmt.Implicit to indicate explicit
  or implicit semicolon
- fix ast.EmptyStmt.End() accordingly
- adjusted parser and added test case

Fixes #9979.

Change-Id: I72b0983b3a0cabea085598e1bf6c8df629776b57
Reviewed-on: https://go-review.googlesource.com/5720Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent c651fdc0
......@@ -12,6 +12,7 @@ crypto/cipher: clarify what will happen if len(src) != len(dst) for the Stream i
crypto/elliptic: add Name field to CurveParams struct (https://golang.org/cl/2133)
crypto/tls: change default minimum version to TLS 1.0. (https://golang.org/cl/1791)
encoding/base64: add unpadded encodings (https://golang.org/cl/1511)
go/ast: add Implicit field to ast.EmptyStmt; changed meaning of ast.EmptyStmt.Semicolon position (https://golang.org/cl/5720)
log: add SetOutput functions (https://golang.org/cl/2686, https://golang.org/cl/3023)
net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157)
net/http/cgi: fix REMOTE_ADDR, REMOTE_HOST, add REMOTE_PORT (https://golang.org/cl/4933)
......
......@@ -562,10 +562,11 @@ type (
// An EmptyStmt node represents an empty statement.
// The "position" of the empty statement is the position
// of the immediately preceding semicolon.
// of the immediately following (explicit or implicit) semicolon.
//
EmptyStmt struct {
Semicolon token.Pos // position of preceding ";"
Semicolon token.Pos // position of following ";"
Implicit bool // if set, ";" was omitted in the source
}
// A LabeledStmt node represents a labeled statement.
......@@ -734,6 +735,9 @@ func (s *RangeStmt) Pos() token.Pos { return s.For }
func (s *BadStmt) End() token.Pos { return s.To }
func (s *DeclStmt) End() token.Pos { return s.Decl.End() }
func (s *EmptyStmt) End() token.Pos {
if s.Implicit {
return s.Semicolon
}
return s.Semicolon + 1 /* len(";") */
}
func (s *LabeledStmt) End() token.Pos { return s.Stmt.End() }
......
......@@ -2152,11 +2152,14 @@ func (p *parser) parseStmt() (s ast.Stmt) {
case token.FOR:
s = p.parseForStmt()
case token.SEMICOLON:
s = &ast.EmptyStmt{Semicolon: p.pos}
// Is it ever possible to have an implicit semicolon
// producing an empty statement in a valid program?
// (handle correctly anyway)
s = &ast.EmptyStmt{Semicolon: p.pos, Implicit: p.lit == "\n"}
p.next()
case token.RBRACE:
// a semicolon may be omitted before a closing "}"
s = &ast.EmptyStmt{Semicolon: p.pos}
s = &ast.EmptyStmt{Semicolon: p.pos, Implicit: true}
default:
// no statement found
pos := p.pos
......
......@@ -445,3 +445,50 @@ type T struct {
t.Error("not expected to find T.f3")
}
}
// TestIssue9979 verifies that empty statements are contained within their enclosing blocks.
func TestIssue9979(t *testing.T) {
for _, src := range []string{
"package p; func f() {;}",
"package p; func f() {L:}",
"package p; func f() {L:;}",
"package p; func f() {L:\n}",
"package p; func f() {L:\n;}",
"package p; func f() { ; }",
"package p; func f() { L: }",
"package p; func f() { L: ; }",
"package p; func f() { L: \n}",
"package p; func f() { L: \n; }",
} {
fset := token.NewFileSet()
f, err := ParseFile(fset, "", src, 0)
if err != nil {
t.Fatal(err)
}
var pos, end token.Pos
ast.Inspect(f, func(x ast.Node) bool {
switch s := x.(type) {
case *ast.BlockStmt:
pos, end = s.Pos()+1, s.End()-1 // exclude "{", "}"
case *ast.LabeledStmt:
pos, end = s.Pos()+2, s.End() // exclude "L:"
case *ast.EmptyStmt:
// check containment
if s.Pos() < pos || s.End() > end {
t.Errorf("%s: %T[%d, %d] not inside [%d, %d]", src, s, s.Pos(), s.End(), pos, end)
}
// check semicolon
offs := fset.Position(s.Pos()).Offset
if ch := src[offs]; ch != ';' != s.Implicit {
want := "want ';'"
if s.Implicit {
want = "but ';' is implicit"
}
t.Errorf("%s: found %q at offset %d; %s", src, ch, offs, want)
}
}
return true
})
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment