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