Commit 49d2d986 authored by Robert Griesemer's avatar Robert Griesemer

go/printer, gofmt: nicer formatting of multi-line returns

This affects corner (test) cases only; gofmt -w src misc
doesn't cause any changes.

- added additional test cases
- removed doIndent parameter from printer.valueSpec
  (was always false)
- gofmt -w src misc causes no changes

Fixes #1207.

R=dsymonds, rsc
CC=golang-dev
https://golang.org/cl/5786060
parent c9e5600f
...@@ -15,7 +15,7 @@ import ( ...@@ -15,7 +15,7 @@ import (
"unicode/utf8" "unicode/utf8"
) )
// Other formatting issues: // Formatting issues:
// - better comment formatting for /*-style comments at the end of a line (e.g. a declaration) // - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
// when the comment spans multiple lines; if such a comment is just two lines, formatting is // when the comment spans multiple lines; if such a comment is just two lines, formatting is
// not idempotent // not idempotent
...@@ -964,6 +964,41 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po ...@@ -964,6 +964,41 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
} }
} }
// indentList reports whether an expression list would look better if it
// were indented wholesale (starting with the very first element, rather
// than starting at the first line break).
//
func (p *printer) indentList(list []ast.Expr) bool {
// Heuristic: indentList returns true if there are more than one multi-
// line element in the list, or if there is any element that is not
// starting on the same line as the previous one ends.
if len(list) >= 2 {
var b = p.lineFor(list[0].Pos())
var e = p.lineFor(list[len(list)-1].End())
if 0 < b && b < e {
// list spans multiple lines
n := 0 // multi-line element count
line := b
for _, x := range list {
xb := p.lineFor(x.Pos())
xe := p.lineFor(x.End())
if line < xb {
// x is not starting on the same
// line as the previous one ended
return true
}
if xb < xe {
// x is a multi-line element
n++
}
line = xe
}
return n > 1
}
}
return false
}
func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) { func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
p.print(stmt.Pos()) p.print(stmt.Pos())
...@@ -1030,8 +1065,19 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) { ...@@ -1030,8 +1065,19 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
p.print(token.RETURN) p.print(token.RETURN)
if s.Results != nil { if s.Results != nil {
p.print(blank) p.print(blank)
// Use indentList heuristic to make corner cases look
// better (issue 1207). A more systematic approach would
// always indent, but this would cause significant
// reformatting of the code base and not necessarily
// lead to more nicely formatted code in general.
if p.indentList(s.Results) {
p.print(indent)
p.exprList(s.Pos(), s.Results, 1, noIndent, token.NoPos)
p.print(unindent)
} else {
p.exprList(s.Pos(), s.Results, 1, 0, token.NoPos) p.exprList(s.Pos(), s.Results, 1, 0, token.NoPos)
} }
}
case *ast.BranchStmt: case *ast.BranchStmt:
p.print(s.Tok) p.print(s.Tok)
...@@ -1200,9 +1246,9 @@ func keepTypeColumn(specs []ast.Spec) []bool { ...@@ -1200,9 +1246,9 @@ func keepTypeColumn(specs []ast.Spec) []bool {
return m return m
} }
func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool) { func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
p.setComment(s.Doc) p.setComment(s.Doc)
p.identList(s.Names, doIndent) // always present p.identList(s.Names, false) // always present
extraTabs := 3 extraTabs := 3
if s.Type != nil || keepType { if s.Type != nil || keepType {
p.print(vtab) p.print(vtab)
...@@ -1290,7 +1336,7 @@ func (p *printer) genDecl(d *ast.GenDecl) { ...@@ -1290,7 +1336,7 @@ func (p *printer) genDecl(d *ast.GenDecl) {
if i > 0 { if i > 0 {
p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection) p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
} }
p.valueSpec(s.(*ast.ValueSpec), keepType[i], false) p.valueSpec(s.(*ast.ValueSpec), keepType[i])
newSection = p.isMultiLine(s) newSection = p.isMultiLine(s)
} }
} else { } else {
......
...@@ -52,6 +52,18 @@ func _f() { ...@@ -52,6 +52,18 @@ func _f() {
3}, 3},
3, 3,
} }
return T{
1,
2,
}, nil
return T{
1,
2,
},
T{
x: 3,
y: 4,
}, nil
return T{ return T{
1, 1,
2, 2,
...@@ -84,6 +96,37 @@ func _f() { ...@@ -84,6 +96,37 @@ func _f() {
} }
} }
// Formatting of multi-line returns: test cases from issue 1207.
func F() (*T, os.Error) {
return &T{
X: 1,
Y: 2,
},
nil
}
func G() (*T, *T, os.Error) {
return &T{
X: 1,
Y: 2,
},
&T{
X: 3,
Y: 4,
},
nil
}
func _() interface{} {
return &fileStat{
name: basename(file.name),
size: mkSize(d.FileSizeHigh, d.FileSizeLow),
modTime: mkModTime(d.LastWriteTime),
mode: mkMode(d.FileAttributes),
sys: mkSysFromFI(&d),
}, nil
}
// Formatting of if-statement headers. // Formatting of if-statement headers.
func _() { func _() {
if true { if true {
......
...@@ -52,6 +52,18 @@ func _f() { ...@@ -52,6 +52,18 @@ func _f() {
3}, 3},
3, 3,
} }
return T{
1,
2,
}, nil
return T{
1,
2,
},
T{
x: 3,
y: 4,
}, nil
return T{ return T{
1, 1,
2, 2,
...@@ -84,6 +96,37 @@ func _f() { ...@@ -84,6 +96,37 @@ func _f() {
} }
} }
// Formatting of multi-line returns: test cases from issue 1207.
func F() (*T, os.Error) {
return &T{
X: 1,
Y: 2,
},
nil
}
func G() (*T, *T, os.Error) {
return &T{
X: 1,
Y: 2,
},
&T{
X: 3,
Y: 4,
},
nil
}
func _() interface{} {
return &fileStat{
name: basename(file.name),
size: mkSize(d.FileSizeHigh, d.FileSizeLow),
modTime: mkModTime(d.LastWriteTime),
mode: mkMode(d.FileAttributes),
sys: mkSysFromFI(&d),
}, nil
}
// Formatting of if-statement headers. // Formatting of if-statement headers.
func _() { func _() {
if true {} if true {}
......
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