Source file
src/go/ast/filter.go
Documentation: go/ast
1
2
3
4
5 package ast
6
7 import (
8 "go/token"
9 "sort"
10 )
11
12
13
14
15
16 func exportFilter(name string) bool {
17 return IsExported(name)
18 }
19
20
21
22
23
24
25
26
27
28 func FileExports(src *File) bool {
29 return filterFile(src, exportFilter, true)
30 }
31
32
33
34
35
36
37
38
39 func PackageExports(pkg *Package) bool {
40 return filterPackage(pkg, exportFilter, true)
41 }
42
43
44
45
46 type Filter func(string) bool
47
48 func filterIdentList(list []*Ident, f Filter) []*Ident {
49 j := 0
50 for _, x := range list {
51 if f(x.Name) {
52 list[j] = x
53 j++
54 }
55 }
56 return list[0:j]
57 }
58
59
60
61
62
63 func fieldName(x Expr) *Ident {
64 switch t := x.(type) {
65 case *Ident:
66 return t
67 case *SelectorExpr:
68 if _, ok := t.X.(*Ident); ok {
69 return t.Sel
70 }
71 case *StarExpr:
72 return fieldName(t.X)
73 }
74 return nil
75 }
76
77 func filterFieldList(fields *FieldList, filter Filter, export bool) (removedFields bool) {
78 if fields == nil {
79 return false
80 }
81 list := fields.List
82 j := 0
83 for _, f := range list {
84 keepField := false
85 if len(f.Names) == 0 {
86
87 name := fieldName(f.Type)
88 keepField = name != nil && filter(name.Name)
89 } else {
90 n := len(f.Names)
91 f.Names = filterIdentList(f.Names, filter)
92 if len(f.Names) < n {
93 removedFields = true
94 }
95 keepField = len(f.Names) > 0
96 }
97 if keepField {
98 if export {
99 filterType(f.Type, filter, export)
100 }
101 list[j] = f
102 j++
103 }
104 }
105 if j < len(list) {
106 removedFields = true
107 }
108 fields.List = list[0:j]
109 return
110 }
111
112 func filterParamList(fields *FieldList, filter Filter, export bool) bool {
113 if fields == nil {
114 return false
115 }
116 var b bool
117 for _, f := range fields.List {
118 if filterType(f.Type, filter, export) {
119 b = true
120 }
121 }
122 return b
123 }
124
125 func filterType(typ Expr, f Filter, export bool) bool {
126 switch t := typ.(type) {
127 case *Ident:
128 return f(t.Name)
129 case *ParenExpr:
130 return filterType(t.X, f, export)
131 case *ArrayType:
132 return filterType(t.Elt, f, export)
133 case *StructType:
134 if filterFieldList(t.Fields, f, export) {
135 t.Incomplete = true
136 }
137 return len(t.Fields.List) > 0
138 case *FuncType:
139 b1 := filterParamList(t.Params, f, export)
140 b2 := filterParamList(t.Results, f, export)
141 return b1 || b2
142 case *InterfaceType:
143 if filterFieldList(t.Methods, f, export) {
144 t.Incomplete = true
145 }
146 return len(t.Methods.List) > 0
147 case *MapType:
148 b1 := filterType(t.Key, f, export)
149 b2 := filterType(t.Value, f, export)
150 return b1 || b2
151 case *ChanType:
152 return filterType(t.Value, f, export)
153 }
154 return false
155 }
156
157 func filterSpec(spec Spec, f Filter, export bool) bool {
158 switch s := spec.(type) {
159 case *ValueSpec:
160 s.Names = filterIdentList(s.Names, f)
161 if len(s.Names) > 0 {
162 if export {
163 filterType(s.Type, f, export)
164 }
165 return true
166 }
167 case *TypeSpec:
168 if f(s.Name.Name) {
169 if export {
170 filterType(s.Type, f, export)
171 }
172 return true
173 }
174 if !export {
175
176
177
178
179
180 return filterType(s.Type, f, export)
181 }
182 }
183 return false
184 }
185
186 func filterSpecList(list []Spec, f Filter, export bool) []Spec {
187 j := 0
188 for _, s := range list {
189 if filterSpec(s, f, export) {
190 list[j] = s
191 j++
192 }
193 }
194 return list[0:j]
195 }
196
197
198
199
200
201
202
203
204 func FilterDecl(decl Decl, f Filter) bool {
205 return filterDecl(decl, f, false)
206 }
207
208 func filterDecl(decl Decl, f Filter, export bool) bool {
209 switch d := decl.(type) {
210 case *GenDecl:
211 d.Specs = filterSpecList(d.Specs, f, export)
212 return len(d.Specs) > 0
213 case *FuncDecl:
214 return f(d.Name.Name)
215 }
216 return false
217 }
218
219
220
221
222
223
224
225
226
227
228
229 func FilterFile(src *File, f Filter) bool {
230 return filterFile(src, f, false)
231 }
232
233 func filterFile(src *File, f Filter, export bool) bool {
234 j := 0
235 for _, d := range src.Decls {
236 if filterDecl(d, f, export) {
237 src.Decls[j] = d
238 j++
239 }
240 }
241 src.Decls = src.Decls[0:j]
242 return j > 0
243 }
244
245
246
247
248
249
250
251
252
253
254
255
256 func FilterPackage(pkg *Package, f Filter) bool {
257 return filterPackage(pkg, f, false)
258 }
259
260 func filterPackage(pkg *Package, f Filter, export bool) bool {
261 hasDecls := false
262 for _, src := range pkg.Files {
263 if filterFile(src, f, export) {
264 hasDecls = true
265 }
266 }
267 return hasDecls
268 }
269
270
271
272
273
274 type MergeMode uint
275
276 const (
277
278 FilterFuncDuplicates MergeMode = 1 << iota
279
280
281 FilterUnassociatedComments
282
283 FilterImportDuplicates
284 )
285
286
287
288
289
290 func nameOf(f *FuncDecl) string {
291 if r := f.Recv; r != nil && len(r.List) == 1 {
292
293 t := r.List[0].Type
294
295 if p, _ := t.(*StarExpr); p != nil {
296 t = p.X
297 }
298
299 if p, _ := t.(*Ident); p != nil {
300 return p.Name + "." + f.Name.Name
301 }
302
303 }
304 return f.Name.Name
305 }
306
307
308
309
310 var separator = &Comment{token.NoPos, "//"}
311
312
313
314
315 func MergePackageFiles(pkg *Package, mode MergeMode) *File {
316
317
318
319 ndocs := 0
320 ncomments := 0
321 ndecls := 0
322 filenames := make([]string, len(pkg.Files))
323 i := 0
324 for filename, f := range pkg.Files {
325 filenames[i] = filename
326 i++
327 if f.Doc != nil {
328 ndocs += len(f.Doc.List) + 1
329 }
330 ncomments += len(f.Comments)
331 ndecls += len(f.Decls)
332 }
333 sort.Strings(filenames)
334
335
336
337
338
339 var doc *CommentGroup
340 var pos token.Pos
341 if ndocs > 0 {
342 list := make([]*Comment, ndocs-1)
343 i := 0
344 for _, filename := range filenames {
345 f := pkg.Files[filename]
346 if f.Doc != nil {
347 if i > 0 {
348
349 list[i] = separator
350 i++
351 }
352 for _, c := range f.Doc.List {
353 list[i] = c
354 i++
355 }
356 if f.Package > pos {
357
358
359
360 pos = f.Package
361 }
362 }
363 }
364 doc = &CommentGroup{list}
365 }
366
367
368 var decls []Decl
369 if ndecls > 0 {
370 decls = make([]Decl, ndecls)
371 funcs := make(map[string]int)
372 i := 0
373 n := 0
374 for _, filename := range filenames {
375 f := pkg.Files[filename]
376 for _, d := range f.Decls {
377 if mode&FilterFuncDuplicates != 0 {
378
379
380
381
382
383
384
385
386
387 if f, isFun := d.(*FuncDecl); isFun {
388 name := nameOf(f)
389 if j, exists := funcs[name]; exists {
390
391 if decls[j] != nil && decls[j].(*FuncDecl).Doc == nil {
392
393
394 decls[j] = nil
395 } else {
396
397 d = nil
398 }
399 n++
400 } else {
401 funcs[name] = i
402 }
403 }
404 }
405 decls[i] = d
406 i++
407 }
408 }
409
410
411
412
413
414
415 if n > 0 {
416 i = 0
417 for _, d := range decls {
418 if d != nil {
419 decls[i] = d
420 i++
421 }
422 }
423 decls = decls[0:i]
424 }
425 }
426
427
428 var imports []*ImportSpec
429 if mode&FilterImportDuplicates != 0 {
430 seen := make(map[string]bool)
431 for _, filename := range filenames {
432 f := pkg.Files[filename]
433 for _, imp := range f.Imports {
434 if path := imp.Path.Value; !seen[path] {
435
436
437
438
439
440
441
442 imports = append(imports, imp)
443 seen[path] = true
444 }
445 }
446 }
447 } else {
448 for _, f := range pkg.Files {
449 imports = append(imports, f.Imports...)
450 }
451 }
452
453
454 var comments []*CommentGroup
455 if mode&FilterUnassociatedComments == 0 {
456 comments = make([]*CommentGroup, ncomments)
457 i := 0
458 for _, f := range pkg.Files {
459 i += copy(comments[i:], f.Comments)
460 }
461 }
462
463
464 return &File{doc, pos, NewIdent(pkg.Name), decls, pkg.Scope, imports, nil, comments}
465 }
466
View as plain text