SatorImaging.UnityAnalyzers 0.2.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package SatorImaging.UnityAnalyzers --version 0.2.0
                    
NuGet\Install-Package SatorImaging.UnityAnalyzers -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SatorImaging.UnityAnalyzers" Version="0.2.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SatorImaging.UnityAnalyzers" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="SatorImaging.UnityAnalyzers">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SatorImaging.UnityAnalyzers --version 0.2.0
                    
#r "nuget: SatorImaging.UnityAnalyzers, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SatorImaging.UnityAnalyzers@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SatorImaging.UnityAnalyzers&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=SatorImaging.UnityAnalyzers&version=0.2.0
                    
Install as a Cake Tool

nuget

đŸ‡ē🇸 English   ❘   đŸ‡¯đŸ‡ĩ æ—ĨæœŦčĒžį‰ˆ   ❘   đŸ‡¨đŸ‡ŗ įŽ€äŊ“ä¸­æ–‡į‰ˆ

Roslyn analyzers to ensure safe and correct code when developing with Unity.

Async Method Analysis

UnityAsyncMethodAnalyzer ensures safe usage of UnityEngine.Object (MonoBehaviour, ScriptableObject, etc.) within async methods.

It checks all async methods declared in any type, including standard C# classes, structs, and records (not just MonoBehaviour or Unity-specific types).

SIUA001: Unreliable Unity object access

Severity: Error

Accessing instance members (methods, properties, fields, events) of a Unity object inside an async method is potentially unsafe because the underlying native object might be destroyed while the managed wrapper still exists.

Rule: You must guard the access with a robust null check using if (obj != null).

Why it matches:

  • Any instance member access on a UnityEngine.Object derivative.
  • Usage of ?. operator (e.g., obj?.Prop) is considered unsafe because it bypasses Unity's custom equality check that handles lifetime validity.

Safe Pattern:

if (unityObject != null)
{
    unityObject.DoSomething(); // OK
}

Unsafe Pattern:

await Task.Yield();

unityObject.DoSomething(); // Error: SIUA001
unityObject?.DoSomething(); // Error: SIUA001 (?. is bypassed)

First Await Exception:

Unity object access before and within the first await expression is safe and will not trigger SIUA001.

// Safe: access before any await
unityObject.DoSomething();

// Safe: access within the first await expression
await unityObject.SomeAsyncMethod();

// Error: access after the first await completes
unityObject.DoSomethingElse(); // Error: SIUA001

This is because Unity objects cannot be destroyed before the async method yields control for the first time.

SIUA002: Await in safe block

Severity: Warning

Using await inside a "Safe Block" (an if (obj != null) block) invalidates the safety guarantee. When the async method resumes after the await, the Unity object may have been destroyed in the meantime.

Rule: Shall not use await inside a block guarded by a Unity object null check.

Unsafe Pattern:

if (unityObject != null)
{
    await Task.Delay(100);

    // unityObject might be destroyed here!
    unityObject.DoSomething(); 
}
// Warning: SIUA002 reported on 'await'

Correct Pattern: Check for null after the await if you need to access the object.

await Task.Delay(100);

if (unityObject != null)
{
    unityObject.DoSomething();
}

Common Analysis Behavior

The following rules and limitations apply to ALL diagnostics in UnityAsyncMethodAnalyzer.

Safe Block Definition (Strictness)

The analyzer is strict about what constitutes a "Safe Block".

  • ALL conditions in the if statement must be Unity object null checks.
  • If you combine a Unity check with ANY other condition (e.g., unityObj != null && someBool), the block is treated as UNSAFE.
  • It typically only accepts if statements (not ternary ? :).
  • The condition must be a direct inequality check against null (e.g., x != null) or composed of them using && (Logic AND).
  • Complex conditions (e.g., ||, pattern matching is not null, or helper methods) may be misdetected (treated as unsafe blocks).

Limitation: No Data Flow Analysis

The analyzer does not verify that the checked variable matches the accessed/usage variable. It simply treats any block guarded by a valid Unity Object null check as "Safe".

Implication for SIUA001: It skips analysis for the block if any Unity Object check is detected, even if you access a different object.

// Valid (Analysis skipped)
// The analyzer considers the block "safe" because Unity object 'foo' is checked, 
// even though Unity object 'bar' is being accessed without a check.
if (foo != null) 
{
    bar.DoSomething(); // No Error (False negative)
}

Implication for SIUA002: It strictly enforces "No Await" inside the block, even if the check is unrelated to the awaited task.

// Warning (Strict enforcement)
if (foo != null) 
{
    await Task.Delay(10); // Warning: SIUA002
}

Limitation: Early Returns

The analyzer does not perform control flow analysis, so "Early Return" style checks are not recognized as creating a Safe Block.

Workaround: Invert the condition and use an else block (or put the code inside the if).

// Unsafe (Analysis does NOT support this)
if (unityObject == null) return;

unityObject.DoSomething(); // Error: SIUA001
// Safe (Using else block)
if (unityObject != null)
{
    unityObject.DoSomething(); // OK
}
else
{
    return;
}

This workaround applies to SIUA002 as well:

// Unsafe (SIUA002 triggers because await is INSIDE the if)
if (unityObject != null)
{
    unityObject.DoSomething();
    await DoFurtherAsync(); // Warning: SIUA002
}
// Safe (await is OUTSIDE the checked block)
if (unityObject != null)
{
    unityObject.DoSomething();
}
else
{
    return;
}

await DoFurtherAsync(); // OK
There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.4.0 92 3/24/2026
1.3.1 90 3/4/2026
1.3.0 90 3/2/2026
1.3.0-rc.1 48 2/22/2026
1.2.0 91 2/22/2026
1.1.1 88 2/19/2026
1.1.0 86 2/19/2026
1.0.0 142 1/10/2026
0.2.0 248 12/7/2025
0.1.0 321 12/7/2025