diff --git a/internal/lsp/source/deep_completion.go b/internal/lsp/source/deep_completion.go index b7eeacdae0..6dd85e7026 100644 --- a/internal/lsp/source/deep_completion.go +++ b/internal/lsp/source/deep_completion.go @@ -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: diff --git a/internal/lsp/testdata/deep/deep.go b/internal/lsp/testdata/deep/deep.go index f6bcbd7a7a..df70c14725 100644 --- a/internal/lsp/testdata/deep/deep.go +++ b/internal/lsp/testdata/deep/deep.go @@ -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) +} diff --git a/internal/lsp/testdata/summary.txt.golden b/internal/lsp/testdata/summary.txt.golden index 3b3b10f8fb..e0a2f22177 100644 --- a/internal/lsp/testdata/summary.txt.golden +++ b/internal/lsp/testdata/summary.txt.golden @@ -3,7 +3,7 @@ CompletionsCount = 178 CompletionSnippetCount = 39 UnimportedCompletionsCount = 1 DeepCompletionsCount = 5 -FuzzyCompletionsCount = 6 +FuzzyCompletionsCount = 7 RankedCompletionsCount = 1 CaseSensitiveCompletionsCount = 4 DiagnosticsCount = 21