From f94b82c52b208bb3b84503522e5b42dc5c3b69bc Mon Sep 17 00:00:00 2001 From: tpodolak Date: Fri, 9 Sep 2022 16:02:59 +0200 Subject: [PATCH] GH-153 - null checks for SyncOverAsyncThrowsCodeFixProvider --- ...tractSyncOverAsyncThrowsCodeFixProvider.cs | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs index 2e3e1df7..25c83925 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSyncOverAsyncThrowsCodeFixProvider.cs @@ -38,25 +38,29 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - if (root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is not { } invocation) + if (root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) is not { } invocationExpression) { return; } var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); - var methodSymbol = (IMethodSymbol)semanticModel.GetSymbolInfo(invocation).Symbol; + if (semanticModel.GetOperation(invocationExpression) is not IInvocationOperation invocationOperation) + { + return; + } + var supportsThrowsAsync = SupportsThrowsAsync(semanticModel.Compilation); - if (!supportsThrowsAsync && methodSymbol.Parameters.Any(param => param.Type.IsCallInfoDelegate(semanticModel.Compilation))) + if (!supportsThrowsAsync && invocationOperation.TargetMethod.Parameters.Any(param => param.Type.IsCallInfoDelegate(semanticModel.Compilation))) { return; } - var replacementMethod = GetReplacementMethodName(methodSymbol, useModernSyntax: supportsThrowsAsync); + var replacementMethod = GetReplacementMethodName(invocationOperation, useModernSyntax: supportsThrowsAsync); var codeAction = CodeAction.Create( $"Replace with {replacementMethod}", - ct => CreateChangedDocument(context, semanticModel, invocation, methodSymbol, supportsThrowsAsync, ct), + ct => CreateChangedDocument(context, semanticModel, invocationOperation, supportsThrowsAsync, ct), nameof(AbstractSyncOverAsyncThrowsCodeFixProvider)); context.RegisterCodeFix(codeAction, diagnostic); @@ -67,13 +71,12 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) private async Task CreateChangedDocument( CodeFixContext context, SemanticModel semanticModel, - SyntaxNode currentInvocationExpression, - IMethodSymbol invocationSymbol, + IInvocationOperation invocationOperation, bool useModernSyntax, CancellationToken cancellationToken) { var documentEditor = await DocumentEditor.CreateAsync(context.Document, cancellationToken); - var invocationOperation = (IInvocationOperation)semanticModel.GetOperation(currentInvocationExpression); + var invocationSymbol = (IMethodSymbol)semanticModel.GetSymbolInfo(invocationOperation.Syntax).Symbol; var updatedInvocationExpression = useModernSyntax ? await CreateThrowsAsyncInvocationExpression( @@ -85,7 +88,7 @@ private async Task CreateChangedDocument( invocationSymbol, context); - documentEditor.ReplaceNode(currentInvocationExpression, updatedInvocationExpression); + documentEditor.ReplaceNode(invocationOperation.Syntax, updatedInvocationExpression); return documentEditor.GetChangedDocument(); } @@ -209,16 +212,18 @@ private static bool SupportsThrowsAsync(Compilation compilation) exceptionExtensionsTypeSymbol.GetMembers(MetadataNames.NSubstituteThrowsAsyncMethod).IsEmpty == false; } - private static string GetReplacementMethodName(IMethodSymbol methodSymbol, bool useModernSyntax) + private static string GetReplacementMethodName(IInvocationOperation invocationOperation, bool useModernSyntax) { + var isThrowsSyncMethod = invocationOperation.TargetMethod.IsThrowsSyncMethod(); + if (useModernSyntax) { - return methodSymbol.IsThrowsSyncMethod() + return isThrowsSyncMethod ? MetadataNames.NSubstituteThrowsAsyncMethod : MetadataNames.NSubstituteThrowsAsyncForAnyArgsMethod; } - return methodSymbol.IsThrowsSyncMethod() + return isThrowsSyncMethod ? MetadataNames.NSubstituteReturnsMethod : MetadataNames.NSubstituteReturnsForAnyArgsMethod; }