diff --git a/src/Atc.Analyzer/Rules/Style/BlankLineBetweenCodeBlocksAnalyzer.cs b/src/Atc.Analyzer/Rules/Style/BlankLineBetweenCodeBlocksAnalyzer.cs index 4f1e7dc..a6cd48b 100644 --- a/src/Atc.Analyzer/Rules/Style/BlankLineBetweenCodeBlocksAnalyzer.cs +++ b/src/Atc.Analyzer/Rules/Style/BlankLineBetweenCodeBlocksAnalyzer.cs @@ -104,7 +104,11 @@ private static int CountBlankLinesBetween( StatementSyntax second) { // Get the end line of the first statement - var firstEndLine = first.GetLocation().GetLineSpan().EndLinePosition.Line; + var firstEndLine = first + .GetLocation() + .GetLineSpan() + .EndLinePosition + .Line; // Get the start line of the second statement (or its first non-whitespace leading trivia) var secondStartLine = GetEffectiveStartLine(second); @@ -117,7 +121,7 @@ private static int CountBlankLinesBetween( private static int GetEffectiveStartLine(StatementSyntax statement) { - // Check leading trivia for comments - if there's a comment, use its line position + // Check leading trivia for comments or preprocessor directives - if found, use its line position var leadingTrivia = statement.GetLeadingTrivia(); foreach (var trivia in leadingTrivia) @@ -125,9 +129,15 @@ private static int GetEffectiveStartLine(StatementSyntax statement) if (trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) || trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) || trivia.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) || - trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia)) + trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia) || + trivia.IsKind(SyntaxKind.IfDirectiveTrivia) || + trivia.IsKind(SyntaxKind.ElseDirectiveTrivia) || + trivia.IsKind(SyntaxKind.ElifDirectiveTrivia) || + trivia.IsKind(SyntaxKind.EndIfDirectiveTrivia) || + trivia.IsKind(SyntaxKind.RegionDirectiveTrivia) || + trivia.IsKind(SyntaxKind.EndRegionDirectiveTrivia)) { - // Return the line where the comment starts + // Return the line where the trivia starts return trivia .GetLocation()? .GetLineSpan() @@ -140,6 +150,10 @@ private static int GetEffectiveStartLine(StatementSyntax statement) } } - return statement.GetLocation().GetLineSpan().StartLinePosition.Line; + return statement + .GetLocation() + .GetLineSpan() + .StartLinePosition + .Line; } } \ No newline at end of file diff --git a/src/Atc.Analyzer/Rules/Style/BlankLineBetweenCodeBlocksCodeFixProvider.cs b/src/Atc.Analyzer/Rules/Style/BlankLineBetweenCodeBlocksCodeFixProvider.cs index d689c17..5ac6985 100644 --- a/src/Atc.Analyzer/Rules/Style/BlankLineBetweenCodeBlocksCodeFixProvider.cs +++ b/src/Atc.Analyzer/Rules/Style/BlankLineBetweenCodeBlocksCodeFixProvider.cs @@ -68,12 +68,16 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) context.Diagnostics); } + [SuppressMessage("Design", "MA0051:Method is too long", Justification = "OK.")] private static async Task FixBlankLinesAsync( Document document, StatementSyntax secondStatement, CancellationToken cancellationToken) { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var root = await document + .GetSyntaxRootAsync(cancellationToken) + .ConfigureAwait(false); + if (root is null) { return document; @@ -85,22 +89,28 @@ private static async Task FixBlankLinesAsync( // Get the leading trivia of the second statement var leadingTrivia = secondStatement.GetLeadingTrivia(); - // Separate comments from whitespace - var comments = new List(); - var hasFoundComment = false; + // Separate comments and preprocessor directives from whitespace + var preservedTrivia = new List(); + var hasFoundPreservedTrivia = false; foreach (var trivia in leadingTrivia) { if (trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) || - trivia.IsKind(SyntaxKind.MultiLineCommentTrivia)) + trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) || + trivia.IsKind(SyntaxKind.IfDirectiveTrivia) || + trivia.IsKind(SyntaxKind.ElseDirectiveTrivia) || + trivia.IsKind(SyntaxKind.ElifDirectiveTrivia) || + trivia.IsKind(SyntaxKind.EndIfDirectiveTrivia) || + trivia.IsKind(SyntaxKind.RegionDirectiveTrivia) || + trivia.IsKind(SyntaxKind.EndRegionDirectiveTrivia)) { - hasFoundComment = true; - comments.Add(trivia); + hasFoundPreservedTrivia = true; + preservedTrivia.Add(trivia); } - else if (hasFoundComment && trivia.IsKind(SyntaxKind.EndOfLineTrivia)) + else if (hasFoundPreservedTrivia && trivia.IsKind(SyntaxKind.EndOfLineTrivia)) { - // Keep the newline after the comment - comments.Add(trivia); + // Keep the newline after the preserved trivia + preservedTrivia.Add(trivia); } } @@ -113,11 +123,11 @@ private static async Task FixBlankLinesAsync( endOfLine, // This is the blank line }; - // Add back any comments with their proper trivia - if (comments.Count > 0) + // Add back any preserved trivia (comments, preprocessor directives) with their proper trivia + if (preservedTrivia.Count > 0) { newTriviaList.Add(SyntaxFactory.Whitespace(indentation)); - newTriviaList.AddRange(comments); + newTriviaList.AddRange(preservedTrivia); } // Add the indentation for the statement diff --git a/test/Atc.Analyzer.Tests/Rules/Style/BlankLineBetweenCodeBlocksAnalyzerNoDiagnosticTests.cs b/test/Atc.Analyzer.Tests/Rules/Style/BlankLineBetweenCodeBlocksAnalyzerNoDiagnosticTests.cs index a09b18d..2ef12b9 100644 --- a/test/Atc.Analyzer.Tests/Rules/Style/BlankLineBetweenCodeBlocksAnalyzerNoDiagnosticTests.cs +++ b/test/Atc.Analyzer.Tests/Rules/Style/BlankLineBetweenCodeBlocksAnalyzerNoDiagnosticTests.cs @@ -432,4 +432,32 @@ public void Method() await AnalyzerVerifier.VerifyAnalyzerAsync(code); } + + [Fact] + public async Task NoDiagnostic_BlockStatementWithPreprocessorDirectiveBetween() + { + const string code = """ + public class Sample + { + public void Method(string value) + { + if (string.IsNullOrEmpty(value)) + { + return; + } + + #if NETSTANDARD2_0 + return; + #else + if (value.Length == 1) + { + return; + } + #endif + } + } + """; + + await AnalyzerVerifier.VerifyAnalyzerAsync(code); + } } \ No newline at end of file