RoslynのCode Analyzerを作ってみるメモ

Visual Studio 2015ではAnalyzeなるものを自作して独自のエラーや警告を出せます。Metro.cs #1でそんな話をしていたので試してみた。

参考資料

VS2015のRoslynでCode Analyzerを自作する(ついでにUnityコードも解析する)
新しいコンパイラー“Roslyn”を用いたプログラミングを体験!
Roslyn を使用した API 向けライブ コード アナライザーの作成
Roslyn アナライザーへのコード修正の追加
Working with Types in Your Analyzer

必要な情報探すのにかなり時間かかった。検索するとほとんど英語で出てきて大変。上4つは貴重な日本語情報でまとまっているので読むべき。

準備

Visual Studio 2015をインストールする。このとき共通ツールのVisual Studio拡張性ツールもインストール。
それと.NET Compiler Platform SDKもインストールする。

プロジェクトを作る

メニューの ファイル>新規作成>プロジェクト を開いて Visual C#>Extensibility>Analyzer with Code Fix を選んで新規作成する。
そうすると説明書(ReadMe.txt)とサンプル(DiagnosticAnalyzer.cs, CodeFixProvicer.cs)が入ったプロジェクトが自動作成される。

コードを書く

DiagnositcAnalyzer.csで問題箇所を見つけてエラーや警告を出す。CodeFixProvider.csではその修正案を作る。
詳しくは参考資料を参照。Syntax Visualizerとデバッグ実行のウォッチ式などを見ながら気合いで何とかするのがデフォっぽい。
今日は調べるだけで力尽きたので、とりあえず非ジェネリックのIEnumearbleを見つけたら警告を出すAnalyzerを書いた。

using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

namespace ForbidIEnumerable
{
    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    public class ForbidIEnumerableAnalyzer : DiagnosticAnalyzer
    {
        public const string DiagnosticId = "ForbidIEnumerable";

        private static readonly LocalizableString Title = "Forbit to use IEnumerable";
        private static readonly LocalizableString MessageFormat = "IEnumerable is forbidden. Please use IEnumerable<T>.";
        private static readonly LocalizableString Description = "IEnumerable error {0}";
        private const string Category = "Prohibition";

        private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);

        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
        { get { return ImmutableArray.Create(Rule); } }

        public override void Initialize(AnalysisContext context)
        {
            context.RegisterSyntaxNodeAction(syntaxContext =>
            {
                var declarationSyntax = (VariableDeclarationSyntax)syntaxContext.Node;
                var typeInfo = syntaxContext.SemanticModel.GetTypeInfo(declarationSyntax.Type);
                if (typeInfo.ConvertedType.SpecialType == SpecialType.System_Collections_IEnumerable) {
                    syntaxContext.ReportDiagnostic(Diagnostic.Create(Rule, syntaxContext.Node.GetLocation()));
                }
            }, SyntaxKind.VariableDeclaration);
        }
    }
}

実行してみる

デバッグ実行するとアナライザを読み込んだVisualStudioが起動されるのでそれでテストできる。
完成したものを実際に使うには組み込むプロジェクトの「参照」を右クリックして「アナライザーの追加」からビルドされたdllを読み込む。

roslyn-code-analyzer
実行してみたところ。警告が出て何か変なことを教えてくれる。なぜか警告メッセージが二重で出ているが原因は不明。