src/pkg/go/doc/exports.go - The Go Programming Language

Golang

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	}