Skip to content

Commit ed2bcba

Browse files
committed
Merge pull request #1461 from sharwell/fix-1456
Fix behavior of SA1506 code fix when a blank line follows a line comment
2 parents 9a4024c + 961286c commit ed2bcba

3 files changed

Lines changed: 92 additions & 21 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test/LayoutRules/SA1506UnitTests.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,9 +572,14 @@ public class TestClass
572572
public void TestMethod1() { }
573573
574574
/// <summary>more documentation.</summary>
575-
575+
576576
/* another comment */
577577
public void TestMethod2() { }
578+
579+
/// <summary>more documentation.</summary>
580+
// another comment (a specific regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1456)
581+
582+
public void TestMethod3() { }
578583
}
579584
";
580585

@@ -592,6 +597,10 @@ public void TestMethod1() { }
592597
/// <summary>more documentation.</summary>
593598
/* another comment */
594599
public void TestMethod2() { }
600+
601+
/// <summary>more documentation.</summary>
602+
// another comment (a specific regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1456)
603+
public void TestMethod3() { }
595604
}
596605
";
597606

@@ -600,6 +609,7 @@ public void TestMethod2() { }
600609
this.CSharpDiagnostic().WithLocation(3, 1),
601610
this.CSharpDiagnostic().WithLocation(10, 1),
602611
this.CSharpDiagnostic().WithLocation(15, 1),
612+
this.CSharpDiagnostic().WithLocation(20, 1),
603613
};
604614

605615
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);

StyleCop.Analyzers/StyleCop.Analyzers/Helpers/TriviaHelper.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,53 @@ internal static int IndexOfTrailingWhitespace(IReadOnlyList<SyntaxTrivia> trivia
112112
return (whiteSpaceStartIndex < triviaList.Count) ? whiteSpaceStartIndex : -1;
113113
}
114114

115+
/// <summary>
116+
/// Removes a range of elements from the <see cref="SyntaxTriviaList"/>.
117+
/// </summary>
118+
/// <param name="list">The list to remove elements from.</param>
119+
/// <param name="index">The zero-based starting index of the range of elements to remove.</param>
120+
/// <param name="count">The number of elements to remove.</param>
121+
/// <returns>A copy of <paramref name="list"/> with the specified range of elements removed.</returns>
122+
/// <exception cref="ArgumentOutOfRangeException">
123+
/// <para>If <paramref name="index"/> is less than 0.</para>
124+
/// <para>-or-</para>
125+
/// <para>If <paramref name="count"/> is less than 0.</para>
126+
/// </exception>
127+
/// <exception cref="ArgumentException">
128+
/// <para>If <paramref name="index"/> and <paramref name="count"/> do not denote a valid range of elements in
129+
/// the <see cref="SyntaxTriviaList"/>.</para>
130+
/// </exception>
131+
internal static SyntaxTriviaList RemoveRange(this SyntaxTriviaList list, int index, int count)
132+
{
133+
if (index < 0)
134+
{
135+
throw new ArgumentOutOfRangeException(nameof(index));
136+
}
137+
138+
if (count < 0)
139+
{
140+
throw new ArgumentOutOfRangeException(nameof(count));
141+
}
142+
143+
if (index > list.Count - count)
144+
{
145+
throw new ArgumentException("The specified range of elements does not exist in the list.");
146+
}
147+
148+
SyntaxTrivia[] trivia = new SyntaxTrivia[list.Count - count];
149+
for (int i = 0; i < index; i++)
150+
{
151+
trivia[i] = list[i];
152+
}
153+
154+
for (int i = index; i + count < list.Count; i++)
155+
{
156+
trivia[i] = list[i + count];
157+
}
158+
159+
return SyntaxFactory.TriviaList(trivia);
160+
}
161+
115162
/// <summary>
116163
/// Returns the index of the last trivia of a specified kind in the trivia list.
117164
/// </summary>

StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1506CodeFixProvider.cs

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,32 +52,46 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
5252
var triviaList = token.LeadingTrivia;
5353

5454
var index = triviaList.IndexOf(SyntaxKind.SingleLineDocumentationCommentTrivia);
55-
for (; index < triviaList.Count - 1; index++)
56-
{
57-
if (triviaList[index].IsKind(SyntaxKind.SingleLineCommentTrivia)
58-
|| triviaList[index].IsKind(SyntaxKind.MultiLineCommentTrivia))
59-
{
60-
break;
61-
}
62-
}
6355

64-
while (!triviaList[index].IsKind(SyntaxKind.EndOfLineTrivia))
56+
int currentLineStart = index + 1;
57+
bool onBlankLine = true;
58+
for (int currentIndex = currentLineStart; currentIndex < triviaList.Count; currentIndex++)
6559
{
66-
index--;
67-
}
60+
switch (triviaList[currentIndex].Kind())
61+
{
62+
case SyntaxKind.EndOfLineTrivia:
63+
if (onBlankLine)
64+
{
65+
triviaList = triviaList.RemoveRange(currentLineStart, currentIndex - currentLineStart + 1);
66+
currentIndex = currentLineStart - 1;
67+
continue;
68+
}
69+
else
70+
{
71+
currentLineStart = currentIndex + 1;
72+
onBlankLine = true;
73+
break;
74+
}
6875

69-
var lastEndOfLine = index;
76+
case SyntaxKind.WhitespaceTrivia:
77+
break;
7078

71-
while (!triviaList[index].IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia))
72-
{
73-
index--;
79+
default:
80+
if (triviaList[currentIndex].HasBuiltinEndLine())
81+
{
82+
currentLineStart = currentIndex + 1;
83+
onBlankLine = true;
84+
break;
85+
}
86+
else
87+
{
88+
onBlankLine = false;
89+
break;
90+
}
91+
}
7492
}
7593

76-
var lastDocumentation = index;
77-
78-
var newLeadingTrivia = triviaList.Take(lastDocumentation + 1).Concat(triviaList.Skip(lastEndOfLine + 1));
79-
var newSyntaxRoot = syntaxRoot.ReplaceToken(token, token.WithLeadingTrivia(newLeadingTrivia));
80-
94+
var newSyntaxRoot = syntaxRoot.ReplaceToken(token, token.WithLeadingTrivia(triviaList));
8195
return document.WithSyntaxRoot(newSyntaxRoot);
8296
}
8397
}

0 commit comments

Comments
 (0)