зеркало из https://github.com/golang/tools.git
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 <rfindley@google.com> Auto-Submit: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Родитель
4fe2c29e13
Коммит
814f676cf4
|
@ -0,0 +1,117 @@
|
|||
// 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()
|
||||
}
|
Загрузка…
Ссылка в новой задаче