読者です 読者をやめる 読者になる 読者になる

@kotyのブログ

.NETとかJavaとかPythonとか勉強会のこととかを、田舎者SEがつづります。記事のライセンスは"CC BY"でお願いします。

FxCopのカスタムルールを作ってみた

FxCopのカスタムルールの作り方をあまり目にしないので、需要があるか分かりませんが書いてみます。かなりの部分を http://cs.gogo-asp.net/blogs/libaty/articles/150.aspx を参考にさせていただきました。

某社のコーディング規約は十数ページにも渡る大作になっており、全部覚えてる人なんて誰もいません。覚えられない規約は意味がないので、機械的にチェックできるところはチェックツールにお任せして、人が覚えなきゃいけない規約をなるべく少なくしたいところです。
Visual Studio はPremiumエディション以上でコード分析機能が同梱されており、コーディング規約のチェックが可能です。チェックのコア部分はFxCopが使われています。なのでPremium未満でもFxCop単体で使えば同様のチェックが可能です。

多くの規約については、FxCopに標準で付属しているルールについて適用・非適用を選択すれば良いのですが、独自の規約を作りたいことがあります。使ってほしくない.NET Frameworkのクラスがある、とかですね。そういったときにカスタムルールを作ることになります。

このカスタムルールの作成方法をあまり目にしないので、簡単に説明してみようと思います。今回はVB.NETのNow関数およびDateTime.Nowプロパティを使っていないかチェックする規約を作ってみました。今回説明したソリューションは、こちらからダウンロードできます。

windows 7 sdkのインストール

まず、windows 7 SDKをダウンロードしてインストールします。何の関係があるの?と思いますが、この中にFxCopおよびFxCopsdkが入っています。

FxCopのインストール

window 7 sdkをインストールするだけではFxCopは入りません。 【c:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\FXCop\FxCopSetup.exe】を起動してインストールします。

プロジェクトの作成と参照設定

次に規約を記述するプロジェクトを作ります。普通のクラスライブラリのプロジェクトを新規に作成します。
プロジェクトを作成したら、【C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\FxCopSdk.dll】を参照設定します。

規約チェックロジックの作成

規約チェックロジックをソースコードに記述します。BaseIntrospectionRuleなるクラスを継承して作ります。FxCopはdllに対してのチェックになるので、IL上のメンバ名でチェックする必要があります。したがってVB.NETのNow関数については、【Microsoft.VisualBasic.DateAndTime.get_Now】をチェックします。チェックしたいメンバがIL上でどうなっているかはReflectorとかで確認すると良いでしょう。
ShouldNotUseNowFunction.cs

using Microsoft.FxCop.Sdk;

namespace MyCompany.MySystem.FxCopRules
{
    public class ShouldNotUseNowFunction : BaseIntrospectionRule
    {
        public ShouldNotUseNowFunction()
            : base("ShouldNotUseNowFunction",
                "MyCompany.MySystem.FxCopRules.Rules",
                typeof(ShouldNotUseNowFunction).Assembly)
        {}

        public override ProblemCollection Check(Member member)
        {
            if (member is Method)
            {
                Visit(member as Method);
            }
            return Problems;
        }

        public override void VisitMethodCall(MethodCall call)
        {
            MemberBinding mb = call.Callee as MemberBinding;
            if (mb.BoundMember.FullName == "Microsoft.VisualBasic.DateAndTime.get_Now")
            {
                Problems.Add(new Problem(GetResolution()));
            }
            base.VisitMethodCall(call);
        }
    }
}
ルール xmlの作成

規約違反検出時に出すメッセージを記述するxmlを追加します。ビルドアクションプロパティは、【埋め込まれたリソース】に設定します。ここでエラー扱いか警告扱いかも指定できるようです。

Rules.xml

 <?xml version="1.0" encoding="utf-8" ?>
<Rules FriendlyName="MySystem コード解析ルール">
  <Rule TypeName="ShouldNotUseDateTimeNow" Category="MyCompany.MySystem.FxCopRules" CheckId="MyRule0010">
    <Name>DateTime.Nowの使用禁止</Name>
    <Description>DateTime.Nowを使ってはいけません。</Description>
    <Owner>基盤グループ</Owner>
    <Url>http://MyCompany/MySystem/</Url>
    <Resolution>XXDateTime(DateTimeのラッパ)を使ってください。</Resolution>
    <Email>hoge@ponyo.pou</Email>
    <MessageLevel Certainty="95">Warning</MessageLevel>
    <FixCategories>NonBreaking</FixCategories>
  </Rule>
  <Rule TypeName="ShouldNotUseNowFunction" Category="MyCompany.MySystem.FxCopRules" CheckId="MyRule0020">
    <Name>Now関数の使用禁止</Name>
    <Description>Now関数を使ってはいけません。</Description>
    <Owner>基盤グループ</Owner>
    <Url>http://MyCompany/MySystem/</Url>
    <Resolution>XXDateTime(DateTimeのラッパ)を使ってください。</Resolution>
    <Email>hoge@ponyo.pou</Email>
    <MessageLevel Certainty="95">Warning</MessageLevel>
    <FixCategories>NonBreaking</FixCategories>
  </Rule>
</Rules>
ルールのデバッグ

デバッグは、FxCopを単体で起動してVisual Studiofxcop.exeにアタッチ後に実際にコードチェックを走らせて行います。

ルールのデプロイ

コンパイルしたdllを【C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\Rules\】にコピーします。(FxCop単体で使いたい場合は、FxCopの画面でルールの追加⇒コンパイルしたdllを選択 します。)

動作確認

うまくいっていれば、Visual Studioのルールセットの画面に出てきます。

ここに出てこないときは何かおかしいです。自分がはまったのはRule xmlのCategory属性の名前と、ソースコードに記述するnamespace、コンストラクタに渡す文字列の3か所を合わせないといけない、という点でした。

というわけで、かなりおおざっぱな説明ですが、FxCopのカスタムルールの作り方について書きました。こういったエンタープライズ開発(っていうんですかね?)関係のノウハウって社内に収まっていてなかなかインタネットに出てきません。もっと目にするようになってほしいものです。