Skip to content

Commit 3e2e37f

Browse files
committed
Update SA1129 CancellationToken handling to properly qualify member access
1 parent 392e70f commit 3e2e37f

2 files changed

Lines changed: 44 additions & 6 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1129CodeFixProvider.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,13 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
5858
private static SyntaxNode GetReplacementNode(SyntaxNode node)
5959
{
6060
var newExpression = (ObjectCreationExpressionSyntax)node;
61-
var identifierName = (newExpression.Type as IdentifierNameSyntax)
62-
?.Identifier.Text;
61+
var nameSyntax = newExpression.Type as NameSyntax;
62+
var identifierName = NameSyntaxHelpers.ToNormalizedString(nameSyntax);
6363

6464
SyntaxNode replacement = null;
65-
if (identifierName.Equals(nameof(CancellationToken), System.StringComparison.OrdinalIgnoreCase))
65+
if (identifierName.EndsWith(nameof(CancellationToken), System.StringComparison.OrdinalIgnoreCase))
6666
{
67-
replacement = GetCancellationTokenNoneSyntax();
67+
replacement = GetCancellationTokenNoneSyntax(nameSyntax);
6868
}
6969
else
7070
{
@@ -76,11 +76,11 @@ private static SyntaxNode GetReplacementNode(SyntaxNode node)
7676
.WithTrailingTrivia(newExpression.GetTrailingTrivia());
7777
}
7878

79-
private static SyntaxNode GetCancellationTokenNoneSyntax()
79+
private static SyntaxNode GetCancellationTokenNoneSyntax(NameSyntax nameSyntax)
8080
{
8181
return SyntaxFactory.MemberAccessExpression(
8282
SyntaxKind.SimpleMemberAccessExpression,
83-
SyntaxFactory.IdentifierName(nameof(CancellationToken)),
83+
nameSyntax,
8484
SyntaxFactory.IdentifierName(nameof(CancellationToken.None)));
8585
}
8686

StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1129UnitTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,44 @@ public void TestMethod()
319319
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
320320
}
321321

322+
/// <summary>
323+
/// Verifies that <c>new CancellationToken()</c> is replaced by <c>CancellationToken.None</c>,
324+
/// and a fully-qualified name is preserved correctly.
325+
/// </summary>
326+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
327+
[Fact]
328+
public async Task VerifyQualifiedCancellationTokenFixUsesNoneSyntaxAsync()
329+
{
330+
var testCode = @"
331+
public class TestClass
332+
{
333+
public void TestMethod()
334+
{
335+
var ct = new System.Threading.CancellationToken();
336+
}
337+
}
338+
";
339+
340+
var fixedTestCode = @"
341+
public class TestClass
342+
{
343+
public void TestMethod()
344+
{
345+
var ct = System.Threading.CancellationToken.None;
346+
}
347+
}
348+
";
349+
350+
DiagnosticResult[] expected =
351+
{
352+
this.CSharpDiagnostic().WithLocation(6, 18),
353+
};
354+
355+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
356+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
357+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
358+
}
359+
322360
/// <inheritdoc/>
323361
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
324362
{

0 commit comments

Comments
 (0)