1+ using System . Collections . Immutable ;
2+ using Microsoft . CodeAnalysis ;
3+ using Microsoft . CodeAnalysis . CSharp ;
4+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
5+ using Microsoft . CodeAnalysis . Diagnostics ;
6+
7+ namespace DataverseAnalyzer ;
8+
9+ [ DiagnosticAnalyzer ( LanguageNames . CSharp ) ]
10+ public sealed class NoBracesForControlFlowAnalyzer : DiagnosticAnalyzer
11+ {
12+ private static readonly Lazy < DiagnosticDescriptor > LazyRule = new ( ( ) => new DiagnosticDescriptor (
13+ "CT0004" ,
14+ Resources . CT0004_Title ,
15+ Resources . CT0004_MessageFormat ,
16+ "Style" ,
17+ DiagnosticSeverity . Error ,
18+ isEnabledByDefault : true ,
19+ description : Resources . CT0004_Description ) ) ;
20+
21+ public static DiagnosticDescriptor Rule => LazyRule . Value ;
22+
23+ public override ImmutableArray < DiagnosticDescriptor > SupportedDiagnostics => ImmutableArray . Create ( Rule ) ;
24+
25+ public override void Initialize ( AnalysisContext context )
26+ {
27+ if ( context is null )
28+ {
29+ throw new ArgumentNullException ( nameof ( context ) ) ;
30+ }
31+
32+ context . ConfigureGeneratedCodeAnalysis ( GeneratedCodeAnalysisFlags . None ) ;
33+ context . EnableConcurrentExecution ( ) ;
34+ context . RegisterSyntaxNodeAction ( AnalyzeIfStatement , SyntaxKind . IfStatement ) ;
35+ context . RegisterSyntaxNodeAction ( AnalyzeElseClause , SyntaxKind . ElseClause ) ;
36+ }
37+
38+ private static void AnalyzeIfStatement ( SyntaxNodeAnalysisContext context )
39+ {
40+ var ifStatement = ( IfStatementSyntax ) context . Node ;
41+ AnalyzeEmbeddedStatement ( context , ifStatement . Statement ) ;
42+ }
43+
44+ private static void AnalyzeElseClause ( SyntaxNodeAnalysisContext context )
45+ {
46+ var elseClause = ( ElseClauseSyntax ) context . Node ;
47+ if ( elseClause . Statement is not IfStatementSyntax )
48+ {
49+ AnalyzeEmbeddedStatement ( context , elseClause . Statement ) ;
50+ }
51+ }
52+
53+ private static void AnalyzeEmbeddedStatement ( SyntaxNodeAnalysisContext context , StatementSyntax statement )
54+ {
55+ if ( statement is not BlockSyntax block )
56+ {
57+ return ;
58+ }
59+
60+ if ( block . Statements . Count != 1 )
61+ {
62+ return ;
63+ }
64+
65+ var singleStatement = block . Statements [ 0 ] ;
66+ if ( ! IsControlFlowStatement ( singleStatement ) )
67+ {
68+ return ;
69+ }
70+
71+ var diagnostic = Diagnostic . Create ( Rule , block . GetLocation ( ) ) ;
72+ context . ReportDiagnostic ( diagnostic ) ;
73+ }
74+
75+ private static bool IsControlFlowStatement ( StatementSyntax statement )
76+ {
77+ return statement . Kind ( ) switch
78+ {
79+ SyntaxKind . ReturnStatement => true ,
80+ SyntaxKind . ThrowStatement => true ,
81+ SyntaxKind . ContinueStatement => true ,
82+ SyntaxKind . BreakStatement => true ,
83+ SyntaxKind . YieldReturnStatement => false ,
84+ SyntaxKind . YieldBreakStatement => true ,
85+ _ => false ,
86+ } ;
87+ }
88+ }
0 commit comments