mirror of
https://github.com/golang/go
synced 2024-11-17 21:34:49 -07:00
godoc: fix formatting of -src output
- go/filter.go: make MergePackageFiles smarter - go/printer.go: handle positions from multiple files R=rsc CC=golang-dev https://golang.org/cl/460042
This commit is contained in:
parent
8107cad45a
commit
3e24f2d6df
@ -1150,7 +1150,7 @@ func (h *httpHandler) getPageInfo(dirname, relpath string, genAST, try bool) Pag
|
||||
if pkg != nil {
|
||||
ast.PackageExports(pkg)
|
||||
if genAST {
|
||||
past = ast.MergePackageFiles(pkg)
|
||||
past = ast.MergePackageFiles(pkg, false)
|
||||
} else {
|
||||
pdoc = doc.NewPackageDoc(pkg, pathutil.Clean(relpath)) // no trailing '/' in importpath
|
||||
}
|
||||
|
@ -195,18 +195,46 @@ func PackageExports(pkg *Package) bool {
|
||||
var separator = &Comment{noPos, []byte("//")}
|
||||
|
||||
|
||||
// lineAfterComment computes the position of the beginning
|
||||
// of the line immediately following a comment.
|
||||
func lineAfterComment(c *Comment) token.Position {
|
||||
pos := c.Pos()
|
||||
line := pos.Line
|
||||
text := c.Text
|
||||
if text[1] == '*' {
|
||||
/*-style comment - determine endline */
|
||||
for _, ch := range text {
|
||||
if ch == '\n' {
|
||||
line++
|
||||
}
|
||||
}
|
||||
}
|
||||
pos.Offset += len(text) + 1 // +1 for newline
|
||||
pos.Line = line + 1 // line after comment
|
||||
pos.Column = 1 // beginning of line
|
||||
return pos
|
||||
}
|
||||
|
||||
|
||||
// MergePackageFiles creates a file AST by merging the ASTs of the
|
||||
// files belonging to a package.
|
||||
// files belonging to a package. If complete is set, the package
|
||||
// files are assumed to contain the complete, unfiltered package
|
||||
// information. In this case, MergePackageFiles collects all entities
|
||||
// and all comments. Otherwise (complete == false), MergePackageFiles
|
||||
// excludes duplicate entries and does not collect comments that are
|
||||
// not attached to AST nodes.
|
||||
//
|
||||
func MergePackageFiles(pkg *Package) *File {
|
||||
// Count the number of package comments and declarations across
|
||||
func MergePackageFiles(pkg *Package, complete bool) *File {
|
||||
// Count the number of package docs, comments and declarations across
|
||||
// all package files.
|
||||
ndocs := 0
|
||||
ncomments := 0
|
||||
ndecls := 0
|
||||
for _, f := range pkg.Files {
|
||||
if f.Doc != nil {
|
||||
ncomments += len(f.Doc.List) + 1 // +1 for separator
|
||||
ndocs += len(f.Doc.List) + 1 // +1 for separator
|
||||
}
|
||||
ncomments += len(f.Comments)
|
||||
ndecls += len(f.Decls)
|
||||
}
|
||||
|
||||
@ -216,8 +244,9 @@ func MergePackageFiles(pkg *Package) *File {
|
||||
// a package comment; but it's better to collect extra comments
|
||||
// than drop them on the floor.
|
||||
var doc *CommentGroup
|
||||
if ncomments > 0 {
|
||||
list := make([]*Comment, ncomments-1) // -1: no separator before first group
|
||||
var pos token.Position
|
||||
if ndocs > 0 {
|
||||
list := make([]*Comment, ndocs-1) // -1: no separator before first group
|
||||
i := 0
|
||||
for _, f := range pkg.Files {
|
||||
if f.Doc != nil {
|
||||
@ -230,6 +259,12 @@ func MergePackageFiles(pkg *Package) *File {
|
||||
list[i] = c
|
||||
i++
|
||||
}
|
||||
end := lineAfterComment(f.Doc.List[len(f.Doc.List)-1])
|
||||
if end.Offset > pos.Offset {
|
||||
// Keep the maximum end position as
|
||||
// position for the package clause.
|
||||
pos = end
|
||||
}
|
||||
}
|
||||
}
|
||||
doc = &CommentGroup{list}
|
||||
@ -239,15 +274,70 @@ func MergePackageFiles(pkg *Package) *File {
|
||||
var decls []Decl
|
||||
if ndecls > 0 {
|
||||
decls = make([]Decl, ndecls)
|
||||
i := 0
|
||||
funcs := make(map[string]int) // map of global function name -> decls index
|
||||
i := 0 // current index
|
||||
n := 0 // number of filtered entries
|
||||
for _, f := range pkg.Files {
|
||||
for _, d := range f.Decls {
|
||||
if !complete {
|
||||
// A language entity may be declared multiple
|
||||
// times in different package files; only at
|
||||
// build time declarations must be unique.
|
||||
// For now, exclude multiple declarations of
|
||||
// functions - keep the one with documentation.
|
||||
//
|
||||
// TODO(gri): Expand this filtering to other
|
||||
// entities (const, type, vars) if
|
||||
// multiple declarations are common.
|
||||
if f, isFun := d.(*FuncDecl); isFun {
|
||||
name := f.Name.Name()
|
||||
if j, exists := funcs[name]; exists {
|
||||
// function declared already
|
||||
if decls[j].(*FuncDecl).Doc == nil {
|
||||
// existing declaration has no documentation;
|
||||
// ignore the existing declaration
|
||||
decls[j] = nil
|
||||
} else {
|
||||
// ignore the new declaration
|
||||
d = nil
|
||||
}
|
||||
n++ // filtered an entry
|
||||
} else {
|
||||
funcs[name] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
decls[i] = d
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// Eliminate nil entries from the decls list if entries were
|
||||
// filtered. We do this using a 2nd pass in order to not disturb
|
||||
// the original declaration order in the source (otherwise, this
|
||||
// would also invalidate the monotonically increasing position
|
||||
// info within a single file).
|
||||
if n > 0 {
|
||||
i = 0
|
||||
for _, d := range decls {
|
||||
if d != nil {
|
||||
decls[i] = d
|
||||
i++
|
||||
}
|
||||
}
|
||||
decls = decls[0:i]
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(gri) Should collect comments as well.
|
||||
return &File{doc, noPos, NewIdent(pkg.Name), decls, nil}
|
||||
// Collect comments from all package files.
|
||||
var comments []*CommentGroup
|
||||
if complete {
|
||||
comments = make([]*CommentGroup, ncomments)
|
||||
i := 0
|
||||
for _, f := range pkg.Files {
|
||||
i += copy(comments[i:], f.Comments)
|
||||
}
|
||||
}
|
||||
|
||||
return &File{doc, pos, NewIdent(pkg.Name), decls, comments}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"go/token"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"tabwriter"
|
||||
@ -240,19 +241,30 @@ func (p *printer) writeTaggedItem(data []byte, tag HTMLTag) {
|
||||
// immediately following the data.
|
||||
//
|
||||
func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
|
||||
fileChanged := false
|
||||
if pos.IsValid() {
|
||||
// continue with previous position if we don't have a valid pos
|
||||
if p.last.IsValid() && p.last.Filename != pos.Filename {
|
||||
// the file has changed - reset state
|
||||
// (used when printing merged ASTs of different files
|
||||
// e.g., the result of ast.MergePackageFiles)
|
||||
p.indent = 0
|
||||
p.escape = false
|
||||
p.buffer = p.buffer[0:0]
|
||||
fileChanged = true
|
||||
}
|
||||
p.pos = pos
|
||||
}
|
||||
if debug {
|
||||
// do not update p.pos - use write0
|
||||
p.write0([]byte(fmt.Sprintf("[%d:%d]", pos.Line, pos.Column)))
|
||||
_, filename := path.Split(pos.Filename)
|
||||
p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column)))
|
||||
}
|
||||
if p.Mode&GenHTML != 0 {
|
||||
// write line tag if on a new line
|
||||
// TODO(gri): should write line tags on each line at the start
|
||||
// will be more useful (e.g. to show line numbers)
|
||||
if p.Styler != nil && pos.Line > p.lastTaggedLine {
|
||||
if p.Styler != nil && (pos.Line != p.lastTaggedLine || fileChanged) {
|
||||
p.writeTaggedItem(p.Styler.LineTag(pos.Line))
|
||||
p.lastTaggedLine = pos.Line
|
||||
}
|
||||
@ -279,7 +291,13 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
|
||||
return
|
||||
}
|
||||
|
||||
if pos.Line == p.last.Line {
|
||||
if pos.IsValid() && pos.Filename != p.last.Filename {
|
||||
// comment in a different file - separate with newlines
|
||||
p.writeNewlines(maxNewlines, true)
|
||||
return
|
||||
}
|
||||
|
||||
if pos.IsValid() && pos.Line == p.last.Line {
|
||||
// comment on the same line as last item:
|
||||
// separate with at least one separator
|
||||
hasSep := false
|
||||
@ -353,6 +371,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
|
||||
// use formfeeds to break columns before a comment;
|
||||
// this is analogous to using formfeeds to separate
|
||||
// individual lines of /*-style comments
|
||||
// (if !pos.IsValid(), pos.Line == 0, and this will
|
||||
// print no newlines)
|
||||
p.writeNewlines(pos.Line-p.last.Line, true)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user