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