diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp12/DocumentationRules/SA1611CSharp12UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp12/DocumentationRules/SA1611CSharp12UnitTests.cs index 62c49ad12..f6050c204 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp12/DocumentationRules/SA1611CSharp12UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp12/DocumentationRules/SA1611CSharp12UnitTests.cs @@ -3,9 +3,109 @@ namespace StyleCop.Analyzers.Test.CSharp12.DocumentationRules { + using System.Threading; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Testing; using StyleCop.Analyzers.Test.CSharp11.DocumentationRules; + using Xunit; + using static StyleCop.Analyzers.Test.Verifiers.CustomDiagnosticVerifier; public partial class SA1611CSharp12UnitTests : SA1611CSharp11UnitTests { + public static TheoryData NonRecordDeclarationKeywords { get; } = new TheoryData() { "class", "struct" }; + + [Theory] + [MemberData(nameof(NonRecordDeclarationKeywords))] + [WorkItem(3770, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3770")] + public async Task TestPrimaryConstructorMissingParametersAsync(string keyword) + { + var testCode = $@" +/// +/// Type. +/// +public {keyword} C(int {{|#0:param1|}}, string {{|#1:param2|}}) {{ }}"; + + DiagnosticResult[] expectedResults = new[] + { + Diagnostic().WithLocation(0).WithArguments("param1"), + Diagnostic().WithLocation(1).WithArguments("param2"), + }; + + await VerifyCSharpDiagnosticAsync(testCode, expectedResults, CancellationToken.None).ConfigureAwait(false); + } + + [Theory] + [MemberData(nameof(NonRecordDeclarationKeywords))] + [WorkItem(3770, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3770")] + public async Task TestPrimaryConstructorPartiallyMissingParametersAsync(string keyword) + { + var testCode = $@" +/// +/// Type. +/// +/// Parameter one. +public {keyword} C(int param1, string {{|#0:param2|}}) {{ }}"; + + await VerifyCSharpDiagnosticAsync(testCode, new[] { Diagnostic().WithLocation(0).WithArguments("param2") }, CancellationToken.None).ConfigureAwait(false); + } + + [Theory] + [MemberData(nameof(NonRecordDeclarationKeywords))] + [WorkItem(3770, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3770")] + public async Task TestPrimaryConstructorNoMissingParametersAsync(string keyword) + { + var testCode = $@" +/// +/// Type. +/// +/// Parameter one. +/// Parameter two. +public {keyword} C(int param1, string param2) {{ }}"; + + await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + } + + [Theory] + [MemberData(nameof(NonRecordDeclarationKeywords))] + [WorkItem(3770, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3770")] + public async Task TestPrimaryConstructorIncludeMissingParametersAsync(string keyword) + { + var testCode = $@" +/// +public {keyword} C(int {{|#0:param1|}}, string {{|#1:param2|}}, bool {{|#2:param3|}}) {{ }}"; + + DiagnosticResult[] expectedResults = new[] + { + Diagnostic().WithLocation(0).WithArguments("param1"), + Diagnostic().WithLocation(1).WithArguments("param2"), + Diagnostic().WithLocation(2).WithArguments("param3"), + }; + + await VerifyCSharpDiagnosticAsync(testCode, expectedResults, CancellationToken.None).ConfigureAwait(false); + } + + [Theory] + [MemberData(nameof(NonRecordDeclarationKeywords))] + [WorkItem(3770, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3770")] + public async Task TestPrimaryConstructorIncludePartiallyMissingParametersAsync(string keyword) + { + var testCode = $@" +/// +public {keyword} C(int {{|#0:param1|}}, string param2, bool param3) {{ }}"; + + await VerifyCSharpDiagnosticAsync(testCode, new[] { Diagnostic().WithLocation(0).WithArguments("param1") }, CancellationToken.None).ConfigureAwait(false); + } + + [Theory] + [MemberData(nameof(NonRecordDeclarationKeywords))] + [WorkItem(3770, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3770")] + public async Task TestPrimaryConstructorIncludeNoMissingParametersAsync(string keyword) + { + var testCode = $@" +/// +public {keyword} C(int param1, string param2, bool param3) {{ }}"; + + await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + } } } diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/DocumentationRules/SA1611CSharp9UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/DocumentationRules/SA1611CSharp9UnitTests.cs index 27bb08e0c..004f297bd 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/DocumentationRules/SA1611CSharp9UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/DocumentationRules/SA1611CSharp9UnitTests.cs @@ -3,9 +3,39 @@ namespace StyleCop.Analyzers.Test.CSharp9.DocumentationRules { + using System.Threading; + using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Testing; using StyleCop.Analyzers.Test.CSharp8.DocumentationRules; + using StyleCop.Analyzers.Test.Helpers; + using Xunit; public partial class SA1611CSharp9UnitTests : SA1611CSharp8UnitTests { + [Theory] + [MemberData(nameof(CommonMemberData.RecordTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + [WorkItem(3770, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3770")] + public async Task TestPrimaryRecordConstructorMissingParametersAsync(string keyword) + { + var testCode = $@" +/// +/// Record. +/// +public {keyword} R(int Param1, string Param2);"; + + await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + } + + [Theory] + [MemberData(nameof(CommonMemberData.RecordTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + [WorkItem(3770, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3770")] + public async Task TestPrimaryRecordConstructorIncludeMissingParametersAsync(string keyword) + { + var testCode = $@" +/// +public {keyword} R(int Param1, string Param2);"; + + await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); + } } } diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1611UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1611UnitTests.cs index c36d12d51..b2978db59 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1611UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1611UnitTests.cs @@ -414,7 +414,7 @@ public void TestMethod(string param1, string param2, string param3) await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false); } - private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[] expected, CancellationToken cancellationToken) + protected static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[] expected, CancellationToken cancellationToken) { string contentWithoutElementDocumentation = @" @@ -455,6 +455,32 @@ private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[ "; + string classWithoutElementDocumentation = @" + + + Foo + + +"; + string classWithPartialElementDocumentation = @" + + + Foo + + Param 2 + Param 3 + +"; + string classWithElementDocumentation = @" + + + Foo + + Param 1 + Param 2 + Param 3 + +"; var test = new StyleCopDiagnosticVerifier.CSharpTest { @@ -465,6 +491,9 @@ private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[ { "WithElementDocumentation.xml", contentWithElementDocumentation }, { "WithPartialElementDocumentation.xml", contentWithPartialElementDocumentation }, { "InheritedDocumentation.xml", contentWithInheritedDocumentation }, + { "MissingClassDocumentation.xml", classWithoutElementDocumentation }, + { "WithClassDocumentation.xml", classWithElementDocumentation }, + { "WithPartialClassDocumentation.xml", classWithPartialElementDocumentation }, }, }; diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1611ElementParametersMustBeDocumented.cs b/StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1611ElementParametersMustBeDocumented.cs index 13ec45241..0d6708f6f 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1611ElementParametersMustBeDocumented.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/DocumentationRules/SA1611ElementParametersMustBeDocumented.cs @@ -10,9 +10,11 @@ namespace StyleCop.Analyzers.DocumentationRules using System.Linq; using System.Xml.Linq; using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using StyleCop.Analyzers.Helpers; + using StyleCop.Analyzers.Lightup; using StyleCop.Analyzers.Settings.ObjectModel; /// @@ -60,6 +62,12 @@ protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, Styl } var node = context.Node; + if (node.IsKind(SyntaxKindEx.RecordDeclaration) || node.IsKind(SyntaxKindEx.RecordStructDeclaration)) + { + // Record parameters are covered by SA1600 instead. + return; + } + var parameterList = GetParameters(node); if (parameterList == null) { @@ -84,6 +92,12 @@ protected override void HandleCompleteDocumentation(SyntaxNodeAnalysisContext co } var node = context.Node; + if (node.IsKind(SyntaxKindEx.RecordDeclaration) || node.IsKind(SyntaxKindEx.RecordStructDeclaration)) + { + // Record parameters are covered by SA1600 instead. + return; + } + var parameterList = GetParameters(node); if (parameterList == null) { @@ -106,7 +120,8 @@ private static IEnumerable GetParameters(SyntaxNode node) { return (node as BaseMethodDeclarationSyntax)?.ParameterList?.Parameters ?? (node as IndexerDeclarationSyntax)?.ParameterList?.Parameters - ?? (node as DelegateDeclarationSyntax)?.ParameterList?.Parameters; + ?? (node as DelegateDeclarationSyntax)?.ParameterList?.Parameters + ?? (node as TypeDeclarationSyntax)?.ParameterList()?.Parameters; } private static void ReportMissingParameters(SyntaxNodeAnalysisContext context, IEnumerable parameterList, IEnumerable documentationParameterNames)