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