Skip to content

Commit b7bfa00

Browse files
committed
Update SA1202 for file-scoped namespaces
1 parent ea800e2 commit b7bfa00

5 files changed

Lines changed: 95 additions & 9 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/OrderingRules/ElementOrderCodeFixProvider.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace StyleCop.Analyzers.OrderingRules
1515
using Microsoft.CodeAnalysis.CSharp;
1616
using Microsoft.CodeAnalysis.CSharp.Syntax;
1717
using StyleCop.Analyzers.Helpers;
18+
using StyleCop.Analyzers.Lightup;
1819
using StyleCop.Analyzers.Settings.ObjectModel;
1920

2021
/// <summary>
@@ -82,9 +83,9 @@ private static SyntaxNode UpdateSyntaxRoot(MemberDeclarationSyntax memberDeclara
8283
return HandleTypeDeclaration(memberToMove, (TypeDeclarationSyntax)parentDeclaration, elementOrder, syntaxRoot, indentationSettings);
8384
}
8485

85-
if (parentDeclaration is NamespaceDeclarationSyntax)
86+
if (BaseNamespaceDeclarationSyntaxWrapper.IsInstance(parentDeclaration))
8687
{
87-
return HandleNamespaceDeclaration(memberToMove, (NamespaceDeclarationSyntax)parentDeclaration, elementOrder, syntaxRoot, indentationSettings);
88+
return HandleBaseNamespaceDeclaration(memberToMove, (BaseNamespaceDeclarationSyntaxWrapper)parentDeclaration, elementOrder, syntaxRoot, indentationSettings);
8889
}
8990

9091
if (parentDeclaration is CompilationUnitSyntax)
@@ -105,7 +106,7 @@ private static SyntaxNode HandleCompilationUnitDeclaration(MemberOrderHelper mem
105106
return OrderMember(memberOrder, compilationUnitDeclaration.Members, elementOrder, syntaxRoot, indentationSettings);
106107
}
107108

108-
private static SyntaxNode HandleNamespaceDeclaration(MemberOrderHelper memberOrder, NamespaceDeclarationSyntax namespaceDeclaration, ImmutableArray<OrderingTrait> elementOrder, SyntaxNode syntaxRoot, IndentationSettings indentationSettings)
109+
private static SyntaxNode HandleBaseNamespaceDeclaration(MemberOrderHelper memberOrder, BaseNamespaceDeclarationSyntaxWrapper namespaceDeclaration, ImmutableArray<OrderingTrait> elementOrder, SyntaxNode syntaxRoot, IndentationSettings indentationSettings)
109110
{
110111
return OrderMember(memberOrder, namespaceDeclaration.Members, elementOrder, syntaxRoot, indentationSettings);
111112
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp10/OrderingRules/SA1202CSharp10UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp10.OrderingRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp9.OrderingRules;
10+
using Xunit;
11+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
12+
StyleCop.Analyzers.OrderingRules.SA1202ElementsMustBeOrderedByAccess,
13+
StyleCop.Analyzers.OrderingRules.ElementOrderCodeFixProvider>;
714

815
public class SA1202CSharp10UnitTests : SA1202CSharp9UnitTests
916
{
17+
/// <summary>
18+
/// Verifies that the analyzer will properly handle ordering within a file-scoped namespace.
19+
/// </summary>
20+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
21+
[Fact]
22+
public async Task TestFileScopedNamespaceClassesAsync()
23+
{
24+
var testCode = @"namespace TestNamespace;
25+
26+
enum TestEnum1 { }
27+
public enum {|#0:TestEnum2|} { }
28+
class TestClass1 { }
29+
public class {|#1:TestClass2|} { }
30+
";
31+
32+
DiagnosticResult[] expected =
33+
{
34+
Diagnostic().WithLocation(0).WithArguments("public", "internal"),
35+
Diagnostic().WithLocation(1).WithArguments("public", "internal"),
36+
};
37+
38+
var fixedCode = @"namespace TestNamespace;
39+
public enum TestEnum2 { }
40+
41+
enum TestEnum1 { }
42+
public class TestClass2 { }
43+
class TestClass1 { }
44+
";
45+
46+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
47+
}
48+
49+
[Fact]
50+
public async Task TestDefaultAccessModifierOrderWithFileScopedNamespaceAsync()
51+
{
52+
string testCode = @"namespace Foo;
53+
54+
public class Class1 { }
55+
internal class Class2 { }
56+
class Class3 { }
57+
internal class Class4 { }
58+
class Class5 { }
59+
";
60+
61+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
62+
}
1063
}
1164
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1202UnitTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,36 @@ class TestClass1 { }
642642
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
643643
}
644644

645+
[Fact]
646+
public async Task TestDefaultAccessModifierOrderInCompilationUnitAsync()
647+
{
648+
string testCode = @"
649+
public class Class1 { }
650+
internal class Class2 { }
651+
class Class3 { }
652+
internal class Class4 { }
653+
class Class5 { }
654+
";
655+
656+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
657+
}
658+
659+
[Fact]
660+
public async Task TestDefaultAccessModifierOrderInNamespaceAsync()
661+
{
662+
string testCode = @"namespace Foo
663+
{
664+
public class Class1 { }
665+
internal class Class2 { }
666+
class Class3 { }
667+
internal class Class4 { }
668+
class Class5 { }
669+
}
670+
";
671+
672+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
673+
}
674+
645675
/// <summary>
646676
/// Verifies that the analyzer will properly handle static constructors.
647677
/// </summary>

StyleCop.Analyzers/StyleCop.Analyzers/Helpers/MemberOrderHelper.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace StyleCop.Analyzers.Helpers
88
using Microsoft.CodeAnalysis;
99
using Microsoft.CodeAnalysis.CSharp;
1010
using Microsoft.CodeAnalysis.CSharp.Syntax;
11+
using StyleCop.Analyzers.Lightup;
1112
using StyleCop.Analyzers.Settings.ObjectModel;
1213

1314
/// <summary>
@@ -151,7 +152,7 @@ internal static AccessLevel GetAccessLevelForOrdering(SyntaxNode member, SyntaxT
151152
accessibility = AccessLevelHelper.GetAccessLevel(modifiers);
152153
if (accessibility == AccessLevel.NotSpecified)
153154
{
154-
if (member.Parent.IsKind(SyntaxKind.CompilationUnit) || member.Parent.IsKind(SyntaxKind.NamespaceDeclaration))
155+
if (member.Parent.IsKind(SyntaxKind.CompilationUnit) || member.Parent.IsKind(SyntaxKind.NamespaceDeclaration) || member.Parent.IsKind(SyntaxKindEx.FileScopedNamespaceDeclaration))
155156
{
156157
accessibility = AccessLevel.Internal;
157158
}

StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1202ElementsMustBeOrderedByAccess.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace StyleCop.Analyzers.OrderingRules
1010
using Microsoft.CodeAnalysis.CSharp.Syntax;
1111
using Microsoft.CodeAnalysis.Diagnostics;
1212
using StyleCop.Analyzers.Helpers;
13+
using StyleCop.Analyzers.Lightup;
1314
using StyleCop.Analyzers.Settings.ObjectModel;
1415

1516
/// <summary>
@@ -69,7 +70,7 @@ internal class SA1202ElementsMustBeOrderedByAccess : DiagnosticAnalyzer
6970
SyntaxKind.OperatorDeclaration);
7071

7172
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> CompilationUnitAction = HandleCompilationUnit;
72-
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> NamespaceDeclarationAction = HandleNamespaceDeclaration;
73+
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> BaseNamespaceDeclarationAction = HandleBaseNamespaceDeclaration;
7374
private static readonly Action<SyntaxNodeAnalysisContext, StyleCopSettings> TypeDeclarationAction = HandleTypeDeclaration;
7475

7576
/// <inheritdoc/>
@@ -83,7 +84,7 @@ public override void Initialize(AnalysisContext context)
8384
context.EnableConcurrentExecution();
8485

8586
context.RegisterSyntaxNodeAction(CompilationUnitAction, SyntaxKind.CompilationUnit);
86-
context.RegisterSyntaxNodeAction(NamespaceDeclarationAction, SyntaxKind.NamespaceDeclaration);
87+
context.RegisterSyntaxNodeAction(BaseNamespaceDeclarationAction, SyntaxKinds.BaseNamespaceDeclaration);
8788
context.RegisterSyntaxNodeAction(TypeDeclarationAction, TypeDeclarationKinds);
8889
}
8990

@@ -101,7 +102,7 @@ private static void HandleCompilationUnit(SyntaxNodeAnalysisContext context, Sty
101102
HandleMemberList(context, elementOrder, accessibilityIndex, compilationUnit.Members);
102103
}
103104

104-
private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
105+
private static void HandleBaseNamespaceDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
105106
{
106107
var elementOrder = settings.OrderingRules.ElementOrder;
107108
int accessibilityIndex = elementOrder.IndexOf(OrderingTrait.Accessibility);
@@ -110,9 +111,9 @@ private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context
110111
return;
111112
}
112113

113-
var compilationUnit = (NamespaceDeclarationSyntax)context.Node;
114+
var baseNamespaceDeclaration = (BaseNamespaceDeclarationSyntaxWrapper)context.Node;
114115

115-
HandleMemberList(context, elementOrder, accessibilityIndex, compilationUnit.Members);
116+
HandleMemberList(context, elementOrder, accessibilityIndex, baseNamespaceDeclaration.Members);
116117
}
117118

118119
private static void HandleTypeDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings)

0 commit comments

Comments
 (0)