Skip to content

Commit 584a021

Browse files
committed
Improved FixAll for TokenSpacingCodeFixProvider
1 parent 7e69f3e commit 584a021

7 files changed

Lines changed: 50 additions & 33 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/SpacingRules/TokenSpacingCodeFixProvider.cs

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace StyleCop.Analyzers.SpacingRules
55
{
6+
using System;
67
using System.Collections.Generic;
78
using System.Collections.Immutable;
89
using System.Composition;
@@ -122,7 +123,7 @@ private static void UpdateReplaceMap(Dictionary<SyntaxToken, SyntaxToken> replac
122123
case TokenSpacingProperties.ActionInsert:
123124
if (!replaceMap.ContainsKey(prevToken))
124125
{
125-
replaceMap[token] = token.WithLeadingTrivia(token.LeadingTrivia.Add(SyntaxFactory.Space));
126+
UpdateReplaceMap(replaceMap, token, t => t.WithLeadingTrivia(token.LeadingTrivia.Add(SyntaxFactory.Space)));
126127
}
127128

128129
break;
@@ -136,11 +137,12 @@ private static void UpdateReplaceMap(Dictionary<SyntaxToken, SyntaxToken> replac
136137
break;
137138
}
138139

139-
replaceMap[prevToken] = prevToken.WithTrailingTrivia();
140+
UpdateReplaceMap(replaceMap, prevToken, t => t.WithTrailingTrivia());
141+
140142
if ((!preserveLayout || !tokenIsFirstInLine)
141143
&& triviaList.All(i => i.IsKind(SyntaxKind.WhitespaceTrivia) || i.IsKind(SyntaxKind.EndOfLineTrivia)))
142144
{
143-
replaceMap[token] = token.WithLeadingTrivia();
145+
UpdateReplaceMap(replaceMap, token, t => token.WithLeadingTrivia());
144146
}
145147
else if (tokenIsFirstInLine && token.IsLastInLine())
146148
{
@@ -176,41 +178,29 @@ private static void UpdateReplaceMap(Dictionary<SyntaxToken, SyntaxToken> replac
176178
// firstNewLineFollowing was adjusted above to account for the missing case.
177179
trailingTrivia = trailingTrivia.AddRange(token.TrailingTrivia.Take(firstNewLineFollowing));
178180

179-
replaceMap[token] = token.WithLeadingTrivia().WithTrailingTrivia(trailingTrivia);
181+
UpdateReplaceMap(replaceMap, token, t => t.WithLeadingTrivia().WithTrailingTrivia(trailingTrivia));
180182
}
181183
else
182184
{
183185
// Just move the token and keep all surrounding trivia.
184186
SyntaxTriviaList trailingTrivia = triviaList.AddRange(token.TrailingTrivia);
185-
replaceMap[token] = token.WithLeadingTrivia().WithTrailingTrivia(trailingTrivia);
187+
UpdateReplaceMap(replaceMap, token, t => t.WithLeadingTrivia().WithTrailingTrivia(trailingTrivia));
186188
}
187189
}
188190
else
189191
{
190192
SyntaxTriviaList trailingTrivia = triviaList.AddRange(token.TrailingTrivia.WithoutLeadingWhitespace(endOfLineIsWhitespace: false));
191-
replaceMap[token] = token.WithLeadingTrivia().WithTrailingTrivia(trailingTrivia);
193+
UpdateReplaceMap(replaceMap, token, t => t.WithLeadingTrivia().WithTrailingTrivia(trailingTrivia));
192194
}
193195

194196
break;
195197

196198
case TokenSpacingProperties.ActionRemoveImmediate:
197-
SyntaxTriviaList tokenLeadingTrivia = token.LeadingTrivia;
198-
while (tokenLeadingTrivia.Any() && tokenLeadingTrivia.Last().IsKind(SyntaxKind.WhitespaceTrivia))
199-
{
200-
tokenLeadingTrivia = tokenLeadingTrivia.RemoveAt(tokenLeadingTrivia.Count - 1);
201-
}
202-
203-
replaceMap[token] = token.WithLeadingTrivia(tokenLeadingTrivia);
199+
UpdateReplaceMap(replaceMap, token, t => t.WithLeadingTrivia(token.LeadingTrivia.WithoutTrailingWhitespace(endOfLineIsWhitespace: false)));
204200

205-
if (!tokenLeadingTrivia.Any())
201+
if (!replaceMap[token].LeadingTrivia.Any())
206202
{
207-
SyntaxTriviaList previousTrailingTrivia = prevToken.TrailingTrivia;
208-
while (previousTrailingTrivia.Any() && previousTrailingTrivia.Last().IsKind(SyntaxKind.WhitespaceTrivia))
209-
{
210-
previousTrailingTrivia = previousTrailingTrivia.RemoveAt(previousTrailingTrivia.Count - 1);
211-
}
212-
213-
replaceMap[prevToken] = prevToken.WithTrailingTrivia(previousTrailingTrivia);
203+
UpdateReplaceMap(replaceMap, prevToken, t => t.WithTrailingTrivia(t.TrailingTrivia.WithoutTrailingWhitespace(endOfLineIsWhitespace: false)));
214204
}
215205

216206
break;
@@ -225,23 +215,40 @@ private static void UpdateReplaceMap(Dictionary<SyntaxToken, SyntaxToken> replac
225215
case TokenSpacingProperties.ActionInsert:
226216
if (!replaceMap.ContainsKey(nextToken))
227217
{
228-
replaceMap[token] = token.WithTrailingTrivia(token.TrailingTrivia.Insert(0, SyntaxFactory.Space));
218+
UpdateReplaceMap(replaceMap, token, t => t.WithTrailingTrivia(t.TrailingTrivia.Insert(0, SyntaxFactory.Space)));
229219
}
230220

231221
break;
232222

233223
case TokenSpacingProperties.ActionRemove:
234224
triviaList = token.TrailingTrivia.AddRange(nextToken.LeadingTrivia);
235225

236-
replaceMap[token] = token.WithTrailingTrivia();
237-
replaceMap[nextToken] = nextToken.WithLeadingTrivia(triviaList.WithoutLeadingWhitespace(true));
226+
UpdateReplaceMap(replaceMap, token, t => t.WithTrailingTrivia());
227+
UpdateReplaceMap(replaceMap, nextToken, t => t.WithLeadingTrivia(triviaList.WithoutLeadingWhitespace(true)));
238228
break;
239229
}
240230

241231
break;
242232
}
243233
}
244234

235+
private static void UpdateReplaceMap(Dictionary<SyntaxToken, SyntaxToken> replaceMap, SyntaxToken token, Func<SyntaxToken, SyntaxToken> action)
236+
{
237+
SyntaxToken existingReplacement;
238+
SyntaxToken newReplacement;
239+
240+
if (replaceMap.TryGetValue(token, out existingReplacement))
241+
{
242+
newReplacement = action(existingReplacement);
243+
}
244+
else
245+
{
246+
newReplacement = action(token);
247+
}
248+
249+
replaceMap[token] = newReplacement;
250+
}
251+
245252
private class FixAll : DocumentBasedFixAllProvider
246253
{
247254
public static FixAllProvider Instance { get; } = new FixAll();

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/NumberSignSpacingTestBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ void Foo()
194194
};
195195

196196
await this.VerifyCSharpDiagnosticAsync(test, expected, CancellationToken.None).ConfigureAwait(false);
197-
await this.VerifyCSharpFixAsync(test, fixedTest, numberOfFixAllIterations: 2, cancellationToken: CancellationToken.None).ConfigureAwait(false);
197+
await this.VerifyCSharpFixAsync(test, fixedTest, cancellationToken: CancellationToken.None).ConfigureAwait(false);
198198
}
199199

200200
[Fact]

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1008UnitTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,7 @@ public void TestMethod(int x, int y)
14541454

14551455
await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostics, CancellationToken.None).ConfigureAwait(false);
14561456
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
1457-
await this.VerifyCSharpFixAsync(testCode, fixedTestCode, numberOfFixAllIterations: 2, cancellationToken: CancellationToken.None).ConfigureAwait(false);
1457+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
14581458
}
14591459

14601460
/// <summary>

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1012UnitTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public class TestClass
158158

159159
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
160160
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
161-
await this.VerifyCSharpFixAsync(testCode, fixedCode, numberOfFixAllIterations: 2, cancellationToken: CancellationToken.None).ConfigureAwait(false);
161+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
162162
}
163163

164164
/// <summary>
@@ -218,7 +218,7 @@ public void TestMethod()
218218

219219
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
220220
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
221-
await this.VerifyCSharpFixAsync(testCode, fixedCode, numberOfFixAllIterations: 2, cancellationToken: CancellationToken.None).ConfigureAwait(false);
221+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
222222
}
223223

224224
[Fact]

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1013UnitTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ public void TestMethod()
186186

187187
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
188188
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
189-
await this.VerifyCSharpFixAsync(testCode, fixedCode, numberOfFixAllIterations: 2, cancellationToken: CancellationToken.None).ConfigureAwait(false);
189+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
190190
}
191191

192192
/// <summary>

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1024UnitTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ private int Bar(int value)
306306

307307
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
308308
await this.VerifyCSharpDiagnosticAsync(ExpectedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
309-
await this.VerifyCSharpFixAsync(testCode, ExpectedCode, numberOfFixAllIterations: 2, cancellationToken: CancellationToken.None).ConfigureAwait(false);
309+
await this.VerifyCSharpFixAsync(testCode, ExpectedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
310310
}
311311

312312
/// <inheritdoc/>

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,10 @@ internal static int IndexOfFirstNonBlankLineTrivia<T>(T triviaList)
8080
/// </summary>
8181
/// <param name="triviaList">The trivia list to process.</param>
8282
/// <typeparam name="T">The type of the trivia list.</typeparam>
83+
/// <param name="endOfLineIsWhitespace"><see langword="true"/> to treat <see cref="SyntaxKind.EndOfLineTrivia"/>
84+
/// as whitespace; otherwise, <see langword="false"/>.</param>
8385
/// <returns>The index where the trailing whitespace starts, or -1 if there is no trailing whitespace.</returns>
84-
internal static int IndexOfTrailingWhitespace<T>(T triviaList)
86+
internal static int IndexOfTrailingWhitespace<T>(T triviaList, bool endOfLineIsWhitespace = true)
8587
where T : IReadOnlyList<SyntaxTrivia>
8688
{
8789
var done = false;
@@ -94,6 +96,12 @@ internal static int IndexOfTrailingWhitespace<T>(T triviaList)
9496
switch (currentTrivia.Kind())
9597
{
9698
case SyntaxKind.EndOfLineTrivia:
99+
if (!endOfLineIsWhitespace)
100+
{
101+
done = true;
102+
break;
103+
}
104+
97105
whiteSpaceStartIndex = index;
98106
previousTriviaWasEndOfLine = true;
99107
break;
@@ -206,10 +214,12 @@ internal static int LastIndexOf(this SyntaxTriviaList list, SyntaxKind kind)
206214
/// Strips all trailing whitespace trivia from the trivia list until a non-whitespace trivia is encountered.
207215
/// </summary>
208216
/// <param name="triviaList">The trivia list to strip of its trailing whitespace.</param>
217+
/// <param name="endOfLineIsWhitespace"><see langword="true"/> to treat <see cref="SyntaxKind.EndOfLineTrivia"/>
218+
/// as whitespace; otherwise, <see langword="false"/>.</param>
209219
/// <returns>The modified triviaList.</returns>
210-
internal static SyntaxTriviaList WithoutTrailingWhitespace(this SyntaxTriviaList triviaList)
220+
internal static SyntaxTriviaList WithoutTrailingWhitespace(this SyntaxTriviaList triviaList, bool endOfLineIsWhitespace = true)
211221
{
212-
var trailingWhitespaceIndex = IndexOfTrailingWhitespace(triviaList);
222+
var trailingWhitespaceIndex = IndexOfTrailingWhitespace(triviaList, endOfLineIsWhitespace);
213223
return (trailingWhitespaceIndex >= 0) ? SyntaxFactory.TriviaList(triviaList.Take(trailingWhitespaceIndex)) : triviaList;
214224
}
215225

0 commit comments

Comments
 (0)