internal/lsp: rank types higher when completing in return of a function
Completion now ranks type names higher for func receiver, type params and type results (e.g. func (<>) foo(<>) (<>) {}). Fixes golang/go#29152 Change-Id: Icdd18b1b344c1cd617a4f45a7b071e53c1345478 GitHub-Last-Rev: e6acb1f2d2a7e571ffcecc500e407fdefd118fed GitHub-Pull-Request: golang/tools#73 Reviewed-on: https://go-review.googlesource.com/c/159797 TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
718ddee956
commit
7414d4c1f7
|
@ -35,7 +35,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
||||||
|
|
||||||
// We hardcode the expected number of test cases to ensure that all tests
|
// We hardcode the expected number of test cases to ensure that all tests
|
||||||
// are being executed. If a test is added, this number must be changed.
|
// are being executed. If a test is added, this number must be changed.
|
||||||
const expectedCompletionsCount = 60
|
const expectedCompletionsCount = 63
|
||||||
const expectedDiagnosticsCount = 13
|
const expectedDiagnosticsCount = 13
|
||||||
const expectedFormatCount = 3
|
const expectedFormatCount = 3
|
||||||
const expectedDefinitionsCount = 16
|
const expectedDefinitionsCount = 16
|
||||||
|
|
|
@ -86,20 +86,24 @@ func Completion(ctx context.Context, f File, pos token.Pos) (items []CompletionI
|
||||||
typ := expectedType(path, pos, pkg.TypesInfo)
|
typ := expectedType(path, pos, pkg.TypesInfo)
|
||||||
sig := enclosingFunction(path, pos, pkg.TypesInfo)
|
sig := enclosingFunction(path, pos, pkg.TypesInfo)
|
||||||
pkgStringer := qualifier(file, pkg.Types, pkg.TypesInfo)
|
pkgStringer := qualifier(file, pkg.Types, pkg.TypesInfo)
|
||||||
|
preferTypeNames := wantTypeNames(pos, path)
|
||||||
|
|
||||||
seen := make(map[types.Object]bool)
|
seen := make(map[types.Object]bool)
|
||||||
|
|
||||||
// found adds a candidate completion.
|
// found adds a candidate completion.
|
||||||
// Only the first candidate of a given name is considered.
|
// Only the first candidate of a given name is considered.
|
||||||
found := func(obj types.Object, weight float64, items []CompletionItem) []CompletionItem {
|
found := func(obj types.Object, weight float64, items []CompletionItem) []CompletionItem {
|
||||||
if obj.Pkg() != nil && obj.Pkg() != pkg.Types && !obj.Exported() {
|
if obj.Pkg() != nil && obj.Pkg() != pkg.Types && !obj.Exported() {
|
||||||
return items // inaccessible
|
return items // inaccessible
|
||||||
}
|
}
|
||||||
|
|
||||||
if !seen[obj] {
|
if !seen[obj] {
|
||||||
seen[obj] = true
|
seen[obj] = true
|
||||||
if typ != nil && matchingTypes(typ, obj.Type()) {
|
if typ != nil && matchingTypes(typ, obj.Type()) {
|
||||||
weight *= 10.0
|
weight *= 10.0
|
||||||
}
|
}
|
||||||
|
if _, ok := obj.(*types.TypeName); !ok && preferTypeNames {
|
||||||
|
weight *= 0.01
|
||||||
|
}
|
||||||
item := formatCompletion(obj, pkgStringer, weight, func(v *types.Var) bool {
|
item := formatCompletion(obj, pkgStringer, weight, func(v *types.Var) bool {
|
||||||
return isParameter(sig, v)
|
return isParameter(sig, v)
|
||||||
})
|
})
|
||||||
|
@ -202,6 +206,34 @@ func selector(sel *ast.SelectorExpr, pos token.Pos, info *types.Info, found find
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wantTypeNames checks if given token position is inside func receiver, type params
|
||||||
|
// or type results (e.g func (<>) foo(<>) (<>) {} ).
|
||||||
|
func wantTypeNames(pos token.Pos, path []ast.Node) bool {
|
||||||
|
for _, p := range path {
|
||||||
|
switch n := p.(type) {
|
||||||
|
case *ast.FuncDecl:
|
||||||
|
recv := n.Recv
|
||||||
|
if recv != nil && recv.Pos() <= pos && pos <= recv.End() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.Type != nil {
|
||||||
|
params := n.Type.Params
|
||||||
|
if params != nil && params.Pos() <= pos && pos <= params.End() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
results := n.Type.Results
|
||||||
|
if results != nil && results.Pos() <= pos && pos <= results.End() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// lexical finds completions in the lexical environment.
|
// lexical finds completions in the lexical environment.
|
||||||
func lexical(path []ast.Node, pos token.Pos, pkg *types.Package, info *types.Info, found finder) (items []CompletionItem) {
|
func lexical(path []ast.Node, pos token.Pos, pkg *types.Package, info *types.Info, found finder) (items []CompletionItem) {
|
||||||
var scopes []*types.Scope // scopes[i], where i<len(path), is the possibly nil Scope of path[i].
|
var scopes []*types.Scope // scopes[i], where i<len(path), is the possibly nil Scope of path[i].
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package func_rank
|
||||||
|
|
||||||
|
var stringAVar = "var" //@item(stringAVar, "stringAVar", "string", "var")
|
||||||
|
func stringBFunc() string { return "str" } //@item(stringBFunc, "stringBFunc()", "string", "func")
|
||||||
|
type stringer struct{} //@item(stringer, "stringer", "struct{...}", "struct")
|
||||||
|
|
||||||
|
func _() stringer //@complete("tr", stringer, stringAVar, stringBFunc)
|
||||||
|
|
||||||
|
func _(val stringer) {} //@complete("tr", stringer, stringAVar, stringBFunc)
|
||||||
|
|
||||||
|
func (stringer) _() {} //@complete("tr", stringer, stringAVar, stringBFunc)
|
||||||
|
|
Loading…
Reference in New Issue