From 472780ca2e4cf6d95558bdf2ac1da2ba9ec2551a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Hellander?= Date: Sat, 16 Sep 2023 10:07:28 +0200 Subject: [PATCH] Update SA1642 and its code fix to handle record structs correctly. Also add tests for records and record classes. #3518 --- .../SA1642SA1643CodeFixProvider.cs | 32 +- .../DocumentationRules/SA1642UnitTests.cs | 276 +++++++++++------- ...yDocumentationMustBeginWithStandardText.cs | 5 +- 3 files changed, 196 insertions(+), 117 deletions(-) diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/SA1642SA1643CodeFixProvider.cs b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/SA1642SA1643CodeFixProvider.cs index 7d291b0ed..716937ebd 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/SA1642SA1643CodeFixProvider.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/DocumentationRules/SA1642SA1643CodeFixProvider.cs @@ -8,7 +8,7 @@ namespace StyleCop.Analyzers.DocumentationRules using System; using System.Collections.Immutable; using System.Composition; - using System.Globalization; + using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; using System.Threading; @@ -20,6 +20,7 @@ namespace StyleCop.Analyzers.DocumentationRules using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; using StyleCop.Analyzers.Helpers; + using StyleCop.Analyzers.Lightup; /// /// Implements a code fix for @@ -83,7 +84,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) internal static ImmutableArray GenerateStandardText(Document document, BaseMethodDeclarationSyntax methodDeclaration, BaseTypeDeclarationSyntax typeDeclaration, CancellationToken cancellationToken) { - bool isStruct = typeDeclaration.IsKind(SyntaxKind.StructDeclaration); + bool isStruct = typeDeclaration.IsKind(SyntaxKind.StructDeclaration) || typeDeclaration.IsKind(SyntaxKindEx.RecordStructDeclaration); var settings = document.Project.AnalyzerOptions.GetStyleCopSettings(methodDeclaration.SyntaxTree, cancellationToken); var culture = settings.DocumentationRules.DocumentationCultureInfo; var resourceManager = DocumentationResources.ResourceManager; @@ -147,7 +148,19 @@ private static TypeParameterListSyntax GetTypeParameterList(BaseTypeDeclarationS return classDeclaration.TypeParameterList; } - return (typeDeclaration as StructDeclarationSyntax)?.TypeParameterList; + if (typeDeclaration is StructDeclarationSyntax structDeclaration) + { + return structDeclaration.TypeParameterList; + } + + if (RecordDeclarationSyntaxWrapper.IsInstance(typeDeclaration)) + { + var recordDeclaration = (RecordDeclarationSyntaxWrapper)typeDeclaration; + return recordDeclaration.TypeParameterList; + } + + Debug.Assert(false, $"Unhandled type {typeDeclaration.Kind()}"); + return null; } private static Task GetTransformedDocumentAsync(Document document, SyntaxNode root, XmlElementSyntax node, CancellationToken cancellationToken) @@ -202,21 +215,10 @@ private static bool IsMultiLine(XmlElementSyntax node) private static Task GetTransformedDocumentAsync(Document document, SyntaxNode root, XmlEmptyElementSyntax node) { var typeDeclaration = node.FirstAncestorOrSelf(); - - TypeParameterListSyntax typeParameterList; - if (typeDeclaration is ClassDeclarationSyntax classDeclaration) - { - typeParameterList = classDeclaration.TypeParameterList; - } - else - { - typeParameterList = (typeDeclaration as StructDeclarationSyntax)?.TypeParameterList; - } + var typeParameterList = GetTypeParameterList(typeDeclaration); var newRoot = root.ReplaceNode(node, BuildSeeElement(typeDeclaration.Identifier, typeParameterList)); - var newDocument = document.WithSyntaxRoot(newRoot); - return Task.FromResult(newDocument); } diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1642UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1642UnitTests.cs index 97393f89e..4433b5044 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1642UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1642UnitTests.cs @@ -5,10 +5,13 @@ namespace StyleCop.Analyzers.Test.DocumentationRules { + using System.Collections.Generic; + using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Testing; using StyleCop.Analyzers.DocumentationRules; + using StyleCop.Analyzers.Lightup; using StyleCop.Analyzers.Test.Helpers; using StyleCop.Analyzers.Test.Verifiers; using Xunit; @@ -21,8 +24,7 @@ namespace StyleCop.Analyzers.Test.DocumentationRules public class SA1642UnitTests { [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNoDocumentationAsync(string typeKind) { var testCode = $@"namespace FooNamespace @@ -38,8 +40,7 @@ public Foo(int arg) } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestEmptyPublicConstructorAsync(string typeKind) { await TestEmptyConstructorAsync(typeKind, "public").ConfigureAwait(false); @@ -54,62 +55,65 @@ public async Task TestEmptyNonPublicConstructorAsync(string typeKind) } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestEmptyStaticConstructorAsync(string typeKind) { await TestEmptyConstructorAsync(typeKind, "static").ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNonPrivateConstructorCorrectDocumentationSimpleAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorCorrectDocumentationSimpleAsync( typeKind, "public", - string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, docTypeKind), false).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNonPrivateConstructorCorrectDocumentationCustomizedAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorCorrectDocumentationCustomizedAsync( typeKind, "public", - string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, docTypeKind), false).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNonPrivateConstructorCorrectDocumentationGenericSimpleAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorCorrectDocumentationSimpleAsync( typeKind, "public", - string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, docTypeKind), true).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNonPrivateConstructorCorrectDocumentationGenericCustomizedAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorCorrectDocumentationCustomizedAsync( typeKind, "public", - string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, docTypeKind), true).ConfigureAwait(false); } @@ -222,56 +226,60 @@ await TestConstructorCorrectDocumentationCustomizedAsync( } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestStaticConstructorCorrectDocumentationAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorCorrectDocumentationAsync( typeKind, "static", - string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, docTypeKind), string.Empty, false).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestStaticConstructorCorrectDocumentationGenericAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorCorrectDocumentationAsync( typeKind, "static", - string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, docTypeKind), string.Empty, true).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNonPrivateConstructorMissingDocumentationAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorMissingDocumentationAsync( typeKind, "public", - string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, docTypeKind), false).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNonPrivateConstructorMissingDocumentationGenericAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorMissingDocumentationAsync( typeKind, "public", - string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, docTypeKind), true).ConfigureAwait(false); } @@ -302,54 +310,58 @@ await TestConstructorMissingDocumentationAsync( } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestStaticConstructorMissingDocumentationAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorMissingDocumentationAsync( typeKind, "static", - string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, docTypeKind), false).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestStaticConstructorMissingDocumentationGenericAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorMissingDocumentationAsync( typeKind, "static", - string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, docTypeKind), true).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNonPrivateConstructorSimpleDocumentationAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorSimpleDocumentationAsync( typeKind, "public", - string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, docTypeKind), false).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNonPrivateConstructorSimpleDocumentationGenericAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorSimpleDocumentationAsync( typeKind, "public", - string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, docTypeKind), true).ConfigureAwait(false); } @@ -380,54 +392,58 @@ await TestConstructorSimpleDocumentationAsync( } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestStaticConstructorSimpleDocumentationAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorSimpleDocumentationAsync( typeKind, "static", - string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, docTypeKind), false).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestStaticConstructorSimpleDocumentationGenericAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorSimpleDocumentationAsync( typeKind, "static", - string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, docTypeKind), true).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNonPrivateConstructorSimpleDocumentationWrongTypeNameAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorSimpleDocumentationWrongTypeNameAsync( typeKind, "public", - string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, docTypeKind), false).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestNonPrivateConstructorSimpleDocumentationGenericWrongTypeNameAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorSimpleDocumentationWrongTypeNameAsync( typeKind, "public", - string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.NonPrivateConstructorStandardTextSecondPart, docTypeKind), true).ConfigureAwait(false); } @@ -458,28 +474,30 @@ await TestConstructorSimpleDocumentationWrongTypeNameAsync( } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestStaticConstructorSimpleDocumentationWrongTypeNameAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorSimpleDocumentationWrongTypeNameAsync( typeKind, "static", - string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, docTypeKind), false).ConfigureAwait(false); } [Theory] - [InlineData("class")] - [InlineData("struct")] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] public async Task TestStaticConstructorSimpleDocumentationGenericWrongTypeNameAsync(string typeKind) { + var docTypeKind = GetDocTypeKind(typeKind); + await TestConstructorSimpleDocumentationWrongTypeNameAsync( typeKind, "static", - string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, typeKind), - string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, typeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextFirstPart, docTypeKind), + string.Format(DocumentationResources.StaticConstructorStandardTextSecondPart, docTypeKind), true).ConfigureAwait(false); } @@ -587,34 +605,66 @@ protected CustomizableBlockSubscriberBase() await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false); } - /// - /// Verifies that an empty see tag is handled properly. - /// - /// A representing the asynchronous unit test. - [Fact] - public async Task TestWithEmptySeeTagAsync() + [Theory] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task TestWithEmptySeeTagAsync(string typeKind) { - string testCode = @" -public class TestClass -{ + var docTypeKind = GetDocTypeKind(typeKind); + + string testCode = $@" +public {typeKind} TestClass +{{ /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the {docTypeKind}. /// - public TestClass() - { - } -} + public TestClass(int i) + {{ + }} +}} "; - string fixedCode = @" -public class TestClass -{ + string fixedCode = $@" +public {typeKind} TestClass +{{ /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the {docTypeKind}. /// - public TestClass() - { - } -} + public TestClass(int i) + {{ + }} +}} +"; + + DiagnosticResult expected = Diagnostic().WithLocation(5, 43); + await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false); + } + + [Theory] + [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))] + public async Task TestWithEmptySeeTagGenericAsync(string typeKind) + { + var docTypeKind = GetDocTypeKind(typeKind); + + string testCode = $@" +public {typeKind} TestClass +{{ + /// + /// Initializes a new instance of the {docTypeKind}. + /// + public TestClass(int i) + {{ + }} +}} +"; + string fixedCode = $@" +public {typeKind} TestClass +{{ + /// + /// Initializes a new instance of the {docTypeKind}. + /// + public TestClass(int i) + {{ + }} +}} "; DiagnosticResult expected = Diagnostic().WithLocation(5, 43); @@ -1108,7 +1158,7 @@ private static async Task TestConstructorCorrectDocumentationCustomizedAsync(str private static async Task TestConstructorMissingDocumentationAsync(string typeKind, string modifiers, string part1, string part2, bool generic) { string typeParameters = generic ? "" : string.Empty; - string arguments = typeKind == "struct" && modifiers != "static" ? "int argument" : null; + string arguments = IsStruct(typeKind) && modifiers != "static" ? "int argument" : null; var testCode = $@"namespace FooNamespace {{ public {typeKind} Foo{typeParameters} @@ -1322,5 +1372,29 @@ private static StyleCopCodeFixVerifier @@ -132,7 +133,9 @@ private static void HandleConstructorDeclaration(SyntaxNodeAnalysisContext conte var culture = settings.DocumentationRules.DocumentationCultureInfo; var resourceManager = DocumentationResources.ResourceManager; - bool isStruct = constructorDeclarationSyntax.Parent?.IsKind(SyntaxKind.StructDeclaration) ?? false; + var parent = constructorDeclarationSyntax.Parent; + bool isStruct = parent != null && + (parent.IsKind(SyntaxKind.StructDeclaration) || parent.IsKind(SyntaxKindEx.RecordStructDeclaration)); var typeKindText = resourceManager.GetString(isStruct ? nameof(DocumentationResources.TypeTextStruct) : nameof(DocumentationResources.TypeTextClass), culture); if (constructorDeclarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword))