aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2011-02-13 19:27:02 -0800
committerRobert Griesemer <gri@golang.org>2011-02-13 19:27:02 -0800
commit6b526eb300ad607fbe12f2f779d5c1639cefe109 (patch)
tree2604edeabfd94883e04d271bbd45b1fca40c718a
parentea46bda72b6b1e651d6f23a8d0b2704f263f9453 (diff)
downloadgo-6b526eb300ad607fbe12f2f779d5c1639cefe109.tar.gz
go-6b526eb300ad607fbe12f2f779d5c1639cefe109.zip
go/printer: line comments must always end in a newline
Fixes #1503. R=rsc CC=golang-dev https://golang.org/cl/4170045
-rw-r--r--src/pkg/go/printer/printer.go47
-rw-r--r--src/pkg/go/printer/printer_test.go37
2 files changed, 63 insertions, 21 deletions
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index 930576a67b..48e2af1b73 100644
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/go/printer/printer.go
@@ -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
}
diff --git a/src/pkg/go/printer/printer_test.go b/src/pkg/go/printer/printer_test.go
index c66471b926..565075aa20 100644
--- a/src/pkg/go/printer/printer_test.go
+++ b/src/pkg/go/printer/printer_test.go
@@ -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)
+ }
+}