| File: Completion\CompletionProviders\PartialTypeCompletionProvider.cs | Web Access |
| Project: src\roslyn\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.Features) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers; [ExportCompletionProvider(nameof(PartialTypeCompletionProvider), LanguageNames.CSharp)] [ExtensionOrder(After = nameof(PartialMethodCompletionProvider))] [Shared] internal sealed partial class PartialTypeCompletionProvider : AbstractPartialTypeCompletionProvider<CSharpSyntaxContext> { private const string InsertionTextOnLessThan = nameof(InsertionTextOnLessThan); private static readonly SymbolDisplayFormat _symbolFormatWithGenerics = new(globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeVariance, miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | SymbolDisplayMiscellaneousOptions.UseSpecialTypes); [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public PartialTypeCompletionProvider() { } internal override string Language => LanguageNames.CSharp; public override bool IsInsertionTrigger(SourceText text, int characterPosition, CompletionOptions options) => text[characterPosition] == ' ' || options.TriggerOnTypingLetters && CompletionUtilities.IsStartingNewWord(text, characterPosition); public override ImmutableHashSet<char> TriggerCharacters { get; } = CompletionUtilities.SpaceTriggerCharacter; protected override SyntaxNode? GetPartialTypeSyntaxNode(SyntaxTree tree, int position, CancellationToken cancellationToken) => tree.IsPartialTypeDeclarationNameContext(position, cancellationToken, out var declaration) ? declaration : null; protected override (string displayText, string suffix, string insertionText) GetDisplayAndSuffixAndInsertionText(INamedTypeSymbol symbol, CSharpSyntaxContext context) { var displayAndInsertionText = symbol.ToMinimalDisplayString(context.SemanticModel, context.Position, _symbolFormatWithGenerics); return (displayAndInsertionText, "", displayAndInsertionText); } protected override IEnumerable<INamedTypeSymbol>? LookupCandidateSymbols(CSharpSyntaxContext context, INamedTypeSymbol declaredSymbol, CancellationToken cancellationToken) { var candidates = base.LookupCandidateSymbols(context, declaredSymbol, cancellationToken); // The base class applies a broad filter when finding candidates, but since C# requires // that all parts have the "partial" modifier, the results can be trimmed further here. return candidates?.Where(symbol => symbol.DeclaringSyntaxReferences.Any(static (reference, cancellationToken) => IsPartialTypeDeclaration(reference.GetSyntax(cancellationToken)), cancellationToken)); } private static bool IsPartialTypeDeclaration(SyntaxNode syntax) => syntax is BaseTypeDeclarationSyntax declarationSyntax && declarationSyntax.Modifiers.Any(SyntaxKind.PartialKeyword); protected override ImmutableArray<KeyValuePair<string, string>> GetProperties(INamedTypeSymbol symbol, CSharpSyntaxContext context) => [KeyValuePair.Create(InsertionTextOnLessThan, symbol.Name.EscapeIdentifier())]; public override async Task<TextChange?> GetTextChangeAsync( Document document, CompletionItem selectedItem, char? ch, CancellationToken cancellationToken) { if (ch == '<') { if (selectedItem.TryGetProperty(InsertionTextOnLessThan, out var insertionText)) { return new TextChange(selectedItem.Span, insertionText); } } return await base.GetTextChangeAsync(document, selectedItem, ch, cancellationToken).ConfigureAwait(false); } }