Skip to content

Commit cbe1c79

Browse files
committed
Fix handling of both a header and a separated comment
When a comment preceding a set of using directives is separated from the first using directive by a blank line, that comment is associated with the list of using directives as opposed to specifically tied to the first one. This means after reordering the separated comment will continue to be separated and placed before the first using directive of the sorted result.
1 parent 49986c4 commit cbe1c79

2 files changed

Lines changed: 78 additions & 1 deletion

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/OrderingRules/UsingCodeFixProvider.UsingsSorter.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ private List<UsingDirectiveSyntax> GenerateUsings(List<UsingDirectiveSyntax> usi
173173

174174
// when there is a directive trivia, add it (and any trivia before it) to the triviaToMove collection.
175175
// when there are leading blank lines for the first entry, add them to the triviaToMove collection.
176+
int triviaToMoveCount = triviaToMove.Count;
176177
var previousIsEndOfLine = false;
177178
for (var m = leadingTrivia.Count - 1; m >= 0; m--)
178179
{
@@ -188,7 +189,8 @@ private List<UsingDirectiveSyntax> GenerateUsings(List<UsingDirectiveSyntax> usi
188189
{
189190
if (previousIsEndOfLine)
190191
{
191-
triviaToMove.Insert(0, leadingTrivia[m]);
192+
triviaToMove.InsertRange(0, leadingTrivia.Take(m + 2));
193+
break;
192194
}
193195

194196
previousIsEndOfLine = true;
@@ -202,6 +204,43 @@ private List<UsingDirectiveSyntax> GenerateUsings(List<UsingDirectiveSyntax> usi
202204
// preserve leading trivia (excluding directive trivia), indenting each line as appropriate
203205
var newLeadingTrivia = leadingTrivia.Except(triviaToMove).ToList();
204206

207+
// indent the triviaToMove if necessary so it behaves correctly later
208+
bool atStartOfLine = triviaToMoveCount == 0 || triviaToMove.Last().HasBuiltinEndLine();
209+
for (int m = triviaToMoveCount; m < triviaToMove.Count; m++)
210+
{
211+
bool currentAtStartOfLine = atStartOfLine;
212+
atStartOfLine = triviaToMove[m].HasBuiltinEndLine();
213+
if (!currentAtStartOfLine)
214+
{
215+
continue;
216+
}
217+
218+
if (triviaToMove[m].IsKind(SyntaxKind.EndOfLineTrivia))
219+
{
220+
// This is a blank line; indenting it would only add trailing whitespace
221+
continue;
222+
}
223+
224+
if (triviaToMove[m].IsDirective)
225+
{
226+
// Only #region and #endregion directives get indented
227+
if (!triviaToMove[m].IsKind(SyntaxKind.RegionDirectiveTrivia) && !triviaToMove[m].IsKind(SyntaxKind.EndRegionDirectiveTrivia))
228+
{
229+
// This is a preprocessor line that doesn't need to be indented
230+
continue;
231+
}
232+
}
233+
234+
if (triviaToMove[m].IsKind(SyntaxKind.DisabledTextTrivia))
235+
{
236+
// This is text in a '#if false' block; just ignore it
237+
continue;
238+
}
239+
240+
triviaToMove.Insert(m, SyntaxFactory.Whitespace(indentation));
241+
m++;
242+
}
243+
205244
// strip any leading whitespace on each line (and also blank lines)
206245
var k = 0;
207246
var startOfLine = true;

StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1200UnitTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,44 @@ namespace TestNamespace
194194
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
195195
}
196196

197+
[Fact]
198+
[WorkItem(2363, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2363")]
199+
public async Task TestInvalidUsingStatementsWithSeparatedFileHeaderAndTriviaAsync()
200+
{
201+
var testCode = @"// File Header
202+
203+
// Leading Comment
204+
205+
using System;
206+
using System.Threading;
207+
208+
namespace TestNamespace
209+
{
210+
}
211+
";
212+
213+
var fixedTestCode = @"// File Header
214+
215+
namespace TestNamespace
216+
{
217+
// Leading Comment
218+
219+
using System;
220+
using System.Threading;
221+
}
222+
";
223+
224+
DiagnosticResult[] expectedResults =
225+
{
226+
this.CSharpDiagnostic(SA1200UsingDirectivesMustBePlacedCorrectly.DescriptorInside).WithLocation(5, 1),
227+
this.CSharpDiagnostic(SA1200UsingDirectivesMustBePlacedCorrectly.DescriptorInside).WithLocation(6, 1),
228+
};
229+
230+
await this.VerifyCSharpDiagnosticAsync(testCode, expectedResults, CancellationToken.None).ConfigureAwait(false);
231+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
232+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
233+
}
234+
197235
[Fact]
198236
[WorkItem(2363, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2363")]
199237
public async Task TestInvalidUsingStatementsWithTriviaAsync()

0 commit comments

Comments
 (0)