diff options
author | Sebastien Pouliot <sebastien@ximian.com> | 2008-02-15 22:40:31 +0300 |
---|---|---|
committer | Sebastien Pouliot <sebastien@ximian.com> | 2008-02-15 22:40:31 +0300 |
commit | d7c847d59a56d480af3ba51445771fe6482a405b (patch) | |
tree | e159fc8e21b8ea64292922a980283a5df1408233 /gendarme/rules | |
parent | 1ad631f9e5e5836e94aa7003b2064b59144e757d (diff) |
2008-02-15 Sebastien Pouliot <sebastien@ximian.com>
* DetectNonAlphaNumericsInTypeNamesRule.cs
* DoNotPrefixValuesWithEnumNameRule.cs
* DoNotUseReservedInEnumValueNamesRule.cs
* EnumNotEndsWithEnumOrFlagsSuffixRule.cs
* ParameterNamesShouldMatchOverridenMethodRule.cs
* UseCorrectCasingRule.cs
* UseCorrectPrefixRule.cs
* UseCorrectSuffixRule.cs
* UsePluralNameInEnumFlagsRule.cs
* UsePreferredTermsRule.cs
* UseSingularNameInEnumsUnlessAreFlagsRule.cs:
Update rules wrt framework changes.
svn path=/trunk/mono-tools/; revision=95803
Diffstat (limited to 'gendarme/rules')
12 files changed, 217 insertions, 225 deletions
diff --git a/gendarme/rules/Gendarme.Rules.Naming/ChangeLog b/gendarme/rules/Gendarme.Rules.Naming/ChangeLog index b5fc554c..b9c29798 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/ChangeLog +++ b/gendarme/rules/Gendarme.Rules.Naming/ChangeLog @@ -1,3 +1,18 @@ +2008-02-15 Sebastien Pouliot <sebastien@ximian.com> + + * DetectNonAlphaNumericsInTypeNamesRule.cs + * DoNotPrefixValuesWithEnumNameRule.cs + * DoNotUseReservedInEnumValueNamesRule.cs + * EnumNotEndsWithEnumOrFlagsSuffixRule.cs + * ParameterNamesShouldMatchOverridenMethodRule.cs + * UseCorrectCasingRule.cs + * UseCorrectPrefixRule.cs + * UseCorrectSuffixRule.cs + * UsePluralNameInEnumFlagsRule.cs + * UsePreferredTermsRule.cs + * UseSingularNameInEnumsUnlessAreFlagsRule.cs: + Update rules wrt framework changes. + 2008-01-18 Sebastien Pouliot <sebastien@ximian.com> * DetectNonAlphaNumericsInTypeNamesRule.cs: Add checks for generated diff --git a/gendarme/rules/Gendarme.Rules.Naming/DetectNonAlphaNumericsInTypeNamesRule.cs b/gendarme/rules/Gendarme.Rules.Naming/DetectNonAlphaNumericsInTypeNamesRule.cs index fd56405b..246b2f28 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/DetectNonAlphaNumericsInTypeNamesRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/DetectNonAlphaNumericsInTypeNamesRule.cs @@ -1,5 +1,5 @@ // -// Gendarme.Rules.Naming.DetectNonAlphaNumericsInTypeNamesRule +// Gendarme.Rules.Naming.DetectNonAlphaNumericInTypeNamesRule // // Authors: // Nidhi Rawal <sonu2404@gmail.com> @@ -36,43 +36,45 @@ using Gendarme.Framework.Rocks; namespace Gendarme.Rules.Naming { - public class DetectNonAlphaNumericsInTypeNamesRule: IMethodRule, ITypeRule { + [Problem ("This type, or method, name contains underscore(s) in its name.")] + [Solution ("Remove the underscore from the name.")] + public class DetectNonAlphanumericInTypeNamesRule: Rule, IMethodRule, ITypeRule { + + private const string Underscore = "Name should not contain underscore."; // Compiler generates an error for any other non alpha-numerics than underscore ('_'), // so we just need to check the presence of underscore in method names private static bool CheckName (string name) { - return (name.IndexOf ("_") == -1); + return (name.IndexOf ("_", StringComparison.Ordinal) == -1); } - public MessageCollection CheckType (TypeDefinition type, Runner runner) + public RuleResult CheckType (TypeDefinition type) { - // type must be public and, if nested, public too - if (type.IsNotPublic || type.IsNestedPrivate || type.IsGeneratedCode ()) - return runner.RuleSuccess; + // type must be visible and not generated by the compiler (or a tool) + if (!type.IsVisible () || type.IsGeneratedCode ()) + return RuleResult.DoesNotApply; // check the type name if (CheckName (type.Name)) - return runner.RuleSuccess; + return RuleResult.Success; - Location location = new Location (type); - Message message = new Message ("Type name should not contain underscore.", location, MessageType.Error); - return new MessageCollection (message); + Runner.Report (type, Severity.Medium, Confidence.High, Underscore); + return RuleResult.Failure; } - public MessageCollection CheckMethod (MethodDefinition method, Runner runner) + public RuleResult CheckMethod (MethodDefinition method) { // exclude non-public methods and special names (like Getter and Setter) if (!method.IsPublic || method.IsSpecialName || method.IsGeneratedCode ()) - return runner.RuleSuccess; + return RuleResult.DoesNotApply; // check the method name if (CheckName (method.Name)) - return runner.RuleSuccess; + return RuleResult.Success; - Location location = new Location (method); - Message message = new Message ("Method name should not contain an underscore.", location, MessageType.Error); - return new MessageCollection (message); + Runner.Report (method, Severity.Medium, Confidence.High, Underscore); + return RuleResult.Failure; } } } diff --git a/gendarme/rules/Gendarme.Rules.Naming/DoNotPrefixValuesWithEnumNameRule.cs b/gendarme/rules/Gendarme.Rules.Naming/DoNotPrefixValuesWithEnumNameRule.cs index 41096630..c80dc33c 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/DoNotPrefixValuesWithEnumNameRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/DoNotPrefixValuesWithEnumNameRule.cs @@ -33,14 +33,14 @@ using Gendarme.Framework.Rocks; namespace Gendarme.Rules.Naming { - public class DoNotPrefixValuesWithEnumNameRule : ITypeRule { + [Problem ("This enumeration contains value names that starts with the enum's name.")] + [Solution ("hange the value name(s) not to include the enum's type name.")] + public class DoNotPrefixValuesWithEnumNameRule : Rule, ITypeRule { - public MessageCollection CheckType (TypeDefinition type, Runner runner) + public RuleResult CheckType (TypeDefinition type) { if (!type.IsEnum) - return runner.RuleSuccess; - - MessageCollection results = null; + return RuleResult.DoesNotApply; foreach (FieldDefinition field in type.Fields) { // this excludes special "value__" @@ -48,15 +48,11 @@ namespace Gendarme.Rules.Naming { continue; if (field.Name.StartsWith (type.Name, StringComparison.OrdinalIgnoreCase)) { - if (results == null) - results = new MessageCollection (); - Location loc = new Location (field); - Message msg = new Message (string.Format ("Enum values should not be prefixed with the enum's name.", type.FullName), loc, MessageType.Warning); - results.Add (msg); + Runner.Report (field, Severity.Medium, Confidence.High, String.Empty); } } - return results; + return Runner.CurrentRuleResult; } } } diff --git a/gendarme/rules/Gendarme.Rules.Naming/DoNotUseReservedInEnumValueNamesRule.cs b/gendarme/rules/Gendarme.Rules.Naming/DoNotUseReservedInEnumValueNamesRule.cs index ab582005..7e70a8f8 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/DoNotUseReservedInEnumValueNamesRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/DoNotUseReservedInEnumValueNamesRule.cs @@ -33,30 +33,27 @@ using Gendarme.Framework.Rocks; namespace Gendarme.Rules.Naming { - public class DoNotUseReservedInEnumValueNamesRule : ITypeRule { + [Problem ("This type is an enumeration that contains value(s) named 'reserved'.")] + [Solution ("The 'reserved' value should be removed since there is no need to reserve enums values.")] + public class DoNotUseReservedInEnumValueNamesRule : Rule, ITypeRule { - public MessageCollection CheckType (TypeDefinition type, Runner runner) + public RuleResult CheckType (TypeDefinition type) { if (!type.IsEnum) - return runner.RuleSuccess; - - MessageCollection results = null; + return RuleResult.DoesNotApply; foreach (FieldDefinition field in type.Fields) { // this excludes special "value__" if (!field.IsStatic) continue; - if (field.Name.ToLowerInvariant ().Contains ("reserved")) { - if (results == null) - results = new MessageCollection (); - Location loc = new Location (field); - Message msg = new Message (string.Format ("Enum should not contain fields for reserved values.", type.FullName), loc, MessageType.Warning); - results.Add (msg); + if (field.Name.ToUpperInvariant ().Contains ("RESERVED")) { + // High since removing/renaming the field can be a breaking change + Runner.Report (field, Severity.High, Confidence.High, String.Empty); } } - return results; + return Runner.CurrentRuleResult; } } } diff --git a/gendarme/rules/Gendarme.Rules.Naming/EnumNotEndsWithEnumOrFlagsSuffixRule.cs b/gendarme/rules/Gendarme.Rules.Naming/EnumNotEndsWithEnumOrFlagsSuffixRule.cs index 52f3040e..71f78f5e 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/EnumNotEndsWithEnumOrFlagsSuffixRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/EnumNotEndsWithEnumOrFlagsSuffixRule.cs @@ -27,6 +27,7 @@ // using System; +using System.Globalization; using Mono.Cecil; @@ -35,33 +36,35 @@ using Gendarme.Framework.Rocks; namespace Gendarme.Rules.Naming { - public class EnumNotEndsWithEnumOrFlagsSuffixRule : ITypeRule { + [Problem ("This type is an enumeration and, by convention, its name should not end with either Enum or Flags.")] + [Solution ("Remove the Enum or Flags suffix in enumeration name.")] + public class EnumNotEndsWithEnumOrFlagsSuffixRule : Rule, ITypeRule { private static bool EndsWithSuffix (string suffix, string typeName) { - return typeName.EndsWith (suffix) || typeName.ToLower ().EndsWith (suffix.ToLower ()); + int pos = typeName.Length - suffix.Length; + if (pos < 0) + return false; + + return (String.Compare (typeName, pos, suffix, 0, suffix.Length, true, CultureInfo.InvariantCulture) == 0); } - public MessageCollection CheckType (TypeDefinition typeDefinition, Runner runner) + public RuleResult CheckType (TypeDefinition type) { // rule applies only to enums - if (!typeDefinition.IsEnum) - return runner.RuleSuccess; + if (!type.IsEnum) + return RuleResult.DoesNotApply; - if (!typeDefinition.IsFlags ()) { - if (EndsWithSuffix ("Enum", typeDefinition.Name)) { - Location location = new Location (typeDefinition); - Message message = new Message ("Enum name should not end with the Enum suffix.", location, MessageType.Error); - return new MessageCollection (message); + if (!type.IsFlags ()) { + if (EndsWithSuffix ("Enum", type.Name)) { + Runner.Report (type, Severity.Medium, Confidence.High, "Enum name should not end with the 'Enum'."); } } else { - if (EndsWithSuffix ("Flags", typeDefinition.Name)) { - Location location = new Location (typeDefinition); - Message message = new Message ("Enum name should not end with the Flags suffix.", location, MessageType.Error); - return new MessageCollection (message); + if (EndsWithSuffix ("Flags", type.Name)) { + Runner.Report (type, Severity.Medium, Confidence.High, "Enum name should not end with the 'Flags'."); } } - return runner.RuleSuccess; + return Runner.CurrentRuleResult; } } } diff --git a/gendarme/rules/Gendarme.Rules.Naming/ParameterNamesShouldMatchOverridenMethodRule.cs b/gendarme/rules/Gendarme.Rules.Naming/ParameterNamesShouldMatchOverridenMethodRule.cs index a0e08563..b807edd7 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/ParameterNamesShouldMatchOverridenMethodRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/ParameterNamesShouldMatchOverridenMethodRule.cs @@ -1,5 +1,5 @@ // -// Gendarme.Rules.Naming.ParameterNamesShouldMatchOverridenMethodRule +// Gendarme.Rules.Naming.ParameterNamesShouldMatchOverriddenMethodRule // // Authors: // Andreas Noever <andreas.noever@gmail.com> @@ -27,13 +27,17 @@ // using System; +using System.Globalization; + using Mono.Cecil; using Gendarme.Framework; using Gendarme.Framework.Rocks; namespace Gendarme.Rules.Naming { - public class ParameterNamesShouldMatchOverridenMethodRule : IMethodRule { + [Problem ("This method overrides (or implement) an existing method but does not use the same parameter names as the original.")] + [Solution ("Keep parameter names consistent when overriding a class or implementing an interface.")] + public class ParameterNamesShouldMatchOverriddenMethodRule : Rule, IMethodRule { private static bool SignatureMatches (MethodDefinition method, MethodDefinition baseMethod, bool explicitInterfaceCheck) { @@ -54,18 +58,17 @@ namespace Gendarme.Rules.Naming { break; } } - if (!paramtersMatch) - return false; - return true; + return paramtersMatch; } private static MethodDefinition GetBaseMethod (MethodDefinition method) { - TypeDefinition baseType = (TypeDefinition) method.DeclaringType; - while (baseType != baseType.BaseType) { //System.Object extends System.Object in cecil - baseType = baseType.BaseType as TypeDefinition; - if (baseType == null) //TODO: ToTypeDefinition () - break; + TypeDefinition baseType = method.DeclaringType.Resolve (); + if (baseType == null) + return null; + + while ((baseType.BaseType != null) && (baseType != baseType.BaseType)) { + baseType = baseType.BaseType.Resolve (); foreach (MethodDefinition baseMethodCandidate in baseType.Methods) { if (SignatureMatches (method, baseMethodCandidate, false)) return baseMethodCandidate; @@ -78,9 +81,9 @@ namespace Gendarme.Rules.Naming { { TypeDefinition type = (TypeDefinition) method.DeclaringType; foreach (TypeReference interfaceReference in type.Interfaces) { - TypeDefinition interfaceCandidate = interfaceReference as TypeDefinition; + TypeDefinition interfaceCandidate = interfaceReference.Resolve (); if (interfaceCandidate == null) - continue; //TODO: ToTypeDefinition (); + continue; foreach (MethodDefinition interfaceMethodCandidate in interfaceCandidate.Methods) { if (SignatureMatches (method, interfaceMethodCandidate, true)) return interfaceMethodCandidate; @@ -89,10 +92,10 @@ namespace Gendarme.Rules.Naming { return null; } - public MessageCollection CheckMethod (MethodDefinition method, Runner runner) + public RuleResult CheckMethod (MethodDefinition method) { if (!method.IsVirtual) - return runner.RuleSuccess; + return RuleResult.DoesNotApply; MethodDefinition baseMethod = null; if (!method.IsNewSlot) @@ -100,20 +103,17 @@ namespace Gendarme.Rules.Naming { if (baseMethod == null) baseMethod = GetInterfaceMethod (method); if (baseMethod == null) - return runner.RuleSuccess; - - MessageCollection results = null; + return RuleResult.Success; for (int i = 0; i < method.Parameters.Count; i++) { if (method.Parameters [i].Name != baseMethod.Parameters [i].Name) { - if (results == null) - results = new MessageCollection (); - Location loc = new Location (method); - Message msg = new Message (string.Format ("The name of parameter {0} ({1}) does not match the name of the parameter in the overriden method ({2}).", i + 1, method.Parameters [i].Name, baseMethod.Parameters [i].Name), loc, MessageType.Warning); - results.Add (msg); + string s = string.Format (CultureInfo.InstalledUICulture, + "The name of parameter #{0} ({1}) does not match the name of the parameter in the overriden method ({2}).", + i + 1, method.Parameters [i].Name, baseMethod.Parameters [i].Name); + Runner.Report (method, Severity.Medium, Confidence.High, s); } } - return results; + return Runner.CurrentRuleResult; } } } diff --git a/gendarme/rules/Gendarme.Rules.Naming/UseCorrectCasingRule.cs b/gendarme/rules/Gendarme.Rules.Naming/UseCorrectCasingRule.cs index e26738bc..b14a76b5 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/UseCorrectCasingRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/UseCorrectCasingRule.cs @@ -38,7 +38,9 @@ using Gendarme.Framework.Rocks; namespace Gendarme.Rules.Naming { - public class UseCorrectCasingRule : ITypeRule, IMethodRule { + [Problem ("This identifier violates .NET naming conventions.")] + [Solution ("Make all type and method names pascal-cased (like MyClass), and all parameter names must be camel-cased (like myParameter).")] + public class UseCorrectCasingRule : Rule, ITypeRule, IMethodRule { // check if name is PascalCased private static bool IsPascalCase (string name) @@ -93,74 +95,67 @@ namespace Gendarme.Rules.Naming { return (index == s.Length) ? 0 : index; } - public MessageCollection CheckType (TypeDefinition typeDefinition, Runner runner) + public RuleResult CheckType (TypeDefinition type) { // rule does not apply to generated code (outside developer's control) - if (typeDefinition.IsGeneratedCode ()) - return runner.RuleSuccess; + if (type.IsGeneratedCode ()) + return RuleResult.DoesNotApply; // <Module> isn't tagged as generated by the compiler but still must be ignored - if (typeDefinition.Name == Constants.ModuleType) - return runner.RuleSuccess; + if (type.Name == Constants.ModuleType) + return RuleResult.DoesNotApply; // ok, rule applies // types should all be PascalCased - if (IsPascalCase (typeDefinition.Name)) - return runner.RuleSuccess; + if (IsPascalCase (type.Name)) + return RuleResult.Success; - Location location = new Location (typeDefinition); - string errorMessage = string.Format ("By existing naming conventions, the type names should all be pascal-cased (e.g. MyClass). Rename '{0}' type to '{1}'.", - typeDefinition.Name, PascalCase (typeDefinition.Name)); - return new MessageCollection (new Message (errorMessage, location, MessageType.Error)); + string s = String.Format ("Type names should all be pascal-cased. Rename '{0}' type to '{1}'.", type.Name, PascalCase (type.Name)); + Runner.Report (type, Severity.Medium, Confidence.High, s); + return RuleResult.Failure; } - public MessageCollection CheckMethod (MethodDefinition methodDefinition, Runner runner) + public RuleResult CheckMethod (MethodDefinition method) { - if (methodDefinition.IsConstructor) - return runner.RuleSuccess; + if (method.IsConstructor) + return RuleResult.DoesNotApply; - string name = methodDefinition.Name; - MethodSemanticsAttributes attrs = methodDefinition.SemanticsAttributes; + string name = method.Name; + MethodSemanticsAttributes attrs = method.SemanticsAttributes; MethodSemanticsAttributes mask = MethodSemanticsAttributes.Getter | MethodSemanticsAttributes.Setter | MethodSemanticsAttributes.AddOn | MethodSemanticsAttributes.RemoveOn; if ((attrs & mask) != 0) { // it's something special - int underscore = methodDefinition.Name.IndexOf ('_'); + int underscore = method.Name.IndexOf ('_'); if (underscore != -1) name = name.Substring (underscore + 1); - } else if (methodDefinition.IsSpecialName || methodDefinition.IsGeneratedCode ()) { - return runner.RuleSuccess; + } else if (method.IsSpecialName || method.IsGeneratedCode ()) { + return RuleResult.Success; } - MessageCollection messages = null; - Location location = new Location (methodDefinition); - // like types, methods/props should all be PascalCased, too if (!IsPascalCase (name)) { string errorMessage = string.Format ("By existing naming conventions, all the method and property names should all be pascal-cased (e.g. MyOperation). Rename '{0}' to '{1}'.", name, PascalCase (name)); - messages = new MessageCollection (new Message (errorMessage, location, MessageType.Error)); + Runner.Report (method, Severity.Medium, Confidence.High, errorMessage); } // check parameters List<string> parameterNames = new List<string> (); - foreach (ParameterDefinition paramDefinition in methodDefinition.Parameters) { + foreach (ParameterDefinition paramDefinition in method.Parameters) { if (!parameterNames.Contains (paramDefinition.Name)) // somewhy they duplicate sometimes parameterNames.Add (paramDefinition.Name); } foreach (string param in parameterNames) { // params should all be camelCased if (!IsCamelCase (param)) { - if (messages == null) - messages = new MessageCollection (); - string errorMessage = string.Format ("By existing naming conventions, the parameter names should all be camel-cased (e.g. myParameter). Rename '{0}' parameter to '{1}'.", param, CamelCase (param)); - messages.Add (new Message (errorMessage, location, MessageType.Error)); + Runner.Report (method, Severity.Medium, Confidence.High, errorMessage); } } - return messages; + return Runner.CurrentRuleResult; } } } diff --git a/gendarme/rules/Gendarme.Rules.Naming/UseCorrectPrefixRule.cs b/gendarme/rules/Gendarme.Rules.Naming/UseCorrectPrefixRule.cs index 049b0d3c..fc5f3ee6 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/UseCorrectPrefixRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/UseCorrectPrefixRule.cs @@ -33,7 +33,9 @@ using Gendarme.Framework; namespace Gendarme.Rules.Naming { - public class UseCorrectPrefixRule : ITypeRule { + [Problem ("This type starts with an incorrect prefix or does not start with the required one. All interface names should start with the 'I' letter, followed by another capital letter. All other type names should not have any specific prefix.")] + [Solution ("Rename the type to have the correct prefix.")] + public class UseCorrectPrefixRule : Rule, ITypeRule { private static bool IsCorrectTypeName (string name) { @@ -50,21 +52,22 @@ namespace Gendarme.Rules.Naming { return name [0] == 'I' && char.IsUpper (name [1]); } - public MessageCollection CheckType (TypeDefinition typeDefinition, Runner runner) + public RuleResult CheckType (TypeDefinition type) { - Location location = new Location (typeDefinition); - if (typeDefinition.IsInterface) { - if (!IsCorrectInterfaceName (typeDefinition.Name)) { // interfaces should look like 'ISomething' - Message message = new Message (string.Format ("The '{0}' interface name doesn't have the required 'I' prefix. Acoording to existing naming conventions, all interface names should begin with the 'I' letter followed by another capital letter.", typeDefinition.Name), location, MessageType.Error); - return new MessageCollection (message); + if (type.IsInterface) { + if (!IsCorrectInterfaceName (type.Name)) { // interfaces should look like 'ISomething' + string s = String.Format ("The '{0}' interface name doesn't have the required 'I' prefix. Acoording to existing naming conventions, all interface names should begin with the 'I' letter followed by another capital letter.", type.Name); + Runner.Report (type, Severity.Critical, Confidence.High, s); + return RuleResult.Failure; } } else { - if (!IsCorrectTypeName (typeDefinition.Name)) { // class should _not_ look like 'CSomething" - Message message = new Message (string.Format ("The '{0}' type name starts with 'C' prefix but, according to existing naming conventions, type names should not have any specific prefix.", typeDefinition.Name), location, MessageType.Error); - return new MessageCollection (message); + if (!IsCorrectTypeName (type.Name)) { // class should _not_ look like 'CSomething" + string s = String.Format ("The '{0}' type name starts with 'C' prefix but, according to existing naming conventions, type names should not have any specific prefix.", type.Name); + Runner.Report (type, Severity.Medium, Confidence.High, s); + return RuleResult.Failure; } } - return runner.RuleSuccess; + return RuleResult.Success; } } } diff --git a/gendarme/rules/Gendarme.Rules.Naming/UseCorrectSuffixRule.cs b/gendarme/rules/Gendarme.Rules.Naming/UseCorrectSuffixRule.cs index 59735f51..c3d08fff 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/UseCorrectSuffixRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/UseCorrectSuffixRule.cs @@ -37,32 +37,31 @@ using Gendarme.Framework.Rocks; namespace Gendarme.Rules.Naming { - public class UseCorrectSuffixRule : ITypeRule { + [Problem ("This type does not end with the correct suffix. That usually happens when you define a custom attribute or exception and forget appending suffixes like 'Attribute' or 'Exception' to the type name.")] + [Solution ("Rename the type and append the correct suffix.")] + public class UseCorrectSuffixRule : Rule, ITypeRule { // keys are base class names, values are arrays of possible suffixes - private Dictionary<string, string []> definedSuffixes = - new Dictionary<string, string []> (); + private static Dictionary<string, string []> definedSuffixes = + new Dictionary<string, string []> () { + { "System.Attribute", new string [] { "Attribute" } }, + { "System.EventArgs", new string [] { "EventArgs" } }, + { "System.Exception", new string [] { "Exception" } }, + { "System.Collections.Queue", new string [] { "Collection", "Queue" } }, + { "System.Collections.Stack", new string [] { "Collection", "Stack" } }, + { "System.Data.DataSet", new string [] { "DataSet" } }, + { "System.Data.DataTable", new string [] { "DataTable", "Collection" } }, + { "System.IO.Stream", new string [] { "Stream" } }, + { "System.Security.IPermission", new string [] { "Permission" } }, + { "System.Security.Policy.IMembershipCondition", new string [] { "Condition" } }, + { "System.Collections.IDictionary", new string [] { "Dictionary" } }, + { "System.Collections.Generic.IDictionary", new string [] { "Dictionary" } }, + { "System.Collections.ICollection", new string [] { "Collection" } }, + { "System.Collections.Generic.ICollection", new string [] { "Collection" } }, + { "System.Collections.IEnumerable", new string [] { "Collection" } } + }; - public UseCorrectSuffixRule () - { - definedSuffixes.Add ("System.Attribute", new string [] { "Attribute" }); - definedSuffixes.Add ("System.EventArgs", new string [] { "EventArgs" }); - definedSuffixes.Add ("System.Exception", new string [] { "Exception" }); - definedSuffixes.Add ("System.Collections.Queue", new string [] { "Collection", "Queue" }); - definedSuffixes.Add ("System.Collections.Stack", new string [] { "Collection", "Stack" }); - definedSuffixes.Add ("System.Data.DataSet", new string [] { "DataSet" }); - definedSuffixes.Add ("System.Data.DataTable", new string [] { "DataTable", "Collection" }); - definedSuffixes.Add ("System.IO.Stream", new string [] { "Stream" }); - definedSuffixes.Add ("System.Security.IPermission", new string [] { "Permission" }); - definedSuffixes.Add ("System.Security.Policy.IMembershipCondition", new string [] { "Condition" }); - definedSuffixes.Add ("System.Collections.IDictionary", new string [] { "Dictionary" }); - definedSuffixes.Add ("System.Collections.Generic.IDictionary", new string [] { "Dictionary" }); - definedSuffixes.Add ("System.Collections.ICollection", new string [] { "Collection" }); - definedSuffixes.Add ("System.Collections.Generic.ICollection", new string [] { "Collection" }); - definedSuffixes.Add ("System.Collections.IEnumerable", new string [] { "Collection" }); - } - - private string [] GetSuffixes (string baseTypeName) + private static string [] GetSuffixes (string baseTypeName) { if (definedSuffixes.ContainsKey (baseTypeName)) { return definedSuffixes [baseTypeName]; @@ -73,48 +72,48 @@ namespace Gendarme.Rules.Naming { // checks if type name ends with an approriate suffix // returns array of proposed suffixes via out suffixes parameter or empty list (if none) - private bool HasRequiredSuffix (TypeDefinition type, out List<string> suffixes) + private static bool HasRequiredSuffix (TypeDefinition type, List<string> suffixes) { - suffixes = new List<string> (); TypeDefinition current = type; while (current != null && current.BaseType != null) { // if we have any suffixes defined by base type, we select them if (definedSuffixes.ContainsKey (current.BaseType.FullName)) { - suffixes.AddRange (GetSuffixes (current.BaseType.FullName)); + suffixes.AddRangeIfNew (GetSuffixes (current.BaseType.FullName)); } else { // if no suffix for base type is found, we start looking through interfaces foreach (TypeReference iface in current.Interfaces) if (definedSuffixes.ContainsKey (iface.FullName)) - suffixes.AddRange (GetSuffixes (iface.FullName)); + suffixes.AddRangeIfNew (GetSuffixes (iface.FullName)); } if (suffixes.Count > 0) { // if any suffixes found // check whether type name ends with any of these suffixes return suffixes.Exists (delegate (string suffix) { return type.Name.EndsWith (suffix); }); } else { - current = current.BaseType as TypeDefinition; // inspect base type + // inspect base type + current = current.BaseType.Resolve (); } } // by default, return true return true; } - public MessageCollection CheckType (TypeDefinition typeDefinition, Runner runner) + private List<string> proposedSuffixes = new List<string> (); + + public RuleResult CheckType (TypeDefinition type) { // rule does not apply to generated code (outside developer's control) - if (typeDefinition.IsGeneratedCode ()) - return runner.RuleSuccess; + if (type.IsGeneratedCode ()) + return RuleResult.DoesNotApply; // ok, rule applies - List<string> proposedSuffixes; - if (HasRequiredSuffix (typeDefinition, out proposedSuffixes)) - return runner.RuleSuccess; + proposedSuffixes.Clear (); + if (HasRequiredSuffix (type, proposedSuffixes)) + return RuleResult.Success; - RemoveDuplicates (ref proposedSuffixes); // there must be some suffixes defined, but type name doesn't end with any of them - Location location = new Location (typeDefinition); string messageText; if (proposedSuffixes.Count > 0) { string joinedSuffixes = proposedSuffixes [0]; @@ -128,18 +127,8 @@ namespace Gendarme.Rules.Naming { } else { messageText = "The class name does not end with the correct suffix. However Gendarme could not determine what suffix should it end with. Contact the author of the rule to fix this bug."; } - Message message = new Message (messageText, location, MessageType.Error); - return new MessageCollection (message); - } - - private static void RemoveDuplicates (ref List<string> list) - { - List<string> newList = new List<string> (); - foreach (string s in list) { - if (!newList.Contains (s)) - newList.Add (s); - } - list = newList; + Runner.Report (type, Severity.Medium, Confidence.High, messageText); + return RuleResult.Failure; } } } diff --git a/gendarme/rules/Gendarme.Rules.Naming/UsePluralNameInEnumFlagsRule.cs b/gendarme/rules/Gendarme.Rules.Naming/UsePluralNameInEnumFlagsRule.cs index 106e05a4..574040ff 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/UsePluralNameInEnumFlagsRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/UsePluralNameInEnumFlagsRule.cs @@ -36,28 +36,29 @@ using Gendarme.Framework.Rocks; namespace Gendarme.Rules.Naming { - public class UsePluralNameInEnumFlagsRule : ITypeRule { + [Problem ("This type is an enumeration and, by convention, enums should have a singular name.")] + [Solution ("Convert this enumeration type name from plural to singular.")] + public class UsePluralNameInEnumFlagsRule : Rule, ITypeRule { private static bool IsPlural (string typeName) { - int stringComparation = String.Compare (typeName, typeName.Length -1, "s", 0, 1, true, CultureInfo.CurrentCulture); - return stringComparation == 0; + return String.Compare (typeName, typeName.Length - 1, "s", 0, 1, true, CultureInfo.CurrentCulture) == 0; } - public MessageCollection CheckType (TypeDefinition type, Runner runner) + public RuleResult CheckType (TypeDefinition type) { // rule applies only to enums with [Flags] attribute if (!type.IsFlags ()) - return runner.RuleSuccess; + return RuleResult.DoesNotApply; // rule applies if (IsPlural (type.Name)) - return runner.RuleSuccess; + return RuleResult.Success; - Location location = new Location (type); - Message message = new Message ("The Enum Flags has singular name.", location, MessageType.Error); - return new MessageCollection (message); + // Confidence == Normal because valid names may end with 's' + Runner.Report (type, Severity.Low, Confidence.Normal, String.Empty); + return RuleResult.Failure; } } } diff --git a/gendarme/rules/Gendarme.Rules.Naming/UsePreferredTermsRule.cs b/gendarme/rules/Gendarme.Rules.Naming/UsePreferredTermsRule.cs index a791fca1..7b7caa68 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/UsePreferredTermsRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/UsePreferredTermsRule.cs @@ -28,67 +28,58 @@ using System; using System.Collections.Generic; +using System.Text; using Mono.Cecil; using Gendarme.Framework; namespace Gendarme.Rules.Naming { - public class UsePreferredTermsRule : ITypeRule, IMethodRule { + [Problem ("The identifier contains some obsolete terms.")] + [Solution ("For consistency replace any obsolete terms with the preferred ones.")] + public class UsePreferredTermsRule : Rule, ITypeRule, IMethodRule { + + private const string Message = "Obsolete term '{0}' should be replaced with '{1}'."; // keys are obsolete terms, values are preferred ones - private Dictionary<string, string> preferredTerms = - new Dictionary<string, string> (); - - public UsePreferredTermsRule () - { - // list is based on the FxCop naming rule (as the whole rule is inspired by it) - // http://www.gotdotnet.com/Team/FxCop/Docs/Rules/Naming/UsePreferredTerms.html - preferredTerms.Add ("ComPlus", "EnterpriseServices"); - preferredTerms.Add ("Cancelled", "Canceled"); - preferredTerms.Add ("Indices", "Indexes"); - preferredTerms.Add ("LogIn", "LogOn"); - preferredTerms.Add ("LogOut", "LogOff"); - preferredTerms.Add ("SignOn", "SignIn"); - preferredTerms.Add ("SignOff", "SignOut"); - preferredTerms.Add ("Writeable", "Writable"); - } + // list is based on the FxCop naming rule (as the whole rule is inspired by it) + // http://www.gotdotnet.com/Team/FxCop/Docs/Rules/Naming/UsePreferredTerms.html + private static Dictionary<string, string> preferredTerms = + new Dictionary<string, string> () { + { "ComPlus", "EnterpriseServices" }, + { "Cancelled", "Canceled" }, + { "Indices", "Indexes" }, + { "LogIn", "LogOn" }, + { "LogOut", "LogOff" }, + { "SignOn", "SignIn" }, + { "SignOff", "SignOut" }, + { "Writeable", "Writable" } + }; // common function checking any identifier - private MessageCollection CheckIdentifier (string identifier, Location location, Runner runner) + private RuleResult CheckIdentifier (TypeDefinition type, MethodDefinition method, string identifier) { - Dictionary<string, string> foundTerms = new Dictionary<string, string> (); // scan for any obsolete terms foreach (KeyValuePair<string, string> pair in preferredTerms) { - if (identifier.IndexOf (pair.Key, StringComparison.InvariantCultureIgnoreCase) != -1) { - foundTerms.Add (pair.Key, pair.Value); + if (identifier.IndexOf (pair.Key, StringComparison.OrdinalIgnoreCase) != -1) { + string s = String.Format (Message, pair.Key, pair.Value); + if (type != null) + Runner.Report (type, Severity.Low, Confidence.High, s); + else + Runner.Report (method, Severity.Low, Confidence.High, s); } } - if (foundTerms.Count == 0) - return runner.RuleSuccess; - - // form our messages - MessageCollection messages = new MessageCollection (); - foreach (KeyValuePair<string, string> pair in foundTerms) { - string errorMessage = string.Format ( - "Obsolete term '{0}' is used in the identifier. Replace it with the preferred term '{1}'.", - pair.Key, pair.Value); - Message message = new Message (errorMessage, location, MessageType.Error); - messages.Add (message); - } - return messages; + return Runner.CurrentRuleResult; } - public MessageCollection CheckType (TypeDefinition typeDefinition, Runner runner) + public RuleResult CheckType (TypeDefinition type) { - Location location = new Location (typeDefinition); - return CheckIdentifier (typeDefinition.Name, location, runner); + return CheckIdentifier (type, null, type.Name); } - public MessageCollection CheckMethod (MethodDefinition methodDefinition, Runner runner) + public RuleResult CheckMethod (MethodDefinition method) { - Location location = new Location (methodDefinition); - return CheckIdentifier (methodDefinition.Name, location, runner); + return CheckIdentifier (null, method, method.Name); } } } diff --git a/gendarme/rules/Gendarme.Rules.Naming/UseSingularNameInEnumsUnlessAreFlagsRule.cs b/gendarme/rules/Gendarme.Rules.Naming/UseSingularNameInEnumsUnlessAreFlagsRule.cs index 22fe1bfb..f6adf451 100644 --- a/gendarme/rules/Gendarme.Rules.Naming/UseSingularNameInEnumsUnlessAreFlagsRule.cs +++ b/gendarme/rules/Gendarme.Rules.Naming/UseSingularNameInEnumsUnlessAreFlagsRule.cs @@ -36,28 +36,28 @@ using Gendarme.Framework.Rocks; namespace Gendarme.Rules.Naming { - public class UseSingularNameInEnumsUnlessAreFlagsRule : ITypeRule { + [Problem ("This type is an enumeration and by convention it should have a singular name.")] + [Solution ("Change the enumeration name from the plural to the singular form.")] + public class UseSingularNameInEnumsUnlessAreFlagsRule : Rule, ITypeRule { private static bool IsPlural (string typeName) { - int stringComparation = String.Compare (typeName, typeName.Length -1, "s", 0, 1, true, CultureInfo.CurrentCulture); - return stringComparation == 0; + return (String.Compare (typeName, typeName.Length - 1, "s", 0, 1, true, CultureInfo.CurrentCulture) == 0); } - public MessageCollection CheckType (TypeDefinition type, Runner runner) + public RuleResult CheckType (TypeDefinition type) { // rule applies only to enums - but not enums marked with [Flags] attribute if (!type.IsEnum || type.IsFlags ()) - return runner.RuleSuccess; + return RuleResult.DoesNotApply; // rule applies if (!IsPlural (type.Name)) - return runner.RuleSuccess; + return RuleResult.Success; - Location location = new Location (type); - Message message = new Message ("The enum should not have a plural name.", location, MessageType.Error); - return new MessageCollection (message); + Runner.Report (type, Severity.Medium, Confidence.Normal, String.Empty); + return RuleResult.Failure; } } } |