11using System ;
22using System . Collections . Immutable ;
3- using CSharpGuidelinesAnalyzer . Extensions ;
3+ using System . Threading ;
44using JetBrains . Annotations ;
55using Microsoft . CodeAnalysis ;
6+ using Microsoft . CodeAnalysis . CSharp ;
7+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
68using Microsoft . CodeAnalysis . Diagnostics ;
7- using Microsoft . CodeAnalysis . Operations ;
89
910namespace CSharpGuidelinesAnalyzer . Rules . Maintainability
1011{
@@ -28,53 +29,139 @@ public sealed class AvoidNestedLoopsAnalyzer : DiagnosticAnalyzer
2829 public override ImmutableArray < DiagnosticDescriptor > SupportedDiagnostics => ImmutableArray . Create ( Rule ) ;
2930
3031 [ NotNull ]
31- private static readonly Action < OperationAnalysisContext > AnalyzeLoopStatementAction =
32- context => context . SkipInvalid ( AnalyzeLoopStatement ) ;
32+ private static readonly SyntaxKind [ ] LoopStatementKinds =
33+ {
34+ SyntaxKind . WhileStatement ,
35+ SyntaxKind . DoStatement ,
36+ SyntaxKind . ForStatement ,
37+ SyntaxKind . ForEachStatement ,
38+ SyntaxKind . ForEachVariableStatement
39+ } ;
40+
41+ [ NotNull ]
42+ private static readonly Action < SyntaxNodeAnalysisContext > AnalyzeLoopStatementAction = AnalyzeLoopStatement ;
3343
3444 public override void Initialize ( [ NotNull ] AnalysisContext context )
3545 {
3646 context . EnableConcurrentExecution ( ) ;
3747 context . ConfigureGeneratedCodeAnalysis ( GeneratedCodeAnalysisFlags . None ) ;
3848
39- context . RegisterOperationAction ( AnalyzeLoopStatementAction , OperationKind . Loop ) ;
49+ context . RegisterSyntaxNodeAction ( AnalyzeLoopStatementAction , LoopStatementKinds ) ;
4050 }
4151
42- private static void AnalyzeLoopStatement ( OperationAnalysisContext context )
43- {
44- var loopStatement = ( ILoopOperation ) context . Operation ;
52+ [ NotNull ]
53+ private static readonly LoopBodyLocator BodyLocator = new LoopBodyLocator ( ) ;
4554
46- var walker = new LoopBodyWalker ( ) ;
47- walker . Visit ( loopStatement . Body ) ;
55+ private static void AnalyzeLoopStatement ( SyntaxNodeAnalysisContext context )
56+ {
57+ StatementSyntax loopBody = BodyLocator . Visit ( context . Node ) ;
58+ if ( loopBody != null )
59+ {
60+ AnalyzeLoopBody ( loopBody , context ) ;
61+ }
62+ }
4863
49- context . CancellationToken . ThrowIfCancellationRequested ( ) ;
64+ private static void AnalyzeLoopBody ( [ NotNull ] StatementSyntax loopBody , SyntaxNodeAnalysisContext context )
65+ {
66+ var walker = new LoopLocationWalker ( context . CancellationToken ) ;
67+ walker . Visit ( loopBody ) ;
5068
5169 if ( walker . LoopStatementLocation != null )
5270 {
5371 context . ReportDiagnostic ( Diagnostic . Create ( Rule , walker . LoopStatementLocation ) ) ;
5472 }
5573 }
5674
57- private sealed class LoopBodyWalker : ExplicitOperationWalker
75+ private sealed class LoopBodyLocator : CSharpSyntaxVisitor < StatementSyntax >
5876 {
77+ [ NotNull ]
78+ public override StatementSyntax VisitWhileStatement ( [ NotNull ] WhileStatementSyntax node )
79+ {
80+ return node . Statement ;
81+ }
82+
83+ [ NotNull ]
84+ public override StatementSyntax VisitDoStatement ( [ NotNull ] DoStatementSyntax node )
85+ {
86+ return node . Statement ;
87+ }
88+
89+ [ CanBeNull ]
90+ public override StatementSyntax VisitForStatement ( [ NotNull ] ForStatementSyntax node )
91+ {
92+ return node . Statement ;
93+ }
94+
95+ [ CanBeNull ]
96+ public override StatementSyntax VisitForEachStatement ( [ NotNull ] ForEachStatementSyntax node )
97+ {
98+ return node . Statement ;
99+ }
100+
101+ [ CanBeNull ]
102+ public override StatementSyntax VisitForEachVariableStatement ( [ NotNull ] ForEachVariableStatementSyntax node )
103+ {
104+ return node . Statement ;
105+ }
106+ }
107+
108+ private sealed class LoopLocationWalker : CSharpSyntaxWalker
109+ {
110+ private CancellationToken cancellationToken ;
111+
59112 [ CanBeNull ]
60113 public Location LoopStatementLocation { get ; private set ; }
61114
62- public override void VisitWhileLoop ( [ NotNull ] IWhileLoopOperation operation )
115+ public LoopLocationWalker ( CancellationToken cancellationToken )
116+ {
117+ this . cancellationToken = cancellationToken ;
118+ }
119+
120+ public override void Visit ( [ NotNull ] SyntaxNode node )
121+ {
122+ cancellationToken . ThrowIfCancellationRequested ( ) ;
123+
124+ base . Visit ( node ) ;
125+ }
126+
127+ public override void VisitWhileStatement ( [ NotNull ] WhileStatementSyntax node )
128+ {
129+ LoopStatementLocation = node . WhileKeyword . GetLocation ( ) ;
130+ }
131+
132+ public override void VisitDoStatement ( [ NotNull ] DoStatementSyntax node )
133+ {
134+ LoopStatementLocation = node . DoKeyword . GetLocation ( ) ;
135+ }
136+
137+ public override void VisitForStatement ( [ NotNull ] ForStatementSyntax node )
138+ {
139+ LoopStatementLocation = node . ForKeyword . GetLocation ( ) ;
140+ }
141+
142+ public override void VisitForEachStatement ( [ NotNull ] ForEachStatementSyntax node )
143+ {
144+ LoopStatementLocation = node . ForEachKeyword . GetLocation ( ) ;
145+ }
146+
147+ public override void VisitForEachVariableStatement ( [ NotNull ] ForEachVariableStatementSyntax node )
148+ {
149+ LoopStatementLocation = node . ForEachKeyword . GetLocation ( ) ;
150+ }
151+
152+ public override void VisitLocalFunctionStatement ( [ NotNull ] LocalFunctionStatementSyntax node )
63153 {
64- LoopStatementLocation = operation . TryGetLocationForKeyword ( ) ;
65154 }
66155
67- public override void VisitForLoop ( [ NotNull ] IForLoopOperation operation )
156+ public override void VisitSimpleLambdaExpression ( [ NotNull ] SimpleLambdaExpressionSyntax node )
68157 {
69- LoopStatementLocation = operation . TryGetLocationForKeyword ( ) ;
70158 }
71159
72- public override void VisitForEachLoop ( [ NotNull ] IForEachLoopOperation operation )
160+ public override void VisitParenthesizedLambdaExpression ( [ NotNull ] ParenthesizedLambdaExpressionSyntax node )
73161 {
74- LoopStatementLocation = operation . TryGetLocationForKeyword ( ) ;
75162 }
76163
77- public override void VisitLocalFunction ( [ NotNull ] ILocalFunctionOperation operation )
164+ public override void VisitAnonymousMethodExpression ( [ NotNull ] AnonymousMethodExpressionSyntax node )
78165 {
79166 }
80167 }
0 commit comments