Skip to content

Commit c3f1630

Browse files
mateusz834gopherbot
authored andcommitted
go/printer: do not treat comments inside a ast.Decl as godoc
This change makes sure that we do not format comments as doc comments inside of a declaration and makes the go doc formatter idempotent: Previously: // test comment //go:directive2 // test comment func main() { } was formatted to: // test comment //go:directive2 // test comment func main() { } after another formatting, it got formatted with doc rules into: // test comment // test comment // //go:directive2 func main() { } With this change it gets directly to the correct form (last one). Change-Id: Id7d8f03e43474357cd714e0672e886652c3fce86 GitHub-Last-Rev: 9833b87 GitHub-Pull-Request: #69134 Reviewed-on: https://go-review.googlesource.com/c/go/+/609077 Reviewed-by: Dmitri Shuralyov <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> Auto-Submit: Robert Griesemer <[email protected]>
1 parent 89958ab commit c3f1630

File tree

3 files changed

+201
-2
lines changed

3 files changed

+201
-2
lines changed

src/go/printer/nodes.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,6 +1737,9 @@ func (p *printer) genDecl(d *ast.GenDecl) {
17371737
p.setPos(d.Pos())
17381738
p.print(d.Tok, blank)
17391739

1740+
defer func(d bool) { p.inDecl = d }(p.inDecl)
1741+
p.inDecl = true
1742+
17401743
if d.Lparen.IsValid() || len(d.Specs) != 1 {
17411744
// group of parenthesized declarations
17421745
p.setPos(d.Lparen)
@@ -1921,6 +1924,10 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
19211924
p.setComment(d.Doc)
19221925
p.setPos(d.Pos())
19231926
p.print(token.FUNC, blank)
1927+
1928+
defer func(d bool) { p.inDecl = d }(p.inDecl)
1929+
p.inDecl = true
1930+
19241931
// We have to save startCol only after emitting FUNC; otherwise it can be on a
19251932
// different line (all whitespace preceding the FUNC is emitted only when the
19261933
// FUNC is emitted).

src/go/printer/printer.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type printer struct {
6363
mode pmode // current printer mode
6464
endAlignment bool // if set, terminate alignment immediately
6565
impliedSemi bool // if set, a linebreak implies a semicolon
66+
inDecl bool // if set, printer is inside declaration (after first token)
6667
lastTok token.Token // last token printed (token.ILLEGAL if it's whitespace)
6768
prevOpen token.Token // previous non-brace "open" token (, [, or token.ILLEGAL
6869
wsbuf []whiteSpace // delayed white space
@@ -739,8 +740,9 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
739740
for p.commentBefore(next) {
740741
list := p.comment.List
741742
changed := false
742-
if p.lastTok != token.IMPORT && // do not rewrite cgo's import "C" comments
743-
p.posFor(p.comment.Pos()).Column == 1 &&
743+
if !p.inDecl &&
744+
p.lastTok != token.IMPORT && // do not rewrite cgo's import "C" comments
745+
p.posFor(p.comment.Pos()).Line != p.last.Line &&
744746
p.posFor(p.comment.End()+1) == next {
745747
// Unindented comment abutting next token position:
746748
// a top-level doc comment.

src/go/printer/printer_test.go

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"io"
1717
"os"
1818
"path/filepath"
19+
"strings"
1920
"testing"
2021
"time"
2122
)
@@ -863,3 +864,192 @@ func TestEmptyDecl(t *testing.T) { // issue 63566
863864
}
864865
}
865866
}
867+
868+
func TestDocFormat(t *testing.T) {
869+
cases := []struct {
870+
src string
871+
want string
872+
}{
873+
{
874+
src: `package main
875+
876+
func main() {
877+
//
878+
//go:directive
879+
// test
880+
//
881+
}
882+
`,
883+
want: `package main
884+
885+
func main() {
886+
//
887+
//go:directive
888+
// test
889+
//
890+
}
891+
`,
892+
},
893+
{
894+
src: `package main
895+
896+
func main() {
897+
//go:directive
898+
// test
899+
type a struct{}
900+
901+
//go:directive
902+
// test
903+
test()
904+
}
905+
`,
906+
want: `package main
907+
908+
func main() {
909+
//go:directive
910+
// test
911+
type a struct{}
912+
913+
//go:directive
914+
// test
915+
test()
916+
}
917+
`,
918+
},
919+
{
920+
src: `package main
921+
922+
func main() {
923+
//go:directive
924+
// test
925+
type a struct{}
926+
}
927+
`,
928+
want: `package main
929+
930+
func main() {
931+
//go:directive
932+
// test
933+
type a struct{}
934+
}
935+
`,
936+
},
937+
{
938+
src: `package main
939+
940+
func a() {
941+
//line a:5:1
942+
//
943+
}
944+
`,
945+
want: `package main
946+
947+
func a() {
948+
//line a:5:1
949+
//
950+
}
951+
`,
952+
},
953+
954+
{
955+
src: `package main
956+
957+
// test comment
958+
//go:directive2
959+
// test comment
960+
func main() {
961+
}
962+
`,
963+
want: `package main
964+
965+
// test comment
966+
// test comment
967+
//
968+
//go:directive2
969+
func main() {
970+
}
971+
`,
972+
},
973+
{
974+
src: `package main
975+
976+
// test comment
977+
//go:directive2
978+
// test comment
979+
func main() {
980+
}
981+
`,
982+
want: `package main
983+
984+
// test comment
985+
// test comment
986+
//
987+
//go:directive2
988+
func main() {
989+
}
990+
`,
991+
},
992+
{
993+
src: `package main
994+
995+
/* test
996+
*/ // test comment
997+
//go:directive2
998+
// test comment
999+
func main() {
1000+
}
1001+
`,
1002+
want: `package main
1003+
1004+
/* test
1005+
*/ // test comment
1006+
//go:directive2
1007+
// test comment
1008+
func main() {
1009+
}
1010+
`,
1011+
},
1012+
1013+
{
1014+
src: `package main //comment
1015+
var a int = 4 //comment
1016+
func a() {
1017+
}
1018+
`,
1019+
want: `package main //comment
1020+
var a int = 4 //comment
1021+
func a() {
1022+
}
1023+
`,
1024+
},
1025+
1026+
// Edge case found by a fuzzer, not a real-world example.
1027+
{
1028+
src: "package A\n\nimport(\"\f\"\n//\n\"\")",
1029+
want: "package A\n\nimport (\n\t\"\f\" //\n\t\"\"\n)\n",
1030+
},
1031+
{
1032+
src: "package A\n\nimport(`\f`\n//\n\"\")",
1033+
want: "package A\n\nimport (\n\t`\f` //\n\t\"\"\n)\n",
1034+
},
1035+
}
1036+
1037+
for _, tt := range cases {
1038+
fset := token.NewFileSet()
1039+
f, err := parser.ParseFile(fset, "test.go", tt.src, parser.ParseComments|parser.SkipObjectResolution)
1040+
if err != nil {
1041+
t.Fatal(err)
1042+
}
1043+
1044+
var buf strings.Builder
1045+
cfg := Config{Tabwidth: 8, Mode: UseSpaces | TabIndent}
1046+
if err := cfg.Fprint(&buf, fset, f); err != nil {
1047+
t.Fatal(err)
1048+
}
1049+
1050+
got := buf.String()
1051+
if got != tt.want {
1052+
t.Errorf("source\n%v\nformatted as:\n%v\nwant formatted as:\n%v", tt.src, got, tt.want)
1053+
}
1054+
}
1055+
}

0 commit comments

Comments
 (0)