}
 
 
+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
 }
 }
 
 
-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)
 
 
 // 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
 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++
                }
 
 
 // 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.
 //
 
 // ----------------------------------------------------------------------------
 // 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++
                }
 }
 
 
-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) {
 }
 
 
-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
 // 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)