private void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);

            var descentNodes = syntaxRoot.DescendantNodes(descendIntoChildren: node => node != null && !node.IsKind(SyntaxKind.ClassDeclaration));

            bool foundNode = false;

            foreach (var node in descentNodes)
            {
                if (node.IsKind(SyntaxKind.NamespaceDeclaration))
                {
                    if (foundNode)
                    {
                        var location = NamedTypeHelpers.GetNameOrIdentifierLocation(node);
                        if (location != null)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
                        }
                    }
                    else
                    {
                        foundNode = true;
                    }
                }
            }
        }
        private static void HandleTypeDeclaration(SyntaxNodeAnalysisContext context)
        {
            var typeDeclaration = (TypeDeclarationSyntax)context.Node;

            var previousFieldReadonly       = true;
            var previousAccessLevel         = AccessLevel.NotSpecified;
            var previousMemberStaticOrConst = true;

            foreach (var member in typeDeclaration.Members)
            {
                var field = member as FieldDeclarationSyntax;
                if (field == null)
                {
                    continue;
                }

                var currentFieldReadonly = field.Modifiers.Any(SyntaxKind.ReadOnlyKeyword);
                var currentAccessLevel   = AccessLevelHelper.GetAccessLevel(field.Modifiers);
                currentAccessLevel = currentAccessLevel == AccessLevel.NotSpecified ? AccessLevel.Private : currentAccessLevel;
                var currentMemberStaticOrConst = field.Modifiers.Any(SyntaxKind.StaticKeyword) || field.Modifiers.Any(SyntaxKind.ConstKeyword);
                if (currentAccessLevel == previousAccessLevel &&
                    !currentMemberStaticOrConst &&
                    !previousMemberStaticOrConst &&
                    currentFieldReadonly &&
                    !previousFieldReadonly)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, NamedTypeHelpers.GetNameOrIdentifierLocation(field), AccessLevelHelper.GetName(currentAccessLevel)));
                }

                previousFieldReadonly       = currentFieldReadonly;
                previousAccessLevel         = currentAccessLevel;
                previousMemberStaticOrConst = currentMemberStaticOrConst;
            }
        }
        private static void HandleTypeDeclaration(SyntaxNodeAnalysisContext context)
        {
            var typeDeclaration = (TypeDeclarationSyntax)context.Node;

            var members = typeDeclaration.Members;
            var previousFieldConstant = true;
            var previousAccessLevel   = AccessLevel.NotSpecified;

            foreach (var member in members)
            {
                var field = member as FieldDeclarationSyntax;
                if (field == null)
                {
                    continue;
                }

                bool currentFieldConstant = field.Modifiers.Any(SyntaxKind.ConstKeyword);
                var  currentAccessLevel   = AccessLevelHelper.GetAccessLevel(field.Modifiers);
                currentAccessLevel = currentAccessLevel == AccessLevel.NotSpecified ? AccessLevel.Private : currentAccessLevel;

                if (currentAccessLevel == previousAccessLevel && !previousFieldConstant && currentFieldConstant)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, NamedTypeHelpers.GetNameOrIdentifierLocation(member), AccessLevelHelper.GetName(currentAccessLevel)));
                }

                previousFieldConstant = currentFieldConstant;
                previousAccessLevel   = currentAccessLevel;
            }
        }
Example #4
0
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);

            var descentNodes = syntaxRoot.DescendantNodes(descendIntoChildren: node => node != null && !node.IsKind(SyntaxKind.ClassDeclaration));

            string foundClassName = null;
            bool   isPartialClass = false;

            foreach (var node in descentNodes)
            {
                if (node.IsKind(SyntaxKind.ClassDeclaration))
                {
                    ClassDeclarationSyntax classDeclaration = node as ClassDeclarationSyntax;
                    if (foundClassName != null)
                    {
                        if (isPartialClass && foundClassName == classDeclaration.Identifier.Text)
                        {
                            continue;
                        }

                        var location = NamedTypeHelpers.GetNameOrIdentifierLocation(node);
                        if (location != null)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
                        }
                    }
                    else
                    {
                        foundClassName = classDeclaration.Identifier.Text;
                        isPartialClass = classDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword);
                    }
                }
            }
        }
        private static void HandleMemberList(SyntaxNodeAnalysisContext context, SyntaxList <MemberDeclarationSyntax> members, ImmutableArray <SyntaxKind> order)
        {
            for (int i = 0; i < members.Count - 1; i++)
            {
                if (members[i + 1].IsKind(SyntaxKind.IncompleteMember))
                {
                    i++;
                    continue;
                }

                if (members[i].IsKind(SyntaxKind.IncompleteMember))
                {
                    continue;
                }

                var elementSyntaxKind = members[i].Kind();
                elementSyntaxKind = elementSyntaxKind == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : elementSyntaxKind;
                int index = order.IndexOf(elementSyntaxKind);

                var nextElementSyntaxKind = members[i + 1].Kind();
                nextElementSyntaxKind = nextElementSyntaxKind == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : nextElementSyntaxKind;
                int nextIndex = order.IndexOf(nextElementSyntaxKind);

                if (index > nextIndex)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, NamedTypeHelpers.GetNameOrIdentifierLocation(members[i + 1]), MemberNames[nextElementSyntaxKind], MemberNames[elementSyntaxKind]));
                }
            }
        }
Example #6
0
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);

            // No need to check file-scoped namespaces because the compiler only allows one per file
            var descentNodes = syntaxRoot.DescendantNodes(descendIntoChildren: node => node.IsKind(SyntaxKind.CompilationUnit) || node.IsKind(SyntaxKind.NamespaceDeclaration));

            bool foundNode = false;

            foreach (var node in descentNodes)
            {
                if (node.IsKind(SyntaxKind.NamespaceDeclaration))
                {
                    if (foundNode)
                    {
                        var location = NamedTypeHelpers.GetNameOrIdentifierLocation(node);
                        if (location != null)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
                        }
                    }
                    else
                    {
                        foundNode = true;
                    }
                }
            }
        }
Example #7
0
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCopSettings settings)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);

            var typeNodes = GetTopLevelTypeDeclarations(syntaxRoot, settings);

            string suffix;
            var    fileName          = FileNameHelpers.GetFileNameAndSuffix(context.Tree.FilePath, out suffix);
            var    preferredTypeNode = typeNodes.FirstOrDefault(n => FileNameHelpers.GetConventionalFileName(n, settings.DocumentationRules.FileNamingConvention) == fileName) ?? typeNodes.FirstOrDefault();

            if (preferredTypeNode == null)
            {
                return;
            }

            var foundTypeName = NamedTypeHelpers.GetNameOrIdentifier(preferredTypeNode);
            var isPartialType = NamedTypeHelpers.IsPartialDeclaration(preferredTypeNode);

            foreach (var typeNode in typeNodes)
            {
                if (typeNode == preferredTypeNode || (isPartialType && foundTypeName == NamedTypeHelpers.GetNameOrIdentifier(typeNode)))
                {
                    continue;
                }

                var location = NamedTypeHelpers.GetNameOrIdentifierLocation(typeNode);
                if (location != null)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
                }
            }
        }
        private static void HandleMemberList(SyntaxNodeAnalysisContext context, SyntaxList <MemberDeclarationSyntax> members, AccessLevel defaultAccessLevel)
        {
            var previousSyntaxKind   = SyntaxKind.None;
            var previousAccessLevel  = AccessLevel.NotSpecified;
            var previousMemberStatic = true;

            foreach (var member in members)
            {
                var currentSyntaxKind = member.Kind();
                currentSyntaxKind = currentSyntaxKind == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : currentSyntaxKind;
                var         modifiers           = member.GetModifiers();
                var         currentMemberStatic = modifiers.Any(SyntaxKind.StaticKeyword);
                var         currentMemberConst  = modifiers.Any(SyntaxKind.ConstKeyword);
                AccessLevel currentAccessLevel;
                if ((currentSyntaxKind == SyntaxKind.ConstructorDeclaration && modifiers.Any(SyntaxKind.StaticKeyword)) ||
                    (currentSyntaxKind == SyntaxKind.MethodDeclaration && (member as MethodDeclarationSyntax)?.ExplicitInterfaceSpecifier != null) ||
                    (currentSyntaxKind == SyntaxKind.PropertyDeclaration && (member as PropertyDeclarationSyntax)?.ExplicitInterfaceSpecifier != null) ||
                    (currentSyntaxKind == SyntaxKind.IndexerDeclaration && (member as IndexerDeclarationSyntax)?.ExplicitInterfaceSpecifier != null))
                {
                    currentAccessLevel = AccessLevel.Public;
                }
                else
                {
                    currentAccessLevel = AccessLevelHelper.GetAccessLevel(member.GetModifiers());
                    currentAccessLevel = currentAccessLevel == AccessLevel.NotSpecified ? defaultAccessLevel : currentAccessLevel;
                }

                if (currentSyntaxKind == previousSyntaxKind &&
                    currentAccessLevel == previousAccessLevel &&
                    !previousMemberStatic &&
                    currentMemberStatic &&
                    !currentMemberConst)
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            Descriptor,
                            NamedTypeHelpers.GetNameOrIdentifierLocation(member),
                            AccessLevelHelper.GetName(currentAccessLevel),
                            MemberNames[currentSyntaxKind]));
                }

                previousSyntaxKind   = currentSyntaxKind;
                previousAccessLevel  = currentAccessLevel;
                previousMemberStatic = currentMemberStatic || currentMemberConst;
            }
        }
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCopSettings settings)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);

            var descentNodes = syntaxRoot.DescendantNodes(descendIntoChildren: node => node != null && !node.IsKind(SyntaxKind.ClassDeclaration));
            var classNodes   = from descentNode in descentNodes
                               where descentNode.IsKind(SyntaxKind.ClassDeclaration)
                               select descentNode as ClassDeclarationSyntax;

            string suffix;
            var    fileName           = FileNameHelpers.GetFileNameAndSuffix(context.Tree.FilePath, out suffix);
            var    preferredClassNode = classNodes.FirstOrDefault(n => FileNameHelpers.GetConventionalFileName(n, settings.DocumentationRules.FileNamingConvention) == fileName) ?? classNodes.FirstOrDefault();

            if (preferredClassNode == null)
            {
                return;
            }

            string foundClassName = null;
            bool   isPartialClass = false;

            foundClassName = preferredClassNode.Identifier.Text;
            isPartialClass = preferredClassNode.Modifiers.Any(SyntaxKind.PartialKeyword);

            foreach (var classNode in classNodes)
            {
                if (classNode == preferredClassNode || (isPartialClass && foundClassName == classNode.Identifier.Text))
                {
                    continue;
                }

                var location = NamedTypeHelpers.GetNameOrIdentifierLocation(classNode);
                if (location != null)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
                }
            }
        }
Example #10
0
        private static void HandleMemberList(SyntaxNodeAnalysisContext context, ImmutableArray <OrderingTrait> elementOrder, int kindIndex, SyntaxList <MemberDeclarationSyntax> members, ImmutableArray <SyntaxKind> order)
        {
            for (int i = 0; i < members.Count - 1; i++)
            {
                if (members[i + 1].IsKind(SyntaxKind.IncompleteMember))
                {
                    i++;
                    continue;
                }

                if (members[i].IsKind(SyntaxKind.IncompleteMember))
                {
                    continue;
                }

                bool compareKind = true;
                for (int j = 0; compareKind && j < kindIndex; j++)
                {
                    switch (elementOrder[j])
                    {
                    case OrderingTrait.Accessibility:
                        if (MemberOrderHelper.GetAccessLevelForOrdering(members[i + 1], members[i + 1].GetModifiers())
                            != MemberOrderHelper.GetAccessLevelForOrdering(members[i], members[i].GetModifiers()))
                        {
                            compareKind = false;
                        }

                        continue;

                    case OrderingTrait.Constant:
                    case OrderingTrait.Readonly:
                        // Only fields may be marked const or readonly, and all fields have the same kind.
                        continue;

                    case OrderingTrait.Static:
                        bool currentIsStatic = members[i].GetModifiers().Any(SyntaxKind.StaticKeyword);
                        bool nextIsStatic    = members[i + 1].GetModifiers().Any(SyntaxKind.StaticKeyword);
                        if (currentIsStatic != nextIsStatic)
                        {
                            compareKind = false;
                        }

                        continue;

                    case OrderingTrait.Kind:
                    default:
                        continue;
                    }
                }

                if (!compareKind)
                {
                    continue;
                }

                var elementSyntaxKind = members[i].Kind();
                int index             = order.IndexOf(GetSyntaxKindForOrdering(elementSyntaxKind));

                var nextElementSyntaxKind = members[i + 1].Kind();
                int nextIndex             = order.IndexOf(GetSyntaxKindForOrdering(nextElementSyntaxKind));

                if (index > nextIndex)
                {
                    // [Issue #3160] Added hardening here to make sure that this won't crash when working with invalid code.
                    var nextElementMemberName = MemberNames.GetValueOrDefault(nextElementSyntaxKind, "<unknown>");
                    var elementMemberName     = MemberNames.GetValueOrDefault(elementSyntaxKind, "<unknown>");

                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, NamedTypeHelpers.GetNameOrIdentifierLocation(members[i + 1]), nextElementMemberName, elementMemberName));
                }
            }
        }
Example #11
0
        private static void HandleMemberList(SyntaxNodeAnalysisContext context, ImmutableArray <OrderingTrait> elementOrder, int kindIndex, SyntaxList <MemberDeclarationSyntax> members, ImmutableArray <SyntaxKind> order)
        {
            for (int i = 0; i < members.Count - 1; i++)
            {
                if (members[i + 1].IsKind(SyntaxKind.IncompleteMember))
                {
                    i++;
                    continue;
                }

                if (members[i].IsKind(SyntaxKind.IncompleteMember))
                {
                    continue;
                }

                bool compareKind = true;
                for (int j = 0; compareKind && j < kindIndex; j++)
                {
                    switch (elementOrder[j])
                    {
                    case OrderingTrait.Accessibility:
                        if (MemberOrderHelper.GetAccessLevelForOrdering(members[i + 1], members[i + 1].GetModifiers())
                            != MemberOrderHelper.GetAccessLevelForOrdering(members[i], members[i].GetModifiers()))
                        {
                            compareKind = false;
                        }

                        continue;

                    case OrderingTrait.Constant:
                    case OrderingTrait.Readonly:
                        // Only fields may be marked const or readonly, and all fields have the same kind.
                        continue;

                    case OrderingTrait.Static:
                        bool currentIsStatic = members[i].GetModifiers().Any(SyntaxKind.StaticKeyword);
                        bool nextIsStatic    = members[i + 1].GetModifiers().Any(SyntaxKind.StaticKeyword);
                        if (currentIsStatic != nextIsStatic)
                        {
                            compareKind = false;
                        }

                        continue;

                    case OrderingTrait.Kind:
                    default:
                        continue;
                    }
                }

                if (!compareKind)
                {
                    continue;
                }

                var elementSyntaxKind = members[i].Kind();
                elementSyntaxKind = elementSyntaxKind == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : elementSyntaxKind;
                int index = order.IndexOf(elementSyntaxKind);

                var nextElementSyntaxKind = members[i + 1].Kind();
                nextElementSyntaxKind = nextElementSyntaxKind == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : nextElementSyntaxKind;
                int nextIndex = order.IndexOf(nextElementSyntaxKind);

                if (index > nextIndex)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, NamedTypeHelpers.GetNameOrIdentifierLocation(members[i + 1]), MemberNames[nextElementSyntaxKind], MemberNames[elementSyntaxKind]));
                }
            }
        }
Example #12
0
        private static void HandleMemberList(SyntaxNodeAnalysisContext context, ImmutableArray <OrderingTrait> elementOrder, int accessibilityIndex, SyntaxList <MemberDeclarationSyntax> members)
        {
            var  previousSyntaxKind  = SyntaxKind.None;
            var  previousAccessLevel = AccessLevel.NotSpecified;
            bool previousIsConst     = false;
            bool previousIsReadonly  = false;
            bool previousIsStatic    = false;

            foreach (var member in members)
            {
                var currentSyntaxKind = member.Kind();
                currentSyntaxKind = currentSyntaxKind == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : currentSyntaxKind;

                // if the SyntaxKind of this member (e.g. SyntaxKind.IncompleteMember) will not
                // be handled, skip early.
                if (!MemberKinds.Contains(currentSyntaxKind))
                {
                    continue;
                }

                var         modifiers          = member.GetModifiers();
                AccessLevel currentAccessLevel = MemberOrderHelper.GetAccessLevelForOrdering(member, modifiers);
                bool        currentIsConst     = modifiers.Any(SyntaxKind.ConstKeyword);
                bool        currentIsReadonly  = modifiers.Any(SyntaxKind.ReadOnlyKeyword);
                bool        currentIsStatic    = modifiers.Any(SyntaxKind.StaticKeyword);

                if (previousAccessLevel != AccessLevel.NotSpecified)
                {
                    bool compareAccessLevel = true;
                    for (int j = 0; compareAccessLevel && j < accessibilityIndex; j++)
                    {
                        switch (elementOrder[j])
                        {
                        case OrderingTrait.Kind:
                            if (previousSyntaxKind != currentSyntaxKind)
                            {
                                compareAccessLevel = false;
                            }

                            continue;

                        case OrderingTrait.Constant:
                            if (previousIsConst != currentIsConst)
                            {
                                compareAccessLevel = false;
                            }

                            continue;

                        case OrderingTrait.Readonly:
                            if (previousIsReadonly != currentIsReadonly)
                            {
                                compareAccessLevel = false;
                            }

                            continue;

                        case OrderingTrait.Static:
                            if (previousIsStatic != currentIsStatic)
                            {
                                compareAccessLevel = false;
                            }

                            continue;

                        case OrderingTrait.Accessibility:
                        default:
                            continue;
                        }
                    }

                    if (compareAccessLevel && currentAccessLevel > previousAccessLevel)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptor,
                                NamedTypeHelpers.GetNameOrIdentifierLocation(member),
                                AccessLevelHelper.GetName(currentAccessLevel),
                                AccessLevelHelper.GetName(previousAccessLevel)));
                    }
                }

                previousSyntaxKind  = currentSyntaxKind;
                previousAccessLevel = currentAccessLevel;
                previousIsConst     = currentIsConst;
                previousIsReadonly  = currentIsReadonly;
                previousIsStatic    = currentIsStatic;
            }
        }
Example #13
0
        private static void HandleTypeDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
        {
            var elementOrder  = settings.OrderingRules.ElementOrder;
            int constantIndex = elementOrder.IndexOf(OrderingTrait.Constant);

            if (constantIndex < 0)
            {
                return;
            }

            var typeDeclaration = (TypeDeclarationSyntax)context.Node;

            var members = typeDeclaration.Members;
            var previousFieldConstant = true;
            var previousFieldStatic   = false;
            var previousFieldReadonly = false;
            var previousAccessLevel   = AccessLevel.NotSpecified;

            foreach (var member in members)
            {
                var field = member as FieldDeclarationSyntax;
                if (field == null)
                {
                    continue;
                }

                AccessLevel currentAccessLevel   = MemberOrderHelper.GetAccessLevelForOrdering(field, field.Modifiers);
                bool        currentFieldConstant = field.Modifiers.Any(SyntaxKind.ConstKeyword);
                bool        currentFieldReadonly = currentFieldConstant || field.Modifiers.Any(SyntaxKind.ReadOnlyKeyword);
                bool        currentFieldStatic   = currentFieldConstant || field.Modifiers.Any(SyntaxKind.StaticKeyword);
                bool        compareConst         = true;
                for (int j = 0; compareConst && j < constantIndex; j++)
                {
                    switch (elementOrder[j])
                    {
                    case OrderingTrait.Accessibility:
                        if (currentAccessLevel != previousAccessLevel)
                        {
                            compareConst = false;
                        }

                        continue;

                    case OrderingTrait.Readonly:
                        if (currentFieldReadonly != previousFieldReadonly)
                        {
                            compareConst = false;
                        }

                        continue;

                    case OrderingTrait.Static:
                        if (currentFieldStatic != previousFieldStatic)
                        {
                            compareConst = false;
                        }

                        continue;

                    case OrderingTrait.Kind:
                        // Only fields may be marked const, and all fields have the same kind.
                        continue;

                    case OrderingTrait.Constant:
                    default:
                        continue;
                    }
                }

                if (compareConst)
                {
                    if (!previousFieldConstant && currentFieldConstant)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, NamedTypeHelpers.GetNameOrIdentifierLocation(member)));
                    }
                }

                previousFieldConstant = currentFieldConstant;
                previousFieldReadonly = currentFieldReadonly;
                previousFieldStatic   = currentFieldStatic;
                previousAccessLevel   = currentAccessLevel;
            }
        }
Example #14
0
        private static void HandleMemberList(SyntaxNodeAnalysisContext context, ImmutableArray <OrderingTrait> elementOrder, int staticIndex, SyntaxList <MemberDeclarationSyntax> members)
        {
            var previousSyntaxKind     = SyntaxKind.None;
            var previousAccessLevel    = AccessLevel.NotSpecified;
            var previousMemberStatic   = true;
            var previousMemberConstant = false;
            var previousMemberReadonly = false;

            foreach (var member in members)
            {
                var modifiers = member.GetModifiers();

                var currentSyntaxKind = member.Kind();
                currentSyntaxKind = currentSyntaxKind == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : currentSyntaxKind;
                var  currentAccessLevel    = MemberOrderHelper.GetAccessLevelForOrdering(member, modifiers);
                bool currentMemberConstant = modifiers.Any(SyntaxKind.ConstKeyword);
                bool currentMemberReadonly = currentMemberConstant || modifiers.Any(SyntaxKind.ReadOnlyKeyword);
                bool currentMemberStatic   = currentMemberConstant || modifiers.Any(SyntaxKind.StaticKeyword);
                bool compareStatic         = true;
                for (int j = 0; compareStatic && j < staticIndex; j++)
                {
                    switch (elementOrder[j])
                    {
                    case OrderingTrait.Accessibility:
                        if (currentAccessLevel != previousAccessLevel)
                        {
                            compareStatic = false;
                        }

                        continue;

                    case OrderingTrait.Readonly:
                        if (currentMemberReadonly != previousMemberReadonly)
                        {
                            compareStatic = false;
                        }

                        continue;

                    case OrderingTrait.Constant:
                        if (currentMemberConstant != previousMemberConstant)
                        {
                            compareStatic = false;
                        }

                        continue;

                    case OrderingTrait.Kind:
                        if (previousSyntaxKind != currentSyntaxKind)
                        {
                            compareStatic = false;
                        }

                        continue;

                    case OrderingTrait.Static:
                    default:
                        continue;
                    }
                }

                if (compareStatic)
                {
                    if (currentMemberStatic && !previousMemberStatic)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptor,
                                NamedTypeHelpers.GetNameOrIdentifierLocation(member),
                                AccessLevelHelper.GetName(currentAccessLevel)));
                    }
                }

                previousSyntaxKind     = currentSyntaxKind;
                previousAccessLevel    = currentAccessLevel;
                previousMemberStatic   = currentMemberStatic;
                previousMemberConstant = currentMemberConstant;
                previousMemberReadonly = currentMemberReadonly;
            }
        }
        private static void HandleTypeDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
        {
            var elementOrder  = settings.OrderingRules.ElementOrder;
            int readonlyIndex = elementOrder.IndexOf(OrderingTrait.Readonly);

            if (readonlyIndex < 0)
            {
                return;
            }

            var typeDeclaration = (TypeDeclarationSyntax)context.Node;

            // This variable is null when the previous member is not a field.
            FieldDeclarationSyntax previousField = null;
            var previousFieldConst    = true;
            var previousFieldStatic   = false;
            var previousFieldReadonly = false;
            var previousAccessLevel   = AccessLevel.NotSpecified;

            foreach (var member in typeDeclaration.Members)
            {
                FieldDeclarationSyntax field = member as FieldDeclarationSyntax;
                if (field == null)
                {
                    previousField = null;
                    continue;
                }

                var  modifiers            = member.GetModifiers();
                var  currentAccessLevel   = MemberOrderHelper.GetAccessLevelForOrdering(member, modifiers);
                bool currentFieldConst    = modifiers.Any(SyntaxKind.ConstKeyword);
                bool currentFieldStatic   = currentFieldConst || modifiers.Any(SyntaxKind.StaticKeyword);
                bool currentFieldReadonly = currentFieldConst || modifiers.Any(SyntaxKind.ReadOnlyKeyword);
                if (previousField == null)
                {
                    previousField         = field;
                    previousFieldConst    = currentFieldConst;
                    previousFieldStatic   = currentFieldStatic;
                    previousFieldReadonly = currentFieldReadonly;
                    previousAccessLevel   = currentAccessLevel;
                    continue;
                }

                bool compareReadonly = true;
                for (int j = 0; compareReadonly && j < readonlyIndex; j++)
                {
                    switch (elementOrder[j])
                    {
                    case OrderingTrait.Kind:
                        // This analyzer only ever looks at sequences of fields.
                        continue;

                    case OrderingTrait.Accessibility:
                        if (previousAccessLevel != currentAccessLevel)
                        {
                            compareReadonly = false;
                        }

                        continue;

                    case OrderingTrait.Constant:
                        if (previousFieldConst != currentFieldConst)
                        {
                            compareReadonly = false;
                        }

                        continue;

                    case OrderingTrait.Static:
                        if (previousFieldStatic != currentFieldStatic)
                        {
                            compareReadonly = false;
                        }

                        continue;

                    case OrderingTrait.Readonly:
                    default:
                        continue;
                    }
                }

                if (compareReadonly)
                {
                    if (currentFieldReadonly && !previousFieldReadonly)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, NamedTypeHelpers.GetNameOrIdentifierLocation(member)));
                    }
                }

                previousField         = field;
                previousFieldConst    = currentFieldConst;
                previousFieldStatic   = currentFieldStatic;
                previousFieldReadonly = currentFieldReadonly;
                previousAccessLevel   = currentAccessLevel;
            }
        }