Skip to content

Commit 2c4e1ca

Browse files
committed
Updated SA1610
1 parent c8903b3 commit 2c4e1ca

2 files changed

Lines changed: 165 additions & 2 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1610UnitTests.cs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ namespace StyleCop.Analyzers.Test.DocumentationRules
66
using System.Collections.Generic;
77
using System.Threading;
88
using System.Threading.Tasks;
9+
using Helpers;
10+
using Microsoft.CodeAnalysis;
911
using Microsoft.CodeAnalysis.CodeFixes;
1012
using Microsoft.CodeAnalysis.Diagnostics;
1113
using StyleCop.Analyzers.DocumentationRules;
@@ -280,6 +282,141 @@ public class ClassName
280282
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
281283
}
282284

285+
/// <summary>
286+
/// Verifies that included property documentation will be accepted.
287+
/// </summary>
288+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
289+
[Fact]
290+
public async Task TestPropertyWithValidIncludeAsync()
291+
{
292+
var testCode = @"
293+
public class ClassName
294+
{
295+
/// <include file='PropertyWithValue.xml' path='/ClassName/Property/*'/>
296+
public int Property
297+
{
298+
get;
299+
}
300+
}";
301+
302+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
303+
}
304+
305+
/// <summary>
306+
/// Verifies that included property documentation without a value tag will be accepted (this is handled by SA1609).
307+
/// </summary>
308+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
309+
[Fact]
310+
public async Task TestPropertyWithoutValueInIncludeAsync()
311+
{
312+
var testCode = @"
313+
public class ClassName
314+
{
315+
/// <include file='PropertyWithoutValue.xml' path='/ClassName/Property/*'/>
316+
public int Property
317+
{
318+
get;
319+
}
320+
}";
321+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
322+
}
323+
324+
/// <summary>
325+
/// Verifies that included property documentation with an empty value tag will be flagged.
326+
/// </summary>
327+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
328+
[Fact]
329+
public async Task TestPropertyWithEmptyValueInIncludeAsync()
330+
{
331+
var testCode = @"
332+
public class ClassName
333+
{
334+
/// <include file='PropertyWithEmptyValue.xml' path='/ClassName/Property/*'/>
335+
public int Property
336+
{
337+
get;
338+
}
339+
}";
340+
var expected = this.CSharpDiagnostic().WithLocation(5, 16);
341+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
342+
}
343+
344+
/// <summary>
345+
/// Verifies that included property documentation containing &gt;inheritdoc/&lt; will be accepted.
346+
/// </summary>
347+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
348+
[Fact]
349+
public async Task TestPropertyWithInheritdocInIncludeAsync()
350+
{
351+
var testCode = @"
352+
public interface ITestInterface
353+
{
354+
/// <summary>
355+
/// Gets the test property value.
356+
/// </summary>
357+
/// <value>Test number.</value>
358+
int Property { get; }
359+
}
360+
361+
public class ClassName : ITestInterface
362+
{
363+
/// <include file='PropertyWithInheritdoc.xml' path='/ClassName/Property/*'/>
364+
public int Property
365+
{
366+
get;
367+
}
368+
}";
369+
370+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
371+
}
372+
373+
protected override Project ApplyCompilationOptions(Project project)
374+
{
375+
var resolver = new TestXmlReferenceResolver();
376+
377+
string contentWithValue = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
378+
<ClassName>
379+
<Property>
380+
<summary>Foo</summary>
381+
<value>Bar</value>
382+
</Property>
383+
</ClassName>
384+
";
385+
resolver.XmlReferences.Add("PropertyWithValue.xml", contentWithValue);
386+
387+
string contentWithoutValue = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
388+
<ClassName>
389+
<Property>
390+
<summary>Foo</summary>
391+
</Property>
392+
</ClassName>
393+
";
394+
resolver.XmlReferences.Add("PropertyWithoutValue.xml", contentWithoutValue);
395+
396+
string contentWithEmptyValue = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
397+
<ClassName>
398+
<Property>
399+
<summary>Foo</summary>
400+
<value> </value>
401+
</Property>
402+
</ClassName>
403+
";
404+
resolver.XmlReferences.Add("PropertyWithEmptyValue.xml", contentWithEmptyValue);
405+
406+
string contentWithInheritdocValue = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
407+
<ClassName>
408+
<Property>
409+
<inheritdoc/>
410+
</Property>
411+
</ClassName>
412+
";
413+
resolver.XmlReferences.Add("PropertyWithInheritdoc.xml", contentWithInheritdocValue);
414+
415+
project = base.ApplyCompilationOptions(project);
416+
project = project.WithCompilationOptions(project.CompilationOptions.WithXmlReferenceResolver(resolver));
417+
return project;
418+
}
419+
283420
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
284421
{
285422
yield return new SA1610PropertyDocumentationMustHaveValueText();

StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1610PropertyDocumentationMustHaveValueText.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace StyleCop.Analyzers.DocumentationRules
55
{
66
using System.Collections.Immutable;
7+
using System.Linq;
78
using System.Xml.Linq;
89
using Helpers;
910
using Microsoft.CodeAnalysis;
@@ -50,10 +51,35 @@ internal class SA1610PropertyDocumentationMustHaveValueText : PropertyDocumentat
5051
/// <inheritdoc/>
5152
protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, XmlNodeSyntax syntax, XElement completeDocumentation, Location diagnosticLocation)
5253
{
53-
if (syntax != null && XmlCommentHelper.IsConsideredEmpty(syntax))
54+
if (completeDocumentation != null)
5455
{
55-
context.ReportDiagnostic(Diagnostic.Create(Descriptor, diagnosticLocation));
56+
var valueTag = completeDocumentation.Nodes().OfType<XElement>().FirstOrDefault(element => element.Name == XmlCommentHelper.ValueXmlTag);
57+
if (valueTag == null)
58+
{
59+
// handled by SA1609
60+
return;
61+
}
62+
63+
if (!XmlCommentHelper.IsConsideredEmpty(valueTag))
64+
{
65+
return;
66+
}
5667
}
68+
else
69+
{
70+
if (syntax == null)
71+
{
72+
// Handled by SA1609
73+
return;
74+
}
75+
76+
if (!XmlCommentHelper.IsConsideredEmpty(syntax))
77+
{
78+
return;
79+
}
80+
}
81+
82+
context.ReportDiagnostic(Diagnostic.Create(Descriptor, diagnosticLocation));
5783
}
5884
}
5985
}

0 commit comments

Comments
 (0)