Source file src/go/doc/reader.go

     1  // Copyright 2009 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  package doc
     6  
     7  import (
     8  	"fmt"
     9  	"go/ast"
    10  	"go/token"
    11  	"internal/lazyregexp"
    12  	"sort"
    13  	"strconv"
    14  	"strings"
    15  )
    16  
    17  // ----------------------------------------------------------------------------
    18  // function/method sets
    19  //
    20  // Internally, we treat functions like methods and collect them in method sets.
    21  
    22  // A methodSet describes a set of methods. Entries where Decl == nil are conflict
    23  // entries (more than one method with the same name at the same embedding level).
    24  //
    25  type methodSet map[string]*Func
    26  
    27  // recvString returns a string representation of recv of the form "T", "*T",
    28  // "T[A, ...]", "*T[A, ...]" or "BADRECV" (if not a proper receiver type).
    29  //
    30  func recvString(recv ast.Expr) string {
    31  	switch t := recv.(type) {
    32  	case *ast.Ident:
    33  		return t.Name
    34  	case *ast.StarExpr:
    35  		return "*" + recvString(t.X)
    36  	case *ast.IndexExpr:
    37  		// Generic type with one parameter.
    38  		return fmt.Sprintf("%s[%s]", recvString(t.X), recvParam(t.Index))
    39  	case *ast.IndexListExpr:
    40  		// Generic type with multiple parameters.
    41  		if len(t.Indices) > 0 {
    42  			var b strings.Builder
    43  			b.WriteString(recvString(t.X))
    44  			b.WriteByte('[')
    45  			b.WriteString(recvParam(t.Indices[0]))
    46  			for _, e := range t.Indices[1:] {
    47  				b.WriteString(", ")
    48  				b.WriteString(recvParam(e))
    49  			}
    50  			b.WriteByte(']')
    51  			return b.String()
    52  		}
    53  	}
    54  	return "BADRECV"
    55  }
    56  
    57  func recvParam(p ast.Expr) string {
    58  	if id, ok := p.(*ast.Ident); ok {
    59  		return id.Name
    60  	}
    61  	return "BADPARAM"
    62  }
    63  
    64  // set creates the corresponding Func for f and adds it to mset.
    65  // If there are multiple f's with the same name, set keeps the first
    66  // one with documentation; conflicts are ignored. The boolean
    67  // specifies whether to leave the AST untouched.
    68  //
    69  func (mset methodSet) set(f *ast.FuncDecl, preserveAST bool) {
    70  	name := f.Name.Name
    71  	if g := mset[name]; g != nil && g.Doc != "" {
    72  		// A function with the same name has already been registered;
    73  		// since it has documentation, assume f is simply another
    74  		// implementation and ignore it. This does not happen if the
    75  		// caller is using go/build.ScanDir to determine the list of
    76  		// files implementing a package.
    77  		return
    78  	}
    79  	// function doesn't exist or has no documentation; use f
    80  	recv := ""
    81  	if f.Recv != nil {
    82  		var typ ast.Expr
    83  		// be careful in case of incorrect ASTs
    84  		if list := f.Recv.List; len(list) == 1 {
    85  			typ = list[0].Type
    86  		}
    87  		recv = recvString(typ)
    88  	}
    89  	mset[name] = &Func{
    90  		Doc:  f.Doc.Text(),
    91  		Name: name,
    92  		Decl: f,
    93  		Recv: recv,
    94  		Orig: recv,
    95  	}
    96  	if !preserveAST {
    97  		f.Doc = nil // doc consumed - remove from AST
    98  	}
    99  }
   100  
   101  // add adds method m to the method set; m is ignored if the method set
   102  // already contains a method with the same name at the same or a higher
   103  // level than m.
   104  //
   105  func (mset methodSet) add(m *Func) {
   106  	old := mset[m.Name]
   107  	if old == nil || m.Level < old.Level {
   108  		mset[m.Name] = m
   109  		return
   110  	}
   111  	if m.Level == old.Level {
   112  		// conflict - mark it using a method with nil Decl
   113  		mset[m.Name] = &Func{
   114  			Name:  m.Name,
   115  			Level: m.Level,
   116  		}
   117  	}
   118  }
   119  
   120  // ----------------------------------------------------------------------------
   121  // Named types
   122  
   123  // baseTypeName returns the name of the base type of x (or "")
   124  // and whether the type is imported or not.
   125  //
   126  func baseTypeName(x ast.Expr) (name string, imported bool) {
   127  	switch t := x.(type) {
   128  	case *ast.Ident:
   129  		return t.Name, false
   130  	case *ast.IndexExpr:
   131  		return baseTypeName(t.X)
   132  	case *ast.IndexListExpr:
   133  		return baseTypeName(t.X)
   134  	case *ast.SelectorExpr:
   135  		if _, ok := t.X.(*ast.Ident); ok {
   136  			// only possible for qualified type names;
   137  			// assume type is imported
   138  			return t.Sel.Name, true
   139  		}
   140  	case *ast.ParenExpr:
   141  		return baseTypeName(t.X)
   142  	case *ast.StarExpr:
   143  		return baseTypeName(t.X)
   144  	}
   145  	return "", false
   146  }
   147  
   148  // An embeddedSet describes a set of embedded types.
   149  type embeddedSet map[*namedType]bool
   150  
   151  // A namedType represents a named unqualified (package local, or possibly
   152  // predeclared) type. The namedType for a type name is always found via
   153  // reader.lookupType.
   154  //
   155  type namedType struct {
   156  	doc  string       // doc comment for type
   157  	name string       // type name
   158  	decl *ast.GenDecl // nil if declaration hasn't been seen yet
   159  
   160  	isEmbedded bool        // true if this type is embedded
   161  	isStruct   bool        // true if this type is a struct
   162  	embedded   embeddedSet // true if the embedded type is a pointer
   163  
   164  	// associated declarations
   165  	values  []*Value // consts and vars
   166  	funcs   methodSet
   167  	methods methodSet
   168  }
   169  
   170  // ----------------------------------------------------------------------------
   171  // AST reader
   172  
   173  // reader accumulates documentation for a single package.
   174  // It modifies the AST: Comments (declaration documentation)
   175  // that have been collected by the reader are set to nil
   176  // in the respective AST nodes so that they are not printed
   177  // twice (once when printing the documentation and once when
   178  // printing the corresponding AST node).
   179  //
   180  type reader struct {
   181  	mode Mode
   182  
   183  	// package properties
   184  	doc       string // package documentation, if any
   185  	filenames []string
   186  	notes     map[string][]*Note
   187  
   188  	// declarations
   189  	imports   map[string]int
   190  	hasDotImp bool     // if set, package contains a dot import
   191  	values    []*Value // consts and vars
   192  	order     int      // sort order of const and var declarations (when we can't use a name)
   193  	types     map[string]*namedType
   194  	funcs     methodSet
   195  
   196  	// support for package-local shadowing of predeclared types
   197  	shadowedPredecl map[string]bool
   198  	fixmap          map[string][]*ast.InterfaceType
   199  }
   200  
   201  func (r *reader) isVisible(name string) bool {
   202  	return r.mode&AllDecls != 0 || token.IsExported(name)
   203  }
   204  
   205  // lookupType returns the base type with the given name.
   206  // If the base type has not been encountered yet, a new
   207  // type with the given name but no associated declaration
   208  // is added to the type map.
   209  //
   210  func (r *reader) lookupType(name string) *namedType {
   211  	if name == "" || name == "_" {
   212  		return nil // no type docs for anonymous types
   213  	}
   214  	if typ, found := r.types[name]; found {
   215  		return typ
   216  	}
   217  	// type not found - add one without declaration
   218  	typ := &namedType{
   219  		name:     name,
   220  		embedded: make(embeddedSet),
   221  		funcs:    make(methodSet),
   222  		methods:  make(methodSet),
   223  	}
   224  	r.types[name] = typ
   225  	return typ
   226  }
   227  
   228  // recordAnonymousField registers fieldType as the type of an
   229  // anonymous field in the parent type. If the field is imported
   230  // (qualified name) or the parent is nil, the field is ignored.
   231  // The function returns the field name.
   232  //
   233  func (r *reader) recordAnonymousField(parent *namedType, fieldType ast.Expr) (fname string) {
   234  	fname, imp := baseTypeName(fieldType)
   235  	if parent == nil || imp {
   236  		return
   237  	}
   238  	if ftype := r.lookupType(fname); ftype != nil {
   239  		ftype.isEmbedded = true
   240  		_, ptr := fieldType.(*ast.StarExpr)
   241  		parent.embedded[ftype] = ptr
   242  	}
   243  	return
   244  }
   245  
   246  func (r *reader) readDoc(comment *ast.CommentGroup) {
   247  	// By convention there should be only one package comment
   248  	// but collect all of them if there are more than one.
   249  	text := comment.Text()
   250  	if r.doc == "" {
   251  		r.doc = text
   252  		return
   253  	}
   254  	r.doc += "\n" + text
   255  }
   256  
   257  func (r *reader) remember(predecl string, typ *ast.InterfaceType) {
   258  	if r.fixmap == nil {
   259  		r.fixmap = make(map[string][]*ast.InterfaceType)
   260  	}
   261  	r.fixmap[predecl] = append(r.fixmap[predecl], typ)
   262  }
   263  
   264  func specNames(specs []ast.Spec) []string {
   265  	names := make([]string, 0, len(specs)) // reasonable estimate
   266  	for _, s := range specs {
   267  		// s guaranteed to be an *ast.ValueSpec by readValue
   268  		for _, ident := range s.(*ast.ValueSpec).Names {
   269  			names = append(names, ident.Name)
   270  		}
   271  	}
   272  	return names
   273  }
   274  
   275  // readValue processes a const or var declaration.
   276  //
   277  func (r *reader) readValue(decl *ast.GenDecl) {
   278  	// determine if decl should be associated with a type
   279  	// Heuristic: For each typed entry, determine the type name, if any.
   280  	//            If there is exactly one type name that is sufficiently
   281  	//            frequent, associate the decl with the respective type.
   282  	domName := ""
   283  	domFreq := 0
   284  	prev := ""
   285  	n := 0
   286  	for _, spec := range decl.Specs {
   287  		s, ok := spec.(*ast.ValueSpec)
   288  		if !ok {
   289  			continue // should not happen, but be conservative
   290  		}
   291  		name := ""
   292  		switch {
   293  		case s.Type != nil:
   294  			// a type is present; determine its name
   295  			if n, imp := baseTypeName(s.Type); !imp {
   296  				name = n
   297  			}
   298  		case decl.Tok == token.CONST && len(s.Values) == 0:
   299  			// no type or value is present but we have a constant declaration;
   300  			// use the previous type name (possibly the empty string)
   301  			name = prev
   302  		}
   303  		if name != "" {
   304  			// entry has a named type
   305  			if domName != "" && domName != name {
   306  				// more than one type name - do not associate
   307  				// with any type
   308  				domName = ""
   309  				break
   310  			}
   311  			domName = name
   312  			domFreq++
   313  		}
   314  		prev = name
   315  		n++
   316  	}
   317  
   318  	// nothing to do w/o a legal declaration
   319  	if n == 0 {
   320  		return
   321  	}
   322  
   323  	// determine values list with which to associate the Value for this decl
   324  	values := &r.values
   325  	const threshold = 0.75
   326  	if domName != "" && r.isVisible(domName) && domFreq >= int(float64(len(decl.Specs))*threshold) {
   327  		// typed entries are sufficiently frequent
   328  		if typ := r.lookupType(domName); typ != nil {
   329  			values = &typ.values // associate with that type
   330  		}
   331  	}
   332  
   333  	*values = append(*values, &Value{
   334  		Doc:   decl.Doc.Text(),
   335  		Names: specNames(decl.Specs),
   336  		Decl:  decl,
   337  		order: r.order,
   338  	})
   339  	if r.mode&PreserveAST == 0 {
   340  		decl.Doc = nil // doc consumed - remove from AST
   341  	}
   342  	// Note: It's important that the order used here is global because the cleanupTypes
   343  	// methods may move values associated with types back into the global list. If the
   344  	// order is list-specific, sorting is not deterministic because the same order value
   345  	// may appear multiple times (was bug, found when fixing #16153).
   346  	r.order++
   347  }
   348  
   349  // fields returns a struct's fields or an interface's methods.
   350  //
   351  func fields(typ ast.Expr) (list []*ast.Field, isStruct bool) {
   352  	var fields *ast.FieldList
   353  	switch t := typ.(type) {
   354  	case *ast.StructType:
   355  		fields = t.Fields
   356  		isStruct = true
   357  	case *ast.InterfaceType:
   358  		fields = t.Methods
   359  	}
   360  	if fields != nil {
   361  		list = fields.List
   362  	}
   363  	return
   364  }
   365  
   366  // readType processes a type declaration.
   367  //
   368  func (r *reader) readType(decl *ast.GenDecl, spec *ast.TypeSpec) {
   369  	typ := r.lookupType(spec.Name.Name)
   370  	if typ == nil {
   371  		return // no name or blank name - ignore the type
   372  	}
   373  
   374  	// A type should be added at most once, so typ.decl
   375  	// should be nil - if it is not, simply overwrite it.
   376  	typ.decl = decl
   377  
   378  	// compute documentation
   379  	doc := spec.Doc
   380  	if doc == nil {
   381  		// no doc associated with the spec, use the declaration doc, if any
   382  		doc = decl.Doc
   383  	}
   384  	if r.mode&PreserveAST == 0 {
   385  		spec.Doc = nil // doc consumed - remove from AST
   386  		decl.Doc = nil // doc consumed - remove from AST
   387  	}
   388  	typ.doc = doc.Text()
   389  
   390  	// record anonymous fields (they may contribute methods)
   391  	// (some fields may have been recorded already when filtering
   392  	// exports, but that's ok)
   393  	var list []*ast.Field
   394  	list, typ.isStruct = fields(spec.Type)
   395  	for _, field := range list {
   396  		if len(field.Names) == 0 {
   397  			r.recordAnonymousField(typ, field.Type)
   398  		}
   399  	}
   400  }
   401  
   402  // isPredeclared reports whether n denotes a predeclared type.
   403  //
   404  func (r *reader) isPredeclared(n string) bool {
   405  	return predeclaredTypes[n] && r.types[n] == nil
   406  }
   407  
   408  // readFunc processes a func or method declaration.
   409  //
   410  func (r *reader) readFunc(fun *ast.FuncDecl) {
   411  	// strip function body if requested.
   412  	if r.mode&PreserveAST == 0 {
   413  		fun.Body = nil
   414  	}
   415  
   416  	// associate methods with the receiver type, if any
   417  	if fun.Recv != nil {
   418  		// method
   419  		if len(fun.Recv.List) == 0 {
   420  			// should not happen (incorrect AST); (See issue 17788)
   421  			// don't show this method
   422  			return
   423  		}
   424  		recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type)
   425  		if imp {
   426  			// should not happen (incorrect AST);
   427  			// don't show this method
   428  			return
   429  		}
   430  		if typ := r.lookupType(recvTypeName); typ != nil {
   431  			typ.methods.set(fun, r.mode&PreserveAST != 0)
   432  		}
   433  		// otherwise ignore the method
   434  		// TODO(gri): There may be exported methods of non-exported types
   435  		// that can be called because of exported values (consts, vars, or
   436  		// function results) of that type. Could determine if that is the
   437  		// case and then show those methods in an appropriate section.
   438  		return
   439  	}
   440  
   441  	// Associate factory functions with the first visible result type, as long as
   442  	// others are predeclared types.
   443  	if fun.Type.Results.NumFields() >= 1 {
   444  		var typ *namedType // type to associate the function with
   445  		numResultTypes := 0
   446  		for _, res := range fun.Type.Results.List {
   447  			factoryType := res.Type
   448  			if t, ok := factoryType.(*ast.ArrayType); ok {
   449  				// We consider functions that return slices or arrays of type
   450  				// T (or pointers to T) as factory functions of T.
   451  				factoryType = t.Elt
   452  			}
   453  			if n, imp := baseTypeName(factoryType); !imp && r.isVisible(n) && !r.isPredeclared(n) {
   454  				if lookupTypeParam(n, fun.Type.TypeParams) != nil {
   455  					// Issue #49477: don't associate fun with its type parameter result.
   456  					// A type parameter is not a defined type.
   457  					continue
   458  				}
   459  				if t := r.lookupType(n); t != nil {
   460  					typ = t
   461  					numResultTypes++
   462  					if numResultTypes > 1 {
   463  						break
   464  					}
   465  				}
   466  			}
   467  		}
   468  		// If there is exactly one result type,
   469  		// associate the function with that type.
   470  		if numResultTypes == 1 {
   471  			typ.funcs.set(fun, r.mode&PreserveAST != 0)
   472  			return
   473  		}
   474  	}
   475  
   476  	// just an ordinary function
   477  	r.funcs.set(fun, r.mode&PreserveAST != 0)
   478  }
   479  
   480  // lookupTypeParam searches for type parameters named name within the tparams
   481  // field list, returning the relevant identifier if found, or nil if not.
   482  func lookupTypeParam(name string, tparams *ast.FieldList) *ast.Ident {
   483  	if tparams == nil {
   484  		return nil
   485  	}
   486  	for _, field := range tparams.List {
   487  		for _, id := range field.Names {
   488  			if id.Name == name {
   489  				return id
   490  			}
   491  		}
   492  	}
   493  	return nil
   494  }
   495  
   496  var (
   497  	noteMarker    = `([A-Z][A-Z]+)\(([^)]+)\):?`                // MARKER(uid), MARKER at least 2 chars, uid at least 1 char
   498  	noteMarkerRx  = lazyregexp.New(`^[ \t]*` + noteMarker)      // MARKER(uid) at text start
   499  	noteCommentRx = lazyregexp.New(`^/[/*][ \t]*` + noteMarker) // MARKER(uid) at comment start
   500  )
   501  
   502  // readNote collects a single note from a sequence of comments.
   503  //
   504  func (r *reader) readNote(list []*ast.Comment) {
   505  	text := (&ast.CommentGroup{List: list}).Text()
   506  	if m := noteMarkerRx.FindStringSubmatchIndex(text); m != nil {
   507  		// The note body starts after the marker.
   508  		// We remove any formatting so that we don't
   509  		// get spurious line breaks/indentation when
   510  		// showing the TODO body.
   511  		body := clean(text[m[1]:], keepNL)
   512  		if body != "" {
   513  			marker := text[m[2]:m[3]]
   514  			r.notes[marker] = append(r.notes[marker], &Note{
   515  				Pos:  list[0].Pos(),
   516  				End:  list[len(list)-1].End(),
   517  				UID:  text[m[4]:m[5]],
   518  				Body: body,
   519  			})
   520  		}
   521  	}
   522  }
   523  
   524  // readNotes extracts notes from comments.
   525  // A note must start at the beginning of a comment with "MARKER(uid):"
   526  // and is followed by the note body (e.g., "// BUG(gri): fix this").
   527  // The note ends at the end of the comment group or at the start of
   528  // another note in the same comment group, whichever comes first.
   529  //
   530  func (r *reader) readNotes(comments []*ast.CommentGroup) {
   531  	for _, group := range comments {
   532  		i := -1 // comment index of most recent note start, valid if >= 0
   533  		list := group.List
   534  		for j, c := range list {
   535  			if noteCommentRx.MatchString(c.Text) {
   536  				if i >= 0 {
   537  					r.readNote(list[i:j])
   538  				}
   539  				i = j
   540  			}
   541  		}
   542  		if i >= 0 {
   543  			r.readNote(list[i:])
   544  		}
   545  	}
   546  }
   547  
   548  // readFile adds the AST for a source file to the reader.
   549  //
   550  func (r *reader) readFile(src *ast.File) {
   551  	// add package documentation
   552  	if src.Doc != nil {
   553  		r.readDoc(src.Doc)
   554  		if r.mode&PreserveAST == 0 {
   555  			src.Doc = nil // doc consumed - remove from AST
   556  		}
   557  	}
   558  
   559  	// add all declarations but for functions which are processed in a separate pass
   560  	for _, decl := range src.Decls {
   561  		switch d := decl.(type) {
   562  		case *ast.GenDecl:
   563  			switch d.Tok {
   564  			case token.IMPORT:
   565  				// imports are handled individually
   566  				for _, spec := range d.Specs {
   567  					if s, ok := spec.(*ast.ImportSpec); ok {
   568  						if import_, err := strconv.Unquote(s.Path.Value); err == nil {
   569  							r.imports[import_] = 1
   570  							if s.Name != nil && s.Name.Name == "." {
   571  								r.hasDotImp = true
   572  							}
   573  						}
   574  					}
   575  				}
   576  			case token.CONST, token.VAR:
   577  				// constants and variables are always handled as a group
   578  				r.readValue(d)
   579  			case token.TYPE:
   580  				// types are handled individually
   581  				if len(d.Specs) == 1 && !d.Lparen.IsValid() {
   582  					// common case: single declaration w/o parentheses
   583  					// (if a single declaration is parenthesized,
   584  					// create a new fake declaration below, so that
   585  					// go/doc type declarations always appear w/o
   586  					// parentheses)
   587  					if s, ok := d.Specs[0].(*ast.TypeSpec); ok {
   588  						r.readType(d, s)
   589  					}
   590  					break
   591  				}
   592  				for _, spec := range d.Specs {
   593  					if s, ok := spec.(*ast.TypeSpec); ok {
   594  						// use an individual (possibly fake) declaration
   595  						// for each type; this also ensures that each type
   596  						// gets to (re-)use the declaration documentation
   597  						// if there's none associated with the spec itself
   598  						fake := &ast.GenDecl{
   599  							Doc: d.Doc,
   600  							// don't use the existing TokPos because it
   601  							// will lead to the wrong selection range for
   602  							// the fake declaration if there are more
   603  							// than one type in the group (this affects
   604  							// src/cmd/godoc/godoc.go's posLink_urlFunc)
   605  							TokPos: s.Pos(),
   606  							Tok:    token.TYPE,
   607  							Specs:  []ast.Spec{s},
   608  						}
   609  						r.readType(fake, s)
   610  					}
   611  				}
   612  			}
   613  		}
   614  	}
   615  
   616  	// collect MARKER(...): annotations
   617  	r.readNotes(src.Comments)
   618  	if r.mode&PreserveAST == 0 {
   619  		src.Comments = nil // consumed unassociated comments - remove from AST
   620  	}
   621  }
   622  
   623  func (r *reader) readPackage(pkg *ast.Package, mode Mode) {
   624  	// initialize reader
   625  	r.filenames = make([]string, len(pkg.Files))
   626  	r.imports = make(map[string]int)
   627  	r.mode = mode
   628  	r.types = make(map[string]*namedType)
   629  	r.funcs = make(methodSet)
   630  	r.notes = make(map[string][]*Note)
   631  
   632  	// sort package files before reading them so that the
   633  	// result does not depend on map iteration order
   634  	i := 0
   635  	for filename := range pkg.Files {
   636  		r.filenames[i] = filename
   637  		i++
   638  	}
   639  	sort.Strings(r.filenames)
   640  
   641  	// process files in sorted order
   642  	for _, filename := range r.filenames {
   643  		f := pkg.Files[filename]
   644  		if mode&AllDecls == 0 {
   645  			r.fileExports(f)
   646  		}
   647  		r.readFile(f)
   648  	}
   649  
   650  	// process functions now that we have better type information
   651  	for _, f := range pkg.Files {
   652  		for _, decl := range f.Decls {
   653  			if d, ok := decl.(*ast.FuncDecl); ok {
   654  				r.readFunc(d)
   655  			}
   656  		}
   657  	}
   658  }
   659  
   660  // ----------------------------------------------------------------------------
   661  // Types
   662  
   663  func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int) *Func {
   664  	if f == nil || f.Decl == nil || f.Decl.Recv == nil || len(f.Decl.Recv.List) != 1 {
   665  		return f // shouldn't happen, but be safe
   666  	}
   667  
   668  	// copy existing receiver field and set new type
   669  	newField := *f.Decl.Recv.List[0]
   670  	origPos := newField.Type.Pos()
   671  	_, origRecvIsPtr := newField.Type.(*ast.StarExpr)
   672  	newIdent := &ast.Ident{NamePos: origPos, Name: recvTypeName}
   673  	var typ ast.Expr = newIdent
   674  	if !embeddedIsPtr && origRecvIsPtr {
   675  		newIdent.NamePos++ // '*' is one character
   676  		typ = &ast.StarExpr{Star: origPos, X: newIdent}
   677  	}
   678  	newField.Type = typ
   679  
   680  	// copy existing receiver field list and set new receiver field
   681  	newFieldList := *f.Decl.Recv
   682  	newFieldList.List = []*ast.Field{&newField}
   683  
   684  	// copy existing function declaration and set new receiver field list
   685  	newFuncDecl := *f.Decl
   686  	newFuncDecl.Recv = &newFieldList
   687  
   688  	// copy existing function documentation and set new declaration
   689  	newF := *f
   690  	newF.Decl = &newFuncDecl
   691  	newF.Recv = recvString(typ)
   692  	// the Orig field never changes
   693  	newF.Level = level
   694  
   695  	return &newF
   696  }
   697  
   698  // collectEmbeddedMethods collects the embedded methods of typ in mset.
   699  //
   700  func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvTypeName string, embeddedIsPtr bool, level int, visited embeddedSet) {
   701  	visited[typ] = true
   702  	for embedded, isPtr := range typ.embedded {
   703  		// Once an embedded type is embedded as a pointer type
   704  		// all embedded types in those types are treated like
   705  		// pointer types for the purpose of the receiver type
   706  		// computation; i.e., embeddedIsPtr is sticky for this
   707  		// embedding hierarchy.
   708  		thisEmbeddedIsPtr := embeddedIsPtr || isPtr
   709  		for _, m := range embedded.methods {
   710  			// only top-level methods are embedded
   711  			if m.Level == 0 {
   712  				mset.add(customizeRecv(m, recvTypeName, thisEmbeddedIsPtr, level))
   713  			}
   714  		}
   715  		if !visited[embedded] {
   716  			r.collectEmbeddedMethods(mset, embedded, recvTypeName, thisEmbeddedIsPtr, level+1, visited)
   717  		}
   718  	}
   719  	delete(visited, typ)
   720  }
   721  
   722  // computeMethodSets determines the actual method sets for each type encountered.
   723  //
   724  func (r *reader) computeMethodSets() {
   725  	for _, t := range r.types {
   726  		// collect embedded methods for t
   727  		if t.isStruct {
   728  			// struct
   729  			r.collectEmbeddedMethods(t.methods, t, t.name, false, 1, make(embeddedSet))
   730  		} else {
   731  			// interface
   732  			// TODO(gri) fix this
   733  		}
   734  	}
   735  
   736  	// For any predeclared names that are declared locally, don't treat them as
   737  	// exported fields anymore.
   738  	for predecl := range r.shadowedPredecl {
   739  		for _, ityp := range r.fixmap[predecl] {
   740  			removeAnonymousField(predecl, ityp)
   741  		}
   742  	}
   743  }
   744  
   745  // cleanupTypes removes the association of functions and methods with
   746  // types that have no declaration. Instead, these functions and methods
   747  // are shown at the package level. It also removes types with missing
   748  // declarations or which are not visible.
   749  //
   750  func (r *reader) cleanupTypes() {
   751  	for _, t := range r.types {
   752  		visible := r.isVisible(t.name)
   753  		predeclared := predeclaredTypes[t.name]
   754  
   755  		if t.decl == nil && (predeclared || visible && (t.isEmbedded || r.hasDotImp)) {
   756  			// t.name is a predeclared type (and was not redeclared in this package),
   757  			// or it was embedded somewhere but its declaration is missing (because
   758  			// the AST is incomplete), or we have a dot-import (and all bets are off):
   759  			// move any associated values, funcs, and methods back to the top-level so
   760  			// that they are not lost.
   761  			// 1) move values
   762  			r.values = append(r.values, t.values...)
   763  			// 2) move factory functions
   764  			for name, f := range t.funcs {
   765  				// in a correct AST, package-level function names
   766  				// are all different - no need to check for conflicts
   767  				r.funcs[name] = f
   768  			}
   769  			// 3) move methods
   770  			if !predeclared {
   771  				for name, m := range t.methods {
   772  					// don't overwrite functions with the same name - drop them
   773  					if _, found := r.funcs[name]; !found {
   774  						r.funcs[name] = m
   775  					}
   776  				}
   777  			}
   778  		}
   779  		// remove types w/o declaration or which are not visible
   780  		if t.decl == nil || !visible {
   781  			delete(r.types, t.name)
   782  		}
   783  	}
   784  }
   785  
   786  // ----------------------------------------------------------------------------
   787  // Sorting
   788  
   789  type data struct {
   790  	n    int
   791  	swap func(i, j int)
   792  	less func(i, j int) bool
   793  }
   794  
   795  func (d *data) Len() int           { return d.n }
   796  func (d *data) Swap(i, j int)      { d.swap(i, j) }
   797  func (d *data) Less(i, j int) bool { return d.less(i, j) }
   798  
   799  // sortBy is a helper function for sorting
   800  func sortBy(less func(i, j int) bool, swap func(i, j int), n int) {
   801  	sort.Sort(&data{n, swap, less})
   802  }
   803  
   804  func sortedKeys(m map[string]int) []string {
   805  	list := make([]string, len(m))
   806  	i := 0
   807  	for key := range m {
   808  		list[i] = key
   809  		i++
   810  	}
   811  	sort.Strings(list)
   812  	return list
   813  }
   814  
   815  // sortingName returns the name to use when sorting d into place.
   816  //
   817  func sortingName(d *ast.GenDecl) string {
   818  	if len(d.Specs) == 1 {
   819  		if s, ok := d.Specs[0].(*ast.ValueSpec); ok {
   820  			return s.Names[0].Name
   821  		}
   822  	}
   823  	return ""
   824  }
   825  
   826  func sortedValues(m []*Value, tok token.Token) []*Value {
   827  	list := make([]*Value, len(m)) // big enough in any case
   828  	i := 0
   829  	for _, val := range m {
   830  		if val.Decl.Tok == tok {
   831  			list[i] = val
   832  			i++
   833  		}
   834  	}
   835  	list = list[0:i]
   836  
   837  	sortBy(
   838  		func(i, j int) bool {
   839  			if ni, nj := sortingName(list[i].Decl), sortingName(list[j].Decl); ni != nj {
   840  				return ni < nj
   841  			}
   842  			return list[i].order < list[j].order
   843  		},
   844  		func(i, j int) { list[i], list[j] = list[j], list[i] },
   845  		len(list),
   846  	)
   847  
   848  	return list
   849  }
   850  
   851  func sortedTypes(m map[string]*namedType, allMethods bool) []*Type {
   852  	list := make([]*Type, len(m))
   853  	i := 0
   854  	for _, t := range m {
   855  		list[i] = &Type{
   856  			Doc:     t.doc,
   857  			Name:    t.name,
   858  			Decl:    t.decl,
   859  			Consts:  sortedValues(t.values, token.CONST),
   860  			Vars:    sortedValues(t.values, token.VAR),
   861  			Funcs:   sortedFuncs(t.funcs, true),
   862  			Methods: sortedFuncs(t.methods, allMethods),
   863  		}
   864  		i++
   865  	}
   866  
   867  	sortBy(
   868  		func(i, j int) bool { return list[i].Name < list[j].Name },
   869  		func(i, j int) { list[i], list[j] = list[j], list[i] },
   870  		len(list),
   871  	)
   872  
   873  	return list
   874  }
   875  
   876  func removeStar(s string) string {
   877  	if len(s) > 0 && s[0] == '*' {
   878  		return s[1:]
   879  	}
   880  	return s
   881  }
   882  
   883  func sortedFuncs(m methodSet, allMethods bool) []*Func {
   884  	list := make([]*Func, len(m))
   885  	i := 0
   886  	for _, m := range m {
   887  		// determine which methods to include
   888  		switch {
   889  		case m.Decl == nil:
   890  			// exclude conflict entry
   891  		case allMethods, m.Level == 0, !token.IsExported(removeStar(m.Orig)):
   892  			// forced inclusion, method not embedded, or method
   893  			// embedded but original receiver type not exported
   894  			list[i] = m
   895  			i++
   896  		}
   897  	}
   898  	list = list[0:i]
   899  	sortBy(
   900  		func(i, j int) bool { return list[i].Name < list[j].Name },
   901  		func(i, j int) { list[i], list[j] = list[j], list[i] },
   902  		len(list),
   903  	)
   904  	return list
   905  }
   906  
   907  // noteBodies returns a list of note body strings given a list of notes.
   908  // This is only used to populate the deprecated Package.Bugs field.
   909  //
   910  func noteBodies(notes []*Note) []string {
   911  	var list []string
   912  	for _, n := range notes {
   913  		list = append(list, n.Body)
   914  	}
   915  	return list
   916  }
   917  
   918  // ----------------------------------------------------------------------------
   919  // Predeclared identifiers
   920  
   921  // IsPredeclared reports whether s is a predeclared identifier.
   922  func IsPredeclared(s string) bool {
   923  	return predeclaredTypes[s] || predeclaredFuncs[s] || predeclaredConstants[s]
   924  }
   925  
   926  var predeclaredTypes = map[string]bool{
   927  	"any":        true,
   928  	"bool":       true,
   929  	"byte":       true,
   930  	"comparable": true,
   931  	"complex64":  true,
   932  	"complex128": true,
   933  	"error":      true,
   934  	"float32":    true,
   935  	"float64":    true,
   936  	"int":        true,
   937  	"int8":       true,
   938  	"int16":      true,
   939  	"int32":      true,
   940  	"int64":      true,
   941  	"rune":       true,
   942  	"string":     true,
   943  	"uint":       true,
   944  	"uint8":      true,
   945  	"uint16":     true,
   946  	"uint32":     true,
   947  	"uint64":     true,
   948  	"uintptr":    true,
   949  }
   950  
   951  var predeclaredFuncs = map[string]bool{
   952  	"append":  true,
   953  	"cap":     true,
   954  	"close":   true,
   955  	"complex": true,
   956  	"copy":    true,
   957  	"delete":  true,
   958  	"imag":    true,
   959  	"len":     true,
   960  	"make":    true,
   961  	"new":     true,
   962  	"panic":   true,
   963  	"print":   true,
   964  	"println": true,
   965  	"real":    true,
   966  	"recover": true,
   967  }
   968  
   969  var predeclaredConstants = map[string]bool{
   970  	"false": true,
   971  	"iota":  true,
   972  	"nil":   true,
   973  	"true":  true,
   974  }
   975  

View as plain text