パソナについて
記事検索

Roslyn AnalyzerでUnityコードをチェックする話

現在私が参加しているUnityプロジェクトでは、UniRxを使ってリアクティブプログラミングな実装を行っています。
この時、`Subscribe`のあとに`AddTo`をチェインすることや、非同期型でvoidは使わずUniTaskVoidを使うことなど、いくつかのお作法が決められています。
ただ書き忘れ、PRレビューで指摘されることもしばしば…。🫠
こういった「うっかり」を防ぐために何かツールはないかと探していたところ、**Roslyn Analyzer**という静的解析ツールがあることを知りました。
Roslyn Analyzerを用いた解析の書き方については何本も先行記事がありますが、そちらであまり見られなかった内容を中心に、Roslyn Analyzerの作り方からUnityへの導入まで、ざっくり紹介できればとおもいます🙇‍♂️

Roslyn AnalyzerでUnityコードをチェックする話

現在私が参加しているUnityプロジェクトでは、UniRxを使ってリアクティブプログラミングな実装を行っています。
この時、`Subscribe`のあとに`AddTo`をチェインすることや、非同期型でvoidは使わずUniTaskVoidを使うことなど、いくつかのお作法が決められています。
ただ書き忘れ、PRレビューで指摘されることもしばしば…。🫠
こういった「うっかり」を防ぐために何かツールはないかと探していたところ、**Roslyn Analyzer**という静的解析ツールがあることを知りました。
Roslyn Analyzerを用いた解析の書き方については何本も先行記事がありますが、そちらであまり見られなかった内容を中心に、Roslyn Analyzerの作り方からUnityへの導入まで、ざっくり紹介できればとおもいます🙇‍♂️

知識・情報

2025/07/18 UP

まずは解析ツールを作ってみる

以降の内容はすべてVisual Studio 2019 での内容となります! Visual Studio 2022 でもほぼ同様で実装できるはずです

プロジェクトの作成

「Analyzer with Code Fix (.NET Standard)」というテンプレートを選ぶことで、解析用のプロジェクトが作成されます。

ただし、Visual Studio Extension developmentが導入されていないとテンプレートが見つからないため、VisualStudioInstallerにて追加インストールが必要になります。
|||
|:--|:--|
imageimage-1

プロジェクト構成

ソリューション名は CustomUnityAnalyzer にしました。
中にいくつかプロジェクトがありますが、利用するのは下記2つとなります。

1. CustomUnityAnalyzer: 実際の解析ロジックを書くところ
2. CustomUnityAnalyzer.Vsix: デバッグ用。解析がちゃんと動くか確認するためのプロジェクト

デバッグのやり方

別のプロジェクトを解析対象にして、ルールがちゃんと動いてるか確認できます。
CustomUnityAnalyzer.Vsix を起動すると、Visual Studioがもう1個立ち上がるので、そこで解析対象のプロジェクトを選びます。

image-7

トラブルシューティング:BreakPointが効かない? その1

Visual Studioの設定によっては、ブレークポイントが効かないことがあります。
以下の設定を見直してください。👁️👁️

- VS2022
    - Text Editor > C# > Advanced より、 Run code analysis in separate process を無効化
- VS2019
    - Text Editor > C# > Advanced より、 Use 64-bit process... を無効化
image-3

トラブルシューティング:BreakPointが効かない? その2

Releaseビルドのpdbファイル生成を停止する際に、誤ってDebugビルドのpdbファイル生成も停止していると、これもブレークポイントで停止しなくなります。pdbファイルの設定を確認してください。

|設定|Debug版設定|Release版設定|
|:--|:--|:--|
image-4

image-6

image-5


トラブルシューティング:変な解析が動いてる?

複数のAnalyzerを運用している場合に起きるようでした。
```C:\Users\{USERNAME}\AppData\Local\Microsoft\VisualStudio\16.0_60c18d0eRoslyn\Extensions``` などのディレクトリ内にある現在デバッグしていないプロジェクトフォルダを削除することで、意図しないAnalyzerを無効化できました。

image-2画像における黒塗りディレクトリ以下に削除対象のディレクトリが存在します。🗂️

解析のしくみをざっくり

構成

CustomUnityAnalyzer.csが初期コードとして生成されますが、これを更に単純化してみました。大きく分けて解析ルールの宣言と、宣言したルールを調査するための解析部分があります。

image-18

ルール宣言

赤枠のフィールド宣言部分でルールを定義しています。これは「```async void```ではなく```async UniTaskVoid```を使うべき」や、「Subscribeメソッド呼び出し時にはAddToをチェーンすべき」といったチェックしたい個々の警告に当たります。ここで設定した内容が、実際にルール違反を検知した場合に表示されるIDや文言となります。

ルールと違反時のエディタでの表示は下記画像参照のこと。

- Rule宣言
image-21

- 違反時のエディタ表示(VisualStudio)
image-19

- 違反時のエディタ表示(VisualStudio)
image-20  

-👆UnityEditorのConsoleにも出力され、ダブルクリックでエディタの該当コードにちゃんと飛んでくれます。

解析呼び出し・実行

解析はISymbolおよびSyntaxNodeを使いますが、それぞれに対応した呼び出し方法があります。
image-10

ISymbolとSyntaxNodeについて

Roslyn Analyzerには大きく分けて2種類の解析ルートが存在します。しばらくはどっちの呼び出しを使えばいいのかわからず雰囲気で使っていましたが、SyntaxNodeを用いる方が直感だなぁ、と今は考えています。

||解析対象|解析例|注意点|
|:--|:--|:--|:--|
|ISymbol|コンパイル後のコード|var x として定義されたxの型が何か|コンパイラ生成コードも解析対象|
|SyntaxNode|文字列として見たコード|privateが宣言されているか|クラスの依存など書かれていないものは解析不可|

ISymbolはコンパイル後のコードを対象とするため、var宣言のようにコンパイル後に型が決定するコードの解析が可能です。一方で、デフォルトコンストラクタやプロパティのgetterメソッドなど、ソースコード上に記述されていないコンパイラ自動生成の要素も解析対象としてしまうので、意図しない解析がけっこう走ってしまいました...。

SyntaxNodeはソースコード上に記述されている要素のみを解析対象にします。私は単なるテキストファイルでコードを開いたときに分かるものはこっちで解析可能くらいの感覚でいます。
このため意図しないコードが解析対象に含まれにくい他、private修飾子の有無(ISymbolの場合、省略されていてもprivateとみなされる)や、private・static・readonly修飾子の順序などの解析が可能です。一方で、名前空間を含む型や継承関係など、コンパイルを経て初めて確定する情報の解析はできません。

ISymbolはプログラマが明示的に記述していない要素も解析対象となる一方で、SyntaxNodeからは```context.SemanticModel.GetSymbolInfo(node).Symbol;```としてISymbolを取得できるので、、SyntaxNodeから解析を開始するルートが使い勝手がよいと考えています。

具体的な解析

具体的な解析処理の実装については、生成AIを活用してコードを作成し、適宜添削するのが良いかと思います。

プロンプト例
``` 
RoslynAnalyzerで、SyntaxNodeを用いて解析を行いたい。解析対象はUniRx名前空間のSubscribe関数で、Subscribe呼び出しの末尾にAddTo()がない場合に警告したい。SyntaxNodeで解析を開始すること。
```

関連知識

実際に解析を行う際に、C#における各コード要素の意味や役割を理解しておくとスムーズに処理が追えるかと思います。[【C#】Unityと.NET標準ライブラリの命名規則の違い]にある識別子の命名規則の項目はC#のもつ種類を網羅しておりとても参考になりました!🙇‍♂️🙇‍♂️🙇‍♂️

Unityに組み込む

ビルド

プロジェクトを作成した時点でライブラリプロジェクトとして設定されているので、Unityに組み込むためにはプロジェクトをReleaseビルドし、そのdllを配置すればよいです。

image-12

image-11

導入方法 (Unity)

[Unity公式]に合わせて.dllファイルを配置します。

注意点はDLLをすべてのPlatformで無効化することと、特殊ラベルRoslynAnalyzerを新たに作成し付与することの二点。

|Platform無効化|特殊ラベル付与|
|:--|:--|
image-13image-14

また、ここでDllの名前を変更するとコードエディタの方では解析が動作し、Unity側では解析が動かなくなる挙動が発生しました。何かに使えるかもしれません🤔

配布

概要

DLLを直接配置する方法では、特殊ラベルの設定も必要となります。そこそこ面倒な作業なので自動化したいのですが、UnityのPackage Managerを使うことで実現できそうでした。DLL導入済みのUnityプロジェクトをGitHubリポジトリとして用意し、他のプロジェクトへ容易にインポートできるようになります。

|PackageManager起動|URLによるインポート|
|:--|:--|
image-15image-16

PackageManagerによるURL指定インポート

Package Manager構成

UnityのPackageManagerを利用するためには、[パッケージレイアウト]に準拠したディレクトリ構成でDLLファイルを配置し、[パッケージマニフェスト]の形式に従ったpackage.jsonを用意する必要があります。

配布側で条件を満たした構造のリポジトリを用意さえすれば、利用側はPackageManagerから```{gitのhttpsパス}?path={gitのルートから見たpackage.jsonのディレクトリパス}```の形式でURLを指定するだけで導入が可能になります!

リポジトリアップロード

まず配布用のUnityプロジェクトを作成し、DLLの設定を行います。このプロジェクト内で解析が有効であることを確認したうえで、package.jsonを追加し、GitHubへアップロードすればOKです。開発の利便性を考え、配布用Unityプロジェクトは解析ツールと同じリポジトリ内に配置しました。

ここまでの操作の概要図は👇となります。DLL設定済みのUnityProjectをGithubにアップロード(赤部分)し、別プロジェクトからpackage.jsonを指定することで、同階層以下が別プロジェクトのPackages以下にインポートされます(橙部分)。
image-17

おわりに

Roslyn Analyzerを使うことで、プロジェクト固有のお作法に従わない場合の警告を出せるようになりました。これでUnityプロジェクトのコード品質がぐっと高まるかとおもいます。
また、PRより前段階でWarning表示されるため、レビュワーが毎度似たコメントをする無駄や、コメント対応にかかる時間も抑えられるかなと思います。

最近では、CopilotやCursorなどのコード生成AIを使ったコード生成やレビューを行うことも日常的になりました。ただRoslyn Analyzerには一度ルールを定義すれば、プロジェクト全体に対して一貫したチェックが漏れなく可能な点や、即座に警告が表示される点で優位性があると思っています。

## 参考

### Web記事

2021年のC# Roslyn Analyzerの開発手法、或いはUnityでの利用法

Roslyn analyzers and source generators

Analyzerの作り方と、各メソッドの使い方

構文解析の概要

【Unity】Unityに既存のRoslyn Analyzerを導入する手順まとめ

Roslynアナライザー_ Unityでの開発環境を改善するための静的解析の仕組みの構築

### 生成AI

Microsoft Copilot


この記事を書いたメンバー
image

クラウドソリューション第1チーム 穂積正隆
※こちらの画像は生成AIで作らており、著作権に問題があるご指摘を頂いた場合はすぐに修正致します。