Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sort static members first #4

Merged
merged 1 commit into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ private static async Task<Document> ReorderMembersAsync(Document document, Class
{
SyntaxList<MemberDeclarationSyntax> members = classDeclaration.Members;
List<MemberDeclarationSyntax> sortedMembers = members
.OrderBy(MemberOrderAnalyzer.GetMemberCategory)
.ThenBy(MemberOrderAnalyzer.GetAccessibilityModifier)
.OrderBy(MemberOrderAnalyzer.GetMemberCategoryOrder)
.ThenBy(MemberOrderAnalyzer.GetAccessibilityModifierOrder)
.ThenBy(MemberOrderAnalyzer.GetStaticOrder)
.ThenBy(MemberOrderAnalyzer.GetMemberName)
.ToList();
TryKeepWhiteSpace(ref members, sortedMembers);
Expand Down
35 changes: 31 additions & 4 deletions src/MemberOrder/MemberOrder/MemberOrderAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,19 @@ public class MemberOrderAnalyzer : DiagnosticAnalyzer
/// </summary>
/// <param name="member">The member.</param>
/// <returns><see cref="int"/>.</returns>
public static int GetAccessibilityModifier(MemberDeclarationSyntax member)
public static int GetAccessibilityModifierOrder(MemberDeclarationSyntax member)
{
if (member is null)
{
throw new ArgumentNullException(nameof(member));
}

if (member is ConstructorDeclarationSyntax && member.Modifiers.Any(SyntaxKind.StaticKeyword))
{
// Special case static constructors to come first.
return -1;
}

// public
if (member.Modifiers.Any(SyntaxKind.PublicKeyword))
{
Expand Down Expand Up @@ -96,7 +102,7 @@ public static int GetAccessibilityModifier(MemberDeclarationSyntax member)
/// </summary>
/// <param name="member">The member.</param>
/// <returns><see cref="int"/>.</returns>
public static int GetMemberCategory(MemberDeclarationSyntax member)
public static int GetMemberCategoryOrder(MemberDeclarationSyntax member)
{
if (member is null)
{
Expand Down Expand Up @@ -145,6 +151,26 @@ public static string GetMemberName(MemberDeclarationSyntax member)
};
}

/// <summary>
/// Gets the static order.
/// </summary>
/// <param name="member">The member.</param>
/// <returns><see cref="int"/>.</returns>
public static int GetStaticOrder(MemberDeclarationSyntax member)
{
if (member is null)
{
throw new ArgumentNullException(nameof(member));
}

if (member.Modifiers.Any(SyntaxKind.StaticKeyword))
{
return 0;
}

return 1;
}

/// <summary>
/// Initializes the specified context.
/// </summary>
Expand All @@ -168,8 +194,9 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
Location classLocation = classDeclaration.GetLocation();
SyntaxList<MemberDeclarationSyntax> members = classDeclaration.Members;
List<MemberDeclarationSyntax> sortedMembers = members
.OrderBy(GetMemberCategory)
.ThenBy(GetAccessibilityModifier)
.OrderBy(GetMemberCategoryOrder)
.ThenBy(GetAccessibilityModifierOrder)
.ThenBy(GetStaticOrder)
.ThenBy(GetMemberName)
.ToList();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,29 @@ class MyClass
await VerifyCSCodeFix.VerifyCodeFixAsync(test, expected, fixtest);
}

[TestMethod]
public async Task CodeFix_FieldsOutOfStaticOrder_Reordered()
{
string test = @"
class MyClass
{
public int myPublicFieldA;
public static int myPublicStaticFieldA;
}";

string fixtest = @"
class MyClass
{
public static int myPublicStaticFieldA;
public int myPublicFieldA;
}";

DiagnosticResult expected = VerifyCSCodeFix.Diagnostic(MemberOrderAnalyzer.DiagnosticId)
.WithLocation("", 2, 9)
.WithArguments("MyClass");
await VerifyCSCodeFix.VerifyCodeFixAsync(test, expected, fixtest);
}

[TestMethod]
public async Task CodeFix_MembersOutOfTypeOrder_Reordered()
{
Expand Down
71 changes: 71 additions & 0 deletions tests/MemberOrder/MemberOrder.Tests/MemberOrderUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,54 @@ public async Task Analyzer_Class_AllCategoriesModifiersAndNamesInOrder_NoDiagnos
public class MyClass
{
// Fields
public static int myPublicStaticFieldA;
public static int myPublicStaticFieldB;
public int myPublicFieldA;
public int myPublicFieldB;
internal static int myInternalStaticFieldA;
internal static int myInternalStaticFieldB;
internal int myInternalFieldA;
internal int myInternalFieldB;
protected internal static int myProtectedInternalStaticFieldA;
protected internal static int myProtectedInternalStaticFieldB;
protected internal int myProtectedInternalFieldA;
protected internal int myProtectedInternalFieldB;
private protected static int myPrivateProtectedStaticFieldA;
private protected static int myPrivateProtectedStaticFieldB;
private protected int myPrivateProtectedFieldA;
private protected int myPrivateProtectedFieldB;
protected static int myProtectedStaticFieldA;
protected static int myProtectedStaticFieldB;
protected int myProtectedFieldA;
protected int myProtectedFieldB;
private static int myPrivateStaticFieldA;
private static int myPrivateStaticFieldB;
private int myPrivateFieldA;
private int myPrivateFieldB;

// Properties
public static int MyPublicStaticPropertyA { get; set; }
public static int MyPublicStaticPropertyB { get; set; }
public int MyPublicPropertyA { get; set; }
public int MyPublicPropertyB { get; set; }
internal static int MyInternalStaticPropertyA { get; set; }
internal static int MyInternalStaticPropertyB { get; set; }
internal int MyInternalPropertyA { get; set; }
internal int MyInternalPropertyB { get; set; }
protected internal static int MyProtectedInternalStaticPropertyA { get; set; }
protected internal static int MyProtectedInternalStaticPropertyB { get; set; }
protected internal int MyProtectedInternalPropertyA { get; set; }
protected internal int MyProtectedInternalPropertyB { get; set; }
private protected static int MyPrivateProtectedStaticPropertyA { get; set; }
private protected static int MyPrivateProtectedStaticPropertyB { get; set; }
private protected int MyPrivateProtectedPropertyA { get; set; }
private protected int MyPrivateProtectedPropertyB { get; set; }
protected static int MyProtectedStaticPropertyA { get; set; }
protected static int MyProtectedStaticPropertyB { get; set; }
protected int MyProtectedPropertyA { get; set; }
protected int MyProtectedPropertyB { get; set; }
private static int MyPrivateStaticPropertyA { get; set; }
private static int MyPrivateStaticPropertyB { get; set; }
private int MyPrivatePropertyA { get; set; }
private int MyPrivatePropertyB { get; set; }

Expand Down Expand Up @@ -93,6 +117,7 @@ private event MyPrivateDelegateB MyPrivateEventB { add { } remove { } }
private int this[int a, int b, int c, int d, int e, int f] { get => 0; set { } }

// Constructors
static MyClass() { }
public MyClass() { }
internal MyClass(int a, int b) { }
protected internal MyClass(int a) { }
Expand All @@ -104,16 +129,28 @@ private MyClass(int a, int b, int c, int d, int e) { }
~MyClass() { }

// Methods
public static void MyPublicStaticMethodA() { }
public static void MyPublicStaticMethodB() { }
public void MyPublicMethodA() { }
public void MyPublicMethodB() { }
internal static void MyInternalStaticMethodA() { }
internal static void MyInternalStaticMethodB() { }
internal void MyInternalMethodA() { }
internal void MyInternalMethodB() { }
protected internal static void MyProtectedInternalStaticMethodA() { }
protected internal static void MyProtectedInternalStaticMethodB() { }
protected internal void MyProtectedInternalMethodA() { }
protected internal void MyProtectedInternalMethodB() { }
private protected static void MyPrivateProtectedStaticMethodA() { }
private protected static void MyPrivateProtectedStaticMethodB() { }
private protected void MyPrivateProtectedMethodA() { }
private protected void MyPrivateProtectedMethodB() { }
protected static void MyProtectedStaticMethodA() { }
protected static void MyProtectedStaticMethodB() { }
protected void MyProtectedMethodA() { }
protected void MyProtectedMethodB() { }
private static void MyPrivateStaticMethodA() { }
private static void MyPrivateStaticMethodB() { }
private void MyPrivateMethodA() { }
private void MyPrivateMethodB() { }
}";
Expand Down Expand Up @@ -310,4 +347,38 @@ public async Task Analyzer_EmptyContent_NoDiagnostics()

await VerifyCS.VerifyAnalyzerAsync(test);
}

[TestMethod]
public void GetAccessibilityModifierOrder_NullMember_ThrowsArgumentNullException() =>

// Act and assert
Assert.ThrowsException<ArgumentNullException>(() => MemberOrderAnalyzer.GetAccessibilityModifierOrder(null!));

[TestMethod]
public void GetMemberCategoryOrder_NullMember_ThrowsArgumentNullException() =>

// Act and assert
Assert.ThrowsException<ArgumentNullException>(() => MemberOrderAnalyzer.GetMemberCategoryOrder(null!));

[TestMethod]
public void GetMemberName_NullMember_ThrowsArgumentNullException() =>

// Act and assert
Assert.ThrowsException<ArgumentNullException>(() => MemberOrderAnalyzer.GetMemberName(null!));

[TestMethod]
public void GetStaticOrder_NullMember_ThrowsArgumentNullException() =>

// Act and assert
Assert.ThrowsException<ArgumentNullException>(() => MemberOrderAnalyzer.GetStaticOrder(null!));

[TestMethod]
public void Initialize_NullContext_ThrowsArgumentNullException()
{
// Arrange
MemberOrderAnalyzer analyzer = new();

// Act and assert
Assert.ThrowsException<ArgumentNullException>(() => analyzer.Initialize(null!));
}
}