1// Copyright 2011 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// Api computes the exported API of a set of Go packages. 6 7//modify 2013-2014 visualfc 8 9package goapi 10 11import ( 12 "bufio" 13 "bytes" 14 "fmt" 15 "go/ast" 16 "go/build" 17 "go/doc" 18 "go/parser" 19 "go/printer" 20 "go/token" 21 "io" 22 "io/ioutil" 23 "log" 24 "os" 25 "os/exec" 26 "path" 27 "path/filepath" 28 "regexp" 29 "sort" 30 "strconv" 31 "strings" 32 "time" 33 34 "github.com/visualfc/gotools/pkg/command" 35) 36 37var Command = &command.Command{ 38 Run: runApi, 39 UsageLine: "goapi", 40 Short: "golang api util", 41 Long: `golang api util`, 42} 43 44var apiVerbose bool 45var apiAllmethods bool 46var apiAlldecls bool 47var apiShowpos bool 48var apiSeparate string 49var apiImportParser bool 50var apiDefaultCtx bool 51var apiCustomCtx string 52var apiLookupInfo string 53var apiLookupStdin bool 54var apiOutput string 55 56func init() { 57 Command.Flag.BoolVar(&apiVerbose, "v", false, "verbose debugging") 58 Command.Flag.BoolVar(&apiAllmethods, "e", true, "extract for all embedded methods") 59 Command.Flag.BoolVar(&apiAlldecls, "a", false, "extract for all declarations") 60 Command.Flag.BoolVar(&apiShowpos, "pos", false, "addition token position") 61 Command.Flag.StringVar(&apiSeparate, "sep", ", ", "setup separators") 62 Command.Flag.BoolVar(&apiImportParser, "dep", true, "parser package imports") 63 Command.Flag.BoolVar(&apiDefaultCtx, "default_ctx", true, "extract for default context") 64 Command.Flag.StringVar(&apiCustomCtx, "custom_ctx", "", "optional comma-separated list of <goos>-<goarch>[-cgo] to override default contexts.") 65 Command.Flag.StringVar(&apiLookupInfo, "cursor_info", "", "lookup cursor node info\"file.go:pos\"") 66 Command.Flag.BoolVar(&apiLookupStdin, "cursor_std", false, "cursor_info use stdin") 67 Command.Flag.StringVar(&apiOutput, "o", "", "output file") 68} 69 70func runApi(cmd *command.Command, args []string) error { 71 if len(args) == 0 && apiLookupInfo == "" { 72 cmd.Usage() 73 return os.ErrInvalid 74 } 75 if apiVerbose { 76 now := time.Now() 77 defer func() { 78 log.Println("time", time.Now().Sub(now)) 79 }() 80 } 81 82 var pkgs []string 83 if len(args) > 0 { 84 if args[0] == "std" || args[0] == "all" { 85 out, err := exec.Command("go", "list", "-e", args[0]).Output() 86 if err != nil { 87 log.Fatal(err) 88 } 89 pkgs = strings.Fields(string(out)) 90 } else { 91 pkgs = args 92 } 93 } 94 var curinfo CursorInfo 95 if apiLookupInfo != "" { 96 pos := strings.Index(apiLookupInfo, ":") 97 if pos != -1 { 98 curinfo.file = (apiLookupInfo)[:pos] 99 if i, err := strconv.Atoi((apiLookupInfo)[pos+1:]); err == nil { 100 curinfo.pos = token.Pos(i) 101 } 102 } 103 } 104 105 if len(pkgs) == 1 && curinfo.pos != token.NoPos { 106 curinfo.pkg = pkgs[0] 107 } 108 109 if apiLookupStdin { 110 src, err := ioutil.ReadAll(os.Stdin) 111 if err == nil { 112 curinfo.src = src 113 curinfo.std = true 114 } 115 } 116 117 if apiCustomCtx != "" { 118 apiDefaultCtx = false 119 setCustomContexts() 120 } 121 122 var features []string 123 w := NewWalker() 124 if curinfo.pkg != "" { 125 w.cursorInfo = &curinfo 126 } 127 w.sep = apiSeparate 128 129 if apiDefaultCtx { 130 w.context = &build.Default 131 132 for _, pkg := range pkgs { 133 w.wantedPkg[pkg] = true 134 } 135 136 for _, pkg := range pkgs { 137 w.WalkPackage(pkg) 138 } 139 if w.cursorInfo != nil { 140 goto lookup 141 } else { 142 var file io.Writer 143 if apiOutput != "" { 144 var err error 145 file, err = os.Create(apiOutput) 146 if err != nil { 147 log.Fatal(err) 148 } 149 } else { 150 file = os.Stdout 151 } 152 bw := bufio.NewWriter(file) 153 defer bw.Flush() 154 for _, p := range w.packageMap { 155 if w.wantedPkg[p.name] { 156 for _, f := range p.Features() { 157 fmt.Fprintf(bw, "%s\n", f) 158 } 159 } 160 } 161 return nil 162 } 163 features = w.Features("") 164 } else { 165 for _, c := range contexts { 166 c.Compiler = build.Default.Compiler 167 } 168 169 for _, pkg := range pkgs { 170 w.wantedPkg[pkg] = true 171 } 172 173 var featureCtx = make(map[string]map[string]bool) // feature -> context name -> true 174 for _, context := range contexts { 175 w.context = context 176 w.ctxName = contextName(w.context) + ":" 177 178 for _, pkg := range pkgs { 179 w.WalkPackage(pkg) 180 } 181 if w.cursorInfo != nil && w.cursorInfo.info != nil { 182 goto lookup 183 } 184 } 185 186 for pkg, p := range w.packageMap { 187 if w.wantedPkg[p.name] { 188 pos := strings.Index(pkg, ":") 189 if pos == -1 { 190 continue 191 } 192 ctxName := pkg[:pos] 193 for _, f := range p.Features() { 194 if featureCtx[f] == nil { 195 featureCtx[f] = make(map[string]bool) 196 } 197 featureCtx[f][ctxName] = true 198 } 199 } 200 } 201 202 for f, cmap := range featureCtx { 203 if len(cmap) == len(contexts) { 204 features = append(features, f) 205 continue 206 } 207 comma := strings.Index(f, ",") 208 for cname := range cmap { 209 f2 := fmt.Sprintf("%s (%s)%s", f[:comma], cname, f[comma:]) 210 features = append(features, f2) 211 } 212 } 213 sort.Strings(features) 214 } 215 216lookup: 217 if w.cursorInfo != nil { 218 info := w.cursorInfo.info 219 if info == nil { 220 os.Exit(1) 221 return os.ErrInvalid 222 } 223 // fmt.Println("kind,", info.Kind) 224 // fmt.Println("name,", info.Name) 225 // if info.Type != "" { 226 // fmt.Println("type,", strings.TrimLeft(info.Type, "*")) 227 // } 228 if info.Name == info.Type || info.Type == "" { 229 fmt.Printf("info, %s, %s\n", info.Kind, info.Name) 230 } else { 231 fmt.Printf("info, %s, %s, %s\n", info.Kind, info.Name, info.Type) 232 } 233 if info.Kind == KindImport || info.Kind == KindPackage { 234 if p := w.findPackage(info.Name); p != nil { 235 fmt.Println("help,", p.name) 236 } 237 } 238 if info.T != nil { 239 for _, text := range []string{info.Name, info.Type} { 240 typ := strings.TrimLeft(text, "*") 241 pos := strings.Index(typ, ".") 242 if pos != -1 { 243 if p := w.findPackage(typ[:pos]); p != nil { 244 fmt.Println("help,", p.name+typ[pos:]) 245 break 246 } 247 } 248 } 249 fmt.Println("pos,", w.fset.Position(info.T.Pos())) 250 } 251 return nil 252 } 253 254 fail := false 255 defer func() { 256 if fail { 257 os.Exit(1) 258 } 259 }() 260 261 bw := bufio.NewWriter(os.Stdout) 262 defer bw.Flush() 263 264 for _, f := range features { 265 fmt.Fprintf(bw, "%s\n", f) 266 } 267 return nil 268} 269 270type CursorInfo struct { 271 pkg string 272 file string 273 pos token.Pos 274 src []byte 275 std bool 276 info *TypeInfo 277} 278 279// contexts are the default contexts which are scanned, unless 280// overridden by the -contexts flag. 281var contexts = []*build.Context{ 282 {GOOS: "linux", GOARCH: "386", CgoEnabled: true}, 283 {GOOS: "linux", GOARCH: "386"}, 284 {GOOS: "linux", GOARCH: "amd64", CgoEnabled: true}, 285 {GOOS: "linux", GOARCH: "amd64"}, 286 {GOOS: "linux", GOARCH: "arm"}, 287 {GOOS: "darwin", GOARCH: "386", CgoEnabled: true}, 288 {GOOS: "darwin", GOARCH: "386"}, 289 {GOOS: "darwin", GOARCH: "amd64", CgoEnabled: true}, 290 {GOOS: "darwin", GOARCH: "amd64"}, 291 {GOOS: "windows", GOARCH: "amd64"}, 292 {GOOS: "windows", GOARCH: "386"}, 293 {GOOS: "freebsd", GOARCH: "amd64"}, 294 {GOOS: "freebsd", GOARCH: "386"}, 295} 296 297func contextName(c *build.Context) string { 298 s := c.GOOS + "-" + c.GOARCH 299 if c.CgoEnabled { 300 return s + "-cgo" 301 } 302 return s 303} 304 305func osArchName(c *build.Context) string { 306 return c.GOOS + "-" + c.GOARCH 307} 308 309func parseContext(c string) *build.Context { 310 parts := strings.Split(c, "-") 311 if len(parts) < 2 { 312 log.Fatalf("bad context: %q", c) 313 } 314 bc := &build.Context{ 315 GOOS: parts[0], 316 GOARCH: parts[1], 317 } 318 if len(parts) == 3 { 319 if parts[2] == "cgo" { 320 bc.CgoEnabled = true 321 } else { 322 log.Fatalf("bad context: %q", c) 323 } 324 } 325 return bc 326} 327 328func setCustomContexts() { 329 contexts = []*build.Context{} 330 for _, c := range strings.Split(apiCustomCtx, ",") { 331 contexts = append(contexts, parseContext(c)) 332 } 333} 334 335func set(items []string) map[string]bool { 336 s := make(map[string]bool) 337 for _, v := range items { 338 s[v] = true 339 } 340 return s 341} 342 343var spaceParensRx = regexp.MustCompile(` \(\S+?\)`) 344 345func featureWithoutContext(f string) string { 346 if !strings.Contains(f, "(") { 347 return f 348 } 349 return spaceParensRx.ReplaceAllString(f, "") 350} 351 352func compareAPI(w io.Writer, features, required, optional, exception []string, allowNew bool) (ok bool) { 353 ok = true 354 355 optionalSet := set(optional) 356 exceptionSet := set(exception) 357 featureSet := set(features) 358 359 sort.Strings(features) 360 sort.Strings(required) 361 362 take := func(sl *[]string) string { 363 s := (*sl)[0] 364 *sl = (*sl)[1:] 365 return s 366 } 367 368 for len(required) > 0 || len(features) > 0 { 369 switch { 370 case len(features) == 0 || (len(required) > 0 && required[0] < features[0]): 371 feature := take(&required) 372 if exceptionSet[feature] { 373 fmt.Fprintf(w, "~%s\n", feature) 374 } else if featureSet[featureWithoutContext(feature)] { 375 // okay. 376 } else { 377 fmt.Fprintf(w, "-%s\n", feature) 378 ok = false // broke compatibility 379 } 380 case len(required) == 0 || (len(features) > 0 && required[0] > features[0]): 381 newFeature := take(&features) 382 if optionalSet[newFeature] { 383 // Known added feature to the upcoming release. 384 // Delete it from the map so we can detect any upcoming features 385 // which were never seen. (so we can clean up the nextFile) 386 delete(optionalSet, newFeature) 387 } else { 388 fmt.Fprintf(w, "+%s\n", newFeature) 389 if !allowNew { 390 ok = false // we're in lock-down mode for next release 391 } 392 } 393 default: 394 take(&required) 395 take(&features) 396 } 397 } 398 399 // In next file, but not in API. 400 var missing []string 401 for feature := range optionalSet { 402 missing = append(missing, feature) 403 } 404 sort.Strings(missing) 405 for _, feature := range missing { 406 fmt.Fprintf(w, "±%s\n", feature) 407 } 408 return 409} 410 411func fileFeatures(filename string) []string { 412 bs, err := ioutil.ReadFile(filename) 413 if err != nil { 414 log.Fatalf("Error reading file %s: %v", filename, err) 415 } 416 text := strings.TrimSpace(string(bs)) 417 if text == "" { 418 return nil 419 } 420 return strings.Split(text, "\n") 421} 422 423func isExtract(name string) bool { 424 if apiAlldecls { 425 return true 426 } 427 return ast.IsExported(name) 428} 429 430// pkgSymbol represents a symbol in a package 431type pkgSymbol struct { 432 pkg string // "net/http" 433 symbol string // "RoundTripper" 434} 435 436//expression kind 437type Kind int 438 439const ( 440 KindBuiltin Kind = iota 441 KindPackage 442 KindImport 443 KindVar 444 KindConst 445 KindInterface 446 KindParam 447 KindStruct 448 KindMethod 449 KindField 450 KindType 451 KindFunc 452 KindChan 453 KindArray 454 KindMap 455 KindSlice 456 KindLabel 457 KindBranch 458) 459 460func (k Kind) String() string { 461 switch k { 462 case KindBuiltin: 463 return "builtin" 464 case KindPackage: 465 return "package" 466 case KindImport: 467 return "import" 468 case KindVar: 469 return "var" 470 case KindConst: 471 return "const" 472 case KindParam: 473 return "param" 474 case KindInterface: 475 return "interface" 476 case KindStruct: 477 return "struct" 478 case KindMethod: 479 return "method" 480 case KindField: 481 return "field" 482 case KindType: 483 return "type" 484 case KindFunc: 485 return "func" 486 case KindChan: 487 return "chan" 488 case KindMap: 489 return "map" 490 case KindArray: 491 return "array" 492 case KindSlice: 493 return "slice" 494 case KindLabel: 495 return "label" 496 case KindBranch: 497 return "branch" 498 } 499 return fmt.Sprint("unknown-kind") 500} 501 502//expression type 503type TypeInfo struct { 504 Kind Kind 505 Name string 506 Type string 507 X ast.Expr 508 T ast.Expr 509} 510 511type ExprType struct { 512 X ast.Expr 513 T string 514} 515 516type Package struct { 517 dpkg *doc.Package 518 apkg *ast.Package 519 interfaceMethods map[string]([]typeMethod) 520 interfaces map[string]*ast.InterfaceType //interface 521 structs map[string]*ast.StructType //struct 522 types map[string]ast.Expr //type 523 functions map[string]typeMethod //function 524 consts map[string]*ExprType //const => type 525 vars map[string]*ExprType //var => type 526 name string 527 dir string 528 sep string 529 deps []string 530 features map[string](token.Pos) // set 531} 532 533func NewPackage() *Package { 534 return &Package{ 535 interfaceMethods: make(map[string]([]typeMethod)), 536 interfaces: make(map[string]*ast.InterfaceType), 537 structs: make(map[string]*ast.StructType), 538 types: make(map[string]ast.Expr), 539 functions: make(map[string]typeMethod), 540 consts: make(map[string]*ExprType), 541 vars: make(map[string]*ExprType), 542 features: make(map[string](token.Pos)), 543 sep: ", ", 544 } 545} 546 547func (p *Package) Features() (fs []string) { 548 for f, ps := range p.features { 549 if apiShowpos { 550 fs = append(fs, f+p.sep+strconv.Itoa(int(ps))) 551 } else { 552 fs = append(fs, f) 553 } 554 } 555 sort.Strings(fs) 556 return 557} 558 559func (p *Package) findType(name string) ast.Expr { 560 for k, v := range p.interfaces { 561 if k == name { 562 return v 563 } 564 } 565 for k, v := range p.structs { 566 if k == name { 567 return v 568 } 569 } 570 for k, v := range p.types { 571 if k == name { 572 return v 573 } 574 } 575 return nil 576} 577 578func funcRetType(ft *ast.FuncType, index int) ast.Expr { 579 if ft.Results != nil { 580 pos := 0 581 for _, fi := range ft.Results.List { 582 if fi.Names == nil { 583 if pos == index { 584 return fi.Type 585 } 586 pos++ 587 } else { 588 for _ = range fi.Names { 589 if pos == index { 590 return fi.Type 591 } 592 pos++ 593 } 594 } 595 } 596 } 597 return nil 598} 599 600func findFunction(funcs []*doc.Func, name string) (*ast.Ident, *ast.FuncType) { 601 for _, f := range funcs { 602 if f.Name == name { 603 return &ast.Ident{Name: name, NamePos: f.Decl.Pos()}, f.Decl.Type 604 } 605 } 606 return nil, nil 607} 608 609func (p *Package) findSelectorType(name string) ast.Expr { 610 if t, ok := p.vars[name]; ok { 611 return &ast.Ident{ 612 NamePos: t.X.Pos(), 613 Name: t.T, 614 } 615 } 616 if t, ok := p.consts[name]; ok { 617 return &ast.Ident{ 618 NamePos: t.X.Pos(), 619 Name: t.T, 620 } 621 } 622 if t, ok := p.functions[name]; ok { 623 return t.ft 624 } 625 for k, v := range p.structs { 626 if k == name { 627 return &ast.Ident{ 628 NamePos: v.Pos(), 629 Name: name, 630 } 631 } 632 } 633 for k, v := range p.interfaces { 634 if k == name { 635 return &ast.Ident{ 636 NamePos: v.Pos(), 637 Name: name, 638 } 639 } 640 } 641 for k, v := range p.types { 642 if k == name { 643 return v 644 } 645 } 646 return nil 647} 648 649func (p *Package) findCallFunc(name string) ast.Expr { 650 if fn, ok := p.functions[name]; ok { 651 return fn.ft 652 } 653 if s, ok := p.structs[name]; ok { 654 return s 655 } 656 if t, ok := p.types[name]; ok { 657 return t 658 } 659 if v, ok := p.vars[name]; ok { 660 if strings.HasPrefix(v.T, "func(") { 661 e, err := parser.ParseExpr(v.T + "{}") 662 if err == nil { 663 return e 664 } 665 } 666 } 667 return nil 668} 669 670func (p *Package) findCallType(name string, index int) ast.Expr { 671 if fn, ok := p.functions[name]; ok { 672 return funcRetType(fn.ft, index) 673 } 674 if s, ok := p.structs[name]; ok { 675 return &ast.Ident{ 676 NamePos: s.Pos(), 677 Name: name, 678 } 679 } 680 if t, ok := p.types[name]; ok { 681 return &ast.Ident{ 682 NamePos: t.Pos(), 683 Name: name, 684 } 685 } 686 return nil 687} 688 689func (p *Package) findMethod(typ, name string) (*ast.Ident, *ast.FuncType) { 690 if t, ok := p.interfaces[typ]; ok && t.Methods != nil { 691 for _, fd := range t.Methods.List { 692 switch ft := fd.Type.(type) { 693 case *ast.FuncType: 694 for _, ident := range fd.Names { 695 if ident.Name == name { 696 return ident, ft 697 } 698 } 699 } 700 } 701 } 702 for k, v := range p.interfaceMethods { 703 if k == typ { 704 for _, m := range v { 705 if m.name == name { 706 return &ast.Ident{Name: name, NamePos: m.pos}, m.ft 707 } 708 } 709 } 710 } 711 if p.dpkg == nil { 712 return nil, nil 713 } 714 for _, t := range p.dpkg.Types { 715 if t.Name == typ { 716 return findFunction(t.Methods, name) 717 } 718 } 719 return nil, nil 720} 721 722type Walker struct { 723 context *build.Context 724 fset *token.FileSet 725 scope []string 726 // features map[string](token.Pos) // set 727 lastConstType string 728 curPackageName string 729 sep string 730 ctxName string 731 curPackage *Package 732 constDep map[string]*ExprType // key's const identifier has type of future value const identifier 733 packageState map[string]loadState 734 packageMap map[string]*Package 735 interfaces map[pkgSymbol]*ast.InterfaceType 736 selectorFullPkg map[string]string // "http" => "net/http", updated by imports 737 wantedPkg map[string]bool // packages requested on the command line 738 cursorInfo *CursorInfo 739 localvar map[string]*ExprType 740} 741 742func NewWalker() *Walker { 743 return &Walker{ 744 fset: token.NewFileSet(), 745 // features: make(map[string]token.Pos), 746 packageState: make(map[string]loadState), 747 interfaces: make(map[pkgSymbol]*ast.InterfaceType), 748 packageMap: make(map[string]*Package), 749 selectorFullPkg: make(map[string]string), 750 wantedPkg: make(map[string]bool), 751 localvar: make(map[string]*ExprType), 752 sep: ", ", 753 } 754} 755 756// loadState is the state of a package's parsing. 757type loadState int 758 759const ( 760 notLoaded loadState = iota 761 loading 762 loaded 763) 764 765func (w *Walker) Features(ctx string) (fs []string) { 766 for pkg, p := range w.packageMap { 767 if w.wantedPkg[p.name] { 768 if ctx == "" || strings.HasPrefix(pkg, ctx) { 769 fs = append(fs, p.Features()...) 770 } 771 } 772 } 773 sort.Strings(fs) 774 return 775} 776 777// fileDeps returns the imports in a file. 778func fileDeps(f *ast.File) (pkgs []string) { 779 for _, is := range f.Imports { 780 fpkg, err := strconv.Unquote(is.Path.Value) 781 if err != nil { 782 log.Fatalf("error unquoting import string %q: %v", is.Path.Value, err) 783 } 784 if fpkg != "C" { 785 pkgs = append(pkgs, fpkg) 786 } 787 } 788 return 789} 790 791func (w *Walker) findPackage(pkg string) *Package { 792 if full, ok := w.selectorFullPkg[pkg]; ok { 793 if w.ctxName != "" { 794 ctxName := w.ctxName + full 795 for k, v := range w.packageMap { 796 if k == ctxName { 797 return v 798 } 799 } 800 } 801 for k, v := range w.packageMap { 802 if k == full { 803 return v 804 } 805 } 806 } 807 return nil 808} 809 810func (w *Walker) findPackageOSArch(pkg string) *Package { 811 if full, ok := w.selectorFullPkg[pkg]; ok { 812 ctxName := osArchName(w.context) + ":" + full 813 for k, v := range w.packageMap { 814 if k == ctxName { 815 return v 816 } 817 } 818 } 819 return nil 820} 821 822// WalkPackage walks all files in package `name'. 823// WalkPackage does nothing if the package has already been loaded. 824 825func (w *Walker) WalkPackage(pkg string) { 826 if build.IsLocalImport(pkg) { 827 wd, err := os.Getwd() 828 if err != nil { 829 if apiVerbose { 830 log.Println(err) 831 } 832 return 833 } 834 dir := filepath.Clean(filepath.Join(wd, pkg)) 835 bp, err := w.context.ImportDir(dir, 0) 836 if err != nil { 837 if apiVerbose { 838 log.Println(err) 839 } 840 return 841 } 842 if w.wantedPkg[pkg] == true { 843 w.wantedPkg[bp.Name] = true 844 delete(w.wantedPkg, pkg) 845 } 846 if w.cursorInfo != nil && w.cursorInfo.pkg == pkg { 847 w.cursorInfo.pkg = bp.Name 848 } 849 w.WalkPackageDir(bp.Name, bp.Dir, bp) 850 } else if filepath.IsAbs(pkg) { 851 bp, err := build.ImportDir(pkg, 0) 852 if err != nil { 853 if apiVerbose { 854 log.Println(err) 855 } 856 } 857 if w.wantedPkg[pkg] == true { 858 w.wantedPkg[bp.Name] = true 859 delete(w.wantedPkg, pkg) 860 } 861 if w.cursorInfo != nil && w.cursorInfo.pkg == pkg { 862 w.cursorInfo.pkg = bp.Name 863 } 864 865 w.WalkPackageDir(bp.Name, bp.Dir, bp) 866 } else { 867 bp, err := build.Import(pkg, "", build.FindOnly) 868 if err != nil { 869 if apiVerbose { 870 log.Println(err) 871 } 872 return 873 } 874 w.WalkPackageDir(pkg, bp.Dir, nil) 875 } 876} 877 878func (w *Walker) WalkPackageDir(name string, dir string, bp *build.Package) { 879 ctxName := w.ctxName + name 880 curName := name 881 switch w.packageState[ctxName] { 882 case loading: 883 log.Fatalf("import cycle loading package %q?", name) 884 return 885 case loaded: 886 return 887 } 888 w.packageState[ctxName] = loading 889 w.selectorFullPkg[name] = name 890 891 defer func() { 892 w.packageState[ctxName] = loaded 893 }() 894 895 sname := name[strings.LastIndexAny(name, ".-/\\")+1:] 896 897 apkg := &ast.Package{ 898 Files: make(map[string]*ast.File), 899 } 900 if bp == nil { 901 bp, _ = w.context.ImportDir(dir, 0) 902 } 903 if bp == nil { 904 return 905 } 906 if w.ctxName != "" { 907 isCgo := (len(bp.CgoFiles) > 0) && w.context.CgoEnabled 908 if isCgo { 909 curName = ctxName 910 } else { 911 isOSArch := false 912 for _, file := range bp.GoFiles { 913 if isOSArchFile(w.context, file) { 914 isOSArch = true 915 break 916 } 917 } 918 var p *Package 919 if isOSArch { 920 curName = osArchName(w.context) + ":" + name 921 p = w.findPackageOSArch(name) 922 } else { 923 curName = name 924 p = w.findPackage(name) 925 } 926 if p != nil { 927 if apiImportParser { 928 for _, dep := range p.deps { 929 if _, ok := w.packageState[dep]; ok { 930 continue 931 } 932 w.WalkPackage(dep) 933 } 934 } 935 w.packageMap[ctxName] = p 936 return 937 } 938 } 939 } 940 941 files := append(append([]string{}, bp.GoFiles...), bp.CgoFiles...) 942 943 if w.cursorInfo != nil && w.cursorInfo.pkg == name { 944 files = append(files, bp.TestGoFiles...) 945 for _, v := range bp.XTestGoFiles { 946 if v == w.cursorInfo.file { 947 var xbp build.Package 948 xbp.Name = name + "_test" 949 xbp.GoFiles = append(xbp.GoFiles, bp.XTestGoFiles...) 950 w.cursorInfo.pkg = xbp.Name 951 w.WalkPackageDir(xbp.Name, dir, &xbp) 952 break 953 } 954 } 955 } 956 957 if len(files) == 0 { 958 if apiVerbose { 959 log.Println("no Go source files in", bp.Dir) 960 } 961 return 962 } 963 var deps []string 964 965 for _, file := range files { 966 var src interface{} = nil 967 if w.cursorInfo != nil && 968 w.cursorInfo.pkg == name && 969 w.cursorInfo.file == file && 970 w.cursorInfo.std { 971 src = w.cursorInfo.src 972 } 973 f, err := parser.ParseFile(w.fset, filepath.Join(dir, file), src, 0) 974 if err != nil { 975 if apiVerbose { 976 log.Printf("error parsing package %s, file %s: %v", name, file, err) 977 } 978 } 979 980 if sname != f.Name.Name { 981 continue 982 } 983 apkg.Files[file] = f 984 if apiImportParser { 985 deps = fileDeps(f) 986 for _, dep := range deps { 987 if _, ok := w.packageState[dep]; ok { 988 continue 989 } 990 w.WalkPackage(dep) 991 } 992 } 993 if apiShowpos && w.wantedPkg[name] { 994 tf := w.fset.File(f.Pos()) 995 if tf != nil { 996 fmt.Printf("pos %s%s%s%s%d%s%d\n", name, w.sep, filepath.Join(dir, file), w.sep, tf.Base(), w.sep, tf.Size()) 997 } 998 } 999 } 1000 /* else { 1001 fdir, err := os.Open(dir) 1002 if err != nil { 1003 log.Fatalln(err) 1004 } 1005 infos, err := fdir.Readdir(-1) 1006 fdir.Close() 1007 if err != nil { 1008 log.Fatalln(err) 1009 } 1010 1011 for _, info := range infos { 1012 if info.IsDir() { 1013 continue 1014 } 1015 file := info.Name() 1016 if strings.HasPrefix(file, "_") || strings.HasSuffix(file, "_test.go") { 1017 continue 1018 } 1019 if strings.HasSuffix(file, ".go") { 1020 f, err := parser.ParseFile(w.fset, filepath.Join(dir, file), nil, 0) 1021 if err != nil { 1022 if apiVerbose { 1023 log.Printf("error parsing package %s, file %s: %v", name, file, err) 1024 } 1025 continue 1026 } 1027 if f.Name.Name != sname { 1028 continue 1029 } 1030 1031 apkg.Files[file] = f 1032 if apiImportParser { 1033 for _, dep := range fileDeps(f) { 1034 w.WalkPackage(dep) 1035 } 1036 } 1037 if apiShowpos && w.wantedPkg[name] { 1038 tf := w.fset.File(f.Pos()) 1039 if tf != nil { 1040 fmt.Printf("pos %s%s%s%s%d:%d\n", name, w.sep, filepath.Join(dir, file), w.sep, tf.Base(), tf.Base()+tf.Size()) 1041 } 1042 } 1043 } 1044 } 1045 }*/ 1046 if curName != ctxName { 1047 w.packageState[curName] = loading 1048 1049 defer func() { 1050 w.packageState[curName] = loaded 1051 }() 1052 } 1053 1054 if apiVerbose { 1055 log.Printf("package %s => %s, %v", ctxName, curName, w.wantedPkg[curName]) 1056 } 1057 pop := w.pushScope("pkg " + name) 1058 defer pop() 1059 1060 w.curPackageName = curName 1061 w.constDep = map[string]*ExprType{} 1062 w.curPackage = NewPackage() 1063 w.curPackage.apkg = apkg 1064 w.curPackage.name = name 1065 w.curPackage.dir = dir 1066 w.curPackage.deps = deps 1067 w.curPackage.sep = w.sep 1068 w.packageMap[curName] = w.curPackage 1069 w.packageMap[ctxName] = w.curPackage 1070 1071 for _, afile := range apkg.Files { 1072 w.recordTypes(afile) 1073 } 1074 1075 // Register all function declarations first. 1076 for _, afile := range apkg.Files { 1077 for _, di := range afile.Decls { 1078 if d, ok := di.(*ast.FuncDecl); ok { 1079 if !w.isExtract(d.Name.Name) { 1080 continue 1081 } 1082 w.peekFuncDecl(d) 1083 } 1084 } 1085 } 1086 1087 for _, afile := range apkg.Files { 1088 w.walkFile(afile) 1089 } 1090 1091 w.resolveConstantDeps() 1092 1093 if w.cursorInfo != nil && w.cursorInfo.pkg == name { 1094 for k, v := range apkg.Files { 1095 if k == w.cursorInfo.file { 1096 f := w.fset.File(v.Pos()) 1097 if f == nil { 1098 log.Fatalf("error fset postion %v", v.Pos()) 1099 } 1100 info, err := w.lookupFile(v, token.Pos(f.Base())+w.cursorInfo.pos-1) 1101 if err != nil { 1102 log.Fatalln("lookup error,", err) 1103 } else { 1104 if info != nil && info.Kind == KindImport { 1105 for _, is := range v.Imports { 1106 fpath, err := strconv.Unquote(is.Path.Value) 1107 if err == nil { 1108 if info.Name == path.Base(fpath) { 1109 info.T = is.Path 1110 } 1111 } 1112 } 1113 } 1114 w.cursorInfo.info = info 1115 } 1116 break 1117 } 1118 } 1119 return 1120 } 1121 1122 // Now that we're done walking types, vars and consts 1123 // in the *ast.Package, use go/doc to do the rest 1124 // (functions and methods). This is done here because 1125 // go/doc is destructive. We can't use the 1126 // *ast.Package after this. 1127 var mode doc.Mode 1128 if apiAllmethods { 1129 mode |= doc.AllMethods 1130 } 1131 if apiAlldecls && w.wantedPkg[w.ctxName] { 1132 mode |= doc.AllDecls 1133 } 1134 1135 dpkg := doc.New(apkg, name, mode) 1136 w.curPackage.dpkg = dpkg 1137 1138 if w.wantedPkg[name] != true { 1139 return 1140 } 1141 1142 for _, t := range dpkg.Types { 1143 // Move funcs up to the top-level, not hiding in the Types. 1144 dpkg.Funcs = append(dpkg.Funcs, t.Funcs...) 1145 1146 for _, m := range t.Methods { 1147 w.walkFuncDecl(m.Decl) 1148 } 1149 } 1150 1151 for _, f := range dpkg.Funcs { 1152 w.walkFuncDecl(f.Decl) 1153 } 1154} 1155 1156// pushScope enters a new scope (walking a package, type, node, etc) 1157// and returns a function that will leave the scope (with sanity checking 1158// for mismatched pushes & pops) 1159func (w *Walker) pushScope(name string) (popFunc func()) { 1160 w.scope = append(w.scope, name) 1161 return func() { 1162 if len(w.scope) == 0 { 1163 log.Fatalf("attempt to leave scope %q with empty scope list", name) 1164 } 1165 if w.scope[len(w.scope)-1] != name { 1166 log.Fatalf("attempt to leave scope %q, but scope is currently %#v", name, w.scope) 1167 } 1168 w.scope = w.scope[:len(w.scope)-1] 1169 } 1170} 1171 1172func (w *Walker) recordTypes(file *ast.File) { 1173 cur := w.curPackage 1174 for _, di := range file.Decls { 1175 switch d := di.(type) { 1176 case *ast.GenDecl: 1177 switch d.Tok { 1178 case token.TYPE: 1179 for _, sp := range d.Specs { 1180 ts := sp.(*ast.TypeSpec) 1181 name := ts.Name.Name 1182 switch t := ts.Type.(type) { 1183 case *ast.InterfaceType: 1184 if isExtract(name) { 1185 w.noteInterface(name, t) 1186 } 1187 cur.interfaces[name] = t 1188 case *ast.StructType: 1189 cur.structs[name] = t 1190 default: 1191 cur.types[name] = ts.Type 1192 } 1193 } 1194 } 1195 } 1196 } 1197} 1198 1199func inRange(node ast.Node, p token.Pos) bool { 1200 if node == nil { 1201 return false 1202 } 1203 return p >= node.Pos() && p <= node.End() 1204} 1205 1206func (w *Walker) lookupLabel(body *ast.BlockStmt, name string) (*TypeInfo, error) { 1207 for _, stmt := range body.List { 1208 switch v := stmt.(type) { 1209 case *ast.BlockStmt: 1210 return w.lookupLabel(v, name) 1211 case *ast.LabeledStmt: 1212 return &TypeInfo{Kind: KindLabel, Name: v.Label.Name, Type: "branch", T: v.Label}, nil 1213 } 1214 } 1215 return nil, nil 1216} 1217 1218func (w *Walker) lookupFile(file *ast.File, p token.Pos) (*TypeInfo, error) { 1219 if inRange(file.Name, p) { 1220 return &TypeInfo{Kind: KindPackage, X: file.Name, Name: file.Name.Name, Type: file.Name.Name, T: file.Name}, nil 1221 } 1222 for _, di := range file.Decls { 1223 switch d := di.(type) { 1224 case *ast.GenDecl: 1225 if inRange(d, p) { 1226 return w.lookupDecl(d, p, false) 1227 } 1228 case *ast.FuncDecl: 1229 if inRange(d, p) { 1230 info, err := w.lookupDecl(d, p, false) 1231 if info != nil && info.Kind == KindBranch { 1232 return w.lookupLabel(d.Body, info.Name) 1233 } 1234 return info, err 1235 } 1236 if d.Body != nil && inRange(d.Body, p) { 1237 return w.lookupStmt(d.Body, p) 1238 } 1239 default: 1240 return nil, fmt.Errorf("un parser decl %T", di) 1241 } 1242 } 1243 return nil, fmt.Errorf("un find cursor %v", w.fset.Position(p)) 1244} 1245 1246func (w *Walker) isExtract(name string) bool { 1247 if w.wantedPkg[w.curPackageName] || apiAlldecls { 1248 return true 1249 } 1250 return ast.IsExported(name) 1251} 1252 1253func (w *Walker) isType(typ string) *ExprType { 1254 pos := strings.Index(typ, ".") 1255 if pos != -1 { 1256 pkg := typ[:pos] 1257 typ = typ[pos+1:] 1258 if p := w.findPackage(pkg); p != nil { 1259 if t, ok := p.types[typ]; ok { 1260 if r := w.isType(typ); r != nil { 1261 return r 1262 } 1263 return &ExprType{X: t, T: w.pkgRetType(pkg, w.nodeString(t))} 1264 } 1265 } 1266 return nil 1267 } 1268 if t, ok := w.curPackage.types[typ]; ok { 1269 if r := w.isType(w.nodeString(t)); r != nil { 1270 return r 1271 } 1272 return &ExprType{X: t, T: w.nodeString(t)} 1273 } 1274 return nil 1275} 1276 1277func (w *Walker) lookupStmt(vi ast.Stmt, p token.Pos) (*TypeInfo, error) { 1278 if vi == nil { 1279 return nil, nil 1280 } 1281 switch v := vi.(type) { 1282 case *ast.BadStmt: 1283 // 1284 case *ast.EmptyStmt: 1285 // 1286 case *ast.LabeledStmt: 1287 if inRange(v.Label, p) { 1288 return &TypeInfo{Kind: KindLabel, Name: v.Label.Name}, nil 1289 } 1290 return w.lookupStmt(v.Stmt, p) 1291 // 1292 case *ast.DeclStmt: 1293 return w.lookupDecl(v.Decl, p, true) 1294 case *ast.AssignStmt: 1295 if len(v.Lhs) == len(v.Rhs) { 1296 for i := 0; i < len(v.Lhs); i++ { 1297 switch lt := v.Lhs[i].(type) { 1298 case *ast.Ident: 1299 typ, err := w.varValueType(v.Rhs[i], 0) 1300 if err == nil && v.Tok == token.DEFINE { 1301 w.localvar[lt.Name] = &ExprType{T: typ, X: lt} 1302 } else if apiVerbose { 1303 log.Println(err) 1304 } 1305 } 1306 if inRange(v.Lhs[i], p) { 1307 return w.lookupExprInfo(v.Lhs[i], p) 1308 } else if inRange(v.Rhs[i], p) { 1309 return w.lookupExprInfo(v.Rhs[i], p) 1310 } 1311 if fl, ok := v.Rhs[i].(*ast.FuncLit); ok { 1312 if inRange(fl, p) { 1313 return w.lookupStmt(fl.Body, p) 1314 } 1315 } 1316 } 1317 } else if len(v.Rhs) == 1 { 1318 for i := 0; i < len(v.Lhs); i++ { 1319 switch lt := v.Lhs[i].(type) { 1320 case *ast.Ident: 1321 typ, err := w.varValueType(v.Rhs[0], i) 1322 if err == nil && v.Tok == token.DEFINE { 1323 w.localvar[lt.Name] = &ExprType{T: typ, X: lt} 1324 } else if apiVerbose { 1325 log.Println(err) 1326 } 1327 } 1328 if inRange(v.Lhs[i], p) { 1329 return w.lookupExprInfo(v.Lhs[i], p) 1330 } else if inRange(v.Rhs[0], p) { 1331 return w.lookupExprInfo(v.Rhs[0], p) 1332 } 1333 if fl, ok := v.Rhs[0].(*ast.FuncLit); ok { 1334 if inRange(fl, p) { 1335 return w.lookupStmt(fl.Body, p) 1336 } 1337 } 1338 } 1339 } 1340 return nil, nil 1341 case *ast.ExprStmt: 1342 return w.lookupExprInfo(v.X, p) 1343 case *ast.BlockStmt: 1344 for _, st := range v.List { 1345 if inRange(st, p) { 1346 return w.lookupStmt(st, p) 1347 } 1348 _, err := w.lookupStmt(st, p) 1349 if err != nil { 1350 log.Println(err) 1351 } 1352 } 1353 case *ast.IfStmt: 1354 if inRange(v.Init, p) { 1355 return w.lookupStmt(v.Init, p) 1356 } else { 1357 w.lookupStmt(v.Init, p) 1358 } 1359 if inRange(v.Cond, p) { 1360 return w.lookupExprInfo(v.Cond, p) 1361 } else if inRange(v.Body, p) { 1362 return w.lookupStmt(v.Body, p) 1363 } else if inRange(v.Else, p) { 1364 return w.lookupStmt(v.Else, p) 1365 } 1366 case *ast.SendStmt: 1367 if inRange(v.Chan, p) { 1368 return w.lookupExprInfo(v.Chan, p) 1369 } else if inRange(v.Value, p) { 1370 return w.lookupExprInfo(v.Value, p) 1371 } 1372 case *ast.IncDecStmt: 1373 return w.lookupExprInfo(v.X, p) 1374 case *ast.GoStmt: 1375 return w.lookupExprInfo(v.Call, p) 1376 case *ast.DeferStmt: 1377 return w.lookupExprInfo(v.Call, p) 1378 case *ast.ReturnStmt: 1379 for _, r := range v.Results { 1380 if inRange(r, p) { 1381 return w.lookupExprInfo(r, p) 1382 } 1383 } 1384 case *ast.BranchStmt: 1385 if inRange(v.Label, p) { 1386 return &TypeInfo{Kind: KindBranch, Name: v.Label.Name, Type: "label", T: v.Label}, nil 1387 } 1388 // 1389 case *ast.CaseClause: 1390 for _, r := range v.List { 1391 if inRange(r, p) { 1392 return w.lookupExprInfo(r, p) 1393 } 1394 } 1395 for _, body := range v.Body { 1396 if inRange(body, p) { 1397 return w.lookupStmt(body, p) 1398 } else { 1399 w.lookupStmt(body, p) 1400 } 1401 } 1402 case *ast.SwitchStmt: 1403 if inRange(v.Init, p) { 1404 return w.lookupStmt(v.Init, p) 1405 } else { 1406 w.lookupStmt(v.Init, p) 1407 } 1408 if inRange(v.Tag, p) { 1409 return w.lookupExprInfo(v.Tag, p) 1410 } else if inRange(v.Body, p) { 1411 return w.lookupStmt(v.Body, p) 1412 } 1413 case *ast.TypeSwitchStmt: 1414 if inRange(v.Assign, p) { 1415 return w.lookupStmt(v.Assign, p) 1416 } else { 1417 w.lookupStmt(v.Assign, p) 1418 } 1419 if inRange(v.Init, p) { 1420 return w.lookupStmt(v.Init, p) 1421 } else { 1422 w.lookupStmt(v.Init, p) 1423 } 1424 var vs string 1425 if as, ok := v.Assign.(*ast.AssignStmt); ok { 1426 if len(as.Lhs) == 1 { 1427 vs = w.nodeString(as.Lhs[0]) 1428 } 1429 } 1430 if inRange(v.Body, p) { 1431 for _, s := range v.Body.List { 1432 if inRange(s, p) { 1433 switch cs := s.(type) { 1434 case *ast.CaseClause: 1435 for _, r := range cs.List { 1436 if inRange(r, p) { 1437 return w.lookupExprInfo(r, p) 1438 } else if vs != "" { 1439 typ, err := w.varValueType(r, 0) 1440 if err == nil { 1441 w.localvar[vs] = &ExprType{T: typ, X: r} 1442 } 1443 } 1444 } 1445 for _, body := range cs.Body { 1446 if inRange(body, p) { 1447 return w.lookupStmt(body, p) 1448 } else { 1449 w.lookupStmt(body, p) 1450 } 1451 } 1452 default: 1453 return w.lookupStmt(cs, p) 1454 } 1455 } 1456 } 1457 } 1458 case *ast.CommClause: 1459 if inRange(v.Comm, p) { 1460 return w.lookupStmt(v.Comm, p) 1461 } 1462 for _, body := range v.Body { 1463 if inRange(body, p) { 1464 return w.lookupStmt(body, p) 1465 } 1466 } 1467 case *ast.SelectStmt: 1468 if inRange(v.Body, p) { 1469 return w.lookupStmt(v.Body, p) 1470 } 1471 case *ast.ForStmt: 1472 if inRange(v.Init, p) { 1473 return w.lookupStmt(v.Init, p) 1474 } else { 1475 w.lookupStmt(v.Init, p) 1476 } 1477 if inRange(v.Cond, p) { 1478 return w.lookupExprInfo(v.Cond, p) 1479 } else if inRange(v.Body, p) { 1480 return w.lookupStmt(v.Body, p) 1481 } else if inRange(v.Post, p) { 1482 return w.lookupStmt(v.Post, p) 1483 } 1484 case *ast.RangeStmt: 1485 if inRange(v.X, p) { 1486 return w.lookupExprInfo(v.X, p) 1487 } else if inRange(v.Key, p) { 1488 return &TypeInfo{Kind: KindBuiltin, Name: w.nodeString(v.Key), Type: "int"}, nil 1489 } else if inRange(v.Value, p) { 1490 typ, err := w.lookupExprInfo(v.X, p) 1491 if typ != nil { 1492 typ.Name = w.nodeString(v.Value) 1493 return typ, err 1494 } 1495 } else { 1496 typ, err := w.varValueType(v.X, 0) 1497 //check is type 1498 if t := w.isType(typ); t != nil { 1499 typ = t.T 1500 } 1501 if err == nil { 1502 var kt, vt string 1503 if strings.HasPrefix(typ, "[]") { 1504 kt = "int" 1505 vt = typ[2:] 1506 } else if strings.HasPrefix(typ, "map[") { 1507 node, err := parser.ParseExpr(typ + "{}") 1508 if err == nil { 1509 if cl, ok := node.(*ast.CompositeLit); ok { 1510 if m, ok := cl.Type.(*ast.MapType); ok { 1511 kt = w.nodeString(w.namelessType(m.Key)) 1512 vt = w.nodeString(w.namelessType(m.Value)) 1513 } 1514 } 1515 } 1516 } 1517 if inRange(v.Key, p) { 1518 return &TypeInfo{Kind: KindVar, X: v.Key, Name: w.nodeString(v.Key), T: v.X, Type: kt}, nil 1519 } else if inRange(v.Value, p) { 1520 return &TypeInfo{Kind: KindVar, X: v.Value, Name: w.nodeString(v.Value), T: v.X, Type: vt}, nil 1521 } 1522 if key, ok := v.Key.(*ast.Ident); ok { 1523 w.localvar[key.Name] = &ExprType{T: kt, X: v.Key} 1524 } 1525 if value, ok := v.Value.(*ast.Ident); ok { 1526 w.localvar[value.Name] = &ExprType{T: vt, X: v.Value} 1527 } 1528 } 1529 } 1530 if inRange(v.Body, p) { 1531 return w.lookupStmt(v.Body, p) 1532 } 1533 } 1534 return nil, nil //fmt.Errorf("not lookup stmt %v %T", vi, vi) 1535} 1536 1537func (w *Walker) lookupVar(vs *ast.ValueSpec, p token.Pos, local bool) (*TypeInfo, error) { 1538 if inRange(vs.Type, p) { 1539 return w.lookupExprInfo(vs.Type, p) 1540 } 1541 for _, v := range vs.Values { 1542 if inRange(v, p) { 1543 return w.lookupExprInfo(v, p) 1544 } 1545 } 1546 if vs.Type != nil { 1547 typ := w.nodeString(vs.Type) 1548 for _, ident := range vs.Names { 1549 if local { 1550 w.localvar[ident.Name] = &ExprType{T: typ, X: ident} 1551 } 1552 if inRange(ident, p) { 1553 return &TypeInfo{Kind: KindVar, X: ident, Name: ident.Name, T: vs.Type, Type: typ}, nil 1554 } 1555 } 1556 } else if len(vs.Names) == len(vs.Values) { 1557 for n, ident := range vs.Names { 1558 typ := "" 1559 if !local { 1560 if t, ok := w.curPackage.vars[ident.Name]; ok { 1561 typ = t.T 1562 } 1563 } else { 1564 typ, err := w.varValueType(vs.Values[n], n) 1565 if err != nil { 1566 if apiVerbose { 1567 log.Printf("unknown type of variable2 %q, type %T, error = %v, pos=%s", 1568 ident.Name, vs.Values[n], err, w.fset.Position(vs.Pos())) 1569 } 1570 typ = "unknown-type" 1571 } 1572 w.localvar[ident.Name] = &ExprType{T: typ, X: ident} 1573 } 1574 if inRange(ident, p) { 1575 return &TypeInfo{Kind: KindVar, X: ident, Name: ident.Name, T: ident, Type: typ}, nil 1576 } 1577 } 1578 } else if len(vs.Values) == 1 { 1579 for n, ident := range vs.Names { 1580 typ := "" 1581 if !local { 1582 if t, ok := w.curPackage.vars[ident.Name]; ok { 1583 typ = t.T 1584 } 1585 } else { 1586 typ, err := w.varValueType(vs.Values[0], n) 1587 if err != nil { 1588 if apiVerbose { 1589 log.Printf("unknown type of variable3 %q, type %T, error = %v, pos=%s", 1590 ident.Name, vs.Values[0], err, w.fset.Position(vs.Pos())) 1591 } 1592 typ = "unknown-type" 1593 } 1594 w.localvar[ident.Name] = &ExprType{T: typ, X: ident} 1595 } 1596 if inRange(ident, p) { 1597 return &TypeInfo{Kind: KindVar, X: ident, Name: ident.Name, T: ident, Type: typ}, nil 1598 } 1599 } 1600 } 1601 return nil, fmt.Errorf("not lookup var local:%v value:%v type:s%T", local, w.nodeString(vs), vs) 1602} 1603 1604func (w *Walker) lookupConst(vs *ast.ValueSpec, p token.Pos, local bool) (*TypeInfo, error) { 1605 if inRange(vs.Type, p) { 1606 return w.lookupExprInfo(vs.Type, p) 1607 } 1608 for _, ident := range vs.Names { 1609 typ := "" 1610 if !local { 1611 if t, ok := w.curPackage.consts[ident.Name]; ok { 1612 typ = t.T 1613 } 1614 } else { 1615 litType := "" 1616 if vs.Type != nil { 1617 litType = w.nodeString(vs.Type) 1618 } else { 1619 litType = w.lastConstType 1620 if vs.Values != nil { 1621 if len(vs.Values) != 1 { 1622 if apiVerbose { 1623 log.Printf("const %q, values: %#v", ident.Name, vs.Values) 1624 } 1625 return nil, nil 1626 } 1627 var err error 1628 litType, err = w.constValueType(vs.Values[0]) 1629 if err != nil { 1630 if apiVerbose { 1631 log.Printf("unknown kind in const %q (%T): %v", ident.Name, vs.Values[0], err) 1632 } 1633 litType = "unknown-type" 1634 } 1635 } 1636 } 1637 w.lastConstType = litType 1638 typ = litType 1639 w.localvar[ident.Name] = &ExprType{T: typ, X: ident} 1640 } 1641 if inRange(ident, p) { 1642 return &TypeInfo{Kind: KindConst, X: ident, Name: ident.Name, T: ident, Type: typ}, nil 1643 } 1644 } 1645 return nil, nil 1646} 1647 1648func (w *Walker) lookupType(ts *ast.TypeSpec, p token.Pos, local bool) (*TypeInfo, error) { 1649 switch t := ts.Type.(type) { 1650 case *ast.StructType: 1651 if inRange(t.Fields, p) { 1652 for _, fd := range t.Fields.List { 1653 if inRange(fd.Type, p) { 1654 return w.lookupExprInfo(fd.Type, p) 1655 } 1656 for _, ident := range fd.Names { 1657 if inRange(ident, p) { 1658 return &TypeInfo{Kind: KindField, X: ident, Name: ts.Name.Name + "." + ident.Name, T: fd.Type, Type: w.nodeString(w.namelessType(fd.Type))}, nil 1659 } 1660 } 1661 } 1662 } 1663 return &TypeInfo{Kind: KindStruct, X: ts.Name, Name: ts.Name.Name, T: ts.Type, Type: "struct"}, nil 1664 case *ast.InterfaceType: 1665 if inRange(t.Methods, p) { 1666 for _, fd := range t.Methods.List { 1667 for _, ident := range fd.Names { 1668 if inRange(ident, p) { 1669 return &TypeInfo{Kind: KindMethod, X: ident, Name: ts.Name.Name + "." + ident.Name, T: ident, Type: w.nodeString(w.namelessType(fd.Type))}, nil 1670 } 1671 } 1672 if inRange(fd.Type, p) { 1673 return w.lookupExprInfo(fd.Type, p) 1674 } 1675 } 1676 } 1677 return &TypeInfo{Kind: KindInterface, X: ts.Name, Name: ts.Name.Name, T: ts.Type, Type: "interface"}, nil 1678 default: 1679 return &TypeInfo{Kind: KindType, X: ts.Name, Name: ts.Name.Name, T: ts.Type, Type: w.nodeString(w.namelessType(ts.Type))}, nil 1680 } 1681 return nil, nil 1682} 1683 1684func (w *Walker) lookupDecl(di ast.Decl, p token.Pos, local bool) (*TypeInfo, error) { 1685 switch d := di.(type) { 1686 case *ast.GenDecl: 1687 switch d.Tok { 1688 case token.IMPORT: 1689 for _, sp := range d.Specs { 1690 is := sp.(*ast.ImportSpec) 1691 fpath, err := strconv.Unquote(is.Path.Value) 1692 if err != nil { 1693 return nil, err 1694 } 1695 name := path.Base(fpath) 1696 if is.Name != nil { 1697 name = is.Name.Name 1698 } 1699 if inRange(sp, p) { 1700 return &TypeInfo{Kind: KindImport, X: is.Name, Name: name, T: is.Name, Type: fpath}, nil 1701 } 1702 } 1703 case token.CONST: 1704 for _, sp := range d.Specs { 1705 if inRange(sp, p) { 1706 return w.lookupConst(sp.(*ast.ValueSpec), p, local) 1707 } else { 1708 w.lookupConst(sp.(*ast.ValueSpec), p, local) 1709 } 1710 } 1711 return nil, nil 1712 case token.TYPE: 1713 for _, sp := range d.Specs { 1714 if inRange(sp, p) { 1715 return w.lookupType(sp.(*ast.TypeSpec), p, local) 1716 } else { 1717 w.lookupType(sp.(*ast.TypeSpec), p, local) 1718 } 1719 } 1720 case token.VAR: 1721 for _, sp := range d.Specs { 1722 if inRange(sp, p) { 1723 return w.lookupVar(sp.(*ast.ValueSpec), p, local) 1724 } else { 1725 w.lookupVar(sp.(*ast.ValueSpec), p, local) 1726 } 1727 } 1728 return nil, nil 1729 default: 1730 return nil, fmt.Errorf("unknown token type %d %T in GenDecl", d.Tok, d) 1731 } 1732 case *ast.FuncDecl: 1733 if d.Type.Params != nil { 1734 for _, fd := range d.Type.Params.List { 1735 if inRange(fd, p) { 1736 return w.lookupExprInfo(fd.Type, p) 1737 } 1738 for _, ident := range fd.Names { 1739 if inRange(ident, p) { 1740 info, err := w.lookupExprInfo(fd.Type, p) 1741 if err == nil { 1742 return &TypeInfo{Kind: KindParam, X: ident, Name: ident.Name, T: info.T, Type: info.Type}, nil 1743 } 1744 } 1745 typ, err := w.varValueType(fd.Type, 0) 1746 if err == nil { 1747 w.localvar[ident.Name] = &ExprType{T: typ, X: ident} 1748 } else if apiVerbose { 1749 log.Println(err) 1750 } 1751 } 1752 } 1753 } 1754 if d.Type.Results != nil { 1755 for _, fd := range d.Type.Results.List { 1756 if inRange(fd, p) { 1757 return w.lookupExprInfo(fd.Type, p) 1758 } 1759 for _, ident := range fd.Names { 1760 typ, err := w.varValueType(fd.Type, 0) 1761 if err == nil { 1762 w.localvar[ident.Name] = &ExprType{T: typ, X: ident} 1763 } 1764 } 1765 } 1766 } 1767 if d.Recv != nil { 1768 for _, fd := range d.Recv.List { 1769 if inRange(fd, p) { 1770 return w.lookupExprInfo(fd.Type, p) 1771 } 1772 for _, ident := range fd.Names { 1773 w.localvar[ident.Name] = &ExprType{T: w.nodeString(fd.Type), X: ident} 1774 } 1775 } 1776 } 1777 if inRange(d.Body, p) { 1778 return w.lookupStmt(d.Body, p) 1779 } 1780 var fname = d.Name.Name 1781 kind := KindFunc 1782 if d.Recv != nil { 1783 recvTypeName, imp := baseTypeName(d.Recv.List[0].Type) 1784 if imp { 1785 return nil, nil 1786 } 1787 fname = recvTypeName + "." + d.Name.Name 1788 kind = KindMethod 1789 } 1790 return &TypeInfo{Kind: kind, X: d.Name, Name: fname, T: d.Type, Type: w.nodeString(w.namelessType(d.Type))}, nil 1791 default: 1792 return nil, fmt.Errorf("unhandled %T, %#v\n", di, di) 1793 } 1794 return nil, fmt.Errorf("not lookupDecl %v %T", w.nodeString(di), di) 1795} 1796 1797func (w *Walker) lookupExprInfo(vi ast.Expr, p token.Pos) (*TypeInfo, error) { 1798 _, info, err := w.lookupExpr(vi, p) 1799 return info, err 1800} 1801 1802// lookupExpr , return name,info,error 1803func (w *Walker) lookupExpr(vi ast.Expr, p token.Pos) (string, *TypeInfo, error) { 1804 if apiVerbose { 1805 log.Printf("lookup expr %v %T", w.nodeString(vi), vi) 1806 } 1807 switch v := vi.(type) { 1808 case *ast.BasicLit: 1809 litType, ok := varType[v.Kind] 1810 if !ok { 1811 return "", nil, fmt.Errorf("unknown basic literal kind %#v", v) 1812 } 1813 name := v.Value 1814 if len(name) >= 128 { 1815 name = name[:128] + "..." 1816 } 1817 return litType, &TypeInfo{Kind: KindBuiltin, X: v, Name: name, T: v, Type: litType}, nil 1818 case *ast.StarExpr: 1819 s, info, err := w.lookupExpr(v.X, p) 1820 if err != nil { 1821 return "", nil, err 1822 } 1823 return "*" + s, &TypeInfo{Kind: info.Kind, X: v, Name: "*" + info.Name, T: info.T, Type: "*" + info.Type}, err 1824 case *ast.InterfaceType: 1825 return "interface{}", &TypeInfo{Kind: KindInterface, X: v, Name: w.nodeString(v), T: v, Type: "interface{}"}, nil 1826 case *ast.Ellipsis: 1827 s, info, err := w.lookupExpr(v.Elt, p) 1828 if err != nil { 1829 return "", nil, err 1830 } 1831 return "[]" + s, &TypeInfo{Kind: KindArray, X: v.Elt, Name: "..." + s, T: info.T, Type: "[]" + info.Type}, nil 1832 case *ast.KeyValueExpr: 1833 if inRange(v.Key, p) { 1834 return w.lookupExpr(v.Key, p) 1835 } else if inRange(v.Value, p) { 1836 return w.lookupExpr(v.Value, p) 1837 } 1838 case *ast.CompositeLit: 1839 typ, err := w.varValueType(v.Type, 0) 1840 if err == nil { 1841 typ = strings.TrimLeft(typ, "*") 1842 if strings.HasPrefix(typ, "[]") { 1843 typ = strings.TrimLeft(typ[2:], "*") 1844 } 1845 pos := strings.Index(typ, ".") 1846 var pt *Package = w.curPackage 1847 var pkgdot string 1848 if pos != -1 { 1849 pkg := typ[:pos] 1850 typ = typ[pos+1:] 1851 pt = w.findPackage(pkg) 1852 if pt != nil { 1853 pkgdot = pkg + "." 1854 } 1855 } 1856 if pt != nil { 1857 if ss, ok := pt.structs[typ]; ok { 1858 for _, elt := range v.Elts { 1859 if inRange(elt, p) { 1860 if cl, ok := elt.(*ast.CompositeLit); ok { 1861 for _, elt := range cl.Elts { 1862 if inRange(elt, p) { 1863 if kv, ok := elt.(*ast.KeyValueExpr); ok { 1864 if inRange(kv.Key, p) { 1865 n, t := w.findStructField(ss, w.nodeString(kv.Key)) 1866 if n != nil { 1867 return pkgdot + typ + "." + w.nodeString(kv.Key), &TypeInfo{Kind: KindField, X: kv.Key, Name: pkgdot + typ + "." + w.nodeString(kv.Key), T: n, Type: w.nodeString(w.namelessType(t))}, nil 1868 } 1869 } else if inRange(kv.Value, p) { 1870 return w.lookupExpr(kv.Value, p) 1871 } 1872 } 1873 } 1874 } 1875 } 1876 if kv, ok := elt.(*ast.KeyValueExpr); ok { 1877 if inRange(kv.Key, p) { 1878 n, t := w.findStructField(ss, w.nodeString(kv.Key)) 1879 if n != nil { 1880 return typ + "." + w.nodeString(kv.Key), &TypeInfo{Kind: KindField, X: kv.Key, Name: typ + "." + w.nodeString(kv.Key), T: n, Type: w.nodeString(w.namelessType(t))}, nil 1881 } 1882 } else if inRange(kv.Value, p) { 1883 return w.lookupExpr(kv.Value, p) 1884 } 1885 } 1886 } 1887 } 1888 } 1889 } 1890 } 1891 for _, elt := range v.Elts { 1892 if inRange(elt, p) { 1893 return w.lookupExpr(elt, p) 1894 } 1895 } 1896 return w.lookupExpr(v.Type, p) 1897 case *ast.UnaryExpr: 1898 s, info, err := w.lookupExpr(v.X, p) 1899 return v.Op.String() + s, info, err 1900 case *ast.TypeAssertExpr: 1901 if inRange(v.X, p) { 1902 return w.lookupExpr(v.X, p) 1903 } 1904 return w.lookupExpr(v.Type, p) 1905 case *ast.BinaryExpr: 1906 if inRange(v.X, p) { 1907 return w.lookupExpr(v.X, p) 1908 } else if inRange(v.Y, p) { 1909 return w.lookupExpr(v.Y, p) 1910 } 1911 return "", nil, nil 1912 case *ast.CallExpr: 1913 for _, arg := range v.Args { 1914 if inRange(arg, p) { 1915 return w.lookupExpr(arg, p) 1916 } 1917 } 1918 switch ft := v.Fun.(type) { 1919 case *ast.Ident: 1920 if typ, ok := w.localvar[ft.Name]; ok { 1921 return ft.Name, &TypeInfo{Kind: KindVar, X: ft, Name: ft.Name, T: typ.X, Type: typ.T}, nil 1922 } 1923 if typ, ok := w.curPackage.vars[ft.Name]; ok { 1924 return ft.Name, &TypeInfo{Kind: KindVar, X: v, Name: ft.Name, T: typ.X, Type: typ.T}, nil 1925 } 1926 if typ, ok := w.curPackage.functions[ft.Name]; ok { 1927 return ft.Name, &TypeInfo{Kind: KindFunc, X: ft, Name: ft.Name, T: typ.ft, Type: typ.sig}, nil 1928 } 1929 if typ, ok := w.curPackage.interfaces[ft.Name]; ok { 1930 return ft.Name, &TypeInfo{Kind: KindInterface, X: ft, Name: ft.Name, T: typ, Type: w.nodeString(w.namelessType(typ))}, nil 1931 } 1932 if typ, ok := w.curPackage.interfaces[ft.Name]; ok { 1933 return ft.Name, &TypeInfo{Kind: KindInterface, X: ft, Name: ft.Name, T: typ, Type: w.nodeString(w.namelessType(typ))}, nil 1934 } 1935 if typ, ok := w.curPackage.structs[ft.Name]; ok { 1936 return ft.Name, &TypeInfo{Kind: KindStruct, X: ft, Name: ft.Name, T: typ, Type: w.nodeString(w.namelessType(typ))}, nil 1937 } 1938 if typ, ok := w.curPackage.types[ft.Name]; ok { 1939 return ft.Name, &TypeInfo{Kind: KindType, X: ft, Name: ft.Name, T: typ, Type: w.nodeString(w.namelessType(typ))}, nil 1940 } 1941 if isBuiltinType(ft.Name) { 1942 return ft.Name, &TypeInfo{Kind: KindBuiltin, X: ft, Name: ft.Name}, nil 1943 } 1944 return "", nil, fmt.Errorf("lookup unknown ident %v", v) 1945 case *ast.FuncLit: 1946 if inRange(ft.Body, p) { 1947 info, err := w.lookupStmt(ft.Body, p) 1948 if err == nil { 1949 return "", info, nil 1950 } 1951 return "", nil, err 1952 } 1953 return w.lookupExpr(ft.Type, p) 1954 case *ast.ParenExpr: 1955 return w.lookupExpr(ft.X, p) 1956 case *ast.SelectorExpr: 1957 switch st := ft.X.(type) { 1958 case *ast.Ident: 1959 if inRange(st, p) { 1960 return w.lookupExpr(st, p) 1961 } 1962 s, info, err := w.lookupExpr(st, p) 1963 if err != nil { 1964 return "", nil, err 1965 } 1966 typ := info.Type 1967 if typ == "" { 1968 typ = s 1969 } 1970 fname := typ + "." + ft.Sel.Name 1971 typ = strings.TrimLeft(typ, "*") 1972 if fn, ok := w.curPackage.functions[fname]; ok { 1973 return fname, &TypeInfo{Kind: KindMethod, X: st, Name: fname, T: fn.ft, Type: w.nodeString(w.namelessType(fn.ft))}, nil 1974 } 1975 info, e := w.lookupFunction(typ, ft.Sel.Name) 1976 if e != nil { 1977 return "", nil, e 1978 } 1979 return fname, info, nil 1980 case *ast.SelectorExpr: 1981 if inRange(st.X, p) { 1982 return w.lookupExpr(st.X, p) 1983 } 1984 if inRange(st, p) { 1985 return w.lookupExpr(st, p) 1986 } 1987 typ, err := w.varValueType(st, 0) 1988 if err != nil { 1989 return "", nil, err 1990 } 1991 /* 1992 typ = strings.TrimLeft(typ, "*") 1993 if t := w.curPackage.findType(typ); t != nil { 1994 if ss, ok := t.(*ast.StructType); ok { 1995 for _, fi := range ss.Fields.List { 1996 for _, n := range fi.Names { 1997 if n.Name == st.Sel.Name { 1998 //return fname, &TypeInfo{Kind: KindField, X: n, Name: fname, T: fi.Type, Type: w.nodeString(w.namelessType(fi.Type))}, nil 1999 typ = w.nodeString(w.namelessType(fi.Type)) 2000 } 2001 } 2002 } 2003 } 2004 } 2005 */ 2006 info, e := w.lookupFunction(typ, ft.Sel.Name) 2007 if e != nil { 2008 return "", nil, e 2009 } 2010 return typ + "." + st.Sel.Name, info, nil 2011 case *ast.CallExpr: 2012 if inRange(st, p) { 2013 return w.lookupExpr(st, p) 2014 } 2015 if info, err := w.lookupExprInfo(st, p); err == nil { 2016 if fn, ok := info.X.(*ast.FuncType); ok { 2017 if fn.Results.NumFields() == 1 { 2018 info, err := w.lookupFunction(w.nodeString(fn.Results.List[0].Type), ft.Sel.Name) 2019 if err == nil { 2020 return info.Name, info, err 2021 } 2022 return "", nil, err 2023 } 2024 } 2025 } 2026 //w.lookupFunction(w.nodeString(info.X)) 2027 typ, err := w.varValueType(st, 0) 2028 if err != nil { 2029 return "", nil, err 2030 } 2031 info, e := w.lookupFunction(typ, ft.Sel.Name) 2032 if e != nil { 2033 return "", nil, e 2034 } 2035 return typ + "." + ft.Sel.Name, info, nil 2036 case *ast.TypeAssertExpr: 2037 if inRange(st.X, p) { 2038 return w.lookupExpr(st.X, p) 2039 } 2040 typ := w.nodeString(w.namelessType(st.Type)) 2041 info, e := w.lookupFunction(typ, ft.Sel.Name) 2042 if e != nil { 2043 return "", nil, e 2044 } 2045 return typ + "." + ft.Sel.Name, info, nil 2046 default: 2047 return "", nil, fmt.Errorf("not find select %v %T", v, st) 2048 } 2049 } 2050 return "", nil, fmt.Errorf("not find call %v %T", w.nodeString(v), v.Fun) 2051 case *ast.SelectorExpr: 2052 switch st := v.X.(type) { 2053 case *ast.Ident: 2054 if inRange(st, p) { 2055 return w.lookupExpr(st, p) 2056 } 2057 info, err := w.lookupSelector(st.Name, v.Sel.Name) 2058 if err != nil { 2059 return "", nil, err 2060 } 2061 return st.Name + "." + v.Sel.Name, info, nil 2062 // case *ast.CallExpr: 2063 // typ, err := w.varValueType(v.X, index) 2064 // if err == nil { 2065 // if strings.HasPrefix(typ, "*") { 2066 // typ = typ[1:] 2067 // } 2068 // t := w.curPackage.findType(typ) 2069 // if st, ok := t.(*ast.StructType); ok { 2070 // for _, fi := range st.Fields.List { 2071 // for _, n := range fi.Names { 2072 // if n.Name == v.Sel.Name { 2073 // return w.varValueType(fi.Type, index) 2074 // } 2075 // } 2076 // } 2077 // } 2078 // } 2079 case *ast.SelectorExpr: 2080 if inRange(st.X, p) { 2081 return w.lookupExpr(st.X, p) 2082 } 2083 2084 if inRange(st, p) { 2085 return w.lookupExpr(st, p) 2086 } 2087 2088 typ, err := w.varValueType(st, 0) 2089 if err == nil { 2090 info, err := w.lookupSelector(typ, v.Sel.Name) 2091 if err != nil { 2092 return "", nil, err 2093 } 2094 return typ + v.Sel.Name, info, nil 2095 } 2096 // case *ast.IndexExpr: 2097 // typ, err := w.varValueType(st.X, 0) 2098 // log.Println(typ, err) 2099 // if err == nil { 2100 // if strings.HasPrefix(typ, "[]") { 2101 // return w.varSelectorType(typ[2:], v.Sel.Name) 2102 // } 2103 // } 2104 } 2105 return "", nil, fmt.Errorf("unknown lookup selector expr: %T %s.%s", v.X, w.nodeString(v.X), v.Sel) 2106 2107 // s, info, err := w.lookupExpr(v.X, p) 2108 // if err != nil { 2109 // return "", "", err 2110 // } 2111 // if strings.HasPrefix(s, "*") { 2112 // s = s[1:] 2113 // } 2114 // if inRange(v.X, p) { 2115 // return s, info, err 2116 // } 2117 // t := w.curPackage.findType(s) 2118 // fname := s + "." + v.Sel.Name 2119 // if st, ok := t.(*ast.StructType); ok { 2120 // for _, fi := range st.Fields.List { 2121 // for _, n := range fi.Names { 2122 // if n.Name == v.Sel.Name { 2123 // return fname, fmt.Sprintf("var,%s,%s,%s", fname, w.nodeString(w.namelessType(fi.Type)), w.fset.Position(n.Pos())), nil 2124 // } 2125 // } 2126 // } 2127 // } 2128 // log.Println(">>", s) 2129 // info, e := w.lookupSelector(s, v.Sel.Name) 2130 // return fname, info, e 2131 case *ast.Ident: 2132 if typ, ok := w.localvar[v.Name]; ok { 2133 return typ.T, &TypeInfo{Kind: KindVar, X: v, Name: v.Name, T: typ.X, Type: typ.T}, nil 2134 } 2135 if typ, ok := w.curPackage.interfaces[v.Name]; ok { 2136 return v.Name, &TypeInfo{Kind: KindInterface, X: v, Name: v.Name, T: typ, Type: "interface"}, nil 2137 } 2138 if typ, ok := w.curPackage.structs[v.Name]; ok { 2139 return v.Name, &TypeInfo{Kind: KindStruct, X: v, Name: v.Name, T: typ, Type: "struct"}, nil 2140 } 2141 if typ, ok := w.curPackage.types[v.Name]; ok { 2142 return v.Name, &TypeInfo{Kind: KindType, X: v, Name: v.Name, T: typ, Type: v.Name}, nil 2143 } 2144 if typ, ok := w.curPackage.vars[v.Name]; ok { 2145 return v.Name, &TypeInfo{Kind: KindVar, X: v, Name: v.Name, T: typ.X, Type: typ.T}, nil 2146 } 2147 if typ, ok := w.curPackage.consts[v.Name]; ok { 2148 return v.Name, &TypeInfo{Kind: KindConst, X: v, Name: v.Name, T: typ.X, Type: typ.T}, nil 2149 } 2150 if typ, ok := w.curPackage.functions[v.Name]; ok { 2151 return v.Name, &TypeInfo{Kind: KindFunc, X: typ.ft, Name: v.Name, T: typ.ft, Type: typ.sig}, nil 2152 } 2153 if p := w.findPackage(v.Name); p != nil { 2154 return v.Name, &TypeInfo{Kind: KindImport, X: v, Name: v.Name, Type: p.name}, nil 2155 } 2156 if isBuiltinType(v.Name) { 2157 return v.Name, &TypeInfo{Kind: KindBuiltin, Name: v.Name}, nil 2158 } 2159 return "", nil, fmt.Errorf("lookup unknown ident %v", v) 2160 //return v.Name, &TypeInfo{Kind: KindVar, X: v, Name: v.Name, T: v, Type: v.Name}, nil 2161 case *ast.IndexExpr: 2162 if inRange(v.Index, p) { 2163 return w.lookupExpr(v.Index, p) 2164 } 2165 return w.lookupExpr(v.X, p) 2166 case *ast.ParenExpr: 2167 return w.lookupExpr(v.X, p) 2168 case *ast.FuncLit: 2169 if inRange(v.Type, p) { 2170 return w.lookupExpr(v.Type, p) 2171 } else { 2172 w.lookupExpr(v.Type, p) 2173 } 2174 typ, err := w.varValueType(v.Type, 0) 2175 if err != nil { 2176 return "", nil, err 2177 } 2178 info, e := w.lookupStmt(v.Body, p) 2179 if e != nil { 2180 return "", nil, err 2181 } 2182 return typ, info, nil 2183 case *ast.FuncType: 2184 if v.Params != nil { 2185 for _, fd := range v.Params.List { 2186 if inRange(fd, p) { 2187 return w.lookupExpr(fd.Type, p) 2188 } 2189 for _, ident := range fd.Names { 2190 typ, err := w.varValueType(fd.Type, 0) 2191 if err == nil { 2192 w.localvar[ident.Name] = &ExprType{T: typ, X: ident} 2193 } 2194 } 2195 } 2196 } 2197 if v.Results != nil { 2198 for _, fd := range v.Results.List { 2199 if inRange(fd, p) { 2200 return w.lookupExpr(fd.Type, p) 2201 } 2202 for _, ident := range fd.Names { 2203 typ, err := w.varValueType(fd.Type, 0) 2204 if err == nil { 2205 w.localvar[ident.Name] = &ExprType{T: typ, X: ident} 2206 } 2207 } 2208 } 2209 } 2210 return "", nil, nil 2211 case *ast.ArrayType: 2212 s, info, err := w.lookupExpr(v.Elt, p) 2213 if err != nil { 2214 return "", nil, err 2215 } 2216 return "[]" + s, &TypeInfo{Kind: KindArray, Name: "[]" + info.Name, Type: "[]" + info.Type, T: info.T}, nil 2217 case *ast.SliceExpr: 2218 if inRange(v.High, p) { 2219 return w.lookupExpr(v.High, p) 2220 } else if inRange(v.Low, p) { 2221 return w.lookupExpr(v.Low, p) 2222 } 2223 return w.lookupExpr(v.X, p) 2224 case *ast.MapType: 2225 if inRange(v.Key, p) { 2226 return w.lookupExpr(v.Key, p) 2227 } else if inRange(v.Value, p) { 2228 return w.lookupExpr(v.Value, p) 2229 } 2230 typ, err := w.varValueType(v, 0) 2231 if err != nil { 2232 return "", nil, err 2233 } 2234 return typ, &TypeInfo{Kind: KindMap, X: v, Name: w.nodeString(v), T: v, Type: typ}, nil 2235 case *ast.ChanType: 2236 if inRange(v.Value, p) { 2237 return w.lookupExpr(v.Value, p) 2238 } 2239 typ, err := w.varValueType(v, 0) 2240 if err != nil { 2241 return "", nil, err 2242 } 2243 return typ, &TypeInfo{Kind: KindChan, X: v, Name: w.nodeString(v), T: v, Type: typ}, nil 2244 default: 2245 return "", nil, fmt.Errorf("not lookupExpr %v %T", w.nodeString(v), v) 2246 } 2247 return "", nil, fmt.Errorf("not lookupExpr %v %T", w.nodeString(vi), vi) 2248} 2249 2250func (w *Walker) walkFile(file *ast.File) { 2251 // Not entering a scope here; file boundaries aren't interesting. 2252 for _, di := range file.Decls { 2253 switch d := di.(type) { 2254 case *ast.GenDecl: 2255 switch d.Tok { 2256 case token.IMPORT: 2257 for _, sp := range d.Specs { 2258 is := sp.(*ast.ImportSpec) 2259 fpath, err := strconv.Unquote(is.Path.Value) 2260 if err != nil { 2261 log.Fatal(err) 2262 } 2263 //name := path.Base(fpath) 2264 name := fpath 2265 if i := strings.LastIndexAny(name, ".-/\\"); i > 0 { 2266 name = name[i+1:] 2267 } 2268 if is.Name != nil { 2269 name = is.Name.Name 2270 } 2271 w.selectorFullPkg[name] = fpath 2272 } 2273 case token.CONST: 2274 for _, sp := range d.Specs { 2275 w.walkConst(sp.(*ast.ValueSpec)) 2276 } 2277 case token.TYPE: 2278 for _, sp := range d.Specs { 2279 w.walkTypeSpec(sp.(*ast.TypeSpec)) 2280 } 2281 case token.VAR: 2282 for _, sp := range d.Specs { 2283 w.walkVar(sp.(*ast.ValueSpec)) 2284 } 2285 default: 2286 log.Fatalf("unknown token type %d in GenDecl", d.Tok) 2287 } 2288 case *ast.FuncDecl: 2289 // Ignore. Handled in subsequent pass, by go/doc. 2290 default: 2291 log.Printf("unhandled %T, %#v\n", di, di) 2292 printer.Fprint(os.Stderr, w.fset, di) 2293 os.Stderr.Write([]byte("\n")) 2294 } 2295 } 2296} 2297 2298var constType = map[token.Token]string{ 2299 token.INT: "ideal-int", 2300 token.FLOAT: "ideal-float", 2301 token.STRING: "ideal-string", 2302 token.CHAR: "ideal-char", 2303 token.IMAG: "ideal-imag", 2304} 2305 2306var varType = map[token.Token]string{ 2307 token.INT: "int", 2308 token.FLOAT: "float64", 2309 token.STRING: "string", 2310 token.CHAR: "rune", 2311 token.IMAG: "complex128", 2312} 2313 2314var builtinTypes = []string{ 2315 "bool", "byte", "complex64", "complex128", "error", "float32", "float64", 2316 "int", "int8", "int16", "int32", "int64", "rune", "string", 2317 "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", 2318} 2319 2320func isBuiltinType(typ string) bool { 2321 for _, v := range builtinTypes { 2322 if v == typ { 2323 return true 2324 } 2325 } 2326 return false 2327} 2328 2329func constTypePriority(typ string) int { 2330 switch typ { 2331 case "complex128": 2332 return 100 2333 case "ideal-imag": 2334 return 99 2335 case "complex64": 2336 return 98 2337 case "float64": 2338 return 97 2339 case "ideal-float": 2340 return 96 2341 case "float32": 2342 return 95 2343 case "int64": 2344 return 94 2345 case "int", "uint", "uintptr": 2346 return 93 2347 case "ideal-int": 2348 return 92 2349 case "int16", "uint16", "int8", "uint8", "byte": 2350 return 91 2351 case "ideal-char": 2352 return 90 2353 } 2354 return 101 2355} 2356 2357func (w *Walker) constRealType(typ string) string { 2358 pos := strings.Index(typ, ".") 2359 if pos >= 0 { 2360 pkg := typ[:pos] 2361 if pkg == "C" { 2362 return "int" 2363 } 2364 typ = typ[pos+1:] 2365 if p := w.findPackage(pkg); p != nil { 2366 ret := p.findType(typ) 2367 if ret != nil { 2368 return w.nodeString(w.namelessType(ret)) 2369 } 2370 } 2371 } else { 2372 ret := w.curPackage.findType(typ) 2373 if ret != nil { 2374 return w.nodeString(w.namelessType(ret)) 2375 } 2376 } 2377 return typ 2378} 2379 2380func (w *Walker) constValueType(vi interface{}) (string, error) { 2381 switch v := vi.(type) { 2382 case *ast.BasicLit: 2383 litType, ok := constType[v.Kind] 2384 if !ok { 2385 return "", fmt.Errorf("unknown basic literal kind %#v", v) 2386 } 2387 return litType, nil 2388 case *ast.UnaryExpr: 2389 return w.constValueType(v.X) 2390 case *ast.SelectorExpr: 2391 lhs := w.nodeString(v.X) 2392 rhs := w.nodeString(v.Sel) 2393 //if CGO 2394 if lhs == "C" { 2395 return lhs + "." + rhs, nil 2396 } 2397 if p := w.findPackage(lhs); p != nil { 2398 if ret, ok := p.consts[rhs]; ok { 2399 return w.pkgRetType(p.name, ret.T), nil 2400 } 2401 } 2402 return "", fmt.Errorf("unknown constant reference to %s.%s", lhs, rhs) 2403 case *ast.Ident: 2404 if v.Name == "iota" { 2405 return "ideal-int", nil // hack. 2406 } 2407 if v.Name == "false" || v.Name == "true" { 2408 return "bool", nil 2409 } 2410 if t, ok := w.curPackage.consts[v.Name]; ok { 2411 return t.T, nil 2412 } 2413 return constDepPrefix + v.Name, nil 2414 case *ast.BinaryExpr: 2415 //== > < ! != >= <= 2416 if v.Op == token.EQL || v.Op == token.LSS || v.Op == token.GTR || v.Op == token.NOT || 2417 v.Op == token.NEQ || v.Op == token.LEQ || v.Op == token.GEQ { 2418 return "bool", nil 2419 } 2420 left, err := w.constValueType(v.X) 2421 if err != nil { 2422 return "", err 2423 } 2424 if v.Op == token.SHL || v.Op == token.SHR { 2425 return left, err 2426 } 2427 right, err := w.constValueType(v.Y) 2428 if err != nil { 2429 return "", err 2430 } 2431 //const left != right , one or two is ideal- 2432 if left != right { 2433 if strings.HasPrefix(left, constDepPrefix) && strings.HasPrefix(right, constDepPrefix) { 2434 // Just pick one. 2435 // e.g. text/scanner GoTokens const-dependency:ScanIdents, const-dependency:ScanFloats 2436 return left, nil 2437 } 2438 lp := constTypePriority(w.constRealType(left)) 2439 rp := constTypePriority(w.constRealType(right)) 2440 if lp >= rp { 2441 return left, nil 2442 } else { 2443 return right, nil 2444 } 2445 return "", fmt.Errorf("in BinaryExpr, unhandled type mismatch; left=%q, right=%q", left, right) 2446 } 2447 return left, nil 2448 case *ast.CallExpr: 2449 // Not a call, but a type conversion. 2450 typ := w.nodeString(v.Fun) 2451 switch typ { 2452 case "complex": 2453 return "complex128", nil 2454 case "real", "imag": 2455 return "float64", nil 2456 } 2457 return typ, nil 2458 case *ast.ParenExpr: 2459 return w.constValueType(v.X) 2460 } 2461 return "", fmt.Errorf("unknown const value type %T", vi) 2462} 2463 2464func (w *Walker) pkgRetType(pkg, ret string) string { 2465 pkg = pkg[strings.LastIndex(pkg, "/")+1:] 2466 if strings.HasPrefix(ret, "[]") { 2467 return "[]" + w.pkgRetType(pkg, ret[2:]) 2468 } 2469 if strings.HasPrefix(ret, "*") { 2470 return "*" + w.pkgRetType(pkg, ret[1:]) 2471 } 2472 if ast.IsExported(ret) { 2473 return pkg + "." + ret 2474 } 2475 return ret 2476} 2477 2478func (w *Walker) findStructFieldType(st ast.Expr, name string) ast.Expr { 2479 _, expr := w.findStructField(st, name) 2480 return expr 2481} 2482 2483func (w *Walker) findStructFieldFunction(st ast.Expr, name string) (*TypeInfo, error) { 2484 if s, ok := st.(*ast.StructType); ok { 2485 for _, fi := range s.Fields.List { 2486 typ := fi.Type 2487 if fi.Names == nil { 2488 switch v := typ.(type) { 2489 case *ast.Ident: 2490 if t := w.curPackage.findType(v.Name); t != nil { 2491 return w.lookupFunction(v.Name, name) 2492 } 2493 case *ast.SelectorExpr: 2494 pt := w.nodeString(typ) 2495 pos := strings.Index(pt, ".") 2496 if pos != -1 { 2497 if p := w.findPackage(pt[:pos]); p != nil { 2498 if t := p.findType(pt[pos+1:]); t != nil { 2499 return w.lookupFunction(pt, name) 2500 } 2501 } 2502 } 2503 case *ast.StarExpr: 2504 return w.findStructFieldFunction(v.X, name) 2505 default: 2506 if apiVerbose { 2507 log.Printf("unable to handle embedded %T", typ) 2508 } 2509 } 2510 } 2511 } 2512 } 2513 return nil, nil 2514} 2515 2516func (w *Walker) findStructField(st ast.Expr, name string) (*ast.Ident, ast.Expr) { 2517 if s, ok := st.(*ast.StructType); ok { 2518 for _, fi := range s.Fields.List { 2519 typ := fi.Type 2520 for _, n := range fi.Names { 2521 if n.Name == name { 2522 return n, fi.Type 2523 } 2524 } 2525 if fi.Names == nil { 2526 switch v := typ.(type) { 2527 case *ast.Ident: 2528 if t := w.curPackage.findType(v.Name); t != nil { 2529 if v.Name == name { 2530 return v, v 2531 } 2532 id, expr := w.findStructField(t, name) 2533 if id != nil { 2534 return id, expr 2535 } 2536 } 2537 case *ast.StarExpr: 2538 switch vv := v.X.(type) { 2539 case *ast.Ident: 2540 if t := w.curPackage.findType(vv.Name); t != nil { 2541 if vv.Name == name { 2542 return vv, v.X 2543 } 2544 id, expr := w.findStructField(t, name) 2545 if id != nil { 2546 return id, expr 2547 } 2548 } 2549 case *ast.SelectorExpr: 2550 pt := w.nodeString(typ) 2551 pos := strings.Index(pt, ".") 2552 if pos != -1 { 2553 if p := w.findPackage(pt[:pos]); p != nil { 2554 if t := p.findType(pt[pos+1:]); t != nil { 2555 return w.findStructField(t, name) 2556 } 2557 } 2558 } 2559 default: 2560 if apiVerbose { 2561 log.Printf("unable to handle embedded starexpr before %T", typ) 2562 } 2563 } 2564 case *ast.SelectorExpr: 2565 pt := w.nodeString(typ) 2566 pos := strings.Index(pt, ".") 2567 if pos != -1 { 2568 if p := w.findPackage(pt[:pos]); p != nil { 2569 if t := p.findType(pt[pos+1:]); t != nil { 2570 return w.findStructField(t, name) 2571 } 2572 } 2573 } 2574 default: 2575 if apiVerbose { 2576 log.Printf("unable to handle embedded %T", typ) 2577 } 2578 } 2579 } 2580 } 2581 } 2582 return nil, nil 2583} 2584 2585func (w *Walker) lookupFunction(name, sel string) (*TypeInfo, error) { 2586 name = strings.TrimLeft(name, "*") 2587 if p := w.findPackage(name); p != nil { 2588 fn := p.findCallFunc(sel) 2589 if fn != nil { 2590 return &TypeInfo{Kind: KindFunc, X: fn, Name: name + "." + sel, T: fn, Type: w.nodeString(w.namelessType(fn))}, nil 2591 } 2592 } 2593 pos := strings.Index(name, ".") 2594 if pos != -1 { 2595 pkg := name[:pos] 2596 typ := name[pos+1:] 2597 if p := w.findPackage(pkg); p != nil { 2598 if ident, fn := p.findMethod(typ, sel); fn != nil { 2599 return &TypeInfo{Kind: KindMethod, X: fn, Name: name + "." + sel, T: ident, Type: w.nodeString(w.namelessType(fn))}, nil 2600 } 2601 } 2602 return nil, fmt.Errorf("not lookup pkg type function pkg: %s, %s. %s. %s", name, pkg, typ, sel) 2603 } 2604 2605 //find local var.func() 2606 if ns, nt, n := w.resolveName(name); n >= 0 { 2607 var vt string 2608 if nt != nil { 2609 vt = w.nodeString(w.namelessType(nt)) 2610 } else if ns != nil { 2611 typ, err := w.varValueType(ns, n) 2612 if err == nil { 2613 vt = typ 2614 } 2615 } else { 2616 typ := w.curPackage.findSelectorType(name) 2617 if typ != nil { 2618 vt = w.nodeString(w.namelessType(typ)) 2619 } 2620 } 2621 if strings.HasPrefix(vt, "*") { 2622 vt = vt[1:] 2623 } 2624 if vt == "error" && sel == "Error" { 2625 return &TypeInfo{Kind: KindBuiltin, Name: "error.Error", Type: "()string"}, nil 2626 } 2627 if fn, ok := w.curPackage.functions[vt+"."+sel]; ok { 2628 return &TypeInfo{Kind: KindMethod, X: fn.ft, Name: name + "." + sel, T: fn.ft, Type: w.nodeString(w.namelessType(fn))}, nil 2629 } 2630 } 2631 if typ, ok := w.curPackage.structs[name]; ok { 2632 if fn, ok := w.curPackage.functions[name+"."+sel]; ok { 2633 return &TypeInfo{Kind: KindMethod, X: fn.ft, Name: name + "." + sel, T: fn.ft, Type: w.nodeString(w.namelessType(fn.ft))}, nil 2634 } 2635 if info, err := w.findStructFieldFunction(typ, sel); err == nil { 2636 return info, nil 2637 } 2638 // struct field is type function 2639 if ft := w.findStructFieldType(typ, sel); ft != nil { 2640 typ, err := w.varValueType(ft, 0) 2641 if err != nil { 2642 typ = w.nodeString(ft) 2643 } 2644 return &TypeInfo{Kind: KindField, X: ft, Name: name + "." + sel, T: ft, Type: typ}, nil 2645 } 2646 } 2647 2648 if ident, fn := w.curPackage.findMethod(name, sel); ident != nil && fn != nil { 2649 return &TypeInfo{Kind: KindMethod, X: fn, Name: name + "." + sel, T: ident, Type: w.nodeString(w.namelessType(fn))}, nil 2650 } 2651 2652 if p := w.findPackage(name); p != nil { 2653 fn := p.findCallFunc(sel) 2654 if fn != nil { 2655 return &TypeInfo{Kind: KindFunc, X: fn, Name: name + "." + sel, T: fn, Type: w.nodeString(w.namelessType(fn))}, nil 2656 } 2657 return nil, fmt.Errorf("not find pkg func0 %v.%v", p.name, sel) 2658 } 2659 return nil, fmt.Errorf("not lookup func %v.%v", name, sel) 2660} 2661 2662func (w *Walker) varFunctionType(name, sel string, index int) (string, error) { 2663 name = strings.TrimLeft(name, "*") 2664 pos := strings.Index(name, ".") 2665 if pos != -1 { 2666 pkg := name[:pos] 2667 typ := name[pos+1:] 2668 2669 if p := w.findPackage(pkg); p != nil { 2670 _, fn := p.findMethod(typ, sel) 2671 if fn != nil { 2672 ret := funcRetType(fn, index) 2673 if ret != nil { 2674 return w.pkgRetType(p.name, w.nodeString(w.namelessType(ret))), nil 2675 } 2676 } 2677 } 2678 return "", fmt.Errorf("unknown pkg type function pkg: %s.%s.%s", pkg, typ, sel) 2679 } 2680 //find local var 2681 if v, ok := w.localvar[name]; ok { 2682 vt := v.T 2683 if strings.HasPrefix(vt, "*") { 2684 vt = vt[1:] 2685 } 2686 if vt == "error" && sel == "Error" { 2687 return "string", nil 2688 } 2689 typ, err := w.varFunctionType(vt, sel, 0) 2690 if err == nil { 2691 return typ, nil 2692 } 2693 } 2694 //find global var.func() 2695 if ns, nt, n := w.resolveName(name); n >= 0 { 2696 var vt string 2697 if nt != nil { 2698 vt = w.nodeString(w.namelessType(nt)) 2699 } else if ns != nil { 2700 typ, err := w.varValueType(ns, n) 2701 if err == nil { 2702 vt = typ 2703 } 2704 } else { 2705 typ := w.curPackage.findSelectorType(name) 2706 if typ != nil { 2707 vt = w.nodeString(w.namelessType(typ)) 2708 } 2709 } 2710 if strings.HasPrefix(vt, "*") { 2711 vt = vt[1:] 2712 } 2713 if vt == "error" && sel == "Error" { 2714 return "string", nil 2715 } 2716 if fn, ok := w.curPackage.functions[vt+"."+sel]; ok { 2717 return w.nodeString(w.namelessType(funcRetType(fn.ft, index))), nil 2718 } 2719 } 2720 if typ, ok := w.curPackage.structs[name]; ok { 2721 if ft := w.findStructFieldType(typ, sel); ft != nil { 2722 return w.varValueType(ft, index) 2723 } 2724 } 2725 //find pkg.func() 2726 if p := w.findPackage(name); p != nil { 2727 typ := p.findCallType(sel, index) 2728 if typ != nil { 2729 return w.pkgRetType(p.name, w.nodeString(w.namelessType(typ))), nil 2730 } 2731 //log.Println("->", p.functions) 2732 return "", fmt.Errorf("not find pkg func1 %v . %v", p.name, sel) 2733 } 2734 return "", fmt.Errorf("not find func %v.%v", name, sel) 2735} 2736 2737func (w *Walker) lookupSelector(name string, sel string) (*TypeInfo, error) { 2738 name = strings.TrimLeft(name, "*") 2739 pos := strings.Index(name, ".") 2740 if pos != -1 { 2741 pkg := name[:pos] 2742 typ := name[pos+1:] 2743 if p := w.findPackage(pkg); p != nil { 2744 t := p.findType(typ) 2745 if t != nil { 2746 typ := w.findStructFieldType(t, sel) 2747 if typ != nil { 2748 return &TypeInfo{Kind: KindField, X: typ, Name: name + "." + sel, T: typ, Type: w.pkgRetType(p.name, w.nodeString(w.namelessType(typ)))}, nil 2749 } 2750 } 2751 } 2752 return nil, fmt.Errorf("lookup unknown pkg type selector pkg: %s.%s %s", pkg, typ, sel) 2753 } 2754 2755 if lv, ok := w.localvar[name]; ok { 2756 return w.lookupSelector(lv.T, sel) 2757 } 2758 2759 vs, vt, n := w.resolveName(name) 2760 if n >= 0 { 2761 var typ string 2762 if vt != nil { 2763 typ = w.nodeString(w.namelessType(vt)) 2764 } else { 2765 typ, _ = w.varValueType(vs, n) 2766 } 2767 if strings.HasPrefix(typ, "*") { 2768 typ = typ[1:] 2769 } 2770 //typ is type, find real type 2771 for k, v := range w.curPackage.types { 2772 if k == typ { 2773 typ = w.nodeString(w.namelessType(v)) 2774 } 2775 } 2776 pos := strings.Index(typ, ".") 2777 if pos == -1 { 2778 t := w.curPackage.findType(typ) 2779 if t != nil { 2780 typ := w.findStructFieldType(t, sel) 2781 if typ != nil { 2782 return &TypeInfo{Kind: KindField, X: typ, Name: name + "." + sel, T: typ, Type: w.nodeString(w.namelessType(typ))}, nil 2783 } 2784 } 2785 } else { 2786 name := typ[:pos] 2787 typ = typ[pos+1:] 2788 if p := w.findPackage(name); p != nil { 2789 t := p.findType(typ) 2790 if t != nil { 2791 typ := w.findStructFieldType(t, sel) 2792 if typ != nil { 2793 return &TypeInfo{Kind: KindField, X: typ, Name: name + "." + sel, T: typ, Type: w.nodeString(w.namelessType(typ))}, nil 2794 } 2795 } 2796 } 2797 } 2798 } 2799 if p := w.findPackage(name); p != nil { 2800 typ := p.findSelectorType(sel) 2801 if typ != nil { 2802 return &TypeInfo{Kind: KindType, X: typ, Name: name + "." + sel, T: typ, Type: w.pkgRetType(p.name, w.nodeString(w.namelessType(typ)))}, nil 2803 } 2804 } 2805 t := w.curPackage.findType(name) 2806 if t != nil { 2807 typ := w.findStructFieldType(t, sel) 2808 if typ != nil { 2809 return &TypeInfo{Kind: KindField, X: typ, Name: name + "." + sel, T: typ, Type: w.nodeString(w.namelessType(typ))}, nil 2810 } 2811 } 2812 if t, ok := w.curPackage.types[name]; ok { 2813 return w.lookupSelector(w.nodeString(t), sel) 2814 } 2815 return nil, fmt.Errorf("unknown selector expr ident: %s.%s", name, sel) 2816} 2817 2818func (w *Walker) varSelectorType(name string, sel string) (string, error) { 2819 name = strings.TrimLeft(name, "*") 2820 pos := strings.Index(name, ".") 2821 if pos != -1 { 2822 pkg := name[:pos] 2823 typ := name[pos+1:] 2824 if p := w.findPackage(pkg); p != nil { 2825 t := p.findType(typ) 2826 if t != nil { 2827 typ := w.findStructFieldType(t, sel) 2828 if typ != nil { 2829 return w.pkgRetType(pkg, w.nodeString(w.namelessType(typ))), nil 2830 } 2831 } 2832 } 2833 return "", fmt.Errorf("unknown pkg type selector pkg: %s.%s.%s", pkg, typ, sel) 2834 } 2835 //check local 2836 if lv, ok := w.localvar[name]; ok { 2837 return w.varSelectorType(lv.T, sel) 2838 } 2839 //check struct 2840 if t := w.curPackage.findType(name); t != nil { 2841 typ := w.findStructFieldType(t, sel) 2842 if typ != nil { 2843 return w.nodeString(w.namelessType(typ)), nil 2844 } 2845 } 2846 //check var 2847 vs, vt, n := w.resolveName(name) 2848 if n >= 0 { 2849 var typ string 2850 if vt != nil { 2851 typ = w.nodeString(w.namelessType(vt)) 2852 } else { 2853 typ, _ = w.varValueType(vs, n) 2854 } 2855 if strings.HasPrefix(typ, "*") { 2856 typ = typ[1:] 2857 } 2858 //typ is type, find real type 2859 for k, v := range w.curPackage.types { 2860 if k == typ { 2861 typ = w.nodeString(w.namelessType(v)) 2862 } 2863 } 2864 pos := strings.Index(typ, ".") 2865 if pos == -1 { 2866 t := w.curPackage.findType(typ) 2867 if t != nil { 2868 typ := w.findStructFieldType(t, sel) 2869 if typ != nil { 2870 return w.nodeString(w.namelessType(typ)), nil 2871 } 2872 } 2873 } else { 2874 name := typ[:pos] 2875 typ = typ[pos+1:] 2876 if p := w.findPackage(name); p != nil { 2877 t := p.findType(typ) 2878 if t != nil { 2879 typ := w.findStructFieldType(t, sel) 2880 if typ != nil { 2881 return w.nodeString(w.namelessType(typ)), nil 2882 } 2883 } 2884 } 2885 } 2886 } 2887 2888 if p := w.findPackage(name); p != nil { 2889 typ := p.findSelectorType(sel) 2890 if typ != nil { 2891 return w.pkgRetType(p.name, w.nodeString(w.namelessType(typ))), nil 2892 } 2893 } 2894 return "", fmt.Errorf("unknown var selector expr ident: %s.%s", name, sel) 2895} 2896 2897func (w *Walker) varValueType(vi ast.Expr, index int) (string, error) { 2898 if vi == nil { 2899 return "", nil 2900 } 2901 switch v := vi.(type) { 2902 case *ast.BasicLit: 2903 litType, ok := varType[v.Kind] 2904 if !ok { 2905 return "", fmt.Errorf("unknown basic literal kind %#v", v) 2906 } 2907 return litType, nil 2908 case *ast.CompositeLit: 2909 return w.nodeString(v.Type), nil 2910 case *ast.FuncLit: 2911 return w.nodeString(w.namelessType(v.Type)), nil 2912 case *ast.InterfaceType: 2913 return w.nodeString(v), nil 2914 case *ast.Ellipsis: 2915 typ, err := w.varValueType(v.Elt, index) 2916 if err != nil { 2917 return "", err 2918 } 2919 return "[]" + typ, nil 2920 case *ast.StarExpr: 2921 typ, err := w.varValueType(v.X, index) 2922 if err != nil { 2923 return "", err 2924 } 2925 return "*" + typ, err 2926 case *ast.UnaryExpr: 2927 if v.Op == token.AND { 2928 typ, err := w.varValueType(v.X, index) 2929 return "*" + typ, err 2930 } 2931 return "", fmt.Errorf("unknown unary expr: %#v", v) 2932 case *ast.SelectorExpr: 2933 switch st := v.X.(type) { 2934 case *ast.Ident: 2935 return w.varSelectorType(st.Name, v.Sel.Name) 2936 case *ast.CallExpr: 2937 typ, err := w.varValueType(v.X, index) 2938 if err == nil { 2939 if strings.HasPrefix(typ, "*") { 2940 typ = typ[1:] 2941 } 2942 t := w.curPackage.findType(typ) 2943 if st, ok := t.(*ast.StructType); ok { 2944 for _, fi := range st.Fields.List { 2945 for _, n := range fi.Names { 2946 if n.Name == v.Sel.Name { 2947 return w.varValueType(fi.Type, index) 2948 } 2949 } 2950 } 2951 } 2952 } 2953 case *ast.SelectorExpr: 2954 typ, err := w.varValueType(v.X, index) 2955 if err == nil { 2956 return w.varSelectorType(typ, v.Sel.Name) 2957 } 2958 case *ast.IndexExpr: 2959 typ, err := w.varValueType(st.X, index) 2960 if err == nil { 2961 if strings.HasPrefix(typ, "[]") { 2962 return w.varSelectorType(typ[2:], v.Sel.Name) 2963 } 2964 } 2965 case *ast.CompositeLit: 2966 typ, err := w.varValueType(st.Type, 0) 2967 if err == nil { 2968 //log.Println(typ, v.Sel.Name) 2969 t, err := w.varSelectorType(typ, v.Sel.Name) 2970 if err == nil { 2971 return t, nil 2972 } 2973 } 2974 } 2975 return "", fmt.Errorf("var unknown selector expr: %T %s.%s", v.X, w.nodeString(v.X), v.Sel) 2976 case *ast.Ident: 2977 if v.Name == "true" || v.Name == "false" { 2978 return "bool", nil 2979 } 2980 if isBuiltinType(v.Name) { 2981 return v.Name, nil 2982 } 2983 if lv, ok := w.localvar[v.Name]; ok { 2984 return lv.T, nil 2985 } 2986 vt := w.curPackage.findType(v.Name) 2987 if vt != nil { 2988 if _, ok := vt.(*ast.StructType); ok { 2989 return v.Name, nil 2990 } 2991 return w.nodeString(vt), nil 2992 } 2993 vs, _, n := w.resolveName(v.Name) 2994 if n >= 0 { 2995 return w.varValueType(vs, n) 2996 } 2997 return "", fmt.Errorf("unresolved identifier: %q", v.Name) 2998 case *ast.BinaryExpr: 2999 //== > < ! != >= <= 3000 if v.Op == token.EQL || v.Op == token.LSS || v.Op == token.GTR || v.Op == token.NOT || 3001 v.Op == token.NEQ || v.Op == token.LEQ || v.Op == token.GEQ { 3002 return "bool", nil 3003 } 3004 left, err := w.varValueType(v.X, index) 3005 if err != nil { 3006 return "", err 3007 } 3008 right, err := w.varValueType(v.Y, index) 3009 if err != nil { 3010 return "", err 3011 } 3012 if left != right { 3013 return "", fmt.Errorf("in BinaryExpr, unhandled type mismatch; left=%q, right=%q", left, right) 3014 } 3015 return left, nil 3016 case *ast.ParenExpr: 3017 return w.varValueType(v.X, index) 3018 case *ast.CallExpr: 3019 switch ft := v.Fun.(type) { 3020 case *ast.ArrayType: 3021 return w.nodeString(v.Fun), nil 3022 case *ast.Ident: 3023 switch ft.Name { 3024 case "make": 3025 return w.nodeString(w.namelessType(v.Args[0])), nil 3026 case "new": 3027 return "*" + w.nodeString(w.namelessType(v.Args[0])), nil 3028 case "append": 3029 return w.varValueType(v.Args[0], 0) 3030 case "recover": 3031 return "interface{}", nil 3032 case "len", "cap", "copy": 3033 return "int", nil 3034 case "complex": 3035 return "complex128", nil 3036 case "real": 3037 return "float64", nil 3038 case "imag": 3039 return "float64", nil 3040 } 3041 if isBuiltinType(ft.Name) { 3042 return ft.Name, nil 3043 } 3044 typ := w.curPackage.findCallType(ft.Name, index) 3045 if typ != nil { 3046 return w.nodeString(w.namelessType(typ)), nil 3047 } 3048 //if local var type 3049 if fn, ok := w.localvar[ft.Name]; ok { 3050 typ := fn.T 3051 if strings.HasPrefix(typ, "func(") { 3052 expr, err := parser.ParseExpr(typ + "{}") 3053 if err == nil { 3054 if fl, ok := expr.(*ast.FuncLit); ok { 3055 retType := funcRetType(fl.Type, index) 3056 if retType != nil { 3057 return w.nodeString(w.namelessType(retType)), nil 3058 } 3059 } 3060 } 3061 } 3062 } 3063 //if var is func() type 3064 vs, _, n := w.resolveName(ft.Name) 3065 if n >= 0 { 3066 if vs != nil { 3067 typ, err := w.varValueType(vs, n) 3068 if err == nil { 3069 if strings.HasPrefix(typ, "func(") { 3070 expr, err := parser.ParseExpr(typ + "{}") 3071 if err == nil { 3072 if fl, ok := expr.(*ast.FuncLit); ok { 3073 retType := funcRetType(fl.Type, index) 3074 if retType != nil { 3075 return w.nodeString(w.namelessType(retType)), nil 3076 } 3077 } 3078 } 3079 } 3080 } 3081 } 3082 } 3083 return "", fmt.Errorf("unknown funcion %s %s", w.curPackageName, ft.Name) 3084 case *ast.SelectorExpr: 3085 typ, err := w.varValueType(ft.X, index) 3086 if err == nil { 3087 if strings.HasPrefix(typ, "*") { 3088 typ = typ[1:] 3089 } 3090 retType := w.curPackage.findCallType(typ+"."+ft.Sel.Name, index) 3091 if retType != nil { 3092 return w.nodeString(w.namelessType(retType)), nil 3093 } 3094 } 3095 switch st := ft.X.(type) { 3096 case *ast.Ident: 3097 return w.varFunctionType(st.Name, ft.Sel.Name, index) 3098 case *ast.CallExpr: 3099 typ, err := w.varValueType(st, 0) 3100 if err != nil { 3101 return "", err 3102 } 3103 return w.varFunctionType(typ, ft.Sel.Name, index) 3104 case *ast.SelectorExpr: 3105 typ, err := w.varValueType(st, index) 3106 if err == nil { 3107 return w.varFunctionType(typ, ft.Sel.Name, index) 3108 } 3109 case *ast.IndexExpr: 3110 typ, err := w.varValueType(st.X, index) 3111 if err == nil { 3112 if strings.HasPrefix(typ, "[]") { 3113 return w.varFunctionType(typ[2:], ft.Sel.Name, index) 3114 } 3115 } 3116 case *ast.TypeAssertExpr: 3117 typ := w.nodeString(w.namelessType(st.Type)) 3118 typ = strings.TrimLeft(typ, "*") 3119 return w.varFunctionType(typ, ft.Sel.Name, index) 3120 } 3121 return "", fmt.Errorf("unknown var function selector %v %T", w.nodeString(ft.X), ft.X) 3122 case *ast.FuncLit: 3123 retType := funcRetType(ft.Type, index) 3124 if retType != nil { 3125 return w.nodeString(w.namelessType(retType)), nil 3126 } 3127 case *ast.CallExpr: 3128 typ, err := w.varValueType(v.Fun, 0) 3129 if err == nil && strings.HasPrefix(typ, "func(") { 3130 expr, err := parser.ParseExpr(typ + "{}") 3131 if err == nil { 3132 if fl, ok := expr.(*ast.FuncLit); ok { 3133 retType := funcRetType(fl.Type, index) 3134 if retType != nil { 3135 return w.nodeString(w.namelessType(retType)), nil 3136 } 3137 } 3138 } 3139 } 3140 } 3141 return "", fmt.Errorf("not a known function %T %v", v.Fun, w.nodeString(v.Fun)) 3142 case *ast.MapType: 3143 return fmt.Sprintf("map[%s](%s)", w.nodeString(w.namelessType(v.Key)), w.nodeString(w.namelessType(v.Value))), nil 3144 case *ast.ArrayType: 3145 return fmt.Sprintf("[]%s", w.nodeString(w.namelessType(v.Elt))), nil 3146 case *ast.FuncType: 3147 return w.nodeString(w.namelessType(v)), nil 3148 case *ast.IndexExpr: 3149 typ, err := w.varValueType(v.X, index) 3150 typ = strings.TrimLeft(typ, "*") 3151 if err == nil { 3152 if index == 0 { 3153 return typ, nil 3154 } else if index == 1 { 3155 return "bool", nil 3156 } 3157 if strings.HasPrefix(typ, "[]") { 3158 return typ[2:], nil 3159 } else if strings.HasPrefix(typ, "map[") { 3160 node, err := parser.ParseExpr(typ + "{}") 3161 if err == nil { 3162 if cl, ok := node.(*ast.CompositeLit); ok { 3163 if m, ok := cl.Type.(*ast.MapType); ok { 3164 return w.nodeString(w.namelessType(m.Value)), nil 3165 } 3166 } 3167 } 3168 } 3169 } 3170 return "", fmt.Errorf("unknown index %v %v %v %v", typ, v.X, index, err) 3171 case *ast.SliceExpr: 3172 return w.varValueType(v.X, index) 3173 case *ast.ChanType: 3174 typ, err := w.varValueType(v.Value, index) 3175 if err == nil { 3176 if v.Dir == ast.RECV { 3177 return "<-chan " + typ, nil 3178 } else if v.Dir == ast.SEND { 3179 return "chan<- " + typ, nil 3180 } 3181 return "chan " + typ, nil 3182 } 3183 case *ast.TypeAssertExpr: 3184 if index == 1 { 3185 return "bool", nil 3186 } 3187 return w.nodeString(w.namelessType(v.Type)), nil 3188 default: 3189 return "", fmt.Errorf("unknown value type %v %T", w.nodeString(vi), vi) 3190 } 3191 //panic("unreachable") 3192 return "", fmt.Errorf("unreachable value type %v %T", vi, vi) 3193} 3194 3195// resolveName finds a top-level node named name and returns the node 3196// v and its type t, if known. 3197func (w *Walker) resolveName(name string) (v ast.Expr, t interface{}, n int) { 3198 for _, file := range w.curPackage.apkg.Files { 3199 for _, di := range file.Decls { 3200 switch d := di.(type) { 3201 case *ast.GenDecl: 3202 switch d.Tok { 3203 case token.VAR: 3204 for _, sp := range d.Specs { 3205 vs := sp.(*ast.ValueSpec) 3206 for i, vname := range vs.Names { 3207 if vname.Name == name { 3208 if len(vs.Values) == 1 { 3209 return vs.Values[0], vs.Type, i 3210 } 3211 return nil, vs.Type, i 3212 } 3213 } 3214 } 3215 } 3216 } 3217 } 3218 } 3219 return nil, nil, -1 3220} 3221 3222// constDepPrefix is a magic prefix that is used by constValueType 3223// and walkConst to signal that a type isn't known yet. These are 3224// resolved at the end of walking of a package's files. 3225const constDepPrefix = "const-dependency:" 3226 3227func (w *Walker) walkConst(vs *ast.ValueSpec) { 3228 for _, ident := range vs.Names { 3229 if !w.isExtract(ident.Name) { 3230 continue 3231 } 3232 litType := "" 3233 if vs.Type != nil { 3234 litType = w.nodeString(vs.Type) 3235 } else { 3236 litType = w.lastConstType 3237 if vs.Values != nil { 3238 if len(vs.Values) != 1 { 3239 log.Fatalf("const %q, values: %#v", ident.Name, vs.Values) 3240 } 3241 var err error 3242 litType, err = w.constValueType(vs.Values[0]) 3243 if err != nil { 3244 if apiVerbose { 3245 log.Printf("unknown kind in const %q (%T): %v", ident.Name, vs.Values[0], err) 3246 } 3247 litType = "unknown-type" 3248 } 3249 } 3250 } 3251 if strings.HasPrefix(litType, constDepPrefix) { 3252 dep := litType[len(constDepPrefix):] 3253 w.constDep[ident.Name] = &ExprType{T: dep, X: ident} 3254 continue 3255 } 3256 if litType == "" { 3257 if apiVerbose { 3258 log.Printf("unknown kind in const %q", ident.Name) 3259 } 3260 continue 3261 } 3262 w.lastConstType = litType 3263 3264 w.curPackage.consts[ident.Name] = &ExprType{T: litType, X: ident} 3265 3266 if isExtract(ident.Name) { 3267 w.emitFeature(fmt.Sprintf("const %s %s", ident, litType), ident.Pos()) 3268 } 3269 } 3270} 3271 3272func (w *Walker) resolveConstantDeps() { 3273 var findConstType func(string) string 3274 findConstType = func(ident string) string { 3275 if dep, ok := w.constDep[ident]; ok { 3276 return findConstType(dep.T) 3277 } 3278 if t, ok := w.curPackage.consts[ident]; ok { 3279 return t.T 3280 } 3281 return "" 3282 } 3283 for ident, info := range w.constDep { 3284 if !isExtract(ident) { 3285 continue 3286 } 3287 t := findConstType(ident) 3288 if t == "" { 3289 if apiVerbose { 3290 log.Printf("failed to resolve constant %q", ident) 3291 } 3292 continue 3293 } 3294 w.curPackage.consts[ident] = &ExprType{T: t, X: info.X} 3295 w.emitFeature(fmt.Sprintf("const %s %s", ident, t), info.X.Pos()) 3296 } 3297} 3298 3299func (w *Walker) walkVar(vs *ast.ValueSpec) { 3300 if vs.Type != nil { 3301 typ := w.nodeString(vs.Type) 3302 for _, ident := range vs.Names { 3303 w.curPackage.vars[ident.Name] = &ExprType{T: typ, X: ident} 3304 if isExtract(ident.Name) { 3305 w.emitFeature(fmt.Sprintf("var %s %s", ident, typ), ident.Pos()) 3306 } 3307 } 3308 } else if len(vs.Names) == len(vs.Values) { 3309 for n, ident := range vs.Names { 3310 if !w.isExtract(ident.Name) { 3311 continue 3312 } 3313 typ, err := w.varValueType(vs.Values[n], n) 3314 if err != nil { 3315 if apiVerbose { 3316 log.Printf("unknown type of variable0 %q, type %T, error = %v, pos=%s", 3317 ident.Name, vs.Values[n], err, w.fset.Position(vs.Pos())) 3318 } 3319 typ = "unknown-type" 3320 } 3321 w.curPackage.vars[ident.Name] = &ExprType{T: typ, X: ident} 3322 if isExtract(ident.Name) { 3323 w.emitFeature(fmt.Sprintf("var %s %s", ident, typ), ident.Pos()) 3324 } 3325 } 3326 } else if len(vs.Values) == 1 { 3327 for n, ident := range vs.Names { 3328 if !w.isExtract(ident.Name) { 3329 continue 3330 } 3331 typ, err := w.varValueType(vs.Values[0], n) 3332 if err != nil { 3333 if apiVerbose { 3334 log.Printf("unknown type of variable1 %q, type %T, error = %v, pos=%s", 3335 ident.Name, vs.Values[0], err, w.fset.Position(vs.Pos())) 3336 } 3337 typ = "unknown-type" 3338 } 3339 w.curPackage.vars[ident.Name] = &ExprType{T: typ, X: ident} 3340 if isExtract(ident.Name) { 3341 w.emitFeature(fmt.Sprintf("var %s %s", ident, typ), ident.Pos()) 3342 } 3343 } 3344 } 3345} 3346 3347func (w *Walker) nodeString(node interface{}) string { 3348 if node == nil { 3349 return "" 3350 } 3351 var b bytes.Buffer 3352 printer.Fprint(&b, w.fset, node) 3353 return b.String() 3354} 3355 3356func (w *Walker) nodeDebug(node interface{}) string { 3357 if node == nil { 3358 return "" 3359 } 3360 var b bytes.Buffer 3361 ast.Fprint(&b, w.fset, node, nil) 3362 return b.String() 3363} 3364 3365func (w *Walker) noteInterface(name string, it *ast.InterfaceType) { 3366 w.interfaces[pkgSymbol{w.curPackageName, name}] = it 3367} 3368 3369func (w *Walker) walkTypeSpec(ts *ast.TypeSpec) { 3370 name := ts.Name.Name 3371 if !isExtract(name) { 3372 return 3373 } 3374 switch t := ts.Type.(type) { 3375 case *ast.StructType: 3376 w.walkStructType(name, t) 3377 case *ast.InterfaceType: 3378 w.walkInterfaceType(name, t) 3379 default: 3380 w.emitFeature(fmt.Sprintf("type %s %s", name, w.nodeString(ts.Type)), t.Pos()-token.Pos(len(name)+1)) 3381 } 3382} 3383 3384func (w *Walker) walkStructType(name string, t *ast.StructType) { 3385 typeStruct := fmt.Sprintf("type %s struct", name) 3386 w.emitFeature(typeStruct, t.Pos()-token.Pos(len(name)+1)) 3387 pop := w.pushScope(typeStruct) 3388 defer pop() 3389 for _, f := range t.Fields.List { 3390 typ := f.Type 3391 for _, name := range f.Names { 3392 if isExtract(name.Name) { 3393 w.emitFeature(fmt.Sprintf("%s %s", name, w.nodeString(w.namelessType(typ))), name.Pos()) 3394 } 3395 } 3396 if f.Names == nil { 3397 switch v := typ.(type) { 3398 case *ast.Ident: 3399 if isExtract(v.Name) { 3400 w.emitFeature(fmt.Sprintf("embedded %s", v.Name), v.Pos()) 3401 } 3402 case *ast.StarExpr: 3403 switch vv := v.X.(type) { 3404 case *ast.Ident: 3405 if isExtract(vv.Name) { 3406 w.emitFeature(fmt.Sprintf("embedded *%s", vv.Name), vv.Pos()) 3407 } 3408 case *ast.SelectorExpr: 3409 w.emitFeature(fmt.Sprintf("embedded %s", w.nodeString(typ)), v.Pos()) 3410 default: 3411 log.Fatalf("unable to handle embedded starexpr before %T", typ) 3412 } 3413 case *ast.SelectorExpr: 3414 w.emitFeature(fmt.Sprintf("embedded %s", w.nodeString(typ)), v.Pos()) 3415 default: 3416 if apiVerbose { 3417 log.Printf("unable to handle embedded %T", typ) 3418 } 3419 } 3420 } 3421 } 3422} 3423 3424// typeMethod is a method of an interface. 3425type typeMethod struct { 3426 name string // "Read" 3427 sig string // "([]byte) (int, error)", from funcSigString 3428 ft *ast.FuncType 3429 pos token.Pos 3430 recv ast.Expr 3431} 3432 3433// interfaceMethods returns the expanded list of exported methods for an interface. 3434// The boolean complete reports whether the list contains all methods (that is, the 3435// interface has no unexported methods). 3436// pkg is the complete package name ("net/http") 3437// iname is the interface name. 3438func (w *Walker) interfaceMethods(pkg, iname string) (methods []typeMethod, complete bool) { 3439 t, ok := w.interfaces[pkgSymbol{pkg, iname}] 3440 if !ok { 3441 if apiVerbose { 3442 log.Printf("failed to find interface %s.%s", pkg, iname) 3443 } 3444 return 3445 } 3446 3447 complete = true 3448 for _, f := range t.Methods.List { 3449 typ := f.Type 3450 switch tv := typ.(type) { 3451 case *ast.FuncType: 3452 for _, mname := range f.Names { 3453 if isExtract(mname.Name) { 3454 ft := typ.(*ast.FuncType) 3455 methods = append(methods, typeMethod{ 3456 name: mname.Name, 3457 sig: w.funcSigString(ft), 3458 ft: ft, 3459 pos: f.Pos(), 3460 }) 3461 } else { 3462 complete = false 3463 } 3464 } 3465 case *ast.Ident: 3466 embedded := typ.(*ast.Ident).Name 3467 if embedded == "error" { 3468 methods = append(methods, typeMethod{ 3469 name: "Error", 3470 sig: "() string", 3471 ft: &ast.FuncType{ 3472 Params: nil, 3473 Results: &ast.FieldList{ 3474 List: []*ast.Field{ 3475 &ast.Field{ 3476 Type: &ast.Ident{ 3477 Name: "string", 3478 }, 3479 }, 3480 }, 3481 }, 3482 }, 3483 pos: f.Pos(), 3484 }) 3485 continue 3486 } 3487 if !isExtract(embedded) { 3488 log.Fatalf("unexported embedded interface %q in exported interface %s.%s; confused", 3489 embedded, pkg, iname) 3490 } 3491 m, c := w.interfaceMethods(pkg, embedded) 3492 methods = append(methods, m...) 3493 complete = complete && c 3494 case *ast.SelectorExpr: 3495 lhs := w.nodeString(tv.X) 3496 rhs := w.nodeString(tv.Sel) 3497 fpkg, ok := w.selectorFullPkg[lhs] 3498 if !ok { 3499 log.Fatalf("can't resolve selector %q in interface %s.%s", lhs, pkg, iname) 3500 } 3501 m, c := w.interfaceMethods(fpkg, rhs) 3502 methods = append(methods, m...) 3503 complete = complete && c 3504 default: 3505 log.Fatalf("unknown type %T in interface field", typ) 3506 } 3507 } 3508 return 3509} 3510 3511func (w *Walker) walkInterfaceType(name string, t *ast.InterfaceType) { 3512 methNames := []string{} 3513 pop := w.pushScope("type " + name + " interface") 3514 methods, complete := w.interfaceMethods(w.curPackageName, name) 3515 w.packageMap[w.curPackageName].interfaceMethods[name] = methods 3516 for _, m := range methods { 3517 methNames = append(methNames, m.name) 3518 w.emitFeature(fmt.Sprintf("%s%s", m.name, m.sig), m.pos) 3519 } 3520 if !complete { 3521 // The method set has unexported methods, so all the 3522 // implementations are provided by the same package, 3523 // so the method set can be extended. Instead of recording 3524 // the full set of names (below), record only that there were 3525 // unexported methods. (If the interface shrinks, we will notice 3526 // because a method signature emitted during the last loop, 3527 // will disappear.) 3528 w.emitFeature("unexported methods", 0) 3529 } 3530 pop() 3531 3532 if !complete { 3533 return 3534 } 3535 3536 sort.Strings(methNames) 3537 if len(methNames) == 0 { 3538 w.emitFeature(fmt.Sprintf("type %s interface {}", name), t.Pos()-token.Pos(len(name)+1)) 3539 } else { 3540 w.emitFeature(fmt.Sprintf("type %s interface { %s }", name, strings.Join(methNames, ", ")), t.Pos()-token.Pos(len(name)+1)) 3541 } 3542} 3543 3544func baseTypeName(x ast.Expr) (name string, imported bool) { 3545 switch t := x.(type) { 3546 case *ast.Ident: 3547 return t.Name, false 3548 case *ast.SelectorExpr: 3549 if _, ok := t.X.(*ast.Ident); ok { 3550 // only possible for qualified type names; 3551 // assume type is imported 3552 return t.Sel.Name, true 3553 } 3554 case *ast.StarExpr: 3555 return baseTypeName(t.X) 3556 } 3557 return 3558} 3559 3560func (w *Walker) peekFuncDecl(f *ast.FuncDecl) { 3561 var fname = f.Name.Name 3562 var recv ast.Expr 3563 if f.Recv != nil { 3564 recvTypeName, imp := baseTypeName(f.Recv.List[0].Type) 3565 if imp { 3566 return 3567 } 3568 fname = recvTypeName + "." + f.Name.Name 3569 recv = f.Recv.List[0].Type 3570 } 3571 // Record return type for later use. 3572 //if f.Type.Results != nil && len(f.Type.Results.List) >= 1 { 3573 // record all function 3574 w.curPackage.functions[fname] = typeMethod{ 3575 name: fname, 3576 sig: w.funcSigString(f.Type), 3577 ft: f.Type, 3578 pos: f.Pos(), 3579 recv: recv, 3580 } 3581 //} 3582} 3583 3584func (w *Walker) walkFuncDecl(f *ast.FuncDecl) { 3585 if !w.isExtract(f.Name.Name) { 3586 return 3587 } 3588 if f.Recv != nil { 3589 // Method. 3590 recvType := w.nodeString(f.Recv.List[0].Type) 3591 keep := isExtract(recvType) || 3592 (strings.HasPrefix(recvType, "*") && 3593 isExtract(recvType[1:])) 3594 if !keep { 3595 return 3596 } 3597 w.emitFeature(fmt.Sprintf("method (%s) %s%s", recvType, f.Name.Name, w.funcSigString(f.Type)), f.Name.Pos()) 3598 return 3599 } 3600 // Else, a function 3601 w.emitFeature(fmt.Sprintf("func %s%s", f.Name.Name, w.funcSigString(f.Type)), f.Name.Pos()) 3602} 3603 3604func (w *Walker) funcSigString(ft *ast.FuncType) string { 3605 var b bytes.Buffer 3606 writeField := func(b *bytes.Buffer, f *ast.Field) { 3607 if n := len(f.Names); n > 1 { 3608 for i := 0; i < n; i++ { 3609 if i > 0 { 3610 b.WriteString(", ") 3611 } 3612 b.WriteString(w.nodeString(w.namelessType(f.Type))) 3613 } 3614 } else { 3615 b.WriteString(w.nodeString(w.namelessType(f.Type))) 3616 } 3617 } 3618 b.WriteByte('(') 3619 if ft.Params != nil { 3620 for i, f := range ft.Params.List { 3621 if i > 0 { 3622 b.WriteString(", ") 3623 } 3624 writeField(&b, f) 3625 } 3626 } 3627 b.WriteByte(')') 3628 if ft.Results != nil { 3629 nr := 0 3630 for _, f := range ft.Results.List { 3631 if n := len(f.Names); n > 1 { 3632 nr += n 3633 } else { 3634 nr++ 3635 } 3636 } 3637 if nr > 0 { 3638 b.WriteByte(' ') 3639 if nr > 1 { 3640 b.WriteByte('(') 3641 } 3642 for i, f := range ft.Results.List { 3643 if i > 0 { 3644 b.WriteString(", ") 3645 } 3646 writeField(&b, f) 3647 } 3648 if nr > 1 { 3649 b.WriteByte(')') 3650 } 3651 } 3652 } 3653 return b.String() 3654} 3655 3656// namelessType returns a type node that lacks any variable names. 3657func (w *Walker) namelessType(t interface{}) interface{} { 3658 ft, ok := t.(*ast.FuncType) 3659 if !ok { 3660 return t 3661 } 3662 return &ast.FuncType{ 3663 Params: w.namelessFieldList(ft.Params), 3664 Results: w.namelessFieldList(ft.Results), 3665 } 3666} 3667 3668// namelessFieldList returns a deep clone of fl, with the cloned fields 3669// lacking names. 3670func (w *Walker) namelessFieldList(fl *ast.FieldList) *ast.FieldList { 3671 fl2 := &ast.FieldList{} 3672 if fl != nil { 3673 for _, f := range fl.List { 3674 n := len(f.Names) 3675 if n >= 1 { 3676 for i := 0; i < n; i++ { 3677 fl2.List = append(fl2.List, w.namelessField(f)) 3678 } 3679 } else { 3680 fl2.List = append(fl2.List, w.namelessField(f)) 3681 } 3682 } 3683 } 3684 return fl2 3685} 3686 3687// namelessField clones f, but not preserving the names of fields. 3688// (comments and tags are also ignored) 3689func (w *Walker) namelessField(f *ast.Field) *ast.Field { 3690 return &ast.Field{ 3691 Type: f.Type, 3692 } 3693} 3694 3695func (w *Walker) emitFeature(feature string, pos token.Pos) { 3696 if !w.wantedPkg[w.curPackage.name] { 3697 return 3698 } 3699 more := strings.Index(feature, "\n") 3700 if more != -1 { 3701 if len(feature) <= 1024 { 3702 feature = strings.Replace(feature, "\n", " ", 1) 3703 feature = strings.Replace(feature, "\n", ";", -1) 3704 feature = strings.Replace(feature, "\t", " ", -1) 3705 } else { 3706 feature = feature[:more] + " ...more" 3707 if apiVerbose { 3708 log.Printf("feature contains newlines: %v, %s", feature, w.fset.Position(pos)) 3709 } 3710 } 3711 } 3712 f := strings.Join(w.scope, w.sep) + w.sep + feature 3713 3714 if _, dup := w.curPackage.features[f]; dup { 3715 return 3716 } 3717 w.curPackage.features[f] = pos 3718} 3719 3720func strListContains(l []string, s string) bool { 3721 for _, v := range l { 3722 if v == s { 3723 return true 3724 } 3725 } 3726 return false 3727} 3728 3729const goosList = "darwin freebsd linux netbsd openbsd plan9 windows " 3730const goarchList = "386 amd64 arm " 3731 3732// goodOSArchFile returns false if the name contains a $GOOS or $GOARCH 3733// suffix which does not match the current system. 3734// The recognized name formats are: 3735// 3736// name_$(GOOS).* 3737// name_$(GOARCH).* 3738// name_$(GOOS)_$(GOARCH).* 3739// name_$(GOOS)_test.* 3740// name_$(GOARCH)_test.* 3741// name_$(GOOS)_$(GOARCH)_test.* 3742// 3743func isOSArchFile(ctxt *build.Context, name string) bool { 3744 if dot := strings.Index(name, "."); dot != -1 { 3745 name = name[:dot] 3746 } 3747 l := strings.Split(name, "_") 3748 if n := len(l); n > 0 && l[n-1] == "test" { 3749 l = l[:n-1] 3750 } 3751 n := len(l) 3752 if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] { 3753 return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH 3754 } 3755 if n >= 1 && knownOS[l[n-1]] { 3756 return l[n-1] == ctxt.GOOS 3757 } 3758 if n >= 1 && knownArch[l[n-1]] { 3759 return l[n-1] == ctxt.GOARCH 3760 } 3761 return false 3762} 3763 3764var knownOS = make(map[string]bool) 3765var knownArch = make(map[string]bool) 3766 3767func init() { 3768 for _, v := range strings.Fields(goosList) { 3769 knownOS[v] = true 3770 } 3771 for _, v := range strings.Fields(goarchList) { 3772 knownArch[v] = true 3773 } 3774} 3775