1
0
Fork 0
forked from forgejo/forgejo

Update gitea-vet to v0.2.1 (#12282)

* change to new code location

* vendor

* tagged version v0.2.0

* gitea-vet v0.2.1

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
6543 2020-08-15 19:13:07 +02:00 committed by GitHub
parent eb60a5d054
commit ee97e6a66a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 3421 additions and 403 deletions

View file

@ -7,6 +7,8 @@ import (
"go/token"
"go/types"
"reflect"
"golang.org/x/tools/internal/analysisinternal"
)
// An Analyzer describes an analysis function and its options.
@ -69,6 +71,17 @@ type Analyzer struct {
func (a *Analyzer) String() string { return a.Name }
func init() {
// Set the analysisinternal functions to be able to pass type errors
// to the Pass type without modifying the go/analysis API.
analysisinternal.SetTypeErrors = func(p interface{}, errors []types.Error) {
p.(*Pass).typeErrors = errors
}
analysisinternal.GetTypeErrors = func(p interface{}) []types.Error {
return p.(*Pass).typeErrors
}
}
// A Pass provides information to the Run function that
// applies a specific analyzer to a single Go package.
//
@ -138,6 +151,9 @@ type Pass struct {
// WARNING: This is an experimental API and may change in the future.
AllObjectFacts func() []ObjectFact
// typeErrors contains types.Errors that are associated with the pkg.
typeErrors []types.Error
/* Further fields may be added in future. */
// For example, suggested or applied refactorings.
}

View file

@ -170,6 +170,15 @@ Diagnostic is defined as:
The optional Category field is a short identifier that classifies the
kind of message when an analysis produces several kinds of diagnostic.
Many analyses want to associate diagnostics with a severity level.
Because Diagnostic does not have a severity level field, an Analyzer's
diagnostics effectively all have the same severity level. To separate which
diagnostics are high severity and which are low severity, expose multiple
Analyzers instead. Analyzers should also be separated when their
diagnostics belong in different groups, or could be tagged differently
before being shown to the end user. Analyzers should document their severity
level to help downstream tools surface diagnostics properly.
Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
and buildtag, inspect the raw text of Go source files or even non-Go
files such as assembly. To report a diagnostic against a line of a

View file

@ -382,7 +382,7 @@ func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.
func (tree JSONTree) Print() {
data, err := json.MarshalIndent(tree, "", "\t")
if err != nil {
log.Panicf("internal error: JSON marshalling failed: %v", err)
log.Panicf("internal error: JSON marshaling failed: %v", err)
}
fmt.Printf("%s\n", data)
}

View file

@ -19,8 +19,7 @@ import (
var debug = false
// GetSizes returns the sizes used by the underlying driver with the given parameters.
func GetSizes(ctx context.Context, buildFlags, env []string, dir string, usesExportData bool) (types.Sizes, error) {
func GetSizes(ctx context.Context, buildFlags, env []string, gocmdRunner *gocommand.Runner, dir string) (types.Sizes, error) {
// TODO(matloob): Clean this up. This code is mostly a copy of packages.findExternalDriver.
const toolPrefix = "GOPACKAGESDRIVER="
tool := ""
@ -40,7 +39,7 @@ func GetSizes(ctx context.Context, buildFlags, env []string, dir string, usesExp
}
if tool == "off" {
return GetSizesGolist(ctx, buildFlags, env, dir, usesExportData)
return GetSizesGolist(ctx, buildFlags, env, gocmdRunner, dir)
}
req, err := json.Marshal(struct {
@ -76,7 +75,7 @@ func GetSizes(ctx context.Context, buildFlags, env []string, dir string, usesExp
return response.Sizes, nil
}
func GetSizesGolist(ctx context.Context, buildFlags, env []string, dir string, usesExportData bool) (types.Sizes, error) {
func GetSizesGolist(ctx context.Context, buildFlags, env []string, gocmdRunner *gocommand.Runner, dir string) (types.Sizes, error) {
inv := gocommand.Invocation{
Verb: "list",
Args: []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"},
@ -84,7 +83,7 @@ func GetSizesGolist(ctx context.Context, buildFlags, env []string, dir string, u
BuildFlags: buildFlags,
WorkingDir: dir,
}
stdout, stderr, friendlyErr, rawErr := inv.RunRaw(ctx)
stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv)
var goarch, compiler string
if rawErr != nil {
if strings.Contains(rawErr.Error(), "cannot find main module") {
@ -96,7 +95,7 @@ func GetSizesGolist(ctx context.Context, buildFlags, env []string, dir string, u
Env: env,
WorkingDir: dir,
}
envout, enverr := inv.Run(ctx)
envout, enverr := gocmdRunner.Run(ctx, inv)
if enverr != nil {
return nil, enverr
}

View file

@ -24,7 +24,7 @@ import (
"golang.org/x/tools/go/internal/packagesdriver"
"golang.org/x/tools/internal/gocommand"
"golang.org/x/tools/internal/packagesinternal"
"golang.org/x/xerrors"
)
// debug controls verbose logging.
@ -89,6 +89,10 @@ type golistState struct {
rootDirsError error
rootDirs map[string]string
goVersionOnce sync.Once
goVersionError error
goVersion string // third field of 'go version'
// vendorDirs caches the (non)existence of vendor directories.
vendorDirs map[string]bool
}
@ -142,7 +146,7 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
sizeswg.Add(1)
go func() {
var sizes types.Sizes
sizes, sizeserr = packagesdriver.GetSizesGolist(ctx, cfg.BuildFlags, cfg.Env, cfg.Dir, usesExportData(cfg))
sizes, sizeserr = packagesdriver.GetSizesGolist(ctx, cfg.BuildFlags, cfg.Env, cfg.gocmdRunner, cfg.Dir)
// types.SizesFor always returns nil or a *types.StdSizes.
response.dr.Sizes, _ = sizes.(*types.StdSizes)
sizeswg.Done()
@ -381,7 +385,7 @@ type jsonPackage struct {
Imports []string
ImportMap map[string]string
Deps []string
Module *packagesinternal.Module
Module *Module
TestGoFiles []string
TestImports []string
XTestGoFiles []string
@ -502,10 +506,19 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
errkind = "use of internal package not allowed"
}
if errkind != "" {
if len(old.Error.ImportStack) < 2 {
return nil, fmt.Errorf(`internal error: go list gave a %q error with an import stack with fewer than two elements`, errkind)
if len(old.Error.ImportStack) < 1 {
return nil, fmt.Errorf(`internal error: go list gave a %q error with empty import stack`, errkind)
}
importingPkg := old.Error.ImportStack[len(old.Error.ImportStack)-1]
if importingPkg == old.ImportPath {
// Using an older version of Go which put this package itself on top of import
// stack, instead of the importer. Look for importer in second from top
// position.
if len(old.Error.ImportStack) < 2 {
return nil, fmt.Errorf(`internal error: go list gave a %q error with an import stack without importing package`, errkind)
}
importingPkg = old.Error.ImportStack[len(old.Error.ImportStack)-2]
}
importingPkg := old.Error.ImportStack[len(old.Error.ImportStack)-2]
additionalErrors[importingPkg] = append(additionalErrors[importingPkg], Error{
Pos: old.Error.Pos,
Msg: old.Error.Err,
@ -531,7 +544,26 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
CompiledGoFiles: absJoin(p.Dir, p.CompiledGoFiles),
OtherFiles: absJoin(p.Dir, otherFiles(p)...),
forTest: p.ForTest,
module: p.Module,
Module: p.Module,
}
if (state.cfg.Mode&typecheckCgo) != 0 && len(p.CgoFiles) != 0 {
if len(p.CompiledGoFiles) > len(p.GoFiles) {
// We need the cgo definitions, which are in the first
// CompiledGoFile after the non-cgo ones. This is a hack but there
// isn't currently a better way to find it. We also need the pure
// Go files and unprocessed cgo files, all of which are already
// in pkg.GoFiles.
cgoTypes := p.CompiledGoFiles[len(p.GoFiles)]
pkg.CompiledGoFiles = append([]string{cgoTypes}, pkg.GoFiles...)
} else {
// golang/go#38990: go list silently fails to do cgo processing
pkg.CompiledGoFiles = nil
pkg.Errors = append(pkg.Errors, Error{
Msg: "go list failed to return CompiledGoFiles; https://golang.org/issue/38990?",
Kind: ListError,
})
}
}
// Work around https://golang.org/issue/28749:
@ -607,6 +639,39 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
pkg.CompiledGoFiles = pkg.GoFiles
}
// Temporary work-around for golang/go#39986. Parse filenames out of
// error messages. This happens if there are unrecoverable syntax
// errors in the source, so we can't match on a specific error message.
if err := p.Error; err != nil && state.shouldAddFilenameFromError(p) {
addFilenameFromPos := func(pos string) bool {
split := strings.Split(pos, ":")
if len(split) < 1 {
return false
}
filename := strings.TrimSpace(split[0])
if filename == "" {
return false
}
if !filepath.IsAbs(filename) {
filename = filepath.Join(state.cfg.Dir, filename)
}
info, _ := os.Stat(filename)
if info == nil {
return false
}
pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, filename)
pkg.GoFiles = append(pkg.GoFiles, filename)
return true
}
found := addFilenameFromPos(err.Pos)
// In some cases, go list only reports the error position in the
// error text, not the error position. One such case is when the
// file's package name is a keyword (see golang.org/issue/39763).
if !found {
addFilenameFromPos(err.Err)
}
}
if p.Error != nil {
msg := strings.TrimSpace(p.Error.Err) // Trim to work around golang.org/issue/32363.
// Address golang.org/issue/35964 by appending import stack to error message.
@ -636,6 +701,58 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
return &response, nil
}
func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool {
if len(p.GoFiles) > 0 || len(p.CompiledGoFiles) > 0 {
return false
}
goV, err := state.getGoVersion()
if err != nil {
return false
}
// On Go 1.14 and earlier, only add filenames from errors if the import stack is empty.
// The import stack behaves differently for these versions than newer Go versions.
if strings.HasPrefix(goV, "go1.13") || strings.HasPrefix(goV, "go1.14") {
return len(p.Error.ImportStack) == 0
}
// On Go 1.15 and later, only parse filenames out of error if there's no import stack,
// or the current package is at the top of the import stack. This is not guaranteed
// to work perfectly, but should avoid some cases where files in errors don't belong to this
// package.
return len(p.Error.ImportStack) == 0 || p.Error.ImportStack[len(p.Error.ImportStack)-1] == p.ImportPath
}
func (state *golistState) getGoVersion() (string, error) {
state.goVersionOnce.Do(func() {
var b *bytes.Buffer
// Invoke go version. Don't use invokeGo because it will supply build flags, and
// go version doesn't expect build flags.
inv := gocommand.Invocation{
Verb: "version",
Env: state.cfg.Env,
Logf: state.cfg.Logf,
}
gocmdRunner := state.cfg.gocmdRunner
if gocmdRunner == nil {
gocmdRunner = &gocommand.Runner{}
}
b, _, _, state.goVersionError = gocmdRunner.RunRaw(state.cfg.Context, inv)
if state.goVersionError != nil {
return
}
sp := strings.Split(b.String(), " ")
if len(sp) < 3 {
state.goVersionError = fmt.Errorf("go version output: expected 'go version <version>', got '%s'", b.String())
return
}
state.goVersion = sp[2]
})
return state.goVersion, state.goVersionError
}
// getPkgPath finds the package path of a directory if it's relative to a root directory.
func (state *golistState) getPkgPath(dir string) (string, bool, error) {
absDir, err := filepath.Abs(dir)
@ -707,7 +824,7 @@ func golistargs(cfg *Config, words []string) []string {
func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, error) {
cfg := state.cfg
inv := &gocommand.Invocation{
inv := gocommand.Invocation{
Verb: verb,
Args: args,
BuildFlags: cfg.BuildFlags,
@ -715,8 +832,11 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer,
Logf: cfg.Logf,
WorkingDir: cfg.Dir,
}
stdout, stderr, _, err := inv.RunRaw(cfg.Context)
gocmdRunner := cfg.gocmdRunner
if gocmdRunner == nil {
gocmdRunner = &gocommand.Runner{}
}
stdout, stderr, _, err := gocmdRunner.RunRaw(cfg.Context, inv)
if err != nil {
// Check for 'go' executable not being found.
if ee, ok := err.(*exec.Error); ok && ee.Err == exec.ErrNotFound {
@ -727,7 +847,7 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer,
if !ok {
// Catastrophic error:
// - context cancellation
return nil, fmt.Errorf("couldn't run 'go': %v", err)
return nil, xerrors.Errorf("couldn't run 'go': %w", err)
}
// Old go version?

View file

@ -5,6 +5,7 @@ import (
"fmt"
"go/parser"
"go/token"
"log"
"os"
"path/filepath"
"sort"
@ -22,10 +23,15 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif
needPkgsSet := make(map[string]bool)
modifiedPkgsSet := make(map[string]bool)
pkgOfDir := make(map[string][]*Package)
for _, pkg := range response.dr.Packages {
// This is an approximation of import path to id. This can be
// wrong for tests, vendored packages, and a number of other cases.
havePkgs[pkg.PkgPath] = pkg.ID
x := commonDir(pkg.GoFiles)
if x != "" {
pkgOfDir[x] = append(pkgOfDir[x], pkg)
}
}
// If no new imports are added, it is safe to avoid loading any needPkgs.
@ -64,6 +70,9 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif
// to the overlay.
continue
}
// If all the overlay files belong to a different package, change the
// package name to that package.
maybeFixPackageName(pkgName, isTestFile, pkgOfDir[dir])
nextPackage:
for _, p := range response.dr.Packages {
if pkgName != p.Name && p.ID != "command-line-arguments" {
@ -93,8 +102,11 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif
}
}
}
// The overlay could have included an entirely new package.
if pkg == nil {
// The overlay could have included an entirely new package or an
// ad-hoc package. An ad-hoc package is one that we have manually
// constructed from inadequate `go list` results for a file= query.
// It will have the ID command-line-arguments.
if pkg == nil || pkg.ID == "command-line-arguments" {
// Try to find the module or gopath dir the file is contained in.
// Then for modules, add the module opath to the beginning.
pkgPath, ok, err := state.getPkgPath(dir)
@ -104,34 +116,53 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif
if !ok {
break
}
var forTest string // only set for x tests
isXTest := strings.HasSuffix(pkgName, "_test")
if isXTest {
forTest = pkgPath
pkgPath += "_test"
}
id := pkgPath
if isTestFile && !isXTest {
id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath)
}
// Try to reclaim a package with the same id if it exists in the response.
for _, p := range response.dr.Packages {
if reclaimPackage(p, id, opath, contents) {
pkg = p
break
if isTestFile {
if isXTest {
id = fmt.Sprintf("%s [%s.test]", pkgPath, forTest)
} else {
id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath)
}
}
// Otherwise, create a new package
if pkg == nil {
pkg = &Package{PkgPath: pkgPath, ID: id, Name: pkgName, Imports: make(map[string]*Package)}
response.addPackage(pkg)
havePkgs[pkg.PkgPath] = id
// Add the production package's sources for a test variant.
if isTestFile && !isXTest && testVariantOf != nil {
pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...)
pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...)
// Add the package under test and its imports to the test variant.
pkg.forTest = testVariantOf.PkgPath
for k, v := range testVariantOf.Imports {
pkg.Imports[k] = &Package{ID: v.ID}
if pkg != nil {
// TODO(rstambler): We should change the package's path and ID
// here. The only issue is that this messes with the roots.
} else {
// Try to reclaim a package with the same ID, if it exists in the response.
for _, p := range response.dr.Packages {
if reclaimPackage(p, id, opath, contents) {
pkg = p
break
}
}
// Otherwise, create a new package.
if pkg == nil {
pkg = &Package{
PkgPath: pkgPath,
ID: id,
Name: pkgName,
Imports: make(map[string]*Package),
}
response.addPackage(pkg)
havePkgs[pkg.PkgPath] = id
// Add the production package's sources for a test variant.
if isTestFile && !isXTest && testVariantOf != nil {
pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...)
pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...)
// Add the package under test and its imports to the test variant.
pkg.forTest = testVariantOf.PkgPath
for k, v := range testVariantOf.Imports {
pkg.Imports[k] = &Package{ID: v.ID}
}
}
if isXTest {
pkg.forTest = forTest
}
}
}
@ -149,6 +180,8 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif
continue
}
for _, imp := range imports {
// TODO(rstambler): If the package is an x test and the import has
// a test variant, make sure to replace it.
if _, found := pkg.Imports[imp]; found {
continue
}
@ -282,7 +315,17 @@ func (state *golistState) determineRootDirs() (map[string]string, error) {
}
func (state *golistState) determineRootDirsModules() (map[string]string, error) {
out, err := state.invokeGo("list", "-m", "-json", "all")
// This will only return the root directory for the main module.
// For now we only support overlays in main modules.
// Editing files in the module cache isn't a great idea, so we don't
// plan to ever support that, but editing files in replaced modules
// is something we may want to support. To do that, we'll want to
// do a go list -m to determine the replaced module's module path and
// directory, and then a go list -m {{with .Replace}}{{.Dir}}{{end}} <replaced module's path>
// from the main module to determine if that module is actually a replacement.
// See bcmills's comment here: https://github.com/golang/go/issues/37629#issuecomment-594179751
// for more information.
out, err := state.invokeGo("list", "-m", "-json")
if err != nil {
return nil, err
}
@ -374,3 +417,57 @@ func extractPackageName(filename string, contents []byte) (string, bool) {
}
return f.Name.Name, true
}
func commonDir(a []string) string {
seen := make(map[string]bool)
x := append([]string{}, a...)
for _, f := range x {
seen[filepath.Dir(f)] = true
}
if len(seen) > 1 {
log.Fatalf("commonDir saw %v for %v", seen, x)
}
for k := range seen {
// len(seen) == 1
return k
}
return "" // no files
}
// It is possible that the files in the disk directory dir have a different package
// name from newName, which is deduced from the overlays. If they all have a different
// package name, and they all have the same package name, then that name becomes
// the package name.
// It returns true if it changes the package name, false otherwise.
func maybeFixPackageName(newName string, isTestFile bool, pkgsOfDir []*Package) {
names := make(map[string]int)
for _, p := range pkgsOfDir {
names[p.Name]++
}
if len(names) != 1 {
// some files are in different packages
return
}
var oldName string
for k := range names {
oldName = k
}
if newName == oldName {
return
}
// We might have a case where all of the package names in the directory are
// the same, but the overlay file is for an x test, which belongs to its
// own package. If the x test does not yet exist on disk, we may not yet
// have its package name on disk, but we should not rename the packages.
//
// We use a heuristic to determine if this file belongs to an x test:
// The test file should have a package name whose package name has a _test
// suffix or looks like "newName_test".
maybeXTest := strings.HasPrefix(oldName+"_test", newName) || strings.HasSuffix(newName, "_test")
if isTestFile && maybeXTest {
return
}
for _, p := range pkgsOfDir {
p.Name = newName
}
}

View file

@ -38,7 +38,7 @@ var modeStrings = []string{
func (mod LoadMode) String() string {
m := mod
if m == 0 {
return fmt.Sprintf("LoadMode(0)")
return "LoadMode(0)"
}
var out []string
for i, x := range allModes {

View file

@ -21,9 +21,12 @@ import (
"path/filepath"
"strings"
"sync"
"time"
"golang.org/x/tools/go/gcexportdata"
"golang.org/x/tools/internal/gocommand"
"golang.org/x/tools/internal/packagesinternal"
"golang.org/x/tools/internal/typesinternal"
)
// A LoadMode controls the amount of detail to return when loading.
@ -69,6 +72,13 @@ const (
// NeedTypesSizes adds TypesSizes.
NeedTypesSizes
// typecheckCgo enables full support for type checking cgo. Requires Go 1.15+.
// Modifies CompiledGoFiles and Types, and has no effect on its own.
typecheckCgo
// NeedModule adds Module.
NeedModule
)
const (
@ -127,6 +137,9 @@ type Config struct {
//
Env []string
// gocmdRunner guards go command calls from concurrency errors.
gocmdRunner *gocommand.Runner
// BuildFlags is a list of command-line flags to be passed through to
// the build system's query tool.
BuildFlags []string
@ -178,6 +191,13 @@ type driver func(cfg *Config, patterns ...string) (*driverResponse, error)
// driverResponse contains the results for a driver query.
type driverResponse struct {
// NotHandled is returned if the request can't be handled by the current
// driver. If an external driver returns a response with NotHandled, the
// rest of the driverResponse is ignored, and go/packages will fallback
// to the next driver. If go/packages is extended in the future to support
// lists of multiple drivers, go/packages will fall back to the next driver.
NotHandled bool
// Sizes, if not nil, is the types.Sizes to use when type checking.
Sizes *types.StdSizes
@ -219,14 +239,22 @@ func Load(cfg *Config, patterns ...string) ([]*Package, error) {
return l.refine(response.Roots, response.Packages...)
}
// defaultDriver is a driver that looks for an external driver binary, and if
// it does not find it falls back to the built in go list driver.
// defaultDriver is a driver that implements go/packages' fallback behavior.
// It will try to request to an external driver, if one exists. If there's
// no external driver, or the driver returns a response with NotHandled set,
// defaultDriver will fall back to the go list driver.
func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
driver := findExternalDriver(cfg)
if driver == nil {
driver = goListDriver
}
return driver(cfg, patterns...)
response, err := driver(cfg, patterns...)
if err != nil {
return response, err
} else if response.NotHandled {
return goListDriver(cfg, patterns...)
}
return response, nil
}
// A Package describes a loaded Go package.
@ -253,7 +281,7 @@ type Package struct {
GoFiles []string
// CompiledGoFiles lists the absolute file paths of the package's source
// files that were presented to the compiler.
// files that are suitable for type checking.
// This may differ from GoFiles if files are processed before compilation.
CompiledGoFiles []string
@ -301,16 +329,39 @@ type Package struct {
forTest string
// module is the module information for the package if it exists.
module *packagesinternal.Module
Module *Module
}
// Module provides module information for a package.
type Module struct {
Path string // module path
Version string // module version
Replace *Module // replaced by this module
Time *time.Time // time version was created
Main bool // is this the main module?
Indirect bool // is this module only an indirect dependency of main module?
Dir string // directory holding files for this module, if any
GoMod string // path to go.mod file used when loading this module, if any
GoVersion string // go version used in module
Error *ModuleError // error loading module
}
// ModuleError holds errors loading a module.
type ModuleError struct {
Err string // the error itself
}
func init() {
packagesinternal.GetForTest = func(p interface{}) string {
return p.(*Package).forTest
}
packagesinternal.GetModule = func(p interface{}) *packagesinternal.Module {
return p.(*Package).module
packagesinternal.GetGoCmdRunner = func(config interface{}) *gocommand.Runner {
return config.(*Config).gocmdRunner
}
packagesinternal.SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {
config.(*Config).gocmdRunner = runner
}
packagesinternal.TypecheckCgo = int(typecheckCgo)
}
// An Error describes a problem with a package's metadata, syntax, or types.
@ -473,6 +524,9 @@ func newLoader(cfg *Config) *loader {
if ld.Config.Env == nil {
ld.Config.Env = os.Environ()
}
if ld.Config.gocmdRunner == nil {
ld.Config.gocmdRunner = &gocommand.Runner{}
}
if ld.Context == nil {
ld.Context = context.Background()
}
@ -690,6 +744,9 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
if ld.requestedMode&NeedTypesSizes == 0 {
ld.pkgs[i].TypesSizes = nil
}
if ld.requestedMode&NeedModule == 0 {
ld.pkgs[i].Module = nil
}
}
return result, nil
@ -865,6 +922,15 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
Error: appendError,
Sizes: ld.sizes,
}
if (ld.Mode & typecheckCgo) != 0 {
if !typesinternal.SetUsesCgo(tc) {
appendError(Error{
Msg: "typecheckCgo requires Go 1.15+",
Kind: ListError,
})
return
}
}
types.NewChecker(tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax)
lpkg.importErrors = nil // no longer needed

View file

@ -226,7 +226,8 @@ func For(obj types.Object) (Path, error) {
// the best paths because non-types may
// refer to types, but not the reverse.
empty := make([]byte, 0, 48) // initial space
for _, name := range scope.Names() {
names := scope.Names()
for _, name := range names {
o := scope.Lookup(name)
tname, ok := o.(*types.TypeName)
if !ok {
@ -253,7 +254,7 @@ func For(obj types.Object) (Path, error) {
// Then inspect everything else:
// non-types, and declared methods of defined types.
for _, name := range scope.Names() {
for _, name := range names {
o := scope.Lookup(name)
path := append(empty, name...)
if _, ok := o.(*types.TypeName); !ok {