|
// 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.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Completion.Providers;
internal abstract partial class AbstractOverrideCompletionProvider() : AbstractMemberInsertingCompletionProvider
{
public abstract SyntaxToken FindStartingToken(SyntaxTree tree, int position, CancellationToken cancellationToken);
public abstract ImmutableArray<ISymbol> FilterOverrides(ImmutableArray<ISymbol> members, ITypeSymbol? returnType);
public abstract bool TryDetermineModifiers(SyntaxToken startToken, SourceText text, int startLine, out Accessibility seenAccessibility, out DeclarationModifiers modifiers);
public override async Task ProvideCompletionsAsync(CompletionContext context)
{
var state = await ItemGetter.CreateAsync(this, context.Document, context.Position, context.CancellationToken).ConfigureAwait(false);
var items = await state.GetItemsAsync().ConfigureAwait(false);
if (!items.IsDefaultOrEmpty)
{
context.IsExclusive = true;
context.AddItems(items);
}
}
protected override Task<ISymbol> GenerateMemberAsync(
Document document, CompletionItem completionItem, Compilation compilation, ISymbol overriddenMember, INamedTypeSymbol containingType, CancellationToken cancellationToken)
{
// Special case: if you are overriding object.ToString(), we will make the return value as non-nullable. The
// return was made nullable because are implementations out there that will return null, but that's not
// something we really want new implementations doing. We may need to consider expanding this behavior to other
// methods in the future; if that is the case then we would want there to be an attribute on the return type
// rather than updating this list, but for now there is no such attribute until we find more cases for it. See
// https://github.com/dotnet/roslyn/issues/30317 for some additional conversation about this design decision.
//
// We don't check if methodSymbol.ContainingType is object, in case you're overriding something that is itself an override
if (overriddenMember is IMethodSymbol methodSymbol &&
methodSymbol.Name == "ToString" &&
methodSymbol.Parameters.Length == 0)
{
overriddenMember = CodeGenerationSymbolFactory.CreateMethodSymbol(methodSymbol, returnType: methodSymbol.ReturnType.WithNullableAnnotation(NullableAnnotation.NotAnnotated));
}
// Figure out what to insert, and do it. Throw if we've somehow managed to get this far and can't.
var syntaxFactory = document.GetRequiredLanguageService<SyntaxGenerator>();
var itemModifiers = MemberInsertionCompletionItem.GetModifiers(completionItem);
var modifiers = itemModifiers.WithIsUnsafe(itemModifiers.IsUnsafe | overriddenMember.RequiresUnsafeModifier());
return syntaxFactory.OverrideAsync(
overriddenMember, containingType, document, modifiers, cancellationToken);
}
public abstract bool TryDetermineReturnType(
SyntaxToken startToken,
SemanticModel semanticModel,
CancellationToken cancellationToken,
out ITypeSymbol? returnType,
out SyntaxToken nextToken);
protected static bool IsOnStartLine(int position, SourceText text, int startLine)
=> text.Lines.IndexOf(position) == startLine;
protected static ITypeSymbol GetReturnType(ISymbol symbol)
=> symbol.Kind switch
{
SymbolKind.Event => ((IEventSymbol)symbol).Type,
SymbolKind.Method => ((IMethodSymbol)symbol).ReturnType,
SymbolKind.Property => ((IPropertySymbol)symbol).Type,
_ => throw ExceptionUtilities.UnexpectedValue(symbol.Kind),
};
}
|