Skip to content

Commit 65bdc27

Browse files
committed
Avoid reporting SA1629 inside 'seealso' elements
Closes #2679
1 parent 8aa1cd3 commit 65bdc27

4 files changed

Lines changed: 76 additions & 5 deletions

File tree

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,37 @@ public interface ITest
336336
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
337337
}
338338

339+
[Fact]
340+
[WorkItem(2679, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2679")]
341+
public async Task TestElementsThatDoNotRequirePeriodsAsync()
342+
{
343+
var testCode = @"
344+
/// <summary>
345+
/// Test interface <see cref=""ITest"">a see element</see>
346+
/// </summary>
347+
/// <seealso href=""https://docs.microsoft.com/en-us/dotnet/framework/wpf/index"">Windows Presentation Foundation</seealso>
348+
public interface ITest
349+
{
350+
}
351+
";
352+
353+
var fixedTestCode = @"
354+
/// <summary>
355+
/// Test interface <see cref=""ITest"">a see element</see>.
356+
/// </summary>
357+
/// <seealso href=""https://docs.microsoft.com/en-us/dotnet/framework/wpf/index"">Windows Presentation Foundation</seealso>
358+
public interface ITest
359+
{
360+
}
361+
";
362+
363+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(3, 57);
364+
365+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
366+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
367+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
368+
}
369+
339370
protected override Project ApplyCompilationOptions(Project project)
340371
{
341372
var resolver = new TestXmlReferenceResolver();

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace StyleCop.Analyzers.DocumentationRules
1212
using Microsoft.CodeAnalysis.CSharp.Syntax;
1313
using Microsoft.CodeAnalysis.Diagnostics;
1414
using Microsoft.CodeAnalysis.Text;
15+
using StyleCop.Analyzers.Helpers;
1516

1617
/// <summary>
1718
/// A section of the XML header documentation for a C# element does not end with a period (also known as a full
@@ -77,6 +78,11 @@ protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, bool
7778
{
7879
foreach (var xmlElement in syntaxList.OfType<XmlElementSyntax>())
7980
{
81+
if (xmlElement.StartTag?.Name?.LocalName.ValueText == XmlCommentHelper.SeeAlsoXmlTag)
82+
{
83+
continue;
84+
}
85+
8086
var elementDone = false;
8187
int? reportingLocation = null;
8288
for (var i = xmlElement.Content.Count - 1; !elementDone && (i >= 0); i--)
@@ -100,11 +106,11 @@ protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, bool
100106
}
101107
}
102108
}
103-
else if (xmlElement.Content[i] is XmlEmptyElementSyntax emptyElement)
109+
else if (xmlElement.Content[i].IsInlineElement())
104110
{
105-
// If a diagnostic gets reported for the element, place the diagnostic after the last empty
111+
// If a diagnostic gets reported for the element, place the diagnostic after the last inline
106112
// element.
107-
reportingLocation = emptyElement.Span.End;
113+
reportingLocation = xmlElement.Content[i].Span.End;
108114
}
109115
}
110116
}

StyleCop.Analyzers/StyleCop.Analyzers/Helpers/XmlCommentHelper.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@ internal static class XmlCommentHelper
2121
internal const string InheritdocXmlTag = "inheritdoc";
2222
internal const string ReturnsXmlTag = "returns";
2323
internal const string ValueXmlTag = "value";
24+
internal const string CXmlTag = "c";
2425
internal const string SeeXmlTag = "see";
26+
internal const string SeeAlsoXmlTag = "seealso";
2527
internal const string ParamXmlTag = "param";
28+
internal const string ParamRefXmlTag = "paramref";
2629
internal const string TypeParamXmlTag = "typeparam";
30+
internal const string TypeParamRefXmlTag = "typeparamref";
2731
internal const string RemarksXmlTag = "remarks";
2832
internal const string ExampleXmlTag = "example";
2933
internal const string PermissionXmlTag = "permission";
@@ -264,5 +268,35 @@ internal static T GetFirstAttributeOrDefault<T>(XmlNodeSyntax nodeSyntax)
264268

265269
return null;
266270
}
271+
272+
internal static bool IsInlineElement(this XmlNodeSyntax nodeSyntax)
273+
{
274+
if (nodeSyntax is XmlEmptyElementSyntax emptyElementSyntax)
275+
{
276+
return IsInlineElement(emptyElementSyntax.Name?.LocalName.ValueText);
277+
}
278+
279+
if (nodeSyntax is XmlElementSyntax elementSyntax)
280+
{
281+
return IsInlineElement(elementSyntax.StartTag?.Name?.LocalName.ValueText);
282+
}
283+
284+
return false;
285+
}
286+
287+
private static bool IsInlineElement(string localName)
288+
{
289+
switch (localName)
290+
{
291+
case CXmlTag:
292+
case ParamRefXmlTag:
293+
case SeeXmlTag:
294+
case TypeParamRefXmlTag:
295+
return true;
296+
297+
default:
298+
return false;
299+
}
300+
}
267301
}
268302
}

StyleCop.Analyzers/StyleCop.Analyzers/Helpers/XmlSyntaxFactory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,12 @@ public static XmlEmptyElementSyntax SeeElement(CrefSyntax cref)
256256

257257
public static XmlEmptyElementSyntax SeeAlsoElement(CrefSyntax cref)
258258
{
259-
return EmptyElement("seealso").AddAttributes(CrefAttribute(cref));
259+
return EmptyElement(XmlCommentHelper.SeeAlsoXmlTag).AddAttributes(CrefAttribute(cref));
260260
}
261261

262262
public static XmlElementSyntax SeeAlsoElement(Uri linkAddress, SyntaxList<XmlNodeSyntax> linkText)
263263
{
264-
XmlElementSyntax element = Element("seealso", linkText);
264+
XmlElementSyntax element = Element(XmlCommentHelper.SeeAlsoXmlTag, linkText);
265265
return element.WithStartTag(element.StartTag.AddAttributes(TextAttribute("href", linkAddress.ToString())));
266266
}
267267

0 commit comments

Comments
 (0)