Skip to content

Commit 72da7cb

Browse files
committed
Merge remote-tracking branch 'DotNetAnalyzers/stabilization'
2 parents 282b88d + 35c0aff commit 72da7cb

21 files changed

Lines changed: 810 additions & 27 deletions

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1133CodeFixProvider.cs

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace StyleCop.Analyzers.ReadabilityRules
66
using System.Collections.Generic;
77
using System.Collections.Immutable;
88
using System.Composition;
9+
using System.Linq;
910
using System.Threading;
1011
using System.Threading.Tasks;
1112
using Helpers;
@@ -33,7 +34,7 @@ internal class SA1133CodeFixProvider : CodeFixProvider
3334
/// <inheritdoc/>
3435
public override FixAllProvider GetFixAllProvider()
3536
{
36-
return CustomFixAllProviders.BatchFixer;
37+
return FixAll.Instance;
3738
}
3839

3940
/// <inheritdoc/>
@@ -58,12 +59,22 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
5859
var nodeInSourceSpan = syntaxRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
5960
AttributeListSyntax attributeList = nodeInSourceSpan.FirstAncestorOrSelf<AttributeListSyntax>();
6061

61-
var newAttributeLists = new List<AttributeListSyntax>();
62-
6362
var indentationOptions = IndentationOptions.FromDocument(document);
6463
var indentationSteps = IndentationHelper.GetIndentationSteps(indentationOptions, attributeList);
6564
var indentationTrivia = IndentationHelper.GenerateWhitespaceTrivia(indentationOptions, indentationSteps);
6665

66+
List<AttributeListSyntax> newAttributeLists = GetNewAttributeList(attributeList, indentationTrivia);
67+
68+
var newSyntaxRoot = syntaxRoot.ReplaceNode(attributeList, newAttributeLists);
69+
var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting());
70+
71+
return newDocument;
72+
}
73+
74+
private static List<AttributeListSyntax> GetNewAttributeList(AttributeListSyntax attributeList, SyntaxTrivia indentationTrivia)
75+
{
76+
var newAttributeLists = new List<AttributeListSyntax>();
77+
6778
for (var i = 0; i < attributeList.Attributes.Count; i++)
6879
{
6980
var newAttributes = SyntaxFactory.SingletonSeparatedList(attributeList.Attributes[i]);
@@ -80,10 +91,41 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
8091
newAttributeLists.Add(newAttributeList);
8192
}
8293

83-
var newSyntaxRoot = syntaxRoot.ReplaceNode(attributeList, newAttributeLists);
84-
var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting());
94+
return newAttributeLists;
95+
}
8596

86-
return newDocument;
97+
private class FixAll : DocumentBasedFixAllProvider
98+
{
99+
public static FixAllProvider Instance { get; } =
100+
new FixAll();
101+
102+
protected override string CodeActionTitle =>
103+
ReadabilityResources.SA1133CodeFix;
104+
105+
protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document)
106+
{
107+
var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false);
108+
if (diagnostics.IsEmpty)
109+
{
110+
return null;
111+
}
112+
113+
var indentationOptions = IndentationOptions.FromDocument(document);
114+
var syntaxRoot = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
115+
116+
var nodes = diagnostics.Select(diagnostic => syntaxRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true).FirstAncestorOrSelf<AttributeListSyntax>());
117+
118+
var newRoot = syntaxRoot.TrackNodes(nodes);
119+
120+
foreach (var attributeList in nodes)
121+
{
122+
var indentationSteps = IndentationHelper.GetIndentationSteps(indentationOptions, attributeList);
123+
var indentationTrivia = IndentationHelper.GenerateWhitespaceTrivia(indentationOptions, indentationSteps);
124+
newRoot = newRoot.ReplaceNode(newRoot.GetCurrentNode(attributeList), GetNewAttributeList(attributeList, indentationTrivia));
125+
}
126+
127+
return newRoot;
128+
}
87129
}
88130
}
89131
}

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();

0 commit comments

Comments
 (0)