From 0389051aac628de7a5a93fb2a7e107bb2daba9b0 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 10 May 2011 11:09:56 -0700 Subject: [PATCH] go/ast, go/doc, godoc: consider struct fields and interface methods when filtering ASTs 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 | 59 ++++++++++++++++++++++++++++++++-------- src/pkg/go/doc/doc.go | 34 ++++------------------- 2 files changed, 54 insertions(+), 39 deletions(-) diff --git a/src/pkg/go/ast/filter.go b/src/pkg/go/ast/filter.go index 090d08d34c..97320b90ec 100644 --- a/src/pkg/go/ast/filter.go +++ b/src/pkg/go/ast/filter.go @@ -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. // diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go index 29d205d391..5b58871250 100644 --- a/src/pkg/go/doc/doc.go +++ b/src/pkg/go/doc/doc.go @@ -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) -- 2.50.0