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

Commit

Permalink
Merge pull request #28 from sharwell/fix-20
Browse files Browse the repository at this point in the history
Report warnings for void-returning anonymous methods and lambdas
  • Loading branch information
sharwell committed Jul 21, 2015
2 parents c1d414e + efe417a commit 7eebb27
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<object> 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("<anonymous>").WithLocation(9, 49),
CSharpDiagnostic().WithArguments("<anonymous>").WithLocation(10, 49),
CSharpDiagnostic().WithArguments("<anonymous>").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<Task> ZeroArgumentFunction;
static Func<object, Task> 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()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
{
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

/// <summary>
Expand Down Expand Up @@ -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)
Expand All @@ -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(), "<anonymous>"));
}
}
}

0 comments on commit 7eebb27

Please sign in to comment.