]> Cypherpunks repositories - gostls13.git/commitdiff
go/ast, go/doc, godoc: consider struct fields and interface methods when filtering...
authorRobert Griesemer <gri@golang.org>
Tue, 10 May 2011 18:09:56 +0000 (11:09 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 10 May 2011 18:09:56 +0000 (11:09 -0700)
So far, only top-level names where considered when trimming ASTs
using a filter function. For instance, "godoc reflect Implements"
didn't show the "Implements" method of the type Interface because
the local method name was not considered (on the other hand, "top-
level" declared methods associated with types were considered).

With this CL, AST filter functions look also at struct fields
and interface methods.

R=rsc, r
CC=golang-dev
https://golang.org/cl/4518050

src/pkg/go/ast/filter.go
src/pkg/go/doc/doc.go

index 090d08d34c78325936bcef8c11e95aa12b95c0c6..97320b90ec59f4bf9ae3c1d9983bec7d76a0475c 100644 (file)
@@ -206,13 +206,43 @@ func filterIdentList(list []*Ident, f Filter) []*Ident {
 }
 
 
+func filterFieldList(list []*Field, f Filter) []*Field {
+       j := 0
+       for _, field := range list {
+               field.Names = filterIdentList(field.Names, f)
+               if len(field.Names) > 0 {
+                       list[j] = field
+                       j++
+               }
+       }
+       return list[0:j]
+}
+
+
+func filterFields(fields *FieldList, f Filter) bool {
+       if fields == nil {
+               return false
+       }
+       fields.List = filterFieldList(fields.List, f)
+       return len(fields.List) > 0
+}
+
+
 func filterSpec(spec Spec, f Filter) bool {
        switch s := spec.(type) {
        case *ValueSpec:
                s.Names = filterIdentList(s.Names, f)
                return len(s.Names) > 0
        case *TypeSpec:
-               return f(s.Name.Name)
+               if f(s.Name.Name) {
+                       return true
+               }
+               switch t := s.Type.(type) {
+               case *StructType:
+                       return filterFields(t.Fields, f)
+               case *InterfaceType:
+                       return filterFields(t.Methods, f)
+               }
        }
        return false
 }
@@ -230,7 +260,14 @@ func filterSpecList(list []Spec, f Filter) []Spec {
 }
 
 
-func filterDecl(decl Decl, f Filter) bool {
+// FilterDecl trims the AST for a Go declaration in place by removing
+// all names (including struct field and interface method names, but
+// not from parameter lists) that don't pass through the filter f.
+//
+// FilterDecl returns true if there are any declared names left after
+// filtering; it returns false otherwise.
+//
+func FilterDecl(decl Decl, f Filter) bool {
        switch d := decl.(type) {
        case *GenDecl:
                d.Specs = filterSpecList(d.Specs, f)
@@ -243,10 +280,10 @@ func filterDecl(decl Decl, f Filter) bool {
 
 
 // FilterFile trims the AST for a Go file in place by removing all
-// names from top-level declarations (but not from parameter lists
-// or inside types) that don't pass through the filter f. If the
-// declaration is empty afterwards, the declaration is removed from
-// the AST.
+// names from top-level declarations (including struct field and
+// interface method names, but not from parameter lists) that don't
+// pass through the filter f. If the declaration is empty afterwards,
+// the declaration is removed from the AST.
 // The File.comments list is not changed.
 //
 // FilterFile returns true if there are any top-level declarations
@@ -255,7 +292,7 @@ func filterDecl(decl Decl, f Filter) bool {
 func FilterFile(src *File, f Filter) bool {
        j := 0
        for _, d := range src.Decls {
-               if filterDecl(d, f) {
+               if FilterDecl(d, f) {
                        src.Decls[j] = d
                        j++
                }
@@ -266,10 +303,10 @@ func FilterFile(src *File, f Filter) bool {
 
 
 // FilterPackage trims the AST for a Go package in place by removing all
-// names from top-level declarations (but not from parameter lists
-// or inside types) that don't pass through the filter f. If the
-// declaration is empty afterwards, the declaration is removed from
-// the AST.
+// names from top-level declarations (including struct field and
+// interface method names, but not from parameter lists) that don't
+// pass through the filter f. If the declaration is empty afterwards,
+// the declaration is removed from the AST.
 // The pkg.Files list is not changed, so that file names and top-level
 // package comments don't get lost.
 //
index 29d205d391c82c076f4b45dd82099133b923599e..5b58871250cd75b0bc1c8b6afc018a91f3bb07f1 100644 (file)
@@ -569,32 +569,10 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc
 // ----------------------------------------------------------------------------
 // Filtering by name
 
-type Filter func(string) bool
-
-
-func matchDecl(d *ast.GenDecl, f Filter) bool {
-       for _, d := range d.Specs {
-               switch v := d.(type) {
-               case *ast.ValueSpec:
-                       for _, name := range v.Names {
-                               if f(name.Name) {
-                                       return true
-                               }
-                       }
-               case *ast.TypeSpec:
-                       if f(v.Name.Name) {
-                               return true
-                       }
-               }
-       }
-       return false
-}
-
-
-func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
+func filterValueDocs(a []*ValueDoc, f ast.Filter) []*ValueDoc {
        w := 0
        for _, vd := range a {
-               if matchDecl(vd.Decl, f) {
+               if ast.FilterDecl(vd.Decl, f) {
                        a[w] = vd
                        w++
                }
@@ -603,7 +581,7 @@ func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
 }
 
 
-func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
+func filterFuncDocs(a []*FuncDoc, f ast.Filter) []*FuncDoc {
        w := 0
        for _, fd := range a {
                if f(fd.Name) {
@@ -615,11 +593,11 @@ func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
 }
 
 
-func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
+func filterTypeDocs(a []*TypeDoc, f ast.Filter) []*TypeDoc {
        w := 0
        for _, td := range a {
                n := 0 // number of matches
-               if matchDecl(td.Decl, f) {
+               if ast.FilterDecl(td.Decl, f) {
                        n = 1
                } else {
                        // type name doesn't match, but we may have matching consts, vars, factories or methods
@@ -641,7 +619,7 @@ func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
 // Filter eliminates documentation for names that don't pass through the filter f.
 // TODO: Recognize "Type.Method" as a name.
 //
-func (p *PackageDoc) Filter(f Filter) {
+func (p *PackageDoc) Filter(f ast.Filter) {
        p.Consts = filterValueDocs(p.Consts, f)
        p.Vars = filterValueDocs(p.Vars, f)
        p.Types = filterTypeDocs(p.Types, f)