diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-06 17:57:23 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-06 17:57:23 +0000 |
commit | 593f74bbab63d34c7060918088bcbad686c31c66 (patch) | |
tree | 4ce83ca433796a728e9fdd00af105bce158532b5 /libgo/go/go/printer | |
parent | 46402cbe0ba3ea92be9642cf18eedaefe57a414c (diff) |
libgo: Update to weekly.2012-03-04 release.
From-SVN: r185010
Diffstat (limited to 'libgo/go/go/printer')
-rw-r--r-- | libgo/go/go/printer/nodes.go | 361 | ||||
-rw-r--r-- | libgo/go/go/printer/printer.go | 75 | ||||
-rw-r--r-- | libgo/go/go/printer/printer_test.go | 5 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/comments.golden | 85 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/comments.input | 85 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/declarations.golden | 10 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/declarations.input | 6 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/expressions.golden | 22 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/expressions.input | 22 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/expressions.raw | 22 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/parser.go | 2 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/statements.golden | 76 | ||||
-rw-r--r-- | libgo/go/go/printer/testdata/statements.input | 76 |
13 files changed, 598 insertions, 249 deletions
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go index cd5e075c16c..05b4ef59a2d 100644 --- a/libgo/go/go/printer/nodes.go +++ b/libgo/go/go/printer/nodes.go @@ -12,6 +12,7 @@ import ( "bytes" "go/ast" "go/token" + "unicode/utf8" ) // Other formatting issues: @@ -82,46 +83,37 @@ func (p *printer) setComment(g *ast.CommentGroup) { type exprListMode uint const ( - blankStart exprListMode = 1 << iota // print a blank before a non-empty list - blankEnd // print a blank after a non-empty list - commaSep // elements are separated by commas - commaTerm // list is optionally terminated by a comma - noIndent // no extra indentation in multi-line lists + commaTerm exprListMode = 1 << iota // list is optionally terminated by a comma + noIndent // no extra indentation in multi-line lists ) -// Sets multiLine to true if the identifier list spans multiple lines. // If indent is set, a multi-line identifier list is indented after the // first linebreak encountered. -func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) { +func (p *printer) identList(list []*ast.Ident, indent bool) { // convert into an expression list so we can re-use exprList formatting xlist := make([]ast.Expr, len(list)) for i, x := range list { xlist[i] = x } - mode := commaSep + var mode exprListMode if !indent { - mode |= noIndent + mode = noIndent } - p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos) + p.exprList(token.NoPos, xlist, 1, mode, token.NoPos) } // Print a list of expressions. If the list spans multiple // source lines, the original line breaks are respected between -// expressions. Sets multiLine to true if the list spans multiple -// lines. +// expressions. // // TODO(gri) Consider rewriting this to be independent of []ast.Expr // so that we can use the algorithm for any kind of list // (e.g., pass list via a channel over which to range). -func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next0 token.Pos) { +func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, next0 token.Pos) { if len(list) == 0 { return } - if mode&blankStart != 0 { - p.print(blank) - } - prev := p.posFor(prev0) next := p.posFor(next0) line := p.lineFor(list[0].Pos()) @@ -131,17 +123,11 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp // all list entries on a single line for i, x := range list { if i > 0 { - if mode&commaSep != 0 { - // use position of expression following the comma as - // comma position for correct comment placement - p.print(x.Pos(), token.COMMA) - } - p.print(blank) + // use position of expression following the comma as + // comma position for correct comment placement + p.print(x.Pos(), token.COMMA, blank) } - p.expr0(x, depth, multiLine) - } - if mode&blankEnd != 0 { - p.print(blank) + p.expr0(x, depth) } return } @@ -161,7 +147,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp prevBreak := -1 // index of last expression that was followed by a linebreak if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) { ws = ignore - *multiLine = true prevBreak = 0 } @@ -215,15 +200,13 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp if i > 0 { needsLinebreak := prevLine < line && prevLine > 0 && line > 0 - if mode&commaSep != 0 { - // use position of expression following the comma as - // comma position for correct comment placement, but - // only if the expression is on the same line - if !needsLinebreak { - p.print(x.Pos()) - } - p.print(token.COMMA) + // use position of expression following the comma as + // comma position for correct comment placement, but + // only if the expression is on the same line + if !needsLinebreak { + p.print(x.Pos()) } + p.print(token.COMMA) needsBlank := true if needsLinebreak { // lines are broken using newlines so comments remain aligned @@ -231,7 +214,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp // the same line in which case formfeed is used if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) { ws = ignore - *multiLine = true prevBreak = i needsBlank = false // we got a line break instead } @@ -245,11 +227,11 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp // we have a key:value expression that fits onto one line and // is in a list with more then one entry: use a column for the // key such that consecutive entries can align if possible - p.expr(pair.Key, multiLine) + p.expr(pair.Key) p.print(pair.Colon, token.COLON, vtab) - p.expr(pair.Value, multiLine) + p.expr(pair.Value) } else { - p.expr0(x, depth, multiLine) + p.expr0(x, depth) } } @@ -264,18 +246,13 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp return } - if mode&blankEnd != 0 { - p.print(blank) - } - if ws == ignore && mode&noIndent == 0 { // unindent if we indented p.print(unindent) } } -// Sets multiLine to true if the the parameter list spans multiple lines. -func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) { +func (p *printer) parameters(fields *ast.FieldList) { p.print(fields.Opening, token.LPAREN) if len(fields.List) > 0 { prevLine := p.lineFor(fields.Opening) @@ -306,7 +283,6 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) { if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) { // break line if the opening "(" or previous parameter ended on a different line ws = ignore - *multiLine = true } else if i > 0 { p.print(blank) } @@ -318,11 +294,11 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) { // again at the end (and still ws == indent). Thus, a subsequent indent // by a linebreak call after a type, or in the next multi-line identList // will do the right thing. - p.identList(par.Names, ws == indent, multiLine) + p.identList(par.Names, ws == indent) p.print(blank) } // parameter type - p.expr(par.Type, multiLine) + p.expr(par.Type) prevLine = parLineEnd } // if the closing ")" is on a separate line from the last parameter, @@ -339,27 +315,26 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) { p.print(fields.Closing, token.RPAREN) } -// Sets multiLine to true if the signature spans multiple lines. -func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) { - p.parameters(params, multiLine) +func (p *printer) signature(params, result *ast.FieldList) { + p.parameters(params) n := result.NumFields() if n > 0 { p.print(blank) if n == 1 && result.List[0].Names == nil { // single anonymous result; no ()'s - p.expr(result.List[0].Type, multiLine) + p.expr(result.List[0].Type) return } - p.parameters(result, multiLine) + p.parameters(result) } } func identListSize(list []*ast.Ident, maxSize int) (size int) { for i, x := range list { if i > 0 { - size += 2 // ", " + size += len(", ") } - size += len(x.Name) + size += utf8.RuneCountInString(x.Name) if size >= maxSize { break } @@ -389,6 +364,10 @@ func (p *printer) setLineComment(text string) { p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}}) } +func (p *printer) isMultiLine(n ast.Node) bool { + return p.lineFor(n.End())-p.lineFor(n.Pos()) > 1 +} + func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) { lbrace := fields.Opening list := fields.List @@ -412,12 +391,12 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) // no comments so no need for comma position p.print(token.COMMA, blank) } - p.expr(x, ignoreMultiLine) + p.expr(x) } if len(f.Names) > 0 { p.print(blank) } - p.expr(f.Type, ignoreMultiLine) + p.expr(f.Type) p.print(blank, rbrace, token.RBRACE) return } @@ -435,23 +414,22 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) if len(list) == 1 { sep = blank } - var ml bool + newSection := false for i, f := range list { if i > 0 { - p.linebreak(p.lineFor(f.Pos()), 1, ignore, ml) + p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection) } - ml = false extraTabs := 0 p.setComment(f.Doc) if len(f.Names) > 0 { // named fields - p.identList(f.Names, false, &ml) + p.identList(f.Names, false) p.print(sep) - p.expr(f.Type, &ml) + p.expr(f.Type) extraTabs = 1 } else { // anonymous field - p.expr(f.Type, &ml) + p.expr(f.Type) extraTabs = 2 } if f.Tag != nil { @@ -459,7 +437,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) p.print(sep) } p.print(sep) - p.expr(f.Tag, &ml) + p.expr(f.Tag) extraTabs = 0 } if f.Comment != nil { @@ -468,6 +446,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) } p.setComment(f.Comment) } + newSection = p.isMultiLine(f) } if isIncomplete { if len(list) > 0 { @@ -479,22 +458,22 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) } else { // interface - var ml bool + newSection := false for i, f := range list { if i > 0 { - p.linebreak(p.lineFor(f.Pos()), 1, ignore, ml) + p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection) } - ml = false p.setComment(f.Doc) if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { // method - p.expr(f.Names[0], &ml) - p.signature(ftyp.Params, ftyp.Results, &ml) + p.expr(f.Names[0]) + p.signature(ftyp.Params, ftyp.Results) } else { // embedded interface - p.expr(f.Type, &ml) + p.expr(f.Type) } p.setComment(f.Comment) + newSection = p.isMultiLine(f) } if isIncomplete { if len(list) > 0 { @@ -635,15 +614,14 @@ func reduceDepth(depth int) int { // cutoff is 6 (always use spaces) in Normal mode // and 4 (never use spaces) in Compact mode. // -// Sets multiLine to true if the binary expression spans multiple lines. -func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) { +func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) { prec := x.Op.Precedence() if prec < prec1 { // parenthesis needed // Note: The parser inserts an ast.ParenExpr node; thus this case // can only occur if the AST is created in a different way. p.print(token.LPAREN) - p.expr0(x, reduceDepth(depth), multiLine) // parentheses undo one level of depth + p.expr0(x, reduceDepth(depth)) // parentheses undo one level of depth p.print(token.RPAREN) return } @@ -651,7 +629,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL printBlank := prec < cutoff ws := indent - p.expr1(x.X, prec, depth+diffPrec(x.X, prec), multiLine) + p.expr1(x.X, prec, depth+diffPrec(x.X, prec)) if printBlank { p.print(blank) } @@ -663,14 +641,13 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL // in the source if p.linebreak(yline, 1, ws, true) { ws = ignore - *multiLine = true printBlank = false // no blank after line break } } if printBlank { p.print(blank) } - p.expr1(x.Y, prec+1, depth+1, multiLine) + p.expr1(x.Y, prec+1, depth+1) if ws == ignore { p.print(unindent) } @@ -681,8 +658,7 @@ func isBinary(expr ast.Expr) bool { return ok } -// Sets multiLine to true if the expression spans multiple lines. -func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { +func (p *printer) expr1(expr ast.Expr, prec1, depth int) { p.print(expr.Pos()) switch x := expr.(type) { @@ -697,12 +673,12 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { p.internalError("depth < 1:", depth) depth = 1 } - p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine) + p.binaryExpr(x, prec1, cutoff(x, depth), depth) case *ast.KeyValueExpr: - p.expr(x.Key, multiLine) + p.expr(x.Key) p.print(x.Colon, token.COLON, blank) - p.expr(x.Value, multiLine) + p.expr(x.Value) case *ast.StarExpr: const prec = token.UnaryPrec @@ -710,12 +686,12 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { // parenthesis needed p.print(token.LPAREN) p.print(token.MUL) - p.expr(x.X, multiLine) + p.expr(x.X) p.print(token.RPAREN) } else { // no parenthesis needed p.print(token.MUL) - p.expr(x.X, multiLine) + p.expr(x.X) } case *ast.UnaryExpr: @@ -723,7 +699,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { if prec < prec1 { // parenthesis needed p.print(token.LPAREN) - p.expr(x, multiLine) + p.expr(x) p.print(token.RPAREN) } else { // no parenthesis needed @@ -732,42 +708,41 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { // TODO(gri) Remove this code if it cannot be reached. p.print(blank) } - p.expr1(x.X, prec, depth, multiLine) + p.expr1(x.X, prec, depth) } case *ast.BasicLit: p.print(x) case *ast.FuncLit: - p.expr(x.Type, multiLine) - p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiLine) + p.expr(x.Type) + p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true) case *ast.ParenExpr: if _, hasParens := x.X.(*ast.ParenExpr); hasParens { // don't print parentheses around an already parenthesized expression // TODO(gri) consider making this more general and incorporate precedence levels - p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth + p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth } else { p.print(token.LPAREN) - p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth + p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth p.print(x.Rparen, token.RPAREN) } case *ast.SelectorExpr: - p.expr1(x.X, token.HighestPrec, depth, multiLine) + p.expr1(x.X, token.HighestPrec, depth) p.print(token.PERIOD) if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line { p.print(indent, newline, x.Sel.Pos(), x.Sel, unindent) - *multiLine = true } else { p.print(x.Sel.Pos(), x.Sel) } case *ast.TypeAssertExpr: - p.expr1(x.X, token.HighestPrec, depth, multiLine) + p.expr1(x.X, token.HighestPrec, depth) p.print(token.PERIOD, token.LPAREN) if x.Type != nil { - p.expr(x.Type, multiLine) + p.expr(x.Type) } else { p.print(token.TYPE) } @@ -775,17 +750,17 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { case *ast.IndexExpr: // TODO(gri): should treat[] like parentheses and undo one level of depth - p.expr1(x.X, token.HighestPrec, 1, multiLine) + p.expr1(x.X, token.HighestPrec, 1) p.print(x.Lbrack, token.LBRACK) - p.expr0(x.Index, depth+1, multiLine) + p.expr0(x.Index, depth+1) p.print(x.Rbrack, token.RBRACK) case *ast.SliceExpr: // TODO(gri): should treat[] like parentheses and undo one level of depth - p.expr1(x.X, token.HighestPrec, 1, multiLine) + p.expr1(x.X, token.HighestPrec, 1) p.print(x.Lbrack, token.LBRACK) if x.Low != nil { - p.expr0(x.Low, depth+1, multiLine) + p.expr0(x.Low, depth+1) } // blanks around ":" if both sides exist and either side is a binary expression if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) { @@ -794,7 +769,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { p.print(token.COLON) } if x.High != nil { - p.expr0(x.High, depth+1, multiLine) + p.expr0(x.High, depth+1) } p.print(x.Rbrack, token.RBRACK) @@ -802,21 +777,26 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { if len(x.Args) > 1 { depth++ } - p.expr1(x.Fun, token.HighestPrec, depth, multiLine) + p.expr1(x.Fun, token.HighestPrec, depth) p.print(x.Lparen, token.LPAREN) - p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen) if x.Ellipsis.IsValid() { + p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis) p.print(x.Ellipsis, token.ELLIPSIS) + if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) { + p.print(token.COMMA, formfeed) + } + } else { + p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen) } p.print(x.Rparen, token.RPAREN) case *ast.CompositeLit: // composite literal elements that are composite literals themselves may have the type omitted if x.Type != nil { - p.expr1(x.Type, token.HighestPrec, depth, multiLine) + p.expr1(x.Type, token.HighestPrec, depth) } p.print(x.Lbrace, token.LBRACE) - p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace) + p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace) // do not insert extra line breaks because of comments before // the closing '}' as it might break the code if there is no // trailing ',' @@ -825,16 +805,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { case *ast.Ellipsis: p.print(token.ELLIPSIS) if x.Elt != nil { - p.expr(x.Elt, multiLine) + p.expr(x.Elt) } case *ast.ArrayType: p.print(token.LBRACK) if x.Len != nil { - p.expr(x.Len, multiLine) + p.expr(x.Len) } p.print(token.RBRACK) - p.expr(x.Elt, multiLine) + p.expr(x.Elt) case *ast.StructType: p.print(token.STRUCT) @@ -842,7 +822,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { case *ast.FuncType: p.print(token.FUNC) - p.signature(x.Params, x.Results, multiLine) + p.signature(x.Params, x.Results) case *ast.InterfaceType: p.print(token.INTERFACE) @@ -850,9 +830,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { case *ast.MapType: p.print(token.MAP, token.LBRACK) - p.expr(x.Key, multiLine) + p.expr(x.Key) p.print(token.RBRACK) - p.expr(x.Value, multiLine) + p.expr(x.Value) case *ast.ChanType: switch x.Dir { @@ -864,7 +844,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { p.print(token.CHAN, token.ARROW) } p.print(blank) - p.expr(x.Value, multiLine) + p.expr(x.Value) default: panic("unreachable") @@ -873,14 +853,13 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { return } -func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) { - p.expr1(x, token.LowestPrec, depth, multiLine) +func (p *printer) expr0(x ast.Expr, depth int) { + p.expr1(x, token.LowestPrec, depth) } -// Sets multiLine to true if the expression spans multiple lines. -func (p *printer) expr(x ast.Expr, multiLine *bool) { +func (p *printer) expr(x ast.Expr) { const depth = 1 - p.expr1(x, token.LowestPrec, depth, multiLine) + p.expr1(x, token.LowestPrec, depth) } // ---------------------------------------------------------------------------- @@ -894,13 +873,13 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) { if _indent > 0 { p.print(indent) } - var multiLine bool + multiLine := false for i, s := range list { // _indent == 0 only for lists of switch/select case clauses; // in those cases each clause is a new section p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || _indent == 0 || multiLine) - multiLine = false - p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine) + p.stmt(s, nextIsRBrace && i == len(list)-1) + multiLine = p.isMultiLine(s) } if _indent > 0 { p.print(unindent) @@ -957,25 +936,25 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po if init == nil && post == nil { // no semicolons required if expr != nil { - p.expr(stripParens(expr), ignoreMultiLine) + p.expr(stripParens(expr)) needsBlank = true } } else { // all semicolons required // (they are not separators, print them explicitly) if init != nil { - p.stmt(init, false, ignoreMultiLine) + p.stmt(init, false) } p.print(token.SEMICOLON, blank) if expr != nil { - p.expr(stripParens(expr), ignoreMultiLine) + p.expr(stripParens(expr)) needsBlank = true } if isForStmt { p.print(token.SEMICOLON, blank) needsBlank = false if post != nil { - p.stmt(post, false, ignoreMultiLine) + p.stmt(post, false) needsBlank = true } } @@ -985,8 +964,7 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po } } -// Sets multiLine to true if the statements spans multiple lines. -func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { +func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) { p.print(stmt.Pos()) switch s := stmt.(type) { @@ -994,7 +972,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { p.print("BadStmt") case *ast.DeclStmt: - p.decl(s.Decl, multiLine) + p.decl(s.Decl) case *ast.EmptyStmt: // nothing to do @@ -1004,7 +982,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { // is applied before the line break if there is no comment // between (see writeWhitespace) p.print(unindent) - p.expr(s.Label, multiLine) + p.expr(s.Label) p.print(s.Colon, token.COLON, indent) if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty { if !nextIsRBrace { @@ -1014,21 +992,21 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { } else { p.linebreak(p.lineFor(s.Stmt.Pos()), 1, ignore, true) } - p.stmt(s.Stmt, nextIsRBrace, multiLine) + p.stmt(s.Stmt, nextIsRBrace) case *ast.ExprStmt: const depth = 1 - p.expr0(s.X, depth, multiLine) + p.expr0(s.X, depth) case *ast.SendStmt: const depth = 1 - p.expr0(s.Chan, depth, multiLine) + p.expr0(s.Chan, depth) p.print(blank, s.Arrow, token.ARROW, blank) - p.expr0(s.Value, depth, multiLine) + p.expr0(s.Value, depth) case *ast.IncDecStmt: const depth = 1 - p.expr0(s.X, depth+1, multiLine) + p.expr0(s.X, depth+1) p.print(s.TokPos, s.Tok) case *ast.AssignStmt: @@ -1036,56 +1014,55 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { if len(s.Lhs) > 1 && len(s.Rhs) > 1 { depth++ } - p.exprList(s.Pos(), s.Lhs, depth, commaSep, multiLine, s.TokPos) - p.print(blank, s.TokPos, s.Tok) - p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, token.NoPos) + p.exprList(s.Pos(), s.Lhs, depth, 0, s.TokPos) + p.print(blank, s.TokPos, s.Tok, blank) + p.exprList(s.TokPos, s.Rhs, depth, 0, token.NoPos) case *ast.GoStmt: p.print(token.GO, blank) - p.expr(s.Call, multiLine) + p.expr(s.Call) case *ast.DeferStmt: p.print(token.DEFER, blank) - p.expr(s.Call, multiLine) + p.expr(s.Call) case *ast.ReturnStmt: p.print(token.RETURN) if s.Results != nil { - p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, token.NoPos) + p.print(blank) + p.exprList(s.Pos(), s.Results, 1, 0, token.NoPos) } case *ast.BranchStmt: p.print(s.Tok) if s.Label != nil { p.print(blank) - p.expr(s.Label, multiLine) + p.expr(s.Label) } case *ast.BlockStmt: p.block(s, 1) - *multiLine = true case *ast.IfStmt: p.print(token.IF) p.controlClause(false, s.Init, s.Cond, nil) p.block(s.Body, 1) - *multiLine = true if s.Else != nil { p.print(blank, token.ELSE, blank) switch s.Else.(type) { case *ast.BlockStmt, *ast.IfStmt: - p.stmt(s.Else, nextIsRBrace, ignoreMultiLine) + p.stmt(s.Else, nextIsRBrace) default: p.print(token.LBRACE, indent, formfeed) - p.stmt(s.Else, true, ignoreMultiLine) + p.stmt(s.Else, true) p.print(unindent, formfeed, token.RBRACE) } } case *ast.CaseClause: if s.List != nil { - p.print(token.CASE) - p.exprList(s.Pos(), s.List, 1, blankStart|commaSep, multiLine, s.Colon) + p.print(token.CASE, blank) + p.exprList(s.Pos(), s.List, 1, 0, s.Colon) } else { p.print(token.DEFAULT) } @@ -1096,25 +1073,23 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { p.print(token.SWITCH) p.controlClause(false, s.Init, s.Tag, nil) p.block(s.Body, 0) - *multiLine = true case *ast.TypeSwitchStmt: p.print(token.SWITCH) if s.Init != nil { p.print(blank) - p.stmt(s.Init, false, ignoreMultiLine) + p.stmt(s.Init, false) p.print(token.SEMICOLON) } p.print(blank) - p.stmt(s.Assign, false, ignoreMultiLine) + p.stmt(s.Assign, false) p.print(blank) p.block(s.Body, 0) - *multiLine = true case *ast.CommClause: if s.Comm != nil { p.print(token.CASE, blank) - p.stmt(s.Comm, false, ignoreMultiLine) + p.stmt(s.Comm, false) } else { p.print(token.DEFAULT) } @@ -1129,29 +1104,26 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE) } else { p.block(body, 0) - *multiLine = true } case *ast.ForStmt: p.print(token.FOR) p.controlClause(true, s.Init, s.Cond, s.Post) p.block(s.Body, 1) - *multiLine = true case *ast.RangeStmt: p.print(token.FOR, blank) - p.expr(s.Key, multiLine) + p.expr(s.Key) if s.Value != nil { // use position of value following the comma as // comma position for correct comment placement p.print(s.Value.Pos(), token.COMMA, blank) - p.expr(s.Value, multiLine) + p.expr(s.Value) } p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank) - p.expr(stripParens(s.X), multiLine) + p.expr(stripParens(s.X)) p.print(blank) p.block(s.Body, 1) - *multiLine = true default: panic("unreachable") @@ -1228,20 +1200,20 @@ func keepTypeColumn(specs []ast.Spec) []bool { return m } -func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) { +func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool) { p.setComment(s.Doc) - p.identList(s.Names, doIndent, multiLine) // always present + p.identList(s.Names, doIndent) // always present extraTabs := 3 if s.Type != nil || keepType { p.print(vtab) extraTabs-- } if s.Type != nil { - p.expr(s.Type, multiLine) + p.expr(s.Type) } if s.Values != nil { - p.print(vtab, token.ASSIGN) - p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos) + p.print(vtab, token.ASSIGN, blank) + p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos) extraTabs-- } if s.Comment != nil { @@ -1255,17 +1227,16 @@ func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine // The parameter n is the number of specs in the group. If doIndent is set, // multi-line identifier lists in the spec are indented when the first // linebreak is encountered. -// Sets multiLine to true if the spec spans multiple lines. // -func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) { +func (p *printer) spec(spec ast.Spec, n int, doIndent bool) { switch s := spec.(type) { case *ast.ImportSpec: p.setComment(s.Doc) if s.Name != nil { - p.expr(s.Name, multiLine) + p.expr(s.Name) p.print(blank) } - p.expr(s.Path, multiLine) + p.expr(s.Path) p.setComment(s.Comment) p.print(s.EndPos) @@ -1274,26 +1245,26 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) { p.internalError("expected n = 1; got", n) } p.setComment(s.Doc) - p.identList(s.Names, doIndent, multiLine) // always present + p.identList(s.Names, doIndent) // always present if s.Type != nil { p.print(blank) - p.expr(s.Type, multiLine) + p.expr(s.Type) } if s.Values != nil { - p.print(blank, token.ASSIGN) - p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos) + p.print(blank, token.ASSIGN, blank) + p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos) } p.setComment(s.Comment) case *ast.TypeSpec: p.setComment(s.Doc) - p.expr(s.Name, multiLine) + p.expr(s.Name) if n == 1 { p.print(blank) } else { p.print(vtab) } - p.expr(s.Type, multiLine) + p.expr(s.Type) p.setComment(s.Comment) default: @@ -1301,8 +1272,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) { } } -// Sets multiLine to true if the declaration spans multiple lines. -func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) { +func (p *printer) genDecl(d *ast.GenDecl) { p.setComment(d.Doc) p.print(d.Pos(), d.Tok, blank) @@ -1315,32 +1285,31 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) { // two or more grouped const/var declarations: // determine if the type column must be kept keepType := keepTypeColumn(d.Specs) - var ml bool + newSection := false for i, s := range d.Specs { if i > 0 { - p.linebreak(p.lineFor(s.Pos()), 1, ignore, ml) + p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection) } - ml = false - p.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml) + p.valueSpec(s.(*ast.ValueSpec), keepType[i], false) + newSection = p.isMultiLine(s) } } else { - var ml bool + newSection := false for i, s := range d.Specs { if i > 0 { - p.linebreak(p.lineFor(s.Pos()), 1, ignore, ml) + p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection) } - ml = false - p.spec(s, n, false, &ml) + p.spec(s, n, false) + newSection = p.isMultiLine(s) } } p.print(unindent, formfeed) - *multiLine = true } p.print(d.Rparen, token.RPAREN) } else { // single declaration - p.spec(d.Specs[0], 1, true, multiLine) + p.spec(d.Specs[0], 1, true) } } @@ -1404,8 +1373,7 @@ func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool { return headerSize+bodySize <= maxSize } -// Sets multiLine to true if the function body spans multiple lines. -func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) { +func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool) { if b == nil { return } @@ -1422,7 +1390,7 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi if i > 0 { p.print(token.SEMICOLON, blank) } - p.stmt(s, i == len(b.List)-1, ignoreMultiLine) + p.stmt(s, i == len(b.List)-1) } p.print(blank) } @@ -1432,7 +1400,6 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi p.print(blank) p.block(b, 1) - *multiLine = true } // distance returns the column difference between from and to if both @@ -1446,28 +1413,26 @@ func (p *printer) distance(from0 token.Pos, to token.Position) int { return infinity } -// Sets multiLine to true if the declaration spans multiple lines. -func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) { +func (p *printer) funcDecl(d *ast.FuncDecl) { p.setComment(d.Doc) p.print(d.Pos(), token.FUNC, blank) if d.Recv != nil { - p.parameters(d.Recv, multiLine) // method: print receiver + p.parameters(d.Recv) // method: print receiver p.print(blank) } - p.expr(d.Name, multiLine) - p.signature(d.Type.Params, d.Type.Results, multiLine) - p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine) + p.expr(d.Name) + p.signature(d.Type.Params, d.Type.Results) + p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false) } -// Sets multiLine to true if the declaration spans multiple lines. -func (p *printer) decl(decl ast.Decl, multiLine *bool) { +func (p *printer) decl(decl ast.Decl) { switch d := decl.(type) { case *ast.BadDecl: p.print(d.Pos(), "BadDecl") case *ast.GenDecl: - p.genDecl(d, multiLine) + p.genDecl(d) case *ast.FuncDecl: - p.funcDecl(d, multiLine) + p.funcDecl(d) default: panic("unreachable") } @@ -1490,7 +1455,7 @@ func declToken(decl ast.Decl) (tok token.Token) { func (p *printer) file(src *ast.File) { p.setComment(src.Doc) p.print(src.Pos(), token.PACKAGE, blank) - p.expr(src.Name, ignoreMultiLine) + p.expr(src.Name) if len(src.Decls) > 0 { tok := token.ILLEGAL @@ -1509,7 +1474,7 @@ func (p *printer) file(src *ast.File) { min = 2 } p.linebreak(p.lineFor(d.Pos()), min, ignore, false) - p.decl(d, ignoreMultiLine) + p.decl(d) } } diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go index 72f65a1d852..a027d32da89 100644 --- a/libgo/go/go/printer/printer.go +++ b/libgo/go/go/printer/printer.go @@ -34,9 +34,6 @@ const ( unindent = whiteSpace('<') ) -// Use ignoreMultiLine if the multiLine information is not important. -var ignoreMultiLine = new(bool) - // A pmode value represents the current printer mode. type pmode int @@ -280,10 +277,9 @@ func (p *printer) writeString(pos token.Position, s string, isLit bool) { // it as is likely to help position the comment nicely. // pos is the comment position, next the position of the item // after all pending comments, prev is the previous comment in -// a group of comments (or nil), and isKeyword indicates if the -// next item is a keyword. +// a group of comments (or nil), and tok is the next token. // -func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *ast.Comment, isKeyword bool) { +func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *ast.Comment, tok token.Token) { if len(p.output) == 0 { // the comment is the first item to be printed - don't write any whitespace return @@ -338,38 +334,41 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as // comment on a different line: // separate with at least one line break droppedLinebreak := false - if prev == nil { - // first comment of a comment group - j := 0 - for i, ch := range p.wsbuf { - switch ch { - case blank, vtab: - // ignore any horizontal whitespace before line breaks - p.wsbuf[i] = ignore + j := 0 + for i, ch := range p.wsbuf { + switch ch { + case blank, vtab: + // ignore any horizontal whitespace before line breaks + p.wsbuf[i] = ignore + continue + case indent: + // apply pending indentation + continue + case unindent: + // if this is not the last unindent, apply it + // as it is (likely) belonging to the last + // construct (e.g., a multi-line expression list) + // and is not part of closing a block + if i+1 < len(p.wsbuf) && p.wsbuf[i+1] == unindent { continue - case indent: - // apply pending indentation + } + // if the next token is not a closing }, apply the unindent + // if it appears that the comment is aligned with the + // token; otherwise assume the unindent is part of a + // closing block and stop (this scenario appears with + // comments before a case label where the comments + // apply to the next case instead of the current one) + if tok != token.RBRACE && pos.Column == next.Column { continue - case unindent: - // if the next token is a keyword, apply the outdent - // if it appears that the comment is aligned with the - // keyword; otherwise assume the outdent is part of a - // closing block and stop (this scenario appears with - // comments before a case label where the comments - // apply to the next case instead of the current one) - if isKeyword && pos.Column == next.Column { - continue - } - case newline, formfeed: - // TODO(gri): may want to keep formfeed info in some cases - p.wsbuf[i] = ignore - droppedLinebreak = true } - j = i - break + case newline, formfeed: + p.wsbuf[i] = ignore + droppedLinebreak = prev == nil // record only if first comment of a group } - p.writeWhitespace(j) + j = i + break } + p.writeWhitespace(j) // determine number of linebreaks before the comment n := 0 @@ -678,7 +677,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro var last *ast.Comment for p.commentBefore(next) { for _, c := range p.comment.List { - p.writeCommentPrefix(p.posFor(c.Pos()), next, last, c, tok.IsKeyword()) + p.writeCommentPrefix(p.posFor(c.Pos()), next, last, c, tok) p.writeComment(c) last = c } @@ -1011,18 +1010,18 @@ func (p *printer) printNode(node interface{}) error { // format node switch n := node.(type) { case ast.Expr: - p.expr(n, ignoreMultiLine) + p.expr(n) case ast.Stmt: // A labeled statement will un-indent to position the // label. Set indent to 1 so we don't get indent "underflow". if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt { p.indent = 1 } - p.stmt(n, false, ignoreMultiLine) + p.stmt(n, false) case ast.Decl: - p.decl(n, ignoreMultiLine) + p.decl(n) case ast.Spec: - p.spec(n, 1, false, ignoreMultiLine) + p.spec(n, 1, false) case *ast.File: p.file(n) default: diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go index 2d4f61356c1..497d671f240 100644 --- a/libgo/go/go/printer/printer_test.go +++ b/libgo/go/go/printer/printer_test.go @@ -154,15 +154,12 @@ var data = []entry{ } func TestFiles(t *testing.T) { - for i, e := range data { + for _, e := range data { source := filepath.Join(dataDir, e.source) golden := filepath.Join(dataDir, e.golden) check(t, source, golden, e.mode) // TODO(gri) check that golden is idempotent //check(t, golden, golden, e.mode) - if testing.Short() && i >= 3 { - break - } } } diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden index 4c6f1ab8274..d9aa2d82f7d 100644 --- a/libgo/go/go/printer/testdata/comments.golden +++ b/libgo/go/go/printer/testdata/comments.golden @@ -168,6 +168,91 @@ func typeswitch(x interface{}) { // this comment should not be indented } +// +// Indentation of comments after possibly indented multi-line constructs +// (test cases for issue 3147). +// + +func _() { + s := 1 + + 2 + // should be indented like s +} + +func _() { + s := 1 + + 2 // comment + // should be indented like s +} + +func _() { + s := 1 + + 2 // comment + // should be indented like s + _ = 0 +} + +func _() { + s := 1 + + 2 + // should be indented like s + _ = 0 +} + +func _() { + s := 1 + + 2 + + // should be indented like s +} + +func _() { + s := 1 + + 2 // comment + + // should be indented like s +} + +func _() { + s := 1 + + 2 // comment + + // should be indented like s + _ = 0 +} + +func _() { + s := 1 + + 2 + + // should be indented like s + _ = 0 +} + +// Test case from issue 3147. +func f() { + templateText := "a" + // A + "b" + // B + "c" // C + + // should be aligned with f() + f() +} + +// Modified test case from issue 3147. +func f() { + templateText := "a" + // A + "b" + // B + "c" // C + + // may not be aligned with f() (source is not aligned) + f() +} + +// +// Test cases for alignment of lines in general comments. +// + func _() { /* freestanding comment aligned line diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input index c0f8cca3a92..6084b3fe450 100644 --- a/libgo/go/go/printer/testdata/comments.input +++ b/libgo/go/go/printer/testdata/comments.input @@ -171,6 +171,91 @@ func typeswitch(x interface{}) { // this comment should not be indented } +// +// Indentation of comments after possibly indented multi-line constructs +// (test cases for issue 3147). +// + +func _() { + s := 1 + + 2 +// should be indented like s +} + +func _() { + s := 1 + + 2 // comment + // should be indented like s +} + +func _() { + s := 1 + + 2 // comment + // should be indented like s + _ = 0 +} + +func _() { + s := 1 + + 2 + // should be indented like s + _ = 0 +} + +func _() { + s := 1 + + 2 + +// should be indented like s +} + +func _() { + s := 1 + + 2 // comment + + // should be indented like s +} + +func _() { + s := 1 + + 2 // comment + + // should be indented like s + _ = 0 +} + +func _() { + s := 1 + + 2 + + // should be indented like s + _ = 0 +} + +// Test case from issue 3147. +func f() { + templateText := "a" + // A + "b" + // B + "c" // C + + // should be aligned with f() + f() +} + +// Modified test case from issue 3147. +func f() { + templateText := "a" + // A + "b" + // B + "c" // C + + // may not be aligned with f() (source is not aligned) + f() +} + +// +// Test cases for alignment of lines in general comments. +// + func _() { /* freestanding comment aligned line diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden index 928b8ce0a9f..7ed7cb61ae5 100644 --- a/libgo/go/go/printer/testdata/declarations.golden +++ b/libgo/go/go/printer/testdata/declarations.golden @@ -83,13 +83,13 @@ import ( // more import examples import ( "xxx" - "much longer name" // comment - "short name" // comment + "much_longer_name" // comment + "short_name" // comment ) import ( _ "xxx" - "much longer name" // comment + "much_longer_name" // comment ) import ( @@ -500,7 +500,7 @@ type _ struct { type _ struct { a, b, - c, d int // this line should be indented + c, d int // this line should be indented u, v, w, x float // this line should be indented p, q, r, s float // this line should be indented @@ -562,7 +562,7 @@ var a2, b2, var ( a3, b3, - c3, d3 int // this line should be indented + c3, d3 int // this line should be indented a4, b4, c4 int // this line should be indented ) diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input index 68f90308a36..df8c2b167e1 100644 --- a/libgo/go/go/printer/testdata/declarations.input +++ b/libgo/go/go/printer/testdata/declarations.input @@ -84,13 +84,13 @@ import ( // more import examples import ( "xxx" - "much longer name" // comment - "short name" // comment + "much_longer_name" // comment + "short_name" // comment ) import ( _ "xxx" - "much longer name" // comment + "much_longer_name" // comment ) import ( diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden index 95fdd95ffbb..45fa4d97a4a 100644 --- a/libgo/go/go/printer/testdata/expressions.golden +++ b/libgo/go/go/printer/testdata/expressions.golden @@ -625,3 +625,25 @@ func f() { log.Fatal(err) } } + +// Handle multi-line argument lists ending in ... correctly. +// Was issue 3130. +func _() { + _ = append(s, a...) + _ = append( + s, a...) + _ = append(s, + a...) + _ = append( + s, + a...) + _ = append(s, a..., + ) + _ = append(s, + a..., + ) + _ = append( + s, + a..., + ) +} diff --git a/libgo/go/go/printer/testdata/expressions.input b/libgo/go/go/printer/testdata/expressions.input index d1131498352..f545c66057c 100644 --- a/libgo/go/go/printer/testdata/expressions.input +++ b/libgo/go/go/printer/testdata/expressions.input @@ -654,3 +654,25 @@ func f() { log.Fatal(err) } } + +// Handle multi-line argument lists ending in ... correctly. +// Was issue 3130. +func _() { + _ = append(s, a...) + _ = append( + s, a...) + _ = append(s, + a...) + _ = append( + s, + a...) + _ = append(s, a..., + ) + _ = append(s, + a..., + ) + _ = append( + s, + a..., + ) +} diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw index 3442ba9b950..87a4b00836d 100644 --- a/libgo/go/go/printer/testdata/expressions.raw +++ b/libgo/go/go/printer/testdata/expressions.raw @@ -625,3 +625,25 @@ func f() { log.Fatal(err) } } + +// Handle multi-line argument lists ending in ... correctly. +// Was issue 3130. +func _() { + _ = append(s, a...) + _ = append( + s, a...) + _ = append(s, + a...) + _ = append( + s, + a...) + _ = append(s, a..., + ) + _ = append(s, + a..., + ) + _ = append( + s, + a..., + ) +} diff --git a/libgo/go/go/printer/testdata/parser.go b/libgo/go/go/printer/testdata/parser.go index c85297f5831..dba8bbd4351 100644 --- a/libgo/go/go/printer/testdata/parser.go +++ b/libgo/go/go/printer/testdata/parser.go @@ -52,7 +52,7 @@ type parser struct { // Non-syntactic parser control exprLev int // < 0: in control clause, >= 0: in expression - // Ordinary identifer scopes + // Ordinary identifier scopes pkgScope *ast.Scope // pkgScope.Outer == nil topScope *ast.Scope // top-most scope; may be pkgScope unresolved []*ast.Ident // unresolved identifiers diff --git a/libgo/go/go/printer/testdata/statements.golden b/libgo/go/go/printer/testdata/statements.golden index 90e1743557d..ffca21edba9 100644 --- a/libgo/go/go/printer/testdata/statements.golden +++ b/libgo/go/go/printer/testdata/statements.golden @@ -8,6 +8,82 @@ var expr bool func use(x interface{}) {} +// Formatting of multi-line return statements. +func _f() { + return + return x, y, z + return T{} + return T{1, 2, 3}, + x, y, z + return T{1, 2, 3}, + x, y, + z + return T{1, + 2, + 3} + return T{1, + 2, + 3, + } + return T{ + 1, + 2, + 3} + return T{ + 1, + 2, + 3, + } + return T{ + 1, + T{1, 2, 3}, + 3, + } + return T{ + 1, + T{1, + 2, 3}, + 3, + } + return T{ + 1, + T{1, + 2, + 3}, + 3, + } + return T{ + 1, + 2, + }, + nil + return T{ + 1, + 2, + }, + T{ + x: 3, + y: 4, + }, + nil + return x + y + + z + return func() {} + return func() { + _ = 0 + }, T{ + 1, 2, + } + return func() { + _ = 0 + } + return func() T { + return T{ + 1, 2, + } + } +} + // Formatting of if-statement headers. func _() { if true { diff --git a/libgo/go/go/printer/testdata/statements.input b/libgo/go/go/printer/testdata/statements.input index 86a753c5ad9..99945e9551a 100644 --- a/libgo/go/go/printer/testdata/statements.input +++ b/libgo/go/go/printer/testdata/statements.input @@ -8,6 +8,82 @@ var expr bool func use(x interface{}) {} +// Formatting of multi-line return statements. +func _f() { + return + return x, y, z + return T{} + return T{1, 2, 3}, + x, y, z + return T{1, 2, 3}, + x, y, + z + return T{1, + 2, + 3} + return T{1, + 2, + 3, + } + return T{ + 1, + 2, + 3} + return T{ + 1, + 2, + 3, + } + return T{ + 1, + T{1, 2, 3}, + 3, + } + return T{ + 1, + T{1, + 2, 3}, + 3, + } + return T{ + 1, + T{1, + 2, + 3}, + 3, + } + return T{ + 1, + 2, + }, + nil + return T{ + 1, + 2, + }, + T{ + x: 3, + y: 4, + }, + nil + return x + y + + z + return func() {} + return func() { + _ = 0 + }, T{ + 1, 2, + } + return func() { + _ = 0 + } + return func() T { + return T { + 1, 2, + } + } +} + // Formatting of if-statement headers. func _() { if true {} |