|
// 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(ISymbol newOverriddenMember, INamedTypeSymbol newContainingType, Document newDocument, CompletionItem completionItem, 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 (newOverriddenMember is IMethodSymbol methodSymbol &&
methodSymbol.Name == "ToString" &&
methodSymbol.Parameters.Length == 0)
{
newOverriddenMember = 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 = newDocument.GetRequiredLanguageService<SyntaxGenerator>();
var itemModifiers = MemberInsertionCompletionItem.GetModifiers(completionItem);
var modifiers = itemModifiers.WithIsUnsafe(itemModifiers.IsUnsafe | newOverriddenMember.RequiresUnsafeModifier());
return syntaxFactory.OverrideAsync(
newOverriddenMember, newContainingType, newDocument, 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),
};
}
|