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