Skip to content

Commit 35c0aff

Browse files
committed
Merge pull request #1898 from sharwell/fix-1603
Fix handling of <include> elements in documentation
2 parents b2c2f3b + cd7b0db commit 35c0aff

10 files changed

Lines changed: 478 additions & 16 deletions

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1604UnitTests.cs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ namespace StyleCop.Analyzers.Test.DocumentationRules
66
using System.Collections.Generic;
77
using System.Threading;
88
using System.Threading.Tasks;
9+
using Microsoft.CodeAnalysis;
910
using Microsoft.CodeAnalysis.Diagnostics;
1011
using StyleCop.Analyzers.DocumentationRules;
12+
using StyleCop.Analyzers.Test.Helpers;
1113
using TestHelper;
1214
using Xunit;
1315

@@ -669,6 +671,100 @@ event System.Action Foo { add { } remove { } }
669671
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
670672
}
671673

674+
[Fact]
675+
public async Task TestIncludedDocumentationAsync()
676+
{
677+
var testCode = @"
678+
class Class1
679+
{
680+
/// <include file='ClassWithoutSummary.xml' path='/Class1/MethodName/*'/>
681+
public void MethodName()
682+
{
683+
}
684+
}
685+
";
686+
687+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(5, 17);
688+
689+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
690+
}
691+
692+
[Fact]
693+
public async Task TestIncludedInheritedDocumentationAsync()
694+
{
695+
var testCode = @"
696+
class Class1
697+
{
698+
/// <include file='ClassWithInheritedSummary.xml' path='/Class1/MethodName/*'/>
699+
public void MethodName()
700+
{
701+
}
702+
}
703+
";
704+
705+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
706+
}
707+
708+
[Fact]
709+
public async Task TestIncludedIncompleteDocumentationAsync()
710+
{
711+
var testCode = @"
712+
class Class1
713+
{
714+
/// <include file='ClassWithSummary.xml' path='/Class1/MethodName/*'/>
715+
public void MethodName()
716+
{
717+
}
718+
}
719+
";
720+
721+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
722+
}
723+
724+
/// <inheritdoc/>
725+
protected override Project CreateProject(string[] sources, string language = "C#", string[] filenames = null)
726+
{
727+
var resolver = new TestXmlReferenceResolver();
728+
string contentWithSummary = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
729+
<Class1>
730+
<MethodName>
731+
<summary>
732+
Sample method.
733+
</summary>
734+
<returns>
735+
A <see cref=""Task""/> representing the asynchronous operation.
736+
</returns>
737+
</MethodName>
738+
</Class1>
739+
";
740+
resolver.XmlReferences.Add("ClassWithSummary.xml", contentWithSummary);
741+
742+
string contentWithInheritedSummary = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
743+
<Class1>
744+
<MethodName>
745+
<inheritdoc/>
746+
</MethodName>
747+
</Class1>
748+
";
749+
resolver.XmlReferences.Add("ClassWithInheritedSummary.xml", contentWithInheritedSummary);
750+
751+
string contentWithoutSummary = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
752+
<Class1>
753+
<MethodName>
754+
<returns>
755+
A <see cref=""Task""/> representing the asynchronous operation.
756+
</returns>
757+
</MethodName>
758+
</Class1>
759+
";
760+
resolver.XmlReferences.Add("ClassWithoutSummary.xml", contentWithoutSummary);
761+
762+
Project project = base.CreateProject(sources, language, filenames);
763+
project = project.WithCompilationOptions(project.CompilationOptions.WithXmlReferenceResolver(resolver));
764+
return project;
765+
}
766+
767+
/// <inheritdoc/>
672768
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
673769
{
674770
yield return new SA1604ElementDocumentationMustHaveSummary();

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1606UnitTests.cs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ namespace StyleCop.Analyzers.Test.DocumentationRules
66
using System.Collections.Generic;
77
using System.Threading;
88
using System.Threading.Tasks;
9+
using Microsoft.CodeAnalysis;
910
using Microsoft.CodeAnalysis.Diagnostics;
1011
using StyleCop.Analyzers.DocumentationRules;
12+
using StyleCop.Analyzers.Test.Helpers;
1113
using TestHelper;
1214
using Xunit;
1315

@@ -693,6 +695,101 @@ event System.Action Foo { add { } remove { } }
693695
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
694696
}
695697

698+
[Fact]
699+
public async Task TestIncludedDocumentationAsync()
700+
{
701+
var testCode = @"
702+
class Class1
703+
{
704+
/// <include file='ClassWithEmptySummary.xml' path='/Class1/MethodName/*'/>
705+
public void MethodName()
706+
{
707+
}
708+
}
709+
";
710+
711+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(5, 17);
712+
713+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
714+
}
715+
716+
[Fact]
717+
public async Task TestIncludedInheritedDocumentationAsync()
718+
{
719+
var testCode = @"
720+
class Class1
721+
{
722+
/// <include file='ClassWithInheritedSummary.xml' path='/Class1/MethodName/*'/>
723+
public void MethodName()
724+
{
725+
}
726+
}
727+
";
728+
729+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
730+
}
731+
732+
[Fact]
733+
public async Task TestIncludedIncompleteDocumentationAsync()
734+
{
735+
var testCode = @"
736+
class Class1
737+
{
738+
/// <include file='ClassWithSummary.xml' path='/Class1/MethodName/*'/>
739+
public void MethodName()
740+
{
741+
}
742+
}
743+
";
744+
745+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
746+
}
747+
748+
/// <inheritdoc/>
749+
protected override Project CreateProject(string[] sources, string language = "C#", string[] filenames = null)
750+
{
751+
var resolver = new TestXmlReferenceResolver();
752+
string contentWithSummary = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
753+
<Class1>
754+
<MethodName>
755+
<summary>
756+
Sample method.
757+
</summary>
758+
<returns>
759+
A <see cref=""Task""/> representing the asynchronous operation.
760+
</returns>
761+
</MethodName>
762+
</Class1>
763+
";
764+
resolver.XmlReferences.Add("ClassWithSummary.xml", contentWithSummary);
765+
766+
string contentWithInheritedSummary = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
767+
<Class1>
768+
<MethodName>
769+
<inheritdoc/>
770+
</MethodName>
771+
</Class1>
772+
";
773+
resolver.XmlReferences.Add("ClassWithInheritedSummary.xml", contentWithInheritedSummary);
774+
775+
string contentWithEmptySummary = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
776+
<Class1>
777+
<MethodName>
778+
<summary>
779+
</summary>
780+
<returns>
781+
A <see cref=""Task""/> representing the asynchronous operation.
782+
</returns>
783+
</MethodName>
784+
</Class1>
785+
";
786+
resolver.XmlReferences.Add("ClassWithEmptySummary.xml", contentWithEmptySummary);
787+
788+
Project project = base.CreateProject(sources, language, filenames);
789+
project = project.WithCompilationOptions(project.CompilationOptions.WithXmlReferenceResolver(resolver));
790+
return project;
791+
}
792+
696793
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
697794
{
698795
yield return new SA1606ElementDocumentationMustHaveSummaryText();

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1615UnitTests.cs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ namespace StyleCop.Analyzers.Test.DocumentationRules
77
using System.Threading;
88
using System.Threading.Tasks;
99
using Analyzers.DocumentationRules;
10+
using Helpers;
11+
using Microsoft.CodeAnalysis;
1012
using Microsoft.CodeAnalysis.CodeFixes;
1113
using Microsoft.CodeAnalysis.Diagnostics;
1214
using TestHelper;
@@ -275,11 +277,109 @@ public class ClassName
275277
await this.VerifyCSharpDiagnosticAsync(testCode.Replace("$$", declaration), EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
276278
}
277279

280+
[Fact]
281+
public async Task TestIncludedDocumentationAsync()
282+
{
283+
var testCode = @"
284+
class Class1
285+
{
286+
/// <include file='MethodWithoutReturns.xml' path='/Class1/MethodName/*'/>
287+
public int MethodName()
288+
{
289+
return 0;
290+
}
291+
}
292+
";
293+
294+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(5, 12);
295+
296+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
297+
}
298+
299+
[Fact]
300+
public async Task TestIncludedInheritedDocumentationAsync()
301+
{
302+
var testCode = @"
303+
class Class1
304+
{
305+
/// <include file='MethodWithInheritedReturns.xml' path='/Class1/MethodName/*'/>
306+
public int MethodName()
307+
{
308+
return 0;
309+
}
310+
}
311+
";
312+
313+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
314+
}
315+
316+
[Fact]
317+
public async Task TestIncludedIncompleteDocumentationAsync()
318+
{
319+
var testCode = @"
320+
class Class1
321+
{
322+
/// <include file='MethodWithReturns.xml' path='/Class1/MethodName/*'/>
323+
public int MethodName()
324+
{
325+
return 0;
326+
}
327+
}
328+
";
329+
330+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
331+
}
332+
333+
/// <inheritdoc/>
334+
protected override Project CreateProject(string[] sources, string language = "C#", string[] filenames = null)
335+
{
336+
var resolver = new TestXmlReferenceResolver();
337+
string contentWithReturns = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
338+
<Class1>
339+
<MethodName>
340+
<summary>
341+
Sample method.
342+
</summary>
343+
<returns>
344+
A <see cref=""Task""/> representing the asynchronous operation.
345+
</returns>
346+
</MethodName>
347+
</Class1>
348+
";
349+
resolver.XmlReferences.Add("MethodWithReturns.xml", contentWithReturns);
350+
351+
string contentWithInheritedReturns = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
352+
<Class1>
353+
<MethodName>
354+
<inheritdoc/>
355+
</MethodName>
356+
</Class1>
357+
";
358+
resolver.XmlReferences.Add("MethodWithInheritedReturns.xml", contentWithInheritedReturns);
359+
360+
string contentWithoutReturns = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
361+
<Class1>
362+
<MethodName>
363+
<summary>
364+
Sample method.
365+
</summary>
366+
</MethodName>
367+
</Class1>
368+
";
369+
resolver.XmlReferences.Add("MethodWithoutReturns.xml", contentWithoutReturns);
370+
371+
Project project = base.CreateProject(sources, language, filenames);
372+
project = project.WithCompilationOptions(project.CompilationOptions.WithXmlReferenceResolver(resolver));
373+
return project;
374+
}
375+
376+
/// <inheritdoc/>
278377
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
279378
{
280379
yield return new SA1615ElementReturnValueMustBeDocumented();
281380
}
282381

382+
/// <inheritdoc/>
283383
protected override CodeFixProvider GetCSharpCodeFixProvider()
284384
{
285385
return new SA1615SA1616CodeFixProvider();
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Test.Helpers
5+
{
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using System.Runtime.CompilerServices;
9+
using System.Text;
10+
using Microsoft.CodeAnalysis;
11+
12+
internal class TestXmlReferenceResolver : XmlReferenceResolver
13+
{
14+
public Dictionary<string, string> XmlReferences { get; } =
15+
new Dictionary<string, string>();
16+
17+
public override bool Equals(object other)
18+
{
19+
return ReferenceEquals(this, other);
20+
}
21+
22+
public override int GetHashCode()
23+
{
24+
return RuntimeHelpers.GetHashCode(this);
25+
}
26+
27+
public override Stream OpenRead(string resolvedPath)
28+
{
29+
string content;
30+
if (!this.XmlReferences.TryGetValue(resolvedPath, out content))
31+
{
32+
return null;
33+
}
34+
35+
return new MemoryStream(Encoding.UTF8.GetBytes(content));
36+
}
37+
38+
public override string ResolveReference(string path, string baseFilePath)
39+
{
40+
return path;
41+
}
42+
}
43+
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/StyleCop.Analyzers.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@
177177
<Compile Include="Helpers\ExclusionTestAnalyzer.cs" />
178178
<Compile Include="Helpers\MetadataReferences.cs" />
179179
<Compile Include="Helpers\TestDiagnosticProvider.cs" />
180+
<Compile Include="Helpers\TestXmlReferenceResolver.cs" />
180181
<Compile Include="HelperTests\AccessLevelHelperTests.cs" />
181182
<Compile Include="HelperTests\IndentationHelperTests.cs" />
182183
<Compile Include="HelperTests\TokenHelperTests.cs" />

0 commit comments

Comments
 (0)