private static void HandleMemberDeclaration(SyntaxNodeAnalysisContext context) { MemberDeclarationSyntax memberSyntax = (MemberDeclarationSyntax)context.Node; var modifiers = memberSyntax.GetModifiers(); if (modifiers.Any(SyntaxKind.OverrideKeyword)) { return; } DocumentationCommentTriviaSyntax documentation = memberSyntax.GetDocumentationCommentTriviaSyntax(); if (documentation == null) { return; } Location location; ISymbol declaredSymbol = context.SemanticModel.GetDeclaredSymbol(memberSyntax, context.CancellationToken); if (declaredSymbol == null && memberSyntax.IsKind(SyntaxKind.EventFieldDeclaration)) { var eventFieldDeclarationSyntax = (EventFieldDeclarationSyntax)memberSyntax; VariableDeclaratorSyntax firstVariable = eventFieldDeclarationSyntax.Declaration?.Variables.FirstOrDefault(); if (firstVariable != null) { declaredSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable, context.CancellationToken); } } var includeElement = documentation.Content.GetFirstXmlElement(XmlCommentHelper.IncludeXmlTag) as XmlEmptyElementSyntax; if (includeElement != null) { if (declaredSymbol == null) { return; } var rawDocumentation = declaredSymbol.GetDocumentationCommentXml(expandIncludes: true, cancellationToken: context.CancellationToken); var completeDocumentation = XElement.Parse(rawDocumentation, LoadOptions.None); var inheritDocElement = completeDocumentation.Nodes().OfType <XElement>().FirstOrDefault(element => element.Name == XmlCommentHelper.InheritdocXmlTag); if (inheritDocElement == null) { return; } if (HasXmlCrefAttribute(inheritDocElement)) { return; } location = includeElement.GetLocation(); } else { XmlNodeSyntax inheritDocElement = documentation.Content.GetFirstXmlElement(XmlCommentHelper.InheritdocXmlTag); if (inheritDocElement == null) { return; } if (HasXmlCrefAttribute(inheritDocElement)) { return; } location = inheritDocElement.GetLocation(); } // If we don't have a declared symbol we have some kind of field declaration. A field can not override or // implement anything so we want to report a diagnostic. if (declaredSymbol == null || !NamedTypeHelpers.IsImplementingAnInterfaceMember(declaredSymbol)) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, location)); } }
private static void HandleFieldDeclarationSyntax(SyntaxNodeAnalysisContext context) { FieldDeclarationSyntax syntax = (FieldDeclarationSyntax)context.Node; if (NamedTypeHelpers.IsContainedInNativeMethodsClass(syntax)) { return; } var variables = syntax.Declaration?.Variables; if (variables == null) { return; } foreach (VariableDeclaratorSyntax variableDeclarator in variables.Value) { if (variableDeclarator == null) { continue; } var identifier = variableDeclarator.Identifier; if (identifier.IsMissing) { continue; } switch (identifier.ValueText.IndexOf('_')) { case -1: // no _ character continue; case 0: // leading underscore -> report as SA1309 continue; case 1: switch (identifier.ValueText[0]) { case 'm': case 's': case 't': // m_, s_, and t_ prefixes are reported as SA1308 continue; default: break; } break; default: break; } // Field '{name}' must not contain an underscore string name = identifier.ValueText; context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation(), name)); } }
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) { // [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)); } } }
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; } }
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 void HandleFieldDeclarationSyntax(SyntaxNodeAnalysisContext context) { FieldDeclarationSyntax syntax = (FieldDeclarationSyntax)context.Node; bool isStatic = false; foreach (SyntaxToken token in syntax.Modifiers) { switch (token.Kind()) { case SyntaxKind.StaticKeyword: isStatic = true; break; case SyntaxKind.ReadOnlyKeyword: case SyntaxKind.ConstKeyword: // This analyzer only looks at static, non-const, non-readonly fields. return; case SyntaxKind.InternalKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.PublicKeyword: // This analyzer only looks at private fields. return; default: break; } } if (!isStatic) { return; } if (NamedTypeHelpers.IsContainedInNativeMethodsClass(syntax)) { return; } var variables = syntax.Declaration?.Variables; if (variables == null) { return; } foreach (VariableDeclaratorSyntax variableDeclarator in variables.Value) { if (variableDeclarator == null) { continue; } var identifier = variableDeclarator.Identifier; if (identifier.IsMissing) { continue; } if (identifier.ValueText.StartsWith("_")) { continue; } // Static field '{name}' must begin with an underscore string name = identifier.ValueText; context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation(), name)); } }
private static void HandleMemberList(SyntaxNodeAnalysisContext context, ImmutableArray <OrderingTrait> elementOrder, int accessibilityIndex, SyntaxList <MemberDeclarationSyntax> members, AccessLevel defaultAccessLevel) { MemberDeclarationSyntax previousMember = null; 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))); } } previousMember = member; previousSyntaxKind = currentSyntaxKind; previousAccessLevel = currentAccessLevel; previousIsConst = currentIsConst; previousIsReadonly = currentIsReadonly; previousIsStatic = currentIsStatic; } }
private static void HandleFieldDeclaration(SyntaxNodeAnalysisContext context) { FieldDeclarationSyntax syntax = (FieldDeclarationSyntax)context.Node; if (NamedTypeHelpers.IsContainedInNativeMethodsClass(syntax)) { return; } if (syntax.Modifiers.Any(SyntaxKind.ConstKeyword)) { // this diagnostic does not apply to constant fields return; } if (syntax.Modifiers.Any(SyntaxKind.PublicKeyword) || syntax.Modifiers.Any(SyntaxKind.InternalKeyword)) { // this diagnostic does not apply to public or internal read only fields return; } if (syntax.Modifiers.Any(SyntaxKind.ReadOnlyKeyword) && syntax.Modifiers.Any(SyntaxKind.ProtectedKeyword)) { // this diagnostic does not apply to non-private read only fields return; } if (syntax.Modifiers.Any(SyntaxKind.ReadOnlyKeyword) && syntax.Modifiers.Any(SyntaxKind.StaticKeyword)) { // this diagnostic does not apply to static read only fields return; } var variables = syntax.Declaration?.Variables; if (variables == null) { return; } foreach (VariableDeclaratorSyntax variableDeclarator in variables.Value) { if (variableDeclarator == null) { continue; } var identifier = variableDeclarator.Identifier; if (identifier.IsMissing) { continue; } string name = identifier.ValueText; if (string.IsNullOrEmpty(name)) { continue; } var index = 0; while ((index < name.Length) && name[index] == '_') { index++; } if (index == name.Length) { // ignore fields with all underscores continue; } if (char.IsLower(name, index)) { continue; } // Field names must begin with lower-case letter context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation(), name)); } }
private void HandleFieldDeclarationSyntax(SyntaxNodeAnalysisContext context) { FieldDeclarationSyntax syntax = (FieldDeclarationSyntax)context.Node; if (NamedTypeHelpers.IsContainedInNativeMethodsClass(syntax)) { return; } if (!syntax.Modifiers.Any(SyntaxKind.ReadOnlyKeyword)) { // this analyzer only applies to readonly fields return; } if (!syntax.Modifiers.Any(SyntaxKind.PublicKeyword) && !syntax.Modifiers.Any(SyntaxKind.ProtectedKeyword) && !syntax.Modifiers.Any(SyntaxKind.InternalKeyword)) { // this analyzer only applies to non-private fields return; } if (!syntax.Modifiers.Any(SyntaxKind.InternalKeyword)) { // SA1307 is taken precedence here. SA1307 should be reported if the field is accessible. // So if SA1307 is enabled this diagnostic will only be reported for internal fields. if (context.SemanticModel.Compilation.Options.SpecificDiagnosticOptions .GetValueOrDefault(SA1307AccessibleFieldsMustBeginWithUpperCaseLetter.DiagnosticId, ReportDiagnostic.Default) != ReportDiagnostic.Suppress) { return; } } var variables = syntax.Declaration?.Variables; if (variables == null) { return; } foreach (VariableDeclaratorSyntax variableDeclarator in variables.Value) { if (variableDeclarator == null) { continue; } var identifier = variableDeclarator.Identifier; if (identifier.IsMissing) { continue; } string name = identifier.ValueText; if (string.IsNullOrEmpty(name) || !char.IsLower(name[0])) { continue; } // Non-private readonly fields must begin with upper-case letter. context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation())); } }
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; } }
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)); } } }