SubMain - CodeIt.Right The First Time!

/Community

A Support Community for SubMain Products
 Home Products Services Download Purchase Support
in Search
 
Home Forums Blogs Tutorials Downloads
Welcome to SubMain Community Sign in | Join | Help

Tutorials

  • How CodeIt.Right is better than FxCop?

    The biggest benefit of CodeIt.Right is the automatic code correction and refactoring to patterns. The alternative is you could manually spend hours or even days on some pesky violations rather CodeIt.Right do the work for you in a matter of minutes.

    You can also choose to follow Microsoft Guidelines or you own custom standards, group rule sets into profiles, generate your custom standard documentation, efficiently work with existing/legacy projects, avoid false positives.

    The Enterprise Edition adds Team features, Code Metrics, Statistics, enhanced reporting.

      CodeIt.Right FxCop
      Scans and analyzes source code Runs on compiled assemblies (you have to compile code to use it)
    Correction Corrects violations and code smells automatically N/A
    Refactoring to patterns Automatically implements and corrects most common coding patterns like Dispose/Finalize, ISerializable, Custom Serialization, etc N/A
    Visual Studio Integration Natively integrates into Visual Studio IDE; quick navigation to the violation source code; highlights modifications in the editor; safe Undo/Redo. Basic/Command line
    ASP.NET ASPX/ASCX/ASMX pages, in-page code, code behind source Only compiled code behind assemblies
    Local variables/constants Includes rules that are targeting local variables/constants and any data that is present in the source code Not possible in FxCop - the data is lost in the MSIL
    Follow your own standards Includes Microsoft Guidelines and best industry practices out of the box. Allows to define your own standard to follow - tweak the rule set to your needs without having to write custom rules (which is an option too). For example, go as crazy as enforce Hungarian naming conventions; or convert existing project with Hungarian notation to the new MS style conventions. Strictly enforces Microsoft Guidelines - inflexible and enforces the set with no options to configure
    Define custom rule set Profiles - configure multiple rule subsets and quickly switch between them. Share profiles between the Team members or (EE) push them to the Team. N/A
    Rule Instances Introduces Rule Instances - multiple instances of a single rule that are configured (via rule Properties) to your Team needs Only allows to turn off specific rule, cannot configure/tweak
    Reducing noise (false positives)
    • Exclude violation in Project
    • Exclude violation in source code
    • Exclude Violation, Rule, File, Project
    • Exclude code regions
    • Custom Profiles
    • Override default rule severity, target, scope, etc
    • Exclude violation in Project
    • Exclude violation in source code
    Severity Threshold Unique feature - Severity Threshold - allows to concentrate on most critical violations first and drill down from most severe issues to simple warnings. N/A

    Scan entire solution, project, folder or individual file Scan projects only
    Create own guidelines documentation Generate Team Guidelines document within a mouse click, with description, code samples, etc - based on your custom configured Profile  
    Team features (EE) separate modules to (a) author / configure team standards and (b) run analysis and correction based on the team standard configured by Team Lead/Architect; publish and push (share) Team standard configuration to the Team members; Team usage statistics N/A
    Reporting Flexible reporting/pivot that can be exported and printed N/A
    Code Metrics Available (EE); can be exported, printed, emailed N/A
    Command line output Violations, Code Metrics (EE) Violations only
    Command line filtering Solution, Project, Profile, Severity Threshold Project, Assembly
    Command line delivery File, Send via email File only
    Command line integration Command line tool, MsBuild and NAnt tasks Command line tool
    Update delivery Rule Library auto-update - get new rules when we publish them
    N/A

    Download trial copy of CodeIt.Right today and see the difference yourself!

     

  • XML Comment template: IntelliComment or XML Comment Stub?

    One of the very helpful and important rules that we added in the past few months is the one that finds members that missing XML documents when these are required - General / Type, Member -> Should have XML comments (Externally visible types and members should have XML comments).

    One of the most frequently asked question about the rule is why some users are not seeing the missing XML comment violation on select project. There are two possible reasons for that:

    1. The rule will only trigger violation on public and protected members in its default configuration. If you choose to have it validate private and/or static members, you will need to edit the rule's Scope property to include those as well.
    2. The option to generate XML documentation is turned OFF in  your project. In this case the rule doesn't the missing XML comment violation to reduce false positives since the project setting state it does not need XML documentation.

    To turn the option to generate documentation ON, in C# project, go to project Properties -> Build -> XML documentation file

    XMLComment1

    In VB project, go to project Properties -> Compile -> Generate XML documentation file

    XMLComment2

    In the spirit of CodeIt.Right the rule offers two automatic correction options - IntelliComment and XML Comment Stub. In the default configuration these are fairly similar, the difference is that IntelliComment will fill in the generated XML Comment using data from our GhostDoc engine, while the Stub template will create an empty XML Comment Stub.

    Here is example generated by IntelliComment template

        /// <summary>
        /// Determines the size of the page buffer.
        /// </summary>
        /// <param name="initialPageBufferSize">Initial size of the page buffer.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public int DeterminePageBufferSize(
                               int initialPageBufferSize) {
    
            // Implement the method here
            return 1;
    
        }

    And example generated by XML Comment Stub template

        /// <summary>
        ///  
        /// </summary>
        /// <param name="initialPageBufferSize"> </param>
        /// <returns></returns>
        /// <remarks></remarks>
        public int DeterminePageBufferSize(
                               int initialPageBufferSize) {
    
            // Implement the method here
            return 1;
    
        }

    So, the rule offers two correction option - it is up to you to pick which template works best for your project.

    I notice that I keep using the word "template" when describing the two correction options. That is because these are true T4 templates that you can customize to fit your team requirements.

    Here is default IntelliComment template:

    <#@ template language="C#" #>
    <#
        CodeElement codeElement = Context.CurrentCodeElement;
    #>
    /// <summary>
    /// <#= codeElement.XmlComment.SummaryTagText #>    
    /// </summary>
    <#
        if(codeElement.HasTypeParameters) 
        {
            foreach(TypeParameter typeParameter in codeElement.TypeParameters) {
    #>
    /// <typeparam name="<#= typeParameter.Name #>"><#= typeParameter.XmlComment.TypeParamTagText #></typeparam>
    <#
            }
        }
        
        if(codeElement.HasParameters) 
        {
            foreach(Parameter parameter in codeElement.Parameters) {
    #>
    /// <param name="<#= parameter.Name #>"><#= parameter.XmlComment.ParaTagText #></param>
    <#
            }
        }
        
        if(codeElement.HasReturnType) {
    #>
    /// <returns><#= codeElement.XmlComment.ReturnsTagText #></returns>
    <#
        }
        
        if(codeElement.IsProperty) {
    #>
    /// <value><#= codeElement.XmlComment.ValueTagText #></value>
    <#
        }    
        
        if(codeElement.IsMember) {
    #>
    /// <remarks></remarks>
    <#
        }    
    #>

    As you can see it is very much self-explanatory and you can customize it to your needs. For example, in combination with the CodeIt.Right Global Properties feature, we can have <reviewed/> and <copyright/> data automatically when we add the following at the very end of the template:

    /// <reviewed><#= Context.GetGlobalProperty("UserName") #></reviewed>
    /// <copyright><#= Context.GetGlobalProperty("CompanyName") #> Copyright <#= System.DateTime.Now.Year.ToString() #></copyright>

    Pretty powerful stuff, huh?

  • Tutorial: Extending Existing Rules

    You already know how you can create new custom rules using CodeIt.Right SDK, of not, you may want to read this article first.

    In this tutorial we will show how to extend existing rules using the new SDK features introduced in CodeIt.Right v1.8.09300. The new technique is derive the custom rule from a base rule and override only the methods that need to be modified.

    Let's extend the rule "Avoid single line If statement" (RuleID: CD0002; base class AvoidSingleLineIfStatement) in the Coding Style category:

    ExtendingRules1

    The base rule above will trigger a violation when find a code pattern like this:

    if (x > 0) y = 0;

    When the rule default correction action "Split If block into a multiline statement" is used it will modify the code into:

    if (x > 0)
    {
        y = 0;
    }

    That is what comes in the box.

    Our team may have an internal guideline that requires a single line conditional to be split into two lines without the squiggly brackets:

    if (x > 0)
        y = 0;

    Hey, not all teams are created equal :)

    In this case correction option that comes with the base rule AvoidSingleLineIfStatement is not very useful and we need to extend the rule with our custom correction.

    So, let's start.

    We will skip the list of required referenced  assemblies - you will find them in the complete code sample at the end of the post.

    Declare new class that inherits from the base rule class:

    namespace CustomRuleLibrary.CodingStyle 

        [Serializable] 
        [ModificationDate("10/14/2009")] 
        [Category("CustomRuleLibrary.CodingStyle")] 
        public class AvoidSingleLineIfStatement2 : AvoidSingleLineIfStatement 
        {

    In the code above we also set the Category attribute to "CustomRuleLibrary.CodingStyle" so we could easier find the custom in the Profile.

    We override ID property and use GUID for the new RuleID value. Some of the CodeIt.Right functions, for example, help pages are handled differently for custom rules. Using GUID for RuleID hits CodeIt.Right that the rule is custom.

            public override string ID 
            { 
                get 
                {  
                    // Override the RuleID value with own GUID (recommended)
                    return "6C832235-0B02-4227-911A-156F0B1FAC71"
                } 
            } 

    Property AutoCorrectionOptions needs to be overridden to add new correction action "Split If block into a multiline statement without block":

            /// <summary>
            /// Returns list of auto correction options 
            /// </summary>
            public override string[] AutoCorrectionOptions 
            { 
                get 
                { 
                    IMethodInfo methodInfo = Element as IMethodInfo; 
                    if (methodInfo != null
                    { 
                        // Get the base class list of available corrections
                        string[] baseOptions = base.AutoCorrectionOptions; 
                        string[] options = (string[])Array.CreateInstance(typeof(string), baseOptions.Length + 1); 
                        // Add new correction action to the list
                        Array.Copy(baseOptions, 0, options, 0, baseOptions.Length); 
                        options[options.Length - 1] = "Split \"If\" block into a multiline statement without block"

                        return options; 
                    } 

                    return new string[] { }; 
                } 
            }

    The base rule correction option:

    ExtendingRules2

    Our custom rule correction options with the new action added in the AutoCorrectionOptions above:

    ExtendingRules3

    Now we implement our new custom correction action just the way we like it to work:

            /// <summary>
            /// Implementation of our custom correction action 
            /// </summary>
            private bool Correct_1(IElementInfo elementInfo) 
            { 
                IMethodInfo methodInfo = Element as IMethodInfo; 
                if (methodInfo != null
                { 
                    StatementCollection statements = RuleUtilities.GetMethodStatements(methodInfo); 
                    IStatement statement = SearchForSingleLineIfStatement(statements); 
                    if (statement != null
                    { 
                        string codeToInsertAfter = Environment.NewLine; 
                        string codeToInsertBefore = Environment.NewLine; 

                        IRegion ifBlockRegion = GetIfBlockRegion(statement); 
                        if (ifBlockRegion != null
                        { 
                            string ifBlockText = GetIfBlockText(statement, ifBlockRegion); 
                            if (ifBlockText != null
                            { 
                                methodInfo.ReplaceCodeBlock(ifBlockRegion, 
                                    codeToInsertBefore + ifBlockText + codeToInsertAfter); 

                                return true
                            } 
                        } 
                    } 
                } 

                return false
            }

    And we tie it all together in the method Correct - for correction action with index 0 we execute the base rule correction and for the index 1 (that we added) execute method Correct_1 that implements our custom correction:

            /// <summary>
            /// Execute the specified correction action 
            /// </summary>
            /// <param name="correctionOptionIndex">Index of the correction action</param>
            public override bool Correct(int correctionOptionIndex) 
            { 
                bool result = base.Correct(correctionOptionIndex); 

                switch (correctionOptionIndex) 
                { 
                    case 0
                        // For correction action 0 execute the base class correction
                        return result; 
                    case 1
                        // For correction action 1 execute our custom correction
                        return Correct_1(Element); 

                    default
                        break
                } 

                return false
            }

    And we are done!

    The final steps are to compile the new rule, drop the assembly to Program Files\SubMain\CodeIt.Right\Rules\ and we can now add the rule to a profile:

    ExtendingRules4

    Here is the complete code for our custom rule:

    using System;
    using System.IO;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Runtime.Serialization;
    using System.Globalization;

    using SubMain.CodeObjectModel.Reflection;
    using SubMain.Core.Services;
    using SubMain.CodeItRight.Sdk;
    using SubMain.CodeItRight.Sdk.Core.Collections;
    using SubMain.CodeItRight.Sdk.Core.Reflection;
    using SubMain.CodeItRight.Sdk.Core.Rules;
    using SubMain.CodeItRight.Sdk.Core.Utils;
    using SubMain.CodeItRight.Sdk.Rules;
    using SubMain.CodeItRight.Sdk.Utils;
    using SubMain.CodeItRight.Rules.CodingStyle;

    namespace CustomRuleLibrary.CodingStyle
    {
        [Serializable]
        [ModificationDate("10/14/2009")]
        [Category("CustomRuleLibrary.CodingStyle")]
        public class AvoidSingleLineIfStatement2 : AvoidSingleLineIfStatement
        {
            /// <summary>
            /// Returns list of auto correction options
            /// </summary>
            public override string[] AutoCorrectionOptions
            {
                get
                {
                    IMethodInfo methodInfo = Element as IMethodInfo;
                    if (methodInfo != null)
                    {
                        // Get the base class list of available corrections
                        string[] baseOptions = base.AutoCorrectionOptions;
                        string[] options = (string[])Array.CreateInstance(typeof(string), baseOptions.Length + 1);
                        // Add new correction action to the list
                        Array.Copy(baseOptions, 0, options, 0, baseOptions.Length);
                        options[options.Length - 1] = "Split \"If\" block into a multiline statement without block";

                        return options;
                    }

                    return new string[] { };
                }
            }

            /// <summary>
            /// Implementation of our custom correction action 
            /// </summary>
            private bool Correct_1(IElementInfo elementInfo)
            {
                IMethodInfo methodInfo = Element as IMethodInfo;
                if (methodInfo != null)
                {
                    StatementCollection statements = RuleUtilities.GetMethodStatements(methodInfo);
                    IStatement statement = SearchForSingleLineIfStatement(statements);
                    if (statement != null)
                    {
                        string codeToInsertAfter = Environment.NewLine;
                        string codeToInsertBefore = Environment.NewLine;

                        IRegion ifBlockRegion = GetIfBlockRegion(statement);
                        if (ifBlockRegion != null)
                        {
                            string ifBlockText = GetIfBlockText(statement, ifBlockRegion);
                            if (ifBlockText != null)
                            {
                                methodInfo.ReplaceCodeBlock(ifBlockRegion,
                                    codeToInsertBefore + ifBlockText + codeToInsertAfter);

                                return true;
                            }
                        }
                    }
                }

                return false;
            }

            public override string ID
            {
                get
                { 
                    // Override the RuleID value with own GUID (recommended)
                    return "6C832235-0B02-4227-911A-156F0B1FAC71";
                }
            } 

            /// <summary>
            /// Execute the specified correction action
            /// </summary>
            /// <param name="correctionOptionIndex">Index of the correction action</param>
            public override bool Correct(int correctionOptionIndex)
            {
                bool result = base.Correct(correctionOptionIndex);

                switch (correctionOptionIndex)
                {
                    case 0:
                        // For correction action 0 execute the base class correction
                        return result;
                    case 1:
                        // For correction action 1 execute our custom correction
                        return Correct_1(Element);

                    default:
                        break;
                }

                return false;
            }

        }
    }
  • CodeItRight.Cmd.exe Command Line Options

    CodeItRight.Cmd is the command-line companion to the CodeIt.Right application. Like CodeIt.Right, CodeItRight.Cmd analyzes source code and reports violations, such as possible design, performance, and security issues. CodeItRight.Cmd can be used as a stand-alone tool or added to automated build processes. 

    The following are the command line parameters that are supported by SubMain.CodeItRight.Cmd.exe ; Parameter values are not case sensitive.

    /Solution  - (Required*) - full file name of the solution to load (*.sln file) (*) This parameter is not required if /Project parameter specified.
     
    /Project   - (Required*) - full file name of the project to load (*.csproj or *.vbproj file) (*) This parameter is not required if /Solution parameter specified.

    /Out  - (Required) - full name of the xml report output file.

    /OutXSL  - (Optional) - full name of the xsl file to override the default xsl.

    /CRData  - (Optional) - full name of the CodeIt.Right .crdata file. When specified, CodeItRight.Cmd will use the exclusion list (violations, rules and files) saved using the Visual Studio version of CodeIt.Right.

    /Profile  - (Optional) - name of the User Profile that defines active rule set for the analysis. When omitted, the built-in profile is used.

    /severityThreshold  - (Optional) - Severity Threshold value to limit the output violation set. When omitted, the the lowest Severity is used - None. Accepted values (from Higher to Lower):

    • CriticalError
    • Error
    • CriticalWarning
    • Warning
    • Information
    • None

    /Quiet - (Optional) - disables console output.
     
    /Help  - display list of command line parameters.

    Example:

    SubMain.CodeItRight.Cmd.exe /Solution:"C:\MyProjects\MyProject\MyProject.sln"
    /Out:"C:\MyProjects\MyProject\MyProject.CIR.Output.xml"
    /CRData:"C:\MyProjects\MyProject\MyProject.crdata" /Profile:"My Profile" /severityThreshold:"Error"

    CodeItRight.Cmd Error Codes

    Returns

    • Positive code equal to the number of violations found
    • 0 - No violations and no errors found
    • Negative codes for internal errors:
    -1 Command Line Switch Error
    -2 Command Line Argument Error
    -3 Initialization Error
    -4 Analysis Error
    -5 Output Error
    -6 Unknown Error
  • Tutorial: Creating Custom Rules

    The best part about CodeIt.Right is that you are not limited to just the rule libraries included into the box. You can easily define your own (custom) rules. What makes this possible is the "CodeIt.Right SDK". The SDK documentation is available online at http://submain.com/codeit.right/sdk/ as well as locally as part of your CodeIt.Right help file.

    In this tutorial we will create "Use Certain Suffixes For Derived Types" rule. We will

    • Create Custom Rule Template using Wizard that CodeIt.Right adds to Visual Studio
    • Implement set of methods and properties that will find and correct violations of the rule
    • Define Configurable Properties for the rule, so the users will be able to create instances of the rule and tweak it to their needs
    • Deploy the new rule

    Create Custom Rule Template Using Wizard

    1. Open Visual Studio

    2. In the menu bar, click File, and then click New Project

    3. In the New Project dialog box, in the Project Types pane, select CodeIt.Right Projects if that option is not already selected.

    4. In the Templates pane, select the template for the appropriate programming language (Visual Basic or Visual C#). The custom rule in the examples uses Visual Basic.

    5. Complete the Name, Location, and Solution fields for the custom rule.

    6. Click OK. The New Rule Wizard dialog box appears.

    7. In the New Rule Wizard dialog box, complete as many of the fields as possible. Fields that have a red asterisk to the right are required. Click Next.

    8. Select the options to determine the scope for the custom rule. To select or deselect all the options, select All. Click Next.

    9. Select the targets for the custom rule. When done, click Finish.

    The status bar at the bottom of the Visual Studio window displays the progress of the creation of the custom rule.

    Edit the Generated Template

    After a custom rule template is created, you can edit it in the Solution Explorer. You can edit template information, the content generated by the New Rule Wizard, and implement code of the Check and Correct methods.

    1. Double-click the rule in Soultion Explorer to edit it. The generated regions of the rule are collapsed by default.

    2. Expand the Wizard Generated Code region to review the code generated based on options selected in the New Rule Wizard. You can edit the options if necessary. Note that the rule's ID is automatically generated GUID - you can edit it as well but make sure your ID is not equal to any of the built-in CodeIt.Right rules or even better your rule ID doesn't follow CodeIt.Right internal ID schema.

      #Region "Wizard Generated Code"
      
      #Region "Data Entered On Wizard form"
      
          Private Const InputID As String = "0500daf7-f2a0-4549-b90e-bd8f6d515bb5"
          Private Const InputName As String = "UseCertainSuffixesForDerivedTypes"
          Private Const InputTitle As String = "Use Certain Suffixes For Derived Types"
          Private Const InputSeverity As SeverityLevel = SeverityLevel.Warning
          Private Const InputScopes As RuleScopes = _
            RuleScopes.Public or RuleScopes.ProtectedInternal or RuleScopes.Private or RuleScopes.Abstract or RuleScopes.Sealed _
            or RuleScopes.Readonly or RuleScopes.Virtual or RuleScopes.Override or RuleScopes.Extern or RuleScopes.Unsafe _
            or RuleScopes.SpecialName or RuleScopes.Const or RuleScopes.Volatile or RuleScopes.WriteOnly _
            or RuleScopes.WithEvents or RuleScopes.Default
          Private Const InputAuthor As String = "SubMain Team"
          Private Const InputEmail As String = "support@submain.com"
          Private Const InputUrl As String = ""
          Private Const InputAvailableTargets As RuleTargets = RuleTargets.Class
          Private Const InputViolationDescription As String = ""
      
      #End Region
      
      #Region "Constructor"
      
          Public Sub New()
              Me.Name = InputName
              Me.Title = InputTitle
              Me.Severity = InputSeverity
              Me.Targets = Me.AvailableTargets
              Me.Scopes = InputScopes
          End Sub
      
      #End Region
      
          Public Overrides ReadOnly Property ID As String
              Get
                  Return InputID
              End Get
          End Property
      
          Public Overrides ReadOnly Property AvailableTargets As RuleTargets
              Get
                  Return InputAvailableTargets
              End Get
          End Property
      
          Public Overrides ReadOnly Property Author As String
              Get
                  Return InputAuthor
              End Get
          End Property
      
          Public Overrides ReadOnly Property Email As String
              Get
                  Return InputEmail
              End Get
          End Property
      
          Public Overrides ReadOnly Property Url As String
              Get
                  Return InputUrl
              End Get
          End Property
      
          Public Overrides ReadOnly Property ViolationDescription As String
              Get
                  Return InputViolationDescription
              End Get
          End Property
      
          Public Overloads Function Correct(ByVal correctionOptionIndex as Integer) As Boolean
              MyBase.Correct(correctionOptionIndex)
      
              Select Case correctionOptionIndex
      
                  Case Else
              End Select
      
              Return False
          End Function
      
      #End Region
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      

    3. In the Template to be populated by rule author region, edit the AutoCorrectionOptions property to establish all the options for automatic correction of violations to the rule. Each option is added to the drop-down list in the Action column when code is analyzed. The GetCorrect0Name will be implemented in the next bullet.

      Public Overrides ReadOnly Property AutoCorrectionOptions As String()
      
          Get
      
              If (MyBase._userCorrectOptions.Count = 0) Then
      
                  ' Get title of the correction option
                  Dim text As String = Me.GetCorrect0Name
      
                  If ([text].Length > 0) Then
      
                      ' Add to the list of available options
                      MyBase._userCorrectOptions.Add([text])
      
                  End If
      
              End If
      
              Return MyBase.AutoCorrectionOptions
      
          End Get
      
      End Property
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      

    4. In the Template to be populated by rule author region, edit the Correction method to establish how violations to the rule are corrected. In the example below, the correct suffix is added to the code element. The new name is then checked using helper function NamingRuleUtilities.FixForUniqueName to make sure it is unique in the solution. If not, the name is further modified so that it is unique. SuffixToCheck is a configurable property that we will define later in this tutorial.

      Private Function GetCorrect0Name() As String
      
          Dim baseName As String = String.Empty
      
          If (Not MyBase.Element Is Nothing) Then
      
              Dim info As ICodeElementInfo = MyBase.Element.ToCodeElementInfo
      
              If (Not info Is Nothing) Then
      
                  ' Get the code element name
                  Dim displayName As String = info.DisplayName
      
                  ' Add the correct suffix
                  If ((Not Me.SuffixToCheck Is Nothing) AndAlso (Me.SuffixToCheck.Length > 0)) Then
                      baseName = (displayName & Me.SuffixToCheck)
                  End If
      
              End If
          End If
      
          ' Make sure the new name is unique
          Return NamingRuleUtilities.FixForUniqueName(baseName, MyBase.Element)
      
      End Function
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      

    5. In the Template to be populated by rule author region, edit the Check method to establish violations to the rule are found. In the example below, each appropriate code element is checked for the correct suffix. If the element does not include the correct suffix, it is flagged as a violation. MustImplement is another configurable property defined later in the tutorial. Method ITypeInfo.IsAssignableFrom returns True if the code element derived from the type stored in MustImplement. Helper function NamingRuleUtilities.HasSuffix returns True is code element has the suffix, False otherwise.

      Public Overrides Function Check(ByVal element As IElementInfo) As Boolean
      
          If (Not element Is Nothing) Then
      
              Dim info As ICodeElementInfo = element.ToCodeElementInfo
      
              If (Not info Is Nothing) Then
      
                  ' Get the code element name
                  Dim displayName As String = info.DisplayName
      
                  ' If configurable properties SuffixToCheck and MustImplement have values
                  If (((Not Me.SuffixToCheck Is Nothing) AndAlso (Me.SuffixToCheck.Length > 0)) _
                     AndAlso ((Not Me.MustImplement Is Nothing) AndAlso (Me.MustImplement.Length > 0))) Then
      
                      Dim info2 As ITypeInfo = TryCast(info, ITypeInfo)
      
                      ' If element derives from the type (MustImplement) and doesn't have correct suffix (SuffixToCheck)
                      If (((Not info2 Is Nothing) AndAlso info2.IsAssignableFrom(Me.MustImplement)) _
                         AndAlso Not NamingRuleUtilities.HasSuffix(displayName, Me.SuffixToCheck)) Then
      
                          ' Flag the violation
                          Return True
      
                      End If
      
                  End If
      
              End If
      
          End If
      
          Return False
      
      End Function
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      

    Configurable Properties

    Configurable Properties are flexible mechanism that allows to develop rules that can be customized in user profiles (rule instances). They must be marked with attribute <ConfigurableProperty>.

    For our rule we need two configurable properties -

    • MustImplement - will filter and only run the rest of the rule against code elements that derive from the type assigned in this property
    • SuffixToCheck - will allow to define for each rule instance suffix to be that the code element derived from MustImplement should have

    • <ConfigurableProperty, Description("Type should implement the specified type or interface")> _
          Public Property MustImplement As String
      
              Get
                  Return Me._mustImplement
              End Get
      
              Set(ByVal value As String)
                  Me._mustImplement = value
              End Set
      
          End Property
      
      <ConfigurableProperty, Description("Certain Suffix to be checked")> _
          Public Property SuffixToCheck As String
      
              Get
                  Return Me._suffixToCheck
              End Get
      
              Set(ByVal value As String)
                  Me._suffixToCheck = value
              End Set
      
          End Property
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      

    Here is how properties are configured for a specific instance of the rule we developed in this tutorial - "Exception class name must have 'Exception' suffix" (click the image for full size):

    Adding another rule to the same project

    At this point of the tutorial we have one custom rule implemented in the project (library). If you want to add another rule or more to the library, you need to right-click project in the Solution Explorer, select Add New Item and pick Custom Rule Class under CodeIt.Right Items - this will start New Rule Wizard.

    Build and Deploy new rule

    Our rule is now ready to be deployed.

    1. Build your custom rule project
    2. Copy the resulting .dll assembly into the <CodeIt.Right installation>\Rules directory (typically Program Files\SubMain\CodeIt.Right\Rules)
    3. Add a new instance of the new rule to your user profile. See How to add rule to User Profile.

    Note: You don't need to close Visual Studio when you deploy new or updated rule library. CodeIt.Right picks up the rule library changes every time you analyze code or open Profile Editor.

    Where do I find samples?

    Your best source for rule examples is CodeIt.Right's own rule library (see the <CodeIt.Right installation>\Rules directory). As of this post we have implemented 75+ rule classes with 100+ rule instances in the detault profile. Feel free to explore what we've got using Lutz Roeder's wonderful Reflector and learn what's inside of each rule.

    Keep an eye on is our community Custom Rule Repository - it will grow as users develop and share their rules. This is also the place where we post our complete sample rule projects.

    Further Reading and Resources

    1. CodeIt.Right SDK Documentation
    2. CodeIt.Right Tutorials
    3. How to create own Profile
    4. How to add rule to User Profile
    5. Defining ViolationDescription and CorrectionDescription properties (to be published)
    6. Built-in API helper functions
    7. Custom Rule Repository
    8. FxCop rule mapping (to be published)
    9. Using SuppressMessage Attribute (to be published)
    10. Top 10 most useful API helper functions explained (to be published)
    
 
     
 
Home |  Products |  Services |  Download |  Purchase |  Support |  Community |  About Us |