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// +build go1.16
6
7package doc
8
9import "go/ast"
10
11type Filter func(string) bool
12
13func matchFields(fields *ast.FieldList, f Filter) bool {
14	if fields != nil {
15		for _, field := range fields.List {
16			for _, name := range field.Names {
17				if f(name.Name) {
18					return true
19				}
20			}
21		}
22	}
23	return false
24}
25
26func matchDecl(d *ast.GenDecl, f Filter) bool {
27	for _, d := range d.Specs {
28		switch v := d.(type) {
29		case *ast.ValueSpec:
30			for _, name := range v.Names {
31				if f(name.Name) {
32					return true
33				}
34			}
35		case *ast.TypeSpec:
36			if f(v.Name.Name) {
37				return true
38			}
39			switch t := v.Type.(type) {
40			case *ast.StructType:
41				if matchFields(t.Fields, f) {
42					return true
43				}
44			case *ast.InterfaceType:
45				if matchFields(t.Methods, f) {
46					return true
47				}
48			}
49		}
50	}
51	return false
52}
53
54func filterValues(a []*Value, f Filter) []*Value {
55	w := 0
56	for _, vd := range a {
57		if matchDecl(vd.Decl, f) {
58			a[w] = vd
59			w++
60		}
61	}
62	return a[0:w]
63}
64
65func filterFuncs(a []*Func, f Filter) []*Func {
66	w := 0
67	for _, fd := range a {
68		if f(fd.Name) {
69			a[w] = fd
70			w++
71		}
72	}
73	return a[0:w]
74}
75
76func filterTypes(a []*Type, f Filter) []*Type {
77	w := 0
78	for _, td := range a {
79		n := 0 // number of matches
80		if matchDecl(td.Decl, f) {
81			n = 1
82		} else {
83			// type name doesn't match, but we may have matching consts, vars, factories or methods
84			td.Consts = filterValues(td.Consts, f)
85			td.Vars = filterValues(td.Vars, f)
86			td.Funcs = filterFuncs(td.Funcs, f)
87			td.Methods = filterFuncs(td.Methods, f)
88			n += len(td.Consts) + len(td.Vars) + len(td.Funcs) + len(td.Methods)
89		}
90		if n > 0 {
91			a[w] = td
92			w++
93		}
94	}
95	return a[0:w]
96}
97
98// Filter eliminates documentation for names that don't pass through the filter f.
99// TODO(gri): Recognize "Type.Method" as a name.
100//
101func (p *Package) Filter(f Filter) {
102	p.Consts = filterValues(p.Consts, f)
103	p.Vars = filterValues(p.Vars, f)
104	p.Types = filterTypes(p.Types, f)
105	p.Funcs = filterFuncs(p.Funcs, f)
106	p.Doc = "" // don't show top-level package doc
107}
108