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