File: Organizing\Organizers\MemberDeclarationsOrganizer.Comparer.vb
Web Access
Project: src\src\Features\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.Features.vbproj (Microsoft.CodeAnalysis.VisualBasic.Features)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
 
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.VisualBasic.Utilities
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Organizing.Organizers
    Partial Friend Class MemberDeclarationsOrganizer
        Public Class Comparer
            Implements IComparer(Of StatementSyntax)
            ' TODO(cyrusn): Allow users to specify the ordering they want
            Public Enum OuterOrdering
                Fields
                EventFields
                Constructors
                Destructors
                Properties
                Events
                Indexers
                Operators
                ConversionOperators
                Methods
                Types
                Remaining
            End Enum
 
            Public Enum InnerOrdering
                StaticInstance
                Accessibility
                Name
            End Enum
 
            Public Enum Accessibility
                [Public]
                [Protected]
                [Friend]
                [Private]
            End Enum
 
            Public Function Compare(x As StatementSyntax, y As StatementSyntax) As Integer Implements IComparer(Of StatementSyntax).Compare
                If x Is y Then
                    Return 0
                End If
 
                Dim xOuterOrdering = GetOuterOrdering(x)
                Dim yOuterOrdering = GetOuterOrdering(y)
 
                Dim value = xOuterOrdering - yOuterOrdering
                If value <> 0 Then
                    Return value
                End If
 
                If xOuterOrdering = OuterOrdering.Remaining Then
                    Return 1
                ElseIf yOuterOrdering = OuterOrdering.Remaining Then
                    Return -1
                End If
 
                If xOuterOrdering = OuterOrdering.Fields OrElse yOuterOrdering = OuterOrdering.Fields Then
                    ' Fields with initializers can't be reordered relative to 
                    ' themselves due to ordering issues.
                    Dim xHasInitializer = DirectCast(x, FieldDeclarationSyntax).Declarators.Any(Function(v) v.Initializer IsNot Nothing)
                    Dim yHasInitializer = DirectCast(y, FieldDeclarationSyntax).Declarators.Any(Function(v) v.Initializer IsNot Nothing)
                    If xHasInitializer AndAlso yHasInitializer Then
                        Return 0
                    End If
                End If
 
                Dim xIsShared = x.GetModifiers().Any(Function(t) t.Kind = SyntaxKind.SharedKeyword)
                Dim yIsShared = y.GetModifiers().Any(Function(t) t.Kind = SyntaxKind.SharedKeyword)
 
                value = Comparer(Of Boolean).Default.Inverse().Compare(xIsShared, yIsShared)
                If value <> 0 Then
                    Return value
                End If
 
                Dim xAccessibility = GetAccessibility(x)
                Dim yAccessibility = GetAccessibility(y)
                value = xAccessibility - yAccessibility
                If value <> 0 Then
                    Return value
                End If
 
                Dim xName = If(ShouldCompareByName(x), TryCast(x, DeclarationStatementSyntax).GetNameToken(), Nothing)
                Dim yName = If(ShouldCompareByName(x), TryCast(y, DeclarationStatementSyntax).GetNameToken(), Nothing)
 
                value = TokenComparer.NormalInstance.Compare(xName, yName)
                If value <> 0 Then
                    Return value
                End If
 
                ' Their names were the same.  Order them by arity at this point.
                Return x.GetArity() - y.GetArity()
            End Function
 
            Private Shared Function GetAccessibility(x As StatementSyntax) As Accessibility
                Dim xModifiers = x.GetModifiers()
 
                If xModifiers.Any(Function(t) t.Kind = SyntaxKind.PublicKeyword) Then
                    Return Accessibility.Public
                ElseIf xModifiers.Any(Function(t) t.Kind = SyntaxKind.FriendKeyword) Then
                    Return Accessibility.Friend
                ElseIf xModifiers.Any(Function(t) t.Kind = SyntaxKind.ProtectedKeyword) Then
                    Return Accessibility.Protected
                Else
                    ' Only fields are private in VB. All other members are public
                    If x.Kind = SyntaxKind.FieldDeclaration Then
                        Return Accessibility.Private
                    Else
                        Return Accessibility.Public
                    End If
                End If
            End Function
 
            Private Shared Function GetOuterOrdering(x As StatementSyntax) As OuterOrdering
                Select Case x.Kind
                    Case SyntaxKind.FieldDeclaration
                        Return OuterOrdering.Fields
                    Case SyntaxKind.ConstructorBlock
                        Return OuterOrdering.Constructors
                    Case SyntaxKind.PropertyBlock
                        Return OuterOrdering.Properties
                    Case SyntaxKind.EventBlock
                        Return OuterOrdering.Events
                    Case SyntaxKind.OperatorBlock
                        Return OuterOrdering.Operators
                    Case SyntaxKind.SubBlock,
                        SyntaxKind.FunctionBlock
                        Return OuterOrdering.Methods
                    Case SyntaxKind.ClassBlock,
                        SyntaxKind.InterfaceBlock,
                        SyntaxKind.StructureBlock,
                        SyntaxKind.EnumBlock,
                        SyntaxKind.DelegateSubStatement,
                        SyntaxKind.DelegateFunctionStatement
                        Return OuterOrdering.Types
                    Case Else
                        Return OuterOrdering.Remaining
                End Select
            End Function
 
            Private Shared Function ShouldCompareByName(x As StatementSyntax) As Boolean
                ' Constructors and operators should not be sorted by name.
                Select Case x.Kind
                    Case SyntaxKind.ConstructorBlock,
                         SyntaxKind.OperatorBlock
                        Return False
                    Case Else
                        Return True
                End Select
            End Function
        End Class
    End Class
End Namespace