mirror of https://github.com/golang/go.git
go/printer: format doc comments
[This CL is part of a sequence implementing the proposal #51082. The design doc is at https://go.dev/s/godocfmt-design.] Use go/doc/comment to reformat doc comments into a standard form, enabling future expansion later and generally making it easier to edit and read doc comments. For #51082. Change-Id: I6ab3b80846f03d781951111e4c36f86f47d21bb2 Reviewed-on: https://go-review.googlesource.com/c/go/+/384264 Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Jonathan Amsterdam <jba@google.com> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
e1b0862925
commit
078cc6a04f
|
|
@ -159,6 +159,7 @@ func (g *CommentGroup) Text() string {
|
|||
}
|
||||
|
||||
// isDirective reports whether c is a comment directive.
|
||||
// This code is also in go/printer.
|
||||
func isDirective(c string) bool {
|
||||
// "//line " is a line directive.
|
||||
// (The // has been removed.)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,152 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package printer
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/doc/comment"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// formatDocComment reformats the doc comment list,
|
||||
// returning the canonical formatting.
|
||||
func formatDocComment(list []*ast.Comment) []*ast.Comment {
|
||||
// Extract comment text (removing comment markers).
|
||||
var kind, text string
|
||||
var directives []*ast.Comment
|
||||
if len(list) == 1 && strings.HasPrefix(list[0].Text, "/*") {
|
||||
kind = "/*"
|
||||
text = list[0].Text
|
||||
if !strings.Contains(text, "\n") || allStars(text) {
|
||||
// Single-line /* .. */ comment in doc comment position,
|
||||
// or multiline old-style comment like
|
||||
// /*
|
||||
// * Comment
|
||||
// * text here.
|
||||
// */
|
||||
// Should not happen, since it will not work well as a
|
||||
// doc comment, but if it does, just ignore:
|
||||
// reformatting it will only make the situation worse.
|
||||
return list
|
||||
}
|
||||
text = text[2 : len(text)-2] // cut /* and */
|
||||
} else if strings.HasPrefix(list[0].Text, "//") {
|
||||
kind = "//"
|
||||
var b strings.Builder
|
||||
for _, c := range list {
|
||||
if !strings.HasPrefix(c.Text, "//") {
|
||||
return list
|
||||
}
|
||||
// Accumulate //go:build etc lines separately.
|
||||
if isDirective(c.Text[2:]) {
|
||||
directives = append(directives, c)
|
||||
continue
|
||||
}
|
||||
b.WriteString(strings.TrimPrefix(c.Text[2:], " "))
|
||||
b.WriteString("\n")
|
||||
}
|
||||
text = b.String()
|
||||
} else {
|
||||
// Not sure what this is, so leave alone.
|
||||
return list
|
||||
}
|
||||
|
||||
if text == "" {
|
||||
return list
|
||||
}
|
||||
|
||||
// Parse comment and reformat as text.
|
||||
var p comment.Parser
|
||||
d := p.Parse(text)
|
||||
|
||||
var pr comment.Printer
|
||||
text = string(pr.Comment(d))
|
||||
|
||||
// For /* */ comment, return one big comment with text inside.
|
||||
slash := list[0].Slash
|
||||
if kind == "/*" {
|
||||
c := &ast.Comment{
|
||||
Slash: slash,
|
||||
Text: "/*\n" + text + "*/",
|
||||
}
|
||||
return []*ast.Comment{c}
|
||||
}
|
||||
|
||||
// For // comment, return sequence of // lines.
|
||||
var out []*ast.Comment
|
||||
for text != "" {
|
||||
var line string
|
||||
line, text, _ = strings.Cut(text, "\n")
|
||||
if line == "" {
|
||||
line = "//"
|
||||
} else if strings.HasPrefix(line, "\t") {
|
||||
line = "//" + line
|
||||
} else {
|
||||
line = "// " + line
|
||||
}
|
||||
out = append(out, &ast.Comment{
|
||||
Slash: slash,
|
||||
Text: line,
|
||||
})
|
||||
}
|
||||
if len(directives) > 0 {
|
||||
out = append(out, &ast.Comment{
|
||||
Slash: slash,
|
||||
Text: "//",
|
||||
})
|
||||
for _, c := range directives {
|
||||
out = append(out, &ast.Comment{
|
||||
Slash: slash,
|
||||
Text: c.Text,
|
||||
})
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// isDirective reports whether c is a comment directive.
|
||||
// See go.dev/issue/37974.
|
||||
// This code is also in go/ast.
|
||||
func isDirective(c string) bool {
|
||||
// "//line " is a line directive.
|
||||
// (The // has been removed.)
|
||||
if strings.HasPrefix(c, "line ") {
|
||||
return true
|
||||
}
|
||||
|
||||
// "//[a-z0-9]+:[a-z0-9]"
|
||||
// (The // has been removed.)
|
||||
colon := strings.Index(c, ":")
|
||||
if colon <= 0 || colon+1 >= len(c) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i <= colon+1; i++ {
|
||||
if i == colon {
|
||||
continue
|
||||
}
|
||||
b := c[i]
|
||||
if !('a' <= b && b <= 'z' || '0' <= b && b <= '9') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// allStars reports whether text is the interior of an
|
||||
// old-style /* */ comment with a star at the start of each line.
|
||||
func allStars(text string) bool {
|
||||
for i := 0; i < len(text); i++ {
|
||||
if text[i] == '\n' {
|
||||
j := i + 1
|
||||
for j < len(text) && (text[j] == ' ' || text[j] == '\t') {
|
||||
j++
|
||||
}
|
||||
if j < len(text) && text[j] != '*' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -738,11 +738,28 @@ func (p *printer) containsLinebreak() bool {
|
|||
func (p *printer) intersperseComments(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
|
||||
var last *ast.Comment
|
||||
for p.commentBefore(next) {
|
||||
for _, c := range p.comment.List {
|
||||
list := p.comment.List
|
||||
changed := false
|
||||
if p.lastTok != token.IMPORT && // do not rewrite cgo's import "C" comments
|
||||
p.posFor(p.comment.Pos()).Column == 1 &&
|
||||
p.posFor(p.comment.End()+1) == next {
|
||||
// Unindented comment abutting next token position:
|
||||
// a top-level doc comment.
|
||||
list = formatDocComment(list)
|
||||
changed = true
|
||||
}
|
||||
for _, c := range list {
|
||||
p.writeCommentPrefix(p.posFor(c.Pos()), next, last, tok)
|
||||
p.writeComment(c)
|
||||
last = c
|
||||
}
|
||||
// In case list was rewritten, change print state to where
|
||||
// the original list would have ended.
|
||||
if len(p.comment.List) > 0 && changed {
|
||||
last = p.comment.List[len(p.comment.List)-1]
|
||||
p.pos = p.posFor(last.End())
|
||||
p.last = p.pos
|
||||
}
|
||||
p.nextComment()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package printer
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
|
|
@ -92,8 +93,7 @@ func checkEqual(aname, bname string, a, b []byte) error {
|
|||
if bytes.Equal(a, b) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("diff %s %s\n%s", aname, bname, diff.Diff(aname, a, bname, b))
|
||||
return errors.New(string(diff.Diff(aname, a, bname, b)))
|
||||
}
|
||||
|
||||
func runcheck(t *testing.T, source, golden string, mode checkMode) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This is a package for testing comment placement by go/printer.
|
||||
//
|
||||
package main
|
||||
|
||||
import "fmt" // fmt
|
||||
|
|
@ -97,6 +96,13 @@ type S3 struct {
|
|||
f3 int // f3 is not exported
|
||||
}
|
||||
|
||||
// Here is a comment.
|
||||
// Here is an accidentally unindented line.
|
||||
// More comment.
|
||||
//
|
||||
//dir:ect ive
|
||||
type directiveCheck struct{}
|
||||
|
||||
// This comment group should be separated
|
||||
// with a newline from the next comment
|
||||
// group.
|
||||
|
|
@ -116,9 +122,7 @@ func f0() {
|
|||
x := pi
|
||||
}
|
||||
|
||||
//
|
||||
// This comment should be associated with f1, with one blank line before the comment.
|
||||
//
|
||||
func f1() {
|
||||
f0()
|
||||
/* 1 */
|
||||
|
|
@ -691,6 +695,7 @@ func _() {
|
|||
// Print line directives correctly.
|
||||
|
||||
// The following is a legal line directive.
|
||||
//
|
||||
//line foo:1
|
||||
func _() {
|
||||
_ = 0
|
||||
|
|
|
|||
|
|
@ -97,6 +97,12 @@ type S3 struct {
|
|||
f3 int // f3 is not exported
|
||||
}
|
||||
|
||||
// Here is a comment.
|
||||
//Here is an accidentally unindented line.
|
||||
//dir:ect ive
|
||||
// More comment.
|
||||
type directiveCheck struct{}
|
||||
|
||||
// This comment group should be separated
|
||||
// with a newline from the next comment
|
||||
// group.
|
||||
|
|
@ -616,7 +622,7 @@ func _() {
|
|||
func _() {
|
||||
f(); f()
|
||||
f(); /* comment */ f()
|
||||
f() /* comment */; f()
|
||||
f() /* comment */; f()
|
||||
f(); /* a */ /* b */ f()
|
||||
f() /* a */ /* b */; f()
|
||||
f() /* a */; /* b */ f()
|
||||
|
|
@ -663,7 +669,7 @@ func _() {
|
|||
// This way, commas interspersed in lists stay with the respective expression.
|
||||
func f(x/* comment */, y int, z int /* comment */, u, v, w int /* comment */) {
|
||||
f(x /* comment */, y)
|
||||
f(x /* comment */,
|
||||
f(x /* comment */,
|
||||
y)
|
||||
f(
|
||||
x /* comment */,
|
||||
|
|
@ -718,10 +724,10 @@ var lflag bool // -l - disable line directives
|
|||
|
||||
// Trailing white space in comments should be trimmed
|
||||
func _() {
|
||||
// This comment has 4 blanks following that should be trimmed:
|
||||
/* Each line of this comment has blanks or tabs following that should be trimmed:
|
||||
line 2:
|
||||
line 3:
|
||||
// This comment has 4 blanks following that should be trimmed:
|
||||
/* Each line of this comment has blanks or tabs following that should be trimmed:
|
||||
line 2:
|
||||
line 3:
|
||||
*/
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
// This is a package for testing comment placement by go/printer.
|
||||
//
|
||||
package main
|
||||
|
||||
// The SZ struct; it is empty.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This is a package for testing comment placement by go/printer.
|
||||
//
|
||||
package main
|
||||
|
||||
// Test cases for idempotent comment formatting (was issue 1835).
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package p
|
||||
|
||||
/*
|
||||
Doc comment.
|
||||
|
||||
- List1.
|
||||
|
||||
- List2.
|
||||
*/
|
||||
var X int
|
||||
|
||||
/* erroneous doc comment */
|
||||
var Y int
|
||||
|
||||
/*
|
||||
* Another erroneous
|
||||
* doc comment.
|
||||
*/
|
||||
var Z int
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package p
|
||||
|
||||
/*
|
||||
Doc comment.
|
||||
- List1.
|
||||
|
||||
- List2.
|
||||
*/
|
||||
var X int
|
||||
|
||||
/* erroneous doc comment */
|
||||
var Y int
|
||||
|
||||
/*
|
||||
* Another erroneous
|
||||
* doc comment.
|
||||
*/
|
||||
var Z int
|
||||
|
||||
|
||||
Loading…
Reference in New Issue