github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/go/doc/exports.go (about) 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 }