-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
20 changed files
with
614 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
...chmarks.Source.CSharp/DiagnosticsSources/AsyncReceivedInOrderCallbackDiagnosticsSource.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System.Threading.Tasks; | ||
|
||
namespace NSubstitute.Analyzers.Benchmarks.Source.CSharp.DiagnosticsSources | ||
{ | ||
public class AsyncReceivedInOrderCallbackDiagnosticsSource | ||
{ | ||
public void NS5002_AsyncCallbackUsedInReceivedInOrderMethod() | ||
{ | ||
Received.InOrder(async () => { await Task.CompletedTask; }); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
...ks.Source.VisualBasic/DiagnosticsSources/AsyncReceivedInOrderCallbackDiagnosticsSource.vb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
Imports System.Threading.Tasks | ||
|
||
Namespace DiagnosticsSources | ||
Public Class AsyncReceivedInOrderCallbackDiagnosticsSource | ||
Public Sub NS5002_AsyncCallbackUsedInReceivedInOrderMethod() | ||
NSubstitute.Received.InOrder(Async Sub() | ||
Await Task.CompletedTask | ||
End Sub) | ||
End Sub | ||
End Class | ||
End Namespace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# NS5002 | ||
|
||
<table> | ||
<tr> | ||
<td>CheckId</td> | ||
<td>NS5002</td> | ||
</tr> | ||
<tr> | ||
<td>Category</td> | ||
<td>Usage</td> | ||
</tr> | ||
</table> | ||
|
||
## Cause | ||
|
||
Usage of async callback in `Received.InOrder` method. | ||
|
||
## Rule description | ||
|
||
A violation of this rule occurs when async callback is used in `Received.InOrder` method. `Received.InOrder` is used to specify calls which should be received by one or more substitutes. Running/awaiting these calls is not required for this, and can cause some problems as described in issue [#604](https://github.com/nsubstitute/NSubstitute/issues/604). | ||
|
||
## How to fix violations | ||
|
||
To fix a violation of this rule, remove async modifier from `Received.InOrder` callback. | ||
|
||
For example: | ||
|
||
````c# | ||
// Incorrect: | ||
Received.InOrder(async () => | ||
{ | ||
await sub.Received().Bar(); | ||
}) | ||
|
||
// Correct: | ||
Received.InOrder(() => | ||
{ | ||
sub.Bar(); | ||
}) | ||
```` | ||
|
||
## How to suppress violations | ||
|
||
This warning can be suppressed by disabling the warning in the **ruleset** file for the project. | ||
The warning can also be suppressed programmatically for an assembly: | ||
````c# | ||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "NS5002:Async callback used in Received.InOrder method.", Justification = "Reviewed")] | ||
```` | ||
|
||
Or for a specific code block: | ||
````c# | ||
#pragma warning disable NS5002 // Async callback used in Received.InOrder method. | ||
// the code which produces warning | ||
#pragma warning restore NS5002 // Async callback used in Received.InOrder method. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; | ||
|
||
namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers | ||
{ | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
internal sealed class AsyncReceivedInOrderCallbackAnalyzer : AbstractAsyncReceivedInOrderCallbackAnalyzer<SyntaxKind, InvocationExpressionSyntax> | ||
{ | ||
public AsyncReceivedInOrderCallbackAnalyzer() | ||
: base(CSharp.DiagnosticDescriptorsProvider.Instance) | ||
{ | ||
} | ||
|
||
protected override int AsyncExpressionRawKind { get; } = (int)SyntaxKind.AsyncKeyword; | ||
|
||
protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; | ||
|
||
protected override IEnumerable<SyntaxNode> GetArgumentExpressions(InvocationExpressionSyntax invocationExpressionSyntax) | ||
{ | ||
return invocationExpressionSyntax.ArgumentList.Arguments.Select<ArgumentSyntax, SyntaxNode>(arg => arg.Expression); | ||
} | ||
|
||
protected override IEnumerable<SyntaxToken?> GetCallbackArgumentSyntaxTokens(SyntaxNode node) | ||
{ | ||
return node.ChildTokens().Select<SyntaxToken, SyntaxToken?>(token => token); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
73 changes: 73 additions & 0 deletions
73
...tute.Analyzers.Shared/DiagnosticAnalyzers/AbstractAsyncReceivedInOrderCallbackAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using NSubstitute.Analyzers.Shared.Extensions; | ||
|
||
namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers | ||
{ | ||
internal abstract class AbstractAsyncReceivedInOrderCallbackAnalyzer<TSyntaxKind, TInvocationExpressionSyntax> : AbstractDiagnosticAnalyzer | ||
where TSyntaxKind : struct | ||
where TInvocationExpressionSyntax : SyntaxNode | ||
{ | ||
private readonly Action<SyntaxNodeAnalysisContext> _analyzeInvocationAction; | ||
|
||
protected AbstractAsyncReceivedInOrderCallbackAnalyzer( | ||
IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider) | ||
: base(diagnosticDescriptorsProvider) | ||
{ | ||
_analyzeInvocationAction = AnalyzeInvocation; | ||
SupportedDiagnostics = ImmutableArray.Create(diagnosticDescriptorsProvider.AsyncCallbackUsedInReceivedInOrder); | ||
} | ||
|
||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } | ||
|
||
protected abstract int AsyncExpressionRawKind { get; } | ||
|
||
protected abstract TSyntaxKind InvocationExpressionKind { get; } | ||
|
||
protected abstract IEnumerable<SyntaxNode> GetArgumentExpressions(TInvocationExpressionSyntax invocationExpressionSyntax); | ||
|
||
protected abstract IEnumerable<SyntaxToken?> GetCallbackArgumentSyntaxTokens(SyntaxNode node); | ||
|
||
protected sealed override void InitializeAnalyzer(AnalysisContext context) | ||
{ | ||
context.RegisterSyntaxNodeAction(_analyzeInvocationAction, InvocationExpressionKind); | ||
} | ||
|
||
private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) | ||
{ | ||
var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node; | ||
var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression); | ||
|
||
if (methodSymbolInfo.Symbol?.Kind != SymbolKind.Method) | ||
{ | ||
return; | ||
} | ||
|
||
if (methodSymbolInfo.Symbol.IsReceivedInOrderMethod() == false) | ||
{ | ||
return; | ||
} | ||
|
||
foreach (var expression in GetArgumentExpressions(invocationExpression)) | ||
{ | ||
var asyncToken = GetCallbackArgumentSyntaxTokens(expression) | ||
.FirstOrDefault(token => token.HasValue && token.Value.RawKind == AsyncExpressionRawKind); | ||
|
||
if (asyncToken.HasValue == false) | ||
{ | ||
continue; | ||
} | ||
|
||
var diagnostic = Diagnostic.Create( | ||
DiagnosticDescriptorsProvider.AsyncCallbackUsedInReceivedInOrder, | ||
asyncToken.Value.GetLocation()); | ||
|
||
syntaxNodeContext.ReportDiagnostic(diagnostic); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
...stitute.Analyzers.VisualBasic/DiagnosticAnalyzers/AsyncReceivedInOrderCallbackAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using Microsoft.CodeAnalysis.VisualBasic; | ||
using Microsoft.CodeAnalysis.VisualBasic.Syntax; | ||
using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; | ||
|
||
namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers | ||
{ | ||
[DiagnosticAnalyzer(LanguageNames.VisualBasic)] | ||
internal sealed class AsyncReceivedInOrderCallbackAnalyzer : AbstractAsyncReceivedInOrderCallbackAnalyzer<SyntaxKind, InvocationExpressionSyntax> | ||
{ | ||
public AsyncReceivedInOrderCallbackAnalyzer() | ||
: base(VisualBasic.DiagnosticDescriptorsProvider.Instance) | ||
{ | ||
} | ||
|
||
protected override int AsyncExpressionRawKind { get; } = (int)SyntaxKind.AsyncKeyword; | ||
|
||
protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; | ||
|
||
protected override IEnumerable<SyntaxNode> GetArgumentExpressions(InvocationExpressionSyntax invocationExpressionSyntax) | ||
{ | ||
return invocationExpressionSyntax.ArgumentList.Arguments.Select<ArgumentSyntax, SyntaxNode>(arg => arg.GetExpression()); | ||
} | ||
|
||
protected override IEnumerable<SyntaxToken?> GetCallbackArgumentSyntaxTokens(SyntaxNode node) | ||
{ | ||
switch (node) | ||
{ | ||
case LambdaExpressionSyntax lambdaExpressionSyntax: | ||
return lambdaExpressionSyntax.SubOrFunctionHeader.ChildTokens().Select<SyntaxToken, SyntaxToken?>(token => token); | ||
} | ||
|
||
return Enumerable.Empty<SyntaxToken?>(); | ||
} | ||
} | ||
} |
Oops, something went wrong.