mirror of
https://github.com/golang/go
synced 2024-11-25 13:07:57 -07:00
Gofmt preserves newlines in multiline selector expressions.
This is for making the fluent interface idiom usable with gofmt. R=gri CC=golang-dev https://golang.org/cl/802043
This commit is contained in:
parent
76fc2f62d3
commit
ac58f646ac
@ -10,6 +10,7 @@ package printer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"container/vector"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
)
|
)
|
||||||
@ -89,6 +90,7 @@ const (
|
|||||||
commaSep // elements are separated by commas
|
commaSep // elements are separated by commas
|
||||||
commaTerm // list is optionally terminated by a comma
|
commaTerm // list is optionally terminated by a comma
|
||||||
noIndent // no extra indentation in multi-line lists
|
noIndent // no extra indentation in multi-line lists
|
||||||
|
periodSep // elements are separated by periods
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -176,7 +178,19 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
|
|||||||
// the first linebreak is always a formfeed since this section must not
|
// the first linebreak is always a formfeed since this section must not
|
||||||
// depend on any previous formatting
|
// depend on any previous formatting
|
||||||
prevBreak := -1 // index of last expression that was followed by a linebreak
|
prevBreak := -1 // index of last expression that was followed by a linebreak
|
||||||
if prev.IsValid() && prev.Line < line && p.linebreak(line, 1, 2, ws, true) {
|
linebreakMin := 1
|
||||||
|
if mode&periodSep != 0 {
|
||||||
|
// Make fragments like
|
||||||
|
//
|
||||||
|
// a.Bar(1,
|
||||||
|
// 2).Foo
|
||||||
|
//
|
||||||
|
// format correctly (a linebreak shouldn't be added before Foo) when
|
||||||
|
// doing period-separated expr lists by setting minimum linebreak to 0
|
||||||
|
// lines for them.
|
||||||
|
linebreakMin = 0
|
||||||
|
}
|
||||||
|
if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, 2, ws, true) {
|
||||||
ws = ignore
|
ws = ignore
|
||||||
*multiLine = true
|
*multiLine = true
|
||||||
prevBreak = 0
|
prevBreak = 0
|
||||||
@ -230,19 +244,23 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
|
|||||||
if mode&commaSep != 0 {
|
if mode&commaSep != 0 {
|
||||||
p.print(token.COMMA)
|
p.print(token.COMMA)
|
||||||
}
|
}
|
||||||
|
if mode&periodSep != 0 {
|
||||||
|
p.print(token.PERIOD)
|
||||||
|
}
|
||||||
if prevLine < line && prevLine > 0 && line > 0 {
|
if prevLine < line && prevLine > 0 && line > 0 {
|
||||||
// lines are broken using newlines so comments remain aligned
|
// lines are broken using newlines so comments remain aligned
|
||||||
// unless forceFF is set or there are multiple expressions on
|
// unless forceFF is set or there are multiple expressions on
|
||||||
// the same line in which case formfeed is used
|
// the same line in which case formfeed is used
|
||||||
// broken with a formfeed
|
// broken with a formfeed
|
||||||
if p.linebreak(line, 1, 2, ws, useFF || prevBreak+1 < i) {
|
if p.linebreak(line, linebreakMin, 2, ws, useFF || prevBreak+1 < i) {
|
||||||
ws = ignore
|
ws = ignore
|
||||||
*multiLine = true
|
*multiLine = true
|
||||||
prevBreak = i
|
prevBreak = i
|
||||||
}
|
}
|
||||||
} else {
|
} else if mode&periodSep == 0 {
|
||||||
p.print(blank)
|
p.print(blank)
|
||||||
}
|
}
|
||||||
|
// period-separadet list elements don't need a blank
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPair && size > 0 && len(list) > 1 {
|
if isPair && size > 0 && len(list) > 1 {
|
||||||
@ -652,6 +670,68 @@ func isBinary(expr ast.Expr) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If the expression contains one or more selector expressions, splits it into
|
||||||
|
// two expressions at the rightmost period. Writes entire expr to suffix when
|
||||||
|
// selector isn't found. Rewrites AST nodes for calls, index expressions and
|
||||||
|
// type assertions, all of which may be found in selector chains, to make them
|
||||||
|
// parts of the chain.
|
||||||
|
func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
|
||||||
|
// Rewrite call and index expressions to be a part of the selector chain so
|
||||||
|
// that their multiline arguments get indented correctly.
|
||||||
|
switch x := expr.(type) {
|
||||||
|
case *ast.SelectorExpr:
|
||||||
|
body, suffix = x.X, x.Sel
|
||||||
|
return
|
||||||
|
case *ast.CallExpr:
|
||||||
|
body, suffix = splitSelector(x.Fun)
|
||||||
|
if body != nil {
|
||||||
|
suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Rparen}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case *ast.IndexExpr:
|
||||||
|
body, suffix = splitSelector(x.X)
|
||||||
|
if body != nil {
|
||||||
|
suffix = &ast.IndexExpr{suffix, x.Index}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case *ast.SliceExpr:
|
||||||
|
body, suffix = splitSelector(x.X)
|
||||||
|
if body != nil {
|
||||||
|
suffix = &ast.SliceExpr{suffix, x.Index, x.End}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case *ast.TypeAssertExpr:
|
||||||
|
body, suffix = splitSelector(x.X)
|
||||||
|
if body != nil {
|
||||||
|
suffix = &ast.TypeAssertExpr{suffix, x.Type}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
suffix = expr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Convert an expression into an expression list split at the periods of
|
||||||
|
// selector expressions.
|
||||||
|
func selectorExprList(expr ast.Expr) (result []ast.Expr) {
|
||||||
|
var list vector.Vector
|
||||||
|
for expr != nil {
|
||||||
|
var suffix ast.Expr
|
||||||
|
expr, suffix = splitSelector(expr)
|
||||||
|
list.Push(suffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
result = make([]ast.Expr, len(list))
|
||||||
|
i := len(result)
|
||||||
|
for _, x := range list {
|
||||||
|
i--
|
||||||
|
result[i] = x.(ast.Expr)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Sets multiLine to true if the expression spans multiple lines.
|
// Sets multiLine to true if the expression spans multiple lines.
|
||||||
func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multiLine *bool) {
|
func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multiLine *bool) {
|
||||||
p.print(expr.Pos())
|
p.print(expr.Pos())
|
||||||
@ -719,9 +799,8 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
|
|||||||
p.print(x.Rparen, token.RPAREN)
|
p.print(x.Rparen, token.RPAREN)
|
||||||
|
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
p.expr1(x.X, token.HighestPrec, depth, 0, multiLine)
|
parts := selectorExprList(expr)
|
||||||
p.print(token.PERIOD)
|
p.exprList(noPos, parts, depth, periodSep, multiLine, noPos)
|
||||||
p.expr1(x.Sel, token.HighestPrec, depth, 0, multiLine)
|
|
||||||
|
|
||||||
case *ast.TypeAssertExpr:
|
case *ast.TypeAssertExpr:
|
||||||
p.expr1(x.X, token.HighestPrec, depth, 0, multiLine)
|
p.expr1(x.X, token.HighestPrec, depth, 0, multiLine)
|
||||||
|
71
src/pkg/go/printer/testdata/expressions.golden
vendored
71
src/pkg/go/printer/testdata/expressions.golden
vendored
@ -403,3 +403,74 @@ func addState(s []state, inst instr, match []int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *T) foo(x int) *T { return self }
|
||||||
|
|
||||||
|
func _() { module.Func1().Func2() }
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
_ = new(T).
|
||||||
|
foo(1).
|
||||||
|
foo(2).
|
||||||
|
foo(3)
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo(1).
|
||||||
|
foo(2). // inline comments
|
||||||
|
foo(3)
|
||||||
|
|
||||||
|
_ = new(T).foo(1).foo(2).foo(3)
|
||||||
|
|
||||||
|
// handle multiline argument list correctly
|
||||||
|
_ = new(T).
|
||||||
|
foo(
|
||||||
|
1).
|
||||||
|
foo(2)
|
||||||
|
|
||||||
|
_ = new(T).foo(
|
||||||
|
1).foo(2)
|
||||||
|
|
||||||
|
_ = Array[3+
|
||||||
|
4]
|
||||||
|
|
||||||
|
_ = Method(1, 2,
|
||||||
|
3)
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar().(*Type)
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar().(*Type).
|
||||||
|
baz()
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()["idx"]
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()["idx"].
|
||||||
|
baz()
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()[1:2]
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()[1:2].
|
||||||
|
baz()
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
Field.
|
||||||
|
Array[3+
|
||||||
|
4].
|
||||||
|
Table["foo"].
|
||||||
|
Blob.(*Type).
|
||||||
|
Slices[1:4].
|
||||||
|
Method(1, 2,
|
||||||
|
3).
|
||||||
|
Thingy
|
||||||
|
}
|
||||||
|
71
src/pkg/go/printer/testdata/expressions.input
vendored
71
src/pkg/go/printer/testdata/expressions.input
vendored
@ -395,3 +395,74 @@ func addState(s []state, inst instr, match []int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *T) foo(x int) *T { return self }
|
||||||
|
|
||||||
|
func _() { module.Func1().Func2() }
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
_ = new(T).
|
||||||
|
foo(1).
|
||||||
|
foo(2).
|
||||||
|
foo(3)
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo(1).
|
||||||
|
foo(2). // inline comments
|
||||||
|
foo(3)
|
||||||
|
|
||||||
|
_ = new(T).foo(1).foo(2).foo(3)
|
||||||
|
|
||||||
|
// handle multiline argument list correctly
|
||||||
|
_ = new(T).
|
||||||
|
foo(
|
||||||
|
1).
|
||||||
|
foo(2)
|
||||||
|
|
||||||
|
_ = new(T).foo(
|
||||||
|
1).foo(2)
|
||||||
|
|
||||||
|
_ = Array[3 +
|
||||||
|
4]
|
||||||
|
|
||||||
|
_ = Method(1, 2,
|
||||||
|
3)
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar().(*Type)
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar().(*Type).
|
||||||
|
baz()
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()["idx"]
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()["idx"].
|
||||||
|
baz()
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()[1:2]
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()[1:2].
|
||||||
|
baz()
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
Field.
|
||||||
|
Array[3+
|
||||||
|
4].
|
||||||
|
Table["foo"].
|
||||||
|
Blob.(*Type).
|
||||||
|
Slices[1:4].
|
||||||
|
Method(1, 2,
|
||||||
|
3).
|
||||||
|
Thingy
|
||||||
|
}
|
||||||
|
71
src/pkg/go/printer/testdata/expressions.raw
vendored
71
src/pkg/go/printer/testdata/expressions.raw
vendored
@ -403,3 +403,74 @@ func addState(s []state, inst instr, match []int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *T) foo(x int) *T { return self }
|
||||||
|
|
||||||
|
func _() { module.Func1().Func2() }
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
_ = new(T).
|
||||||
|
foo(1).
|
||||||
|
foo(2).
|
||||||
|
foo(3)
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo(1).
|
||||||
|
foo(2). // inline comments
|
||||||
|
foo(3)
|
||||||
|
|
||||||
|
_ = new(T).foo(1).foo(2).foo(3)
|
||||||
|
|
||||||
|
// handle multiline argument list correctly
|
||||||
|
_ = new(T).
|
||||||
|
foo(
|
||||||
|
1).
|
||||||
|
foo(2)
|
||||||
|
|
||||||
|
_ = new(T).foo(
|
||||||
|
1).foo(2)
|
||||||
|
|
||||||
|
_ = Array[3+
|
||||||
|
4]
|
||||||
|
|
||||||
|
_ = Method(1, 2,
|
||||||
|
3)
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar().(*Type)
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar().(*Type).
|
||||||
|
baz()
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()["idx"]
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()["idx"].
|
||||||
|
baz()
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()[1:2]
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
foo().
|
||||||
|
bar()[1:2].
|
||||||
|
baz()
|
||||||
|
|
||||||
|
_ = new(T).
|
||||||
|
Field.
|
||||||
|
Array[3+
|
||||||
|
4].
|
||||||
|
Table["foo"].
|
||||||
|
Blob.(*Type).
|
||||||
|
Slices[1:4].
|
||||||
|
Method(1, 2,
|
||||||
|
3).
|
||||||
|
Thingy
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user