How to add a custom rule to VSTS Code Analysis
The code analysis feature that ships with Visual Studio Team System (VSTS), FxCop, comes with a rich API to write custom rules. Since the API almost lacks of documentation, I've been struggling for a while before I got my custom rules to work. That's why I've decided to write this short guide on how to make your own rules: (It is required that you have the VSTS version of Visual Studio 2005 intalled)
- Create a new class library project.
- Add references to the Microsoft.cci.dll and FxCopSdk.dll assemblies (typically installed in C:\Program Files\Microsoft Visual Studio 8\Team Tools\Static Analysis Tools\FxCop).
- Create your custom rule class and make it derive from BaseIntrospectionRule.
- Make the constructor of your class call its base constructor, which has three parameters: the rule's name, the name of the rule descriptor file (see step 4), and the assembly that contains the rule. Note that, if your project will consist on more than a single rule, it is convenient to write your own base class for all the rules not to repeat code.
- I took as example the base class of the FxCop design rules:
using System;
using Microsoft.Cci;
using Microsoft.FxCop.Sdk;
using Microsoft.FxCop.Sdk.Introspection;
namespace Microsoft.FxCop.Rules.Design{
internal abstract class DesignIntrospectionRule
: BaseIntrospectionRule {
protected DesignIntrospectionRule(string name)
: base(name,
"Microsoft.FxCop.Rules.Design.DesignRules",
typeof(DesignIntrospectionRule).Assembly) {
}
public override void AfterAnalysis(){
DesignRuleUtilities.Clear();
}
}
} - Override one of the Check methods to implement your custom rule's logic. Here's a snippet of one of the design rules that overrides the Check(TypeNode) method. Other Check overloads are available, for checking members, types, modules, etc. If it happends that the target being analyzed does not match the rule's condition, a new Problem is added to the Problems collection, and this collection is returned by the check method. The GetResolution method allows you to fetch a resolution from the rules xml file.
internal sealed class AbstractTypesShouldNotHaveConstructors
: DesignIntrospectionRule {
public AbstractTypesShouldNotHaveConstructors()
: base("AbstractTypesShouldNotHaveConstructors") {
}
public override ProblemCollection Check(TypeNode type) {
if (!type.IsAbstract) {
return null;
}
for (int num1 = 0; num1 < type.Members.Length; num1++) {
InstanceInitializer initializer1 = type.Members[num1]
as InstanceInitializer;
if ((initializer1 != null) && initializer1.IsPublic) {
Resolution resolution1 = base.GetResolution(new string[]
{ type.Name.Name });
Problem problem1 = new Problem(resolution1);
base.Problems.Add(problem1);
break;
}
}
return base.Problems;
}
...
} - Eventually override the BeforeAnalysis or AfterAnalysis methods if you need to execute something before or after the analysis process takes place respectivelly.
- Add the rules .xml descriptor file to the project as an embedded resource, with the not copy to the target directory option set. The file's name (including it's namespace, and without the extension) must match the second parameter of the BaseIntrospectionRule constructor. It seems that there's no schema available for the xml, but here's a portion of the DesignRules descriptor:
<Rules FriendlyName="Design Rules">
...
<Rule TypeName="AbstractTypesShouldNotHaveConstructors"
Category="Microsoft.Design"
CheckId="CA1012">
<Name>Abstract types should not have constructors</Name>
<Description>Public constructors for abstract types do
not make sense because you cannot create instances of
abstract types.</Description>
<Url>/Design/AbstractTypesShouldNotHaveConstructors.html</Url>
<Resolution>Change the accessibility of all public constructors
in '{0}' to protected.</Resolution>
<Email>
</Email>
<MessageLevel Certainty="95">CriticalWarning</MessageLevel>
<FixCategories>NonBreaking</FixCategories>
<Owner />
</Rule>
...
</Rules> - Integrate the custom rules with visual studio's code analysis
- In order to register your rules with VS, you just need to copy the assembly containing your rules to the rules directory (c:\Program Files\Microsoft Visual Studio 8\Team Tools\Static Analysis Tools\FxCop\Rules).
- All the rules contained in the assembly will be enabled by default.
- You can now simply run the code analysis over a project to evaluate it with your own rules.