5eaae37b7decdf0b9c21197561f4a31e538e7e07
[platform/upstream/gcc48.git] / libgo / go / 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         "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 then 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.
41 //
42 func (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 then m.
75 //
76 func (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 //
97 func 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.
114 type 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 //
120 type 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 //
145 type reader struct {
146         mode Mode
147
148         // package properties
149         doc       string // package documentation, if any
150         filenames []string
151         bugs      []string
152
153         // declarations
154         imports map[string]int
155         values  []*Value // consts and vars
156         types   map[string]*namedType
157         funcs   methodSet
158
159         // support for package-local error type declarations
160         errorDecl bool                 // if set, type "error" was declared locally
161         fixlist   []*ast.InterfaceType // list of interfaces containing anonymous field "error"
162 }
163
164 func (r *reader) isVisible(name string) bool {
165         return r.mode&AllDecls != 0 || ast.IsExported(name)
166 }
167
168 // lookupType returns the base type with the given name.
169 // If the base type has not been encountered yet, a new
170 // type with the given name but no associated declaration
171 // is added to the type map.
172 //
173 func (r *reader) lookupType(name string) *namedType {
174         if name == "" || name == "_" {
175                 return nil // no type docs for anonymous types
176         }
177         if typ, found := r.types[name]; found {
178                 return typ
179         }
180         // type not found - add one without declaration
181         typ := &namedType{
182                 name:     name,
183                 embedded: make(embeddedSet),
184                 funcs:    make(methodSet),
185                 methods:  make(methodSet),
186         }
187         r.types[name] = typ
188         return typ
189 }
190
191 // recordAnonymousField registers fieldType as the type of an
192 // anonymous field in the parent type. If the field is imported
193 // (qualified name) or the parent is nil, the field is ignored.
194 // The function returns the field name.
195 //
196 func (r *reader) recordAnonymousField(parent *namedType, fieldType ast.Expr) (fname string) {
197         fname, imp := baseTypeName(fieldType)
198         if parent == nil || imp {
199                 return
200         }
201         if ftype := r.lookupType(fname); ftype != nil {
202                 ftype.isEmbedded = true
203                 _, ptr := fieldType.(*ast.StarExpr)
204                 parent.embedded[ftype] = ptr
205         }
206         return
207 }
208
209 func (r *reader) readDoc(comment *ast.CommentGroup) {
210         // By convention there should be only one package comment
211         // but collect all of them if there are more then one.
212         text := comment.Text()
213         if r.doc == "" {
214                 r.doc = text
215                 return
216         }
217         r.doc += "\n" + text
218 }
219
220 func (r *reader) remember(typ *ast.InterfaceType) {
221         r.fixlist = append(r.fixlist, typ)
222 }
223
224 func specNames(specs []ast.Spec) []string {
225         names := make([]string, 0, len(specs)) // reasonable estimate
226         for _, s := range specs {
227                 // s guaranteed to be an *ast.ValueSpec by readValue
228                 for _, ident := range s.(*ast.ValueSpec).Names {
229                         names = append(names, ident.Name)
230                 }
231         }
232         return names
233 }
234
235 // readValue processes a const or var declaration.
236 //
237 func (r *reader) readValue(decl *ast.GenDecl) {
238         // determine if decl should be associated with a type
239         // Heuristic: For each typed entry, determine the type name, if any.
240         //            If there is exactly one type name that is sufficiently
241         //            frequent, associate the decl with the respective type.
242         domName := ""
243         domFreq := 0
244         prev := ""
245         n := 0
246         for _, spec := range decl.Specs {
247                 s, ok := spec.(*ast.ValueSpec)
248                 if !ok {
249                         continue // should not happen, but be conservative
250                 }
251                 name := ""
252                 switch {
253                 case s.Type != nil:
254                         // a type is present; determine its name
255                         if n, imp := baseTypeName(s.Type); !imp {
256                                 name = n
257                         }
258                 case decl.Tok == token.CONST:
259                         // no type is present but we have a constant declaration;
260                         // use the previous type name (w/o more type information
261                         // we cannot handle the case of unnamed variables with
262                         // initializer expressions except for some trivial cases)
263                         name = prev
264                 }
265                 if name != "" {
266                         // entry has a named type
267                         if domName != "" && domName != name {
268                                 // more than one type name - do not associate
269                                 // with any type
270                                 domName = ""
271                                 break
272                         }
273                         domName = name
274                         domFreq++
275                 }
276                 prev = name
277                 n++
278         }
279
280         // nothing to do w/o a legal declaration
281         if n == 0 {
282                 return
283         }
284
285         // determine values list with which to associate the Value for this decl
286         values := &r.values
287         const threshold = 0.75
288         if domName != "" && r.isVisible(domName) && domFreq >= int(float64(len(decl.Specs))*threshold) {
289                 // typed entries are sufficiently frequent
290                 if typ := r.lookupType(domName); typ != nil {
291                         values = &typ.values // associate with that type
292                 }
293         }
294
295         *values = append(*values, &Value{
296                 Doc:   decl.Doc.Text(),
297                 Names: specNames(decl.Specs),
298                 Decl:  decl,
299                 order: len(*values),
300         })
301         decl.Doc = nil // doc consumed - remove from AST
302 }
303
304 // fields returns a struct's fields or an interface's methods.
305 //
306 func fields(typ ast.Expr) (list []*ast.Field, isStruct bool) {
307         var fields *ast.FieldList
308         switch t := typ.(type) {
309         case *ast.StructType:
310                 fields = t.Fields
311                 isStruct = true
312         case *ast.InterfaceType:
313                 fields = t.Methods
314         }
315         if fields != nil {
316                 list = fields.List
317         }
318         return
319 }
320
321 // readType processes a type declaration.
322 //
323 func (r *reader) readType(decl *ast.GenDecl, spec *ast.TypeSpec) {
324         typ := r.lookupType(spec.Name.Name)
325         if typ == nil {
326                 return // no name or blank name - ignore the type
327         }
328
329         // A type should be added at most once, so typ.decl
330         // should be nil - if it is not, simply overwrite it.
331         typ.decl = decl
332
333         // compute documentation
334         doc := spec.Doc
335         spec.Doc = nil // doc consumed - remove from AST
336         if doc == nil {
337                 // no doc associated with the spec, use the declaration doc, if any
338                 doc = decl.Doc
339         }
340         decl.Doc = nil // doc consumed - remove from AST
341         typ.doc = doc.Text()
342
343         // record anonymous fields (they may contribute methods)
344         // (some fields may have been recorded already when filtering
345         // exports, but that's ok)
346         var list []*ast.Field
347         list, typ.isStruct = fields(spec.Type)
348         for _, field := range list {
349                 if len(field.Names) == 0 {
350                         r.recordAnonymousField(typ, field.Type)
351                 }
352         }
353 }
354
355 // readFunc processes a func or method declaration.
356 //
357 func (r *reader) readFunc(fun *ast.FuncDecl) {
358         // strip function body
359         fun.Body = nil
360
361         // associate methods with the receiver type, if any
362         if fun.Recv != nil {
363                 // method
364                 recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type)
365                 if imp {
366                         // should not happen (incorrect AST);
367                         // don't show this method
368                         return
369                 }
370                 if typ := r.lookupType(recvTypeName); typ != nil {
371                         typ.methods.set(fun)
372                 }
373                 // otherwise ignore the method
374                 // TODO(gri): There may be exported methods of non-exported types
375                 // that can be called because of exported values (consts, vars, or
376                 // function results) of that type. Could determine if that is the
377                 // case and then show those methods in an appropriate section.
378                 return
379         }
380
381         // associate factory functions with the first visible result type, if any
382         if fun.Type.Results.NumFields() >= 1 {
383                 res := fun.Type.Results.List[0]
384                 if len(res.Names) <= 1 {
385                         // exactly one (named or anonymous) result associated
386                         // with the first type in result signature (there may
387                         // be more than one result)
388                         if n, imp := baseTypeName(res.Type); !imp && r.isVisible(n) {
389                                 if typ := r.lookupType(n); typ != nil {
390                                         // associate function with typ
391                                         typ.funcs.set(fun)
392                                         return
393                                 }
394                         }
395                 }
396         }
397
398         // just an ordinary function
399         r.funcs.set(fun)
400 }
401
402 var (
403         bug_markers = regexp.MustCompile("^/[/*][ \t]*BUG\\(.*\\):[ \t]*") // BUG(uid):
404         bug_content = regexp.MustCompile("[^ \n\r\t]+")                    // at least one non-whitespace char
405 )
406
407 // readFile adds the AST for a source file to the reader.
408 //
409 func (r *reader) readFile(src *ast.File) {
410         // add package documentation
411         if src.Doc != nil {
412                 r.readDoc(src.Doc)
413                 src.Doc = nil // doc consumed - remove from AST
414         }
415
416         // add all declarations
417         for _, decl := range src.Decls {
418                 switch d := decl.(type) {
419                 case *ast.GenDecl:
420                         switch d.Tok {
421                         case token.IMPORT:
422                                 // imports are handled individually
423                                 for _, spec := range d.Specs {
424                                         if s, ok := spec.(*ast.ImportSpec); ok {
425                                                 if import_, err := strconv.Unquote(s.Path.Value); err == nil {
426                                                         r.imports[import_] = 1
427                                                 }
428                                         }
429                                 }
430                         case token.CONST, token.VAR:
431                                 // constants and variables are always handled as a group
432                                 r.readValue(d)
433                         case token.TYPE:
434                                 // types are handled individually
435                                 if len(d.Specs) == 1 && !d.Lparen.IsValid() {
436                                         // common case: single declaration w/o parentheses
437                                         // (if a single declaration is parenthesized,
438                                         // create a new fake declaration below, so that
439                                         // go/doc type declarations always appear w/o
440                                         // parentheses)
441                                         if s, ok := d.Specs[0].(*ast.TypeSpec); ok {
442                                                 r.readType(d, s)
443                                         }
444                                         break
445                                 }
446                                 for _, spec := range d.Specs {
447                                         if s, ok := spec.(*ast.TypeSpec); ok {
448                                                 // use an individual (possibly fake) declaration
449                                                 // for each type; this also ensures that each type
450                                                 // gets to (re-)use the declaration documentation
451                                                 // if there's none associated with the spec itself
452                                                 fake := &ast.GenDecl{
453                                                         Doc: d.Doc,
454                                                         // don't use the existing TokPos because it
455                                                         // will lead to the wrong selection range for
456                                                         // the fake declaration if there are more
457                                                         // than one type in the group (this affects
458                                                         // src/cmd/godoc/godoc.go's posLink_urlFunc)
459                                                         TokPos: s.Pos(),
460                                                         Tok:    token.TYPE,
461                                                         Specs:  []ast.Spec{s},
462                                                 }
463                                                 r.readType(fake, s)
464                                         }
465                                 }
466                         }
467                 case *ast.FuncDecl:
468                         r.readFunc(d)
469                 }
470         }
471
472         // collect BUG(...) comments
473         for _, c := range src.Comments {
474                 text := c.List[0].Text
475                 if m := bug_markers.FindStringIndex(text); m != nil {
476                         // found a BUG comment; maybe empty
477                         if btxt := text[m[1]:]; bug_content.MatchString(btxt) {
478                                 // non-empty BUG comment; collect comment without BUG prefix
479                                 list := append([]*ast.Comment(nil), c.List...) // make a copy
480                                 list[0].Text = text[m[1]:]
481                                 r.bugs = append(r.bugs, (&ast.CommentGroup{List: list}).Text())
482                         }
483                 }
484         }
485         src.Comments = nil // consumed unassociated comments - remove from AST
486 }
487
488 func (r *reader) readPackage(pkg *ast.Package, mode Mode) {
489         // initialize reader
490         r.filenames = make([]string, len(pkg.Files))
491         r.imports = make(map[string]int)
492         r.mode = mode
493         r.types = make(map[string]*namedType)
494         r.funcs = make(methodSet)
495
496         // sort package files before reading them so that the
497         // result result does not depend on map iteration order
498         i := 0
499         for filename := range pkg.Files {
500                 r.filenames[i] = filename
501                 i++
502         }
503         sort.Strings(r.filenames)
504
505         // process files in sorted order
506         for _, filename := range r.filenames {
507                 f := pkg.Files[filename]
508                 if mode&AllDecls == 0 {
509                         r.fileExports(f)
510                 }
511                 r.readFile(f)
512         }
513 }
514
515 // ----------------------------------------------------------------------------
516 // Types
517
518 var predeclaredTypes = map[string]bool{
519         "bool":       true,
520         "byte":       true,
521         "complex64":  true,
522         "complex128": true,
523         "error":      true,
524         "float32":    true,
525         "float64":    true,
526         "int":        true,
527         "int8":       true,
528         "int16":      true,
529         "int32":      true,
530         "int64":      true,
531         "rune":       true,
532         "string":     true,
533         "uint":       true,
534         "uint8":      true,
535         "uint16":     true,
536         "uint32":     true,
537         "uint64":     true,
538         "uintptr":    true,
539 }
540
541 func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int) *Func {
542         if f == nil || f.Decl == nil || f.Decl.Recv == nil || len(f.Decl.Recv.List) != 1 {
543                 return f // shouldn't happen, but be safe
544         }
545
546         // copy existing receiver field and set new type
547         newField := *f.Decl.Recv.List[0]
548         _, origRecvIsPtr := newField.Type.(*ast.StarExpr)
549         var typ ast.Expr = ast.NewIdent(recvTypeName)
550         if !embeddedIsPtr && origRecvIsPtr {
551                 typ = &ast.StarExpr{X: typ}
552         }
553         newField.Type = typ
554
555         // copy existing receiver field list and set new receiver field
556         newFieldList := *f.Decl.Recv
557         newFieldList.List = []*ast.Field{&newField}
558
559         // copy existing function declaration and set new receiver field list
560         newFuncDecl := *f.Decl
561         newFuncDecl.Recv = &newFieldList
562
563         // copy existing function documentation and set new declaration
564         newF := *f
565         newF.Decl = &newFuncDecl
566         newF.Recv = recvString(typ)
567         // the Orig field never changes
568         newF.Level = level
569
570         return &newF
571 }
572
573 // collectEmbeddedMethods collects the embedded methods of typ in mset.
574 //
575 func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvTypeName string, embeddedIsPtr bool, level int, visited embeddedSet) {
576         visited[typ] = true
577         for embedded, isPtr := range typ.embedded {
578                 // Once an embedded type is embedded as a pointer type
579                 // all embedded types in those types are treated like
580                 // pointer types for the purpose of the receiver type
581                 // computation; i.e., embeddedIsPtr is sticky for this
582                 // embedding hierarchy.
583                 thisEmbeddedIsPtr := embeddedIsPtr || isPtr
584                 for _, m := range embedded.methods {
585                         // only top-level methods are embedded
586                         if m.Level == 0 {
587                                 mset.add(customizeRecv(m, recvTypeName, thisEmbeddedIsPtr, level))
588                         }
589                 }
590                 if !visited[embedded] {
591                         r.collectEmbeddedMethods(mset, embedded, recvTypeName, thisEmbeddedIsPtr, level+1, visited)
592                 }
593         }
594         delete(visited, typ)
595 }
596
597 // computeMethodSets determines the actual method sets for each type encountered.
598 //
599 func (r *reader) computeMethodSets() {
600         for _, t := range r.types {
601                 // collect embedded methods for t
602                 if t.isStruct {
603                         // struct
604                         r.collectEmbeddedMethods(t.methods, t, t.name, false, 1, make(embeddedSet))
605                 } else {
606                         // interface
607                         // TODO(gri) fix this
608                 }
609         }
610
611         // if error was declared locally, don't treat it as exported field anymore
612         if r.errorDecl {
613                 for _, ityp := range r.fixlist {
614                         removeErrorField(ityp)
615                 }
616         }
617 }
618
619 // cleanupTypes removes the association of functions and methods with
620 // types that have no declaration. Instead, these functions and methods
621 // are shown at the package level. It also removes types with missing
622 // declarations or which are not visible.
623 // 
624 func (r *reader) cleanupTypes() {
625         for _, t := range r.types {
626                 visible := r.isVisible(t.name)
627                 if t.decl == nil && (predeclaredTypes[t.name] || t.isEmbedded && visible) {
628                         // t.name is a predeclared type (and was not redeclared in this package),
629                         // or it was embedded somewhere but its declaration is missing (because
630                         // the AST is incomplete): move any associated values, funcs, and methods
631                         // back to the top-level so that they are not lost.
632                         // 1) move values
633                         r.values = append(r.values, t.values...)
634                         // 2) move factory functions
635                         for name, f := range t.funcs {
636                                 // in a correct AST, package-level function names
637                                 // are all different - no need to check for conflicts
638                                 r.funcs[name] = f
639                         }
640                         // 3) move methods
641                         for name, m := range t.methods {
642                                 // don't overwrite functions with the same name - drop them
643                                 if _, found := r.funcs[name]; !found {
644                                         r.funcs[name] = m
645                                 }
646                         }
647                 }
648                 // remove types w/o declaration or which are not visible
649                 if t.decl == nil || !visible {
650                         delete(r.types, t.name)
651                 }
652         }
653 }
654
655 // ----------------------------------------------------------------------------
656 // Sorting
657
658 type data struct {
659         n    int
660         swap func(i, j int)
661         less func(i, j int) bool
662 }
663
664 func (d *data) Len() int           { return d.n }
665 func (d *data) Swap(i, j int)      { d.swap(i, j) }
666 func (d *data) Less(i, j int) bool { return d.less(i, j) }
667
668 // sortBy is a helper function for sorting
669 func sortBy(less func(i, j int) bool, swap func(i, j int), n int) {
670         sort.Sort(&data{n, swap, less})
671 }
672
673 func sortedKeys(m map[string]int) []string {
674         list := make([]string, len(m))
675         i := 0
676         for key := range m {
677                 list[i] = key
678                 i++
679         }
680         sort.Strings(list)
681         return list
682 }
683
684 // sortingName returns the name to use when sorting d into place.
685 //
686 func sortingName(d *ast.GenDecl) string {
687         if len(d.Specs) == 1 {
688                 if s, ok := d.Specs[0].(*ast.ValueSpec); ok {
689                         return s.Names[0].Name
690                 }
691         }
692         return ""
693 }
694
695 func sortedValues(m []*Value, tok token.Token) []*Value {
696         list := make([]*Value, len(m)) // big enough in any case
697         i := 0
698         for _, val := range m {
699                 if val.Decl.Tok == tok {
700                         list[i] = val
701                         i++
702                 }
703         }
704         list = list[0:i]
705
706         sortBy(
707                 func(i, j int) bool {
708                         if ni, nj := sortingName(list[i].Decl), sortingName(list[j].Decl); ni != nj {
709                                 return ni < nj
710                         }
711                         return list[i].order < list[j].order
712                 },
713                 func(i, j int) { list[i], list[j] = list[j], list[i] },
714                 len(list),
715         )
716
717         return list
718 }
719
720 func sortedTypes(m map[string]*namedType, allMethods bool) []*Type {
721         list := make([]*Type, len(m))
722         i := 0
723         for _, t := range m {
724                 list[i] = &Type{
725                         Doc:     t.doc,
726                         Name:    t.name,
727                         Decl:    t.decl,
728                         Consts:  sortedValues(t.values, token.CONST),
729                         Vars:    sortedValues(t.values, token.VAR),
730                         Funcs:   sortedFuncs(t.funcs, true),
731                         Methods: sortedFuncs(t.methods, allMethods),
732                 }
733                 i++
734         }
735
736         sortBy(
737                 func(i, j int) bool { return list[i].Name < list[j].Name },
738                 func(i, j int) { list[i], list[j] = list[j], list[i] },
739                 len(list),
740         )
741
742         return list
743 }
744
745 func removeStar(s string) string {
746         if len(s) > 0 && s[0] == '*' {
747                 return s[1:]
748         }
749         return s
750 }
751
752 func sortedFuncs(m methodSet, allMethods bool) []*Func {
753         list := make([]*Func, len(m))
754         i := 0
755         for _, m := range m {
756                 // determine which methods to include
757                 switch {
758                 case m.Decl == nil:
759                         // exclude conflict entry
760                 case allMethods, m.Level == 0, !ast.IsExported(removeStar(m.Orig)):
761                         // forced inclusion, method not embedded, or method
762                         // embedded but original receiver type not exported
763                         list[i] = m
764                         i++
765                 }
766         }
767         list = list[0:i]
768         sortBy(
769                 func(i, j int) bool { return list[i].Name < list[j].Name },
770                 func(i, j int) { list[i], list[j] = list[j], list[i] },
771                 len(list),
772         )
773         return list
774 }