mirror of
https://github.com/golang/go
synced 2024-11-18 23:24:39 -07:00
internal/lsp/source: scan loaded packages first for completions
Packages that have already been loaded by gopls are more likely to be used, and have full type information. Check them for completion candidates before scanning the disk. Also, minor bug fixes: add a missing mutex, and use a lower-than-usual score for typed unimported completions. Change-Id: I46388802913f9a89342fb47290f704b471154ec0 Reviewed-on: https://go-review.googlesource.com/c/tools/+/212860 Run-TryBot: Heschi Kreinick <heschi@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
2f3125dfbf
commit
9a28a1fa70
@ -617,7 +617,7 @@ func (c *completer) selector(sel *ast.SelectorExpr) error {
|
|||||||
// Is sel a qualified identifier?
|
// Is sel a qualified identifier?
|
||||||
if id, ok := sel.X.(*ast.Ident); ok {
|
if id, ok := sel.X.(*ast.Ident); ok {
|
||||||
if pkgname, ok := c.pkg.GetTypesInfo().Uses[id].(*types.PkgName); ok {
|
if pkgname, ok := c.pkg.GetTypesInfo().Uses[id].(*types.PkgName); ok {
|
||||||
c.packageMembers(pkgname.Imported(), nil)
|
c.packageMembers(pkgname.Imported(), stdScore, nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -630,20 +630,43 @@ func (c *completer) selector(sel *ast.SelectorExpr) error {
|
|||||||
|
|
||||||
// Try unimported packages.
|
// Try unimported packages.
|
||||||
if id, ok := sel.X.(*ast.Ident); ok && c.opts.Unimported && len(c.items) < unimportedTarget {
|
if id, ok := sel.X.(*ast.Ident); ok && c.opts.Unimported && len(c.items) < unimportedTarget {
|
||||||
|
if err := c.unimportedMembers(id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *completer) unimportedMembers(id *ast.Ident) error {
|
||||||
|
// Try loaded packages first. They're relevant, fast, and fully typed.
|
||||||
|
known := c.snapshot.KnownImportPaths()
|
||||||
|
for path, pkg := range known {
|
||||||
|
if pkg.GetTypes().Name() != id.Name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// We don't know what this is, so assign it the highest score.
|
||||||
|
score := 0.01 * imports.MaxRelevance
|
||||||
|
c.packageMembers(pkg.GetTypes(), score, &importInfo{
|
||||||
|
importPath: path,
|
||||||
|
name: pkg.GetTypes().Name(),
|
||||||
|
pkg: pkg,
|
||||||
|
})
|
||||||
|
if len(c.items) >= unimportedTarget {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx, cancel := c.deepCompletionContext()
|
ctx, cancel := c.deepCompletionContext()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
var mu sync.Mutex
|
||||||
known := c.snapshot.KnownImportPaths()
|
|
||||||
add := func(pkgExport imports.PackageExport) {
|
add := func(pkgExport imports.PackageExport) {
|
||||||
// If we've seen this import path, use the fully-typed version.
|
mu.Lock()
|
||||||
if knownPkg, ok := known[pkgExport.Fix.StmtInfo.ImportPath]; ok {
|
defer mu.Unlock()
|
||||||
c.packageMembers(knownPkg.GetTypes(), &importInfo{
|
if _, ok := known[pkgExport.Fix.StmtInfo.ImportPath]; ok {
|
||||||
importPath: pkgExport.Fix.StmtInfo.ImportPath,
|
return // We got this one above.
|
||||||
name: pkgExport.Fix.StmtInfo.Name,
|
}
|
||||||
pkg: knownPkg,
|
|
||||||
})
|
// Continue with untyped proposals.
|
||||||
} else {
|
|
||||||
// Otherwise, continue with untyped proposals.
|
|
||||||
pkg := types.NewPackage(pkgExport.Fix.StmtInfo.ImportPath, pkgExport.Fix.IdentName)
|
pkg := types.NewPackage(pkgExport.Fix.StmtInfo.ImportPath, pkgExport.Fix.IdentName)
|
||||||
for _, export := range pkgExport.Exports {
|
for _, export := range pkgExport.Exports {
|
||||||
score := 0.01 * float64(pkgExport.Fix.Relevance)
|
score := 0.01 * float64(pkgExport.Fix.Relevance)
|
||||||
@ -656,27 +679,22 @@ func (c *completer) selector(sel *ast.SelectorExpr) error {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if len(c.items) >= unimportedTarget {
|
if len(c.items) >= unimportedTarget {
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := c.snapshot.View().RunProcessEnvFunc(ctx, func(opts *imports.Options) error {
|
return c.snapshot.View().RunProcessEnvFunc(ctx, func(opts *imports.Options) error {
|
||||||
return imports.GetPackageExports(ctx, add, id.Name, c.filename, opts)
|
return imports.GetPackageExports(ctx, add, id.Name, c.filename, opts)
|
||||||
}); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *completer) packageMembers(pkg *types.Package, imp *importInfo) {
|
func (c *completer) packageMembers(pkg *types.Package, score float64, imp *importInfo) {
|
||||||
scope := pkg.Scope()
|
scope := pkg.Scope()
|
||||||
for _, name := range scope.Names() {
|
for _, name := range scope.Names() {
|
||||||
obj := scope.Lookup(name)
|
obj := scope.Lookup(name)
|
||||||
c.found(candidate{
|
c.found(candidate{
|
||||||
obj: obj,
|
obj: obj,
|
||||||
score: stdScore,
|
score: score,
|
||||||
imp: imp,
|
imp: imp,
|
||||||
addressable: isVar(obj),
|
addressable: isVar(obj),
|
||||||
})
|
})
|
||||||
|
@ -186,7 +186,7 @@ func (c *completer) deepSearch(cand candidate) {
|
|||||||
|
|
||||||
switch obj := obj.(type) {
|
switch obj := obj.(type) {
|
||||||
case *types.PkgName:
|
case *types.PkgName:
|
||||||
c.packageMembers(obj.Imported(), cand.imp)
|
c.packageMembers(obj.Imported(), stdScore, cand.imp)
|
||||||
default:
|
default:
|
||||||
c.methodsAndFields(obj.Type(), cand.addressable, cand.imp)
|
c.methodsAndFields(obj.Type(), cand.addressable, cand.imp)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user