127 lines
3.3 KiB
Go
127 lines
3.3 KiB
Go
// Copyright 2016 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.
|
|
|
|
// +build go1.7
|
|
// +build gc
|
|
|
|
package gcexportdata_test
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"go/types"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"golang.org/x/tools/go/gcexportdata"
|
|
)
|
|
|
|
// ExampleRead uses gcexportdata.Read to load type information for the
|
|
// "fmt" package from the fmt.a file produced by the gc compiler.
|
|
func ExampleRead() {
|
|
// Find the export data file.
|
|
filename, path := gcexportdata.Find("fmt", "")
|
|
if filename == "" {
|
|
log.Fatalf("can't find export data for fmt")
|
|
}
|
|
fmt.Printf("Package path: %s\n", path)
|
|
fmt.Printf("Export data: %s\n", filepath.Base(filename))
|
|
|
|
// Open and read the file.
|
|
f, err := os.Open(filename)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
r, err := gcexportdata.NewReader(f)
|
|
if err != nil {
|
|
log.Fatalf("reading export data %s: %v", filename, err)
|
|
}
|
|
|
|
// Decode the export data.
|
|
fset := token.NewFileSet()
|
|
imports := make(map[string]*types.Package)
|
|
pkg, err := gcexportdata.Read(r, fset, imports, path)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Print package information.
|
|
members := pkg.Scope().Names()
|
|
if members[0] == ".inittask" {
|
|
// An improvement to init handling in 1.13 added ".inittask". Remove so go >= 1.13 and go < 1.13 both pass.
|
|
members = members[1:]
|
|
}
|
|
fmt.Printf("Package members: %s...\n", members[:5])
|
|
println := pkg.Scope().Lookup("Println")
|
|
posn := fset.Position(println.Pos())
|
|
posn.Line = 123 // make example deterministic
|
|
fmt.Printf("Println type: %s\n", println.Type())
|
|
fmt.Printf("Println location: %s\n", slashify(posn))
|
|
|
|
// Output:
|
|
//
|
|
// Package path: fmt
|
|
// Export data: fmt.a
|
|
// Package members: [Errorf Formatter Fprint Fprintf Fprintln]...
|
|
// Println type: func(a ...interface{}) (n int, err error)
|
|
// Println location: $GOROOT/src/fmt/print.go:123:1
|
|
}
|
|
|
|
// ExampleNewImporter demonstrates usage of NewImporter to provide type
|
|
// information for dependencies when type-checking Go source code.
|
|
func ExampleNewImporter() {
|
|
const src = `package myrpc
|
|
|
|
// choosing a package that doesn't change across releases
|
|
import "net/rpc"
|
|
|
|
const serverError rpc.ServerError = ""
|
|
`
|
|
fset := token.NewFileSet()
|
|
f, err := parser.ParseFile(fset, "myrpc.go", src, 0)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
packages := make(map[string]*types.Package)
|
|
imp := gcexportdata.NewImporter(fset, packages)
|
|
conf := types.Config{Importer: imp}
|
|
pkg, err := conf.Check("myrpc", fset, []*ast.File{f}, nil)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// object from imported package
|
|
pi := packages["net/rpc"].Scope().Lookup("ServerError")
|
|
fmt.Printf("type %s.%s %s // %s\n",
|
|
pi.Pkg().Path(),
|
|
pi.Name(),
|
|
pi.Type().Underlying(),
|
|
slashify(fset.Position(pi.Pos())),
|
|
)
|
|
|
|
// object in source package
|
|
twopi := pkg.Scope().Lookup("serverError")
|
|
fmt.Printf("const %s %s = %s // %s\n",
|
|
twopi.Name(),
|
|
twopi.Type(),
|
|
twopi.(*types.Const).Val(),
|
|
slashify(fset.Position(twopi.Pos())),
|
|
)
|
|
|
|
// Output:
|
|
//
|
|
// type net/rpc.ServerError string // $GOROOT/src/net/rpc/client.go:20:1
|
|
// const serverError net/rpc.ServerError = "" // myrpc.go:6:7
|
|
}
|
|
|
|
func slashify(posn token.Position) token.Position {
|
|
posn.Filename = filepath.ToSlash(posn.Filename) // for MS Windows portability
|
|
return posn
|
|
}
|