Custom StyleCop Rules

Microsoft’s StyleCop is a code style and consistency analysis tool for C#. The tool integrates into the Visual Studio IDE, or can be run on the command line. StyleCop ships with a default set of rules enforcing common style guidelines.

This article describes how to write custom StyleCop rules.

How to write a custom StyleCop rule

Lets say you want to check your code for methods longer than 50 lines.

  1. Create a Class Library project in Visual Studio
  2. Add a reference to Microsoft.StyleCop and Microsoft.StyleCop.CSharp
  3. Create your analyzer class that inherits from SourceAnalyzer
  4. Add an XML file with the same name as the analyzer class. Set the properties of the Xml file to be an Embedded Resource and not copy to the output directory.
  5. Override the AnalyzeDocument method
  6. You are ready to write your own analysis code

Here’s an example of the analyzer class:

namespace CustomStyleCopRule
{
using System;
using Microsoft.StyleCop;
using Microsoft.StyleCop.CSharp;

namespace CustomStyleCopRule
{
    using System;
    using Microsoft.StyleCop;
    using Microsoft.StyleCop.CSharp;

    [SourceAnalyzer(typeof(CsParser))]
    public class CustomSourceAnalyzer : SourceAnalyzer
    {
        public override void AnalyzeDocument(CodeDocument document)
        {
            var csharpDocument = document as CsDocument;
            if (csharpDocument != null)
            {
                csharpDocument.WalkDocument(
                    new CodeWalkerElementVisitor<CustomSourceAnalyzer>(this.VisitElement),
                    new CodeWalkerStatementVisitor<CustomSourceAnalyzer>(this.VisitStatement),
                    new CodeWalkerExpressionVisitor<CustomSourceAnalyzer>(this.VisitExpression),
                    this);
            }
        }

        private bool VisitElement(CsElement element, CsElement parentElement, CustomSourceAnalyzer context)
        {
            // Add your code here.
            return true;
        }

        private bool VisitStatement(Statement statement, Expression parentExpression, Statement parentStatement, CsElement parentElement, CustomSourceAnalyzer context)
        {
            // Add your code here.
            return true;
        }

        private bool VisitExpression(Expression expression, Expression parentExpression, Statement parentStatement, CsElement parentElement, CustomSourceAnalyzer context)
        {
            // Add your code here.
            return true;
        }
    }
}

As you can see in the example class above, StyleCop has some important concepts to walk through a Document. The Document represents the code file itself, Elements are children of a Document. In an upcoming article I will explain Statement and Expression. For our example to inspect a method, we can start with the Element. To give you some concrete examples the Elements can be Class, Constructor, Delegate, Destructor, Event, Field, Method, Property and some more.

And here’s an example of the corresponding Xml file:

<?xml version="1.0" encoding="utf-8" ?>
<SourceAnalyzer Name="CustomRules">
  <Rules>
    <RuleGroup Name="Custom Rules">
      <Rule Name="TooLongMethod" CheckId="CR0001">
        <Context>The method '{0}' has about {1} lines (allowed are {2} lines) and is too long.</Context>
      </Rule>
    </RuleGroup>
  </Rules>
</SourceAnalyzer>

Every rule must have a unique Name and a CheckId consisting of two characters (StyleCop uses ‘SA’ here) and four digits. The Context tag can be used for the message in the Visual Studio Error List window. Additional parameters can be added to the AddViolation call, which will be formatted into your message. The RuleGroup can be used to enable or disable a whole group of rules.

With all the given information it’s relatively easy to add some code for the check of all the methods in a document:

        private bool VisitElement(CsElement element, CsElement parentElement, CustomSourceAnalyzer context)
        {
            if (element.ElementType == ElementType.Method)
            {
                int firstLineNumber = element.LineNumber;
                int lastLineNumer = firstLineNumber;

                foreach (var statement in element.ChildStatements)
                {
                    lastLineNumer = statement.LineNumber;
                }

                int numberOfLinesInMethod = lastLineNumer - firstLineNumber + 1;
                if (numberOfLinesInMethod > 50)
                {
                    context.AddViolation(element, "TooLongMethod", element.Declaration.Name,
                        numberOfLinesInMethod, 50);
                }
            }
            return true;
        }

The important thing in the code above is the AddViolation call, which was already mentioned with the Xml document above. The visitor delegates return true to continue the analysis, false to stop the analysis for the current document.

Install the custom rules

Your code should already compile, we just need to install the assembly. That’s relatively easy. Just copy the Assembly to the install folder of StyleCop or any subfolder. When you start Visual Studio, the custom rules will automatically be loaded by StyleCop.

Outlook

As mentioned I will explain more details of StyleCop’s code model with Elements, Statements and Expressions as well as how to write unit tests for your custom rules.

Until then you should have your first cutom rules up and running.

About the author

13 comments

  • You defined the SourceAnalyzer attribute both on the namespace and the class. Is this necessary? Or would either be enough?

    I’m looking forward to the complete clean code rule set 🙂
    Urs

  • I’m sorry it’s not the real code; it’s the beginner’s sample. The SourceAnalyzer attribute only applies to the class. I’ve updated the post.

    Cheers
    Thomas

  • Hi,

    I know that it’s just a sample, but you can check for a method length by quite easier way afaik:

    int firstLineNumber = element.Tokens.First.Value.LineNumber;
    int lastLineNumber = element.Tokens.Last.Value.LineNumber;
    int numberOfLinesInMethod = lastLineNumber – firstLineNumber + 1;
    // do whatever you want to

  • Hi georgem

    You are completely right. I don’t count the first line, so I just left away “+ 1”.

    Thanx
    Thomas

  • Is there away removing a violation or extending a rule that has already been defined.

    This is one of the many I am looking at regarding comments:

    SA1515: SingleLineCommentMustBePrecededByBlankLine

    We are merging with Japaneese code and I want programatically remove a violation.

    We have already implemeneted some our own custom rules. I can break on the violation and but can’t figure out how to remove it.

  • The defined rules can be enabled/disabled at project level (see this article: http://blogs.msdn.com/b/sourceanalysis/archive/2008/05/25/enabling-or-disabling-source-analysis-rules.aspx). Can you explain what your scenario is to programmatically remove a violation?

    As far as I know, existing rules cannot be extended. You have to create your own rule which can be derived from the (now) available source code. See announcement here: http://blogs.msdn.com/b/sourceanalysis/archive/2010/04/24/stylecop-is-going-open-source.aspx and http://stylecop.codeplex.com/

  • Essentially I want to write some some code to parse the source code of a violation. If we think this does not violate it then we want to remove the violation. We don’t want to remove a rule at a Project level as the rule/s still apply.

    Essentially its to get round some problems we have merging some code from Japan. Bascically we want to ignore any code they put in. The problem is its a shared code base. i.e. They could start // [Japan] and we could ignore it

    Looking at I think the answer is no once a violation has been generated it can not be removed. Removing them is not strictly what should happen.

    The other way would be to pre-check a violation before it is added but I can’t see away of doing this.

  • Know this posts a little out of date, thought there might be someone that could explain to me what I’ve done wrong, this is now the third guide I have found on creating custom rules for StyleCop. All of which are more or less identical in what they tell you to do. I have placed my assembly dll in the StyleCop folder, and it seems that StyleCop is using the dll, because I can not delete or move it as it is use.

    Unfortunately, it still does not show up when I open up the StyleCop settings. I’ve tried restarting visual studio, opening it through the command line as well as through Sonar and still no joy. I am using StyleCop version 4.4.0.14. Can anyone suggest what I might have done wrong? I’ve spent too long trying to get this working 🙁

    Thanks in advance!

    Rich

  • Hi Rich
    No problem about the date. I am still working on this project.
    When I understood you correctly, you just had problems with the Settings page?
    It might help, when you download and compare with my examples from http://code.google.com/p/stylecopcustomrulecleancode/.
    For the settings part it is important, that you add the properties to the definition xml file and embedd it as a resource (Build Action). For the control to display you use the following code:
    ///
    /// UserControl to display the cusomizable properties for Clean Code rules.
    ///
    public partial class CleanCodeSettings : UserControl, IPropertyControlPage

    Do you have more difficulties than just the Settings? I would love to look at your code and try to solve it.

    Cheers
    Thomas

By Thomas

Recent Posts