Commit 6b526eb3 authored by Robert Griesemer's avatar Robert Griesemer

go/printer: line comments must always end in a newline

Fixes #1503.

R=rsc
CC=golang-dev
https://golang.org/cl/4170045
parent ea46bda7
......@@ -145,11 +145,13 @@ func (p *printer) nlines(n, min int) int {
// write0 does not indent after newlines, and does not HTML-escape or update p.pos.
//
func (p *printer) write0(data []byte) {
n, err := p.output.Write(data)
p.written += n
if err != nil {
p.errors <- err
runtime.Goexit()
if len(data) > 0 {
n, err := p.output.Write(data)
p.written += n
if err != nil {
p.errors <- err
runtime.Goexit()
}
}
}
......@@ -254,14 +256,13 @@ func (p *printer) writeItem(pos token.Position, data []byte) {
// If there is any pending whitespace, it consumes as much of
// it as is likely to help position the comment nicely.
// pos is the comment position, next the position of the item
// after all pending comments, isFirst indicates if this is the
// first comment in a group of comments, and isKeyword indicates
// if the next item is a keyword.
// after all pending comments, prev is the previous comment in
// a group of comments (or nil), and isKeyword indicates if the
// next item is a keyword.
//
func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeyword bool) {
if !p.last.IsValid() {
// there was no preceeding item and the comment is the
// first item to be printed - don't write any whitespace
func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment, isKeyword bool) {
if p.written == 0 {
// the comment is the first item to be printed - don't write any whitespace
return
}
......@@ -271,11 +272,12 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
return
}
if pos.IsValid() && pos.Line == p.last.Line {
if pos.Line == p.last.Line && (prev == nil || prev.Text[1] != '/') {
// comment on the same line as last item:
// separate with at least one separator
hasSep := false
if isFirst {
if prev == nil {
// first comment of a comment group
j := 0
for i, ch := range p.buffer {
switch ch {
......@@ -312,7 +314,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
} else {
// comment on a different line:
// separate with at least one line break
if isFirst {
if prev == nil {
// first comment of a comment group
j := 0
for i, ch := range p.buffer {
switch ch {
......@@ -344,10 +347,14 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
}
// use formfeeds to break columns before a comment;
// this is analogous to using formfeeds to separate
// individual lines of /*-style comments
// (if !pos.IsValid(), pos.Line == 0, and this will
// print no newlines)
p.writeNewlines(pos.Line-p.last.Line, true)
// individual lines of /*-style comments - but make
// sure there is at least one line break if the previous
// comment was a line comment
n := pos.Line - p.last.Line // if !pos.IsValid(), pos.Line == 0, and n will be 0
if n <= 0 && prev != nil && prev.Text[1] == '/' {
n = 1
}
p.writeNewlines(n, true)
}
}
......@@ -611,7 +618,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
var last *ast.Comment
for ; p.commentBefore(next); p.cindex++ {
for _, c := range p.comments[p.cindex].List {
p.writeCommentPrefix(p.fset.Position(c.Pos()), next, last == nil, tok.IsKeyword())
p.writeCommentPrefix(p.fset.Position(c.Pos()), next, last, tok.IsKeyword())
p.writeComment(c)
last = c
}
......
......@@ -127,7 +127,7 @@ var data = []entry{
}
func Test(t *testing.T) {
func TestFiles(t *testing.T) {
for _, e := range data {
source := path.Join(dataDir, e.source)
golden := path.Join(dataDir, e.golden)
......@@ -136,3 +136,38 @@ func Test(t *testing.T) {
//check(t, golden, golden, e.mode);
}
}
// TestLineComments, using a simple test case, checks that consequtive line
// comments are properly terminated with a newline even if the AST position
// information is incorrect.
//
func TestLineComments(t *testing.T) {
const src = `// comment 1
// comment 2
// comment 3
package main
`
fset := token.NewFileSet()
ast1, err1 := parser.ParseFile(fset, "", src, parser.ParseComments)
if err1 != nil {
panic(err1)
}
var buf bytes.Buffer
fset = token.NewFileSet() // use the wrong file set
Fprint(&buf, fset, ast1)
nlines := 0
for _, ch := range buf.Bytes() {
if ch == '\n' {
nlines++
}
}
const expected = 3
if nlines < expected {
t.Errorf("got %d, expected %d\n", nlines, expected)
}
}
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