// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build ignore // The gcimporter command reads the compiler's export data for the // named packages and prints the decoded type information. // // It is provided for debugging export data problems. package main import ( "bytes" "flag" "fmt" "go/token" "go/types" "log" "os" "sort" "golang.org/x/tools/go/gcexportdata" "golang.org/x/tools/go/packages" "golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/internal/gcimporter" ) func main() { flag.Parse() cfg := &packages.Config{ Fset: token.NewFileSet(), // Don't request NeedTypes: we want to be certain that // we loaded the types ourselves, from export data. Mode: packages.NeedName | packages.NeedExportFile, } pkgs, err := packages.Load(cfg, flag.Args()...) if err != nil { log.Fatal(err) } if packages.PrintErrors(pkgs) > 0 { os.Exit(1) } for _, pkg := range pkgs { // Read types from compiler's unified export data file. // This Package may included non-exported functions if they // are called by inlinable exported functions. var tpkg1 *types.Package { export, err := os.ReadFile(pkg.ExportFile) if err != nil { log.Fatalf("can't read %q export data: %v", pkg.PkgPath, err) } r, err := gcexportdata.NewReader(bytes.NewReader(export)) if err != nil { log.Fatalf("reading export data %s: %v", pkg.ExportFile, err) } tpkg1, err = gcexportdata.Read(r, cfg.Fset, make(map[string]*types.Package), pkg.PkgPath) if err != nil { log.Fatalf("decoding export data: %v", err) } } fmt.Println("# Read from compiler's unified export data:") printPackage(tpkg1) // Now reexport as indexed (deep) export data, and reimport. // The Package will contain only exported symbols. var tpkg2 *types.Package { var out bytes.Buffer if err := gcimporter.IExportData(&out, cfg.Fset, tpkg1); err != nil { log.Fatal(err) } var err error _, tpkg2, err = gcimporter.IImportData(cfg.Fset, make(map[string]*types.Package), out.Bytes(), tpkg1.Path()) if err != nil { log.Fatal(err) } } fmt.Println("# After round-tripping through indexed export data:") printPackage(tpkg2) } } func printPackage(pkg *types.Package) { fmt.Printf("package %s %q\n", pkg.Name(), pkg.Path()) if !pkg.Complete() { fmt.Printf("\thas incomplete exported type info\n") } // imports var lines []string for _, imp := range pkg.Imports() { lines = append(lines, fmt.Sprintf("\timport %q", imp.Path())) } sort.Strings(lines) for _, line := range lines { fmt.Println(line) } // types of package members qual := types.RelativeTo(pkg) scope := pkg.Scope() for _, name := range scope.Names() { obj := scope.Lookup(name) fmt.Printf("\t%s\n", types.ObjectString(obj, qual)) if _, ok := obj.(*types.TypeName); ok { for _, meth := range typeutil.IntuitiveMethodSet(obj.Type(), nil) { fmt.Printf("\t%s\n", types.SelectionString(meth, qual)) } } } fmt.Println() }