return cfg, nil
}
+var importerForCompiler = func(_ *token.FileSet, compiler string, lookup importer.Lookup) types.Importer {
+ // broken legacy implementation (github.com/golang/go/issues/28995)
+ return importer.For(compiler, lookup)
+}
+
func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]result, error) {
// Load, parse, typecheck.
var files []*ast.File
}
files = append(files, f)
}
- compilerImporter := importer.For(cfg.Compiler, func(path string) (io.ReadCloser, error) {
+ compilerImporter := importerForCompiler(fset, cfg.Compiler, func(path string) (io.ReadCloser, error) {
// path is a resolved package path, not an import path.
file, ok := cfg.PackageFile[path]
if !ok {
--- /dev/null
+// +build go1.12
+
+package unitchecker
+
+import "go/importer"
+
+func init() {
+ importerForCompiler = importer.ForCompiler
+}
// a given import path, or an error if no matching package is found.
type Lookup func(path string) (io.ReadCloser, error)
-// For returns an Importer for importing from installed packages
+// ForCompiler returns an Importer for importing from installed packages
// for the compilers "gc" and "gccgo", or for importing directly
// from the source if the compiler argument is "source". In this
// latter case, importing may fail under circumstances where the
// (not relative or absolute ones); it is assumed that the translation
// to canonical import paths is being done by the client of the
// importer.
-func For(compiler string, lookup Lookup) types.Importer {
+func ForCompiler(fset *token.FileSet, compiler string, lookup Lookup) types.Importer {
switch compiler {
case "gc":
return &gcimports{
+ fset: fset,
packages: make(map[string]*types.Package),
lookup: lookup,
}
panic("source importer for custom import path lookup not supported (issue #13847).")
}
- return srcimporter.New(&build.Default, token.NewFileSet(), make(map[string]*types.Package))
+ return srcimporter.New(&build.Default, fset, make(map[string]*types.Package))
}
// compiler not supported
return nil
}
+// For calls ForCompiler with a new FileSet.
+//
+// Deprecated: use ForCompiler, which populates a FileSet
+// with the positions of objects created by the importer.
+func For(compiler string, lookup Lookup) types.Importer {
+ return ForCompiler(token.NewFileSet(), compiler, lookup)
+}
+
// Default returns an Importer for the compiler that built the running binary.
// If available, the result implements types.ImporterFrom.
func Default() types.Importer {
// gc importer
type gcimports struct {
+ fset *token.FileSet
packages map[string]*types.Package
lookup Lookup
}
if mode != 0 {
panic("mode must be 0")
}
- return gcimporter.Import(m.packages, path, srcDir, m.lookup)
+ return gcimporter.Import(m.fset, m.packages, path, srcDir, m.lookup)
}
// gccgo importer
package importer
import (
+ "go/token"
"internal/testenv"
"io"
+ "io/ioutil"
"os"
"os/exec"
+ "runtime"
"strings"
"testing"
)
-func TestFor(t *testing.T) {
+func TestForCompiler(t *testing.T) {
testenv.MustHaveGoBuild(t)
const thePackage = "math/big"
t.Skip("golang.org/issue/22500")
}
+ fset := token.NewFileSet()
+
t.Run("LookupDefault", func(t *testing.T) {
- imp := For(compiler, nil)
+ imp := ForCompiler(fset, compiler, nil)
pkg, err := imp.Import(thePackage)
if err != nil {
t.Fatal(err)
if pkg.Path() != thePackage {
t.Fatalf("Path() = %q, want %q", pkg.Path(), thePackage)
}
+
+ // Check that the fileset positions are accurate.
+ // https://github.com/golang/go#28995
+ mathBigInt := pkg.Scope().Lookup("Int")
+ posn := fset.Position(mathBigInt.Pos()) // "$GOROOT/src/math/big/int.go:25:1"
+ filename := strings.Replace(posn.Filename, "$GOROOT", runtime.GOROOT(), 1)
+ data, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Fatalf("can't read file containing declaration of math/big.Int: %v", err)
+ }
+ lines := strings.Split(string(data), "\n")
+ if posn.Line > len(lines) || !strings.HasPrefix(lines[posn.Line-1], "type Int") {
+ t.Fatalf("Object %v position %s does not contain its declaration",
+ mathBigInt, posn)
+ }
})
t.Run("LookupCustom", func(t *testing.T) {
}
return f, nil
}
- imp := For(compiler, lookup)
+ imp := ForCompiler(fset, compiler, lookup)
pkg, err := imp.Import("math/bigger")
if err != nil {
t.Fatal(err)
// the corresponding package object to the packages map, and returns the object.
// The packages map must contain all packages already imported.
//
-func Import(packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) {
+func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) {
var rc io.ReadCloser
var id string
if lookup != nil {
break
}
- // TODO(gri): allow clients of go/importer to provide a FileSet.
- // Or, define a new standard go/types/gcexportdata package.
- fset := token.NewFileSet()
-
// The indexed export format starts with an 'i'; the older
// binary export format starts with a 'c', 'd', or 'v'
// (from "version"). Select appropriate importer.
"testing"
"time"
+ "go/token"
"go/types"
)
func testPath(t *testing.T, path, srcDir string) *types.Package {
t0 := time.Now()
- pkg, err := Import(make(map[string]*types.Package), path, srcDir, nil)
+ fset := token.NewFileSet()
+ pkg, err := Import(fset, make(map[string]*types.Package), path, srcDir, nil)
if err != nil {
t.Errorf("testPath(%s): %s", path, err)
return nil
t.Fatal(err)
}
+ fset := token.NewFileSet()
+
for _, f := range list {
name := f.Name()
if !strings.HasSuffix(name, ".a") {
}
// test that export data can be imported
- _, err := Import(make(map[string]*types.Package), pkgpath, dir, nil)
+ _, err := Import(fset, make(map[string]*types.Package), pkgpath, dir, nil)
if err != nil {
// ok to fail if it fails with a newer version error for select files
if strings.Contains(err.Error(), "newer version") {
ioutil.WriteFile(filename, data, 0666)
// test that importing the corrupted file results in an error
- _, err = Import(make(map[string]*types.Package), pkgpath, corruptdir, nil)
+ _, err = Import(fset, make(map[string]*types.Package), pkgpath, corruptdir, nil)
if err == nil {
t.Errorf("import corrupted %q succeeded", pkgpath)
} else if msg := err.Error(); !strings.Contains(msg, "version skew") {
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
}
+ fset := token.NewFileSet()
for _, test := range importedObjectTests {
s := strings.Split(test.name, ".")
if len(s) != 2 {
importPath := s[0]
objName := s[1]
- pkg, err := Import(make(map[string]*types.Package), importPath, ".", nil)
+ pkg, err := Import(fset, make(map[string]*types.Package), importPath, ".", nil)
if err != nil {
t.Error(err)
continue
}
imports := make(map[string]*types.Package)
- _, err := Import(imports, "net/http", ".", nil)
+ fset := token.NewFileSet()
+ _, err := Import(fset, imports, "net/http", ".", nil)
if err != nil {
t.Fatal(err)
}
}
// import go/internal/gcimporter which imports go/types partially
+ fset := token.NewFileSet()
imports := make(map[string]*types.Package)
- _, err := Import(imports, "go/internal/gcimporter", ".", nil)
+ _, err := Import(fset, imports, "go/internal/gcimporter", ".", nil)
if err != nil {
t.Fatal(err)
}
// file and package path are different, exposing the problem if present.
// The same issue occurs with vendoring.)
imports := make(map[string]*types.Package)
+ fset := token.NewFileSet()
for i := 0; i < 3; i++ {
- if _, err := Import(imports, "./././testdata/p", tmpdir, nil); err != nil {
+ if _, err := Import(fset, imports, "./././testdata/p", tmpdir, nil); err != nil {
t.Fatal(err)
}
}
}
func importPkg(t *testing.T, path, srcDir string) *types.Package {
- pkg, err := Import(make(map[string]*types.Package), path, srcDir, nil)
+ fset := token.NewFileSet()
+ pkg, err := Import(fset, make(map[string]*types.Package), path, srcDir, nil)
if err != nil {
t.Fatal(err)
}