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