1
0
mirror of https://github.com/golang/go synced 2024-11-22 05:54:40 -07:00

associate const and var declarations with a type where possible

R=rsc
DELTA=105  (87 added, 7 deleted, 11 changed)
OCL=34062
CL=34119
This commit is contained in:
Robert Griesemer 2009-08-31 10:47:34 -07:00
parent c62b9d8f2a
commit 3dc7b382f9
3 changed files with 98 additions and 18 deletions

View File

@ -48,6 +48,14 @@
<h2>type <a href="{Decl|link}">{Type.Name|html}</a></h2> <h2>type <a href="{Decl|link}">{Type.Name|html}</a></h2>
{Doc|html-comment} {Doc|html-comment}
<p><pre>{Decl|html}</pre></p> <p><pre>{Decl|html}</pre></p>
{.repeated section Consts}
{Doc|html-comment}
<pre>{Decl|html}</pre>
{.end}
{.repeated section Vars}
{Doc|html-comment}
<pre>{Decl|html}</pre>
{.end}
{.repeated section Factories} {.repeated section Factories}
<h3>func <a href="{Decl|link}">{Name|html}</a></h3> <h3>func <a href="{Decl|link}">{Name|html}</a></h3>
<p><code>{Decl|html}</code></p> <p><code>{Decl|html}</code></p>

View File

@ -48,6 +48,14 @@ TYPES
{.repeated section @} {.repeated section @}
{Decl} {Decl}
{Doc} {Doc}
{.repeated section Consts}
{Decl}
{Doc}
{.end}
{.repeated section Vars}
{Decl}
{Doc}
{.end}
{.repeated section Factories} {.repeated section Factories}
{Decl} {Decl}
{Doc} {Doc}

View File

@ -22,7 +22,8 @@ type typeDoc struct {
// 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 // if the type declaration hasn't been seen yet, decl is nil
decl *ast.GenDecl; decl *ast.GenDecl;
// factory functions and methods associated with the type // values, factory functions, and methods associated with the type
values *vector.Vector; // list of *ast.GenDecl (consts and vars)
factories map[string] *ast.FuncDecl; factories map[string] *ast.FuncDecl;
methods map[string] *ast.FuncDecl; methods map[string] *ast.FuncDecl;
} }
@ -93,13 +94,13 @@ func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
return nil; // no type docs for anonymous types return nil; // no type docs for anonymous types
} }
if _, found := predeclaredTypes[name]; found { if _, found := predeclaredTypes[name]; found {
return nil; // no type docs for prdeclared types return nil; // no type docs for predeclared types
} }
if tdoc, found := doc.types[name]; found { if tdoc, found := doc.types[name]; found {
return tdoc; return tdoc;
} }
// type wasn't found - add one without declaration // type wasn't found - add one without declaration
tdoc := &typeDoc{nil, make(map[string] *ast.FuncDecl), make(map[string] *ast.FuncDecl)}; tdoc := &typeDoc{nil, vector.New(0), make(map[string] *ast.FuncDecl), make(map[string] *ast.FuncDecl)};
doc.types[name] = tdoc; doc.types[name] = tdoc;
return tdoc; return tdoc;
} }
@ -116,6 +117,64 @@ func baseTypeName(typ ast.Expr) string {
} }
func (doc *docReader) addValue(decl *ast.GenDecl) {
// determine if decl should be associated with a type
// Heuristic: Collect all types and determine the most frequent type.
// If it is "dominant enough" the decl is associated with
// that type.
// determine type frequencies
freq := make(map[string]int);
prev := "";
for _, s := range decl.Specs {
if v, ok := s.(*ast.ValueSpec); ok {
name := "";
switch {
case v.Type != nil:
// a type is present; determine it's name
name = baseTypeName(v.Type);
case decl.Tok == token.CONST:
// no type is present but we have a constant declaration;
// use the previous type name (w/o more type information
// we cannot handle the case of unnamed variables with
// initializer expressions except for some trivial cases)
name = prev;
}
if name != "" {
// increase freq count for name
f := 0;
if f0, found := freq[name]; found {
f = f0;
}
freq[name] = f+1;
}
prev = name;
}
}
// determine most common type
domName, domFreq := "", 0;
for name, f := range freq {
if f > domFreq {
domName, domFreq = name, f;
}
}
// determine values list
const threshold = 0.75;
values := doc.values;
if domFreq >= int(float(len(decl.Specs)) * threshold) {
// most common type is "dominant enough"
typ := doc.lookupTypeDoc(domName);
if typ != nil {
values = typ.values; // associate with that type
}
}
values.Push(decl);
}
func (doc *docReader) addFunc(fun *ast.FuncDecl) { func (doc *docReader) addFunc(fun *ast.FuncDecl) {
name := fun.Name.Value; name := fun.Name.Value;
@ -160,7 +219,7 @@ func (doc *docReader) addDecl(decl ast.Decl) {
switch d.Tok { switch d.Tok {
case token.CONST, token.VAR: case token.CONST, token.VAR:
// constants and variables are always handled as a group // constants and variables are always handled as a group
doc.values.Push(d); doc.addValue(d);
case token.TYPE: case token.TYPE:
// types are handled individually // types are handled individually
var noPos token.Position; var noPos token.Position;
@ -378,11 +437,14 @@ func makeFuncDocs(m map[string] *ast.FuncDecl) []*FuncDoc {
// TypeDoc is the documentation for a declared type. // TypeDoc is the documentation for a declared type.
// Consts and Vars are sorted lists of constants and variables of (mostly) that type.
// Factories is a sorted list of factory functions that return that type. // Factories is a sorted list of factory functions that return that type.
// Methods is a sorted list of method functions on that type. // Methods is a sorted list of method functions on that type.
type TypeDoc struct { type TypeDoc struct {
Doc string; Doc string;
Type *ast.TypeSpec; Type *ast.TypeSpec;
Consts []*ValueDoc;
Vars []*ValueDoc;
Factories []*FuncDoc; Factories []*FuncDoc;
Methods []*FuncDoc; Methods []*FuncDoc;
Decl *ast.GenDecl; Decl *ast.GenDecl;
@ -425,6 +487,8 @@ func (doc *docReader) makeTypeDocs(m map[string] *typeDoc) []*TypeDoc {
decl.Doc = nil; // doc consumed - remove from ast.Decl node decl.Doc = nil; // doc consumed - remove from ast.Decl node
t.Doc = astComment(doc); t.Doc = astComment(doc);
t.Type = typespec; t.Type = typespec;
t.Consts = makeValueDocs(old.values, token.CONST);
t.Vars = makeValueDocs(old.values, token.VAR);
t.Factories = makeFuncDocs(old.factories); t.Factories = makeFuncDocs(old.factories);
t.Methods = makeFuncDocs(old.methods); t.Methods = makeFuncDocs(old.methods);
t.Decl = old.decl; t.Decl = old.decl;
@ -432,21 +496,20 @@ func (doc *docReader) makeTypeDocs(m map[string] *typeDoc) []*TypeDoc {
d[i] = t; d[i] = t;
i++; i++;
} else { } else {
// no corresponding type declaration found - add any associated // no corresponding type declaration found - move any associated
// factory functions to the top-level functions lists so they // values, factory functions, and methods back to the top-level
// are not lost (this should only happen for factory methods // so that they are not lost (this should only happen if a package
// returning a type that is imported via a "." import such // file containing the explicit type declaration is missing or if
// that the type name is not a qualified identifier, or if // an unqualified type name was used after a "." import)
// the package file containing the type declaration is missing) // 1) move values
doc.values.AppendVector(old.values);
// 2) move factory functions
for name, f := range old.factories { for name, f := range old.factories {
doc.funcs[name] = f; doc.funcs[name] = f;
} }
// add any associated methods to the top-level functions // 3) move methods
// list so they are not lost, but only do it if they don't
// have the same names as existing top-level functions
// (this could happen if a package file containing the type
// declaration is missing)
for name, f := range old.methods { for name, f := range old.methods {
// don't overwrite functions with the same name
if _, found := doc.funcs[name]; !found { if _, found := doc.funcs[name]; !found {
doc.funcs[name] = f; doc.funcs[name] = f;
} }
@ -494,11 +557,12 @@ func (doc *docReader) newDoc(pkgname, importpath, filepath string, filenames []s
sort.SortStrings(filenames); sort.SortStrings(filenames);
p.Filenames = filenames; p.Filenames = filenames;
p.Doc = astComment(doc.doc); p.Doc = astComment(doc.doc);
// makeTypeDocs may extend the list of doc.values and
// doc.funcs and thus must be called before any other
// function consuming those lists
p.Types = doc.makeTypeDocs(doc.types);
p.Consts = makeValueDocs(doc.values, token.CONST); p.Consts = makeValueDocs(doc.values, token.CONST);
p.Vars = makeValueDocs(doc.values, token.VAR); p.Vars = makeValueDocs(doc.values, token.VAR);
// makeTypeDocs may extend the list of doc.funcs
// and thus should be called before makeFuncDocs
p.Types = doc.makeTypeDocs(doc.types);
p.Funcs = makeFuncDocs(doc.funcs); p.Funcs = makeFuncDocs(doc.funcs);
p.Bugs = makeBugDocs(doc.bugs); p.Bugs = makeBugDocs(doc.bugs);
return p; return p;