diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/NamingRules/SA1300CSharp10UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/NamingRules/SA1300CSharp10UnitTests.cs
index a73681caa..52afca31d 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/NamingRules/SA1300CSharp10UnitTests.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/NamingRules/SA1300CSharp10UnitTests.cs
@@ -95,5 +95,38 @@ public async Task TestAllowedLowerCaseComplicatedFileScopedNamespaceIsNotReporte
Settings = customTestSettings,
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
}
+
+ [Fact]
+ [WorkItem(3979, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3979")]
+ public async Task TestRecordStructNameMustStartWithUpperCaseLetterAsync()
+ {
+ var testCode = @"
+public record struct {|#0:r|}(int A)
+{
+ public {|#1:r|}(int a, int b)
+ : this(A: a)
+ {
+ }
+}
+";
+
+ var fixedCode = @"
+public record struct R(int A)
+{
+ public R(int a, int b)
+ : this(A: a)
+ {
+ }
+}
+";
+
+ DiagnosticResult[] expected =
+ {
+ Diagnostic().WithLocation(0).WithArguments("r"),
+ Diagnostic().WithLocation(1).WithArguments("r"),
+ };
+
+ await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
+ }
}
}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1204UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1204UnitTests.cs
index fb7769f31..f7e82f18d 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1204UnitTests.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1204UnitTests.cs
@@ -132,63 +132,23 @@ public class TestClass1 { }
}
///
- /// Verifies that the analyzer will properly handle non-static elements before static in a class.
+ /// Verifies that the analyzer will properly handle non-static elements before static in a type.
///
+ /// The keyword used to declare the type.
/// A representing the asynchronous unit test.
- [Fact]
- public async Task TestOrderingInClassAsync()
- {
- var testCode = @"public class TestClass
-{
- public int TestField1;
- public static int TestField2;
- public int TestProperty1 { get; set; }
- public static int TestProperty2 { get; set; }
- public void TestMethod1() { }
- public static void TestMethod2() { }
-
-}
-";
-
- DiagnosticResult[] expected =
- {
- Diagnostic().WithLocation(4, 23),
- Diagnostic().WithLocation(6, 23),
- Diagnostic().WithLocation(8, 24),
- };
-
- var fixedCode = @"public class TestClass
-{
- public static int TestField2;
- public int TestField1;
- public static int TestProperty2 { get; set; }
- public int TestProperty1 { get; set; }
- public static void TestMethod2() { }
- public void TestMethod1() { }
-
-}
-";
-
- await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
- }
-
- ///
- /// Verifies that the analyzer will properly handle non-static elements before static in a struct.
- ///
- /// A representing the asynchronous unit test.
- [Fact]
- public async Task TestOrderingInStructAsync()
+ [Theory]
+ [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))]
+ public async Task TestOrderingInClassAsync(string keyword)
{
- var testCode = @"public struct TestStruct
-{
+ var testCode = $@"public {keyword} TestClass
+{{
public int TestField1;
public static int TestField2;
- public int TestProperty1 { get; set; }
- public static int TestProperty2 { get; set; }
- public void TestMethod1() { }
- public static void TestMethod2() { }
-
-}
+ public int TestProperty1 {{ get; set; }}
+ public static int TestProperty2 {{ get; set; }}
+ public void TestMethod1() {{ }}
+ public static void TestMethod2() {{ }}
+}}
";
DiagnosticResult[] expected =
@@ -198,16 +158,15 @@ public static void TestMethod2() { }
Diagnostic().WithLocation(8, 24),
};
- var fixedCode = @"public struct TestStruct
-{
+ var fixedCode = $@"public {keyword} TestClass
+{{
public static int TestField2;
public int TestField1;
- public static int TestProperty2 { get; set; }
- public int TestProperty1 { get; set; }
- public static void TestMethod2() { }
- public void TestMethod1() { }
-
-}
+ public static int TestProperty2 {{ get; set; }}
+ public int TestProperty1 {{ get; set; }}
+ public static void TestMethod2() {{ }}
+ public void TestMethod1() {{ }}
+}}
";
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1214UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1214UnitTests.cs
index e1c66ed4d..5cff234fd 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1214UnitTests.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1214UnitTests.cs
@@ -85,10 +85,35 @@ private void TestMethod10() { }
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
}
+ [Theory]
+ [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))]
+ public async Task TestTwoFieldsInClassStaticReadonlyFieldPlacedAfterStaticNonReadonlyAsync(string keyword)
+ {
+ var testCode = $@"
+public {keyword} Foo
+{{
+ private static int i = 0;
+ private static readonly int {{|#0:j|}} = 0;
+}}";
+
+ var expected = new[]
+ {
+ Diagnostic().WithLocation(0),
+ };
+
+ var fixTestCode = $@"
+public {keyword} Foo
+{{
+ private static readonly int j = 0;
+ private static int i = 0;
+}}";
+ await VerifyCSharpFixAsync(testCode, expected, fixTestCode, CancellationToken.None).ConfigureAwait(false);
+ }
+
[Theory]
[InlineData("\n")]
[InlineData("\r\n")]
- public async Task TestTwoFieldsInClassStaticReadonlyFieldPlacedAfterStaticNonReadonlyAsync(string lineEnding)
+ public async Task TestTwoFieldsInClassStaticReadonlyFieldPlacedAfterStaticNonReadonlyWithLineEndingAsync(string lineEnding)
{
var testCode = @"
public class Foo
@@ -146,36 +171,24 @@ public class Foo
await VerifyCSharpFixAsync(testCode, expected, fixTestCode, CancellationToken.None).ConfigureAwait(false);
}
- [Fact]
- public async Task TestTwoFieldsInClassStaticReadonlyFieldPlacedBeforeStaticNonReadonlyAsync()
- {
- var testCode = @"
-public class Foo
-{
- private static readonly int i = 0;
- private static int j = 0;
-}";
-
- await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
- }
-
- [Fact]
- public async Task TestTwoFieldsInClassNonStaticReadonlyFieldPlacedAfterNonStaticNonReadonlyAsync()
+ [Theory]
+ [MemberData(nameof(CommonMemberData.DataTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))]
+ public async Task TestTwoFieldsInClassNonStaticReadonlyFieldPlacedAfterNonStaticNonReadonlyAsync(string keyword)
{
- var testCode = @"
-public class Foo
-{
- private int i = 0;
- private readonly int j = 0;
-}";
- var fixedCode = @"
-public class Foo
-{
- private readonly int j = 0;
- private int i = 0;
-}";
-
- var expected = Diagnostic().WithLocation(5, 26);
+ var testCode = $@"
+public {keyword} Foo
+{{
+ private int i;
+ private readonly int {{|#0:j|}};
+}}";
+ var fixedCode = $@"
+public {keyword} Foo
+{{
+ private readonly int j;
+ private int i;
+}}";
+
+ var expected = Diagnostic().WithLocation(0);
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
}
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1204StaticElementsMustAppearBeforeInstanceElements.cs b/StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1204StaticElementsMustAppearBeforeInstanceElements.cs
index 1e8ff1830..e348a3801 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1204StaticElementsMustAppearBeforeInstanceElements.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1204StaticElementsMustAppearBeforeInstanceElements.cs
@@ -41,7 +41,12 @@ internal class SA1204StaticElementsMustAppearBeforeInstanceElements : Diagnostic
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.OrderingRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
private static readonly ImmutableArray TypeDeclarationKinds =
- ImmutableArray.Create(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.InterfaceDeclaration);
+ ImmutableArray.Create(
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.StructDeclaration,
+ SyntaxKind.InterfaceDeclaration,
+ SyntaxKindEx.RecordDeclaration,
+ SyntaxKindEx.RecordStructDeclaration);
private static readonly Action CompilationUnitAction = HandleCompilationUnit;
private static readonly Action BaseNamespaceDeclarationAction = HandleBaseNamespaceDeclaration;
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1214ReadonlyElementsMustAppearBeforeNonReadonlyElements.cs b/StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1214ReadonlyElementsMustAppearBeforeNonReadonlyElements.cs
index a732a62f9..d0661ac9e 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1214ReadonlyElementsMustAppearBeforeNonReadonlyElements.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1214ReadonlyElementsMustAppearBeforeNonReadonlyElements.cs
@@ -12,6 +12,7 @@ namespace StyleCop.Analyzers.OrderingRules
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using StyleCop.Analyzers.Helpers;
+ using StyleCop.Analyzers.Lightup;
using StyleCop.Analyzers.Settings.ObjectModel;
///
@@ -34,7 +35,11 @@ internal class SA1214ReadonlyElementsMustAppearBeforeNonReadonlyElements : Diagn
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.OrderingRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
private static readonly ImmutableArray TypeDeclarationKinds =
- ImmutableArray.Create(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration);
+ ImmutableArray.Create(
+ SyntaxKind.ClassDeclaration,
+ SyntaxKind.StructDeclaration,
+ SyntaxKindEx.RecordDeclaration,
+ SyntaxKindEx.RecordStructDeclaration);
private static readonly Action TypeDeclarationAction = HandleTypeDeclaration;
diff --git a/documentation/SA1201.md b/documentation/SA1201.md
index ccf2d2c51..f1db9a7a1 100644
--- a/documentation/SA1201.md
+++ b/documentation/SA1201.md
@@ -47,9 +47,9 @@ Within a class, struct, or interface, elements should be positioned in the follo
* Indexers
* Methods
* Structs
-* Classes*
+* Classes
-> 📝 For ordering purposes, C# 9 records are treated as classes.
+> 📝 For ordering purposes, C# 9 records are treated as classes, and C# 10 record structs are treated as structs.
Complying with a standard ordering scheme based on element type can increase the readability and maintainability of the file and encourage code reuse.
diff --git a/documentation/SA1642.md b/documentation/SA1642.md
index cdacbb95f..2e2ae326b 100644
--- a/documentation/SA1642.md
+++ b/documentation/SA1642.md
@@ -52,7 +52,19 @@ public MyStruct()
}
```
-For C# 9 record types, constructors follow the same pattern: record classes use the word 'class' in the summary text, while record structs use 'struct'.
+For record types, constructors follow the same pattern: record classes use the word 'class' in the summary text, while record structs use 'struct'. For example:
+
+```csharp
+public record struct Customer
+{
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ public Customer()
+ {
+ }
+}
+```
If the class contains generic parameters, these can be annotated within the `cref` link using either of the following
two formats: