Source file
src/go/doc/exports.go
1
2
3
4
5
6
7 package doc
8
9 import (
10 "go/ast"
11 "go/token"
12 )
13
14
15
16 func filterIdentList(list []*ast.Ident) []*ast.Ident {
17 j := 0
18 for _, x := range list {
19 if token.IsExported(x.Name) {
20 list[j] = x
21 j++
22 }
23 }
24 return list[0:j]
25 }
26
27 var underscore = ast.NewIdent("_")
28
29 func filterCompositeLit(lit *ast.CompositeLit, filter Filter, export bool) {
30 n := len(lit.Elts)
31 lit.Elts = filterExprList(lit.Elts, filter, export)
32 if len(lit.Elts) < n {
33 lit.Incomplete = true
34 }
35 }
36
37 func filterExprList(list []ast.Expr, filter Filter, export bool) []ast.Expr {
38 j := 0
39 for _, exp := range list {
40 switch x := exp.(type) {
41 case *ast.CompositeLit:
42 filterCompositeLit(x, filter, export)
43 case *ast.KeyValueExpr:
44 if x, ok := x.Key.(*ast.Ident); ok && !filter(x.Name) {
45 continue
46 }
47 if x, ok := x.Value.(*ast.CompositeLit); ok {
48 filterCompositeLit(x, filter, export)
49 }
50 }
51 list[j] = exp
52 j++
53 }
54 return list[0:j]
55 }
56
57
58
59 func updateIdentList(list []*ast.Ident) (hasExported bool) {
60 for i, x := range list {
61 if token.IsExported(x.Name) {
62 hasExported = true
63 } else {
64 list[i] = underscore
65 }
66 }
67 return hasExported
68 }
69
70
71 func hasExportedName(list []*ast.Ident) bool {
72 for _, x := range list {
73 if x.IsExported() {
74 return true
75 }
76 }
77 return false
78 }
79
80
81 func removeAnonymousField(name string, ityp *ast.InterfaceType) {
82 list := ityp.Methods.List
83 j := 0
84 for _, field := range list {
85 keepField := true
86 if n := len(field.Names); n == 0 {
87
88 if fname, _ := baseTypeName(field.Type); fname == name {
89 keepField = false
90 }
91 }
92 if keepField {
93 list[j] = field
94 j++
95 }
96 }
97 if j < len(list) {
98 ityp.Incomplete = true
99 }
100 ityp.Methods.List = list[0:j]
101 }
102
103
104
105
106
107 func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp *ast.InterfaceType) (removedFields bool) {
108 if fields == nil {
109 return
110 }
111 list := fields.List
112 j := 0
113 for _, field := range list {
114 keepField := false
115 if n := len(field.Names); n == 0 {
116
117 fname := r.recordAnonymousField(parent, field.Type)
118 if fname != "" {
119 if token.IsExported(fname) {
120 keepField = true
121 } else if ityp != nil && predeclaredTypes[fname] {
122
123
124
125 keepField = true
126 r.remember(fname, ityp)
127 }
128 } else {
129
130
131
132
133
134 keepField = ityp != nil
135 }
136 } else {
137 field.Names = filterIdentList(field.Names)
138 if len(field.Names) < n {
139 removedFields = true
140 }
141 if len(field.Names) > 0 {
142 keepField = true
143 }
144 }
145 if keepField {
146 r.filterType(nil, field.Type)
147 list[j] = field
148 j++
149 }
150 }
151 if j < len(list) {
152 removedFields = true
153 }
154 fields.List = list[0:j]
155 return
156 }
157
158
159 func (r *reader) filterParamList(fields *ast.FieldList) {
160 if fields != nil {
161 for _, f := range fields.List {
162 r.filterType(nil, f.Type)
163 }
164 }
165 }
166
167
168
169
170 func (r *reader) filterType(parent *namedType, typ ast.Expr) {
171 switch t := typ.(type) {
172 case *ast.Ident:
173
174 case *ast.ParenExpr:
175 r.filterType(nil, t.X)
176 case *ast.StarExpr:
177 r.filterType(nil, t.X)
178 case *ast.UnaryExpr:
179 if t.Op == token.TILDE {
180 r.filterType(nil, t.X)
181 }
182 case *ast.BinaryExpr:
183 if t.Op == token.OR {
184 r.filterType(nil, t.X)
185 r.filterType(nil, t.Y)
186 }
187 case *ast.ArrayType:
188 r.filterType(nil, t.Elt)
189 case *ast.StructType:
190 if r.filterFieldList(parent, t.Fields, nil) {
191 t.Incomplete = true
192 }
193 case *ast.FuncType:
194 r.filterParamList(t.TypeParams)
195 r.filterParamList(t.Params)
196 r.filterParamList(t.Results)
197 case *ast.InterfaceType:
198 if r.filterFieldList(parent, t.Methods, t) {
199 t.Incomplete = true
200 }
201 case *ast.MapType:
202 r.filterType(nil, t.Key)
203 r.filterType(nil, t.Value)
204 case *ast.ChanType:
205 r.filterType(nil, t.Value)
206 }
207 }
208
209 func (r *reader) filterSpec(spec ast.Spec) bool {
210 switch s := spec.(type) {
211 case *ast.ImportSpec:
212
213 return true
214 case *ast.ValueSpec:
215 s.Values = filterExprList(s.Values, token.IsExported, true)
216 if len(s.Values) > 0 || s.Type == nil && len(s.Values) == 0 {
217
218
219
220
221
222
223 if updateIdentList(s.Names) {
224 r.filterType(nil, s.Type)
225 return true
226 }
227 } else {
228 s.Names = filterIdentList(s.Names)
229 if len(s.Names) > 0 {
230 r.filterType(nil, s.Type)
231 return true
232 }
233 }
234 case *ast.TypeSpec:
235
236
237 if name := s.Name.Name; token.IsExported(name) {
238 r.filterType(r.lookupType(s.Name.Name), s.Type)
239 return true
240 } else if IsPredeclared(name) {
241 if r.shadowedPredecl == nil {
242 r.shadowedPredecl = make(map[string]bool)
243 }
244 r.shadowedPredecl[name] = true
245 }
246 }
247 return false
248 }
249
250
251
252
253 func copyConstType(typ ast.Expr, pos token.Pos) ast.Expr {
254 switch typ := typ.(type) {
255 case *ast.Ident:
256 return &ast.Ident{Name: typ.Name, NamePos: pos}
257 case *ast.SelectorExpr:
258 if id, ok := typ.X.(*ast.Ident); ok {
259
260 return &ast.SelectorExpr{
261 Sel: ast.NewIdent(typ.Sel.Name),
262 X: &ast.Ident{Name: id.Name, NamePos: pos},
263 }
264 }
265 }
266 return nil
267 }
268
269 func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec {
270 if tok == token.CONST {
271
272
273 var prevType ast.Expr
274 for _, spec := range list {
275 spec := spec.(*ast.ValueSpec)
276 if spec.Type == nil && len(spec.Values) == 0 && prevType != nil {
277
278 spec.Type = copyConstType(prevType, spec.Pos())
279 }
280 if hasExportedName(spec.Names) {
281
282 prevType = nil
283 } else {
284 prevType = spec.Type
285 }
286 }
287 }
288
289 j := 0
290 for _, s := range list {
291 if r.filterSpec(s) {
292 list[j] = s
293 j++
294 }
295 }
296 return list[0:j]
297 }
298
299 func (r *reader) filterDecl(decl ast.Decl) bool {
300 switch d := decl.(type) {
301 case *ast.GenDecl:
302 d.Specs = r.filterSpecList(d.Specs, d.Tok)
303 return len(d.Specs) > 0
304 case *ast.FuncDecl:
305
306
307
308
309 return token.IsExported(d.Name.Name)
310 }
311 return false
312 }
313
314
315 func (r *reader) fileExports(src *ast.File) {
316 j := 0
317 for _, d := range src.Decls {
318 if r.filterDecl(d) {
319 src.Decls[j] = d
320 j++
321 }
322 }
323 src.Decls = src.Decls[0:j]
324 }
325
View as plain text