Black Lives Matter. Support the Equal Justice Initiative.

Source file src/go/doc/reader.go

Documentation: go/doc

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

View as plain text