mirror of
https://github.com/golang/go
synced 2024-11-18 13:04:46 -07:00
internal/imports: cache module information
To avoid proposing unusable completions, such as those in modules that need a replace statement to be usable, we need to know what module a directory is in. That involves walking up the directory tree to find a go.mod file, which is expensive to do over and over. Really, we just need to check if the directory we're in has a go.mod file, then use the parent dir's results. Add module information to the cache and use it when figuring out what module a dir is in. Change-Id: Ia74ba9b37d73fca5e6786a94c73c8fd71b591645 Reviewed-on: https://go-review.googlesource.com/c/tools/+/202541 Run-TryBot: Heschi Kreinick <heschi@google.com> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
3057e18543
commit
7178990c25
@ -249,28 +249,41 @@ func (r *ModuleResolver) dirIsNestedModule(dir string, mod *ModuleJSON) bool {
|
||||
// so it cannot be a nested module.
|
||||
return false
|
||||
}
|
||||
mf := r.findModFile(dir)
|
||||
if mf == "" {
|
||||
modDir, _ := r.modInfo(dir)
|
||||
if modDir == "" {
|
||||
return false
|
||||
}
|
||||
return filepath.Dir(mf) != mod.Dir
|
||||
return modDir != mod.Dir
|
||||
}
|
||||
|
||||
func (r *ModuleResolver) findModFile(dir string) string {
|
||||
func (r *ModuleResolver) modInfo(dir string) (modDir string, modName string) {
|
||||
readModName := func(modFile string) string {
|
||||
modBytes, err := ioutil.ReadFile(modFile)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return modulePath(modBytes)
|
||||
}
|
||||
|
||||
if r.dirInModuleCache(dir) {
|
||||
matches := modCacheRegexp.FindStringSubmatch(dir)
|
||||
index := strings.Index(dir, matches[1]+"@"+matches[2])
|
||||
return filepath.Join(dir[:index], matches[1]+"@"+matches[2], "go.mod")
|
||||
modDir := filepath.Join(dir[:index], matches[1]+"@"+matches[2])
|
||||
return modDir, readModName(filepath.Join(modDir, "go.mod"))
|
||||
}
|
||||
for {
|
||||
if info, ok := r.cacheLoad(dir); ok {
|
||||
return info.moduleDir, info.moduleName
|
||||
}
|
||||
f := filepath.Join(dir, "go.mod")
|
||||
info, err := os.Stat(f)
|
||||
if err == nil && !info.IsDir() {
|
||||
return f
|
||||
return dir, readModName(f)
|
||||
}
|
||||
|
||||
d := filepath.Dir(dir)
|
||||
if len(d) >= len(dir) {
|
||||
return "" // reached top of file system, no go.mod
|
||||
return "", "" // reached top of file system, no go.mod
|
||||
}
|
||||
dir = d
|
||||
}
|
||||
@ -478,22 +491,22 @@ func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) dir
|
||||
importPath = subdir
|
||||
}
|
||||
|
||||
modDir, modName := r.modInfo(dir)
|
||||
result := directoryPackageInfo{
|
||||
status: directoryScanned,
|
||||
dir: dir,
|
||||
rootType: root.Type,
|
||||
nonCanonicalImportPath: importPath,
|
||||
needsReplace: false,
|
||||
moduleDir: modDir,
|
||||
moduleName: modName,
|
||||
}
|
||||
if root.Type == gopathwalk.RootGOROOT {
|
||||
// stdlib packages are always in scope, despite the confusing go.mod
|
||||
return result
|
||||
}
|
||||
// Check that this package is not obviously impossible to import.
|
||||
modFile := r.findModFile(dir)
|
||||
|
||||
modBytes, err := ioutil.ReadFile(modFile)
|
||||
if err == nil && !strings.HasPrefix(importPath, modulePath(modBytes)) {
|
||||
if !strings.HasPrefix(importPath, modName) {
|
||||
// The module's declared path does not match
|
||||
// its expected path. It probably needs a
|
||||
// replace directive we don't have.
|
||||
|
@ -51,6 +51,10 @@ type directoryPackageInfo struct {
|
||||
// replace directive.
|
||||
needsReplace bool
|
||||
|
||||
// Module-related information.
|
||||
moduleDir string // The directory that is the module root of this dir.
|
||||
moduleName string // The module name that contains this dir.
|
||||
|
||||
// Set when status >= nameLoaded.
|
||||
|
||||
packageName string // the package name, as declared in the source.
|
||||
|
@ -765,12 +765,12 @@ package x
|
||||
import _ "rsc.io/quote"
|
||||
`, "")
|
||||
defer mt.cleanup()
|
||||
want := filepath.Join(mt.resolver.env.GOPATH, "pkg/mod", "rsc.io/quote@v1.5.2", "go.mod")
|
||||
want := filepath.Join(mt.resolver.env.GOPATH, "pkg/mod", "rsc.io/quote@v1.5.2")
|
||||
|
||||
found := mt.assertScanFinds("rsc.io/quote", "quote")
|
||||
modFile := mt.resolver.findModFile(found.dir)
|
||||
if modFile != want {
|
||||
t.Errorf("expected: %s, got: %s", want, modFile)
|
||||
modDir, _ := mt.resolver.modInfo(found.dir)
|
||||
if modDir != want {
|
||||
t.Errorf("expected: %s, got: %s", want, modDir)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user