Skip to content

Commit b4e98e7

Browse files
committed
gopls/internal/golang: get sign over func name
Currently, signatures can only be returned within the parentheses when use lsp."textDocument/signatureHelp"; they cannot be returned on the function name. Because we prefere to use "." to trigger a code complete menu, we also need the ability to retrieve function signatures Fixes golang/go#68922
1 parent 66adacf commit b4e98e7

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

gopls/internal/golang/signature_help.go

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,23 @@ func SignatureHelp(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle
3939
if err != nil {
4040
return nil, 0, err
4141
}
42-
// Find a call expression surrounding the query position.
43-
var callExpr *ast.CallExpr
42+
// Find a call/SelectorExpr expression surrounding the query position.
43+
var callNode ast.Node
4444
path, _ := astutil.PathEnclosingInterval(pgf.File, pos, pos)
4545
if path == nil {
4646
return nil, 0, fmt.Errorf("cannot find node enclosing position")
4747
}
4848
FindCall:
4949
for _, node := range path {
5050
switch node := node.(type) {
51+
case *ast.SelectorExpr:
52+
if pos >= node.Pos() && pos <= node.End() {
53+
callNode = node
54+
break FindCall
55+
}
5156
case *ast.CallExpr:
5257
if pos >= node.Lparen && pos <= node.Rparen {
53-
callExpr = node
58+
callNode = node
5459
break FindCall
5560
}
5661
case *ast.FuncLit, *ast.FuncType:
@@ -67,23 +72,36 @@ FindCall:
6772
// you've already dismissed the help!).
6873
return nil, 0, nil
6974
}
75+
default:
7076
}
7177

7278
}
73-
if callExpr == nil || callExpr.Fun == nil {
79+
80+
if callNode == nil {
7481
return nil, 0, nil
7582
}
7683

7784
info := pkg.TypesInfo()
7885

86+
var expr ast.Expr
87+
switch node := callNode.(type) {
88+
case *ast.SelectorExpr:
89+
expr = node
90+
case *ast.CallExpr:
91+
if node.Fun == nil {
92+
return nil, 0, nil
93+
}
94+
expr = node.Fun
95+
}
96+
7997
// Get the type information for the function being called.
8098
var sig *types.Signature
81-
if tv, ok := info.Types[callExpr.Fun]; !ok {
82-
return nil, 0, fmt.Errorf("cannot get type for Fun %[1]T (%[1]v)", callExpr.Fun)
99+
if tv, ok := info.Types[expr]; !ok {
100+
return nil, 0, fmt.Errorf("cannot get type for Fun %[1]T (%[1]v)", expr)
83101
} else if tv.IsType() {
84102
return nil, 0, nil // a conversion, not a call
85103
} else if sig, ok = tv.Type.Underlying().(*types.Signature); !ok {
86-
return nil, 0, fmt.Errorf("call operand is not a func or type: %[1]T (%[1]v)", callExpr.Fun)
104+
return nil, 0, fmt.Errorf("call operand is not a func or type: %[1]T (%[1]v)", expr)
87105
}
88106
// Inv: sig != nil
89107

@@ -93,16 +111,26 @@ FindCall:
93111
// There is no object in certain cases such as calling a function returned by
94112
// a function (e.g. "foo()()").
95113
var obj types.Object
96-
switch t := callExpr.Fun.(type) {
114+
switch t := expr.(type) {
97115
case *ast.Ident:
98116
obj = info.ObjectOf(t)
99117
case *ast.SelectorExpr:
100118
obj = info.ObjectOf(t.Sel)
101119
}
120+
121+
activeParam := 0
122+
switch node := callNode.(type) {
123+
case *ast.SelectorExpr:
124+
case *ast.CallExpr:
125+
// only return activeParam when CallExpr
126+
// because we don't modify arguments when get function signature only
127+
activeParam = activeParameter(node, sig.Params().Len(), sig.Variadic(), pos)
128+
}
129+
102130
if obj != nil && isBuiltin(obj) {
103131
// function?
104132
if obj, ok := obj.(*types.Builtin); ok {
105-
return builtinSignature(ctx, snapshot, callExpr, obj.Name(), pos)
133+
return builtinSignature(ctx, snapshot, activeParam, obj.Name(), pos)
106134
}
107135

108136
// method (only error.Error)?
@@ -116,8 +144,6 @@ FindCall:
116144
return nil, 0, bug.Errorf("call to unexpected built-in %v (%T)", obj, obj)
117145
}
118146

119-
activeParam := activeParameter(callExpr, sig.Params().Len(), sig.Variadic(), pos)
120-
121147
var (
122148
name string
123149
comment *ast.CommentGroup
@@ -148,7 +174,7 @@ FindCall:
148174
}, activeParam, nil
149175
}
150176

151-
func builtinSignature(ctx context.Context, snapshot *cache.Snapshot, callExpr *ast.CallExpr, name string, pos token.Pos) (*protocol.SignatureInformation, int, error) {
177+
func builtinSignature(ctx context.Context, snapshot *cache.Snapshot, activeParam int, name string, pos token.Pos) (*protocol.SignatureInformation, int, error) {
152178
sig, err := NewBuiltinSignature(ctx, snapshot, name)
153179
if err != nil {
154180
return nil, 0, err
@@ -157,7 +183,7 @@ func builtinSignature(ctx context.Context, snapshot *cache.Snapshot, callExpr *a
157183
for _, p := range sig.params {
158184
paramInfo = append(paramInfo, protocol.ParameterInformation{Label: p})
159185
}
160-
activeParam := activeParameter(callExpr, len(sig.params), sig.variadic, pos)
186+
161187
return &protocol.SignatureInformation{
162188
Label: sig.name + sig.Format(),
163189
Documentation: stringToSigInfoDocumentation(sig.doc, snapshot.Options()),

gopls/internal/test/integration/misc/signature_help_test.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ go 1.18
2121
-- a/a/a.go --
2222
package a
2323
24+
func GoSomething(int) {}
2425
func DoSomething(int) {}
2526
2627
func _() {
@@ -40,6 +41,7 @@ import "a.com/a"
4041
4142
func _() {
4243
a.DoSomething()
44+
a.DoSomething.
4345
}
4446
`
4547

@@ -48,8 +50,8 @@ func _() {
4850
).Run(t, files, func(t *testing.T, env *Env) {
4951
env.OpenFile("a/a/a.go")
5052
env.OpenFile("b/b/b.go")
51-
signatureHelp := func(filename string) *protocol.SignatureHelp {
52-
loc := env.RegexpSearch(filename, `DoSomething\(()\)`)
53+
signatureHelp := func(filename, posRegex string) *protocol.SignatureHelp {
54+
loc := env.RegexpSearch(filename, posRegex)
5355
var params protocol.SignatureHelpParams
5456
params.TextDocument.URI = loc.URI
5557
params.Position = loc.Range.Start
@@ -59,11 +61,15 @@ func _() {
5961
}
6062
return help
6163
}
62-
ahelp := signatureHelp("a/a/a.go")
63-
bhelp := signatureHelp("b/b/b.go")
64+
ahelp := signatureHelp("a/a/a.go", `DoSomething\(()\)`)
65+
bhelp := signatureHelp("b/b/b.go", `DoSomething\(()\)`)
6466

6567
if diff := cmp.Diff(ahelp, bhelp); diff != "" {
6668
t.Fatal(diff)
6769
}
70+
chelp := signatureHelp("b/b/b.go", `DoSomethin()g\.`)
71+
if diff := cmp.Diff(ahelp, chelp); diff != "" {
72+
t.Fatal(diff)
73+
}
6874
})
6975
}

0 commit comments

Comments
 (0)