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

View as plain text