提交 022d70ee 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #19338 from CyrusNajmabadi/completionInEnumInitializer

Offer enum completion inside an enum member's initializer
......@@ -16,9 +16,7 @@ public EnumAndCompletionListTagCompletionProviderTests(CSharpTestWorkspaceFixtur
}
internal override CompletionProvider CreateCompletionProvider()
{
return new EnumAndCompletionListTagCompletionProvider();
}
=> new EnumAndCompletionListTagCompletionProvider();
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task NullableEnum()
......@@ -518,5 +516,105 @@ enum E
";
await VerifyNoItemsExistAsync(markup);
}
[WorkItem(5419, "https://github.com/dotnet/roslyn/issues/5419")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestInEnumInitializer1()
{
var markup =
@"using System;
[Flags]
internal enum ProjectTreeWriterOptions
{
None,
Tags,
FilePath,
Capabilities,
Visibility,
AllProperties = FilePath | Visibility | $$
}";
await VerifyItemExistsAsync(markup, "ProjectTreeWriterOptions");
}
[WorkItem(5419, "https://github.com/dotnet/roslyn/issues/5419")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestInEnumInitializer2()
{
var markup =
@"using System;
[Flags]
internal enum ProjectTreeWriterOptions
{
None,
Tags,
FilePath,
Capabilities,
Visibility,
AllProperties = FilePath | $$ Visibility
}";
await VerifyItemExistsAsync(markup, "ProjectTreeWriterOptions");
}
[WorkItem(5419, "https://github.com/dotnet/roslyn/issues/5419")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestInEnumInitializer3()
{
var markup =
@"using System;
[Flags]
internal enum ProjectTreeWriterOptions
{
None,
Tags,
FilePath,
Capabilities,
Visibility,
AllProperties = FilePath | $$ | Visibility
}";
await VerifyItemExistsAsync(markup, "ProjectTreeWriterOptions");
}
[WorkItem(5419, "https://github.com/dotnet/roslyn/issues/5419")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestInEnumInitializer4()
{
var markup =
@"using System;
[Flags]
internal enum ProjectTreeWriterOptions
{
None,
Tags,
FilePath,
Capabilities,
Visibility,
AllProperties = FilePath ^ $$
}";
await VerifyItemExistsAsync(markup, "ProjectTreeWriterOptions");
}
[WorkItem(5419, "https://github.com/dotnet/roslyn/issues/5419")]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task TestInEnumInitializer5()
{
var markup =
@"using System;
[Flags]
internal enum ProjectTreeWriterOptions
{
None,
Tags,
FilePath,
Capabilities,
Visibility,
AllProperties = FilePath & $$
}";
await VerifyItemExistsAsync(markup, "ProjectTreeWriterOptions");
}
}
}
}
\ No newline at end of file
......@@ -91,7 +91,9 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
if (type.TypeKind != TypeKind.Enum)
{
type = GetCompletionListType(type, semanticModel.GetEnclosingNamedType(position, cancellationToken), semanticModel.Compilation);
type = TryGetEnumTypeInEnumInitializer(semanticModel, token, type, cancellationToken) ??
TryGetCompletionListType(type, semanticModel.GetEnclosingNamedType(position, cancellationToken), semanticModel.Compilation);
if (type == null)
{
return;
......@@ -104,7 +106,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
}
// Does type have any aliases?
ISymbol alias = await type.FindApplicableAlias(position, semanticModel, cancellationToken).ConfigureAwait(false);
var alias = await type.FindApplicableAlias(position, semanticModel, cancellationToken).ConfigureAwait(false);
var displayService = document.GetLanguageService<ISymbolDisplayService>();
var displayText = alias != null
......@@ -128,6 +130,47 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
}
}
private ITypeSymbol TryGetEnumTypeInEnumInitializer(
SemanticModel semanticModel, SyntaxToken token,
ITypeSymbol type, CancellationToken cancellationToken)
{
// https://github.com/dotnet/roslyn/issues/5419
//
// 14.3: "Within an enum member initializer, values of other enum members are always
// treated as having the type of their underlying type"
// i.e. if we have "enum E { X, Y, Z = X |
// then we want to offer the enum after the |. However, the compiler will report this
// as an 'int' type, not the enum type.
// See if we're after a common enum-combining operator.
if (token.Kind() == SyntaxKind.BarToken ||
token.Kind() == SyntaxKind.AmpersandToken ||
token.Kind() == SyntaxKind.CaretToken)
{
// See if the type we're looking at is the underlying type for the enum we're contained in.
var containingType = semanticModel.GetEnclosingNamedType(token.SpanStart, cancellationToken);
if (containingType?.TypeKind == TypeKind.Enum &&
type.Equals(containingType.EnumUnderlyingType))
{
// If so, walk back to the token before the operator token and see if it binds to a member
// of this enum.
var previousToken = token.GetPreviousToken();
var symbol = semanticModel.GetSymbolInfo(previousToken.Parent, cancellationToken).Symbol;
if (symbol?.Kind == SymbolKind.Field &&
containingType.Equals(symbol.ContainingType))
{
// If so, then offer this as a place for enum completion for the enum we're currently
// inside of.
return containingType;
}
}
}
return null;
}
protected override Task<CompletionDescription> GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken)
=> SymbolCompletionItem.GetDescriptionAsync(item, document, cancellationToken);
......@@ -136,7 +179,7 @@ protected override Task<CompletionDescription> GetDescriptionWorkerAsync(Documen
.WithMatchPriority(MatchPriority.Preselect)
.WithSelectionBehavior(CompletionItemSelectionBehavior.HardSelection);
private INamedTypeSymbol GetCompletionListType(ITypeSymbol type, INamedTypeSymbol within, Compilation compilation)
private INamedTypeSymbol TryGetCompletionListType(ITypeSymbol type, INamedTypeSymbol within, Compilation compilation)
{
// PERF: None of the SpecialTypes include <completionlist> tags,
// so we don't even need to load the documentation.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册