LWG 3035. std::allocator's constructors should be constexpr
[official-gcc.git] / libgo / go / go / doc / exports.go
blob40cbb22797e06081ef81f599393092eaaedadf3c
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.
5 // This file implements export filtering of an AST.
7 package doc
9 import (
10 "go/ast"
11 "go/token"
14 // filterIdentList removes unexported names from list in place
15 // and returns the resulting list.
17 func filterIdentList(list []*ast.Ident) []*ast.Ident {
18 j := 0
19 for _, x := range list {
20 if ast.IsExported(x.Name) {
21 list[j] = x
22 j++
25 return list[0:j]
28 // hasExportedName reports whether list contains any exported names.
30 func hasExportedName(list []*ast.Ident) bool {
31 for _, x := range list {
32 if x.IsExported() {
33 return true
36 return false
39 // removeErrorField removes anonymous fields named "error" from an interface.
40 // This is called when "error" has been determined to be a local name,
41 // not the predeclared type.
43 func removeErrorField(ityp *ast.InterfaceType) {
44 list := ityp.Methods.List // we know that ityp.Methods != nil
45 j := 0
46 for _, field := range list {
47 keepField := true
48 if n := len(field.Names); n == 0 {
49 // anonymous field
50 if fname, _ := baseTypeName(field.Type); fname == "error" {
51 keepField = false
54 if keepField {
55 list[j] = field
56 j++
59 if j < len(list) {
60 ityp.Incomplete = true
62 ityp.Methods.List = list[0:j]
65 // filterFieldList removes unexported fields (field names) from the field list
66 // in place and reports whether fields were removed. Anonymous fields are
67 // recorded with the parent type. filterType is called with the types of
68 // all remaining fields.
70 func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp *ast.InterfaceType) (removedFields bool) {
71 if fields == nil {
72 return
74 list := fields.List
75 j := 0
76 for _, field := range list {
77 keepField := false
78 if n := len(field.Names); n == 0 {
79 // anonymous field
80 fname := r.recordAnonymousField(parent, field.Type)
81 if ast.IsExported(fname) {
82 keepField = true
83 } else if ityp != nil && fname == "error" {
84 // possibly the predeclared error interface; keep
85 // it for now but remember this interface so that
86 // it can be fixed if error is also defined locally
87 keepField = true
88 r.remember(ityp)
90 } else {
91 field.Names = filterIdentList(field.Names)
92 if len(field.Names) < n {
93 removedFields = true
95 if len(field.Names) > 0 {
96 keepField = true
99 if keepField {
100 r.filterType(nil, field.Type)
101 list[j] = field
105 if j < len(list) {
106 removedFields = true
108 fields.List = list[0:j]
109 return
112 // filterParamList applies filterType to each parameter type in fields.
114 func (r *reader) filterParamList(fields *ast.FieldList) {
115 if fields != nil {
116 for _, f := range fields.List {
117 r.filterType(nil, f.Type)
122 // filterType strips any unexported struct fields or method types from typ
123 // in place. If fields (or methods) have been removed, the corresponding
124 // struct or interface type has the Incomplete field set to true.
126 func (r *reader) filterType(parent *namedType, typ ast.Expr) {
127 switch t := typ.(type) {
128 case *ast.Ident:
129 // nothing to do
130 case *ast.ParenExpr:
131 r.filterType(nil, t.X)
132 case *ast.ArrayType:
133 r.filterType(nil, t.Elt)
134 case *ast.StructType:
135 if r.filterFieldList(parent, t.Fields, nil) {
136 t.Incomplete = true
138 case *ast.FuncType:
139 r.filterParamList(t.Params)
140 r.filterParamList(t.Results)
141 case *ast.InterfaceType:
142 if r.filterFieldList(parent, t.Methods, t) {
143 t.Incomplete = true
145 case *ast.MapType:
146 r.filterType(nil, t.Key)
147 r.filterType(nil, t.Value)
148 case *ast.ChanType:
149 r.filterType(nil, t.Value)
153 func (r *reader) filterSpec(spec ast.Spec) bool {
154 switch s := spec.(type) {
155 case *ast.ImportSpec:
156 // always keep imports so we can collect them
157 return true
158 case *ast.ValueSpec:
159 s.Names = filterIdentList(s.Names)
160 if len(s.Names) > 0 {
161 r.filterType(nil, s.Type)
162 return true
164 case *ast.TypeSpec:
165 if name := s.Name.Name; ast.IsExported(name) {
166 r.filterType(r.lookupType(s.Name.Name), s.Type)
167 return true
168 } else if name == "error" {
169 // special case: remember that error is declared locally
170 r.errorDecl = true
173 return false
176 // copyConstType returns a copy of typ with position pos.
177 // typ must be a valid constant type.
178 // In practice, only (possibly qualified) identifiers are possible.
180 func copyConstType(typ ast.Expr, pos token.Pos) ast.Expr {
181 switch typ := typ.(type) {
182 case *ast.Ident:
183 return &ast.Ident{Name: typ.Name, NamePos: pos}
184 case *ast.SelectorExpr:
185 if id, ok := typ.X.(*ast.Ident); ok {
186 // presumably a qualified identifier
187 return &ast.SelectorExpr{
188 Sel: ast.NewIdent(typ.Sel.Name),
189 X: &ast.Ident{Name: id.Name, NamePos: pos},
193 return nil // shouldn't happen, but be conservative and don't panic
196 func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec {
197 if tok == token.CONST {
198 // Propagate any type information that would get lost otherwise
199 // when unexported constants are filtered.
200 var prevType ast.Expr
201 for _, spec := range list {
202 spec := spec.(*ast.ValueSpec)
203 if spec.Type == nil && len(spec.Values) == 0 && prevType != nil {
204 // provide current spec with an explicit type
205 spec.Type = copyConstType(prevType, spec.Pos())
207 if hasExportedName(spec.Names) {
208 // exported names are preserved so there's no need to propagate the type
209 prevType = nil
210 } else {
211 prevType = spec.Type
216 j := 0
217 for _, s := range list {
218 if r.filterSpec(s) {
219 list[j] = s
223 return list[0:j]
226 func (r *reader) filterDecl(decl ast.Decl) bool {
227 switch d := decl.(type) {
228 case *ast.GenDecl:
229 d.Specs = r.filterSpecList(d.Specs, d.Tok)
230 return len(d.Specs) > 0
231 case *ast.FuncDecl:
232 // ok to filter these methods early because any
233 // conflicting method will be filtered here, too -
234 // thus, removing these methods early will not lead
235 // to the false removal of possible conflicts
236 return ast.IsExported(d.Name.Name)
238 return false
241 // fileExports removes unexported declarations from src in place.
243 func (r *reader) fileExports(src *ast.File) {
244 j := 0
245 for _, d := range src.Decls {
246 if r.filterDecl(d) {
247 src.Decls[j] = d
251 src.Decls = src.Decls[0:j]