Home > .NET, Software, Sourceanalysis > Custom StyleCop Rules

Custom StyleCop Rules

July 19th, 2009
Thomas

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.

 
Share with your geek friends:
  • MisterWong
  • Y!GG
  • Webnews
  • Digg
  • del.icio.us
  • StumbleUpon
  • Reddit
  • DZone

Thomas .NET, Software, Sourceanalysis

  1. Urs Enzler
    July 22nd, 2009 at 07:03 | #1

    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

  2. July 25th, 2009 at 12:24 | #2

    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

  3. georgem
    October 23rd, 2009 at 11:48 | #3

    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

  4. Thomas Weingartner
    October 23rd, 2009 at 20:30 | #4

    Hi georgem

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

    Thanx
    Thomas

  1. September 21st, 2009 at 19:25 | #1