Skip to content

Commit 814f676

Browse files
committed
internal/gcimporter: add tool to inspect export data
This CL adds an unexported command for inspecting "unified" export data produced by the compiler, and checking that it can be roundtripped through "indexed" format as used by gopls. Change-Id: Idc8eea5c8d7287d7f10af7bd15c7a52e6987a4bf Reviewed-on: https://go-review.googlesource.com/c/tools/+/572795 Reviewed-by: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 4fe2c29 commit 814f676

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

internal/gcimporter/main.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
}

0 commit comments

Comments
 (0)