Skip to content

Commit

Permalink
FEATURE: use source-based types.Importer
Browse files Browse the repository at this point in the history
This importer reads type information directly from up-to-date source.
See golang/go#11415.
  • Loading branch information
taylorchu committed Jun 25, 2016
1 parent 4d816de commit 93e1465
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 21 deletions.
8 changes: 5 additions & 3 deletions cmd/generic/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package main

import (
"fmt"
"go/build"
"log"
"os"
"os/exec"
Expand Down Expand Up @@ -29,8 +29,10 @@ func main() {
log.Fatalln(err)
}

if _, err := os.Stat(fmt.Sprintf("%s/src/%s", os.Getenv("GOPATH"), os.Args[1])); err != nil {
err := exec.Command("go", "get", "-u", os.Args[1]).Run()
if _, err := build.Import(os.Args[1], ".", build.FindOnly); err != nil {
cmd := exec.Command("go", "get", "-u", os.Args[1])
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
log.Fatalln(err)
}
Expand Down
59 changes: 59 additions & 0 deletions importer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package generic

import (
"go/ast"
"go/parser"
"go/token"
"go/types"
)

type im struct {
cache map[string]*types.Package
}

// NewImporter creates a new types.Importer.
//
// See https://github.com/golang/go/issues/11415.
// Many applications use the gcimporter package to read type information from compiled object files.
// There's no guarantee that those files are even remotely recent.
func NewImporter() types.Importer {
return &im{
cache: make(map[string]*types.Package),
}
}

func (i *im) Import(pkgPath string) (*types.Package, error) {
if pkgPath == "unsafe" {
return types.Unsafe, nil
}

if pkg, ok := i.cache[pkgPath]; ok {
return pkg, nil
}

fset := token.NewFileSet()
var files []*ast.File
err := walkSource(pkgPath, func(path string) error {
f, err := parser.ParseFile(fset, path, nil, 0)
if err != nil {
return err
}
files = append(files, f)
return nil
})
if err != nil {
return nil, err
}

conf := types.Config{
Importer: i,
}

pkg, err := conf.Check(pkgPath, fset, files, nil)
if err != nil {
return nil, err
}

i.cache[pkgPath] = pkg
return pkg, nil
}
26 changes: 9 additions & 17 deletions rewrite.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import (
"errors"
"fmt"
"go/ast"
"go/build"
"go/format"
"go/importer"
"go/parser"
"go/printer"
"go/token"
"go/types"
"io/ioutil"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -186,22 +185,15 @@ func rewriteTopLevelIdent(nodes map[string]*ast.File, prefix string, typeMap map

// walkSource visits all .go files in a package path except tests.
func walkSource(pkgPath string, sourceFunc func(string) error) error {
fi, err := ioutil.ReadDir(pkgPath)
pkg, err := build.Import(pkgPath, ".", 0)
if err != nil {
if _, ok := err.(*build.NoGoError); ok {
return nil
}
return err
}
for _, info := range fi {
if info.IsDir() {
continue
}
path := fmt.Sprintf("%s/%s", pkgPath, info.Name())
if !strings.HasSuffix(path, ".go") {
continue
}
if strings.HasSuffix(path, "_test.go") {
continue
}
err = sourceFunc(path)
for _, file := range pkg.GoFiles {
err = sourceFunc(fmt.Sprintf("%s/%s", pkg.Dir, file))
if err != nil {
return err
}
Expand Down Expand Up @@ -247,7 +239,7 @@ func RewritePackage(pkgPath string, newPkgPath string, typeMap map[string]Target

fset := token.NewFileSet()
files := make(map[string]*ast.File)
err = walkSource(fmt.Sprintf("%s/src/%s", os.Getenv("GOPATH"), pkgPath), func(path string) error {
err = walkSource(pkgPath, func(path string) error {
f, err := parser.ParseFile(fset, path, nil, 0)
if err != nil {
return err
Expand Down Expand Up @@ -315,7 +307,7 @@ func RewritePackage(pkgPath string, newPkgPath string, typeMap map[string]Target
return err
}
}
conf := types.Config{Importer: importer.Default()}
conf := types.Config{Importer: NewImporter()}
_, err = conf.Check("", fset, tc, nil)
if err != nil {
for _, f := range tc {
Expand Down
2 changes: 1 addition & 1 deletion type_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Target struct {
Import string
}

// ParseTypeMap parses type replacements.
// ParseTypeMap parses raw strings to type replacements.
func ParseTypeMap(args []string) (map[string]Target, error) {
typeMap := make(map[string]Target)

Expand Down

0 comments on commit 93e1465

Please sign in to comment.