{"id":19466798,"url":"https://github.com/dena/mustawaitanalyzer","last_synced_at":"2025-04-15T04:17:08.545Z","repository":{"id":260385365,"uuid":"879829640","full_name":"DeNA/MustAwaitAnalyzer","owner":"DeNA","description":"A roslyn analyzer that enforces the use of await","archived":false,"fork":false,"pushed_at":"2024-11-01T04:56:46.000Z","size":82,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-12T22:47:40.560Z","etag":null,"topics":["dataflow-analysis","roslyn","roslyn-analyzers","static-analysis"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/MustAwaitAnalyzer","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DeNA.png","metadata":{"files":{"readme":"README-ja.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-28T16:08:17.000Z","updated_at":"2024-12-13T05:49:01.000Z","dependencies_parsed_at":"2024-10-31T03:15:53.713Z","dependency_job_id":null,"html_url":"https://github.com/DeNA/MustAwaitAnalyzer","commit_stats":null,"previous_names":["dena/mustawaitanalyzer"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DeNA%2FMustAwaitAnalyzer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DeNA%2FMustAwaitAnalyzer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DeNA%2FMustAwaitAnalyzer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DeNA%2FMustAwaitAnalyzer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DeNA","download_url":"https://codeload.github.com/DeNA/MustAwaitAnalyzer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248643045,"owners_count":21138353,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dataflow-analysis","roslyn","roslyn-analyzers","static-analysis"],"created_at":"2024-11-10T18:30:16.910Z","updated_at":"2025-04-15T04:17:08.523Z","avatar_url":"https://github.com/DeNA.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MustAwaitAnalyzer\n\n## 概要\n\nMustAwaitAnalyzerは\n\n- [System.Threading.Tasks.Task](https://learn.microsoft.com/ja-jp/dotnet/api/system.threading.tasks.task?view=net-7.0)\n- [Cysharp.Threading.Tasks.UniTask](https://github.com/Cysharp/UniTask)\n\nを戻り値に持つメソッドの呼び出しの際にawaitをつけることを強制するアナライザーです。\n\n## Unity プロジェクトでの使用方法\n\nUnity 2021.1.2f1 以上が必要です。\n`https://github.com/DeNA/MustAwaitAnalyzer.git?path=com.dena.must-await-analyzer#1.0.0` を Package Manager に追加してください。\n\n## .NET プロジェクトでの使用方法\n\n[NuGet packages](https://www.nuget.org/packages/MustAwaitAnalyzer) からインストールしてください。\n\n## DENA008: Must use await\n\n| Item     | Value              |\n|----------|--------------------|\n| Category | DenaUnityAnalyzers |\n| Enabled  | True               |\n| Severity | Error              |\n| CodeFix  | False              |\n\n\n### 解析対象\n\n- 式の評価結果が以下の型であるメソッドの呼び出し、プロパティの参照、インスタンスの作成\n- メソッドの呼び出し、プロパティの参照、インスタンスの作成について、それらの評価結果が以下の型のいずれかであるもの\n  - [`System.Threading.Tasks.Task`](https://learn.microsoft.com/ja-jp/dotnet/api/system.threading.tasks.task?view=net-7.0)\n  - [`Cysharp.Threading.Tasks.UniTask`](https://github.com/Cysharp/UniTask?tab=readme-ov-file#compare-with-standard-task-api)\n  - [`System.Threading.Tasks.Task\u003cT\u003e`](https://learn.microsoft.com/ja-jp/dotnet/api/system.threading.tasks.task-1?view=net-8.0)\n  - [`Cysharp.Threading.Tasks.UniTask\u003cT\u003e`](https://github.com/Cysharp/UniTask?tab=readme-ov-file#compare-with-standard-task-api)\n\n以下に例を記載します。\n\n```csharp\n// bad\nnamespace BadCase\n{\n    public class Task1\n    {\n        Task Task_NoAsync() =\u003e Task.Run(() =\u003e {}); // DENA008, Must use await\" がレポートされます\n\n        public Task UseNoAsync()\n        {\n            Task_NoAsync(); // DENA008, Must use await\" がレポートされます\n        }\n        \n        Action\u003cobject\u003e action = (object obj) =\u003e\n                                {\n                                };\n    \n        public async Task Hoge()\n        {\n            new Task(action, \"a\"); // DENA008, Must use await\" がレポートされます\n        }\n    }\n}\n\n// good\nnamespace GoodCase\n{\n    public class Task1\n    {\n        async Task Task_NoAsync() =\u003e await Task.Run(() =\u003e {}); // DENA008, Must use await\" がレポートされません\n\n        public async Task UseNoAsync()\n        {\n            await Task_NoAsync(); // DENA008, Must use await\" がレポートされません\n        }\n        \n        Action\u003cobject\u003e action = (object obj) =\u003e\n                                {\n                                };\n    \n        public async Task Hoge()\n        {\n            await new Task(action, \"a\"); // DENA008, Must use await\" がレポートされません\n        }\n    }\n}\n```\n\nNOTE1: 以下の型の解析は行いません\n\n- [UniTaskVoid](https://github.com/Cysharp/UniTask#async-void-vs-async-unitaskvoid)\n- [ValueTask](https://learn.microsoft.com/ja-jp/dotnet/api/system.threading.tasks.valuetask?view=net-7.0)\n\nNOTE2: メソッドチェーンの最後のメソッド名が Terminate あるいは Forget の場合は、解析は行いません\n\n```csharp\nstatic async UniTask HogeAsync()\n{\n    await Task.Run(() =\u003e {});\n}\n\nstatic void TerminateCase()\n{\n    HogeAsync(); // await漏れによりDENA008がレポートされます\n    HogeAsync().GetAwaiter(); // await漏れによりDENA008がレポートされます\n    HogeAsync().GetAwaiter().Terminate(); // 何もレポートされません\n    HogeAsync().GetAwaiter().Forget(); // 何もレポートされません\n}\n```\n\nNOTE3: 解析対象となるメソッドから直接プロパティ参照が行われる場合、メソッドは解析対象とならずプロパティ参照のみが解析対象となります\n\n```csharp\n// bad\npublic async static Task\u003cTask\u003e BadPropertyCase()\n{\n    var p = new Program();\n    p.Example(); // DENA008がレポートされます\n    return p.Example().Result; // ResultはTaskを返すためDENA008がレポートされます\n}\n\npublic async Task\u003cTask\u003e Example()\n{\n    return await new Task\u003cTask\u003e(null);\n}\n\n// good\npublic async static Task\u003cint\u003e GoodPropertyCase()\n{\n    var p = new Program();\n    p.Example(); // DENA008がレポートされます\n    return p.Example().Result; // Resultはintを返すためDENA008はレポートされません\n}\n\npublic async Task\u003cint\u003e Example()\n{\n    return await new Task\u003cint\u003e(null);\n}\n```\n\nNOTE4: 下記のメソッド呼び出し、プロパティ参照、フィールド参照は解析対象外とします\n\n- `System.Threading.Tasks.Task.CompletedTask`\n- `System.Threading.Tasks.Task.FromResult`\n- `Cysharp.Threading.Tasks.UniTask.CompletedTask`\n- `Cysharp.Threading.Tasks.UniTask.FromResult`\n\nNOTE5: Task や UniTask オブジェクトを変数に代入してから await している場合や、リスト（System.Collections.Generic.IList を実装しているクラス）に格納してまとめて await している場合は警告しません。ただし、try-catch の中で await している場合は警告されます。\n\n```csharp\n// good\npublic async Task M1()\n{\n    var task = Task.Run(() =\u003e {}); // DENA008 はレポートされません\n    await task;\n}\n```\n\n```csharp\n// good\npublic async Task M1()\n{\n    var list = new List\u003cTask\u003e();\n    list.Add(Task.Run(() =\u003e {})); // DENA008 はレポートされません\n    list.Add(Task.Run(() =\u003e {})); // DENA008 はレポートされません\n    await Task.WhenAll(list);\n}\n```\n\n### 解析箇所\n\n解析対象が以下の構文内に存在し、awaitが無い場合、DENA008をレポートします。\n\n#### blockの中\n\n```csharp\n// bad\nnamespace BadCase\n{\n    public class Task1\n    {\n        Task Task_NoAsync() =\u003e Task.Run(() =\u003e {}); // DENA008, Must use await\" がレポートされます\n\n        public Task UseNoAsync()\n        {\n            Task_NoAsync(); // DENA008, Must use await\" がレポートされます\n        }\n    }\n}\n\n// good\nnamespace GoodCase\n{\n    public class Task1\n    {\n        async Task Task_NoAsync() =\u003e await Task.Run(() =\u003e {});\n\n        public async Task UseNoAsync()\n        {\n            await Task_NoAsync();\n        }\n    }\n}\n```\n\n#### statementの中\n\nstatementの解析箇所をいくつか列挙します。\n\n- using statement\n\n```csharp\n// bad\n\nnamespace BadCase\n{\n    public class Task1\n    {\n        public async void M1() \n        {\n            using (M2()) // DENA008, Must use await\" がレポートされます。\n            {\n            }\n        }\n        \n        public async Task\u003cIDisposable\u003e M2()\n        {\n            return await (Task\u003cIDisposable\u003e)Task.Run(() =\u003e {});\n        }\n    }\n}\n\n// good\nnamespace BadCase\n{\n    public class Task1\n    {\n        public async void M1() \n        {\n            using (await M2()) // awaitがついているのでDENA008はレポートされません。\n            {\n            }\n        }\n        \n        public async Task\u003cIDisposable\u003e M2()\n        {\n            return await (Task\u003cIDisposable\u003e)Task.Run(() =\u003e {});\n        }\n    }\n}\n```\n\n- do while statement\n\n```csharp\n// Bad\npublic class BadCase {\n    public async void M() \n    {\n        do \n        {\n            Task.Run(() =\u003e {}); // DENA008, Must use await\" がレポートされます。\n        }\n        while (true);\n        {\n        }\n    }\n}\n\n// Good\npublic class GoodCase {\n    public async void M() \n    {\n        do \n        {\n            await Task.Run(() =\u003e {}); // awaitがついているのでDENA008はレポートされません。\n        }\n        while (true);\n        {\n        }\n    }\n}\n```\n\n- if statement\n\n```csharp\n// bad case\nnamespace FailedCase\n{\n    public class C {\n        public async void M() \n        {\n            if (M2()) // DENA008がレポートされます\n            {\n            }\n        }\n\n        public async Task\u003cbool\u003e M2()\n        {\n            return await (Task\u003cbool\u003e)Task.Run(() =\u003e {});\n        }\n    }\n}\n\n// good case\nnamespace SuccessCase\n{\n    public class C {\n        public async void M() \n        {\n            if (await M2())\n            {\n            }\n        }\n\n        public async Task\u003cbool\u003e M2()\n        {\n            return await (Task\u003cbool\u003e)Task.Run(() =\u003e {});\n        }\n    }\n}\n```\n\n- yield statement\n\n```csharp\n// bad\nnamespace BadCase\n{\n    public class YieldReturn\n    {\n        public async IAsyncEnumerable\u003cint\u003e M1()\n        {\n            for (int i = 0; i \u003c 10; i++)\n            {\n                yield return (Task\u003cint\u003e)Task.Run(() =\u003e 0); // DENA008、CS0029がレポートされます\n            }\n        }\n    }\n}\n\n// good\nnamespace GoodCase\n{\n    public class YieldReturn\n    {\n        public async IAsyncEnumerable\u003cint\u003e M1()\n        {\n            for (int i = 0; i \u003c 10; i++)\n            {\n                yield return await (Task\u003cint\u003e)Task.Run(() =\u003e 0);\n            }\n        }\n    }\n}\n```\n\n#### lambda\n\n```csharp\n// bad\nnamespace FailedCase\n{\n    public class Task1\n    {\n        Func\u003cTask\u003cint\u003e\u003e Example() =\u003e (() =\u003e Task.Run(() =\u003e 0)); // DENA008, Must use await\" がレポートされます\n\n        public void UseAsync()\n        {\n            Example(); // Task\u003cint\u003e型ではなくFunc\u003cTask\u003cint\u003e\u003e型が戻り値のためDENA008はレポートされません\n        }\n    }\n}\n\n// good\nnamespace SuccessCase\n{\n    public class Task1\n    {\n        Func\u003cTask\u003cint\u003e\u003e Example() =\u003e (async () =\u003e await Task.Run(() =\u003e 0));\n\n        public void UseAsync()\n        {\n            Example(); // Task\u003cint\u003e型ではなくFunc\u003cTask\u003cint\u003e\u003e型が戻り値のためDENA008はレポートされません\n        }\n    }\n}\n```\n\n#### PartialMethod内での非同期処理\n\n```csharp\nnamespace BadCase\n{\n    interface IStudent\n    {\n        Task GetName();\n    }\n\n    partial class PartialMethod : IStudent\n    {\n        public virtual partial Task GetName();\n    }\n\n    public partial class PartialMethod\n    {\n        public virtual partial async Task GetName()\n        {\n            Task.Run(() =\u003e {}); // DENA008がレポートされます。\n        }\n    }\n}\n\nnamespace GoodCase\n{\n    interface IStudent\n    {\n        Task GetName();\n    }\n\n    partial class PartialMethod : IStudent\n    {\n        public virtual partial Task GetName();\n    }\n\n    public partial class PartialMethod\n    {\n        public virtual partial async Task GetName()\n        {\n            await Task.Run(() =\u003e {});\n        }\n    }\n}\n```\n\n#### ターゲット型推論\n\n```csharp\n// badcase\nnamespace BadCase\n{\n    public class TargetTypedNewExpression\n    {\n        Func\u003cobject, int\u003e func = null;\n\n\n        public async Task\u003cint\u003e Hoge()\n        {\n            return await new Task\u003cint\u003e(func, \"a\");\n        }\n\n        public async void M()\n        {\n            Dictionary\u003cstring, int\u003e field = new()\n            {\n                { \"item1\", Hoge() } // DENA008がレポートされます\n            };\n        }\n    }\n}\n\n// GoodCase\nnamespace GoodCase\n{\n    public class TargetTypedNewExpression\n    {\n        Func\u003cobject, int\u003e func = null;\n\n\n        public async Task\u003cint\u003e Hoge()\n        {\n            return await new Task\u003cint\u003e(func, \"a\");\n        }\n\n        public async void M()\n        {\n            Dictionary\u003cstring, int\u003e field = new()\n            {\n                { \"item1\", await Hoge() }\n            };\n        }\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdena%2Fmustawaitanalyzer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdena%2Fmustawaitanalyzer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdena%2Fmustawaitanalyzer/lists"}