summaryrefslogtreecommitdiff
path: root/src/pkg/go/printer/nodes.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/go/printer/nodes.go')
-rw-r--r--src/pkg/go/printer/nodes.go116
1 files changed, 73 insertions, 43 deletions
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index 364530634..5f3b4d4a7 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -39,7 +39,10 @@ import (
// future (not yet interspersed) comments in this function.
//
func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
- n := p.nlines(line-p.pos.Line, min)
+ n := nlimit(line - p.pos.Line)
+ if n < min {
+ n = min
+ }
if n > 0 {
p.print(ws)
if newSection {
@@ -69,7 +72,7 @@ func (p *printer) setComment(g *ast.CommentGroup) {
// for some reason there are pending comments; this
// should never happen - handle gracefully and flush
// all comments up to g, ignore anything after that
- p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL)
+ p.flush(p.posFor(g.List[0].Pos()), token.ILLEGAL)
}
p.comments[0] = g
p.cindex = 0
@@ -119,10 +122,10 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
p.print(blank)
}
- prev := p.fset.Position(prev0)
- next := p.fset.Position(next0)
- line := p.fset.Position(list[0].Pos()).Line
- endLine := p.fset.Position(list[len(list)-1].End()).Line
+ prev := p.posFor(prev0)
+ next := p.posFor(next0)
+ line := p.lineFor(list[0].Pos())
+ endLine := p.lineFor(list[len(list)-1].End())
if prev.IsValid() && prev.Line == line && line == endLine {
// all list entries on a single line
@@ -166,7 +169,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// print all list elements
for i, x := range list {
prevLine := line
- line = p.fset.Position(x.Pos()).Line
+ line = p.lineFor(x.Pos())
// determine if the next linebreak, if any, needs to use formfeed:
// in general, use the entire node size to make the decision; for
@@ -269,23 +272,32 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
p.print(fields.Opening, token.LPAREN)
if len(fields.List) > 0 {
+ prevLine := p.lineFor(fields.Opening)
ws := indent
- var prevLine, line int
for i, par := range fields.List {
+ // determine par begin and end line (may be different
+ // if there are multiple parameter names for this par
+ // or the type is on a separate line)
+ var parLineBeg int
+ var parLineEnd = p.lineFor(par.Type.Pos())
+ if len(par.Names) > 0 {
+ parLineBeg = p.lineFor(par.Names[0].Pos())
+ } else {
+ parLineBeg = parLineEnd
+ }
+ // separating "," if needed
if i > 0 {
p.print(token.COMMA)
- if len(par.Names) > 0 {
- line = p.fset.Position(par.Names[0].Pos()).Line
- } else {
- line = p.fset.Position(par.Type.Pos()).Line
- }
- if 0 < prevLine && prevLine < line && p.linebreak(line, 0, ws, true) {
- ws = ignore
- *multiLine = true
- } else {
- p.print(blank)
- }
}
+ // separator if needed (linebreak or blank)
+ if 0 < prevLine && prevLine < parLineBeg && 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)
+ }
+ // parameter names
if len(par.Names) > 0 {
// Very subtle: If we indented before (ws == ignore), identList
// won't indent again. If we didn't (ws == indent), identList will
@@ -296,11 +308,18 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
p.identList(par.Names, ws == indent, multiLine)
p.print(blank)
}
+ // parameter type
p.expr(par.Type, multiLine)
- prevLine = p.fset.Position(par.Type.Pos()).Line
+ prevLine = parLineEnd
}
+ // if the closing ")" is on a separate line from the last parameter,
+ // print an additional "," and line break
+ if closing := p.lineFor(fields.Closing); 0 < prevLine && prevLine < closing {
+ p.print(",")
+ p.linebreak(closing, 0, ignore, true)
+ }
+ // unindent if we indented
if ws == ignore {
- // unindent if we indented
p.print(unindent)
}
}
@@ -354,16 +373,17 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
}
func (p *printer) setLineComment(text string) {
- p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}})
+ p.setComment(&ast.CommentGroup{[]*ast.Comment{{token.NoPos, text}}})
}
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
lbrace := fields.Opening
list := fields.List
rbrace := fields.Closing
- srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(lbrace).Line == p.fset.Position(rbrace).Line
+ hasComments := isIncomplete || p.commentBefore(p.posFor(rbrace))
+ srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.lineFor(lbrace) == p.lineFor(rbrace)
- if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOneLine {
+ if !hasComments && srcIsOneLine {
// possibly a one-line struct/interface
if len(list) == 0 {
// no blank between keyword and {} in this case
@@ -388,9 +408,13 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
return
}
}
+ // hasComments || !srcIsOneLine
+
+ p.print(blank, lbrace, token.LBRACE, indent)
+ if hasComments || len(list) > 0 {
+ p.print(formfeed)
+ }
- // at least one entry or incomplete
- p.print(blank, lbrace, token.LBRACE, indent, formfeed)
if isStruct {
sep := vtab
@@ -400,7 +424,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
var ml bool
for i, f := range list {
if i > 0 {
- p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
+ p.linebreak(p.lineFor(f.Pos()), 1, ignore, ml)
}
ml = false
extraTabs := 0
@@ -435,7 +459,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
if len(list) > 0 {
p.print(formfeed)
}
- p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
+ p.flush(p.posFor(rbrace), token.RBRACE) // make sure we don't lose the last line comment
p.setLineComment("// contains filtered or unexported fields")
}
@@ -444,7 +468,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
var ml bool
for i, f := range list {
if i > 0 {
- p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
+ p.linebreak(p.lineFor(f.Pos()), 1, ignore, ml)
}
ml = false
p.setComment(f.Doc)
@@ -462,7 +486,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
if len(list) > 0 {
p.print(formfeed)
}
- p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
+ p.flush(p.posFor(rbrace), token.RBRACE) // make sure we don't lose the last line comment
p.setLineComment("// contains filtered or unexported methods")
}
@@ -618,7 +642,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
p.print(blank)
}
xline := p.pos.Line // before the operator (it may be on the next line!)
- yline := p.fset.Position(x.Y.Pos()).Line
+ yline := p.lineFor(x.Y.Pos())
p.print(x.OpPos, x.Op)
if xline != yline && xline > 0 && yline > 0 {
// at least one line break, but respect an extra empty line
@@ -911,7 +935,7 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
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.fset.Position(s.Pos()).Line, 1, ignore, i == 0 || _indent == 0 || multiLine)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || _indent == 0 || multiLine)
multiLine = false
p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine)
}
@@ -924,7 +948,7 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
func (p *printer) block(s *ast.BlockStmt, indent int) {
p.print(s.Pos(), token.LBRACE)
p.stmtList(s.List, indent, true)
- p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true)
+ p.linebreak(p.lineFor(s.Rbrace), 1, ignore, true)
p.print(s.Rbrace, token.RBRACE)
}
@@ -1025,7 +1049,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
break
}
} else {
- p.linebreak(p.fset.Position(s.Stmt.Pos()).Line, 1, ignore, true)
+ p.linebreak(p.lineFor(s.Stmt.Pos()), 1, ignore, true)
}
p.stmt(s.Stmt, nextIsRBrace, multiLine)
@@ -1137,7 +1161,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
case *ast.SelectStmt:
p.print(token.SELECT, blank)
body := s.Body
- if len(body.List) == 0 && !p.commentBefore(p.fset.Position(body.Rbrace)) {
+ if len(body.List) == 0 && !p.commentBefore(p.posFor(body.Rbrace)) {
// print empty select statement w/o comments on one line
p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
} else {
@@ -1278,6 +1302,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
}
p.expr(s.Path, multiLine)
p.setComment(s.Comment)
+ p.print(s.EndPos)
case *ast.ValueSpec:
if n != 1 {
@@ -1328,7 +1353,7 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
var ml bool
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, ml)
}
ml = false
p.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml)
@@ -1337,7 +1362,7 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
var ml bool
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, ml)
}
ml = false
p.spec(s, n, false, &ml)
@@ -1376,7 +1401,7 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
// in RawFormat
cfg := Config{Mode: RawFormat}
var buf bytes.Buffer
- if _, err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
+ if err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
return
}
if buf.Len() <= maxSize {
@@ -1394,11 +1419,11 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
pos1 := b.Pos()
pos2 := b.Rbrace
- if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.fset.Position(pos2).Line {
+ if pos1.IsValid() && pos2.IsValid() && p.lineFor(pos1) != p.lineFor(pos2) {
// opening and closing brace are on different lines - don't make it a one-liner
return false
}
- if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) {
+ if len(b.List) > 5 || p.commentBefore(p.posFor(pos2)) {
// too many statements or there is a comment inside - don't make it a one-liner
return false
}
@@ -1449,7 +1474,7 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
// are on the same line; if they are on different lines (or unknown)
// the result is infinity.
func (p *printer) distance(from0 token.Pos, to token.Position) int {
- from := p.fset.Position(from0)
+ from := p.posFor(from0)
if from.IsValid() && to.IsValid() && from.Line == to.Line {
return to.Column - from.Column
}
@@ -1508,12 +1533,17 @@ func (p *printer) file(src *ast.File) {
prev := tok
tok = declToken(d)
// if the declaration token changed (e.g., from CONST to TYPE)
+ // or the next declaration has documentation associated with it,
// print an empty line between top-level declarations
+ // (because p.linebreak is called with the position of d, which
+ // is past any documentation, the minimum requirement is satisfied
+ // even w/o the extra getDoc(d) nil-check - leave it in case the
+ // linebreak logic improves - there's already a TODO).
min := 1
- if prev != tok {
+ if prev != tok || getDoc(d) != nil {
min = 2
}
- p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false)
+ p.linebreak(p.lineFor(d.Pos()), min, ignore, false)
p.decl(d, ignoreMultiLine)
}
}