Custom StyleCop Rules – Part II

In my first post (link) I’ve explained what StyleCop is and how you can start with your own StyleCop rules. We will now dig a little bit deeper into the jungle of StyleCop….

StyleCop’s Code Model

After some reverse engineering of StyleCop’s Code Model, I thought it is not worth to try finding out what the meaning of all the classes is. I’ll just show you, how I exploratively found solutions for the things I wanted to check in the source code.

Just a few things: The Document is one file of C# code. If you walk through the Document using AnalyzeDocument and after that you use StyleCop’s WalkDocument callback mechanism for example to find out which Expression is a magic number, you will see some items twice. Maybe you’re confused now; just try out the source code mentioned at the end of this article.

Custom Rules Made Easy

It’s pretty annoying writing a whole SourceAnalyzer class every time you want to add a new rule. So I’ve created a generic mechanism where you just have to chose the type of item you want to inspect and the write the rule against it. You can try and write a dummy rule for each item to find out, what will be provided by each type of item.

The different items are

  • Tokens
  • Elements
  • Expressions

Additionally you can decide which type of CsTokens (e.g. Attribute, Return, UsingDirective, …), Elements (e.g. Methods, Fields, Struct, …) or Expressions (e.g. Arithmetic, Lambda, Logical, Typeof, …) you like to inspect.

Test Driven Development TDD

It is one of my favorite to develop in TDD and I think it changed the whole thinking about development. To make that possible, you have to use StyleCop’s CodeProject class and the StyleCopConsole class and then some Code that violates your rules. The latter is easy, but the first one gave me some miracles until I solved it.

First of all, create a new CodeProject:

  var configuration = new Configuration(new string[0]);
  CodeProject = new CodeProject(Guid.NewGuid().GetHashCode(), null, configuration);

Then you can add your violating source code to the CodeProject instance:

public void AddSourceCode(string fileName)
{
fileName = Path.GetFullPath(fileName);
bool result = this.StyleCopConsole.Core.Environment.AddSourceCode(CodeProject, fileName, null);
if (result == false)
{
throw new ArgumentException("Source file could not be loaded.", fileName);
}
}

To start the analysis use the following code:

public void StartAnalysis()
{
var projects = new[] { CodeProject };
bool result = this.StyleCopConsole.Start(projects, true);
if (result == false)
{
throw new ArgumentException("StyleCopConsole.Start had a problem.");
}
}

I’ve put all the code above in an abstract base class and for the rules I’ve set up a new test class using Visual Studio’s integrated test runner:

namespace CleanCode.StyleCopCustomRules.UnitTests
{
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class CleanCodeTests : AbstractSourceAnalysisTest
{
[TestMethod]
public void TooManyParameters()
{
AnalyzeCodeWithOneAssertion("TooManyParameters.cs");
}

...

private void AnalyzeCodeWithOneAssertion(string codeFileName)
{
const int ExpectedViolations = 1;
this.AnalyzeCodeWithAssertion(codeFileName, ExpectedViolations);
}

private void AnalyzeCodeWithAssertion(string codeFileName, int expectedViolations)
{
AddSourceCode(codeFileName);
StartAnalysis();
WriteViolationsToConsole();
WriteOutputToConsole();
Assert.AreEqual(expectedViolations, StyleCopViolations.Count);
}

private void WriteOutputToConsole()
{
Console.WriteLine(string.Join(Environment.NewLine, StyleCopOutput.ToArray()));
}

private void WriteViolationsToConsole()
{
foreach (var violation in StyleCopViolations)
{
Console.WriteLine(violation.Message);
}
}
}
}

You would probably ask why I’ve used the Visual Studio test runner and not NUnit or xUnit. The reason is, that I haven’t found a way to copy the source code files that violates the rules to the directory where NUnit could find them. In VS.Net I could use the LocalTestRun.testrunconfig and say that the Resources folder should be deployed where the test is running. I’m curious if you find a solution with NUnit or xUnit.

Putting All Together

Clean Code CoverSo far I’ve implemented some rules from the book “Clean Code” written by Robert C. “Uncle Bob” Martin which can be found here or at amazon. I was astonished and excited about the contents of the book. This was exactly what I was looking for years. Now I know what was wrong with our code walk-through’s and reviews. We had no idea what we were looking for!

The code is available on googlecode here. You should be able to use it after checking out from the subversion repository. Otherwise let me know…

Have fun
Thomas

About the author

6 comments

  • Hi Thomas,
    Recently I am investigating whether StyleCop can help us in our project. I’ve seen many articles but yours really appeals to me because of the generic mechanism you’ve created. And I very much like to unit-test the rules I’m about to make. However, when I run the unit tests from your source code (StyleCopContrib4.3.zip), some unit tests fail. This is because the StyleCopConsole never seems to generate a violation. The Output is always “No violations occurred”. Do you have any idea what I’m doing wrong? (VS2008, Win7 Pro 64bit)

  • Hi. I’m having problems running your code. The AddSourceCode method always fails when running the unit tests. More specifically the line in AbstractSourceAnalysisTest.cs always returns false:

    this.StyleCopConsole.Core.Environment.AddSourceCode…

    I’ve checked that the file exists in the expected location so I’ve no clue why this method returns false. Do you have any ideas?

    Thanks
    Phil

  • @Phil Hale
    Hi Phil

    The code in this post is very old (2009).
    I’ll relay your comment to the original author of the post, maybe he can answer your question.

    Sorry for not being much of help
    Urs

  • @Phil Hale
    Hi Phil

    I have updated the code on googlecode for StyleCop 4.7.8; just use the Branch StyleCop 4.7.

    If you are running Windows 7, you might try to run VS2010 in Administrator mode.

    Cheers
    Thomas

By Thomas

Recent Posts