mirror of https://github.com/golang/go.git
internal/lsp: add snippet completion for function type parameters
Fixes golang/go#51544 Change-Id: I29cf2a0fe878eed263b406ff3ebf1eaeffe10e4b Reviewed-on: https://go-review.googlesource.com/c/tools/+/390854 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Peter Weinberger <pjw@google.com>
This commit is contained in:
parent
94322c4f17
commit
03d333aa5e
|
|
@ -130,7 +130,7 @@ Suffixes:
|
|||
case invoke:
|
||||
if sig, ok := funcType.Underlying().(*types.Signature); ok {
|
||||
s := source.NewSignature(ctx, c.snapshot, c.pkg, sig, nil, c.qf)
|
||||
c.functionCallSnippet("", s.Params(), &snip)
|
||||
c.functionCallSnippet("", s.TypeParams(), s.Params(), &snip)
|
||||
if sig.Results().Len() == 1 {
|
||||
funcType = sig.Results().At(0).Type()
|
||||
}
|
||||
|
|
@ -307,7 +307,7 @@ func (c *completer) formatBuiltin(ctx context.Context, cand candidate) (Completi
|
|||
}
|
||||
item.Detail = "func" + sig.Format()
|
||||
item.snippet = &snippet.Builder{}
|
||||
c.functionCallSnippet(obj.Name(), sig.Params(), item.snippet)
|
||||
c.functionCallSnippet(obj.Name(), sig.TypeParams(), sig.Params(), item.snippet)
|
||||
case *types.TypeName:
|
||||
if types.IsInterface(obj.Type()) {
|
||||
item.Kind = protocol.InterfaceCompletion
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ func (c *completer) structFieldSnippet(cand candidate, detail string, snip *snip
|
|||
}
|
||||
|
||||
// functionCallSnippets calculates the snippet for function calls.
|
||||
func (c *completer) functionCallSnippet(name string, params []string, snip *snippet.Builder) {
|
||||
func (c *completer) functionCallSnippet(name string, tparams, params []string, snip *snippet.Builder) {
|
||||
// If there is no suffix then we need to reuse existing call parens
|
||||
// "()" if present. If there is an identifier suffix then we always
|
||||
// need to include "()" since we don't overwrite the suffix.
|
||||
|
|
@ -73,7 +73,26 @@ func (c *completer) functionCallSnippet(name string, params []string, snip *snip
|
|||
}
|
||||
}
|
||||
|
||||
snip.WriteText(name + "(")
|
||||
snip.WriteText(name)
|
||||
|
||||
if len(tparams) > 0 {
|
||||
snip.WriteText("[")
|
||||
if c.opts.placeholders {
|
||||
for i, tp := range tparams {
|
||||
if i > 0 {
|
||||
snip.WriteText(", ")
|
||||
}
|
||||
snip.WritePlaceholder(func(b *snippet.Builder) {
|
||||
b.WriteText(tp)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
snip.WritePlaceholder(nil)
|
||||
}
|
||||
snip.WriteText("]")
|
||||
}
|
||||
|
||||
snip.WriteText("(")
|
||||
|
||||
if c.opts.placeholders {
|
||||
// A placeholder snippet turns "someFun<>" into "someFunc(<*i int*>, *s string*)".
|
||||
|
|
|
|||
|
|
@ -39,10 +39,10 @@ func FormatType(typ types.Type, qf types.Qualifier) (detail string, kind protoco
|
|||
}
|
||||
|
||||
type signature struct {
|
||||
name, doc string
|
||||
params, results []string
|
||||
variadic bool
|
||||
needResultParens bool
|
||||
name, doc string
|
||||
typeParams, params, results []string
|
||||
variadic bool
|
||||
needResultParens bool
|
||||
}
|
||||
|
||||
func (s *signature) Format() string {
|
||||
|
|
@ -75,6 +75,10 @@ func (s *signature) Format() string {
|
|||
return b.String()
|
||||
}
|
||||
|
||||
func (s *signature) TypeParams() []string {
|
||||
return s.typeParams
|
||||
}
|
||||
|
||||
func (s *signature) Params() []string {
|
||||
return s.params
|
||||
}
|
||||
|
|
@ -171,17 +175,17 @@ func formatFieldList(ctx context.Context, snapshot Snapshot, list *ast.FieldList
|
|||
// FormatTypeParams turns TypeParamList into its Go representation, such as:
|
||||
// [T, Y]. Note that it does not print constraints as this is mainly used for
|
||||
// formatting type params in method receivers.
|
||||
func FormatTypeParams(tp *typeparams.TypeParamList) string {
|
||||
if tp == nil || tp.Len() == 0 {
|
||||
func FormatTypeParams(tparams *typeparams.TypeParamList) string {
|
||||
if tparams == nil || tparams.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
buf.WriteByte('[')
|
||||
for i := 0; i < tp.Len(); i++ {
|
||||
for i := 0; i < tparams.Len(); i++ {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(tp.At(i).Obj().Name())
|
||||
buf.WriteString(tparams.At(i).Obj().Name())
|
||||
}
|
||||
buf.WriteByte(']')
|
||||
return buf.String()
|
||||
|
|
@ -189,6 +193,15 @@ func FormatTypeParams(tp *typeparams.TypeParamList) string {
|
|||
|
||||
// NewSignature returns formatted signature for a types.Signature struct.
|
||||
func NewSignature(ctx context.Context, s Snapshot, pkg Package, sig *types.Signature, comment *ast.CommentGroup, qf types.Qualifier) *signature {
|
||||
var tparams []string
|
||||
tpList := typeparams.ForSignature(sig)
|
||||
for i := 0; i < tpList.Len(); i++ {
|
||||
tparam := tpList.At(i)
|
||||
// TODO: is it possible to reuse the logic from FormatVarType here?
|
||||
s := tparam.Obj().Name() + " " + tparam.Constraint().String()
|
||||
tparams = append(tparams, s)
|
||||
}
|
||||
|
||||
params := make([]string, 0, sig.Params().Len())
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
el := sig.Params().At(i)
|
||||
|
|
@ -199,6 +212,7 @@ func NewSignature(ctx context.Context, s Snapshot, pkg Package, sig *types.Signa
|
|||
}
|
||||
params = append(params, p)
|
||||
}
|
||||
|
||||
var needResultParens bool
|
||||
results := make([]string, 0, sig.Results().Len())
|
||||
for i := 0; i < sig.Results().Len(); i++ {
|
||||
|
|
@ -228,6 +242,7 @@ func NewSignature(ctx context.Context, s Snapshot, pkg Package, sig *types.Signa
|
|||
}
|
||||
return &signature{
|
||||
doc: d,
|
||||
typeParams: tparams,
|
||||
params: params,
|
||||
results: results,
|
||||
variadic: sig.Variadic(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
// +build go1.18
|
||||
//go:build go1.18
|
||||
|
||||
package snippets
|
||||
|
||||
type SyncMap[K comparable, V any] struct{}
|
||||
|
||||
func NewSyncMap[K comparable, V any]() (result *SyncMap[K, V]) { //@item(NewSyncMap, "NewSyncMap", "", "")
|
||||
return
|
||||
}
|
||||
|
||||
func Identity[P ~int](p P) P { //@item(Identity, "Identity", "", "")
|
||||
return p
|
||||
}
|
||||
|
||||
func _() {
|
||||
_ = NewSyncM //@snippet(" //", NewSyncMap, "NewSyncMap[${1:}]()", "NewSyncMap[${1:K comparable}, ${2:V any}]()")
|
||||
_ = Identi //@snippet(" //", Identity, "Identity[${1:}](${2:})", "Identity[${1:P ~int}](${2:p P})")
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
CallHierarchyCount = 2
|
||||
CodeLensCount = 5
|
||||
CompletionsCount = 266
|
||||
CompletionSnippetCount = 107
|
||||
CompletionSnippetCount = 109
|
||||
UnimportedCompletionsCount = 5
|
||||
DeepCompletionsCount = 5
|
||||
FuzzyCompletionsCount = 8
|
||||
|
|
|
|||
Loading…
Reference in New Issue