...

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		"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