mirror of
https://github.com/golang/go
synced 2024-11-25 04:47:57 -07:00
format composite literal types that are "short" struct type literals
on one line for a more compact representation of some composite Literals R=rsc http://go/go-review/1025008
This commit is contained in:
parent
a05a5465c8
commit
832ce7c1d2
@ -25,7 +25,6 @@ const (
|
||||
|
||||
// Other formatting issues:
|
||||
// - replacement of expression spacing algorithm with rsc's algorithm
|
||||
// - support for one-line composite types (e.g. structs) as composite literals types
|
||||
// - 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
|
||||
// not idempotent
|
||||
@ -262,16 +261,70 @@ func (p *printer) signature(params, result []*ast.Field, multiLine *bool) (optSe
|
||||
}
|
||||
|
||||
|
||||
func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isIncomplete, isStruct bool) {
|
||||
if len(list) == 0 && !isIncomplete && !p.commentBefore(rbrace) {
|
||||
// no blank between keyword and {} in this case
|
||||
p.print(lbrace, token.LBRACE, rbrace, token.RBRACE);
|
||||
return;
|
||||
func identListSize(list []*ast.Ident, maxSize int) (size int) {
|
||||
for i, x := range list {
|
||||
if i > 0 {
|
||||
size += 2; // ", "
|
||||
}
|
||||
size += len(x.Value);
|
||||
if size >= maxSize {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
|
||||
if len(list) != 1 {
|
||||
return false; // allow only one field
|
||||
}
|
||||
f := list[0];
|
||||
if f.Tag != nil || f.Comment != nil {
|
||||
return false; // don't allow tags or comments
|
||||
}
|
||||
// only name(s) and type
|
||||
const maxSize = 30; // adjust as appropriate, this is an approximate value
|
||||
namesSize := identListSize(f.Names, maxSize);
|
||||
if namesSize > 0 {
|
||||
namesSize = 1; // blank between names and types
|
||||
}
|
||||
typeSize := p.nodeSize(f.Type, maxSize);
|
||||
return namesSize + typeSize <= maxSize;
|
||||
}
|
||||
|
||||
|
||||
func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isIncomplete bool, ctxt Context) {
|
||||
if !isIncomplete && !p.commentBefore(rbrace) {
|
||||
// possibly a one-line struct/interface
|
||||
if len(list) == 0 {
|
||||
// no blank between keyword and {} in this case
|
||||
p.print(lbrace, token.LBRACE, rbrace, token.RBRACE);
|
||||
return;
|
||||
} else if ctxt&(compositeLit | structType) == compositeLit | structType &&
|
||||
p.isOneLineFieldList(list) { // for now ignore interfaces
|
||||
// small enough - print on one line
|
||||
// (don't use identList and ignore source line breaks)
|
||||
p.print(lbrace, token.LBRACE, blank);
|
||||
f := list[0];
|
||||
for i, x := range f.Names {
|
||||
if i > 0 {
|
||||
p.print(token.COMMA, blank);
|
||||
}
|
||||
p.expr(x, ignoreMultiLine);
|
||||
}
|
||||
if len(f.Names) > 0 {
|
||||
p.print(blank);
|
||||
}
|
||||
p.expr(f.Type, ignoreMultiLine);
|
||||
p.print(blank, rbrace, token.RBRACE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// at least one entry or incomplete
|
||||
p.print(blank, lbrace, token.LBRACE, indent, formfeed);
|
||||
if isStruct {
|
||||
if ctxt & structType != 0 {
|
||||
|
||||
sep := vtab;
|
||||
if len(list) == 1 {
|
||||
@ -286,11 +339,13 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
|
||||
extraTabs := 0;
|
||||
p.leadComment(f.Doc);
|
||||
if len(f.Names) > 0 {
|
||||
// named fields
|
||||
p.identList(f.Names, &ml);
|
||||
p.print(sep);
|
||||
p.expr(f.Type, &ml);
|
||||
extraTabs = 1;
|
||||
} else {
|
||||
// anonymous field
|
||||
p.expr(f.Type, &ml);
|
||||
extraTabs = 2;
|
||||
}
|
||||
@ -354,6 +409,15 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok
|
||||
// ----------------------------------------------------------------------------
|
||||
// Expressions
|
||||
|
||||
// Context describes the syntactic environment in which an expression node is printed.
|
||||
type Context uint
|
||||
|
||||
const (
|
||||
compositeLit = 1<<iota;
|
||||
structType;
|
||||
)
|
||||
|
||||
|
||||
func needsBlanks(expr ast.Expr) bool {
|
||||
switch x := expr.(type) {
|
||||
case *ast.Ident:
|
||||
@ -420,7 +484,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1 int, multiLine *bool) {
|
||||
|
||||
// Print collected operations left-to-right, with blanks if necessary.
|
||||
ws := indent;
|
||||
p.expr1(x.X, prec, multiLine);
|
||||
p.expr1(x.X, prec, 0, multiLine);
|
||||
for list.Len() > 0 {
|
||||
x = list.Pop().(*ast.BinaryExpr);
|
||||
prev := line;
|
||||
@ -443,7 +507,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1 int, multiLine *bool) {
|
||||
}
|
||||
p.print(x.OpPos, x.Op);
|
||||
}
|
||||
p.expr1(x.Y, prec, multiLine);
|
||||
p.expr1(x.Y, prec, 0, multiLine);
|
||||
}
|
||||
if ws == ignore {
|
||||
p.print(unindent);
|
||||
@ -453,7 +517,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1 int, multiLine *bool) {
|
||||
|
||||
// Returns true if a separating semicolon is optional.
|
||||
// Sets multiLine to true if the expression spans multiple lines.
|
||||
func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool) {
|
||||
func (p *printer) expr1(expr ast.Expr, prec1 int, ctxt Context, multiLine *bool) (optSemi bool) {
|
||||
p.print(expr.Pos());
|
||||
|
||||
switch x := expr.(type) {
|
||||
@ -488,7 +552,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
|
||||
if x.Op == token.RANGE {
|
||||
p.print(blank);
|
||||
}
|
||||
p.expr1(x.X, prec, multiLine);
|
||||
p.expr1(x.X, prec, 0, multiLine);
|
||||
}
|
||||
|
||||
case *ast.BasicLit:
|
||||
@ -507,12 +571,12 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
|
||||
p.print(x.Rparen, token.RPAREN);
|
||||
|
||||
case *ast.SelectorExpr:
|
||||
p.expr1(x.X, token.HighestPrec, multiLine);
|
||||
p.expr1(x.X, token.HighestPrec, 0, multiLine);
|
||||
p.print(token.PERIOD);
|
||||
p.expr1(x.Sel, token.HighestPrec, multiLine);
|
||||
p.expr1(x.Sel, token.HighestPrec, 0, multiLine);
|
||||
|
||||
case *ast.TypeAssertExpr:
|
||||
p.expr1(x.X, token.HighestPrec, multiLine);
|
||||
p.expr1(x.X, token.HighestPrec, 0, multiLine);
|
||||
p.print(token.PERIOD, token.LPAREN);
|
||||
if x.Type != nil {
|
||||
p.expr(x.Type, multiLine);
|
||||
@ -522,9 +586,9 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
|
||||
p.print(token.RPAREN);
|
||||
|
||||
case *ast.IndexExpr:
|
||||
p.expr1(x.X, token.HighestPrec, multiLine);
|
||||
p.expr1(x.X, token.HighestPrec, 0, multiLine);
|
||||
p.print(token.LBRACK);
|
||||
p.expr1(x.Index, token.LowestPrec, multiLine);
|
||||
p.expr1(x.Index, token.LowestPrec, 0, multiLine);
|
||||
if x.End != nil {
|
||||
if needsBlanks(x.Index) || needsBlanks(x.End) {
|
||||
// blanks around ":"
|
||||
@ -538,13 +602,13 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
|
||||
p.print(token.RBRACK);
|
||||
|
||||
case *ast.CallExpr:
|
||||
p.expr1(x.Fun, token.HighestPrec, multiLine);
|
||||
p.expr1(x.Fun, token.HighestPrec, 0, multiLine);
|
||||
p.print(x.Lparen, token.LPAREN);
|
||||
p.exprList(x.Lparen, x.Args, commaSep, multiLine);
|
||||
p.print(x.Rparen, token.RPAREN);
|
||||
|
||||
case *ast.CompositeLit:
|
||||
p.expr1(x.Type, token.HighestPrec, multiLine);
|
||||
p.expr1(x.Type, token.HighestPrec, compositeLit, multiLine);
|
||||
if compositeLitBlank && x.Lbrace.Line < x.Rbrace.Line {
|
||||
// add a blank before the opening { for multi-line composites
|
||||
// TODO(gri): for now this decision is made by looking at the
|
||||
@ -569,7 +633,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
|
||||
|
||||
case *ast.StructType:
|
||||
p.print(token.STRUCT);
|
||||
p.fieldList(x.Lbrace, x.Fields, x.Rbrace, x.Incomplete, true);
|
||||
p.fieldList(x.Lbrace, x.Fields, x.Rbrace, x.Incomplete, ctxt | structType);
|
||||
optSemi = true;
|
||||
|
||||
case *ast.FuncType:
|
||||
@ -578,7 +642,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
|
||||
|
||||
case *ast.InterfaceType:
|
||||
p.print(token.INTERFACE);
|
||||
p.fieldList(x.Lbrace, x.Methods, x.Rbrace, x.Incomplete, false);
|
||||
p.fieldList(x.Lbrace, x.Methods, x.Rbrace, x.Incomplete, ctxt);
|
||||
optSemi = true;
|
||||
|
||||
case *ast.MapType:
|
||||
@ -610,7 +674,7 @@ func (p *printer) expr1(expr ast.Expr, prec1 int, multiLine *bool) (optSemi bool
|
||||
// Returns true if a separating semicolon is optional.
|
||||
// Sets multiLine to true if the expression spans multiple lines.
|
||||
func (p *printer) expr(x ast.Expr, multiLine *bool) (optSemi bool) {
|
||||
return p.expr1(x, token.LowestPrec, multiLine);
|
||||
return p.expr1(x, token.LowestPrec, 0, multiLine);
|
||||
}
|
||||
|
||||
|
||||
|
14
src/pkg/go/printer/testdata/expressions.golden
vendored
14
src/pkg/go/printer/testdata/expressions.golden
vendored
@ -104,6 +104,20 @@ func _() {
|
||||
}
|
||||
|
||||
|
||||
// one-line structs/interfaces in composite literals (up to a threshold)
|
||||
func _() {
|
||||
_ = struct{}{};
|
||||
_ = struct{ x int }{0};
|
||||
_ = struct{ x, y, z int }{0, 1, 2};
|
||||
_ = struct{ int }{0};
|
||||
_ = struct {
|
||||
s struct {
|
||||
int;
|
||||
};
|
||||
}{struct{ int }{0}}; // compositeLit context not propagated => multiLine result
|
||||
}
|
||||
|
||||
|
||||
func _() {
|
||||
// do not modify literals
|
||||
_ = "tab1 tab2 tab3 end"; // string contains 3 tabs
|
||||
|
10
src/pkg/go/printer/testdata/expressions.input
vendored
10
src/pkg/go/printer/testdata/expressions.input
vendored
@ -104,6 +104,16 @@ func _() {
|
||||
}
|
||||
|
||||
|
||||
// one-line structs/interfaces in composite literals (up to a threshold)
|
||||
func _() {
|
||||
_ = struct{}{};
|
||||
_ = struct{ x int }{0};
|
||||
_ = struct{ x, y, z int }{0, 1, 2};
|
||||
_ = struct{ int }{0};
|
||||
_ = struct{ s struct { int } }{struct{ int}{0}}; // compositeLit context not propagated => multiLine result
|
||||
}
|
||||
|
||||
|
||||
func _() {
|
||||
// do not modify literals
|
||||
_ = "tab1 tab2 tab3 end"; // string contains 3 tabs
|
||||
|
14
src/pkg/go/printer/testdata/expressions.raw
vendored
14
src/pkg/go/printer/testdata/expressions.raw
vendored
@ -104,6 +104,20 @@ func _() {
|
||||
}
|
||||
|
||||
|
||||
// one-line structs/interfaces in composite literals (up to a threshold)
|
||||
func _() {
|
||||
_ = struct{}{};
|
||||
_ = struct{ x int }{0};
|
||||
_ = struct{ x, y, z int }{0, 1, 2};
|
||||
_ = struct{ int }{0};
|
||||
_ = struct {
|
||||
s struct {
|
||||
int;
|
||||
};
|
||||
}{struct{ int }{0}}; // compositeLit context not propagated => multiLine result
|
||||
}
|
||||
|
||||
|
||||
func _() {
|
||||
// do not modify literals
|
||||
_ = "tab1 tab2 tab3 end"; // string contains 3 tabs
|
||||
|
Loading…
Reference in New Issue
Block a user