Version: 2022.1
言語: 日本語
ユニットテスト
スクリプティングの概念

Roslyn アナライザーとソースジェネレーター

コードのスタイルや品質、その他の問題を検査するには、Unity プロジェクトで Roslyn アナライザー、ソースジェネレーター、ルールセットファイルを使用します。

既存のアナライザーライブラリを使用してコードを検査したり、独自のアナライザーを作成して組織内の効率的な方法や規則を推進したりすることができます。このページでは、空の Unity プロジェクトで Roslyn アナライザーとソースジェネレーターを使用する方法を説明します。

ノート: Roslyn アナライザーは、Unity が公式にサポートしている IDE、すなわち Visual Studio と JetBrains Rider にのみ対応しています。

Roslyn アナライザーの書き方と使用方法の詳細については、Microsoft の概要 およびRoslyn アナライザーの概要 のドキュメントを参照してください。

ソースジェネレーター

ソース ジェネレーターは、スクリプトのコンパイルプロセスの追加手順として使用できます。ソースジェネレーターを使用すると、既存のコードをコンパイルしている間に新しいコードを追加することができます。アナライザーのように、既存のソースジェネレーターを使用することも、独自のソースジェネレーターを作成することもできます。

ノート: Unity は ‘System.Text.Json’ 名前空間のバージョン 6.0.0-preview のみをサポートしています。アプリケーションでこの名前空間を使用する場合は、バージョン 6.0.0-preview を使用するようにしてください。 System.Text.Json の詳細については、Microsoft のSystem.Text.Json 名前空間 ドキュメントを参照してください。

Visual Studio を使用してソースジェネレーターをセットアップするには、以下を行います。

  1. Visual Studioで、.NET Standard 2.0 をターゲットとする .NET 標準ライブラリプロジェクトを作成します。
  2. Microsoft.CodeAnalysis NuGet パッケージをインストールします。Unity で動作させるには、ソースジェネレーターは、Microsoft.CodeAnalysis 3.8 を使う必要があります。
  3. Visual Studio のプロジェクトで、新しい C# ファイルを作成し、以下のコードを追加します。
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System.Text;

namespace ExampleSourceGenerator
{
    [Generator]
    public class ExampleSourceGenerator : ISourceGenerator
    {
        public void Execute(GeneratorExecutionContext context)
        {
            System.Console.WriteLine(System.DateTime.Now.ToString());

            var sourceBuilder = new StringBuilder(
            @"
            using System;
            namespace ExampleSourceGenerated
            {
                public static class ExampleSourceGenerated
                {
                    public static string GetTestText() 
                    {
                        return ""This is from source generator ");

            sourceBuilder.Append(System.DateTime.Now.ToString());

            sourceBuilder.Append(
                @""";
                    }
    }
}
");

            context.AddSource("exampleSourceGenerator", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
        }

        public void Initialize(GeneratorInitializationContext context) { }
    }
}
  1. リリース用にソースジェネレーターをビルドします。これを行うには、 Build にアクセスし、 Batch Build オプションを選択します。
  2. ソースジェネレーターのプロジェクトフォルダーで、bin/Release/netstandard2.0/ExampleSourceGenerator.dll ファイルを見つけます。
  3. このファイルを Unity プロジェクトの Assets フォルダー内にコピーします。
  4. アセットブラウザー内で、.dll ファイルをクリックし、Plugin Inspector ウィンドウを開きます。
  5. プラグインの Select platforms に移動し、Any Platform を無効にします。
  6. Include Platforms に移動し、EditorStandalone を無効にします。
  7. Asset Labels に移動し、Asset Labels サブメニューを開きます。
  8. RoslynAnalyzer という新しいラベルを作成し、割り当てます。これを行うには、Asset Labels サブメニューのテキスト入力ウィンドウに “RoslynAnalyzer” と入力します。このラベルは正確に一致する必要があり、大文字と小文字が区別されます。最初のアナライザーのラベルを作成すると、このラベルが Asset Labels サブメニューに表示されます。このメニューでラベルの名前をクリックすると、そのラベルを他のアナライザーに割り当てることができます。
  9. ソースジェネレーターが動作することを確認するために、エディターで以下のコードを使って新しい C# スクリプトを作成します。
using UnityEngine;

public class HelloFromSourceGenerator : MonoBehaviour
{
    static string GetStringFromSourceGenerator()
    {
        return ExampleSourceGenerated.ExampleSourceGenerated.GetTestText();
    }

    // Start is called before the first frame update
    void Start()
    {
        var output = "Test";
        output = GetStringFromSourceGenerator();
        Debug.Log(output);
    }
}
  1. このスクリプトをシーン内のゲームオブジェクトに加えて、再生モードにします。コンソールウィンドウに、タイムスタンプなどソースジェネレータからのメッセージが表示されます。

ソースジェネレーターに関する詳細については、Microsoft の ソース ジェネレーター ドキュメントを参照してください。

アナライザーのスコープ

アセンブリ定義を使用することで、プロジェクトのアナライザーのスコープを制限することができます。これにより、コードの特定の部分のみを分析します。

Unity は、プロジェクトの Assets フォルダー内、または親フォルダーに アセンブリ定義ファイル が含まれていないサブフォルダー内のすべてのアセンブリにアナライザーを適用します。アナライザーがアセンブリ定義を含むフォルダー、またはそのようなフォルダーのサブフォルダーにある場合、アナライザーはそのアセンブリ定義から生成されたアセンブリと、それを参照するアセンブリ定義にのみ適用されます。

つまり、例えば パッケージ は、そのパッケージに関連するコードのみを分析するアナライザーを供給できます。これは、パッケージのユーザーがパッケージの API を正しく使用する助けとなります。

アナライザー診断のレポート

アナライザーとソースジェネレーターの合計実行時間や、各アナライザーまたはソースジェネレーターの関連実行時間などの情報を表示するには、Preferences > Diagnostic Switches と移動し、EnableDomainReloadTimings を有効にしてください。これを有効にすると、コンソールウィンドウに情報が表示されます。

既存の Roslyn アナライザーまたはソースジェネレーターのインストール

Unity は、NuGet を通じて直接 Roslyn アナライザーやソースジェネレーターをインストールすることをサポートしていません。以下の例は、ErrorProne.NET.CoreAnalyzers ライブラリを使用して、NuGet から Roslyn アナライザーとソースジェネレーターをインストールする方法を表します。

  1. Download package ボタンで、ライブラリを .zip ファイルとしてダウンロードします。
  2. .zip ファイルのコンテンツを解凍します。
  3. 解凍されたフォルダー内で、アナライザーを含む .dll ファイルを探します。この例では、Download package に移動します。必要なファイルはこのフォルダーの ErrorProne.NET.Core.dllErrorProne.Net.CoreAnalyzers.dllRuntimeContracts.dll です。
  4. これらのファイルを、Unity プロジェクトの Assets フォルダー、または Assets フォルダー内にネスト状になっている任意のフォルダーに移動します。これを行うには、Assets > Import new asset と進み、3 つのファイルそれぞれの .dll を選択するか、デバイスのファイルブラウザーを通じてプロジェクトの Assets フォルダーにコピーします。
  5. Unity の Asset Browser 内の .dll ファイルをクリックし、Plugin Inspector ウィンドウを開きます。
  6. Plugin Inspector ウィンドウの中で、以下を行います。
    • Select platforms for plugin の見出しで、Any Platform を無効にします。
    • Include Platforms の見出しで、EditorStandalone を無効にします。
  7. Plugin Inspector ウィンドウの Asset Labels の見出しの下にある、青いラベルアイコンをクリックして、Asset Labels サブメニューを表示します。
  8. RoslynAnalyzer という新しいラベルを作成し、割り当てます。これを行うには、Asset Labels サブメニューのテキスト入力ウィンドウに “RoslynAnalyzer” と入力し、Return を押します。このラベルは正確に例と一致する必要があり、大文字と小文字が区別されます。最初のアナライザーのラベルを作成すると、このラベルが Asset Labels サブメニューの使用可能なラベルのリストに表示されます。このメニューでラベルの名前をクリックすると、そのラベルを他のアナライザーに割り当てることができます。

Unity は RoslynAnalyzer ラベルを認識し、このラベルが付いたアセットを Roslyn アナライザーまたはソースジェネレーターとして扱います。アナライザーにこのラベルを割り当てると、Unity はアナライザーのスコープ内のスクリプトを再コンパイルし、アナライザーの規則に従ってそれらのスクリプトのコードを分析します。アナライザーと同じアセンブリ定義内にあるスクリプトは、そのアナライザーのスコープに含まれます。Assets フォルダーのルートレベルにあるアナライザーの場合、Unity はプロジェクト内のすべてのファイルをスコープとみなします。スコープの詳細については、アナライザーのスコープ を参照してください。

アナライザーが正しく動作することをテストするには、以下の例に従ってください。アナライザーが正しくインストールされている場合、ErrorProne.NET アナライザーは例のコードを解析する際に警告を表示します。

RethrowError.cs という名前の新しいスクリプトファイルを作成します。このスクリプトに以下のコードをコピーして、ファイルを保存します。

using System;
using UnityEngine;

public class RethrowError : MonoBehaviour
{
    void Update()
    {
        try
        {
            DoSomethingInteresting();
        }
        catch (Exception e)
        {
            Debug.Log(e.Message);
            throw e;
        }
    }

    private void DoSomethingInteresting()
    {
        throw new System.NotImplementedException();
    }
}

ファイルを保存すると、Unity はスクリプトを再コンパイルし、スクリプトのコードに適用可能なアナライザーを実行します。ErrorProne.NET アナライザーが正しくインストールされている場合、コンソールウィンドウに上記のコードについて以下のような警告が表示されます。

Assets\\RethrowError.cs(14,23): warning EPC12: Suspicious exception handling: only e.Message is observed in exception block.

Assets\\RethrowError.cs(15,19): warning ERP021: Incorrect exception propagation. Use throw; instead.

ルールセットファイル

プロジェクトのアナライザーが発するさまざまな警告やエラーを処理する方法を独自の規則で定義するには、ルールセットファイルを作成します。カスタムルールセットの作成方法の詳細については、Microsoft の Visual Studio のドキュメント ルールセットをカスタマイズする を参照してください。

Assets ルートフォルダーに、Default.ruleset という名前のルールセットファイルを置きます。Default.ruleset で定義する規則は、すべての定義済みアセンブリ (例えば、Assembly-CSharp.dll)、および .asmdef ファイルを使用して構築されたすべてのアセンブリに適用されます。

Default.ruleset の規則を定義済みのアセンブリにオーバーライドするには、ルートフォルダーに .ruleset ファイルを作成し、 [PredefinedAssemblyName].ruleset と名づけます。例えば、Assembly-CSharp.ruleset の規則は、Assembly-CSharp.dll のコードに適用されます。これらの .ruleset ファイルのみがルートフォルダー内で許可されます。

  • Default.Ruleset
  • Assembly-CSharp.ruleset
  • Assembly-CSharp-firstpass.ruleset
  • Assembly-CSharp-Editor.ruleset
  • Assembly-CSharp-Editor-firstpass.ruleset

ワークフロー: Unity でルールセットファイルをテストする

Unity でルールセットファイルをテストするには、以下を行います。

ステップ 1: ルールセットファイルの設定

  1. プロジェクトの Assets フォルダーの中に “Subfolder” という名前のサブフォルダーを作成します。
  2. Subfolder 内で以下を行います。
    1. 新しい .asmdef ファイルを作成します。
    2. RethrowError.cs の複製を保存します。
  3. Assets 内にDefault.ruleset ファイルを作成し、以下のコードを記述します。
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="New Rule Set" Description=" " ToolsVersion="10.0">
  <Rules AnalyzerId="ErrorProne.NET.CodeAnalyzers" RuleNamespace="ErrorProne.NET.CodeAnalyzers">
    <Rule Id="ERP021" Action="Error" />
  <Rule Id="EPC12" Action="None" />
  </Rules>
</RuleSet>

Default.ruleset ファイルでは、以下の規則が定義されています。

  • EPC12 の抑制。疑わしい例外処理についての警告です。
  • ERP021 の発生。誤った例外伝播に関する警告です。

ステップ 2: プロジェクトの再ロード

プロジェクトにルールセットファイルを追加した後、規則を適用するアセンブリ内にあるスクリプトをすべて再インポートします。これを行うと、Unity は新しいルールセットファイルを使用してアセンブリを再コンパイルします。再コンパイルの後、コンソールウィンドウに以下の 2 つのメッセージが表示されます。

Assets\\Subfolder\\RethrowError.cs(15,19): error ERP021: Incorrect exception propagation. Use throw; instead.

Assets\\RethrowError.cs(15,19): error ERP021: Incorrect exception propagation. Use throw; instead.

Unity は Default.ruleset で定義された規則を Assets/RethrowError.csAssets/Subfolder/RethrowError.cs の両方に適用していることに注目してください。

ステップ 3: カスタムルールセットの追加

Assets/Subfolder に .ruleset ファイルを作成し、任意の名前を付けます (この例では Hello.ruleset)。

<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="New Rule Set" Description=" " ToolsVersion="10.0">
  <Rules AnalyzerId="ErrorProne.NET.CodeAnalyzers" RuleNamespace="ErrorProne.NET.CodeAnalyzers">
    <Rule Id="ERP021" Action="Info" />
    <Rule Id="EPC12" Action="Info" />
  </Rules>
</RuleSet>

この新しい Hello.ruleset ファイルは、Unity に EPC12 と ERP021 の両方を警告やエラーとして扱わずに、コンソールに出力するように指示します。

Unity がプロジェクトを再度コンパイルすると、コンソールウィンドウに以下のメッセージが表示されます。

Assets\\Subfolder\\RethrowError.cs(14,23): info EPC12: Suspicious exception handling: only e.Message is observed in exception block.

Assets\\Subfolder\\RethrowError.cs(15,19): info ERP021: Incorrect exception propagation. Use throw; instead.

Assets\\RethrowError.cs(15,19): error ERP021: Incorrect exception propagation. Use throw; instead.

Default.ruleset の規則は Assets\\RethrowError.cs にはまだ適用されますが、Assets\\Subfolder\\RethrowError.cs には適用されません。Hello.ruleset の規則がそれをオーバーライドするためです。

許可されているすべてのルールセットのアクションファイルの詳細については、Visual Studio のドキュメント コード分析ルールセットエディターを使用する を参照してください。

その他のアナライザー

以下は、よく使われる Roslyn アナライザーライブラリの Github リポジトリへのリンクです。

ユニットテスト
スクリプティングの概念