1
0
mirror of https://github.com/golang/go synced 2024-11-25 04:47:57 -07:00

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

Fixes #1503.

R=rsc
CC=golang-dev
https://golang.org/cl/4170045
This commit is contained in:
Robert Griesemer 2011-02-13 19:27:02 -08:00
parent ea46bda72b
commit 6b526eb300
2 changed files with 63 additions and 21 deletions

View File

@ -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. // write0 does not indent after newlines, and does not HTML-escape or update p.pos.
// //
func (p *printer) write0(data []byte) { func (p *printer) write0(data []byte) {
n, err := p.output.Write(data) if len(data) > 0 {
p.written += n n, err := p.output.Write(data)
if err != nil { p.written += n
p.errors <- err if err != nil {
runtime.Goexit() 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 // If there is any pending whitespace, it consumes as much of
// it as is likely to help position the comment nicely. // it as is likely to help position the comment nicely.
// pos is the comment position, next the position of the item // pos is the comment position, next the position of the item
// after all pending comments, isFirst indicates if this is the // after all pending comments, prev is the previous comment in
// first comment in a group of comments, and isKeyword indicates // a group of comments (or nil), and isKeyword indicates if the
// if the next item is a keyword. // next item is a keyword.
// //
func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeyword bool) { func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment, isKeyword bool) {
if !p.last.IsValid() { if p.written == 0 {
// there was no preceeding item and the comment is the // the comment is the first item to be printed - don't write any whitespace
// first item to be printed - don't write any whitespace
return return
} }
@ -271,11 +272,12 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
return 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: // comment on the same line as last item:
// separate with at least one separator // separate with at least one separator
hasSep := false hasSep := false
if isFirst { if prev == nil {
// first comment of a comment group
j := 0 j := 0
for i, ch := range p.buffer { for i, ch := range p.buffer {
switch ch { switch ch {
@ -312,7 +314,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
} else { } else {
// comment on a different line: // comment on a different line:
// separate with at least one line break // separate with at least one line break
if isFirst { if prev == nil {
// first comment of a comment group
j := 0 j := 0
for i, ch := range p.buffer { for i, ch := range p.buffer {
switch ch { switch ch {
@ -344,10 +347,14 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
} }
// use formfeeds to break columns before a comment; // use formfeeds to break columns before a comment;
// this is analogous to using formfeeds to separate // this is analogous to using formfeeds to separate
// individual lines of /*-style comments // individual lines of /*-style comments - but make
// (if !pos.IsValid(), pos.Line == 0, and this will // sure there is at least one line break if the previous
// print no newlines) // comment was a line comment
p.writeNewlines(pos.Line-p.last.Line, true) 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 var last *ast.Comment
for ; p.commentBefore(next); p.cindex++ { for ; p.commentBefore(next); p.cindex++ {
for _, c := range p.comments[p.cindex].List { 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) p.writeComment(c)
last = c last = c
} }

View File

@ -127,7 +127,7 @@ var data = []entry{
} }
func Test(t *testing.T) { func TestFiles(t *testing.T) {
for _, e := range data { for _, e := range data {
source := path.Join(dataDir, e.source) source := path.Join(dataDir, e.source)
golden := path.Join(dataDir, e.golden) golden := path.Join(dataDir, e.golden)
@ -136,3 +136,38 @@ func Test(t *testing.T) {
//check(t, golden, golden, e.mode); //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)
}
}