Slide 1

Slide 1 text

KanColleViewer PluginAnalyzerの実装 2015/09/16 Metro.cs #1 @veigr

Slide 2

Slide 2 text

Self Introduction ゔぇい Work 小さな独立系 SIer (C# + WPF + ASP .NET WebAPI とか) Private 提督業も忙しい! (KanColleViewer) 開発メンバー (Plugin Analyzer / Network 等) 同プラグイン開発 Nekoxy (艦これ向け HTTP プロキシライブラリ) 開発 Twitter: @veigr Blog: http://www.cat-ears.net

Slide 3

Slide 3 text

Agenda 作ったもの KanColleViewer.PluginAnalyzer Analyzer の作成準備と概要 Analyzer with Code Fix Analyzer 実例 ExportMetadataAnalyzer の実装

Slide 4

Slide 4 text

KanColleViewer.PluginAnalyzer 作ったもの

Slide 5

Slide 5 text

KanColleViewer.PluginAnalyzer プラグイン開発支援用 Roslyn Analyzer RC 時代に勉強 1 週間+コーディング 3 日位で作ったやつ Roslyn とか殆ど無知だった

Slide 6

Slide 6 text

KanColleViewer.PluginAnalyzer プラグイン開発支援用 Roslyn Analyzer 目的: プラグイン開発特有の実装ルールを守らせる • 実装しなければならない Interface • Interface に対応した ExportAttribute の実装 • 本体が要求する Metadata の実装 ソース: https://github.com/Grabacr07/KanColleViewer/tree/develop/source/Analyzers

Slide 7

Slide 7 text

Analyzer with Code Fix Analyzerの 作成準備と概要

Slide 8

Slide 8 text

SDKインストール 新しいプロジェクト > Extensibility > Download the .NET Compiler Platform SDK インストール

Slide 9

Slide 9 text

プロジェクト作成 新しいプロジェクト > Extensibility > Analyzer with Code Fix (NuGet + VSIX)

Slide 10

Slide 10 text

ソリューション構成 Analyzer 本体 Analyzer.Test テスト用プロジェクト Analyzer.Vsix VS 拡張機能 作成用プロジェクト サンプルコード入り

Slide 11

Slide 11 text

プロジェクト構成 (本体) DiagnosticAnalyzer.cs 解析するやつ CodeFixProvider.cs コード修正するやつ tools フォルダ NuGet パッケージ用 PowerShell スクリプト

Slide 12

Slide 12 text

Analyzer with Code Fix とは 要するに 解析 (Analyze) & 修正 (CodeFix)

Slide 13

Slide 13 text

Analyzer with Code Fix の例 DiagnosticAnalyzer で SyntaxTree を解析 CodeFixProvider で SyntaxTree を修正 足りてない! 追加!

Slide 14

Slide 14 text

Analyzer with Code Fix の例 DiagnosticAnalyzer で SyntaxTree を解析 CodeFixProvider で SyntaxTree を修正 これは一体……?

Slide 15

Slide 15 text

Syntax Visualizer ソースコードの Syntax Tree (構文木)を表示してくれる • Analyzer 作るなら必携 • SDK と一緒にインストール される

Slide 16

Slide 16 text

参考になるやつ Roslyn Overview · dotnet/roslyn Wiki https://github.com/dotnet/roslyn/wiki/Roslyn%20Overview Samples and Walkthroughs · dotnet/roslyn Wiki https://github.com/dotnet/roslyn/wiki/Samples-and-Walkthroughs neuecc さんとか岩永さんとかの Blog や成果物 色々あるのでググろう

Slide 17

Slide 17 text

Analyzer のインストール方法 作ったAnaylzerの利用

Slide 18

Slide 18 text

作った Anaylzer の利用 Analyzer インストール方法 • DLL を参照追加してインストール • NuGet パッケージにしてインストール • VSIX にしてインストール ※プロジェクト参照はできないっぽい ※Analyzer が依存している外部アセンブリがあるとちょっと面倒

Slide 19

Slide 19 text

ExportMetadataAnalyzer の実装 Analyzer 実例

Slide 20

Slide 20 text

作りたいもの プラグイン一覧に表示するための情報は ExportMetadata 属性で指定している

Slide 21

Slide 21 text

作りたいもの 不足している ExportMetadata 属性があったら補完したい

Slide 22

Slide 22 text

作りたいもの 解析: 不足している ExportMetadata 属性を検出 修正: 検出した不足属性を追加 で行けそうな気がする……

Slide 23

Slide 23 text

まずはコード解析 DiagnosticsAnalyzer

Slide 24

Slide 24 text

DiagnosticsAnalyzer 解析したいこと クラスに足りてない ExportMetadata 属性を探したい →クラス情報の取得と、その属性の 解析ができればいい気がする

Slide 25

Slide 25 text

DiagnosticsAnalyzer 基本的な解析の流れ 1. 渡された AnalysisContext に解析の起点となる Action を登録 2. その Action 内で解析し、結果を Report する

Slide 26

Slide 26 text

DiagnosticsAnalyzer Action の登録 AnalysisContext のどの Register~Action()を使うべきか…… 何が何やらさっぱりわからない問題 (今でもよく分かってない)

Slide 27

Slide 27 text

DiagnosticsAnalyzer AnalysisContext のどの Register~Action()を使うべきか…… RegisterSyntaxNodeAction 単一ファイルを解析する場合はこれで大体何とかなるっぽい RegisterCompilationAction プロジェクト全体を解析したい場合とかに使えるっぽい RegisterSymbolAction 特定の型とか変数とかを処理したい時に使えるっぽい 今回はこれでいけそう

Slide 28

Slide 28 text

DiagnosticsAnalyzer Syntax をどう解析するか…… RegisterSyntaxNodeAction() で SyntaxKind.ClassDeclaration を指定すれば、受け取った Context から ClassDeclarationSyntax (クラスの情報)が取得できる クラスの情報

Slide 29

Slide 29 text

DiagnosticsAnalyzer クラス情報から属性の情報が欲しい…… ClassDeclarationSyntax の GetAttributes で属性が取れそう IntelliSense とデバッグ実行で頑張って調べる

Slide 30

Slide 30 text

属性の情報から引数の内容が欲しい…… AttributeSyntax の ArgumentList.Arguments で属性の引数が取れそう DiagnosticsAnalyzer

Slide 31

Slide 31 text

DiagnosticsAnalyzer 属性の情報から引数の内容が欲しい…… AttributeSyntax の ArgumentList.Arguments で属性の引数が取れそう 大体これの繰り返し…… 続きは WEB (GitHub) で

Slide 32

Slide 32 text

解析結果をどう Report するか…… ReportDiagnostic() でエラーが有ることを通知 DiagnosticDescriptor IDとかカテゴリとかエラーレベルとかメッセージとか Location エラーを出す場所 DiagnosticsAnalyzer ReportDiagnostic() を 呼ばなければ何も起きない

Slide 33

Slide 33 text

DiagnosticsAnalyzer 何を ReportDiagnostic するか…… DiagnosticDescriptor の内容 DiagnosticId : 「エラー一覧」の「コード」とかに出てくるID ExportMetadataMessageFormat : リソースファイルでお好きなメッセージをどうぞ Category : Analyzer の一覧のグループ化あたりで使う名前 DiagnosticSeverity : エラーレベル / Error のが残っているとコンパイルできなくなる

Slide 34

Slide 34 text

修正対象を解析したらコード修正 CodeFixProvider

Slide 35

Slide 35 text

CodeFixProvider 修正したいこと クラスに足りてない ExportMetadata 属性を足したい

Slide 36

Slide 36 text

CodeFixProvider 修正の流れ 1. 受け取った CodeFixContext から解析結果を受け取る 2. コード修正を行う CodeAction を修正候補として登録

Slide 37

Slide 37 text

CodeFixProvider どう解析結果を受け取るか…… • CodeFixContext からはエラーの位置くらいしかもらえない • だがその位置から問題のある ClassDeclaration は探せる • 解析の時は ClassDeclaration を使って不足属性を検出した • なら解析の時と同じことをもう一度やればいい!

Slide 38

Slide 38 text

CodeFixProvider どう解析結果を受け取るか…… 解析を RegisterSyntaxNodeAction() でやっていれば、 同じロジックで再び ClassDeclaration を解析するだけ

Slide 39

Slide 39 text

CodeFixProvider どうコード修正するか…… 1. Task を返すメソッドを作る 2. それを元にタイトル等を付加した CodeAction 生成 3. 生成した CodeAction を、修正候補として CodeFixContext に登録 ここがキモ

Slide 40

Slide 40 text

CodeFixProvider Task の作り方 1. 元 Document (ソースコード)を CodeFixContext から取得 2. SyntaxFactory で新たな SyntaxTree を構築 3. 構築した SyntaxTree で問題の箇所を置換 4. 置換した Document を返す

Slide 41

Slide 41 text

CodeFixProvider Task の作り方 1. 元 Document (ソースコード)を CodeFixContext から取得

Slide 42

Slide 42 text

CodeFixProvider Task の作り方 2. SyntaxFactory で新たな SyntaxTree を構築 ※あらゆる Syntax は immutable なので、常に新たなインスタンスを生成するようなコードにしな ければならない点に注意

Slide 43

Slide 43 text

CodeFixProvider Task の作り方 3. 構築した SyntaxTree で問題の箇所を置換

Slide 44

Slide 44 text

CodeFixProvider Task の作り方 4. 置換した Document を返す

Slide 45

Slide 45 text

CodeFixProvider Task の作り方 まとめるとこう

Slide 46

Slide 46 text

出来上がったもの

Slide 47

Slide 47 text

まとめ

Slide 48

Slide 48 text

まとめ • DiagnosticAnalyzer でコード解析 • CodeFixProvider でコード修正 • 無勉強状態からでも1~2週間くらいあればなんとか作れる • より良い実装方法などは色々あるハズ

Slide 49

Slide 49 text

おわりに • 完璧にしようとするとしんどい • 細かいところで結構ハマる • ググってもあまり情報が出てこない • とりあえずデバッグ実行して片っ端から試すのが良さげ EOF