Skip to content

Commit aacf8a5

Browse files
authored
Merge pull request #3401 from sharwell/record-struct
Support C# 10 'record struct'
2 parents d690a72 + 22d1715 commit aacf8a5

29 files changed

+1261
-45
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/LayoutRules/SA1502CodeFixProvider.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ private Document CreateCodeFix(Document document, IndentationSettings indentatio
7070
case SyntaxKind.InterfaceDeclaration:
7171
case SyntaxKind.StructDeclaration:
7272
case SyntaxKindEx.RecordDeclaration:
73+
case SyntaxKindEx.RecordStructDeclaration:
7374
case SyntaxKind.EnumDeclaration:
7475
newSyntaxRoot = this.RegisterBaseTypeDeclarationCodeFix(syntaxRoot, (BaseTypeDeclarationSyntax)node, indentationSettings);
7576
break;

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/MaintainabilityRules/SA1400CodeFixProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ private static Task<Document> GetTransformedDocumentAsync(Document document, Syn
8484
break;
8585

8686
case SyntaxKindEx.RecordDeclaration:
87+
case SyntaxKindEx.RecordStructDeclaration:
8788
updatedDeclarationNode = HandleRecordDeclaration((RecordDeclarationSyntaxWrapper)declarationNode);
8889
break;
8990

@@ -378,6 +379,7 @@ private static SyntaxNode FindParentDeclarationNode(SyntaxNode node)
378379
case SyntaxKind.EnumDeclaration:
379380
case SyntaxKind.StructDeclaration:
380381
case SyntaxKindEx.RecordDeclaration:
382+
case SyntaxKindEx.RecordStructDeclaration:
381383
case SyntaxKind.DelegateDeclaration:
382384
case SyntaxKind.EventDeclaration:
383385
case SyntaxKind.EventFieldDeclaration:

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/OrderingRules/SA1205CodeFixProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ private static TypeDeclarationSyntax ReplaceModifiers(TypeDeclarationSyntax node
113113
case SyntaxKind.StructDeclaration:
114114
return ((StructDeclarationSyntax)node).WithModifiers(modifiers);
115115
case SyntaxKindEx.RecordDeclaration:
116+
case SyntaxKindEx.RecordStructDeclaration:
116117
return ((RecordDeclarationSyntaxWrapper)node).WithModifiers(modifiers);
117118
}
118119

@@ -132,6 +133,7 @@ private static TypeDeclarationSyntax ReplaceKeyword(TypeDeclarationSyntax node,
132133
case SyntaxKind.StructDeclaration:
133134
return ((StructDeclarationSyntax)node).WithKeyword(keyword);
134135
case SyntaxKindEx.RecordDeclaration:
136+
case SyntaxKindEx.RecordStructDeclaration:
135137
return ((RecordDeclarationSyntaxWrapper)node).WithKeyword(keyword);
136138
}
137139

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/NamingRules/SA1313CSharp10UnitTests.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,50 @@
33

44
namespace StyleCop.Analyzers.Test.CSharp10.NamingRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.CSharp;
69
using StyleCop.Analyzers.Test.CSharp9.NamingRules;
10+
using StyleCop.Analyzers.Test.Verifiers;
11+
using Xunit;
12+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
13+
StyleCop.Analyzers.NamingRules.SA1313ParameterNamesMustBeginWithLowerCaseLetter,
14+
StyleCop.Analyzers.NamingRules.RenameToLowerCaseCodeFixProvider>;
715

816
public class SA1313CSharp10UnitTests : SA1313CSharp9UnitTests
917
{
18+
[Theory]
19+
[WorkItem(3384, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3384")]
20+
[InlineData("class")]
21+
[InlineData("struct")]
22+
public async Task TestRecordTypeAsync(string typeKind)
23+
{
24+
var testCode = $@"
25+
public record {typeKind} R(int A)
26+
{{
27+
public R(int [|A|], int [|B|])
28+
: this(A)
29+
{{
30+
}}
31+
}}
32+
";
33+
34+
var fixedCode = $@"
35+
public record {typeKind} R(int A)
36+
{{
37+
public R(int a, int b)
38+
: this(a)
39+
{{
40+
}}
41+
}}
42+
";
43+
44+
await new CSharpTest(LanguageVersion.CSharp10)
45+
{
46+
ReferenceAssemblies = GenericAnalyzerTest.ReferenceAssembliesNet60,
47+
TestCode = testCode,
48+
FixedCode = fixedCode,
49+
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
50+
}
1051
}
1152
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1618UnitTests.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,22 @@ public static IEnumerable<object[]> Types
3434
{
3535
get
3636
{
37-
yield return new object[] { "class Foo<Ta, Tb> { }" };
38-
yield return new object[] { "struct Foo<Ta, Tb> { }" };
39-
yield return new object[] { "interface Foo<Ta, Tb> { }" };
40-
yield return new object[] { "class Foo<Ta, T\\u0062> { }" };
41-
yield return new object[] { "struct Foo<Ta, T\\u0062> { }" };
42-
yield return new object[] { "interface Foo<Ta, T\\u0062> { }" };
37+
yield return new object[] { "class Foo<{|#0:Ta|}, {|#1:Tb|}> { }" };
38+
yield return new object[] { "struct Foo<{|#0:Ta|}, {|#1:Tb|}> { }" };
39+
yield return new object[] { "interface Foo<{|#0:Ta|}, {|#1:Tb|}> { }" };
40+
yield return new object[] { "class Foo<{|#0:Ta|}, {|#1:T\\u0062|}> { }" };
41+
yield return new object[] { "struct Foo<{|#0:Ta|}, {|#1:T\\u0062|}> { }" };
42+
yield return new object[] { "interface Foo<{|#0:Ta|}, {|#1:T\\u0062|}> { }" };
4343
if (LightupHelpers.SupportsCSharp9)
4444
{
45-
yield return new object[] { "record Foo<Ta, Tb> { }" };
46-
yield return new object[] { "record Foo<Ta, T\\u0062> { }" };
45+
yield return new object[] { "record Foo<{|#0:Ta|}, {|#1:Tb|}> { }" };
46+
yield return new object[] { "record Foo<{|#0:Ta|}, {|#1:T\\u0062|}> { }" };
47+
}
48+
49+
if (LightupHelpers.SupportsCSharp10)
50+
{
51+
yield return new object[] { "record class Foo<{|#0:Ta|}, {|#1:Tb|}> { }" };
52+
yield return new object[] { "record struct Foo<{|#0:Ta|}, {|#1:T\\u0062|}> { }" };
4753
}
4854
}
4955
}
@@ -264,8 +270,8 @@ public async Task TestTypesWithMissingDocumentationAsync(string p)
264270

265271
var expected = new[]
266272
{
267-
Diagnostic().WithLocation(5, 22).WithArguments("Ta"),
268-
Diagnostic().WithLocation(5, 26).WithArguments("Tb"),
273+
Diagnostic().WithLocation(0).WithArguments("Ta"),
274+
Diagnostic().WithLocation(1).WithArguments("Tb"),
269275
};
270276

271277
await VerifyCSharpDiagnosticAsync(testCode.Replace("##", p), expected, CancellationToken.None).ConfigureAwait(false);

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1619UnitTests.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,22 @@ public static IEnumerable<object[]> Types
2222
{
2323
get
2424
{
25-
yield return new object[] { "class Foo<Ta, Tb> { }" };
26-
yield return new object[] { "struct Foo<Ta, Tb> { }" };
27-
yield return new object[] { "interface Foo<Ta, Tb> { }" };
28-
yield return new object[] { "class Foo<Ta, T\\u0062> { }" };
29-
yield return new object[] { "struct Foo<Ta, T\\u0062> { }" };
30-
yield return new object[] { "interface Foo<Ta, T\\u0062> { }" };
25+
yield return new object[] { "class Foo<{|#0:Ta|}, {|#1:Tb|}> { }" };
26+
yield return new object[] { "struct Foo<{|#0:Ta|}, {|#1:Tb|}> { }" };
27+
yield return new object[] { "interface Foo<{|#0:Ta|}, {|#1:Tb|}> { }" };
28+
yield return new object[] { "class Foo<{|#0:Ta|}, {|#1:T\\u0062|}> { }" };
29+
yield return new object[] { "struct Foo<{|#0:Ta|}, {|#1:T\\u0062|}> { }" };
30+
yield return new object[] { "interface Foo<{|#0:Ta|}, {|#1:T\\u0062|}> { }" };
3131
if (LightupHelpers.SupportsCSharp9)
3232
{
33-
yield return new object[] { "record Foo<Ta, Tb> { }" };
34-
yield return new object[] { "record Foo<Ta, T\\u0062> { }" };
33+
yield return new object[] { "record Foo<{|#0:Ta|}, {|#1:Tb|}> { }" };
34+
yield return new object[] { "record Foo<{|#0:Ta|}, {|#1:T\\u0062|}> { }" };
35+
}
36+
37+
if (LightupHelpers.SupportsCSharp10)
38+
{
39+
yield return new object[] { "record class Foo<{|#0:Ta|}, {|#1:Tb|}> { }" };
40+
yield return new object[] { "record struct Foo<{|#0:Ta|}, {|#1:T\\u0062|}> { }" };
3541
}
3642
}
3743
}
@@ -120,8 +126,8 @@ public async Task TestPartialTypesWithMissingDocumentationAsync(string p)
120126

121127
var expected = new[]
122128
{
123-
Diagnostic().WithLocation(5, 30).WithArguments("Ta"),
124-
Diagnostic().WithLocation(5, 34).WithArguments("Tb"),
129+
Diagnostic().WithLocation(0).WithArguments("Ta"),
130+
Diagnostic().WithLocation(1).WithArguments("Tb"),
125131
};
126132

127133
await VerifyCSharpDiagnosticAsync(testCode.Replace("##", p), expected, CancellationToken.None).ConfigureAwait(false);

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1625UnitTests.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ public static IEnumerable<object[]> Members
3333
{
3434
yield return new[] { "public record Test { }" };
3535
}
36+
37+
if (LightupHelpers.SupportsCSharp10)
38+
{
39+
yield return new[] { "public record class Test { }" };
40+
yield return new[] { "public record struct Test { }" };
41+
}
3642
}
3743
}
3844

StyleCop.Analyzers/StyleCop.Analyzers.Test/Helpers/CommonMemberData.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,17 @@ public static IEnumerable<object[]> DataTypeDeclarationKeywords
1515
{
1616
yield return new[] { "class" };
1717
yield return new[] { "struct" };
18+
1819
if (LightupHelpers.SupportsCSharp9)
1920
{
2021
yield return new[] { "record" };
2122
}
23+
24+
if (LightupHelpers.SupportsCSharp10)
25+
{
26+
yield return new[] { "record class" };
27+
yield return new[] { "record struct" };
28+
}
2229
}
2330
}
2431

StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1205UnitTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,19 @@ public static IEnumerable<object[]> ValidDeclarations
5555
yield return new object[] { "internal sealed partial record" };
5656
yield return new object[] { "record" };
5757
}
58+
59+
if (LightupHelpers.SupportsCSharp10)
60+
{
61+
yield return new object[] { "public partial record class" };
62+
yield return new object[] { "internal partial record class" };
63+
yield return new object[] { "public sealed partial record class" };
64+
yield return new object[] { "internal sealed partial record class" };
65+
yield return new object[] { "record class" };
66+
67+
yield return new object[] { "public partial record struct" };
68+
yield return new object[] { "internal partial record struct" };
69+
yield return new object[] { "record struct" };
70+
}
5871
}
5972
}
6073

@@ -72,6 +85,14 @@ public static IEnumerable<object[]> InvalidDeclarations
7285
yield return new object[] { "partial record" };
7386
yield return new object[] { "sealed partial record" };
7487
}
88+
89+
if (LightupHelpers.SupportsCSharp10)
90+
{
91+
yield return new object[] { "partial record class" };
92+
yield return new object[] { "sealed partial record class" };
93+
94+
yield return new object[] { "partial record struct" };
95+
}
7596
}
7697
}
7798

@@ -113,6 +134,23 @@ public static IEnumerable<object[]> ValidNestedDeclarations
113134
yield return new object[] { "private", "record" };
114135
yield return new object[] { "private protected", "record" };
115136
}
137+
138+
if (LightupHelpers.SupportsCSharp10)
139+
{
140+
yield return new object[] { "public", "record class" };
141+
yield return new object[] { "protected", "record class" };
142+
yield return new object[] { "internal", "record class" };
143+
yield return new object[] { "protected internal", "record class" };
144+
yield return new object[] { "private", "record class" };
145+
yield return new object[] { "private protected", "record class" };
146+
147+
yield return new object[] { "public", "record struct" };
148+
yield return new object[] { "protected", "record struct" };
149+
yield return new object[] { "internal", "record struct" };
150+
yield return new object[] { "protected internal", "record struct" };
151+
yield return new object[] { "private", "record struct" };
152+
yield return new object[] { "private protected", "record struct" };
153+
}
116154
}
117155
}
118156

StyleCop.Analyzers/StyleCop.Analyzers/Helpers/NamedTypeHelpers.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ internal static string GetNameOrIdentifier(MemberDeclarationSyntax member)
8787
case SyntaxKind.InterfaceDeclaration:
8888
case SyntaxKind.StructDeclaration:
8989
case SyntaxKindEx.RecordDeclaration:
90+
case SyntaxKindEx.RecordStructDeclaration:
9091
return ((TypeDeclarationSyntax)member).Identifier.Text;
9192

9293
case SyntaxKind.EnumDeclaration:

0 commit comments

Comments
 (0)