1
0
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:
Heschi Kreinick 2019-12-30 13:29:58 -05:00
parent 2f3125dfbf
commit 9a28a1fa70
2 changed files with 56 additions and 38 deletions

View File

@ -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),
}) })

View File

@ -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)
} }