Skip to content

Commit 04c27a3

Browse files
committed
Test InheritdocCodeFixProviderUnitTests with CS1591
Also updated FixAllContextHelper to support code fixes for standard C# compiler warnings.
1 parent fc11011 commit 04c27a3

4 files changed

Lines changed: 113 additions & 37 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Helpers/FixAllContextHelper.cs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,7 @@ public static async Task<ImmutableDictionary<Document, ImmutableArray<Diagnostic
4040

4141
case FixAllScope.Project:
4242
projectsToFix = ImmutableArray.Create(project);
43-
var compilation = await project.GetCompilationAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
44-
var compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, fixAllContext.CancellationToken);
45-
allDiagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false);
46-
allDiagnostics = allDiagnostics.Where(x => fixAllContext.DiagnosticIds.Contains(x.Id)).ToImmutableArray();
43+
allDiagnostics = await GetAllDiagnosticsAsync(fixAllContext, project, analyzers).ConfigureAwait(false);
4744
break;
4845

4946
case FixAllScope.Solution:
@@ -60,9 +57,7 @@ public static async Task<ImmutableDictionary<Document, ImmutableArray<Diagnostic
6057
tasks[i] = Task.Run(
6158
async () =>
6259
{
63-
var projectCompilation = await projectToFix.GetCompilationAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
64-
var projectCompilationWithAnalyzers = projectCompilation.WithAnalyzers(analyzers, projectToFix.AnalyzerOptions, fixAllContext.CancellationToken);
65-
var projectDiagnostics = await projectCompilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false);
60+
var projectDiagnostics = await GetAllDiagnosticsAsync(fixAllContext, projectToFix, analyzers).ConfigureAwait(false);
6661
diagnostics.TryAdd(projectToFix.Id, projectDiagnostics);
6762
}, fixAllContext.CancellationToken);
6863
}
@@ -157,6 +152,28 @@ private static ImmutableArray<DiagnosticAnalyzer> GetDiagnosticAnalyzersForConte
157152
.ToImmutableArray();
158153
}
159154

155+
private static async Task<ImmutableArray<Diagnostic>> GetAllDiagnosticsAsync(FixAllContext fixAllContext, Project project, ImmutableArray<DiagnosticAnalyzer> analyzers)
156+
{
157+
bool includeCompilerDiagnostics = fixAllContext.DiagnosticIds.Any(x => x.StartsWith("CS", StringComparison.Ordinal));
158+
var compilation = await project.GetCompilationAsync(fixAllContext.CancellationToken).ConfigureAwait(false);
159+
160+
var diagnostics = ImmutableArray<Diagnostic>.Empty;
161+
if (analyzers.Any())
162+
{
163+
var compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, project.AnalyzerOptions, fixAllContext.CancellationToken);
164+
diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false);
165+
}
166+
167+
if (includeCompilerDiagnostics)
168+
{
169+
var compilerDiagnostics = compilation.GetDiagnostics(fixAllContext.CancellationToken);
170+
diagnostics = diagnostics.AddRange(compilerDiagnostics);
171+
}
172+
173+
diagnostics = diagnostics.Where(x => fixAllContext.DiagnosticIds.Contains(x.Id)).ToImmutableArray();
174+
return diagnostics;
175+
}
176+
160177
private static async Task<ImmutableDictionary<Document, ImmutableArray<Diagnostic>>> GetDocumentDiagnosticsToFixAsync(
161178
ImmutableArray<Diagnostic> diagnostics,
162179
ImmutableArray<Project> projects,

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/InheritdocCodeFixProviderUnitTests.cs

Lines changed: 81 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ 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.CodeFixes;
1011
using Microsoft.CodeAnalysis.Diagnostics;
1112
using StyleCop.Analyzers.DocumentationRules;
@@ -17,12 +18,22 @@ namespace StyleCop.Analyzers.Test.DocumentationRules
1718
/// </summary>
1819
public class InheritdocCodeFixProviderUnitTests : CodeFixVerifier
1920
{
21+
private static readonly DiagnosticDescriptor SA1600 = new SA1600ElementsMustBeDocumented().SupportedDiagnostics[0];
22+
private static readonly DiagnosticDescriptor CS1591 =
23+
new DiagnosticDescriptor(nameof(CS1591), "Title", "Missing XML comment for publicly visible type or member '{0}'", "Category", DiagnosticSeverity.Error, AnalyzerConstants.EnabledByDefault);
24+
25+
private DiagnosticDescriptor descriptor = SA1600;
26+
2027
[Theory]
21-
[InlineData("string TestMember { get; set; }")]
22-
[InlineData("string TestMember() { return null; }")]
23-
[InlineData("string this[int a] { get { return \"a\"; } set { } }")]
24-
[InlineData("event EventHandler TestMember { add { } remove { } }")]
25-
public async Task TestClassVirtualInheritedMembersAsync(string memberData)
28+
[InlineData(false, null, "string TestMember { get; set; }")]
29+
[InlineData(false, null, "string TestMember() { return null; }")]
30+
[InlineData(false, null, "string this[int a] { get { return \"a\"; } set { } }")]
31+
[InlineData(false, null, "event EventHandler TestMember { add { } remove { } }")]
32+
[InlineData(true, "ChildClass.TestMember", "string TestMember { get; set; }")]
33+
[InlineData(true, "ChildClass.TestMember()", "string TestMember() { return null; }")]
34+
[InlineData(true, "ChildClass.this[int]", "string this[int a] { get { return \"a\"; } set { } }")]
35+
[InlineData(true, "ChildClass.TestMember", "event EventHandler TestMember { add { } remove { } }")]
36+
public async Task TestClassVirtualInheritedMembersAsync(bool compilerWarning, string memberName, string memberData)
2637
{
2738
var testCode = $@"using System;
2839
public class ParentClass
@@ -55,17 +66,22 @@ public override {memberData}
5566
}}
5667
";
5768

69+
if (compilerWarning)
70+
{
71+
this.descriptor = CS1591;
72+
}
73+
5874
DiagnosticResult[] expected =
5975
{
60-
this.CSharpDiagnostic().WithLocation(2, 14),
61-
this.CSharpDiagnostic().WithLocation(10, 14),
62-
this.CSharpDiagnostic().WithLocation(12, 40),
76+
this.CSharpDiagnostic(this.descriptor).WithArguments("ParentClass").WithLocation(2, 14),
77+
this.CSharpDiagnostic(this.descriptor).WithArguments("ChildClass").WithLocation(10, 14),
78+
this.CSharpDiagnostic(this.descriptor).WithArguments(memberName).WithLocation(12, 40),
6379
};
6480

6581
DiagnosticResult[] expectedFixed =
6682
{
67-
this.CSharpDiagnostic().WithLocation(2, 14),
68-
this.CSharpDiagnostic().WithLocation(10, 14),
83+
this.CSharpDiagnostic(this.descriptor).WithArguments("ParentClass").WithLocation(2, 14),
84+
this.CSharpDiagnostic(this.descriptor).WithArguments("ChildClass").WithLocation(10, 14),
6985
};
7086

7187
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
@@ -74,11 +90,15 @@ public override {memberData}
7490
}
7591

7692
[Theory]
77-
[InlineData("string TestMember { get; set; }", "string TestMember { get; set; }")]
78-
[InlineData("string TestMember();", "string TestMember() { return null; }")]
79-
[InlineData("string this[int a] { get; set; }", "string this[int a] { get { return \"a\"; } set { } }")]
80-
[InlineData("event EventHandler TestMember;", "event EventHandler TestMember { add { } remove { } }")]
81-
public async Task TestInterfaceInheritedMembersAsync(string parentData, string childData)
93+
[InlineData(false, null, "string TestMember { get; set; }", "string TestMember { get; set; }")]
94+
[InlineData(false, null, "string TestMember();", "string TestMember() { return null; }")]
95+
[InlineData(false, null, "string this[int a] { get; set; }", "string this[int a] { get { return \"a\"; } set { } }")]
96+
[InlineData(false, null, "event EventHandler TestMember;", "event EventHandler TestMember { add { } remove { } }")]
97+
[InlineData(true, "ChildClass.TestMember", "string TestMember { get; set; }", "string TestMember { get; set; }")]
98+
[InlineData(true, "ChildClass.TestMember()", "string TestMember();", "string TestMember() { return null; }")]
99+
[InlineData(true, "ChildClass.this[int]", "string this[int a] { get; set; }", "string this[int a] { get { return \"a\"; } set { } }")]
100+
[InlineData(true, "ChildClass.TestMember", "event EventHandler TestMember;", "event EventHandler TestMember { add { } remove { } }")]
101+
public async Task TestInterfaceInheritedMembersAsync(bool compilerWarning, string memberName, string parentData, string childData)
82102
{
83103
var testCode = $@"using System;
84104
public interface IParent
@@ -111,17 +131,22 @@ public class ChildClass : IParent
111131
}}
112132
";
113133

134+
if (compilerWarning)
135+
{
136+
this.descriptor = CS1591;
137+
}
138+
114139
DiagnosticResult[] expected =
115140
{
116-
this.CSharpDiagnostic().WithLocation(2, 18),
117-
this.CSharpDiagnostic().WithLocation(10, 14),
118-
this.CSharpDiagnostic().WithLocation(12, 31),
141+
this.CSharpDiagnostic(this.descriptor).WithArguments("IParent").WithLocation(2, 18),
142+
this.CSharpDiagnostic(this.descriptor).WithArguments("ChildClass").WithLocation(10, 14),
143+
this.CSharpDiagnostic(this.descriptor).WithArguments(memberName).WithLocation(12, 31),
119144
};
120145

121146
DiagnosticResult[] expectedFixed =
122147
{
123-
this.CSharpDiagnostic().WithLocation(2, 18),
124-
this.CSharpDiagnostic().WithLocation(10, 14),
148+
this.CSharpDiagnostic(this.descriptor).WithArguments("IParent").WithLocation(2, 18),
149+
this.CSharpDiagnostic(this.descriptor).WithArguments("ChildClass").WithLocation(10, 14),
125150
};
126151

127152
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
@@ -153,9 +178,9 @@ public class ChildClass : ParentClass
153178

154179
DiagnosticResult[] expected =
155180
{
156-
this.CSharpDiagnostic().WithLocation(2, 14),
157-
this.CSharpDiagnostic().WithLocation(10, 14),
158-
this.CSharpDiagnostic().WithLocation(12, 35),
181+
this.CSharpDiagnostic(this.descriptor).WithLocation(2, 14),
182+
this.CSharpDiagnostic(this.descriptor).WithLocation(10, 14),
183+
this.CSharpDiagnostic(this.descriptor).WithLocation(12, 35),
159184
};
160185

161186
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
@@ -188,15 +213,45 @@ public class ChildClass : ParentClass
188213

189214
DiagnosticResult[] expected =
190215
{
191-
this.CSharpDiagnostic().WithLocation(2, 14),
192-
this.CSharpDiagnostic().WithLocation(10, 14),
193-
this.CSharpDiagnostic().WithLocation(12, 35),
216+
this.CSharpDiagnostic(this.descriptor).WithLocation(2, 14),
217+
this.CSharpDiagnostic(this.descriptor).WithLocation(10, 14),
218+
this.CSharpDiagnostic(this.descriptor).WithLocation(12, 35),
194219
};
195220

196221
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
197222
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
198223
}
199224

225+
/// <inheritdoc/>
226+
protected override IEnumerable<string> GetDisabledDiagnostics()
227+
{
228+
if (this.descriptor == CS1591)
229+
{
230+
yield return SA1600.Id;
231+
}
232+
}
233+
234+
/// <inheritdoc/>
235+
protected override Project ApplyCompilationOptions(Project project)
236+
{
237+
project = base.ApplyCompilationOptions(project);
238+
239+
if (this.descriptor == CS1591)
240+
{
241+
var supportedDiagnosticsSpecificOptions = new Dictionary<string, ReportDiagnostic>();
242+
supportedDiagnosticsSpecificOptions.Add(CS1591.Id, ReportDiagnostic.Error);
243+
244+
// update the project compilation options
245+
var modifiedSpecificDiagnosticOptions = project.CompilationOptions.SpecificDiagnosticOptions.SetItem(CS1591.Id, ReportDiagnostic.Error);
246+
var modifiedCompilationOptions = project.CompilationOptions.WithSpecificDiagnosticOptions(modifiedSpecificDiagnosticOptions);
247+
248+
Solution solution = project.Solution.WithProjectCompilationOptions(project.Id, modifiedCompilationOptions);
249+
project = solution.GetProject(project.Id);
250+
}
251+
252+
return project;
253+
}
254+
200255
/// <inheritdoc/>
201256
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
202257
{

StyleCop.Analyzers/StyleCop.Analyzers.Test/Helpers/DiagnosticVerifier.Helper.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,17 +157,17 @@ protected DiagnosticResult CSharpDiagnostic(string diagnosticId = null)
157157
var supportedDiagnostics = analyzers.SelectMany(analyzer => analyzer.SupportedDiagnostics);
158158
if (diagnosticId == null)
159159
{
160-
return new DiagnosticResult(supportedDiagnostics.Single());
160+
return this.CSharpDiagnostic(supportedDiagnostics.Single());
161161
}
162162
else
163163
{
164-
return new DiagnosticResult(supportedDiagnostics.Single(i => i.Id == diagnosticId));
164+
return this.CSharpDiagnostic(supportedDiagnostics.Single(i => i.Id == diagnosticId));
165165
}
166166
}
167167

168168
protected DiagnosticResult CSharpDiagnostic(DiagnosticDescriptor descriptor)
169169
{
170-
return this.CSharpDiagnostic(descriptor.Id).WithMessageFormat(descriptor.MessageFormat);
170+
return new DiagnosticResult(descriptor);
171171
}
172172

173173
/// <summary>

StyleCop.Analyzers/StyleCop.Analyzers.Test/Verifiers/CodeFixVerifier.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,11 @@ private static async Task<Document> GetFixAllAnalyzerAsync(FixAllScope scope, Im
289289

290290
FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics);
291291

292-
FixAllContext fixAllContext = new FixAllContext(document, codeFixProvider, scope, equivalenceKey, analyzers.SelectMany(x => x.SupportedDiagnostics).Select(x => x.Id), fixAllDiagnosticProvider, cancellationToken);
292+
IEnumerable<string> analyzerDiagnosticIds = analyzers.SelectMany(x => x.SupportedDiagnostics).Select(x => x.Id);
293+
IEnumerable<string> compilerDiagnosticIds = codeFixProvider.FixableDiagnosticIds.Where(x => x.StartsWith("CS", StringComparison.Ordinal));
294+
IEnumerable<string> disabledDiagnosticIds = document.Project.CompilationOptions.SpecificDiagnosticOptions.Where(x => x.Value == ReportDiagnostic.Suppress).Select(x => x.Key);
295+
IEnumerable<string> relevantIds = analyzerDiagnosticIds.Concat(compilerDiagnosticIds).Except(disabledDiagnosticIds).Distinct();
296+
FixAllContext fixAllContext = new FixAllContext(document, codeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken);
293297

294298
CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);
295299
if (action == null)

0 commit comments

Comments
 (0)