...

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