Skip to content

Commit 73af9b4

Browse files
authored
Merge pull request #3879 from 6bee/fix/3803
Exempt file-local types from SA1402 [resolves #3803]
2 parents 4484f72 + 1d31122 commit 73af9b4

File tree

10 files changed

+199
-1
lines changed

10 files changed

+199
-1
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/MaintainabilityRules/SA1402ForClassCSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.MaintainabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp10.MaintainabilityRules;
10+
using Xunit;
711

812
public partial class SA1402ForClassCSharp11UnitTests : SA1402ForClassCSharp10UnitTests
913
{
14+
/// <summary>
15+
/// Verifies that SA1402 is not reported for file-local class types.
16+
/// </summary>
17+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
18+
[Fact]
19+
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
20+
public async Task VerifyFileLocalClassExemptionAsync()
21+
{
22+
var testCode = @"namespace TestNamespace;
23+
24+
public class TestClass1 { }
25+
26+
file class TestClass2 { }
27+
";
28+
29+
await this.VerifyCSharpDiagnosticAsync(testCode, this.GetSettings(), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
30+
}
31+
32+
/// <summary>
33+
/// Verifies that SA1402 is not reported for file-local static class types.
34+
/// </summary>
35+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
36+
[Fact]
37+
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
38+
public async Task VerifyFileLocalStaticClassExemptionAsync()
39+
{
40+
var testCode = @"namespace TestNamespace;
41+
42+
public class TestClass1 { }
43+
44+
file static class TestClass2 { }
45+
";
46+
47+
await this.VerifyCSharpDiagnosticAsync(testCode, this.GetSettings(), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
48+
}
1049
}
1150
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/MaintainabilityRules/SA1402ForDelegateCSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.MaintainabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp10.MaintainabilityRules;
10+
using Xunit;
711

812
public partial class SA1402ForDelegateCSharp11UnitTests : SA1402ForDelegateCSharp10UnitTests
913
{
14+
/// <summary>
15+
/// Verifies that SA1402 is not reported for file-local delegate types.
16+
/// </summary>
17+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
18+
[Fact]
19+
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
20+
public async Task VerifyFileLocalDelegateExemptionAsync()
21+
{
22+
var testCode = @"namespace TestNamespace;
23+
24+
public class TestClass { }
25+
26+
file delegate void TestDelegate();
27+
";
28+
29+
await VerifyCSharpDiagnosticAsync(testCode, this.GetSettings(), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
30+
}
1031
}
1132
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/MaintainabilityRules/SA1402ForEnumCSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.MaintainabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp10.MaintainabilityRules;
10+
using Xunit;
711

812
public partial class SA1402ForEnumCSharp11UnitTests : SA1402ForEnumCSharp10UnitTests
913
{
14+
/// <summary>
15+
/// Verifies that SA1402 is not reported for file-local enum types.
16+
/// </summary>
17+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
18+
[Fact]
19+
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
20+
public async Task VerifyFileLocalEnumExemptionAsync()
21+
{
22+
var testCode = @"namespace TestNamespace;
23+
24+
public class TestClass1 { }
25+
26+
file enum TestEnum { }
27+
";
28+
29+
await VerifyCSharpDiagnosticAsync(testCode, this.GetSettings(), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
30+
}
1031
}
1132
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/MaintainabilityRules/SA1402ForInterfaceCSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.MaintainabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp10.MaintainabilityRules;
10+
using Xunit;
711

812
public partial class SA1402ForInterfaceCSharp11UnitTests : SA1402ForInterfaceCSharp10UnitTests
913
{
14+
/// <summary>
15+
/// Verifies that SA1402 is not reported for file-local interface types.
16+
/// </summary>
17+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
18+
[Fact]
19+
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
20+
public async Task VerifyFileLocalInterfaceExemptionAsync()
21+
{
22+
var testCode = @"namespace TestNamespace;
23+
24+
public interface TestInterface1 { }
25+
26+
file interface TestInterface2 { }
27+
";
28+
29+
await this.VerifyCSharpDiagnosticAsync(testCode, this.GetSettings(), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
30+
}
1031
}
1132
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/MaintainabilityRules/SA1402ForRecordCSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.MaintainabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp10.MaintainabilityRules;
10+
using Xunit;
711

812
public partial class SA1402ForRecordCSharp11UnitTests : SA1402ForRecordCSharp10UnitTests
913
{
14+
/// <summary>
15+
/// Verifies that SA1402 is not reported for file-local record types.
16+
/// </summary>
17+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
18+
[Fact]
19+
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
20+
public async Task VerifyFileLocalRecordExemptionAsync()
21+
{
22+
var testCode = @"namespace TestNamespace;
23+
24+
public record TestRecord1 { }
25+
26+
file record TestRecord2 { }
27+
";
28+
29+
await this.VerifyCSharpDiagnosticAsync(testCode, this.GetSettings(), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
30+
}
1031
}
1132
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/MaintainabilityRules/SA1402ForRecordClassCSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.MaintainabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp10.MaintainabilityRules;
10+
using Xunit;
711

812
public partial class SA1402ForRecordClassCSharp11UnitTests : SA1402ForRecordClassCSharp10UnitTests
913
{
14+
/// <summary>
15+
/// Verifies that SA1402 is not reported for file-local record class types.
16+
/// </summary>
17+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
18+
[Fact]
19+
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
20+
public async Task VerifyFileLocalRecordClassExemptionAsync()
21+
{
22+
var testCode = @"namespace TestNamespace;
23+
24+
public class TestClass { }
25+
26+
file record class TestRecordClass { }
27+
";
28+
29+
await this.VerifyCSharpDiagnosticAsync(testCode, this.GetSettings(), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
30+
}
1031
}
1132
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/MaintainabilityRules/SA1402ForRecordStructCSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.MaintainabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp10.MaintainabilityRules;
10+
using Xunit;
711

812
public partial class SA1402ForRecordStructCSharp11UnitTests : SA1402ForRecordStructCSharp10UnitTests
913
{
14+
/// <summary>
15+
/// Verifies that SA1402 is not reported for file-local record struct types.
16+
/// </summary>
17+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
18+
[Fact]
19+
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
20+
public async Task VerifyFileLocalRecordStructExemptionAsync()
21+
{
22+
var testCode = @"namespace TestNamespace;
23+
24+
public class TestClass { }
25+
26+
file record struct TestRecordStruct { }
27+
";
28+
29+
await this.VerifyCSharpDiagnosticAsync(testCode, this.GetSettings(), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
30+
}
1031
}
1132
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp11/MaintainabilityRules/SA1402ForStructCSharp11UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp11.MaintainabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp10.MaintainabilityRules;
10+
using Xunit;
711

812
public partial class SA1402ForStructCSharp11UnitTests : SA1402ForStructCSharp10UnitTests
913
{
14+
/// <summary>
15+
/// Verifies that SA1402 is not reported for file-local struct types.
16+
/// </summary>
17+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
18+
[Fact]
19+
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
20+
public async Task VerifyFileLocalStructExemptionAsync()
21+
{
22+
var testCode = @"namespace TestNamespace;
23+
24+
public struct TestStruct1 { }
25+
26+
file struct TestStruct2 { }
27+
";
28+
29+
await this.VerifyCSharpDiagnosticAsync(testCode, this.GetSettings(), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
30+
}
1031
}
1132
}

StyleCop.Analyzers/StyleCop.Analyzers/MaintainabilityRules/SA1402FileMayOnlyContainASingleType.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,13 @@ private static bool ContainsTopLevelTypeDeclarations(SyntaxNode node)
108108
return node.IsKind(SyntaxKind.CompilationUnit) || node.IsKind(SyntaxKind.NamespaceDeclaration) || node.IsKind(SyntaxKindEx.FileScopedNamespaceDeclaration);
109109
}
110110

111-
private static bool IsRelevantType(SyntaxNode node, StyleCopSettings settings)
111+
private static bool IsRelevantType(MemberDeclarationSyntax node, StyleCopSettings settings)
112112
{
113+
if (IsFileLocalType(node))
114+
{
115+
return false;
116+
}
117+
113118
var topLevelTypes = settings.MaintainabilityRules.TopLevelTypes;
114119
var isRelevant = false;
115120

@@ -136,5 +141,10 @@ private static bool IsRelevantType(SyntaxNode node, StyleCopSettings settings)
136141

137142
return isRelevant;
138143
}
144+
145+
private static bool IsFileLocalType(MemberDeclarationSyntax node)
146+
{
147+
return node.GetModifiers().Any(SyntaxKindEx.FileKeyword);
148+
}
139149
}
140150
}

documentation/SA1402.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ It is possible to configure which kind of types this rule should affect. By defa
2727

2828
It is also possible to place multiple parts of the same partial type within the same file.
2929

30+
File-local types declared using `file` modifier are exempt from this rule.
31+
3032
## How to fix violations
3133

3234
To fix an instance of this violation, move each type into its own file.

0 commit comments

Comments
 (0)