Skip to content

Commit 8be1649

Browse files
Support name completion on generic types (#76170)
Fixes #63943
2 parents 490be18 + f7440e0 commit 8be1649

File tree

2 files changed

+48
-18
lines changed

2 files changed

+48
-18
lines changed

src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionSe
2222
using static SymbolSpecification;
2323

2424
[Trait(Traits.Feature, Traits.Features.Completion)]
25-
public class DeclarationNameCompletionProviderTests : AbstractCSharpCompletionProviderTests
25+
public sealed class DeclarationNameCompletionProviderTests : AbstractCSharpCompletionProviderTests
2626
{
2727
private const string Span = """
2828
namespace System
@@ -337,13 +337,13 @@ internal override Type GetCompletionProviderType()
337337
[InlineData("record struct")]
338338
public async Task TreatRecordPositionalParameterAsProperty(string record)
339339
{
340-
var markup = $@"
341-
public class MyClass
342-
{{
343-
}}
340+
var markup = $$"""
341+
public class MyClass
342+
{
343+
}
344344
345-
public {record} R(MyClass $$
346-
";
345+
public {{record}} R(MyClass $$
346+
""";
347347
await VerifyItemExistsAsync(markup, "MyClass", glyph: (int)Glyph.PropertyPublic);
348348
}
349349

@@ -352,13 +352,13 @@ public class MyClass
352352
[InlineData("struct")]
353353
public async Task DoNotTreatPrimaryConstructorParameterAsProperty(string record)
354354
{
355-
var markup = $@"
356-
public class MyClass
357-
{{
358-
}}
355+
var markup = $$"""
356+
public class MyClass
357+
{
358+
}
359359
360-
public {record} R(MyClass $$
361-
";
360+
public {{record}} R(MyClass $$
361+
""";
362362
await VerifyItemIsAbsentAsync(markup, "MyClass");
363363
}
364364

@@ -2916,6 +2916,25 @@ void M(IEnumerable<Customer> $$)
29162916
await VerifyItemExistsAsync(markup, "customers");
29172917
}
29182918

2919+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/63943")]
2920+
public async Task InferOffOfGenericNameInPattern()
2921+
{
2922+
var markup = """
2923+
using System.Collections.Generic;
2924+
2925+
class Customer { }
2926+
2927+
class V
2928+
{
2929+
void M(object o)
2930+
{
2931+
if (o is List<Customer> $$
2932+
}
2933+
}
2934+
""";
2935+
await VerifyItemExistsAsync(markup, "customers");
2936+
}
2937+
29192938
private static NamingStylePreferences MultipleCamelCaseLocalRules()
29202939
{
29212940
var styles = new[]

src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationName/DeclarationNameInfo.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -461,11 +461,22 @@ private static bool IsParameterDeclaration(SyntaxToken token, SemanticModel sema
461461
return result.Type != null;
462462
}
463463

464-
private static bool IsPatternMatching(SyntaxToken token, SemanticModel semanticModel,
465-
CancellationToken cancellationToken, out NameDeclarationInfo result)
464+
private static bool IsPatternMatching(
465+
SyntaxToken token,
466+
SemanticModel semanticModel,
467+
CancellationToken cancellationToken,
468+
out NameDeclarationInfo result)
466469
{
467470
result = default;
468-
if (token.Parent.IsParentKind(SyntaxKind.IsExpression))
471+
472+
var parent = token.Parent;
473+
if (token.Kind() is SyntaxKind.GreaterThanToken &&
474+
parent is TypeArgumentListSyntax { Parent: GenericNameSyntax genericName })
475+
{
476+
parent = genericName;
477+
}
478+
479+
if (parent.IsParentKind(SyntaxKind.IsExpression))
469480
{
470481
result = IsLastTokenOfType<BinaryExpressionSyntax>(
471482
token, semanticModel,
@@ -474,7 +485,7 @@ private static bool IsPatternMatching(SyntaxToken token, SemanticModel semanticM
474485
_ => s_parameterSyntaxKind,
475486
cancellationToken);
476487
}
477-
else if (token.Parent.IsParentKind(SyntaxKind.CaseSwitchLabel))
488+
else if (parent.IsParentKind(SyntaxKind.CaseSwitchLabel))
478489
{
479490
result = IsLastTokenOfType<CaseSwitchLabelSyntax>(
480491
token, semanticModel,
@@ -483,7 +494,7 @@ private static bool IsPatternMatching(SyntaxToken token, SemanticModel semanticM
483494
_ => s_parameterSyntaxKind,
484495
cancellationToken);
485496
}
486-
else if (token.Parent.IsParentKind(SyntaxKind.DeclarationPattern))
497+
else if (parent.IsParentKind(SyntaxKind.DeclarationPattern))
487498
{
488499
result = IsLastTokenOfType<DeclarationPatternSyntax>(
489500
token, semanticModel,

0 commit comments

Comments
 (0)