type Mode int
const (
- // extract documentation for all package-level declarations,
- // not just exported ones
+ // AllDecls says to extract documentation for all package-level
+ // declarations, not just exported ones.
AllDecls Mode = 1 << iota
- // show all embedded methods, not just the ones of
- // invisible (unexported) anonymous fields
+ // AllMethods says to show all embedded methods, not just the ones of
+ // invisible (unexported) anonymous fields.
AllMethods
+
+ // PreserveAST says to leave the AST unmodified. Originally, pieces of
+ // the AST such as function bodies were nil-ed out to save memory in
+ // godoc, but not all programs want that behavior.
+ PreserveAST
)
// New computes the package documentation for the given package AST.
// set creates the corresponding Func for f and adds it to mset.
// If there are multiple f's with the same name, set keeps the first
-// one with documentation; conflicts are ignored.
+// one with documentation; conflicts are ignored. The boolean
+// specifies whether to leave the AST untouched.
//
-func (mset methodSet) set(f *ast.FuncDecl) {
+func (mset methodSet) set(f *ast.FuncDecl, preserveAST bool) {
name := f.Name.Name
if g := mset[name]; g != nil && g.Doc != "" {
// A function with the same name has already been registered;
Recv: recv,
Orig: recv,
}
- f.Doc = nil // doc consumed - remove from AST
+ if !preserveAST {
+ f.Doc = nil // doc consumed - remove from AST
+ }
}
// add adds method m to the method set; m is ignored if the method set
Decl: decl,
order: r.order,
})
- decl.Doc = nil // doc consumed - remove from AST
-
+ if r.mode&PreserveAST == 0 {
+ decl.Doc = nil // doc consumed - remove from AST
+ }
// Note: It's important that the order used here is global because the cleanupTypes
// methods may move values associated with types back into the global list. If the
// order is list-specific, sorting is not deterministic because the same order value
// compute documentation
doc := spec.Doc
- spec.Doc = nil // doc consumed - remove from AST
if doc == nil {
// no doc associated with the spec, use the declaration doc, if any
doc = decl.Doc
}
- decl.Doc = nil // doc consumed - remove from AST
+ if r.mode&PreserveAST == 0 {
+ spec.Doc = nil // doc consumed - remove from AST
+ decl.Doc = nil // doc consumed - remove from AST
+ }
typ.doc = doc.Text()
// record anonymous fields (they may contribute methods)
// readFunc processes a func or method declaration.
//
func (r *reader) readFunc(fun *ast.FuncDecl) {
- // strip function body
- fun.Body = nil
+ // strip function body if requested.
+ if r.mode&PreserveAST == 0 {
+ fun.Body = nil
+ }
// associate methods with the receiver type, if any
if fun.Recv != nil {
return
}
if typ := r.lookupType(recvTypeName); typ != nil {
- typ.methods.set(fun)
+ typ.methods.set(fun, r.mode&PreserveAST != 0)
}
// otherwise ignore the method
// TODO(gri): There may be exported methods of non-exported types
}
// If there is exactly one result type, associate the function with that type.
if numResultTypes == 1 {
- typ.funcs.set(fun)
+ typ.funcs.set(fun, r.mode&PreserveAST != 0)
return
}
}
// just an ordinary function
- r.funcs.set(fun)
+ r.funcs.set(fun, r.mode&PreserveAST != 0)
}
var (
// add package documentation
if src.Doc != nil {
r.readDoc(src.Doc)
- src.Doc = nil // doc consumed - remove from AST
+ if r.mode&PreserveAST == 0 {
+ src.Doc = nil // doc consumed - remove from AST
+ }
}
// add all declarations
// collect MARKER(...): annotations
r.readNotes(src.Comments)
- src.Comments = nil // consumed unassociated comments - remove from AST
+ if r.mode&PreserveAST == 0 {
+ src.Comments = nil // consumed unassociated comments - remove from AST
+ }
}
func (r *reader) readPackage(pkg *ast.Package, mode Mode) {