Source file src/pkg/go/doc/exports.go
1 // Copyright 2011 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 // This file implements export filtering of an AST.
6
7 package doc
8
9 import "go/ast"
10
11 // filterIdentList removes unexported names from list in place
12 // and returns the resulting list.
13 //
14 func filterIdentList(list []*ast.Ident) []*ast.Ident {
15 j := 0
16 for _, x := range list {
17 if ast.IsExported(x.Name) {
18 list[j] = x
19 j++
20 }
21 }
22 return list[0:j]
23 }
24
25 // removeErrorField removes anonymous fields named "error" from an interface.
26 // This is called when "error" has been determined to be a local name,
27 // not the predeclared type.
28 //
29 func removeErrorField(ityp *ast.InterfaceType) {
30 list := ityp.Methods.List // we know that ityp.Methods != nil
31 j := 0
32 for _, field := range list {
33 keepField := true
34 if n := len(field.Names); n == 0 {
35 // anonymous field
36 if fname, _ := baseTypeName(field.Type); fname == "error" {
37 keepField = false
38 }
39 }
40 if keepField {
41 list[j] = field
42 j++
43 }
44 }
45 if j < len(list) {
46 ityp.Incomplete = true
47 }
48 ityp.Methods.List = list[0:j]
49 }
50
51 // filterFieldList removes unexported fields (field names) from the field list
52 // in place and returns true if fields were removed. Anonymous fields are
53 // recorded with the parent type. filterType is called with the types of
54 // all remaining fields.
55 //
56 func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp *ast.InterfaceType) (removedFields bool) {
57 if fields == nil {
58 return
59 }
60 list := fields.List
61 j := 0
62 for _, field := range list {
63 keepField := false
64 if n := len(field.Names); n == 0 {
65 // anonymous field
66 fname := r.recordAnonymousField(parent, field.Type)
67 if ast.IsExported(fname) {
68 keepField = true
69 } else if ityp != nil && fname == "error" {
70 // possibly the predeclared error interface; keep
71 // it for now but remember this interface so that
72 // it can be fixed if error is also defined locally
73 keepField = true
74 r.remember(ityp)
75 }
76 } else {
77 field.Names = filterIdentList(field.Names)
78 if len(field.Names) < n {
79 removedFields = true
80 }
81 if len(field.Names) > 0 {
82 keepField = true
83 }
84 }
85 if keepField {
86 r.filterType(nil, field.Type)
87 list[j] = field
88 j++
89 }
90 }
91 if j < len(list) {
92 removedFields = true
93 }
94 fields.List = list[0:j]
95 return
96 }
97
98 // filterParamList applies filterType to each parameter type in fields.
99 //
100 func (r *reader) filterParamList(fields *ast.FieldList) {
101 if fields != nil {
102 for _, f := range fields.List {
103 r.filterType(nil, f.Type)
104 }
105 }
106 }
107
108 // filterType strips any unexported struct fields or method types from typ
109 // in place. If fields (or methods) have been removed, the corresponding
110 // struct or interface type has the Incomplete field set to true.
111 //
112 func (r *reader) filterType(parent *namedType, typ ast.Expr) {
113 switch t := typ.(type) {
114 case *ast.Ident:
115 // nothing to do
116 case *ast.ParenExpr:
117 r.filterType(nil, t.X)
118 case *ast.ArrayType:
119 r.filterType(nil, t.Elt)
120 case *ast.StructType:
121 if r.filterFieldList(parent, t.Fields, nil) {
122 t.Incomplete = true
123 }
124 case *ast.FuncType:
125 r.filterParamList(t.Params)
126 r.filterParamList(t.Results)
127 case *ast.InterfaceType:
128 if r.filterFieldList(parent, t.Methods, t) {
129 t.Incomplete = true
130 }
131 case *ast.MapType:
132 r.filterType(nil, t.Key)
133 r.filterType(nil, t.Value)
134 case *ast.ChanType:
135 r.filterType(nil, t.Value)
136 }
137 }
138
139 func (r *reader) filterSpec(spec ast.Spec) bool {
140 switch s := spec.(type) {
141 case *ast.ImportSpec:
142 // always keep imports so we can collect them
143 return true
144 case *ast.ValueSpec:
145 s.Names = filterIdentList(s.Names)
146 if len(s.Names) > 0 {
147 r.filterType(nil, s.Type)
148 return true
149 }
150 case *ast.TypeSpec:
151 if name := s.Name.Name; ast.IsExported(name) {
152 r.filterType(r.lookupType(s.Name.Name), s.Type)
153 return true
154 } else if name == "error" {
155 // special case: remember that error is declared locally
156 r.errorDecl = true
157 }
158 }
159 return false
160 }
161
162 func (r *reader) filterSpecList(list []ast.Spec) []ast.Spec {
163 j := 0
164 for _, s := range list {
165 if r.filterSpec(s) {
166 list[j] = s
167 j++
168 }
169 }
170 return list[0:j]
171 }
172
173 func (r *reader) filterDecl(decl ast.Decl) bool {
174 switch d := decl.(type) {
175 case *ast.GenDecl:
176 d.Specs = r.filterSpecList(d.Specs)
177 return len(d.Specs) > 0
178 case *ast.FuncDecl:
179 // ok to filter these methods early because any
180 // conflicting method will be filtered here, too -
181 // thus, removing these methods early will not lead
182 // to the false removal of possible conflicts
183 return ast.IsExported(d.Name.Name)
184 }
185 return false
186 }
187
188 // fileExports removes unexported declarations from src in place.
189 //
190 func (r *reader) fileExports(src *ast.File) {
191 j := 0
192 for _, d := range src.Decls {
193 if r.filterDecl(d) {
194 src.Decls[j] = d
195 j++
196 }
197 }
198 src.Decls = src.Decls[0:j]
199 }