aboutsummaryrefslogtreecommitdiff
path: root/internal/lsp
diff options
context:
space:
mode:
authorRebecca Stambler <rstambler@golang.org>2020-04-21 21:28:44 -0400
committerRebecca Stambler <rstambler@golang.org>2020-04-22 20:52:58 +0000
commit72e4a01eba4315301fd9ce00c8c2f492580ded8a (patch)
tree3048e7b3c18aabd69e698e24a5ad7bb45ed2696f /internal/lsp
parent3d37a677963775f298425e28f9ebc473003bee39 (diff)
downloadgolang-x-tools-72e4a01eba4315301fd9ce00c8c2f492580ded8a.tar.gz
internal/lsp: refactor code for formatting signatures
The code for formatting function signatures is fairly confusing. Factoring out an unexported signature type simplifies things a bit. Hopefully we'll be able to pull out more formatting logic from the other features. Ideally, I'd like to return to the separation between internal/lsp/source and internal/lsp so that a formatting package can be pulled out and used in internal/lsp. Change-Id: I7428db5004eab371e46402188e0dc6bb30f0c425 Reviewed-on: https://go-review.googlesource.com/c/tools/+/229318 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
Diffstat (limited to 'internal/lsp')
-rw-r--r--internal/lsp/source/completion_format.go76
-rw-r--r--internal/lsp/source/hover.go12
-rw-r--r--internal/lsp/source/signature_help.go61
-rw-r--r--internal/lsp/source/symbols.go8
-rw-r--r--internal/lsp/source/types_format.go218
-rw-r--r--internal/lsp/source/util.go130
-rw-r--r--internal/lsp/testdata/lsp/primarymod/godef/a/random.go.golden1
-rw-r--r--internal/lsp/testdata/lsp/primarymod/signature/signature.go.golden6
8 files changed, 276 insertions, 236 deletions
diff --git a/internal/lsp/source/completion_format.go b/internal/lsp/source/completion_format.go
index b40b9f4a9..88ff10299 100644
--- a/internal/lsp/source/completion_format.go
+++ b/internal/lsp/source/completion_format.go
@@ -5,11 +5,9 @@
package source
import (
- "bytes"
"context"
"fmt"
"go/ast"
- "go/printer"
"go/types"
"strings"
@@ -28,7 +26,7 @@ func (c *completer) item(ctx context.Context, cand candidate) (CompletionItem, e
// Handle builtin types separately.
if obj.Parent() == types.Universe {
- return c.formatBuiltin(ctx, cand), nil
+ return c.formatBuiltin(ctx, cand)
}
var (
@@ -46,10 +44,12 @@ func (c *completer) item(ctx context.Context, cand candidate) (CompletionItem, e
// expandFuncCall mutates the completion label, detail, and snippet
// to that of an invocation of sig.
expandFuncCall := func(sig *types.Signature) {
- params := formatParams(ctx, c.snapshot, c.pkg, sig, c.qf)
- snip = c.functionCallSnippet(label, params)
- results, writeParens := formatResults(sig.Results(), c.qf)
- detail = "func" + formatFunction(params, results, writeParens)
+ s, err := newSignature(ctx, c.snapshot, c.pkg, "", sig, nil, c.qf)
+ if err != nil {
+ return
+ }
+ snip = c.functionCallSnippet(label, s.params)
+ detail = "func" + s.format()
// Add variadic "..." if we are using a function result to fill in a variadic parameter.
if sig.Results().Len() == 1 && c.inference.matchesVariadic(sig.Results().At(0).Type()) {
@@ -232,7 +232,7 @@ func (c *completer) importEdits(ctx context.Context, imp *importInfo) ([]protoco
})
}
-func (c *completer) formatBuiltin(ctx context.Context, cand candidate) CompletionItem {
+func (c *completer) formatBuiltin(ctx context.Context, cand candidate) (CompletionItem, error) {
obj := cand.obj
item := CompletionItem{
Label: obj.Name(),
@@ -244,20 +244,12 @@ func (c *completer) formatBuiltin(ctx context.Context, cand candidate) Completio
item.Kind = protocol.ConstantCompletion
case *types.Builtin:
item.Kind = protocol.FunctionCompletion
- astObj, err := c.snapshot.View().LookupBuiltin(ctx, obj.Name())
+ sig, err := newBuiltinSignature(ctx, c.snapshot.View(), obj.Name())
if err != nil {
- event.Error(ctx, "no builtin package", err)
- break
- }
- decl, ok := astObj.Decl.(*ast.FuncDecl)
- if !ok {
- break
+ return CompletionItem{}, err
}
- params, _ := formatFieldList(ctx, c.snapshot.View(), decl.Type.Params)
- results, writeResultParens := formatFieldList(ctx, c.snapshot.View(), decl.Type.Results)
- item.Label = obj.Name()
- item.Detail = "func" + formatFunction(params, results, writeResultParens)
- item.snippet = c.functionCallSnippet(obj.Name(), params)
+ item.Detail = "func" + sig.format()
+ item.snippet = c.functionCallSnippet(obj.Name(), sig.params)
case *types.TypeName:
if types.IsInterface(obj.Type()) {
item.Kind = protocol.InterfaceCompletion
@@ -267,48 +259,7 @@ func (c *completer) formatBuiltin(ctx context.Context, cand candidate) Completio
case *types.Nil:
item.Kind = protocol.VariableCompletion
}
- return item
-}
-
-var replacer = strings.NewReplacer(
- `ComplexType`, `complex128`,
- `FloatType`, `float64`,
- `IntegerType`, `int`,
-)
-
-func formatFieldList(ctx context.Context, v View, list *ast.FieldList) ([]string, bool) {
- if list == nil {
- return nil, false
- }
- var writeResultParens bool
- var result []string
- for i := 0; i < len(list.List); i++ {
- if i >= 1 {
- writeResultParens = true
- }
- p := list.List[i]
- cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 4}
- b := &bytes.Buffer{}
- if err := cfg.Fprint(b, v.Session().Cache().FileSet(), p.Type); err != nil {
- event.Error(ctx, "unable to print type", nil, tag.Type.Of(p.Type))
- continue
- }
- typ := replacer.Replace(b.String())
- if len(p.Names) == 0 {
- result = append(result, typ)
- }
- for _, name := range p.Names {
- if name.Name != "" {
- if i == 0 {
- writeResultParens = true
- }
- result = append(result, fmt.Sprintf("%s %s", name.Name, typ))
- } else {
- result = append(result, typ)
- }
- }
- }
- return result, writeResultParens
+ return item, nil
}
// qualifier returns a function that appropriately formats a types.PkgName
@@ -321,7 +272,6 @@ func qualifier(f *ast.File, pkg *types.Package, info *types.Info) types.Qualifie
if imp.Name != nil {
obj = info.Defs[imp.Name]
} else {
-
obj = info.Implicits[imp]
}
if pkgname, ok := obj.(*types.PkgName); ok {
diff --git a/internal/lsp/source/hover.go b/internal/lsp/source/hover.go
index 6c0024f6b..b15cccbb1 100644
--- a/internal/lsp/source/hover.go
+++ b/internal/lsp/source/hover.go
@@ -307,7 +307,10 @@ func formatVar(node ast.Spec, obj types.Object, decl *ast.GenDecl) *HoverInforma
}
func FormatHover(h *HoverInformation, options Options) (string, error) {
- signature := formatSignature(h.Signature, options)
+ signature := h.Signature
+ if options.PreferredContentFormat == protocol.Markdown {
+ signature = fmt.Sprintf("```go\n%s\n```", signature)
+ }
switch options.HoverKind {
case SingleLine:
return h.SingleLine, nil
@@ -347,13 +350,6 @@ func formatLink(h *HoverInformation, options Options) string {
}
}
-func formatSignature(signature string, options Options) string {
- if options.PreferredContentFormat == protocol.Markdown {
- signature = fmt.Sprintf("```go\n%s\n```", signature)
- }
- return signature
-}
-
func formatDoc(doc string, options Options) string {
if options.PreferredContentFormat == protocol.Markdown {
return CommentToMarkdown(doc)
diff --git a/internal/lsp/source/signature_help.go b/internal/lsp/source/signature_help.go
index e80ea2fcf..20d2431a3 100644
--- a/internal/lsp/source/signature_help.go
+++ b/internal/lsp/source/signature_help.go
@@ -63,6 +63,8 @@ FindCall:
return nil, 0, errors.Errorf("cannot find an enclosing function")
}
+ qf := qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo())
+
// Get the object representing the function, if available.
// There is no object in certain cases such as calling a function returned by
// a function (e.g. "foo()()").
@@ -90,9 +92,6 @@ FindCall:
return nil, 0, errors.Errorf("cannot find signature for Fun %[1]T (%[1]v)", callExpr.Fun)
}
- qf := qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo())
- params := formatParams(ctx, snapshot, pkg, sig, qf)
- results, writeResultParens := formatResults(sig.Results(), qf)
activeParam := activeParameter(callExpr, sig.Params().Len(), sig.Variadic(), rng.Start)
var (
@@ -122,51 +121,37 @@ FindCall:
} else {
name = "func"
}
- return signatureInformation(name, comment, params, results, writeResultParens), activeParam, nil
-}
-
-func builtinSignature(ctx context.Context, v View, callExpr *ast.CallExpr, name string, pos token.Pos) (*protocol.SignatureInformation, int, error) {
- astObj, err := v.LookupBuiltin(ctx, name)
+ s, err := newSignature(ctx, snapshot, pkg, name, sig, comment, qf)
if err != nil {
return nil, 0, err
}
- decl, ok := astObj.Decl.(*ast.FuncDecl)
- if !ok {
- return nil, 0, errors.Errorf("no function declaration for builtin: %s", name)
- }
- params, _ := formatFieldList(ctx, v, decl.Type.Params)
- results, writeResultParens := formatFieldList(ctx, v, decl.Type.Results)
-
- var (
- numParams int
- variadic bool
- )
- if decl.Type.Params.List != nil {
- numParams = len(decl.Type.Params.List)
- lastParam := decl.Type.Params.List[numParams-1]
- if _, ok := lastParam.Type.(*ast.Ellipsis); ok {
- variadic = true
- }
+ paramInfo := make([]protocol.ParameterInformation, 0, len(s.params))
+ for _, p := range s.params {
+ paramInfo = append(paramInfo, protocol.ParameterInformation{Label: p})
}
- activeParam := activeParameter(callExpr, numParams, variadic, pos)
- return signatureInformation(name, nil, params, results, writeResultParens), activeParam, nil
+ return &protocol.SignatureInformation{
+ Label: name + s.format(),
+ Documentation: doc.Synopsis(s.doc),
+ Parameters: paramInfo,
+ }, activeParam, nil
}
-func signatureInformation(name string, comment *ast.CommentGroup, params, results []string, writeResultParens bool) *protocol.SignatureInformation {
- paramInfo := make([]protocol.ParameterInformation, 0, len(params))
- for _, p := range params {
- paramInfo = append(paramInfo, protocol.ParameterInformation{Label: p})
+func builtinSignature(ctx context.Context, view View, callExpr *ast.CallExpr, name string, pos token.Pos) (*protocol.SignatureInformation, int, error) {
+ sig, err := newBuiltinSignature(ctx, view, name)
+ if err != nil {
+ return nil, 0, err
}
- label := name + formatFunction(params, results, writeResultParens)
- var c string
- if comment != nil {
- c = doc.Synopsis(comment.Text())
+ paramInfo := make([]protocol.ParameterInformation, 0, len(sig.params))
+ for _, p := range sig.params {
+ paramInfo = append(paramInfo, protocol.ParameterInformation{Label: p})
}
+ activeParam := activeParameter(callExpr, len(sig.params), sig.variadic, pos)
return &protocol.SignatureInformation{
- Label: label,
- Documentation: c,
+ Label: sig.name + sig.format(),
+ Documentation: doc.Synopsis(sig.doc),
Parameters: paramInfo,
- }
+ }, activeParam, nil
+
}
func activeParameter(callExpr *ast.CallExpr, numParams int, variadic bool, pos token.Pos) (activeParam int) {
diff --git a/internal/lsp/source/symbols.go b/internal/lsp/source/symbols.go
index 1a1624dec..8b09f81dc 100644
--- a/internal/lsp/source/symbols.go
+++ b/internal/lsp/source/symbols.go
@@ -112,11 +112,11 @@ func funcSymbol(view View, pkg Package, decl *ast.FuncDecl, obj types.Object, q
return s, nil
}
-func typeSymbol(view View, pkg Package, info *types.Info, spec *ast.TypeSpec, obj types.Object, q types.Qualifier) (protocol.DocumentSymbol, error) {
+func typeSymbol(view View, pkg Package, info *types.Info, spec *ast.TypeSpec, obj types.Object, qf types.Qualifier) (protocol.DocumentSymbol, error) {
s := protocol.DocumentSymbol{
Name: obj.Name(),
}
- s.Detail, _ = formatType(obj.Type(), q)
+ s.Detail, _ = formatType(obj.Type(), qf)
s.Kind = typeToKind(obj.Type())
var err error
@@ -137,7 +137,7 @@ func typeSymbol(view View, pkg Package, info *types.Info, spec *ast.TypeSpec, ob
Name: f.Name(),
Kind: protocol.Field,
}
- child.Detail, _ = formatType(f.Type(), q)
+ child.Detail, _ = formatType(f.Type(), qf)
spanNode, selectionNode := nodesForStructField(i, st)
if span, err := nodeToProtocolRange(view, pkg, spanNode); err == nil {
@@ -189,7 +189,7 @@ func typeSymbol(view View, pkg Package, info *types.Info, spec *ast.TypeSpec, ob
}
child := protocol.DocumentSymbol{
- Name: types.TypeString(embedded, q),
+ Name: types.TypeString(embedded, qf),
}
child.Kind = typeToKind(embedded)
var spanNode, selectionNode ast.Node
diff --git a/internal/lsp/source/types_format.go b/internal/lsp/source/types_format.go
new file mode 100644
index 000000000..a536ffd9f
--- /dev/null
+++ b/internal/lsp/source/types_format.go
@@ -0,0 +1,218 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package source
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "go/ast"
+ "go/doc"
+ "go/printer"
+ "go/types"
+ "strings"
+
+ "golang.org/x/tools/internal/lsp/debug/tag"
+ "golang.org/x/tools/internal/lsp/protocol"
+ "golang.org/x/tools/internal/telemetry/event"
+)
+
+// formatType returns the detail and kind for a types.Type.
+func formatType(typ types.Type, qf types.Qualifier) (detail string, kind protocol.CompletionItemKind) {
+ if types.IsInterface(typ) {
+ detail = "interface{...}"
+ kind = protocol.InterfaceCompletion
+ } else if _, ok := typ.(*types.Struct); ok {
+ detail = "struct{...}"
+ kind = protocol.StructCompletion
+ } else if typ != typ.Underlying() {
+ detail, kind = formatType(typ.Underlying(), qf)
+ } else {
+ detail = types.TypeString(typ, qf)
+ kind = protocol.ClassCompletion
+ }
+ return detail, kind
+}
+
+type signature struct {
+ name, doc string
+ params, results []string
+ variadic bool
+ needResultParens bool
+}
+
+func (s *signature) format() string {
+ var b strings.Builder
+ b.WriteByte('(')
+ for i, p := range s.params {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ b.WriteString(p)
+ }
+ b.WriteByte(')')
+
+ // Add space between parameters and results.
+ if len(s.results) > 0 {
+ b.WriteByte(' ')
+ }
+ if s.needResultParens {
+ b.WriteByte('(')
+ }
+ for i, r := range s.results {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ b.WriteString(r)
+ }
+ if s.needResultParens {
+ b.WriteByte(')')
+ }
+ return b.String()
+}
+
+func newBuiltinSignature(ctx context.Context, view View, name string) (*signature, error) {
+ astObj, err := view.LookupBuiltin(ctx, name)
+ if err != nil {
+ return nil, err
+ }
+ decl, ok := astObj.Decl.(*ast.FuncDecl)
+ if !ok {
+ return nil, fmt.Errorf("no function declaration for builtin: %s", name)
+ }
+ if decl.Type == nil {
+ return nil, fmt.Errorf("no type for builtin decl %s", decl.Name)
+ }
+ var variadic bool
+ if decl.Type.Params.List != nil {
+ numParams := len(decl.Type.Params.List)
+ lastParam := decl.Type.Params.List[numParams-1]
+ if _, ok := lastParam.Type.(*ast.Ellipsis); ok {
+ variadic = true
+ }
+ }
+ params, _ := formatFieldList(ctx, view, decl.Type.Params, variadic)
+ results, needResultParens := formatFieldList(ctx, view, decl.Type.Results, false)
+ return &signature{
+ doc: decl.Doc.Text(),
+ name: name,
+ needResultParens: needResultParens,
+ params: params,
+ results: results,
+ variadic: variadic,
+ }, nil
+}
+
+func newSignature(ctx context.Context, s Snapshot, pkg Package, name string, sig *types.Signature, comment *ast.CommentGroup, qf types.Qualifier) (*signature, error) {
+ params := make([]string, 0, sig.Params().Len())
+ for i := 0; i < sig.Params().Len(); i++ {
+ el := sig.Params().At(i)
+ typ, err := formatFieldType(ctx, s, pkg, el)
+ if err != nil {
+ typ = types.TypeString(el.Type(), qf)
+ }
+ // Handle a variadic parameter (can only be the final parameter).
+ if sig.Variadic() && i == sig.Params().Len()-1 {
+ typ = strings.Replace(typ, "[]", "...", 1)
+ }
+ p := typ
+ if el.Name() != "" {
+ p = el.Name() + " " + typ
+ }
+ params = append(params, p)
+ }
+ var needResultParens bool
+ results := make([]string, 0, sig.Results().Len())
+ for i := 0; i < sig.Results().Len(); i++ {
+ if i >= 1 {
+ needResultParens = true
+ }
+ el := sig.Results().At(i)
+ typ := types.TypeString(el.Type(), qf)
+
+ if el.Name() == "" {
+ results = append(results, typ)
+ } else {
+ if i == 0 {
+ needResultParens = true
+ }
+ results = append(results, el.Name()+" "+typ)
+ }
+ }
+ var c string
+ if comment != nil {
+ c = doc.Synopsis(comment.Text())
+ }
+ return &signature{
+ doc: c,
+ params: params,
+ results: results,
+ variadic: sig.Variadic(),
+ needResultParens: needResultParens,
+ }, nil
+}
+
+func formatFieldType(ctx context.Context, s Snapshot, srcpkg Package, obj *types.Var) (string, error) {
+ file, pkg, err := findPosInPackage(s.View(), srcpkg, obj.Pos())
+ if err != nil {
+ return "", err
+ }
+ ident, err := findIdentifier(ctx, s, pkg, file, obj.Pos())
+ if err != nil {
+ return "", err
+ }
+ if i := ident.ident; i == nil || i.Obj == nil || i.Obj.Decl == nil {
+ return "", fmt.Errorf("no object for ident %v", i.Name)
+ }
+ f, ok := ident.ident.Obj.Decl.(*ast.Field)
+ if !ok {
+ return "", fmt.Errorf("ident %s is not a field type", ident.Name)
+ }
+ return formatNode(s.View().Session().Cache().FileSet(), f.Type), nil
+}
+
+var replacer = strings.NewReplacer(
+ `ComplexType`, `complex128`,
+ `FloatType`, `float64`,
+ `IntegerType`, `int`,
+)
+
+func formatFieldList(ctx context.Context, view View, list *ast.FieldList, variadic bool) ([]string, bool) {
+ if list == nil {
+ return nil, false
+ }
+ var writeResultParens bool
+ var result []string
+ for i := 0; i < len(list.List); i++ {
+ if i >= 1 {
+ writeResultParens = true
+ }
+ p := list.List[i]
+ cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 4}
+ b := &bytes.Buffer{}
+ if err := cfg.Fprint(b, view.Session().Cache().FileSet(), p.Type); err != nil {
+ event.Error(ctx, "unable to print type", nil, tag.Type.Of(p.Type))
+ continue
+ }
+ typ := replacer.Replace(b.String())
+ if len(p.Names) == 0 {
+ result = append(result, typ)
+ }
+ for _, name := range p.Names {
+ if name.Name != "" {
+ if i == 0 {
+ writeResultParens = true
+ }
+ result = append(result, fmt.Sprintf("%s %s", name.Name, typ))
+ } else {
+ result = append(result, typ)
+ }
+ }
+ }
+ if variadic {
+ result[len(result)-1] = strings.Replace(result[len(result)-1], "[]", "...", 1)
+ }
+ return result, writeResultParens
+}
diff --git a/internal/lsp/source/util.go b/internal/lsp/source/util.go
index 5d275bddc..69cfba9f1 100644
--- a/internal/lsp/source/util.go
+++ b/internal/lsp/source/util.go
@@ -376,6 +376,14 @@ func resolveInvalid(fset *token.FileSet, obj types.Object, node ast.Node, info *
return types.NewVar(obj.Pos(), obj.Pkg(), obj.Name(), typ)
}
+func formatNode(fset *token.FileSet, n ast.Node) string {
+ var buf strings.Builder
+ if err := printer.Fprint(&buf, fset, n); err != nil {
+ return ""
+ }
+ return buf.String()
+}
+
func isPointer(T types.Type) bool {
_, ok := T.(*types.Pointer)
return ok
@@ -499,128 +507,6 @@ func fieldsAccessible(s *types.Struct, p *types.Package) bool {
return false
}
-func formatParams(ctx context.Context, s Snapshot, pkg Package, sig *types.Signature, qf types.Qualifier) []string {
- params := make([]string, 0, sig.Params().Len())
- for i := 0; i < sig.Params().Len(); i++ {
- el := sig.Params().At(i)
- typ, err := formatFieldType(ctx, s, pkg, el)
- if err != nil {
- typ = types.TypeString(el.Type(), qf)
- }
-
- // Handle a variadic parameter (can only be the final parameter).
- if sig.Variadic() && i == sig.Params().Len()-1 {
- typ = strings.Replace(typ, "[]", "...", 1)
- }
-
- if el.Name() == "" {
- params = append(params, typ)
- } else {
- params = append(params, el.Name()+" "+typ)
- }
- }
- return params
-}
-
-func formatFieldType(ctx context.Context, s Snapshot, srcpkg Package, obj types.Object) (string, error) {
- file, pkg, err := findPosInPackage(s.View(), srcpkg, obj.Pos())
- if err != nil {
- return "", err
- }
- ident, err := findIdentifier(ctx, s, pkg, file, obj.Pos())
- if err != nil {
- return "", err
- }
- if i := ident.ident; i == nil || i.Obj == nil || i.Obj.Decl == nil {
- return "", errors.Errorf("no object for ident %v", i.Name)
- }
- f, ok := ident.ident.Obj.Decl.(*ast.Field)
- if !ok {
- return "", errors.Errorf("ident %s is not a field type", ident.Name)
- }
- return formatNode(s.View().Session().Cache().FileSet(), f.Type), nil
-}
-
-func formatNode(fset *token.FileSet, n ast.Node) string {
- var buf strings.Builder
- if err := printer.Fprint(&buf, fset, n); err != nil {
- return ""
- }
- return buf.String()
-}
-
-func formatResults(tup *types.Tuple, qf types.Qualifier) ([]string, bool) {
- var writeResultParens bool
- results := make([]string, 0, tup.Len())
- for i := 0; i < tup.Len(); i++ {
- if i >= 1 {
- writeResultParens = true
- }
- el := tup.At(i)
- typ := types.TypeString(el.Type(), qf)
-
- if el.Name() == "" {
- results = append(results, typ)
- } else {
- if i == 0 {
- writeResultParens = true
- }
- results = append(results, el.Name()+" "+typ)
- }
- }
- return results, writeResultParens
-}
-
-// formatType returns the detail and kind for an object of type *types.TypeName.
-func formatType(typ types.Type, qf types.Qualifier) (detail string, kind protocol.CompletionItemKind) {
- if types.IsInterface(typ) {
- detail = "interface{...}"
- kind = protocol.InterfaceCompletion
- } else if _, ok := typ.(*types.Struct); ok {
- detail = "struct{...}"
- kind = protocol.StructCompletion
- } else if typ != typ.Underlying() {
- detail, kind = formatType(typ.Underlying(), qf)
- } else {
- detail = types.TypeString(typ, qf)
- kind = protocol.ClassCompletion
- }
- return detail, kind
-}
-
-func formatFunction(params []string, results []string, writeResultParens bool) string {
- var detail strings.Builder
-
- detail.WriteByte('(')
- for i, p := range params {
- if i > 0 {
- detail.WriteString(", ")
- }
- detail.WriteString(p)
- }
- detail.WriteByte(')')
-
- // Add space between parameters and results.
- if len(results) > 0 {
- detail.WriteByte(' ')
- }
-
- if writeResultParens {
- detail.WriteByte('(')
- }
- for i, p := range results {
- if i > 0 {
- detail.WriteString(", ")
- }
- detail.WriteString(p)
- }
- if writeResultParens {
- detail.WriteByte(')')
- }
-
- return detail.String()
-}
-
func SortDiagnostics(d []*Diagnostic) {
sort.Slice(d, func(i int, j int) bool {
return CompareDiagnostic(d[i], d[j]) < 0
diff --git a/internal/lsp/testdata/lsp/primarymod/godef/a/random.go.golden b/internal/lsp/testdata/lsp/primarymod/godef/a/random.go.golden
index 033e581cb..adba70063 100644
--- a/internal/lsp/testdata/lsp/primarymod/godef/a/random.go.golden
+++ b/internal/lsp/testdata/lsp/primarymod/godef/a/random.go.golden
@@ -88,7 +88,6 @@ var y int
godef/a/random.go:17:18-23: defined here as ```go
field field string
```
-
-- TypField-definition-json --
{
"span": {
diff --git a/internal/lsp/testdata/lsp/primarymod/signature/signature.go.golden b/internal/lsp/testdata/lsp/primarymod/signature/signature.go.golden
index 22d2a515e..387abf6dc 100644
--- a/internal/lsp/testdata/lsp/primarymod/signature/signature.go.golden
+++ b/internal/lsp/testdata/lsp/primarymod/signature/signature.go.golden
@@ -27,12 +27,18 @@ func(string, int) bool
-- make(t Type, size ...int) Type-signature --
make(t Type, size ...int) Type
+The make built-in function allocates and initializes an object of type slice, map, or chan (only).
+
-- myFunc(foo int) string-signature --
myFunc(foo int) string
-- panic(v interface{})-signature --
panic(v interface{})
+The panic built-in function stops normal execution of the current goroutine.
+
-- println(args ...Type)-signature --
println(args ...Type)
+The println built-in function formats its arguments in an implementation-specific way and writes the result to standard error.
+