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
- Open Visual Studio
- In the menu bar, click File, and then click New Project

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

- 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.
- Complete the Name, Location, and Solution fields for the custom rule.
- Click OK. The New Rule Wizard dialog box appears.
- 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.

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

- 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.
- Double-click the rule in Soultion Explorer to edit it. The generated regions of the rule are collapsed by default.

- 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
|
- 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
Dim text As String = Me.GetCorrect0Name
If ([text].Length > 0) Then
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
|
- 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
Dim displayName As String = info.DisplayName
If ((Not Me.SuffixToCheck Is Nothing) AndAlso (Me.SuffixToCheck.Length > 0)) Then
baseName = (displayName & Me.SuffixToCheck)
End If
End If
End If
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
|
- 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
Dim displayName As String = info.DisplayName
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 (((Not info2 Is Nothing) AndAlso info2.IsAssignableFrom(Me.MustImplement)) _
AndAlso Not NamingRuleUtilities.HasSuffix(displayName, Me.SuffixToCheck)) Then
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.
- Build your custom rule project
- Copy the resulting .dll assembly into the <CodeIt.Right installation>\Rules directory (typically Program Files\SubMain\CodeIt.Right\Rules)
- 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
- CodeIt.Right SDK Documentation
- CodeIt.Right Tutorials
- How to create own Profile
- How to add rule to User Profile
- Defining ViolationDescription and CorrectionDescription properties (to be published)
- Built-in API helper functions
- Custom Rule Repository
- FxCop rule mapping (to be published)
- Using SuppressMessage Attribute (to be published)
- Top 10 most useful API helper functions explained (to be published)