diff --git a/AsyncUsageAnalyzers/AsyncUsageAnalyzers.Test/Reliability/AvoidAsyncVoidUnitTests.cs b/AsyncUsageAnalyzers/AsyncUsageAnalyzers.Test/Reliability/AvoidAsyncVoidUnitTests.cs index bf2c2a7..47c3521 100644 --- a/AsyncUsageAnalyzers/AsyncUsageAnalyzers.Test/Reliability/AvoidAsyncVoidUnitTests.cs +++ b/AsyncUsageAnalyzers/AsyncUsageAnalyzers.Test/Reliability/AvoidAsyncVoidUnitTests.cs @@ -44,6 +44,58 @@ async void MethodNameAsync(object sender, EventArgs e) { } await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false); } + [Fact] + public async Task TestAsyncLambdaEventHandlerReturnVoidAsync() + { + string testCode = @" +using System; +class ClassName +{ + static event Action SingleArgumentEvent; + + ClassName() + { + AppDomain.CurrentDomain.DomainUnload += async (sender, e) => { }; + AppDomain.CurrentDomain.DomainUnload += async delegate (object sender, EventArgs e) { }; + SingleArgumentEvent += async arg => { }; + } +} +"; + + // This analyzer does not currently handle this case differently from any other method + DiagnosticResult[] expected = + { + CSharpDiagnostic().WithArguments("").WithLocation(9, 49), + CSharpDiagnostic().WithArguments("").WithLocation(10, 49), + CSharpDiagnostic().WithArguments("").WithLocation(11, 32), + }; + await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false); + } + + [Fact] + public async Task TestAsyncLambdaReturnTaskAsync() + { + string testCode = @" +using System; +using System.Threading.Tasks; +class ClassName +{ + static Func ZeroArgumentFunction; + static Func SingleArgumentFunction; + + ClassName() + { + ZeroArgumentFunction = async () => await Task.Delay(42); + SingleArgumentFunction = async arg => await Task.Delay(42); + SingleArgumentFunction = async (object arg) => await Task.Delay(42); + SingleArgumentFunction = async delegate (object arg) { await Task.Delay(42); }; + } +} +"; + + await VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + } + [Fact] public async Task TestAsyncReturnTaskAsync() { diff --git a/AsyncUsageAnalyzers/AsyncUsageAnalyzers/Reliability/AvoidAsyncVoidAnalyzer.cs b/AsyncUsageAnalyzers/AsyncUsageAnalyzers/Reliability/AvoidAsyncVoidAnalyzer.cs index 2e8f880..0ac8c19 100644 --- a/AsyncUsageAnalyzers/AsyncUsageAnalyzers/Reliability/AvoidAsyncVoidAnalyzer.cs +++ b/AsyncUsageAnalyzers/AsyncUsageAnalyzers/Reliability/AvoidAsyncVoidAnalyzer.cs @@ -2,6 +2,8 @@ { using System.Collections.Immutable; using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; /// @@ -32,6 +34,11 @@ public class AvoidAsyncVoidAnalyzer : DiagnosticAnalyzer public override void Initialize(AnalysisContext context) { context.RegisterSymbolAction(HandleMethodDeclaration, SymbolKind.Method); + context.RegisterSyntaxNodeActionHonorExclusions( + HandleAnonymousFunctionExpression, + SyntaxKind.AnonymousMethodExpression, + SyntaxKind.ParenthesizedLambdaExpression, + SyntaxKind.SimpleLambdaExpression); } private void HandleMethodDeclaration(SymbolAnalysisContext context) @@ -42,5 +49,25 @@ private void HandleMethodDeclaration(SymbolAnalysisContext context) context.ReportDiagnostic(Diagnostic.Create(Descriptor, symbol.Locations[0], symbol.Name)); } + + private static void HandleAnonymousFunctionExpression(SyntaxNodeAnalysisContext context) + { + AnonymousFunctionExpressionSyntax node = (AnonymousFunctionExpressionSyntax)context.Node; + if (node.AsyncKeyword.IsKind(SyntaxKind.None) || node.AsyncKeyword.IsMissing) + return; + + TypeInfo typeInfo = context.SemanticModel.GetTypeInfo(node); + INamedTypeSymbol convertedType = typeInfo.ConvertedType as INamedTypeSymbol; + if (convertedType == null) + return; + + if (convertedType.TypeKind != TypeKind.Delegate || convertedType.DelegateInvokeMethod == null) + return; + + if (!convertedType.DelegateInvokeMethod.ReturnsVoid) + return; + + context.ReportDiagnostic(Diagnostic.Create(Descriptor, node.AsyncKeyword.GetLocation(), "")); + } } }