~john-koepi/ubuntu/trusty/golang/default

« back to all changes in this revision

Viewing changes to src/pkg/go/doc/doc.go

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-04-20 17:36:48 UTC
  • Revision ID: james.westby@ubuntu.com-20110420173648-ifergoxyrm832trd
Tags: upstream-2011.03.07.1
Import upstream version 2011.03.07.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2009 The Go Authors. All rights reserved.
 
2
// Use of this source code is governed by a BSD-style
 
3
// license that can be found in the LICENSE file.
 
4
 
 
5
// The doc package extracts source code documentation from a Go AST.
 
6
package doc
 
7
 
 
8
import (
 
9
        "go/ast"
 
10
        "go/token"
 
11
        "regexp"
 
12
        "sort"
 
13
)
 
14
 
 
15
 
 
16
// ----------------------------------------------------------------------------
 
17
 
 
18
type typeDoc struct {
 
19
        // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
 
20
        // if the type declaration hasn't been seen yet, decl is nil
 
21
        decl *ast.GenDecl
 
22
        // values, factory functions, and methods associated with the type
 
23
        values    []*ast.GenDecl // consts and vars
 
24
        factories map[string]*ast.FuncDecl
 
25
        methods   map[string]*ast.FuncDecl
 
26
}
 
27
 
 
28
 
 
29
// docReader accumulates documentation for a single package.
 
30
// It modifies the AST: Comments (declaration documentation)
 
31
// that have been collected by the DocReader are set to nil
 
32
// in the respective AST nodes so that they are not printed
 
33
// twice (once when printing the documentation and once when
 
34
// printing the corresponding AST node).
 
35
//
 
36
type docReader struct {
 
37
        doc     *ast.CommentGroup // package documentation, if any
 
38
        pkgName string
 
39
        values  []*ast.GenDecl // consts and vars
 
40
        types   map[string]*typeDoc
 
41
        funcs   map[string]*ast.FuncDecl
 
42
        bugs    []*ast.CommentGroup
 
43
}
 
44
 
 
45
 
 
46
func (doc *docReader) init(pkgName string) {
 
47
        doc.pkgName = pkgName
 
48
        doc.types = make(map[string]*typeDoc)
 
49
        doc.funcs = make(map[string]*ast.FuncDecl)
 
50
}
 
51
 
 
52
 
 
53
func (doc *docReader) addDoc(comments *ast.CommentGroup) {
 
54
        if doc.doc == nil {
 
55
                // common case: just one package comment
 
56
                doc.doc = comments
 
57
                return
 
58
        }
 
59
 
 
60
        // More than one package comment: Usually there will be only
 
61
        // one file with a package comment, but it's better to collect
 
62
        // all comments than drop them on the floor.
 
63
        // (This code isn't particularly clever - no amortized doubling is
 
64
        // used - but this situation occurs rarely and is not time-critical.)
 
65
        n1 := len(doc.doc.List)
 
66
        n2 := len(comments.List)
 
67
        list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line
 
68
        copy(list, doc.doc.List)
 
69
        list[n1] = &ast.Comment{token.NoPos, []byte("//")} // separator line
 
70
        copy(list[n1+1:], comments.List)
 
71
        doc.doc = &ast.CommentGroup{list}
 
72
}
 
73
 
 
74
 
 
75
func (doc *docReader) addType(decl *ast.GenDecl) {
 
76
        spec := decl.Specs[0].(*ast.TypeSpec)
 
77
        typ := doc.lookupTypeDoc(spec.Name.Name)
 
78
        // typ should always be != nil since declared types
 
79
        // are always named - be conservative and check
 
80
        if typ != nil {
 
81
                // a type should be added at most once, so typ.decl
 
82
                // should be nil - if it isn't, simply overwrite it
 
83
                typ.decl = decl
 
84
        }
 
85
}
 
86
 
 
87
 
 
88
func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
 
89
        if name == "" {
 
90
                return nil // no type docs for anonymous types
 
91
        }
 
92
        if tdoc, found := doc.types[name]; found {
 
93
                return tdoc
 
94
        }
 
95
        // type wasn't found - add one without declaration
 
96
        tdoc := &typeDoc{nil, nil, make(map[string]*ast.FuncDecl), make(map[string]*ast.FuncDecl)}
 
97
        doc.types[name] = tdoc
 
98
        return tdoc
 
99
}
 
100
 
 
101
 
 
102
func baseTypeName(typ ast.Expr) string {
 
103
        switch t := typ.(type) {
 
104
        case *ast.Ident:
 
105
                // if the type is not exported, the effect to
 
106
                // a client is as if there were no type name
 
107
                if t.IsExported() {
 
108
                        return string(t.Name)
 
109
                }
 
110
        case *ast.StarExpr:
 
111
                return baseTypeName(t.X)
 
112
        }
 
113
        return ""
 
114
}
 
115
 
 
116
 
 
117
func (doc *docReader) addValue(decl *ast.GenDecl) {
 
118
        // determine if decl should be associated with a type
 
119
        // Heuristic: For each typed entry, determine the type name, if any.
 
120
        //            If there is exactly one type name that is sufficiently
 
121
        //            frequent, associate the decl with the respective type.
 
122
        domName := ""
 
123
        domFreq := 0
 
124
        prev := ""
 
125
        for _, s := range decl.Specs {
 
126
                if v, ok := s.(*ast.ValueSpec); ok {
 
127
                        name := ""
 
128
                        switch {
 
129
                        case v.Type != nil:
 
130
                                // a type is present; determine its name
 
131
                                name = baseTypeName(v.Type)
 
132
                        case decl.Tok == token.CONST:
 
133
                                // no type is present but we have a constant declaration;
 
134
                                // use the previous type name (w/o more type information
 
135
                                // we cannot handle the case of unnamed variables with
 
136
                                // initializer expressions except for some trivial cases)
 
137
                                name = prev
 
138
                        }
 
139
                        if name != "" {
 
140
                                // entry has a named type
 
141
                                if domName != "" && domName != name {
 
142
                                        // more than one type name - do not associate
 
143
                                        // with any type
 
144
                                        domName = ""
 
145
                                        break
 
146
                                }
 
147
                                domName = name
 
148
                                domFreq++
 
149
                        }
 
150
                        prev = name
 
151
                }
 
152
        }
 
153
 
 
154
        // determine values list
 
155
        const threshold = 0.75
 
156
        values := &doc.values
 
157
        if domName != "" && domFreq >= int(float64(len(decl.Specs))*threshold) {
 
158
                // typed entries are sufficiently frequent
 
159
                typ := doc.lookupTypeDoc(domName)
 
160
                if typ != nil {
 
161
                        values = &typ.values // associate with that type
 
162
                }
 
163
        }
 
164
 
 
165
        *values = append(*values, decl)
 
166
}
 
167
 
 
168
 
 
169
// Helper function to set the table entry for function f. Makes sure that
 
170
// at least one f with associated documentation is stored in table, if there
 
171
// are multiple f's with the same name.
 
172
func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
 
173
        name := f.Name.Name
 
174
        if g, exists := table[name]; exists && g.Doc != nil {
 
175
                // a function with the same name has already been registered;
 
176
                // since it has documentation, assume f is simply another
 
177
                // implementation and ignore it
 
178
                // TODO(gri) consider collecting all functions, or at least
 
179
                //           all comments
 
180
                return
 
181
        }
 
182
        // function doesn't exist or has no documentation; use f
 
183
        table[name] = f
 
184
}
 
185
 
 
186
 
 
187
func (doc *docReader) addFunc(fun *ast.FuncDecl) {
 
188
        name := fun.Name.Name
 
189
 
 
190
        // determine if it should be associated with a type
 
191
        if fun.Recv != nil {
 
192
                // method
 
193
                typ := doc.lookupTypeDoc(baseTypeName(fun.Recv.List[0].Type))
 
194
                if typ != nil {
 
195
                        // exported receiver type
 
196
                        setFunc(typ.methods, fun)
 
197
                }
 
198
                // otherwise don't show the method
 
199
                // TODO(gri): There may be exported methods of non-exported types
 
200
                // that can be called because of exported values (consts, vars, or
 
201
                // function results) of that type. Could determine if that is the
 
202
                // case and then show those methods in an appropriate section.
 
203
                return
 
204
        }
 
205
 
 
206
        // perhaps a factory function
 
207
        // determine result type, if any
 
208
        if fun.Type.Results.NumFields() >= 1 {
 
209
                res := fun.Type.Results.List[0]
 
210
                if len(res.Names) <= 1 {
 
211
                        // exactly one (named or anonymous) result associated
 
212
                        // with the first type in result signature (there may
 
213
                        // be more than one result)
 
214
                        tname := baseTypeName(res.Type)
 
215
                        typ := doc.lookupTypeDoc(tname)
 
216
                        if typ != nil {
 
217
                                // named and exported result type
 
218
 
 
219
                                // Work-around for failure of heuristic: In package os
 
220
                                // too many functions are considered factory functions
 
221
                                // for the Error type. Eliminate manually for now as
 
222
                                // this appears to be the only important case in the
 
223
                                // current library where the heuristic fails.
 
224
                                if doc.pkgName == "os" && tname == "Error" &&
 
225
                                        name != "NewError" && name != "NewSyscallError" {
 
226
                                        // not a factory function for os.Error
 
227
                                        setFunc(doc.funcs, fun) // treat as ordinary function
 
228
                                        return
 
229
                                }
 
230
 
 
231
                                setFunc(typ.factories, fun)
 
232
                                return
 
233
                        }
 
234
                }
 
235
        }
 
236
 
 
237
        // ordinary function
 
238
        setFunc(doc.funcs, fun)
 
239
}
 
240
 
 
241
 
 
242
func (doc *docReader) addDecl(decl ast.Decl) {
 
243
        switch d := decl.(type) {
 
244
        case *ast.GenDecl:
 
245
                if len(d.Specs) > 0 {
 
246
                        switch d.Tok {
 
247
                        case token.CONST, token.VAR:
 
248
                                // constants and variables are always handled as a group
 
249
                                doc.addValue(d)
 
250
                        case token.TYPE:
 
251
                                // types are handled individually
 
252
                                for _, spec := range d.Specs {
 
253
                                        // make a (fake) GenDecl node for this TypeSpec
 
254
                                        // (we need to do this here - as opposed to just
 
255
                                        // for printing - so we don't lose the GenDecl
 
256
                                        // documentation)
 
257
                                        //
 
258
                                        // TODO(gri): Consider just collecting the TypeSpec
 
259
                                        // node (and copy in the GenDecl.doc if there is no
 
260
                                        // doc in the TypeSpec - this is currently done in
 
261
                                        // makeTypeDocs below). Simpler data structures, but
 
262
                                        // would lose GenDecl documentation if the TypeSpec
 
263
                                        // has documentation as well.
 
264
                                        doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, token.NoPos, []ast.Spec{spec}, token.NoPos})
 
265
                                        // A new GenDecl node is created, no need to nil out d.Doc.
 
266
                                }
 
267
                        }
 
268
                }
 
269
        case *ast.FuncDecl:
 
270
                doc.addFunc(d)
 
271
        }
 
272
}
 
273
 
 
274
 
 
275
func copyCommentList(list []*ast.Comment) []*ast.Comment {
 
276
        return append([]*ast.Comment(nil), list...)
 
277
}
 
278
 
 
279
var (
 
280
        bug_markers = regexp.MustCompile("^/[/*][ \t]*BUG\\(.*\\):[ \t]*") // BUG(uid):
 
281
        bug_content = regexp.MustCompile("[^ \n\r\t]+")                    // at least one non-whitespace char
 
282
)
 
283
 
 
284
 
 
285
// addFile adds the AST for a source file to the docReader.
 
286
// Adding the same AST multiple times is a no-op.
 
287
//
 
288
func (doc *docReader) addFile(src *ast.File) {
 
289
        // add package documentation
 
290
        if src.Doc != nil {
 
291
                doc.addDoc(src.Doc)
 
292
                src.Doc = nil // doc consumed - remove from ast.File node
 
293
        }
 
294
 
 
295
        // add all declarations
 
296
        for _, decl := range src.Decls {
 
297
                doc.addDecl(decl)
 
298
        }
 
299
 
 
300
        // collect BUG(...) comments
 
301
        for _, c := range src.Comments {
 
302
                text := c.List[0].Text
 
303
                if m := bug_markers.FindIndex(text); m != nil {
 
304
                        // found a BUG comment; maybe empty
 
305
                        if btxt := text[m[1]:]; bug_content.Match(btxt) {
 
306
                                // non-empty BUG comment; collect comment without BUG prefix
 
307
                                list := copyCommentList(c.List)
 
308
                                list[0].Text = text[m[1]:]
 
309
                                doc.bugs = append(doc.bugs, &ast.CommentGroup{list})
 
310
                        }
 
311
                }
 
312
        }
 
313
        src.Comments = nil // consumed unassociated comments - remove from ast.File node
 
314
}
 
315
 
 
316
 
 
317
func NewFileDoc(file *ast.File) *PackageDoc {
 
318
        var r docReader
 
319
        r.init(file.Name.Name)
 
320
        r.addFile(file)
 
321
        return r.newDoc("", nil)
 
322
}
 
323
 
 
324
 
 
325
func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
 
326
        var r docReader
 
327
        r.init(pkg.Name)
 
328
        filenames := make([]string, len(pkg.Files))
 
329
        i := 0
 
330
        for filename, f := range pkg.Files {
 
331
                r.addFile(f)
 
332
                filenames[i] = filename
 
333
                i++
 
334
        }
 
335
        return r.newDoc(importpath, filenames)
 
336
}
 
337
 
 
338
 
 
339
// ----------------------------------------------------------------------------
 
340
// Conversion to external representation
 
341
 
 
342
// ValueDoc is the documentation for a group of declared
 
343
// values, either vars or consts.
 
344
//
 
345
type ValueDoc struct {
 
346
        Doc   string
 
347
        Decl  *ast.GenDecl
 
348
        order int
 
349
}
 
350
 
 
351
type sortValueDoc []*ValueDoc
 
352
 
 
353
func (p sortValueDoc) Len() int      { return len(p) }
 
354
func (p sortValueDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
 
355
 
 
356
 
 
357
func declName(d *ast.GenDecl) string {
 
358
        if len(d.Specs) != 1 {
 
359
                return ""
 
360
        }
 
361
 
 
362
        switch v := d.Specs[0].(type) {
 
363
        case *ast.ValueSpec:
 
364
                return v.Names[0].Name
 
365
        case *ast.TypeSpec:
 
366
                return v.Name.Name
 
367
        }
 
368
 
 
369
        return ""
 
370
}
 
371
 
 
372
 
 
373
func (p sortValueDoc) Less(i, j int) bool {
 
374
        // sort by name
 
375
        // pull blocks (name = "") up to top
 
376
        // in original order
 
377
        if ni, nj := declName(p[i].Decl), declName(p[j].Decl); ni != nj {
 
378
                return ni < nj
 
379
        }
 
380
        return p[i].order < p[j].order
 
381
}
 
382
 
 
383
 
 
384
func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
 
385
        d := make([]*ValueDoc, len(list)) // big enough in any case
 
386
        n := 0
 
387
        for i, decl := range list {
 
388
                if decl.Tok == tok {
 
389
                        d[n] = &ValueDoc{CommentText(decl.Doc), decl, i}
 
390
                        n++
 
391
                        decl.Doc = nil // doc consumed - removed from AST
 
392
                }
 
393
        }
 
394
        d = d[0:n]
 
395
        sort.Sort(sortValueDoc(d))
 
396
        return d
 
397
}
 
398
 
 
399
 
 
400
// FuncDoc is the documentation for a func declaration,
 
401
// either a top-level function or a method function.
 
402
//
 
403
type FuncDoc struct {
 
404
        Doc  string
 
405
        Recv ast.Expr // TODO(rsc): Would like string here
 
406
        Name string
 
407
        Decl *ast.FuncDecl
 
408
}
 
409
 
 
410
type sortFuncDoc []*FuncDoc
 
411
 
 
412
func (p sortFuncDoc) Len() int           { return len(p) }
 
413
func (p sortFuncDoc) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 
414
func (p sortFuncDoc) Less(i, j int) bool { return p[i].Name < p[j].Name }
 
415
 
 
416
 
 
417
func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
 
418
        d := make([]*FuncDoc, len(m))
 
419
        i := 0
 
420
        for _, f := range m {
 
421
                doc := new(FuncDoc)
 
422
                doc.Doc = CommentText(f.Doc)
 
423
                f.Doc = nil // doc consumed - remove from ast.FuncDecl node
 
424
                if f.Recv != nil {
 
425
                        doc.Recv = f.Recv.List[0].Type
 
426
                }
 
427
                doc.Name = f.Name.Name
 
428
                doc.Decl = f
 
429
                d[i] = doc
 
430
                i++
 
431
        }
 
432
        sort.Sort(sortFuncDoc(d))
 
433
        return d
 
434
}
 
435
 
 
436
 
 
437
// TypeDoc is the documentation for a declared type.
 
438
// Consts and Vars are sorted lists of constants and variables of (mostly) that type.
 
439
// Factories is a sorted list of factory functions that return that type.
 
440
// Methods is a sorted list of method functions on that type.
 
441
type TypeDoc struct {
 
442
        Doc       string
 
443
        Type      *ast.TypeSpec
 
444
        Consts    []*ValueDoc
 
445
        Vars      []*ValueDoc
 
446
        Factories []*FuncDoc
 
447
        Methods   []*FuncDoc
 
448
        Decl      *ast.GenDecl
 
449
        order     int
 
450
}
 
451
 
 
452
type sortTypeDoc []*TypeDoc
 
453
 
 
454
func (p sortTypeDoc) Len() int      { return len(p) }
 
455
func (p sortTypeDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
 
456
func (p sortTypeDoc) Less(i, j int) bool {
 
457
        // sort by name
 
458
        // pull blocks (name = "") up to top
 
459
        // in original order
 
460
        if ni, nj := p[i].Type.Name.Name, p[j].Type.Name.Name; ni != nj {
 
461
                return ni < nj
 
462
        }
 
463
        return p[i].order < p[j].order
 
464
}
 
465
 
 
466
 
 
467
// NOTE(rsc): This would appear not to be correct for type ( )
 
468
// blocks, but the doc extractor above has split them into
 
469
// individual declarations.
 
470
func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
 
471
        d := make([]*TypeDoc, len(m))
 
472
        i := 0
 
473
        for _, old := range m {
 
474
                // all typeDocs should have a declaration associated with
 
475
                // them after processing an entire package - be conservative
 
476
                // and check
 
477
                if decl := old.decl; decl != nil {
 
478
                        typespec := decl.Specs[0].(*ast.TypeSpec)
 
479
                        t := new(TypeDoc)
 
480
                        doc := typespec.Doc
 
481
                        typespec.Doc = nil // doc consumed - remove from ast.TypeSpec node
 
482
                        if doc == nil {
 
483
                                // no doc associated with the spec, use the declaration doc, if any
 
484
                                doc = decl.Doc
 
485
                        }
 
486
                        decl.Doc = nil // doc consumed - remove from ast.Decl node
 
487
                        t.Doc = CommentText(doc)
 
488
                        t.Type = typespec
 
489
                        t.Consts = makeValueDocs(old.values, token.CONST)
 
490
                        t.Vars = makeValueDocs(old.values, token.VAR)
 
491
                        t.Factories = makeFuncDocs(old.factories)
 
492
                        t.Methods = makeFuncDocs(old.methods)
 
493
                        t.Decl = old.decl
 
494
                        t.order = i
 
495
                        d[i] = t
 
496
                        i++
 
497
                } else {
 
498
                        // no corresponding type declaration found - move any associated
 
499
                        // values, factory functions, and methods back to the top-level
 
500
                        // so that they are not lost (this should only happen if a package
 
501
                        // file containing the explicit type declaration is missing or if
 
502
                        // an unqualified type name was used after a "." import)
 
503
                        // 1) move values
 
504
                        doc.values = append(doc.values, old.values...)
 
505
                        // 2) move factory functions
 
506
                        for name, f := range old.factories {
 
507
                                doc.funcs[name] = f
 
508
                        }
 
509
                        // 3) move methods
 
510
                        for name, f := range old.methods {
 
511
                                // don't overwrite functions with the same name
 
512
                                if _, found := doc.funcs[name]; !found {
 
513
                                        doc.funcs[name] = f
 
514
                                }
 
515
                        }
 
516
                }
 
517
        }
 
518
        d = d[0:i] // some types may have been ignored
 
519
        sort.Sort(sortTypeDoc(d))
 
520
        return d
 
521
}
 
522
 
 
523
 
 
524
func makeBugDocs(list []*ast.CommentGroup) []string {
 
525
        d := make([]string, len(list))
 
526
        for i, g := range list {
 
527
                d[i] = CommentText(g)
 
528
        }
 
529
        return d
 
530
}
 
531
 
 
532
 
 
533
// PackageDoc is the documentation for an entire package.
 
534
//
 
535
type PackageDoc struct {
 
536
        PackageName string
 
537
        ImportPath  string
 
538
        Filenames   []string
 
539
        Doc         string
 
540
        Consts      []*ValueDoc
 
541
        Types       []*TypeDoc
 
542
        Vars        []*ValueDoc
 
543
        Funcs       []*FuncDoc
 
544
        Bugs        []string
 
545
}
 
546
 
 
547
 
 
548
// newDoc returns the accumulated documentation for the package.
 
549
//
 
550
func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc {
 
551
        p := new(PackageDoc)
 
552
        p.PackageName = doc.pkgName
 
553
        p.ImportPath = importpath
 
554
        sort.SortStrings(filenames)
 
555
        p.Filenames = filenames
 
556
        p.Doc = CommentText(doc.doc)
 
557
        // makeTypeDocs may extend the list of doc.values and
 
558
        // doc.funcs and thus must be called before any other
 
559
        // function consuming those lists
 
560
        p.Types = doc.makeTypeDocs(doc.types)
 
561
        p.Consts = makeValueDocs(doc.values, token.CONST)
 
562
        p.Vars = makeValueDocs(doc.values, token.VAR)
 
563
        p.Funcs = makeFuncDocs(doc.funcs)
 
564
        p.Bugs = makeBugDocs(doc.bugs)
 
565
        return p
 
566
}
 
567
 
 
568
 
 
569
// ----------------------------------------------------------------------------
 
570
// Filtering by name
 
571
 
 
572
type Filter func(string) bool
 
573
 
 
574
 
 
575
func matchDecl(d *ast.GenDecl, f Filter) bool {
 
576
        for _, d := range d.Specs {
 
577
                switch v := d.(type) {
 
578
                case *ast.ValueSpec:
 
579
                        for _, name := range v.Names {
 
580
                                if f(name.Name) {
 
581
                                        return true
 
582
                                }
 
583
                        }
 
584
                case *ast.TypeSpec:
 
585
                        if f(v.Name.Name) {
 
586
                                return true
 
587
                        }
 
588
                }
 
589
        }
 
590
        return false
 
591
}
 
592
 
 
593
 
 
594
func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
 
595
        w := 0
 
596
        for _, vd := range a {
 
597
                if matchDecl(vd.Decl, f) {
 
598
                        a[w] = vd
 
599
                        w++
 
600
                }
 
601
        }
 
602
        return a[0:w]
 
603
}
 
604
 
 
605
 
 
606
func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
 
607
        w := 0
 
608
        for _, fd := range a {
 
609
                if f(fd.Name) {
 
610
                        a[w] = fd
 
611
                        w++
 
612
                }
 
613
        }
 
614
        return a[0:w]
 
615
}
 
616
 
 
617
 
 
618
func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
 
619
        w := 0
 
620
        for _, td := range a {
 
621
                n := 0 // number of matches
 
622
                if matchDecl(td.Decl, f) {
 
623
                        n = 1
 
624
                } else {
 
625
                        // type name doesn't match, but we may have matching consts, vars, factories or methods
 
626
                        td.Consts = filterValueDocs(td.Consts, f)
 
627
                        td.Vars = filterValueDocs(td.Vars, f)
 
628
                        td.Factories = filterFuncDocs(td.Factories, f)
 
629
                        td.Methods = filterFuncDocs(td.Methods, f)
 
630
                        n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
 
631
                }
 
632
                if n > 0 {
 
633
                        a[w] = td
 
634
                        w++
 
635
                }
 
636
        }
 
637
        return a[0:w]
 
638
}
 
639
 
 
640
 
 
641
// Filter eliminates documentation for names that don't pass through the filter f.
 
642
// TODO: Recognize "Type.Method" as a name.
 
643
//
 
644
func (p *PackageDoc) Filter(f Filter) {
 
645
        p.Consts = filterValueDocs(p.Consts, f)
 
646
        p.Vars = filterValueDocs(p.Vars, f)
 
647
        p.Types = filterTypeDocs(p.Types, f)
 
648
        p.Funcs = filterFuncDocs(p.Funcs, f)
 
649
        p.Doc = "" // don't show top-level package doc
 
650
}