Skip to content

Commit cc64ff5

Browse files
committed
Implement SA1130
1 parent 98b446f commit cc64ff5

3 files changed

Lines changed: 47 additions & 3 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/ReadabilityResources.Designer.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/ReadabilityResources.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@
421421
<value>Lambda expressions are more succinct and easier to read than anonymous methods, so they should are preferred whenever the two are functionally equivalent.</value>
422422
</data>
423423
<data name="SA1130MessageFormat" xml:space="preserve">
424-
<value />
424+
<value>Use lambda syntax</value>
425425
</data>
426426
<data name="SA1130Title" xml:space="preserve">
427427
<value>Use lambda syntax</value>

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1130UseLambdaSyntax.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
namespace StyleCop.Analyzers.ReadabilityRules
55
{
6+
using System;
67
using System.Collections.Immutable;
78
using Microsoft.CodeAnalysis;
9+
using Microsoft.CodeAnalysis.CSharp;
10+
using Microsoft.CodeAnalysis.CSharp.Syntax;
811
using Microsoft.CodeAnalysis.Diagnostics;
912

1013
/// <summary>
@@ -22,6 +25,7 @@ internal class SA1130UseLambdaSyntax : DiagnosticAnalyzer
2225
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(ReadabilityResources.SA1130MessageFormat), ReadabilityResources.ResourceManager, typeof(ReadabilityResources));
2326
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(ReadabilityResources.SA1130Description), ReadabilityResources.ResourceManager, typeof(ReadabilityResources));
2427
private static readonly string HelpLink = "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1130.md";
28+
private static readonly ParameterListSyntax EmptyParameterList = SyntaxFactory.ParameterList();
2529

2630
private static readonly DiagnosticDescriptor Descriptor =
2731
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.ReadabilityRules, DiagnosticSeverity.Warning, AnalyzerConstants.DisabledNoTests, Description, HelpLink);
@@ -33,7 +37,47 @@ internal class SA1130UseLambdaSyntax : DiagnosticAnalyzer
3337
/// <inheritdoc/>
3438
public override void Initialize(AnalysisContext context)
3539
{
36-
// TODO: Implement analysis
40+
context.RegisterCompilationStartAction(HandleCompilationStart);
41+
}
42+
43+
private static void HandleCompilationStart(CompilationStartAnalysisContext context)
44+
{
45+
context.RegisterSyntaxNodeActionHonorExclusions(HandleAnonymousMethodExpression, SyntaxKind.AnonymousMethodExpression);
46+
}
47+
48+
private static void HandleAnonymousMethodExpression(SyntaxNodeAnalysisContext context)
49+
{
50+
var anonymousMethod = (AnonymousMethodExpressionSyntax)context.Node;
51+
52+
if (anonymousMethod.Parent.IsKind(SyntaxKind.Argument))
53+
{
54+
// invocation -> argument list -> argument -> anonymous method
55+
var originalInvocationExpression = anonymousMethod?.Parent?.Parent?.Parent as InvocationExpressionSyntax;
56+
57+
if (originalInvocationExpression != null)
58+
{
59+
// In some cases passing a delegate as an argument to a method is required to call the right overload
60+
// When there is an other overload that takes an expression.
61+
var lambdaExpression = SyntaxFactory.ParenthesizedLambdaExpression(
62+
anonymousMethod.AsyncKeyword,
63+
anonymousMethod.ParameterList ?? EmptyParameterList,
64+
SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken),
65+
anonymousMethod.Body);
66+
67+
var invocationExpression = originalInvocationExpression.ReplaceNode(anonymousMethod, lambdaExpression);
68+
69+
SymbolInfo originalSymbolInfo = context.SemanticModel.GetSymbolInfo(originalInvocationExpression);
70+
Location location = originalInvocationExpression.GetLocation();
71+
SymbolInfo newSymbolInfo = context.SemanticModel.GetSpeculativeSymbolInfo(location.SourceSpan.Start, invocationExpression, SpeculativeBindingOption.BindAsExpression);
72+
73+
if (originalSymbolInfo.Symbol != newSymbolInfo.Symbol)
74+
{
75+
return;
76+
}
77+
}
78+
}
79+
80+
context.ReportDiagnostic(Diagnostic.Create(Descriptor, anonymousMethod.GetLocation()));
3781
}
3882
}
3983
}

0 commit comments

Comments
 (0)