Skip to content

Commit 31c7de9

Browse files
authored
Ensure LSP uses actual signature help trigger characters (dotnet#78076)
Resolves dotnet/vscode-csharp#8154
2 parents 587c8aa + 7fa7591 commit 31c7de9

File tree

39 files changed

+296
-208
lines changed

39 files changed

+296
-208
lines changed

src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ private async Task<Model> ComputeModelInBackgroundAsync(
7575
}
7676

7777
if (triggerInfo.TriggerCharacter.HasValue &&
78-
!currentModel.Provider.IsRetriggerCharacter(triggerInfo.TriggerCharacter.Value))
78+
!currentModel.Provider.RetriggerCharacters.Contains(triggerInfo.TriggerCharacter.Value))
7979
{
8080
return currentModel;
8181
}

src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_TypeChar.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ void IChainedCommandHandler<TypeCharCommandArgs>.ExecuteCommand(TypeCharCommandA
100100
else
101101
{
102102
var computed = false;
103-
if (allProviders.Any(static (p, args) => p.IsRetriggerCharacter(args.TypedChar), args))
103+
if (allProviders.Any(static (p, args) => p.RetriggerCharacters.Contains(args.TypedChar), args))
104104
{
105105
// The user typed a character that might close the scope of the current model.
106106
// In this case, we should requery all providers.
@@ -138,7 +138,7 @@ void IChainedCommandHandler<TypeCharCommandArgs>.ExecuteCommand(TypeCharCommandA
138138
using var unmatchedProvidersDisposer = ArrayBuilder<ISignatureHelpProvider>.GetInstance(out var unmatchedProviders);
139139
foreach (var provider in providers)
140140
{
141-
if (provider.IsTriggerCharacter(ch))
141+
if (provider.TriggerCharacters.Contains(ch))
142142
{
143143
matchedProviders.Add(provider);
144144
}

src/EditorFeatures/Test2/IntelliSense/SignatureHelpControllerTests.vb

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
' The .NET Foundation licenses this file to you under the MIT license.
33
' See the LICENSE file in the project root for more information.
44

5+
Imports System.Collections.Immutable
56
Imports System.Runtime.CompilerServices
67
Imports System.Threading
78
Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense
@@ -60,8 +61,8 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
6061

6162
' Create a provider that will return an empty state when queried the second time
6263
Dim slowProvider = New Mock(Of ISignatureHelpProvider)(MockBehavior.Strict)
63-
slowProvider.Setup(Function(p) p.IsTriggerCharacter(" "c)).Returns(True)
64-
slowProvider.Setup(Function(p) p.IsRetriggerCharacter(" "c)).Returns(True)
64+
slowProvider.Setup(Function(p) p.TriggerCharacters).Returns(ImmutableArray.Create(Of Char)(" "c))
65+
slowProvider.Setup(Function(p) p.RetriggerCharacters).Returns(ImmutableArray.Create(Of Char)(" "c))
6566
slowProvider.Setup(Function(p) p.GetItemsAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of SignatureHelpTriggerInfo), options, It.IsAny(Of CancellationToken))) _
6667
.Returns(Task.FromResult(New SignatureHelpItems(CreateItems(2), TextSpan.FromBounds(0, 0), selectedItem:=0, semanticParameterIndex:=0, syntacticArgumentCount:=0, argumentName:=Nothing)))
6768
Dim controller = Await CreateController(CreateWorkspace(), provider:=slowProvider.Object, waitForPresentation:=True)
@@ -214,13 +215,17 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
214215
Nothing))
215216
End Function
216217

217-
Public Function IsTriggerCharacter(ch As Char) As Boolean Implements ISignatureHelpProvider.IsTriggerCharacter
218-
Return ch = "("c
219-
End Function
220-
221-
Public Function IsRetriggerCharacter(ch As Char) As Boolean Implements ISignatureHelpProvider.IsRetriggerCharacter
222-
Return ch = ")"c
223-
End Function
218+
Public ReadOnly Property TriggerCharacters As ImmutableArray(Of Char) Implements ISignatureHelpProvider.TriggerCharacters
219+
Get
220+
Return ImmutableArray.Create("("c)
221+
End Get
222+
End Property
223+
224+
Public ReadOnly Property RetriggerCharacters As ImmutableArray(Of Char) Implements ISignatureHelpProvider.RetriggerCharacters
225+
Get
226+
Return ImmutableArray.Create(")"c)
227+
End Get
228+
End Property
224229
End Class
225230

226231
Private Shared Function CreateMockTextView(buffer As ITextBuffer) As Mock(Of ITextView)

src/EditorFeatures/TestUtilities/SignatureHelp/AbstractSignatureHelpProviderTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,12 @@ protected void VerifyTriggerCharacters(char[] expectedTriggerCharacters, char[]
131131

132132
foreach (var expectedTriggerCharacter in expectedTriggerCharacters)
133133
{
134-
Assert.True(signatureHelpProvider.IsTriggerCharacter(expectedTriggerCharacter), "Expected '" + expectedTriggerCharacter + "' to be a trigger character");
134+
Assert.True(signatureHelpProvider.TriggerCharacters.Contains(expectedTriggerCharacter), "Expected '" + expectedTriggerCharacter + "' to be a trigger character");
135135
}
136136

137137
foreach (var unexpectedTriggerCharacter in unexpectedTriggerCharacters)
138138
{
139-
Assert.False(signatureHelpProvider.IsTriggerCharacter(unexpectedTriggerCharacter), "Expected '" + unexpectedTriggerCharacter + "' to NOT be a trigger character");
139+
Assert.False(signatureHelpProvider.TriggerCharacters.Contains(unexpectedTriggerCharacter), "Expected '" + unexpectedTriggerCharacter + "' to NOT be a trigger character");
140140
}
141141
}
142142

@@ -389,7 +389,7 @@ private async Task TestSignatureHelpWorkerSharedAsync(
389389
SignatureHelpTriggerReason.TypeCharCommand,
390390
code.ElementAt(cursorPosition - 1));
391391

392-
if (!signatureHelpProvider.IsTriggerCharacter(triggerInfo.TriggerCharacter.Value))
392+
if (!signatureHelpProvider.TriggerCharacters.Contains(triggerInfo.TriggerCharacter.Value))
393393
{
394394
return;
395395
}

src/Features/CSharp/Portable/SignatureHelp/AttributeSignatureHelpProvider.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66
using System.Collections.Generic;
7+
using System.Collections.Immutable;
78
using System.Composition;
89
using System.Diagnostics.CodeAnalysis;
910
using System.Linq;
@@ -31,11 +32,9 @@ public AttributeSignatureHelpProvider()
3132
{
3233
}
3334

34-
public override bool IsTriggerCharacter(char ch)
35-
=> ch is '(' or ',';
35+
public override ImmutableArray<char> TriggerCharacters => ['(', ','];
3636

37-
public override bool IsRetriggerCharacter(char ch)
38-
=> ch == ')';
37+
public override ImmutableArray<char> RetriggerCharacters => [')'];
3938

4039
private bool TryGetAttributeExpression(
4140
SyntaxNode root,
@@ -58,7 +57,7 @@ private bool IsTriggerToken(SyntaxToken token)
5857
{
5958
return !token.IsKind(SyntaxKind.None) &&
6059
token.ValueText.Length == 1 &&
61-
IsTriggerCharacter(token.ValueText[0]) &&
60+
TriggerCharacters.Contains(token.ValueText[0]) &&
6261
token.Parent is AttributeArgumentListSyntax &&
6362
token.Parent.Parent is AttributeSyntax;
6463
}

src/Features/CSharp/Portable/SignatureHelp/ConstructorInitializerSignatureHelpProvider.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66
using System.Collections.Generic;
7+
using System.Collections.Immutable;
78
using System.Composition;
89
using System.Linq;
910
using System.Threading;
@@ -29,11 +30,9 @@ public ConstructorInitializerSignatureHelpProvider()
2930
{
3031
}
3132

32-
public override bool IsTriggerCharacter(char ch)
33-
=> ch is '(' or ',';
33+
public override ImmutableArray<char> TriggerCharacters => ['(', ','];
3434

35-
public override bool IsRetriggerCharacter(char ch)
36-
=> ch == ')';
35+
public override ImmutableArray<char> RetriggerCharacters => [')'];
3736

3837
private async Task<ConstructorInitializerSyntax?> TryGetConstructorInitializerAsync(
3938
Document document,
@@ -57,7 +56,7 @@ public override bool IsRetriggerCharacter(char ch)
5756
}
5857

5958
private bool IsTriggerToken(SyntaxToken token)
60-
=> SignatureHelpUtilities.IsTriggerParenOrComma<ConstructorInitializerSyntax>(token, IsTriggerCharacter);
59+
=> SignatureHelpUtilities.IsTriggerParenOrComma<ConstructorInitializerSyntax>(token, TriggerCharacters);
6160

6261
private static bool IsArgumentListToken(ConstructorInitializerSyntax expression, SyntaxToken token)
6362
{

src/Features/CSharp/Portable/SignatureHelp/ElementAccessExpressionSignatureHelpProvider.cs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,17 @@ namespace Microsoft.CodeAnalysis.CSharp.SignatureHelp;
2828
[ExportSignatureHelpProvider("ElementAccessExpressionSignatureHelpProvider", LanguageNames.CSharp), Shared]
2929
internal sealed class ElementAccessExpressionSignatureHelpProvider : AbstractCSharpSignatureHelpProvider
3030
{
31+
private static readonly ImmutableArray<char> s_triggerCharacters = ['[', ','];
32+
3133
[ImportingConstructor]
3234
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
3335
public ElementAccessExpressionSignatureHelpProvider()
3436
{
3537
}
3638

37-
public override bool IsTriggerCharacter(char ch)
38-
=> IsTriggerCharacterInternal(ch);
39-
40-
private static bool IsTriggerCharacterInternal(char ch)
41-
=> ch is '[' or ',';
39+
public override ImmutableArray<char> TriggerCharacters => s_triggerCharacters;
4240

43-
public override bool IsRetriggerCharacter(char ch)
44-
=> ch == ']';
41+
public override ImmutableArray<char> RetriggerCharacters => [']'];
4542

4643
private static bool TryGetElementAccessExpression(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, SignatureHelpTriggerReason triggerReason, CancellationToken cancellationToken, [NotNullWhen(true)] out ExpressionSyntax? identifier, out SyntaxToken openBrace)
4744
{
@@ -281,7 +278,7 @@ internal static bool IsTriggerToken(SyntaxToken token)
281278
{
282279
return !token.IsKind(SyntaxKind.None) &&
283280
token.ValueText.Length == 1 &&
284-
IsTriggerCharacterInternal(token.ValueText[0]) &&
281+
s_triggerCharacters.Contains(token.ValueText[0]) &&
285282
token.Parent is BracketedArgumentListSyntax &&
286283
token.Parent.Parent is ElementAccessExpressionSyntax;
287284
}
@@ -330,7 +327,7 @@ internal static bool IsTriggerToken(SyntaxToken token)
330327
{
331328
return !token.IsKind(SyntaxKind.None) &&
332329
token.ValueText.Length == 1 &&
333-
IsTriggerCharacterInternal(token.ValueText[0]) &&
330+
s_triggerCharacters.Contains(token.ValueText[0]) &&
334331
token.Parent is ArrayRankSpecifierSyntax;
335332
}
336333

@@ -365,7 +362,7 @@ internal static bool IsTriggerToken(SyntaxToken token)
365362
{
366363
return !token.IsKind(SyntaxKind.None) &&
367364
token.ValueText.Length == 1 &&
368-
IsTriggerCharacterInternal(token.ValueText[0]) &&
365+
s_triggerCharacters.Contains(token.ValueText[0]) &&
369366
token.Parent is BracketedArgumentListSyntax &&
370367
token.Parent.Parent is ElementBindingExpressionSyntax &&
371368
token.Parent.Parent.Parent is ConditionalAccessExpressionSyntax;

src/Features/CSharp/Portable/SignatureHelp/GenericNameSignatureHelpProvider.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66
using System.Collections.Generic;
7+
using System.Collections.Immutable;
78
using System.Composition;
89
using System.Linq;
910
using System.Threading;
@@ -31,11 +32,9 @@ public GenericNameSignatureHelpProvider()
3132
{
3233
}
3334

34-
public override bool IsTriggerCharacter(char ch)
35-
=> ch is '<' or ',';
35+
public override ImmutableArray<char> TriggerCharacters => ['<', ','];
3636

37-
public override bool IsRetriggerCharacter(char ch)
38-
=> ch == '>';
37+
public override ImmutableArray<char> RetriggerCharacters => ['>'];
3938

4039
protected virtual bool TryGetGenericIdentifier(
4140
SyntaxNode root, int position,
@@ -62,7 +61,7 @@ private bool IsTriggerToken(SyntaxToken token)
6261
{
6362
return !token.IsKind(SyntaxKind.None) &&
6463
token.ValueText.Length == 1 &&
65-
IsTriggerCharacter(token.ValueText[0]) &&
64+
TriggerCharacters.Contains(token.ValueText[0]) &&
6665
token.Parent is TypeArgumentListSyntax &&
6766
token.Parent.Parent is GenericNameSyntax;
6867
}

src/Features/CSharp/Portable/SignatureHelp/InitializerExpressionSignatureHelpProvider.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Collections.Immutable;
67
using System.Composition;
78
using System.Diagnostics.CodeAnalysis;
89
using System.Linq;
@@ -26,11 +27,9 @@ public InitializerExpressionSignatureHelpProvider()
2627
{
2728
}
2829

29-
public override bool IsTriggerCharacter(char ch)
30-
=> ch is '{' or ',';
30+
public override ImmutableArray<char> TriggerCharacters => ['{', ','];
3131

32-
public override bool IsRetriggerCharacter(char ch)
33-
=> ch == '}';
32+
public override ImmutableArray<char> RetriggerCharacters => ['}'];
3433

3534
private bool TryGetInitializerExpression(
3635
SyntaxNode root,
@@ -47,7 +46,7 @@ private bool TryGetInitializerExpression(
4746
private bool IsTriggerToken(SyntaxToken token)
4847
=> !token.IsKind(SyntaxKind.None) &&
4948
token.ValueText.Length == 1 &&
50-
IsTriggerCharacter(token.ValueText[0]) &&
49+
TriggerCharacters.Contains(token.ValueText[0]) &&
5150
token.Parent is InitializerExpressionSyntax;
5251

5352
private static bool IsInitializerExpressionToken(InitializerExpressionSyntax expression, SyntaxToken token)

src/Features/CSharp/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,9 @@ public InvocationExpressionSignatureHelpProvider()
3030

3131
internal partial class InvocationExpressionSignatureHelpProviderBase : AbstractOrdinaryMethodSignatureHelpProvider
3232
{
33-
public override bool IsTriggerCharacter(char ch)
34-
=> ch is '(' or ',';
33+
public override ImmutableArray<char> TriggerCharacters => ['(', ','];
3534

36-
public override bool IsRetriggerCharacter(char ch)
37-
=> ch == ')';
35+
public override ImmutableArray<char> RetriggerCharacters => [')'];
3836

3937
private async Task<InvocationExpressionSyntax?> TryGetInvocationExpressionAsync(Document document, int position, SignatureHelpTriggerReason triggerReason, CancellationToken cancellationToken)
4038
{
@@ -54,7 +52,7 @@ public override bool IsRetriggerCharacter(char ch)
5452
}
5553

5654
private bool IsTriggerToken(SyntaxToken token)
57-
=> SignatureHelpUtilities.IsTriggerParenOrComma<InvocationExpressionSyntax>(token, IsTriggerCharacter);
55+
=> SignatureHelpUtilities.IsTriggerParenOrComma<InvocationExpressionSyntax>(token, TriggerCharacters);
5856

5957
private static bool IsArgumentListToken(InvocationExpressionSyntax expression, SyntaxToken token)
6058
{

0 commit comments

Comments
 (0)