Writing a Custom Code Analysis Rule for Guard Classes

CA1062 does essentially check for parameter validation in public methods. That’s nice and really a good practice, but the way CA1062 implements the check enforces you to write at least one if-statement per parameter, which leads to unreadable code. A better approach are Guard-classes and of course CodeContracts in Visual Studio 2010. Unfortunately both are not recognized by CA1062.
I’ve implemented a little Code Analysis Rule to perform a check for usage of guard classes, which I will extend to cover CodeContracts, too.
First of all, to see how that works, we need to know how to implement a Code Analysis Rule at all – and how to debug it. The easy part of that is to reference FxCopSdk and Microsoft.Cci in a new Class Library project. To implement a Code Analysis Rule you will need to inherit from the abstract class BaseIntrospectionRule and override one of the Check methods.
When trying to follow these steps you will get the first problem: you will need to implement a parameter less constructor – performing “the right” actions. In my implementation I’ve created a base class with a handy one parameter constructor:

protected SemRule(string name)
    : base(
        name, // The name of the rule (must match Rules.XML)
        string.Format("{0}.Rules",
        typeof(SemRule).Assembly.GetName().Name), // The name Rules.XML
        typeof(SemRule).Assembly) // The assembly to find the Rules XML
{
}

The base class calls the BaseIntrospectionRule constructor specifying the name of the rule, the name of the embedded xml file resource to lookup the strings for the messages and the assembly to look for the xml. This xml file is another thing you need to add to your project. It defines the name and description of the rule as well as the text for the solution of the rule problem:

  <Rule TypeName="PublicMethodParametersMustBeCheckedByGuardClassMethod" Category="BestPractice.Robustnes" CheckId="SEM1001">
    <Name>PublicMethodParametersMustBeCheckedByGuardClassMethod</Name>
    <Description>All parameters of public members must be checked with a method of a guard class (that class must have the GuardClassAttribute)</Description>
    <Url></Url>
    <Resolution>The parameter {0} must be checked for a valid value.</Resolution>
    <MessageLevel Certainty="95">Warning</MessageLevel>
    <FixCategories>NonBreaking</FixCategories>
    <Email />
    <Owner />
  </Rule>

You still have to supply the “name” parameter to the constructor. This is done in a parameterless constructor of the rule implementation class:

public PublicMethodParametersMustBeCheckedByGuardClassMethod()
    : base(typeof(PublicMethodParametersMustBeCheckedByGuardClassMethod).Name)
{
}

It looks up the name from its own type. Unfortunately we cannot us the “this” keyword in this context, because the class instance has not been created at this point.
My base class also implements another AddProblem overload, so you can add a problem using only two simple parameters:

protected void AddProblem(string faultyElement, Node target)
{
    // Get the message text that is shown in the error-list.
    // Works like string.Format and inserts the given faulty element string
    // into the error text defined in the Rules.xml
    var resolution = GetResolution(faultyElement);

    // Create a new Problem with the resolution and the target node given
    var problem = new Problem(resolution, target)
    {
        Certainty = 100,
        FixCategory = FixCategories.NonBreaking,
        MessageLevel = MessageLevel.Warning,
    };

    // Add the Problem to the Problemlist
    Problems.Add(problem);
}

My business logic for the parameter check is this:

public override ProblemCollection Check(Member member)
{
    var method = member as Method;

    // only check methods, that are not abstract and do not come from the
    // framework, also don't check the guard class itself
    if (method == null
        || method.IsAbstract
        || method.DeclaringType.DeclaringModule.ContainingAssembly == FrameworkAssemblies.Mscorlib
        || IsGuardClass(method.DeclaringType))
    {
        return null;
    }

    // get all "checked" parameters
    var checkedParameters = GetCheckedParameters(method);

    // enumerate all parameters of the method
    // and test if they are in the list of checked parameters
    foreach (var parameter in method.Parameters)
    {
        var parameterName = parameter.Name.Name;
        if (checkedParameters.Contains(parameterName))
        {
            continue;
        }

        // add a problem for each non-checked parameter
        this.AddProblem(parameterName, member);
    }

    return this.Problems;
}

So first we exclude abstract, framework and guard class methods from the analysis, then we determine the checked parameters and finally we check each method parameter to be in the list of checked parameters. For each parameter we don’t have in the list, we generate a new “Problem”.
Building the list of checked parameters in GetCheckedParameters involves some code parsing. Code Analysis Rules do work with the IL code instead of the source files, so we have to deal with the IL code, too. In our case we will simply parse calls to the guard class methods – that will limit the amount of IL op-codes to parse. An interesting detail here is that non-static methods do have one parameter that you don’t see in C#: the “this”-pointer. Each non-static method does have the pointer to the current instance data of the object as the first parameter. Unfortunately FxCop does not show this parameter, so to lookup the name of the parameters, we have to subtract 1 from the parameter index determined from the IL code in case of non-static methods (in static methods the 1st parameter in IL code is the same as the first parameter in C# and FxCop). I will not show the code here, because it’s mainly a huge switch statement.
My implementation does detect Guard-Classes simply by name – you will have to name the class or its base class “GuardClass”.
Debugging Code Analysis Rules is also fun. The easiest way (IMHO) is this:

  • Make your rule project your startup project.
  • Inside the project properties under “Debug” change the Start Action to “Start external program”
  • and enter “C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Static Analysis Tools\FxCop\FxCopCmd.exe” in the textbox (you might need to adapt the path).
  • Add command options like this:
    /rule:”C:\{path to your bin folder}\{your code analysis assembly}” /file:”C:\ {path to your bin folder}\{an assembly you want to analyze}” /console
    I’m usually using “..\bin” as the build folder, so both {path to your bin folder} are the same. {an assembly you want to analyze} can be an executable or library with code that will be analyzed.
  • Set the “Working directory” to C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Static Analysis Tools\FxCop\
  • Place a breakpoint and hit F5.

This way you will start the command line version of FxCop with your rule running against some test code you have under control ({your code analysis assembly}).
To see such code in action, have a look at http://semprojectsettings.codeplex.com/. There I’ve a solution with that rule implemented (Visual Studio 2008).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Sylvio's Infobox

Aktuelle Themen rund um SQL Server, BI, Windows, ...

Meredith Lewis

Professional Digital Portfolio

Vittorio Bertocci

Just another WordPress.com weblog

ScottGu's Blog

Just another WordPress.com weblog

AJ's blog

Thoughts and informations I think worthwhile to share...

Outlawtrail - .NET Development

Architecture & Design

SDX eXperts Flurfunk

Just another WordPress.com weblog

%d bloggers like this: