summaryrefslogtreecommitdiff
path: root/src/pkg/go/doc/doc.go
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2009-08-28 09:11:01 -0700
committerRobert Griesemer <gri@golang.org>2009-08-28 09:11:01 -0700
commitd820612026ad44252988b00bc5fcfa3e350dbc2a (patch)
tree0f24901520c8327a41f5755193f506d548a40424 /src/pkg/go/doc/doc.go
parentb979c01cf58ce2c5ed0865dc29ad0e88dc0233cc (diff)
downloadgolang-d820612026ad44252988b00bc5fcfa3e350dbc2a.tar.gz
- collect consts and vars in one list
- handle absence of forward-decls correctly (cannot assume a type was declared before it was used) R=rsc DELTA=112 (32 added, 38 deleted, 42 changed) OCL=34008 CL=34027
Diffstat (limited to 'src/pkg/go/doc/doc.go')
-rw-r--r--src/pkg/go/doc/doc.go144
1 files changed, 69 insertions, 75 deletions
diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go
index b88709980..21d086f89 100644
--- a/src/pkg/go/doc/doc.go
+++ b/src/pkg/go/doc/doc.go
@@ -19,7 +19,10 @@ import (
// ----------------------------------------------------------------------------
type typeDoc struct {
- decl *ast.GenDecl; // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
+ // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
+ // if the type declaration hasn't been seen yet, decl is nil
+ decl *ast.GenDecl;
+ // factory functions and methods associated with the type
factories map[string] *ast.FuncDecl;
methods map[string] *ast.FuncDecl;
}
@@ -34,23 +37,34 @@ type typeDoc struct {
//
type docReader struct {
doc *ast.CommentGroup; // package documentation, if any
- consts *vector.Vector; // list of *ast.GenDecl
+ values *vector.Vector; // list of *ast.GenDecl (consts and vars)
types map[string] *typeDoc;
- vars *vector.Vector; // list of *ast.GenDecl
funcs map[string] *ast.FuncDecl;
bugs *vector.Vector; // list of *ast.CommentGroup
}
func (doc *docReader) init() {
- doc.consts = vector.New(0);
+ doc.values = vector.New(0);
doc.types = make(map[string] *typeDoc);
- doc.vars = vector.New(0);
doc.funcs = make(map[string] *ast.FuncDecl);
doc.bugs = vector.New(0);
}
+func (doc *docReader) addType(decl *ast.GenDecl) {
+ spec := decl.Specs[0].(*ast.TypeSpec);
+ typ := doc.lookupTypeDoc(spec.Name.Value);
+ // typ should always be != nil since declared types
+ // are always named - be conservative and check
+ if typ != nil {
+ // a type should be added at most once, so typ.decl
+ // should be nil - if it isn't, simply overwrite it
+ typ.decl = decl;
+ }
+}
+
+
func baseTypeName(typ ast.Expr) string {
switch t := typ.(type) {
case *ast.Ident:
@@ -62,39 +76,17 @@ func baseTypeName(typ ast.Expr) string {
}
-func (doc *docReader) lookupTypeDoc(typ ast.Expr) *typeDoc {
- tdoc, found := doc.types[baseTypeName(typ)];
- if found {
- return tdoc;
+func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
+ if name == "" {
+ return nil; // no type docs for anonymous types
}
- return nil;
-}
-
-
-func isForwardDecl(typ ast.Expr) bool {
- switch t := typ.(type) {
- case *ast.StructType:
- return t.Fields == nil;
- case *ast.InterfaceType:
- return t.Methods == nil;
- }
- return false;
-}
-
-
-func (doc *docReader) addType(decl *ast.GenDecl) {
- spec := decl.Specs[0].(*ast.TypeSpec);
- name := spec.Name.Value;
if tdoc, found := doc.types[name]; found {
- if !isForwardDecl(tdoc.decl.Specs[0].(*ast.TypeSpec).Type) || isForwardDecl(spec.Type) {
- // existing type was not a forward-declaration or the
- // new type is a forward declaration - leave it alone
- return;
- }
- // replace existing type
+ return tdoc;
}
- tdoc := &typeDoc{decl, make(map[string] *ast.FuncDecl), make(map[string] *ast.FuncDecl)};
+ // type wasn't found - add one without declaration
+ tdoc := &typeDoc{nil, make(map[string] *ast.FuncDecl), make(map[string] *ast.FuncDecl)};
doc.types[name] = tdoc;
+ return tdoc;
}
@@ -102,21 +94,15 @@ func (doc *docReader) addFunc(fun *ast.FuncDecl) {
name := fun.Name.Value;
// determine if it should be associated with a type
- var typ *typeDoc;
if fun.Recv != nil {
// method
- // (all receiver types must be declared before they are used)
- // TODO(gri) Reconsider this logic if no forward-declarations
- // are required anymore.
- typ = doc.lookupTypeDoc(fun.Recv.Type);
+ typ := doc.lookupTypeDoc(baseTypeName(fun.Recv.Type));
+ // typ should always be != nil since receiver base
+ // types must be named - be conservative and check
if typ != nil {
- // type found (i.e., exported)
typ.methods[name] = fun;
+ return;
}
- // if the type wasn't found, it wasn't exported
- // TODO(gri): a non-exported type may still have exported functions
- // determine what to do in that case
- return;
}
// perhaps a factory function
@@ -125,8 +111,9 @@ func (doc *docReader) addFunc(fun *ast.FuncDecl) {
res := fun.Type.Results[0];
if len(res.Names) <= 1 {
// exactly one (named or anonymous) result type
- typ = doc.lookupTypeDoc(res.Type);
+ typ := doc.lookupTypeDoc(baseTypeName(res.Type));
if typ != nil {
+ // named result type
typ.factories[name] = fun;
return;
}
@@ -134,6 +121,7 @@ func (doc *docReader) addFunc(fun *ast.FuncDecl) {
}
// ordinary function
+ // (or method that was not associated to a type for some reason)
doc.funcs[name] = fun;
}
@@ -143,11 +131,9 @@ func (doc *docReader) addDecl(decl ast.Decl) {
case *ast.GenDecl:
if len(d.Specs) > 0 {
switch d.Tok {
- case token.IMPORT:
- // ignore
- case token.CONST:
- // constants are always handled as a group
- doc.consts.Push(d);
+ case token.CONST, token.VAR:
+ // constants and variables are always handled as a group
+ doc.values.Push(d);
case token.TYPE:
// types are handled individually
var noPos token.Position;
@@ -166,9 +152,6 @@ func (doc *docReader) addDecl(decl ast.Decl) {
doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, noPos, []ast.Spec{spec}, noPos});
// A new GenDecl node is created, no need to nil out d.Doc.
}
- case token.VAR:
- // variables are always handled as a group
- doc.vars.Push(d);
}
}
case *ast.FuncDecl:
@@ -314,13 +297,18 @@ func (p sortValueDoc) Less(i, j int) bool {
}
-func makeValueDocs(v *vector.Vector) []*ValueDoc {
- d := make([]*ValueDoc, v.Len());
+func makeValueDocs(v *vector.Vector, tok token.Token) []*ValueDoc {
+ d := make([]*ValueDoc, v.Len()); // big enough in any case
+ n := 0;
for i := range d {
decl := v.At(i).(*ast.GenDecl);
- d[i] = &ValueDoc{astComment(decl.Doc), decl, i};
- decl.Doc = nil; // doc consumed - removed from AST
+ if decl.Tok == tok {
+ d[n] = &ValueDoc{astComment(decl.Doc), decl, i};
+ n++;
+ decl.Doc = nil; // doc consumed - removed from AST
+ }
}
+ d = d[0 : n];
sort.Sort(sortValueDoc(d));
return d;
}
@@ -395,24 +383,30 @@ func makeTypeDocs(m map[string] *typeDoc) []*TypeDoc {
d := make([]*TypeDoc, len(m));
i := 0;
for _, old := range m {
- typespec := old.decl.Specs[0].(*ast.TypeSpec);
- t := new(TypeDoc);
- doc := typespec.Doc;
- typespec.Doc = nil; // doc consumed - remove from ast.TypeSpec node
- if doc == nil {
- // no doc associated with the spec, use the declaration doc, if any
- doc = old.decl.Doc;
+ // all typeDocs should have a declaration associated with
+ // them after processing an entire package - be conservative
+ // and check
+ if decl := old.decl; decl != nil {
+ typespec := decl.Specs[0].(*ast.TypeSpec);
+ t := new(TypeDoc);
+ doc := typespec.Doc;
+ typespec.Doc = nil; // doc consumed - remove from ast.TypeSpec node
+ 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.Decl node
+ t.Doc = astComment(doc);
+ t.Type = typespec;
+ t.Factories = makeFuncDocs(old.factories);
+ t.Methods = makeFuncDocs(old.methods);
+ t.Decl = old.decl;
+ t.order = i;
+ d[i] = t;
+ i++;
}
- old.decl.Doc = nil; // doc consumed - remove from ast.Decl node
- t.Doc = astComment(doc);
- t.Type = typespec;
- t.Factories = makeFuncDocs(old.factories);
- t.Methods = makeFuncDocs(old.methods);
- t.Decl = old.decl;
- t.order = i;
- d[i] = t;
- i++;
}
+ d = d[0 : i]; // some types may have been ignored
sort.Sort(sortTypeDoc(d));
return d;
}
@@ -453,8 +447,8 @@ func (doc *docReader) newDoc(pkgname, importpath, filepath string, filenames []s
sort.SortStrings(filenames);
p.Filenames = filenames;
p.Doc = astComment(doc.doc);
- p.Consts = makeValueDocs(doc.consts);
- p.Vars = makeValueDocs(doc.vars);
+ p.Consts = makeValueDocs(doc.values, token.CONST);
+ p.Vars = makeValueDocs(doc.values, token.VAR);
p.Types = makeTypeDocs(doc.types);
p.Funcs = makeFuncDocs(doc.funcs);
p.Bugs = makeBugDocs(doc.bugs);