StyleCop でカスタムスタイルを入れてみる
http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=sourceanalysis&ReleaseId=1425
ここで StyleCop と一緒に配布されてる SDK を落として解凍、、、、、はしなくていいかも知れない。
だって chm ドキュメントが1個転がってるだけだ(手順が書いてある)。
それでもAPIドキュメント付なので、あったほうが断然よい。
ちなみにここの説明がわかりやすかったのでメモ
http://www.dotnetspark.com/kb/500-c-sharp-code-reviews-using-stylecop.aspx
.NET Library プロジェクトを作成する
特に特記するものなし。普通に作ってよい。
ちなみに。.NET 3.5 で作って普通に動く。
Microsoft.StyleCop , Microsoft.StyleCop.CSharp に参照通す
StyleCop インストールディレクトリにファイルがあるはずなので参照する。
クラスを作る
論よりRunに近い何か。コメントの書き方で 3 つほど指摘されるが力尽きた。
MyCustomRules.cs
namespace CustomStyle { using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using Microsoft.StyleCop; using Microsoft.StyleCop.CSharp; /// <summary> /// サンプルのカスタムルールを作成します。 /// このカスタムルールでは、プライベート変数の命名規則として、 /// 小文字、もしくはアンダースコアを強制させます。 /// また、空のブロック要素を禁止します。 /// </summary> [SourceAnalyzer(typeof(CsParser))] public class MyCustomRules : SourceAnalyzer { /// <summary> /// オーバーライドされます。 /// StyleCop のカスタムルールでは、このメソッドがエントリポイントとなります。 /// </summary> /// <param name="document"> /// パースされたドキュメント要素を取得します。 /// ドキュメント要素は CsDocument 型で渡されます。 /// </param> public override void AnalyzeDocument(CodeDocument document) { CsDocument csharpDocument = (CsDocument)document; if (csharpDocument.RootElement != null && !csharpDocument.RootElement.Generated) { csharpDocument.WalkDocument( new CodeWalkerElementVisitor<object>(this.VisitElement), new CodeWalkerStatementVisitor<object>(this.VisitStatement), null); //// new CodeWalkerExpressionVisitor<object>(this.VisitExpression)); } } /// <summary> /// private な変数で、小文字で始まらない or _ で始まらない変数は認めません。 /// </summary> /// <param name="element"> /// ターゲットとなる要素名を指定します。 /// この要素を判定します。 /// </param> /// <param name="parentElement"> /// ターゲットとなる要素を含む要素(ここではもっぱらクラス定義のブロック)をあらわします。 /// 基本的に利用していません。 /// </param> /// <param name="context"> /// 追加パラメータとして渡されます。 /// ぶっちゃけわかりません。 /// </param> /// <returns> /// 解析を継続するかどうかを表します。 /// 継続しない場合は false を返します。 /// </returns> private bool VisitElement(CsElement element, CsElement parentElement, object context) { if (element.ElementType == ElementType.Field) { Regex reg = new Regex("^[a-z_]"); if (!reg.IsMatch(element.Declaration.Name)) { this.AddViolation(element, element.LineNumber, "PrivateNameHaveToLowerOrUnderscore"); } } return true; } /// <summary> /// メソッド以下のブロックにて、空っぽのループや分岐条件を警告します。 /// このメソッドでは、要素とは別に、ステートメントのチェックを行います。 /// </summary> /// <param name="statement"> /// 検査対象のステートメントです。 /// ブロックであるかどうか、また、子要素数を確認します。 /// </param> /// <param name="parentExpression"> /// このステートメントを含む Expression だそうですが、 /// ぶっちゃけなんのこっちゃわかりません。使ってりゃ把握するんじゃないかと。 /// </param> /// <param name="parentStatement"></param> /// <param name="parentElement"></param> /// <param name="context"></param> /// <returns></returns> private bool VisitStatement(Statement statement, Expression parentExpression, Statement parentStatement, CsElement parentElement, object context) { if (statement.StatementType == StatementType.Block && statement.ChildStatements.Count == 0) { // {} 空のブロックは禁止 this.AddViolation(parentElement, statement.LineNumber, "BlockStatementsShouldNotBeEmpty"); } return true; } } }
XML リソースを作る
このリソースは「埋め込まれたリソース」を指定すること。
MyCustomRules.xml
<?xml version="1.0" encoding="utf-8" ?> <SourceAnalyzer Name="MyCustomRules"> <Description> private name and blank block check. </Description> <Rules> <RuleGroup Name="My Policy"> <Rule Name="BlockStatementsShouldNotBeEmpty" CheckId="AZ1000"> <Context>A block statement should always contain child statements.</Context> <Description>Validates that the code does not contain any empty block statements.</Description> </Rule> <Rule Name="PrivateNameHaveToLowerOrUnderscore" CheckId="AZ1001"> <Context>Private name have to starts with lower case or underscore.</Context> <Description>Private name have to starts with lower case or underscore.</Description> </Rule> </RuleGroup> </Rules> </SourceAnalyzer>
コンパイルしてデプロイする
コンパイルして、StyleCop インストールディレクトリにポイ。
これで勝手に読み込んで動く。素敵。