internal/lsp: hide signature help in function literals
Often anonymous functions can be passed as arguments to a function. In these cases, it can be annoying for a user to see signature help for the entire duration of their writing this function. This change detects if the user is typing in a function literal and disables signature help in that case. Fixes golang/go#31633 Change-Id: I7166910739b6e1ec0da2ec852336136b81d13be0 Reviewed-on: https://go-review.googlesource.com/c/tools/+/184260 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Suzy Mueller <suzmue@golang.org>
This commit is contained in:
parent
f80f67146e
commit
7e72c71c50
|
@ -681,16 +681,25 @@ func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
||||||
Position: loc.Range.Start,
|
Position: loc.Range.Start,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
// Only fail if we got an error we did not expect.
|
||||||
|
if expectedSignatures != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if expectedSignatures == nil {
|
||||||
|
if gotSignatures != nil {
|
||||||
|
t.Errorf("expected no signature, got %v", gotSignatures)
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff := diffSignatures(spn, expectedSignatures, gotSignatures); diff != "" {
|
if diff := diffSignatures(spn, expectedSignatures, gotSignatures); diff != "" {
|
||||||
t.Error(diff)
|
t.Error(diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func diffSignatures(spn span.Span, want source.SignatureInformation, got *protocol.SignatureHelp) string {
|
func diffSignatures(spn span.Span, want *source.SignatureInformation, got *protocol.SignatureHelp) string {
|
||||||
decorate := func(f string, args ...interface{}) string {
|
decorate := func(f string, args ...interface{}) string {
|
||||||
return fmt.Sprintf("Invalid signature at %s: %s", spn, fmt.Sprintf(f, args...))
|
return fmt.Sprintf("Invalid signature at %s: %s", spn, fmt.Sprintf(f, args...))
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,19 @@ func SignatureHelp(ctx context.Context, f GoFile, pos token.Pos) (*SignatureInfo
|
||||||
if path == nil {
|
if path == nil {
|
||||||
return nil, fmt.Errorf("cannot find node enclosing position")
|
return nil, fmt.Errorf("cannot find node enclosing position")
|
||||||
}
|
}
|
||||||
|
FindCall:
|
||||||
for _, node := range path {
|
for _, node := range path {
|
||||||
if c, ok := node.(*ast.CallExpr); ok && pos >= c.Lparen && pos <= c.Rparen {
|
switch node := node.(type) {
|
||||||
callExpr = c
|
case *ast.CallExpr:
|
||||||
break
|
if pos >= node.Lparen && pos <= node.Rparen {
|
||||||
|
callExpr = node
|
||||||
|
break FindCall
|
||||||
|
}
|
||||||
|
case *ast.FuncLit, *ast.FuncType:
|
||||||
|
// The user is within an anonymous function,
|
||||||
|
// which may be the parameter to the *ast.CallExpr.
|
||||||
|
// Don't show signature help in this case.
|
||||||
|
return nil, fmt.Errorf("no signature help within a function declaration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if callExpr == nil || callExpr.Fun == nil {
|
if callExpr == nil || callExpr.Fun == nil {
|
||||||
|
|
|
@ -615,7 +615,7 @@ func summarizeSymbols(i int, want []source.Symbol, got []source.Symbol, reason s
|
||||||
|
|
||||||
func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
for spn, expectedSignatures := range data {
|
for spn, expectedSignature := range data {
|
||||||
f, err := r.view.GetFile(ctx, spn.URI())
|
f, err := r.view.GetFile(ctx, spn.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", spn, err)
|
t.Fatalf("failed for %v: %v", spn, err)
|
||||||
|
@ -624,27 +624,33 @@ func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
||||||
pos := tok.Pos(spn.Start().Offset())
|
pos := tok.Pos(spn.Start().Offset())
|
||||||
gotSignature, err := source.SignatureHelp(ctx, f.(source.GoFile), pos)
|
gotSignature, err := source.SignatureHelp(ctx, f.(source.GoFile), pos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed for %v: %v", spn, err)
|
// Only fail if we got an error we did not expect.
|
||||||
|
if expectedSignature != nil {
|
||||||
|
t.Fatalf("failed for %v: %v", spn, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if diff := diffSignatures(spn, expectedSignatures, *gotSignature); diff != "" {
|
if expectedSignature == nil {
|
||||||
|
if gotSignature != nil {
|
||||||
|
t.Errorf("expected no signature, got %v", gotSignature)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if diff := diffSignatures(spn, expectedSignature, gotSignature); diff != "" {
|
||||||
t.Error(diff)
|
t.Error(diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func diffSignatures(spn span.Span, want source.SignatureInformation, got source.SignatureInformation) string {
|
func diffSignatures(spn span.Span, want *source.SignatureInformation, got *source.SignatureInformation) string {
|
||||||
decorate := func(f string, args ...interface{}) string {
|
decorate := func(f string, args ...interface{}) string {
|
||||||
return fmt.Sprintf("Invalid signature at %s: %s", spn, fmt.Sprintf(f, args...))
|
return fmt.Sprintf("Invalid signature at %s: %s", spn, fmt.Sprintf(f, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
if want.ActiveParameter != got.ActiveParameter {
|
if want.ActiveParameter != got.ActiveParameter {
|
||||||
return decorate("wanted active parameter of %d, got %f", want.ActiveParameter, got.ActiveParameter)
|
return decorate("wanted active parameter of %d, got %f", want.ActiveParameter, got.ActiveParameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
if want.Label != got.Label {
|
if want.Label != got.Label {
|
||||||
return decorate("wanted label %q, got %q", want.Label, got.Label)
|
return decorate("wanted label %q, got %q", want.Label, got.Label)
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramParts []string
|
var paramParts []string
|
||||||
for _, p := range got.Parameters {
|
for _, p := range got.Parameters {
|
||||||
paramParts = append(paramParts, p.Label)
|
paramParts = append(paramParts, p.Label)
|
||||||
|
@ -653,10 +659,9 @@ func diffSignatures(spn span.Span, want source.SignatureInformation, got source.
|
||||||
if !strings.Contains(got.Label, paramsStr) {
|
if !strings.Contains(got.Label, paramsStr) {
|
||||||
return decorate("expected signature %q to contain params %q", got.Label, paramsStr)
|
return decorate("expected signature %q to contain params %q", got.Label, paramsStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Link(t *testing.T, data tests.Links) {
|
func (r *runner) Link(t *testing.T, data tests.Links) {
|
||||||
//This is a pure LSP feature, no source level functionality to be tested
|
// This is a pure LSP feature, no source level functionality to be tested.
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,4 +60,11 @@ func Qux() {
|
||||||
|
|
||||||
panic("oops!") //@signature("oops", "panic(v interface{})", 0)
|
panic("oops!") //@signature("oops", "panic(v interface{})", 0)
|
||||||
println("hello", "world") //@signature("world", "println(args ...Type)", 0)
|
println("hello", "world") //@signature("world", "println(args ...Type)", 0)
|
||||||
|
|
||||||
|
Hello(func() {
|
||||||
|
//@signature("//", "", 0)
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Hello(func()) {}
|
||||||
|
|
|
@ -36,7 +36,7 @@ const (
|
||||||
ExpectedReferencesCount = 4
|
ExpectedReferencesCount = 4
|
||||||
ExpectedRenamesCount = 11
|
ExpectedRenamesCount = 11
|
||||||
ExpectedSymbolsCount = 1
|
ExpectedSymbolsCount = 1
|
||||||
ExpectedSignaturesCount = 20
|
ExpectedSignaturesCount = 21
|
||||||
ExpectedLinksCount = 2
|
ExpectedLinksCount = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ type References map[span.Span][]span.Span
|
||||||
type Renames map[span.Span]string
|
type Renames map[span.Span]string
|
||||||
type Symbols map[span.URI][]source.Symbol
|
type Symbols map[span.URI][]source.Symbol
|
||||||
type SymbolsChildren map[string][]source.Symbol
|
type SymbolsChildren map[string][]source.Symbol
|
||||||
type Signatures map[span.Span]source.SignatureInformation
|
type Signatures map[span.Span]*source.SignatureInformation
|
||||||
type Links map[span.URI][]Link
|
type Links map[span.URI][]Link
|
||||||
|
|
||||||
type Data struct {
|
type Data struct {
|
||||||
|
@ -505,10 +505,14 @@ func (data *Data) collectSymbols(name string, spn span.Span, kind string, parent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (data *Data) collectSignatures(spn span.Span, signature string, activeParam int64) {
|
func (data *Data) collectSignatures(spn span.Span, signature string, activeParam int64) {
|
||||||
data.Signatures[spn] = source.SignatureInformation{
|
data.Signatures[spn] = &source.SignatureInformation{
|
||||||
Label: signature,
|
Label: signature,
|
||||||
ActiveParameter: int(activeParam),
|
ActiveParameter: int(activeParam),
|
||||||
}
|
}
|
||||||
|
// Hardcode special case to test the lack of a signature.
|
||||||
|
if signature == "" && activeParam == 0 {
|
||||||
|
data.Signatures[spn] = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (data *Data) collectCompletionSnippets(spn span.Span, item token.Pos, plain, placeholder string) {
|
func (data *Data) collectCompletionSnippets(spn span.Span, item token.Pos, plain, placeholder string) {
|
||||||
|
|
Loading…
Reference in New Issue