]> Cypherpunks repositories - gostls13.git/commitdiff
go/printer: line comments must always end in a newline
authorRobert Griesemer <gri@golang.org>
Mon, 14 Feb 2011 03:27:02 +0000 (19:27 -0800)
committerRobert Griesemer <gri@golang.org>
Mon, 14 Feb 2011 03:27:02 +0000 (19:27 -0800)
Fixes #1503.

R=rsc
CC=golang-dev
https://golang.org/cl/4170045

src/pkg/go/printer/printer.go
src/pkg/go/printer/printer_test.go

index 930576a67b73f35aad04f8b6e0f55af1f1f1a5d3..48e2af1b736af7ac1b74fea78b38d9fca17792b8 100644 (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.
 //
 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
                }
index c66471b926a6f83f522319a64aa4e411c7e1c512..565075aa20cd948ee07db7c33679fcdb48108b16 100644 (file)
@@ -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)
+       }
+}