Commit 3d4c12d9 authored by Robert Griesemer's avatar Robert Griesemer

go/printer: refine handling of one-line functions

Functions that "fit" on one line and were on one
line in the original source are not broken up into
two lines anymore simply because they contain a comment.

- Fine-tuned use of separating blanks after /*-style comments, so:

( /* extra blank after this comment */ )
(a int /* no extra blank after this comment*/)

- Factored out comment state (from printer state) into commentInfo.
- No impact on $GOROOT/src, misc formatting.

Fixes #5543.

LGTM=r
R=golang-codereviews, r
CC=golang-codereviews
https://golang.org/cl/68630043
parent 3081261b
...@@ -826,10 +826,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { ...@@ -826,10 +826,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
} }
p.print(x.Lbrace, token.LBRACE) p.print(x.Lbrace, token.LBRACE)
p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace) p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace)
// do not insert extra line breaks because of comments before // do not insert extra line break following a /*-style comment
// the closing '}' as it might break the code if there is no // before the closing '}' as it might break the code if there
// trailing ',' // is no trailing ','
p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak) mode := noExtraLinebreak
// do not insert extra blank following a /*-style comment
// before the closing '}' unless the literal is empty
if len(x.Elts) > 0 {
mode |= noExtraBlank
}
p.print(mode, x.Rbrace, token.RBRACE, mode)
case *ast.Ellipsis: case *ast.Ellipsis:
p.print(token.ELLIPSIS) p.print(token.ELLIPSIS)
...@@ -1461,13 +1467,16 @@ func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int { ...@@ -1461,13 +1467,16 @@ func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
// opening and closing brace are on different lines - don't make it a one-liner // opening and closing brace are on different lines - don't make it a one-liner
return maxSize + 1 return maxSize + 1
} }
if len(b.List) > 5 || p.commentBefore(p.posFor(pos2)) { if len(b.List) > 5 {
// too many statements or there is a comment inside - don't make it a one-liner // too many statements - don't make it a one-liner
return maxSize + 1 return maxSize + 1
} }
// otherwise, estimate body size // otherwise, estimate body size
bodySize := 0 bodySize := p.commentSizeBefore(p.posFor(pos2))
for i, s := range b.List { for i, s := range b.List {
if bodySize > maxSize {
break // no need to continue
}
if i > 0 { if i > 0 {
bodySize += 2 // space for a semicolon and blank bodySize += 2 // space for a semicolon and blank
} }
...@@ -1501,7 +1510,7 @@ func (p *printer) adjBlock(headerSize int, sep whiteSpace, b *ast.BlockStmt) { ...@@ -1501,7 +1510,7 @@ func (p *printer) adjBlock(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
} }
p.print(blank) p.print(blank)
} }
p.print(b.Rbrace, token.RBRACE) p.print(noExtraLinebreak, b.Rbrace, token.RBRACE, noExtraLinebreak)
return return
} }
......
...@@ -39,9 +39,17 @@ const ( ...@@ -39,9 +39,17 @@ const (
type pmode int type pmode int
const ( const (
noExtraLinebreak pmode = 1 << iota noExtraBlank pmode = 1 << iota // disables extra blank after /*-style comment
noExtraLinebreak // disables extra line break after /*-style comment
) )
type commentInfo struct {
cindex int // current comment index
comment *ast.CommentGroup // = printer.comments[cindex]; or nil
commentOffset int // = printer.posFor(printer.comments[cindex].List[0].Pos()).Offset; or infinity
commentNewline bool // true if the comment group contains newlines
}
type printer struct { type printer struct {
// Configuration (does not change after initialization) // Configuration (does not change after initialization)
Config Config
...@@ -52,7 +60,8 @@ type printer struct { ...@@ -52,7 +60,8 @@ type printer struct {
indent int // current indentation indent int // current indentation
mode pmode // current printer mode mode pmode // current printer mode
impliedSemi bool // if set, a linebreak implies a semicolon impliedSemi bool // if set, a linebreak implies a semicolon
lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace) lastTok token.Token // last token printed (token.ILLEGAL if it's whitespace)
prevOpen token.Token // previous non-brace "open" token (, [, or token.ILLEGAL
wsbuf []whiteSpace // delayed white space wsbuf []whiteSpace // delayed white space
// Positions // Positions
...@@ -67,13 +76,10 @@ type printer struct { ...@@ -67,13 +76,10 @@ type printer struct {
// The list of all source comments, in order of appearance. // The list of all source comments, in order of appearance.
comments []*ast.CommentGroup // may be nil comments []*ast.CommentGroup // may be nil
cindex int // current comment index
useNodeComments bool // if not set, ignore lead and line comments of nodes useNodeComments bool // if not set, ignore lead and line comments of nodes
// Information about p.comments[p.cindex]; set up by nextComment. // Information about p.comments[p.cindex]; set up by nextComment.
comment *ast.CommentGroup // = p.comments[p.cindex]; or nil commentInfo
commentOffset int // = p.posFor(p.comments[p.cindex].List[0].Pos()).Offset; or infinity
commentNewline bool // true if the comment group contains newlines
// Cache of already computed node sizes. // Cache of already computed node sizes.
nodeSizes map[ast.Node]int nodeSizes map[ast.Node]int
...@@ -129,6 +135,33 @@ func (p *printer) nextComment() { ...@@ -129,6 +135,33 @@ func (p *printer) nextComment() {
p.commentOffset = infinity p.commentOffset = infinity
} }
// commentBefore returns true iff the current comment group occurs
// before the next position in the source code and printing it does
// not introduce implicit semicolons.
//
func (p *printer) commentBefore(next token.Position) bool {
return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
}
// commentSizeBefore returns the estimated size of the
// comments on the same line before the next position.
//
func (p *printer) commentSizeBefore(next token.Position) int {
// save/restore current p.commentInfo (p.nextComment() modifies it)
defer func(info commentInfo) {
p.commentInfo = info
}(p.commentInfo)
size := 0
for p.commentBefore(next) {
for _, c := range p.comment.List {
size += len(c.Text)
}
p.nextComment()
}
return size
}
func (p *printer) internalError(msg ...interface{}) { func (p *printer) internalError(msg ...interface{}) {
if debug { if debug {
fmt.Print(p.pos.String() + ": ") fmt.Print(p.pos.String() + ": ")
...@@ -675,10 +708,14 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro ...@@ -675,10 +708,14 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
if last != nil { if last != nil {
// if the last comment is a /*-style comment and the next item // if the last comment is a /*-style comment and the next item
// follows on the same line but is not a comma or a "closing" // follows on the same line but is not a comma, and not a "closing"
// token, add an extra blank for separation // token immediately following its corresponding "opening" token,
if last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line && tok != token.COMMA && // add an extra blank for separation unless explicitly disabled
tok != token.RPAREN && tok != token.RBRACK && tok != token.RBRACE { if p.mode&noExtraBlank == 0 &&
last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line &&
tok != token.COMMA &&
(tok != token.RPAREN || p.prevOpen == token.LPAREN) &&
(tok != token.RBRACK || p.prevOpen == token.LBRACK) {
p.writeByte(' ', 1) p.writeByte(' ', 1)
} }
// ensure that there is a line break after a //-style comment, // ensure that there is a line break after a //-style comment,
...@@ -735,12 +772,8 @@ func (p *printer) writeWhitespace(n int) { ...@@ -735,12 +772,8 @@ func (p *printer) writeWhitespace(n int) {
} }
// shift remaining entries down // shift remaining entries down
i := 0 l := copy(p.wsbuf, p.wsbuf[n:])
for ; n < len(p.wsbuf); n++ { p.wsbuf = p.wsbuf[:l]
p.wsbuf[i] = p.wsbuf[n]
i++
}
p.wsbuf = p.wsbuf[0:i]
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
...@@ -790,6 +823,17 @@ func (p *printer) print(args ...interface{}) { ...@@ -790,6 +823,17 @@ func (p *printer) print(args ...interface{}) {
var isLit bool var isLit bool
var impliedSemi bool // value for p.impliedSemi after this arg var impliedSemi bool // value for p.impliedSemi after this arg
// record previous opening token, if any
switch p.lastTok {
case token.ILLEGAL:
// ignore (white space)
case token.LPAREN, token.LBRACK:
p.prevOpen = p.lastTok
default:
// other tokens followed any opening token
p.prevOpen = token.ILLEGAL
}
switch x := arg.(type) { switch x := arg.(type) {
case pmode: case pmode:
// toggle printer mode // toggle printer mode
...@@ -904,14 +948,6 @@ func (p *printer) print(args ...interface{}) { ...@@ -904,14 +948,6 @@ func (p *printer) print(args ...interface{}) {
} }
} }
// commentBefore returns true iff the current comment group occurs
// before the next position in the source code and printing it does
// not introduce implicit semicolons.
//
func (p *printer) commentBefore(next token.Position) (result bool) {
return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
}
// flush prints any pending comments and whitespace occurring textually // flush prints any pending comments and whitespace occurring textually
// before the position of the next token tok. The flush result indicates // before the position of the next token tok. The flush result indicates
// if a newline was written or if a formfeed was dropped from the whitespace // if a newline was written or if a formfeed was dropped from the whitespace
......
...@@ -494,16 +494,21 @@ func _() { ...@@ -494,16 +494,21 @@ func _() {
func _( /* this */ x /* is */ /* an */ int) { func _( /* this */ x /* is */ /* an */ int) {
} }
func _( /* no params */) {} func _( /* no params - extra blank before and after comment */ ) {}
func _(a, b int /* params - no extra blank after comment */) {}
func _() { f( /* no args - extra blank before and after comment */ ) }
func _() { f(a, b /* args - no extra blank after comment */) }
func _() { func _() {
f( /* no args */) f( /* no args - extra blank before and after comment */ )
f(a, b /* args - no extra blank after comment */)
} }
func ( /* comment1 */ T /* comment2 */) _() {} func ( /* comment1 */ T /* comment2 */) _() {}
func _() { /* one-line functions with comments are formatted as multi-line functions */ func _() { /* "short-ish one-line functions with comments are formatted as multi-line functions */ }
} func _() { x := 0; /* comment */ y = x /* comment */ }
func _() { func _() {
_ = 0 _ = 0
......
...@@ -500,15 +500,21 @@ func _() { ...@@ -500,15 +500,21 @@ func _() {
func _(/* this */x/* is *//* an */ int) { func _(/* this */x/* is *//* an */ int) {
} }
func _(/* no params */) {} func _(/* no params - extra blank before and after comment */) {}
func _(a, b int /* params - no extra blank after comment */) {}
func _() { f(/* no args - extra blank before and after comment */) }
func _() { f(a, b /* args - no extra blank after comment */) }
func _() { func _() {
f(/* no args */) f(/* no args - extra blank before and after comment */)
f(a, b /* args - no extra blank after comment */)
} }
func (/* comment1 */ T /* comment2 */) _() {} func (/* comment1 */ T /* comment2 */) _() {}
func _() { /* one-line functions with comments are formatted as multi-line functions */ } func _() { /* "short-ish one-line functions with comments are formatted as multi-line functions */ }
func _() { x := 0; /* comment */ y = x /* comment */ }
func _() { func _() {
_ = 0 _ = 0
......
...@@ -723,7 +723,8 @@ func _() int { ...@@ -723,7 +723,8 @@ func _() int {
} }
// making function declarations safe for new semicolon rules // making function declarations safe for new semicolon rules
func _() { /* multi-line func because of comment */ func _() { /* single-line function because of "short-ish" comment */ }
func _() { /* multi-line function because of "long-ish" comment - much more comment text is following here */ /* and more */
} }
func _() { func _() {
......
...@@ -737,7 +737,8 @@ func _() int { ...@@ -737,7 +737,8 @@ func _() int {
// making function declarations safe for new semicolon rules // making function declarations safe for new semicolon rules
func _() { /* multi-line func because of comment */ } func _() { /* single-line function because of "short-ish" comment */ }
func _() { /* multi-line function because of "long-ish" comment - much more comment text is following here */ /* and more */ }
func _() { func _() {
/* multi-line func because block is on multiple lines */ } /* multi-line func because block is on multiple lines */ }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment