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  }