33
44namespace 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