Skip to content
This repository was archived by the owner on Nov 8, 2018. It is now read-only.

Commit efe417a

Browse files
committed
Report warnings for void-returning anonymous methods and lambdas
Fixes #20
1 parent c1d414e commit efe417a

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

AsyncUsageAnalyzers/AsyncUsageAnalyzers.Test/Reliability/AvoidAsyncVoidUnitTests.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,58 @@ async void MethodNameAsync(object sender, EventArgs e) { }
4444
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
4545
}
4646

47+
[Fact]
48+
public async Task TestAsyncLambdaEventHandlerReturnVoidAsync()
49+
{
50+
string testCode = @"
51+
using System;
52+
class ClassName
53+
{
54+
static event Action<object> SingleArgumentEvent;
55+
56+
ClassName()
57+
{
58+
AppDomain.CurrentDomain.DomainUnload += async (sender, e) => { };
59+
AppDomain.CurrentDomain.DomainUnload += async delegate (object sender, EventArgs e) { };
60+
SingleArgumentEvent += async arg => { };
61+
}
62+
}
63+
";
64+
65+
// This analyzer does not currently handle this case differently from any other method
66+
DiagnosticResult[] expected =
67+
{
68+
CSharpDiagnostic().WithArguments("<anonymous>").WithLocation(9, 49),
69+
CSharpDiagnostic().WithArguments("<anonymous>").WithLocation(10, 49),
70+
CSharpDiagnostic().WithArguments("<anonymous>").WithLocation(11, 32),
71+
};
72+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
73+
}
74+
75+
[Fact]
76+
public async Task TestAsyncLambdaReturnTaskAsync()
77+
{
78+
string testCode = @"
79+
using System;
80+
using System.Threading.Tasks;
81+
class ClassName
82+
{
83+
static Func<Task> ZeroArgumentFunction;
84+
static Func<object, Task> SingleArgumentFunction;
85+
86+
ClassName()
87+
{
88+
ZeroArgumentFunction = async () => await Task.Delay(42);
89+
SingleArgumentFunction = async arg => await Task.Delay(42);
90+
SingleArgumentFunction = async (object arg) => await Task.Delay(42);
91+
SingleArgumentFunction = async delegate (object arg) { await Task.Delay(42); };
92+
}
93+
}
94+
";
95+
96+
await VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
97+
}
98+
4799
[Fact]
48100
public async Task TestAsyncReturnTaskAsync()
49101
{

AsyncUsageAnalyzers/AsyncUsageAnalyzers/Reliability/AvoidAsyncVoidAnalyzer.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
{
33
using System.Collections.Immutable;
44
using Microsoft.CodeAnalysis;
5+
using Microsoft.CodeAnalysis.CSharp;
6+
using Microsoft.CodeAnalysis.CSharp.Syntax;
57
using Microsoft.CodeAnalysis.Diagnostics;
68

79
/// <summary>
@@ -32,6 +34,11 @@ public class AvoidAsyncVoidAnalyzer : DiagnosticAnalyzer
3234
public override void Initialize(AnalysisContext context)
3335
{
3436
context.RegisterSymbolAction(HandleMethodDeclaration, SymbolKind.Method);
37+
context.RegisterSyntaxNodeActionHonorExclusions(
38+
HandleAnonymousFunctionExpression,
39+
SyntaxKind.AnonymousMethodExpression,
40+
SyntaxKind.ParenthesizedLambdaExpression,
41+
SyntaxKind.SimpleLambdaExpression);
3542
}
3643

3744
private void HandleMethodDeclaration(SymbolAnalysisContext context)
@@ -42,5 +49,25 @@ private void HandleMethodDeclaration(SymbolAnalysisContext context)
4249

4350
context.ReportDiagnostic(Diagnostic.Create(Descriptor, symbol.Locations[0], symbol.Name));
4451
}
52+
53+
private static void HandleAnonymousFunctionExpression(SyntaxNodeAnalysisContext context)
54+
{
55+
AnonymousFunctionExpressionSyntax node = (AnonymousFunctionExpressionSyntax)context.Node;
56+
if (node.AsyncKeyword.IsKind(SyntaxKind.None) || node.AsyncKeyword.IsMissing)
57+
return;
58+
59+
TypeInfo typeInfo = context.SemanticModel.GetTypeInfo(node);
60+
INamedTypeSymbol convertedType = typeInfo.ConvertedType as INamedTypeSymbol;
61+
if (convertedType == null)
62+
return;
63+
64+
if (convertedType.TypeKind != TypeKind.Delegate || convertedType.DelegateInvokeMethod == null)
65+
return;
66+
67+
if (!convertedType.DelegateInvokeMethod.ReturnsVoid)
68+
return;
69+
70+
context.ReportDiagnostic(Diagnostic.Create(Descriptor, node.AsyncKeyword.GetLocation(), "<anonymous>"));
71+
}
4572
}
4673
}

0 commit comments

Comments
 (0)