Skip to content

Commit 1ee512c

Browse files
authored
Merge pull request #3174 from angelobreuer/fix-3173
#3173 - SA1611 ignores included documentation
2 parents f2d4dd7 + 64de324 commit 1ee512c

File tree

2 files changed

+83
-22
lines changed

2 files changed

+83
-22
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1611UnitTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,55 @@ public void TestMethod(string param1, string param2, string param3)
313313
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
314314
}
315315

316+
/// <summary>
317+
/// Verifies that included documentation with missing elements documented produces the expected diagnostics.
318+
/// </summary>
319+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
320+
[Fact]
321+
public async Task VerifyIncludedPartialDocumentationMissingElementsAsync()
322+
{
323+
var testCode = @"
324+
/// <summary>
325+
/// Foo
326+
/// </summary>
327+
public class ClassName
328+
{
329+
/// <include file='WithPartialElementDocumentation.xml' path='/TestClass/TestMethod/*' />
330+
public void TestMethod(string param1, string param2, string param3)
331+
{
332+
}
333+
}";
334+
DiagnosticResult[] expected =
335+
{
336+
Diagnostic().WithLocation(8, 35).WithArguments("param1"),
337+
};
338+
339+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
340+
}
341+
342+
/// <summary>
343+
/// Verifies that included documentation with missing elements documented produces the expected diagnostics.
344+
/// </summary>
345+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
346+
[Fact]
347+
public async Task VerifyIncludedPartialDocumentationElementsAsync()
348+
{
349+
var testCode = @"
350+
/// <summary>
351+
/// Foo
352+
/// </summary>
353+
public class ClassName
354+
{
355+
/// <param name=""param1"">Param 1</param>
356+
/// <include file='WithPartialElementDocumentation.xml' path='/TestClass/TestMethod/*' />
357+
public void TestMethod(string param1, string param2, string param3)
358+
{
359+
}
360+
}";
361+
362+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
363+
}
364+
316365
/// <summary>
317366
/// Verifies that included documentation with an <c>&lt;inheritdoc&gt;</c> tag is ignored.
318367
/// </summary>
@@ -356,6 +405,17 @@ private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[
356405
<param name=""param3"">Param 3</param>
357406
</TestMethod>
358407
</TestClass>
408+
";
409+
string contentWithPartialElementDocumentation = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
410+
<TestClass>
411+
<TestMethod>
412+
<summary>
413+
Foo
414+
</summary>
415+
<param name=""param2"">Param 2</param>
416+
<param name=""param3"">Param 3</param>
417+
</TestMethod>
418+
</TestClass>
359419
";
360420
string contentWithInheritedDocumentation = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
361421
<TestClass>
@@ -372,6 +432,7 @@ private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[
372432
{
373433
{ "MissingElementDocumentation.xml", contentWithoutElementDocumentation },
374434
{ "WithElementDocumentation.xml", contentWithElementDocumentation },
435+
{ "WithPartialElementDocumentation.xml", contentWithPartialElementDocumentation },
375436
{ "InheritedDocumentation.xml", contentWithInheritedDocumentation },
376437
},
377438
};

StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/ElementDocumentationBase.cs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -229,34 +229,34 @@ private void HandleDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettin
229229
return;
230230
}
231231

232-
IEnumerable<XmlNodeSyntax> matchingXmlElements = string.IsNullOrEmpty(this.matchElementName)
233-
? documentation.Content
234-
.Where(x => x is XmlElementSyntax || x is XmlEmptyElementSyntax)
235-
.Where(x => !string.Equals(x.GetName()?.ToString(), XmlCommentHelper.IncludeXmlTag, StringComparison.Ordinal))
236-
: documentation.Content.GetXmlElements(this.matchElementName);
232+
var hasIncludedDocumentation =
233+
documentation.Content.GetFirstXmlElement(XmlCommentHelper.IncludeXmlTag) is object;
237234

238-
if (!matchingXmlElements.Any())
235+
if (hasIncludedDocumentation)
239236
{
240-
var includedDocumentation = documentation.Content.GetFirstXmlElement(XmlCommentHelper.IncludeXmlTag);
241-
if (includedDocumentation != null)
237+
var declaration = context.SemanticModel.GetDeclaredSymbol(node, context.CancellationToken);
238+
var rawDocumentation = declaration?.GetDocumentationCommentXml(expandIncludes: true, cancellationToken: context.CancellationToken);
239+
var completeDocumentation = XElement.Parse(rawDocumentation, LoadOptions.None);
240+
241+
if (this.inheritDocSuppressesWarnings &&
242+
completeDocumentation.Nodes().OfType<XElement>().Any(element => element.Name == XmlCommentHelper.InheritdocXmlTag))
242243
{
243-
var declaration = context.SemanticModel.GetDeclaredSymbol(node, context.CancellationToken);
244-
var rawDocumentation = declaration?.GetDocumentationCommentXml(expandIncludes: true, cancellationToken: context.CancellationToken);
245-
var completeDocumentation = XElement.Parse(rawDocumentation, LoadOptions.None);
246-
247-
if (this.inheritDocSuppressesWarnings &&
248-
completeDocumentation.Nodes().OfType<XElement>().Any(element => element.Name == XmlCommentHelper.InheritdocXmlTag))
249-
{
250-
// Ignore nodes with an <inheritdoc/> tag in the included XML.
251-
return;
252-
}
253-
254-
this.HandleCompleteDocumentation(context, needsComment, completeDocumentation, locations);
255-
return; // done
244+
// Ignore nodes with an <inheritdoc/> tag in the included XML.
245+
return;
256246
}
247+
248+
this.HandleCompleteDocumentation(context, needsComment, completeDocumentation, locations);
257249
}
250+
else
251+
{
252+
IEnumerable<XmlNodeSyntax> matchingXmlElements = string.IsNullOrEmpty(this.matchElementName)
253+
? documentation.Content
254+
.Where(x => x is XmlElementSyntax || x is XmlEmptyElementSyntax)
255+
.Where(x => !string.Equals(x.GetName()?.ToString(), XmlCommentHelper.IncludeXmlTag, StringComparison.Ordinal))
256+
: documentation.Content.GetXmlElements(this.matchElementName);
258257

259-
this.HandleXmlElement(context, settings, needsComment, matchingXmlElements, locations);
258+
this.HandleXmlElement(context, settings, needsComment, matchingXmlElements, locations);
259+
}
260260
}
261261
}
262262
}

0 commit comments

Comments
 (0)