gcexportdata

package
v0.5.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 5, 2020 License: BSD-3-Clause Imports: 9 Imported by: 0

Documentation

Overview

Package gcexportdata provides functions for locating, reading, and writing export data files containing type information produced by the gc compiler. This package supports go1.7 export data format and all later versions.

Although it might seem convenient for this package to live alongside go/types in the standard library, this would cause version skew problems for developer tools that use it, since they must be able to consume the outputs of the gc compiler both before and after a Go update such as from Go 1.7 to Go 1.8. Because this package lives in github.com/jd-ly/tools, sites can update their version of this repo some time before the Go 1.8 release and rebuild and redeploy their developer tools, which will then be able to consume both Go 1.7 and Go 1.8 export data files, so they will work before and after the Go update. (See discussion at https://golang.org/issue/15651.)

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Find

func Find(importPath, srcDir string) (filename, path string)

Find returns the name of an object (.o) or archive (.a) file containing type information for the specified import path, using the workspace layout conventions of go/build. If no file was found, an empty filename is returned.

A relative srcDir is interpreted relative to the current working directory.

Find also returns the package's resolved (canonical) import path, reflecting the effects of srcDir and vendoring on importPath.

func NewImporter

func NewImporter(fset *token.FileSet, imports map[string]*types.Package) types.ImporterFrom

NewImporter returns a new instance of the types.Importer interface that reads type information from export data files written by gc. The Importer also satisfies types.ImporterFrom.

Export data files are located using "go build" workspace conventions and the build.Default context.

Use this importer instead of go/importer.For("gc", ...) to avoid the version-skew problems described in the documentation of this package, or to control the FileSet or access the imports map populated during package loading.

Example

ExampleNewImporter demonstrates usage of NewImporter to provide type information for dependencies when type-checking Go source code.

package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"go/types"
	"log"
	"path/filepath"

	"github.com/jd-ly/tools/go/gcexportdata"
)

func main() {
	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())),
	)

}

func slashify(posn token.Position) token.Position {
	posn.Filename = filepath.ToSlash(posn.Filename)
	return posn
}
Output:


type net/rpc.ServerError string // $GOROOT/src/net/rpc/client.go:20:1
const serverError net/rpc.ServerError = "" // myrpc.go:6:7

func NewReader

func NewReader(r io.Reader) (io.Reader, error)

NewReader returns a reader for the export data section of an object (.o) or archive (.a) file read from r. The new reader may provide additional trailing data beyond the end of the export data.

func Read

func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error)

Read reads export data from in, decodes it, and returns type information for the package. The package name is specified by path. File position information is added to fset.

Read may inspect and add to the imports map to ensure that references within the export data to other packages are consistent. The caller must ensure that imports[path] does not exist, or exists but is incomplete (see types.Package.Complete), and Read inserts the resulting package into this map entry.

On return, the state of the reader is undefined.

Example

ExampleRead uses gcexportdata.Read to load type information for the "fmt" package from the fmt.a file produced by the gc compiler.

package main

import (
	"fmt"
	"go/token"
	"go/types"
	"log"
	"os"
	"path/filepath"

	"github.com/jd-ly/tools/go/gcexportdata"
)

func main() {
	// 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))

}

func slashify(posn token.Position) token.Position {
	posn.Filename = filepath.ToSlash(posn.Filename)
	return 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

func Write

func Write(out io.Writer, fset *token.FileSet, pkg *types.Package) error

Write writes encoded type information for the specified package to out. The FileSet provides file position information for named objects.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL