@@ -217,13 +217,13 @@ private static void HandleSwitchStatement(SyntaxNodeAnalysisContext context)
217217 var labels = ImmutableList . CreateBuilder < SwitchLabelSyntax > ( ) ;
218218 var statements = ImmutableList . CreateBuilder < StatementSyntax > ( ) ;
219219 var labeledStatements = ImmutableList . CreateBuilder < StatementSyntax > ( ) ;
220- var blockStatements = ImmutableList . CreateBuilder < StatementSyntax > ( ) ;
220+ var blockStatements = ImmutableList . CreateBuilder < BlockSyntax > ( ) ;
221221 foreach ( SwitchSectionSyntax switchSection in switchStatement . Sections )
222222 {
223223 labels . AddRange ( switchSection . Labels ) ;
224224 if ( switchSection . Statements . Count == 1 && switchSection . Statements [ 0 ] . IsKind ( SyntaxKind . Block ) )
225225 {
226- blockStatements . Add ( switchSection . Statements [ 0 ] ) ;
226+ blockStatements . Add ( ( BlockSyntax ) switchSection . Statements [ 0 ] ) ;
227227 continue ;
228228 }
229229
@@ -243,20 +243,22 @@ private static void HandleSwitchStatement(SyntaxNodeAnalysisContext context)
243243 CheckElements ( context , labels . ToImmutable ( ) ) ;
244244 CheckElements ( context , statements . ToImmutable ( ) ) ;
245245 CheckElements ( context , labeledStatements . ToImmutable ( ) ) ;
246- CheckElements ( context , blockStatements . ToImmutable ( ) ) ;
246+ CheckBlocks ( context , blockStatements . ToImmutable ( ) ) ;
247247 }
248248
249249 private static void HandleInitializerExpression ( SyntaxNodeAnalysisContext context )
250250 {
251251 var initializerExpression = ( InitializerExpressionSyntax ) context . Node ;
252252
253+ CheckBraces ( context , initializerExpression . OpenBraceToken , initializerExpression . CloseBraceToken ) ;
253254 CheckElements ( context , initializerExpression . Expressions ) ;
254255 }
255256
256257 private static void HandleAnonymousObjectCreationExpression ( SyntaxNodeAnalysisContext context )
257258 {
258259 var anonymousObjectCreationExpression = ( AnonymousObjectCreationExpressionSyntax ) context . Node ;
259260
261+ CheckBraces ( context , anonymousObjectCreationExpression . OpenBraceToken , anonymousObjectCreationExpression . CloseBraceToken ) ;
260262 CheckElements ( context , anonymousObjectCreationExpression . Initializers ) ;
261263 }
262264
@@ -353,6 +355,50 @@ private static void CheckElements<T>(SyntaxNodeAnalysisContext context, Separate
353355 CheckElements ( context , elements . ToImmutableList ( ) ) ;
354356 }
355357
358+ // BlockSyntax is analyzed separately because it needs to check both braces.
359+ private static void CheckBlocks ( SyntaxNodeAnalysisContext context , ImmutableList < BlockSyntax > elements )
360+ {
361+ if ( elements . Count < 2 )
362+ {
363+ return ;
364+ }
365+
366+ elements = CleanupElementsList ( elements ) ;
367+
368+ if ( elements . Count < 2 )
369+ {
370+ return ;
371+ }
372+
373+ bool first = true ;
374+ string expectedIndentation = null ;
375+ foreach ( BlockSyntax element in elements )
376+ {
377+ SyntaxTrivia openBraceIndentationTrivia = element . OpenBraceToken . LeadingTrivia . LastOrDefault ( ) ;
378+ string openBraceIndentation = openBraceIndentationTrivia . IsKind ( SyntaxKind . WhitespaceTrivia ) ? openBraceIndentationTrivia . ToString ( ) : string . Empty ;
379+
380+ SyntaxTrivia closeBraceIndentationTrivia = element . CloseBraceToken . LeadingTrivia . LastOrDefault ( ) ;
381+ string closeBraceIndentation = closeBraceIndentationTrivia . IsKind ( SyntaxKind . WhitespaceTrivia ) ? closeBraceIndentationTrivia . ToString ( ) : string . Empty ;
382+
383+ if ( first )
384+ {
385+ expectedIndentation = openBraceIndentation ;
386+ first = false ;
387+ continue ;
388+ }
389+
390+ if ( ! string . Equals ( expectedIndentation , openBraceIndentation , StringComparison . Ordinal ) )
391+ {
392+ ReportDiagnostic ( context , element . OpenBraceToken , openBraceIndentationTrivia , openBraceIndentation , expectedIndentation ) ;
393+ }
394+
395+ if ( ! string . Equals ( expectedIndentation , closeBraceIndentation , StringComparison . Ordinal ) )
396+ {
397+ ReportDiagnostic ( context , element . CloseBraceToken , closeBraceIndentationTrivia , closeBraceIndentation , expectedIndentation ) ;
398+ }
399+ }
400+ }
401+
356402 private static void CheckElements < T > ( SyntaxNodeAnalysisContext context , ImmutableList < T > elements )
357403 where T : SyntaxNode
358404 {
@@ -361,12 +407,7 @@ private static void CheckElements<T>(SyntaxNodeAnalysisContext context, Immutabl
361407 return ;
362408 }
363409
364- elements = elements . RemoveAll (
365- element =>
366- {
367- SyntaxToken firstToken = GetFirstTokenForAnalysis ( element ) ;
368- return firstToken . IsMissingOrDefault ( ) || ! firstToken . IsFirstInLine ( allowNonWhitespaceTrivia : false ) ;
369- } ) ;
410+ elements = CleanupElementsList ( elements ) ;
370411
371412 if ( elements . Count < 2 )
372413 {
@@ -397,25 +438,22 @@ private static void CheckElements<T>(SyntaxNodeAnalysisContext context, Immutabl
397438 continue ;
398439 }
399440
400- if ( string . Equals ( expectedIndentation , indentation , StringComparison . Ordinal ) )
441+ if ( ! string . Equals ( expectedIndentation , indentation , StringComparison . Ordinal ) )
401442 {
402- // This handles the case where elements are indented properly
403- continue ;
443+ ReportDiagnostic ( context , firstToken , indentationTrivia , indentation , expectedIndentation ) ;
404444 }
445+ }
446+ }
405447
406- Location location ;
407- if ( indentation . Length == 0 )
408- {
409- location = firstToken . GetLocation ( ) ;
410- }
411- else
448+ private static ImmutableList < T > CleanupElementsList < T > ( ImmutableList < T > elements )
449+ where T : SyntaxNode
450+ {
451+ return elements . RemoveAll (
452+ element =>
412453 {
413- location = indentationTrivia . GetLocation ( ) ;
414- }
415-
416- ImmutableDictionary < string , string > properties = ImmutableDictionary . Create < string , string > ( ) . SetItem ( ExpectedIndentationKey , expectedIndentation ) ;
417- context . ReportDiagnostic ( Diagnostic . Create ( Descriptor , location , properties ) ) ;
418- }
454+ SyntaxToken firstToken = GetFirstTokenForAnalysis ( element ) ;
455+ return firstToken . IsMissingOrDefault ( ) || ! firstToken . IsFirstInLine ( allowNonWhitespaceTrivia : false ) ;
456+ } ) ;
419457 }
420458
421459 private static SyntaxToken GetFirstTokenForAnalysis ( SyntaxNode node )
@@ -433,5 +471,32 @@ private static SyntaxToken GetFirstTokenForAnalysis(SyntaxNode node)
433471
434472 return firstToken ;
435473 }
474+
475+ private static void CheckBraces ( SyntaxNodeAnalysisContext context , SyntaxToken openBraceToken , SyntaxToken closeBraceToken )
476+ {
477+ if ( openBraceToken . GetLine ( ) == closeBraceToken . GetLine ( ) )
478+ {
479+ // If the braces are on the same line, there is no point in checking indentation
480+ return ;
481+ }
482+
483+ SyntaxTrivia openBraceIndentationTrivia = openBraceToken . LeadingTrivia . LastOrDefault ( ) ;
484+ string openBraceIndentation = openBraceIndentationTrivia . IsKind ( SyntaxKind . WhitespaceTrivia ) ? openBraceIndentationTrivia . ToString ( ) : string . Empty ;
485+
486+ SyntaxTrivia closeBraceIndentationTrivia = closeBraceToken . LeadingTrivia . LastOrDefault ( ) ;
487+ string closeBraceIndentation = closeBraceIndentationTrivia . IsKind ( SyntaxKind . WhitespaceTrivia ) ? closeBraceIndentationTrivia . ToString ( ) : string . Empty ;
488+
489+ if ( ! string . Equals ( openBraceIndentation , closeBraceIndentation , StringComparison . Ordinal ) )
490+ {
491+ ReportDiagnostic ( context , closeBraceToken , closeBraceIndentationTrivia , closeBraceIndentation , openBraceIndentation ) ;
492+ }
493+ }
494+
495+ private static void ReportDiagnostic ( SyntaxNodeAnalysisContext context , SyntaxToken token , SyntaxTrivia tokenLeadingTrivia , string indentation , string expectedIndentation )
496+ {
497+ Location location = ( indentation . Length == 0 ) ? token . GetLocation ( ) : tokenLeadingTrivia . GetLocation ( ) ;
498+ ImmutableDictionary < string , string > properties = ImmutableDictionary . Create < string , string > ( ) . SetItem ( ExpectedIndentationKey , expectedIndentation ) ;
499+ context . ReportDiagnostic ( Diagnostic . Create ( Descriptor , location , properties ) ) ;
500+ }
436501 }
437502}
0 commit comments