mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
internal/lsp: search for deep completions across function calls
We now continue deep completion search across function calls. The function must take no arguments and return a single argument. For example, when completing "fo<>" you might get candidates such as "foo.bar().baz()". Previously we would stop searching for deep completions when we hit a function call. For example, we would stop at "foo.bar()", never finding "foo.bar().baz()". At the time I was worried about the search scope growing too large, but now that we dynamically limit the search scope there isn't much left to worry about. Change-Id: I48772c154400662876682503c1f58ef6e3dca688 Reviewed-on: https://go-review.googlesource.com/c/tools/+/201222 Reviewed-by: Rebecca Stambler <rstambler@golang.org> Run-TryBot: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
02335f11d5
commit
0abb09c987
@ -39,10 +39,16 @@ type deepCompletionState struct {
|
||||
candidateCount int
|
||||
}
|
||||
|
||||
// push pushes obj onto our search stack.
|
||||
func (s *deepCompletionState) push(obj types.Object) {
|
||||
// push pushes obj onto our search stack. If invoke is true then
|
||||
// invocation parens "()" will be appended to the object name.
|
||||
func (s *deepCompletionState) push(obj types.Object, invoke bool) {
|
||||
s.chain = append(s.chain, obj)
|
||||
s.chainNames = append(s.chainNames, obj.Name())
|
||||
|
||||
name := obj.Name()
|
||||
if invoke {
|
||||
name += "()"
|
||||
}
|
||||
s.chainNames = append(s.chainNames, name)
|
||||
}
|
||||
|
||||
// pop pops the last object off our search stack.
|
||||
@ -156,8 +162,21 @@ func (c *completer) deepSearch(obj types.Object) {
|
||||
return
|
||||
}
|
||||
|
||||
if sig, ok := obj.Type().Underlying().(*types.Signature); ok {
|
||||
// If obj is a function that takes no arguments and returns one
|
||||
// value, keep searching across the function call.
|
||||
if sig.Params().Len() == 0 && sig.Results().Len() == 1 {
|
||||
// Pass invoke=true since the function needs to be invoked in
|
||||
// the deep chain.
|
||||
c.deepState.push(obj, true)
|
||||
// The result of a function call is not addressable.
|
||||
c.methodsAndFields(sig.Results().At(0).Type(), false)
|
||||
c.deepState.pop()
|
||||
}
|
||||
}
|
||||
|
||||
// Push this object onto our search stack.
|
||||
c.deepState.push(obj)
|
||||
c.deepState.push(obj, false)
|
||||
|
||||
switch obj := obj.(type) {
|
||||
case *types.PkgName:
|
||||
|
35
internal/lsp/testdata/deep/deep.go
vendored
35
internal/lsp/testdata/deep/deep.go
vendored
@ -88,3 +88,38 @@ func _() {
|
||||
var i int
|
||||
i = a //@deep(" //", deepAD, deepABC, deepA, deepAB)
|
||||
}
|
||||
|
||||
type foo struct {
|
||||
b bar
|
||||
}
|
||||
|
||||
func (f foo) bar() bar {
|
||||
return f.b
|
||||
}
|
||||
|
||||
func (f foo) barPtr() *bar {
|
||||
return &f.b
|
||||
}
|
||||
|
||||
type bar struct{}
|
||||
|
||||
func (b bar) valueReceiver() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (b *bar) ptrReceiver() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func _() {
|
||||
var (
|
||||
i int
|
||||
f foo
|
||||
)
|
||||
|
||||
f.bar().valueReceiver //@item(deepBarValue, "f.bar().valueReceiver", "func() int", "method")
|
||||
f.barPtr().valueReceiver //@item(deepBarPtrValue, "f.barPtr().valueReceiver", "func() int", "method")
|
||||
f.barPtr().ptrReceiver //@item(deepBarPtrPtr, "f.barPtr().ptrReceiver", "func() int", "method")
|
||||
|
||||
i = fb //@fuzzy(" //", deepBarValue, deepBarPtrPtr, deepBarPtrValue)
|
||||
}
|
||||
|
2
internal/lsp/testdata/summary.txt.golden
vendored
2
internal/lsp/testdata/summary.txt.golden
vendored
@ -3,7 +3,7 @@ CompletionsCount = 178
|
||||
CompletionSnippetCount = 39
|
||||
UnimportedCompletionsCount = 1
|
||||
DeepCompletionsCount = 5
|
||||
FuzzyCompletionsCount = 6
|
||||
FuzzyCompletionsCount = 7
|
||||
RankedCompletionsCount = 1
|
||||
CaseSensitiveCompletionsCount = 4
|
||||
DiagnosticsCount = 21
|
||||
|
Loading…
x
Reference in New Issue
Block a user