golang.org/x/tools@v0.21.0/internal/gcimporter/main.go (about) 1 // Copyright 2024 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 //go:build ignore 6 7 // The gcimporter command reads the compiler's export data for the 8 // named packages and prints the decoded type information. 9 // 10 // It is provided for debugging export data problems. 11 package main 12 13 import ( 14 "bytes" 15 "flag" 16 "fmt" 17 "go/token" 18 "go/types" 19 "log" 20 "os" 21 "sort" 22 23 "golang.org/x/tools/go/gcexportdata" 24 "golang.org/x/tools/go/packages" 25 "golang.org/x/tools/go/types/typeutil" 26 "golang.org/x/tools/internal/gcimporter" 27 ) 28 29 func main() { 30 flag.Parse() 31 cfg := &packages.Config{ 32 Fset: token.NewFileSet(), 33 // Don't request NeedTypes: we want to be certain that 34 // we loaded the types ourselves, from export data. 35 Mode: packages.NeedName | packages.NeedExportFile, 36 } 37 pkgs, err := packages.Load(cfg, flag.Args()...) 38 if err != nil { 39 log.Fatal(err) 40 } 41 if packages.PrintErrors(pkgs) > 0 { 42 os.Exit(1) 43 } 44 45 for _, pkg := range pkgs { 46 // Read types from compiler's unified export data file. 47 // This Package may included non-exported functions if they 48 // are called by inlinable exported functions. 49 var tpkg1 *types.Package 50 { 51 export, err := os.ReadFile(pkg.ExportFile) 52 if err != nil { 53 log.Fatalf("can't read %q export data: %v", pkg.PkgPath, err) 54 } 55 r, err := gcexportdata.NewReader(bytes.NewReader(export)) 56 if err != nil { 57 log.Fatalf("reading export data %s: %v", pkg.ExportFile, err) 58 } 59 tpkg1, err = gcexportdata.Read(r, cfg.Fset, make(map[string]*types.Package), pkg.PkgPath) 60 if err != nil { 61 log.Fatalf("decoding export data: %v", err) 62 } 63 } 64 fmt.Println("# Read from compiler's unified export data:") 65 printPackage(tpkg1) 66 67 // Now reexport as indexed (deep) export data, and reimport. 68 // The Package will contain only exported symbols. 69 var tpkg2 *types.Package 70 { 71 var out bytes.Buffer 72 if err := gcimporter.IExportData(&out, cfg.Fset, tpkg1); err != nil { 73 log.Fatal(err) 74 } 75 var err error 76 _, tpkg2, err = gcimporter.IImportData(cfg.Fset, make(map[string]*types.Package), out.Bytes(), tpkg1.Path()) 77 if err != nil { 78 log.Fatal(err) 79 } 80 } 81 fmt.Println("# After round-tripping through indexed export data:") 82 printPackage(tpkg2) 83 } 84 } 85 86 func printPackage(pkg *types.Package) { 87 fmt.Printf("package %s %q\n", pkg.Name(), pkg.Path()) 88 89 if !pkg.Complete() { 90 fmt.Printf("\thas incomplete exported type info\n") 91 } 92 93 // imports 94 var lines []string 95 for _, imp := range pkg.Imports() { 96 lines = append(lines, fmt.Sprintf("\timport %q", imp.Path())) 97 } 98 sort.Strings(lines) 99 for _, line := range lines { 100 fmt.Println(line) 101 } 102 103 // types of package members 104 qual := types.RelativeTo(pkg) 105 scope := pkg.Scope() 106 for _, name := range scope.Names() { 107 obj := scope.Lookup(name) 108 fmt.Printf("\t%s\n", types.ObjectString(obj, qual)) 109 if _, ok := obj.(*types.TypeName); ok { 110 for _, meth := range typeutil.IntuitiveMethodSet(obj.Type(), nil) { 111 fmt.Printf("\t%s\n", types.SelectionString(meth, qual)) 112 } 113 } 114 } 115 116 fmt.Println() 117 }