Skip to content

Commit bf34aa9

Browse files
committed
Treat ';' and ',' as typos for SA1629 code fix
1 parent b15704e commit bf34aa9

File tree

3 files changed

+80
-3
lines changed

3 files changed

+80
-3
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/SA1629CodeFixProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
5252
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
5353
{
5454
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
55-
var newText = text.WithChanges(new TextChange(new TextSpan(diagnostic.Location.SourceSpan.Start, 0), "."));
55+
bool replaceChar = diagnostic.Properties.ContainsKey(SA1629DocumentationTextMustEndWithAPeriod.ReplaceCharKey);
56+
var newText = text.WithChanges(new TextChange(new TextSpan(diagnostic.Location.SourceSpan.Start, replaceChar ? 1 : 0), "."));
5657

5758
return document.WithText(newText);
5859
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1629UnitTests.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,58 @@ public interface ITest
476476
await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, CancellationToken.None).ConfigureAwait(false);
477477
}
478478

479+
[Theory]
480+
[InlineData(",")]
481+
[InlineData(";")]
482+
public async Task TestSentenceEndingWithTypoAsync(string typo)
483+
{
484+
var testCode = $@"
485+
/// <summary>
486+
/// Summary{typo}
487+
/// </summary>
488+
public interface ITest
489+
{{
490+
}}
491+
";
492+
var fixedTestCode = $@"
493+
/// <summary>
494+
/// Summary.
495+
/// </summary>
496+
public interface ITest
497+
{{
498+
}}
499+
";
500+
501+
DiagnosticResult expected = Diagnostic().WithLocation(3, 12);
502+
await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, default).ConfigureAwait(false);
503+
}
504+
505+
[Theory]
506+
[InlineData(",")]
507+
[InlineData(";")]
508+
public async Task TestSentenceEndingWithTypoAndParenthesisAsync(string typo)
509+
{
510+
var testCode = $@"
511+
/// <summary>
512+
/// Summary (for example{typo})
513+
/// </summary>
514+
public interface ITest
515+
{{
516+
}}
517+
";
518+
var fixedTestCode = $@"
519+
/// <summary>
520+
/// Summary (for example.)
521+
/// </summary>
522+
public interface ITest
523+
{{
524+
}}
525+
";
526+
527+
DiagnosticResult expected = Diagnostic().WithLocation(3, 25);
528+
await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, default).ConfigureAwait(false);
529+
}
530+
479531
[Fact]
480532
public async Task TestMultipleParagraphBlocksAsync()
481533
{

StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1629DocumentationTextMustEndWithAPeriod.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ internal class SA1629DocumentationTextMustEndWithAPeriod : ElementDocumentationB
5252
/// </summary>
5353
internal const string NoCodeFixKey = "NoCodeFix";
5454

55+
internal const string ReplaceCharKey = "CharToReplace";
56+
5557
private const string HelpLink = "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1629.md";
5658
private static readonly LocalizableString Title = new LocalizableResourceString(nameof(DocumentationResources.SA1629Title), DocumentationResources.ResourceManager, typeof(DocumentationResources));
5759
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(DocumentationResources.SA1629MessageFormat), DocumentationResources.ResourceManager, typeof(DocumentationResources));
@@ -128,8 +130,30 @@ private static void HandleSectionOrBlockXmlElement(SyntaxNodeAnalysisContext con
128130
&& (startingWithFinalParagraph || !textWithoutTrailingWhitespace.EndsWith(":", StringComparison.Ordinal))
129131
&& !textWithoutTrailingWhitespace.EndsWith("-or-", StringComparison.Ordinal))
130132
{
131-
var location = Location.Create(xmlElement.SyntaxTree, new TextSpan(textToken.SpanStart + textWithoutTrailingWhitespace.Length, 1));
132-
context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
133+
int spanStart = textToken.SpanStart + textWithoutTrailingWhitespace.Length;
134+
ImmutableDictionary<string, string> properties = null;
135+
if (textWithoutTrailingWhitespace.EndsWith(",", StringComparison.Ordinal)
136+
|| textWithoutTrailingWhitespace.EndsWith(";", StringComparison.Ordinal))
137+
{
138+
spanStart -= 1;
139+
SetReplaceChar();
140+
}
141+
else if (textWithoutTrailingWhitespace.EndsWith(",)", StringComparison.Ordinal)
142+
|| textWithoutTrailingWhitespace.EndsWith(";)", StringComparison.Ordinal))
143+
{
144+
spanStart -= 2;
145+
SetReplaceChar();
146+
}
147+
148+
var location = Location.Create(xmlElement.SyntaxTree, new TextSpan(spanStart, 1));
149+
context.ReportDiagnostic(Diagnostic.Create(Descriptor, location, properties));
150+
151+
void SetReplaceChar()
152+
{
153+
var propertiesBuilder = ImmutableDictionary.CreateBuilder<string, string>();
154+
propertiesBuilder.Add(ReplaceCharKey, string.Empty);
155+
properties = propertiesBuilder.ToImmutable();
156+
}
133157
}
134158

135159
currentParagraphDone = true;

0 commit comments

Comments
 (0)