woodpecker/vendor/github.com/quasilyte/go-ruleguard/ruleguard/importer.go
2021-11-16 21:07:53 +01:00

95 lines
2.4 KiB
Go

package ruleguard
import (
"fmt"
"go/build"
"go/importer"
"go/token"
"go/types"
"runtime"
"github.com/quasilyte/go-ruleguard/internal/xsrcimporter"
)
// goImporter is a `types.Importer` that tries to load a package no matter what.
// It iterates through multiple import strategies and accepts whatever succeeds first.
type goImporter struct {
// TODO(quasilyte): share importers with gogrep?
state *engineState
defaultImporter types.Importer
srcImporter types.Importer
fset *token.FileSet
buildContext *build.Context
debugImports bool
debugPrint func(string)
}
type goImporterConfig struct {
fset *token.FileSet
debugImports bool
debugPrint func(string)
buildContext *build.Context
}
func newGoImporter(state *engineState, config goImporterConfig) *goImporter {
imp := &goImporter{
state: state,
fset: config.fset,
debugImports: config.debugImports,
debugPrint: config.debugPrint,
defaultImporter: importer.Default(),
buildContext: config.buildContext,
}
imp.initSourceImporter()
return imp
}
func (imp *goImporter) Import(path string) (*types.Package, error) {
if pkg := imp.state.GetCachedPackage(path); pkg != nil {
if imp.debugImports {
imp.debugPrint(fmt.Sprintf(`imported "%s" from importer cache`, path))
}
return pkg, nil
}
pkg, srcErr := imp.srcImporter.Import(path)
if srcErr == nil {
imp.state.AddCachedPackage(path, pkg)
if imp.debugImports {
imp.debugPrint(fmt.Sprintf(`imported "%s" from source importer`, path))
}
return pkg, nil
}
pkg, defaultErr := imp.defaultImporter.Import(path)
if defaultErr == nil {
imp.state.AddCachedPackage(path, pkg)
if imp.debugImports {
imp.debugPrint(fmt.Sprintf(`imported "%s" from %s importer`, path, runtime.Compiler))
}
return pkg, nil
}
if imp.debugImports {
imp.debugPrint(fmt.Sprintf(`failed to import "%s":`, path))
imp.debugPrint(fmt.Sprintf(" %s importer: %v", runtime.Compiler, defaultErr))
imp.debugPrint(fmt.Sprintf(" source importer: %v", srcErr))
imp.debugPrint(fmt.Sprintf(" GOROOT=%q GOPATH=%q", imp.buildContext.GOROOT, imp.buildContext.GOPATH))
}
return nil, defaultErr
}
func (imp *goImporter) initSourceImporter() {
if imp.buildContext == nil {
if imp.debugImports {
imp.debugPrint("using build.Default context")
}
imp.buildContext = &build.Default
}
imp.srcImporter = xsrcimporter.New(imp.buildContext, imp.fset)
}