mirror of
https://github.com/golang/go
synced 2024-11-24 20:20:03 -07:00
godoc: don't convert multi-line functions into one-liners by default
- new heuristic: if both the opening { and closing } braces are on the same line, and the function body doesn't contain comments or is other- wise too long (e.g. signature too long), it is formatted as a one-line function - related cleanups along the way - gofmt -w src misc led to no additional changes as expected R=rsc, rsc1 CC=golang-dev, ken2, r https://golang.org/cl/758041
This commit is contained in:
parent
c93273c0f5
commit
6358e1faf6
@ -74,7 +74,7 @@ func (p *printer) setComment(g *ast.CommentGroup) {
|
|||||||
// for some reason there are pending comments; this
|
// for some reason there are pending comments; this
|
||||||
// should never happen - handle gracefully and flush
|
// should never happen - handle gracefully and flush
|
||||||
// all comments up to g, ignore anything after that
|
// all comments up to g, ignore anything after that
|
||||||
p.flush(g.List[0].Pos(), false)
|
p.flush(g.List[0].Pos(), token.ILLEGAL)
|
||||||
}
|
}
|
||||||
p.comments[0] = g
|
p.comments[0] = g
|
||||||
p.cindex = 0
|
p.cindex = 0
|
||||||
@ -112,7 +112,6 @@ func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
|
|||||||
// Compute the key size of a key:value expression.
|
// Compute the key size of a key:value expression.
|
||||||
// Returns 0 if the expression doesn't fit onto a single line.
|
// Returns 0 if the expression doesn't fit onto a single line.
|
||||||
func (p *printer) keySize(pair *ast.KeyValueExpr) int {
|
func (p *printer) keySize(pair *ast.KeyValueExpr) int {
|
||||||
const infinity = 1e6 // larger than any source line
|
|
||||||
if p.nodeSize(pair, infinity) <= infinity {
|
if p.nodeSize(pair, infinity) <= infinity {
|
||||||
// entire expression fits on one line - return key size
|
// entire expression fits on one line - return key size
|
||||||
return p.nodeSize(pair.Key, infinity)
|
return p.nodeSize(pair.Key, infinity)
|
||||||
@ -431,7 +430,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
|
|||||||
if len(list) > 0 {
|
if len(list) > 0 {
|
||||||
p.print(formfeed)
|
p.print(formfeed)
|
||||||
}
|
}
|
||||||
p.flush(rbrace, false) // make sure we don't loose the last line comment
|
p.flush(rbrace, token.RBRACE) // make sure we don't loose the last line comment
|
||||||
p.setLineComment("// contains unexported fields")
|
p.setLineComment("// contains unexported fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +457,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
|
|||||||
if len(list) > 0 {
|
if len(list) > 0 {
|
||||||
p.print(formfeed)
|
p.print(formfeed)
|
||||||
}
|
}
|
||||||
p.flush(rbrace, false) // make sure we don't loose the last line comment
|
p.flush(rbrace, token.RBRACE) // make sure we don't loose the last line comment
|
||||||
p.setLineComment("// contains unexported methods")
|
p.setLineComment("// contains unexported methods")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1224,16 +1223,26 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
|
|||||||
|
|
||||||
|
|
||||||
func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
|
func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
|
||||||
const maxSize = 90 // adjust as appropriate, this is an approximate value
|
pos1 := b.Pos()
|
||||||
bodySize := 0
|
pos2 := b.Rbrace
|
||||||
switch {
|
if pos1.IsValid() && pos2.IsValid() && pos1.Line != pos2.Line {
|
||||||
case len(b.List) > 1 || p.commentBefore(b.Rbrace):
|
// opening and closing brace are on different lines - don't make it a one-liner
|
||||||
return false // too many statements or there is a comment - all bets are off
|
return false
|
||||||
case len(b.List) == 1:
|
|
||||||
bodySize = p.nodeSize(b.List[0], maxSize)
|
|
||||||
}
|
}
|
||||||
// require both headers and overall size to be not "too large"
|
if len(b.List) > 5 || p.commentBefore(pos2) {
|
||||||
return headerSize <= maxSize/2 && headerSize+bodySize <= maxSize
|
// too many statements or there is a comment inside - don't make it a one-liner
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// otherwise, estimate body size
|
||||||
|
const maxSize = 100
|
||||||
|
bodySize := 0
|
||||||
|
for i, s := range b.List {
|
||||||
|
if i > 0 {
|
||||||
|
bodySize += 2 // space for a semicolon and blank
|
||||||
|
}
|
||||||
|
bodySize += p.nodeSize(s, maxSize)
|
||||||
|
}
|
||||||
|
return headerSize+bodySize <= maxSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1248,13 +1257,18 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
|
|||||||
if isLit {
|
if isLit {
|
||||||
sep = blank
|
sep = blank
|
||||||
}
|
}
|
||||||
|
p.print(sep, b.Pos(), token.LBRACE)
|
||||||
if len(b.List) > 0 {
|
if len(b.List) > 0 {
|
||||||
p.print(sep, b.Pos(), token.LBRACE, blank)
|
p.print(blank)
|
||||||
p.stmt(b.List[0], ignoreMultiLine)
|
for i, s := range b.List {
|
||||||
p.print(blank, b.Rbrace, token.RBRACE)
|
if i > 0 {
|
||||||
} else {
|
p.print(token.SEMICOLON, blank)
|
||||||
p.print(sep, b.Pos(), token.LBRACE, b.Rbrace, token.RBRACE)
|
}
|
||||||
|
p.stmt(s, ignoreMultiLine)
|
||||||
|
}
|
||||||
|
p.print(blank)
|
||||||
}
|
}
|
||||||
|
p.print(b.Rbrace, token.RBRACE)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1266,12 +1280,12 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
|
|||||||
|
|
||||||
// distance returns the column difference between from and to if both
|
// distance returns the column difference between from and to if both
|
||||||
// are on the same line; if they are on different lines (or unknown)
|
// are on the same line; if they are on different lines (or unknown)
|
||||||
// the result is infinity (1<<30).
|
// the result is infinity.
|
||||||
func distance(from, to token.Position) int {
|
func distance(from, to token.Position) int {
|
||||||
if from.IsValid() && to.IsValid() && from.Line == to.Line {
|
if from.IsValid() && to.IsValid() && from.Line == to.Line {
|
||||||
return to.Column - from.Column
|
return to.Column - from.Column
|
||||||
}
|
}
|
||||||
return 1 << 30
|
return infinity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,8 +53,8 @@ var (
|
|||||||
|
|
||||||
|
|
||||||
// Special positions
|
// Special positions
|
||||||
var noPos token.Position // use noPos when a position is needed but not known
|
var noPos token.Position // use noPos when a position is needed but not known
|
||||||
var infinity = token.Position{Offset: 1 << 30, Line: 1 << 30} // use infinity to indicate the end of the source
|
var infinity = 1 << 30
|
||||||
|
|
||||||
|
|
||||||
// Use ignoreMultiLine if the multiLine information is not important.
|
// Use ignoreMultiLine if the multiLine information is not important.
|
||||||
@ -640,17 +640,16 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
|
|||||||
|
|
||||||
|
|
||||||
// intersperseComments consumes all comments that appear before the next token
|
// intersperseComments consumes all comments that appear before the next token
|
||||||
// and prints it together with the buffered whitespace (i.e., the whitespace
|
// tok and prints it together with the buffered whitespace (i.e., the whitespace
|
||||||
// that needs to be written before the next token). A heuristic is used to mix
|
// that needs to be written before the next token). A heuristic is used to mix
|
||||||
// the comments and whitespace. The isKeyword parameter indicates if the next
|
// the comments and whitespace. intersperseComments returns true if a pending
|
||||||
// token is a keyword or not. intersperseComments returns true if a pending
|
|
||||||
// formfeed was dropped from the whitespace buffer.
|
// formfeed was dropped from the whitespace buffer.
|
||||||
//
|
//
|
||||||
func (p *printer) intersperseComments(next token.Position, isKeyword bool) (droppedFF bool) {
|
func (p *printer) intersperseComments(next token.Position, tok token.Token) (droppedFF bool) {
|
||||||
var last *ast.Comment
|
var last *ast.Comment
|
||||||
for ; p.commentBefore(next); p.cindex++ {
|
for ; p.commentBefore(next); p.cindex++ {
|
||||||
for _, c := range p.comments[p.cindex].List {
|
for _, c := range p.comments[p.cindex].List {
|
||||||
p.writeCommentPrefix(c.Pos(), next, last == nil, isKeyword)
|
p.writeCommentPrefix(c.Pos(), next, last == nil, tok.IsKeyword())
|
||||||
p.writeComment(c)
|
p.writeComment(c)
|
||||||
last = c
|
last = c
|
||||||
}
|
}
|
||||||
@ -663,8 +662,8 @@ func (p *printer) intersperseComments(next token.Position, isKeyword bool) (drop
|
|||||||
p.write([]byte{' '})
|
p.write([]byte{' '})
|
||||||
}
|
}
|
||||||
// ensure that there is a newline after a //-style comment
|
// ensure that there is a newline after a //-style comment
|
||||||
// or if we are at the end of a file after a /*-style comment
|
// or if we are before a closing '}' or at the end of a file
|
||||||
return p.writeCommentSuffix(last.Text[1] == '/' || next.Offset == infinity.Offset)
|
return p.writeCommentSuffix(last.Text[1] == '/' || tok == token.RBRACE || tok == token.EOF)
|
||||||
}
|
}
|
||||||
|
|
||||||
// no comment was written - we should never reach here since
|
// no comment was written - we should never reach here since
|
||||||
@ -743,7 +742,7 @@ func (p *printer) print(args ...interface{}) {
|
|||||||
next := p.pos // estimated position of next item
|
next := p.pos // estimated position of next item
|
||||||
var data []byte
|
var data []byte
|
||||||
var tag HTMLTag
|
var tag HTMLTag
|
||||||
isKeyword := false
|
var tok token.Token
|
||||||
switch x := f.(type) {
|
switch x := f.(type) {
|
||||||
case whiteSpace:
|
case whiteSpace:
|
||||||
if x == ignore {
|
if x == ignore {
|
||||||
@ -785,7 +784,7 @@ func (p *printer) print(args ...interface{}) {
|
|||||||
} else {
|
} else {
|
||||||
data = []byte(x.String())
|
data = []byte(x.String())
|
||||||
}
|
}
|
||||||
isKeyword = x.IsKeyword()
|
tok = x
|
||||||
case token.Position:
|
case token.Position:
|
||||||
if x.IsValid() {
|
if x.IsValid() {
|
||||||
next = x // accurate position of next item
|
next = x // accurate position of next item
|
||||||
@ -797,7 +796,7 @@ func (p *printer) print(args ...interface{}) {
|
|||||||
p.pos = next
|
p.pos = next
|
||||||
|
|
||||||
if data != nil {
|
if data != nil {
|
||||||
droppedFF := p.flush(next, isKeyword)
|
droppedFF := p.flush(next, tok)
|
||||||
|
|
||||||
// intersperse extra newlines if present in the source
|
// intersperse extra newlines if present in the source
|
||||||
// (don't do this in flush as it will cause extra newlines
|
// (don't do this in flush as it will cause extra newlines
|
||||||
@ -820,14 +819,15 @@ func (p *printer) commentBefore(next token.Position) bool {
|
|||||||
|
|
||||||
|
|
||||||
// Flush prints any pending comments and whitespace occuring
|
// Flush prints any pending comments and whitespace occuring
|
||||||
// textually before the position of the next item. Flush returns
|
// textually before the position of the next token tok. Flush
|
||||||
// true if a pending formfeed character was dropped from the
|
// returns true if a pending formfeed character was dropped
|
||||||
// whitespace buffer as a result of interspersing comments.
|
// from the whitespace buffer as a result of interspersing
|
||||||
|
// comments.
|
||||||
//
|
//
|
||||||
func (p *printer) flush(next token.Position, isKeyword bool) (droppedFF bool) {
|
func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
|
||||||
if p.commentBefore(next) {
|
if p.commentBefore(next) {
|
||||||
// if there are comments before the next item, intersperse them
|
// if there are comments before the next item, intersperse them
|
||||||
droppedFF = p.intersperseComments(next, isKeyword)
|
droppedFF = p.intersperseComments(next, tok)
|
||||||
} else {
|
} else {
|
||||||
// otherwise, write any leftover whitespace
|
// otherwise, write any leftover whitespace
|
||||||
p.writeWhitespace(len(p.buffer))
|
p.writeWhitespace(len(p.buffer))
|
||||||
@ -1026,7 +1026,7 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
|
|||||||
p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n))
|
p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n))
|
||||||
runtime.Goexit()
|
runtime.Goexit()
|
||||||
}
|
}
|
||||||
p.flush(infinity, false)
|
p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF)
|
||||||
p.errors <- nil // no errors
|
p.errors <- nil // no errors
|
||||||
}()
|
}()
|
||||||
err := <-p.errors // wait for completion of goroutine
|
err := <-p.errors // wait for completion of goroutine
|
||||||
|
11
src/pkg/go/printer/testdata/comments.golden
vendored
11
src/pkg/go/printer/testdata/comments.golden
vendored
@ -411,7 +411,8 @@ func _() {
|
|||||||
|
|
||||||
|
|
||||||
// Some interesting interspersed comments
|
// Some interesting interspersed comments
|
||||||
func _( /* this */ x /* is */ /* an */ int) {}
|
func _( /* this */ x /* is */ /* an */ int) {
|
||||||
|
}
|
||||||
|
|
||||||
func _( /* no params */ ) {}
|
func _( /* no params */ ) {}
|
||||||
|
|
||||||
@ -421,7 +422,13 @@ func _() {
|
|||||||
|
|
||||||
func ( /* comment1 */ T /* comment2 */ ) _() {}
|
func ( /* comment1 */ T /* comment2 */ ) _() {}
|
||||||
|
|
||||||
func _() { /* one-liner */ }
|
func _() { /* one-liner */
|
||||||
|
}
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
_ = 0
|
||||||
|
/* closing curly brace should be on new line */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Line comments with tabs
|
// Line comments with tabs
|
||||||
|
4
src/pkg/go/printer/testdata/comments.input
vendored
4
src/pkg/go/printer/testdata/comments.input
vendored
@ -424,6 +424,10 @@ func (/* comment1 */ T /* comment2 */) _() {}
|
|||||||
|
|
||||||
func _() { /* one-liner */ }
|
func _() { /* one-liner */ }
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
_ = 0
|
||||||
|
/* closing curly brace should be on new line */ }
|
||||||
|
|
||||||
|
|
||||||
// Line comments with tabs
|
// Line comments with tabs
|
||||||
func _() {
|
func _() {
|
||||||
|
27
src/pkg/go/printer/testdata/declarations.golden
vendored
27
src/pkg/go/printer/testdata/declarations.golden
vendored
@ -356,7 +356,8 @@ func _() {
|
|||||||
// formatting of structs
|
// formatting of structs
|
||||||
type _ struct{}
|
type _ struct{}
|
||||||
|
|
||||||
type _ struct { /* this comment should be visible */ }
|
type _ struct { /* this comment should be visible */
|
||||||
|
}
|
||||||
|
|
||||||
type _ struct {
|
type _ struct {
|
||||||
// this comment should be visible and properly indented
|
// this comment should be visible and properly indented
|
||||||
@ -588,15 +589,31 @@ func _() {}
|
|||||||
func _() {}
|
func _() {}
|
||||||
|
|
||||||
func _() { f(1, 2, 3) }
|
func _() { f(1, 2, 3) }
|
||||||
func _(x int) int { return x + 1 }
|
func _(x int) int { y := x; return y + 1 }
|
||||||
func _() int { type T struct{} }
|
func _() int { type T struct{}; var x T; return x }
|
||||||
|
|
||||||
|
// these must remain multi-line since they are multi-line in the source
|
||||||
|
func _() {
|
||||||
|
f(1, 2, 3)
|
||||||
|
}
|
||||||
|
func _(x int) int {
|
||||||
|
y := x
|
||||||
|
return y + 1
|
||||||
|
}
|
||||||
|
func _() int {
|
||||||
|
type T struct{}
|
||||||
|
var x T
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// making function declarations safe for new semicolon rules
|
// making function declarations safe for new semicolon rules
|
||||||
func _() { /* one-line func */ }
|
func _() { /* multi-line func because of comment */
|
||||||
|
}
|
||||||
|
|
||||||
func _() {
|
func _() {
|
||||||
/* one-line func */ }
|
/* multi-line func because block is on multiple lines */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ellipsis parameters
|
// ellipsis parameters
|
||||||
|
13
src/pkg/go/printer/testdata/declarations.input
vendored
13
src/pkg/go/printer/testdata/declarations.input
vendored
@ -581,22 +581,27 @@ func _() {} // an empty line before this function
|
|||||||
func _() {}
|
func _() {}
|
||||||
func _() {}
|
func _() {}
|
||||||
|
|
||||||
|
func _() { f(1, 2, 3) }
|
||||||
|
func _(x int) int { y := x; return y+1 }
|
||||||
|
func _() int { type T struct{}; var x T; return x }
|
||||||
|
|
||||||
|
// these must remain multi-line since they are multi-line in the source
|
||||||
func _() {
|
func _() {
|
||||||
f(1, 2, 3)
|
f(1, 2, 3)
|
||||||
}
|
}
|
||||||
func _(x int) int {
|
func _(x int) int {
|
||||||
return x+1
|
y := x; return y+1
|
||||||
}
|
}
|
||||||
func _() int {
|
func _() int {
|
||||||
type T struct{}
|
type T struct{}; var x T; return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// making function declarations safe for new semicolon rules
|
// making function declarations safe for new semicolon rules
|
||||||
func _() { /* one-line func */ }
|
func _() { /* multi-line func because of comment */ }
|
||||||
|
|
||||||
func _() {
|
func _() {
|
||||||
/* one-line func */ }
|
/* multi-line func because block is on multiple lines */ }
|
||||||
|
|
||||||
|
|
||||||
// ellipsis parameters
|
// ellipsis parameters
|
||||||
|
27
src/pkg/go/printer/testdata/expressions.golden
vendored
27
src/pkg/go/printer/testdata/expressions.golden
vendored
@ -210,14 +210,31 @@ func _() {
|
|||||||
|
|
||||||
|
|
||||||
func _() {
|
func _() {
|
||||||
// one-line function literals
|
// one-line function literals (body is on a single line)
|
||||||
_ = func() {}
|
_ = func() {}
|
||||||
_ = func() int { return 0 }
|
_ = func() int { return 0 }
|
||||||
_ = func(x, y int) bool { return x < y }
|
_ = func(x, y int) bool { m := (x + y) / 2; return m < 0 }
|
||||||
|
|
||||||
f(func() {})
|
// multi-line function literals (body is not on one line)
|
||||||
f(func() int { return 0 })
|
_ = func() {
|
||||||
f(func(x, y int) bool { return x < y })
|
}
|
||||||
|
_ = func() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
_ = func(x, y int) bool {
|
||||||
|
m := (x + y) / 2
|
||||||
|
return x < y
|
||||||
|
}
|
||||||
|
|
||||||
|
f(func() {
|
||||||
|
})
|
||||||
|
f(func() int {
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
f(func(x, y int) bool {
|
||||||
|
m := (x + y) / 2
|
||||||
|
return x < y
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
17
src/pkg/go/printer/testdata/expressions.input
vendored
17
src/pkg/go/printer/testdata/expressions.input
vendored
@ -206,22 +206,27 @@ _ = `foo
|
|||||||
|
|
||||||
|
|
||||||
func _() {
|
func _() {
|
||||||
// one-line function literals
|
// one-line function literals (body is on a single line)
|
||||||
_ = func() {}
|
_ = func() {}
|
||||||
|
_ = func() int { return 0 }
|
||||||
|
_ = func(x, y int) bool { m := (x+y)/2; return m < 0 }
|
||||||
|
|
||||||
|
// multi-line function literals (body is not on one line)
|
||||||
|
_ = func() {
|
||||||
|
}
|
||||||
_ = func() int {
|
_ = func() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
_ = func(x, y int) bool {
|
_ = func(x, y int) bool {
|
||||||
return x < y
|
m := (x+y)/2; return x < y }
|
||||||
}
|
|
||||||
|
|
||||||
f(func() {})
|
f(func() {
|
||||||
|
})
|
||||||
f(func() int {
|
f(func() int {
|
||||||
return 0
|
return 0
|
||||||
})
|
})
|
||||||
f(func(x, y int) bool {
|
f(func(x, y int) bool {
|
||||||
return x < y
|
m := (x+y)/2; return x < y })
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
27
src/pkg/go/printer/testdata/expressions.raw
vendored
27
src/pkg/go/printer/testdata/expressions.raw
vendored
@ -210,14 +210,31 @@ func _() {
|
|||||||
|
|
||||||
|
|
||||||
func _() {
|
func _() {
|
||||||
// one-line function literals
|
// one-line function literals (body is on a single line)
|
||||||
_ = func() {}
|
_ = func() {}
|
||||||
_ = func() int { return 0 }
|
_ = func() int { return 0 }
|
||||||
_ = func(x, y int) bool { return x < y }
|
_ = func(x, y int) bool { m := (x + y) / 2; return m < 0 }
|
||||||
|
|
||||||
f(func() {})
|
// multi-line function literals (body is not on one line)
|
||||||
f(func() int { return 0 })
|
_ = func() {
|
||||||
f(func(x, y int) bool { return x < y })
|
}
|
||||||
|
_ = func() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
_ = func(x, y int) bool {
|
||||||
|
m := (x + y) / 2
|
||||||
|
return x < y
|
||||||
|
}
|
||||||
|
|
||||||
|
f(func() {
|
||||||
|
})
|
||||||
|
f(func() int {
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
f(func(x, y int) bool {
|
||||||
|
m := (x + y) / 2
|
||||||
|
return x < y
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user