|
// 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.
#nullable disable
using System;
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.CodeGeneration;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Formatting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.ImplementInterface;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CSharp.ImplementInterface;
[ExportLanguageService(typeof(IImplementInterfaceService), LanguageNames.CSharp), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class CSharpImplementInterfaceService() : AbstractImplementInterfaceService
{
protected override ISyntaxFormatting SyntaxFormatting
=> CSharpSyntaxFormatting.Instance;
protected override SyntaxGeneratorInternal SyntaxGeneratorInternal
=> CSharpSyntaxGeneratorInternal.Instance;
protected override string ToDisplayString(IMethodSymbol disposeImplMethod, SymbolDisplayFormat format)
=> SymbolDisplay.ToDisplayString(disposeImplMethod, format);
protected override bool AllowDelegateAndEnumConstraints(ParseOptions options)
=> options.LanguageVersion() >= LanguageVersion.CSharp7_3;
protected override bool TryInitializeState(
Document document, SemanticModel model, SyntaxNode node, CancellationToken cancellationToken,
out SyntaxNode classOrStructDecl, out INamedTypeSymbol classOrStructType, out ImmutableArray<INamedTypeSymbol> interfaceTypes)
{
if (!cancellationToken.IsCancellationRequested)
{
if (node is TypeSyntax interfaceNode && interfaceNode.Parent is BaseTypeSyntax baseType &&
baseType.IsParentKind(SyntaxKind.BaseList) &&
baseType.Type == interfaceNode)
{
if (interfaceNode.Parent.Parent?.Parent.Kind() is
SyntaxKind.ClassDeclaration or
SyntaxKind.StructDeclaration or
SyntaxKind.RecordDeclaration or
SyntaxKind.RecordStructDeclaration)
{
var interfaceSymbolInfo = model.GetSymbolInfo(interfaceNode, cancellationToken);
if (interfaceSymbolInfo.CandidateReason != CandidateReason.WrongArity)
{
cancellationToken.ThrowIfCancellationRequested();
if (interfaceSymbolInfo.GetAnySymbol() is INamedTypeSymbol interfaceType && interfaceType.TypeKind == TypeKind.Interface)
{
classOrStructDecl = interfaceNode.Parent.Parent.Parent as TypeDeclarationSyntax;
classOrStructType = model.GetDeclaredSymbol(classOrStructDecl, cancellationToken) as INamedTypeSymbol;
interfaceTypes = [interfaceType];
return interfaceTypes != null && classOrStructType != null;
}
}
}
}
}
classOrStructDecl = null;
classOrStructType = null;
interfaceTypes = default;
return false;
}
protected override bool CanImplementImplicitly => true;
protected override bool HasHiddenExplicitImplementation => true;
protected override SyntaxNode AddCommentInsideIfStatement(SyntaxNode ifStatement, SyntaxTriviaList trivia)
{
return ifStatement.ReplaceToken(
ifStatement.GetLastToken(),
ifStatement.GetLastToken().WithPrependedLeadingTrivia(trivia));
}
protected override SyntaxNode CreateFinalizer(
SyntaxGenerator g, INamedTypeSymbol classType, string disposeMethodDisplayString)
{
// ' Do not change this code...
// Dispose(false)
var disposeStatement = (StatementSyntax)AddComment(
string.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, disposeMethodDisplayString),
g.ExpressionStatement(g.InvocationExpression(
g.IdentifierName(nameof(IDisposable.Dispose)),
g.Argument(DisposingName, RefKind.None, g.FalseLiteralExpression()))));
var methodDecl = SyntaxFactory.DestructorDeclaration(classType.Name).AddBodyStatements(disposeStatement);
return AddComment(
string.Format(CodeFixesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, disposeMethodDisplayString),
methodDecl);
}
}
|