C#ソースコードの分析ツールでカスタムルールを作成する


http://d.hatena.ne.jp/m-tanaka/20080528
の続き。


デフォルトのルールだけではなく、プロジェクトのコーディング規約にあわせてカスタマイズできると便利だな
と思っていたら、早速カスタムルールの作り方を解説している人がいました。


Part I: Creating Custom Rules for Microsoft Source Analyzer
http://lovethedot.blogspot.com/2008/05/creating-custom-rules-for-microsoft.html


Source Analyzer uses Reflection to examine every DLL in its install directory to find custom rules, so all we'll need to do is create a class library with the right classes and attributes and Source Analyzer will automatically load our new rules.

Create a new ClassLibrary project, then add references to the Microsoft.SourceAnalysis and Microsoft.SourceAnalysis.CSharp assemblies:

Source Analyzerは、リフレクション機構によってインストールディレクトリ内のDLLを走査してカスタムルールをさがします。
ですので、正しいクラスと属性を含んだクラスライブラリを作成するだけでSource Analyzerにカスタムルールを読み込ませることができます。
クラスライブラリプロジェクトを作成し、Microsoft.SourceAnalysisとMicrosoft.SourceAnalysis.CSharpへのアセンブリ参照を追加します。



Then add a new class and an XML file with the same name. Set the Properties of the XML file to be an Embedded Resource and not copy to the output directory:

次に新しいクラスと、クラスと同名のXMLファイルを作成します。XMLファイルのプロパティで、「埋め込まれたリソース」と「出力ディレクトリにコピーしない」を設定します。


Part II: Creating Custom Rules for Microsoft Source Analyzer
http://lovethedot.blogspot.com/2008/05/creating-custom-rules-for-microsoft_27.html

<?xml version="1.0" encoding="utf-8" ?>
<SourceAnalyzer Name="Custom Rules">  
  <Description>    Custom rules added to analyzer.  </Description>  
  <Rules>    
    <RuleGroup Name="Custom Rules Group">      
      <Rule Name="MyCustomRule" CheckId="CR0001">        
        <Context>This is a custom rule.</Context>        
        <Description>This is a custom rule description.</Description>      
      </Rule>    
    </RuleGroup>  
  </Rules>
</SourceAnalyzer>


when loaded into settings by the Source Analyzer. The SourceAnalzyer element's Name attribute becomes a node under C#; each RuleGroup becomes a node under that; and each Rule is contained in its RuleGroup.

The CheckID attribute of a Rule must consist of two capital letters and four digits.

The Context element of a Rule is what displays in Visual Studio analysis results and can contain {0} string formatting placeholders (which we'll see in Part III).

The Description element of a Rule is what displays to the user in Source Analysis Settings when they're choosing which Rules to enforce.

Source Analyzerの設定画面に読み込まれると、SourceAnalyzer要素のName属性がC#の下位ノードとなります。
その下位ノードとしてRuleGroup要素が表示され、個々のRuleはRuleGroupに含まれます。
Rule要素のChekID属性は、2文字の英大文字 + 4桁の数値となっている必要があります。
Rule要素中のContext要素は、Visual Studioの分析結果に表示される文言です。書式制御用のプレースホルダとして{0}を含めることができます。
Rule要素中のDescription要素は、Source Analysisの設定画面でユーザが適用するルールを選択する際に表示される文言です。

namespace SourceAnalyzerSample
{
    using System;
    using System.Collections.Generic;   
    using System.Linq;   
    using System.Text;    
    using Microsoft.SourceAnalysis;    
    using Microsoft.SourceAnalysis.CSharp;    
    using System.Windows.Forms;    
    
    [SourceAnalyzer(typeof(CsParser))]    
    public class SampleAddInRules : SourceAnalyzer    
    {        
        public override void AnalyzeDocument(CodeDocument document)        
        {            
            Param.RequireNotNull(document, "document");            
            CsDocument document2 = (CsDocument)document;            
            if ((document2.RootElement != null) && !document2.RootElement.Generated)            
            {                
                AddViolation(document2.RootElement, "MyCustomRule", new object[0]);
            }        
        }    
    }
}


First, we need the references and using directives for Microsoft.SourceAnalysis and Microsoft.SourceAnalysis.CSharp.

Then we create a class inherited from SourceAnalyzer and add a SourceAnalyzer attribute on the class, giving it a parameter of typeof(CsParser). StyleCop uses Reflection to find classes inherited from SourceAnalyzer to add to its rules. The CsParser type tells StyleCop that this class analyzes C# source files.

まず、Microsoft.SourceAnalysisとMicrosoft.SourceAnalysis.CSharpへの参照とusing句を追加します。
次に、SourceAnalyzerクラスを継承したクラスを作成し、typeof(CsParser)をパラメータとして設定したSourceAnalyzer属性を設定します。
StyleCopはSourceAnalyzerを継承したクラスをリフレクションで探し、ルールに加えます。CsParser型は、StyleCopにこのクラスがC#ソースファイルを分析することを通知します。


We next need to override the AnalyzeDocument method from the SourceAnalyzer base-class. This is the entry point StyleCop will use to run our rule and pass it each source file in the project. Each source file is passed in as a parameter of type CodeDocument.

次に、SourceAnalyzerのAnalyzeDocumentをオーバーライドします。これはStyleCopがルールを実行するときのエントリポイントで、プロジェクト内の各ソースコードが渡されます。各ソースコードはCodeDocument型のパラメータとして渡されます。


As part of the Microsoft.SourceAnalysis assembly, they've included a Param class that has a number of methods on it to validate parameters passed to methods. We use this to require that the CodeDocument parameter passed isn't null

Microsoft.SourceAnalysisアセンブリのなかには、メソッドに渡されたパラメータを検証するためのメソッドと多数持っているParamクラスが含まれています。今回はこのParamクラスを利用して、パラメータのCodeDocumentがnullでないことを確認しています。


The next step is to check some things on the document. In this case, we're checking to ensure that the document has a RootElement and that it isn't generated-code. The source code is treated a hierarchy of elements containing other elements, which we'll see more of in Part III.

次に、ドキュメントを検証します。今回の例では、自動生成ではないドキュメントがRootElementを持っていることを検証します。
ソースコードは、エレメントが他のエレメントを含んでいるという階層構造として扱われます。(詳しくはPartIIIで)


Finally, we're going to create the violation. The AddViolation method has a number of overloads:
In general, the method takes:
The CodeElement that violated the rule;
An Enum or String identifying the Rule that's been violated;
An array of Objects -- this array is used to fill {0} placeholders in a formatted string;

最後に、AddViolationメソッドで違反を作成します。AddViolationメソッドにはいくつかのオーバーロードがあります。
AddViolationめそっどは、
・ルール違反となったCodeElement
・違反したルールを特定するためのEnumまたはString
・オブジェクトの配列(プレースホルダの{0}を埋めるために使用されます)


PartIIIは長いのでオリジナルを参照してください