Skip to content

Fix MA0158 not reported when lock field is initialized in constructor#1037

Merged
meziantou merged 2 commits into
mainfrom
copilot/fix-ma0158-reporting-issue
Feb 22, 2026
Merged

Fix MA0158 not reported when lock field is initialized in constructor#1037
meziantou merged 2 commits into
mainfrom
copilot/fix-ma0158-reporting-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 22, 2026

MA0158 was silently suppressed when an object lock field was assigned in a constructor (.ctor or .cctor) instead of inline, even if the field was exclusively used in lock statements.

Root Cause

Every assignment to a field (_lock = new object()) produces an IFieldReferenceOperation on the left-hand side. The analyzer treated any field reference whose parent wasn't an ILockOperation as a disqualifying usage, calling ExcludeSymbol — permanently preventing the diagnostic regardless of how the field was used elsewhere.

Fix

Skip field/local references that are assignment targets — they represent writes, not reads, and carry no information about how the symbol is used:

// Assignment targets (e.g., initializations in constructors) are not usages
if (operation.Parent is IAssignmentOperation { Target: var assignTarget } && assignTarget == operation)
    return;

This correctly handles both instance and static constructor initialization:

public sealed class A
{
    private readonly object _lock; // now correctly reported as MA0158

    public A() { _lock = new object(); }

    public void Run() { lock (_lock) { } }
}

Tests Added

  • Field initialized in .ctor, used only in lock → diagnostic reported
  • Field initialized in .ctor, also used outside lock → no diagnostic
  • Static field initialized in .cctor, used only in lock → diagnostic reported
  • Static field initialized in .cctor, also used outside lock → no diagnostic

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 1s1vsblobprodcus386.vsblob.vsassets.io
    • Triggering command: /usr/share/dotnet/dotnet dotnet restore --no-dependencies /home/REDACTED/work/Meziantou.Analyzer/Meziantou.Analyzer/Meziantou.Analyzer.slnx --packages /home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /usr/share/dotnet/dotnet dotnet restore --no-dependencies /home/REDACTED/work/Meziantou.Analyzer/Meziantou.Analyzer/tests/Meziantou.Analyzer.Test/Meziantou.Analyzer.Test.csproj --packages /home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
  • pdfvsblobprodcus380.vsblob.vsassets.io
    • Triggering command: /usr/share/dotnet/dotnet dotnet restore --no-dependencies /home/REDACTED/work/Meziantou.Analyzer/Meziantou.Analyzer/tests/Meziantou.Analyzer.Test/Meziantou.Analyzer.Test.csproj --packages /home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
  • st8vsblobprodcus339.vsblob.vsassets.io
    • Triggering command: /usr/share/dotnet/dotnet dotnet restore --no-dependencies /home/REDACTED/work/Meziantou.Analyzer/Meziantou.Analyzer/tests/Meziantou.Analyzer.Test/Meziantou.Analyzer.Test.csproj --packages /home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/home/REDACTED/work/Meziantou.Analyzer/.codeql-scratch/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>MA0158 is not reported when lock is initialized in .ctor or .cctor</issue_title>
<issue_description>### Version of the Meziantou.Analyzer NuGet package

3.0.11

Rule Identifier

MA0158

Target Framework

.NET 10.0

C# Language version

C# 14

Description

When the lock field is initialized in the instance or static constructor, MA0158 is not reported if the type of the field is not System.Threading.Lock.

Reproduction Steps

Constructor:

public sealed class A
{
    private readonly object _lock; // MA0158 is not reported

    public A()
    {
        _lock = new object();
    }

    public void Run()
    {
        lock (_lock)
        {
        }
    }
}

Type initializer / .cctor:

public sealed class B
{
    private static readonly object Lock; // MA0158 is not reported

    static B()
    {
        Lock = new object();
    }

    public void Run()
    {
        lock (Lock)
        {
        }
    }
}

Other information

No response</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Co-authored-by: meziantou <509220+meziantou@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix MA0158 not reported for lock initialization Fix MA0158 not reported when lock field is initialized in constructor Feb 22, 2026
Copilot AI requested a review from meziantou February 22, 2026 15:32
@meziantou meziantou marked this pull request as ready for review February 22, 2026 15:37
@meziantou meziantou enabled auto-merge (squash) February 22, 2026 15:39
@meziantou meziantou merged commit 12bfd87 into main Feb 22, 2026
12 checks passed
@meziantou meziantou deleted the copilot/fix-ma0158-reporting-issue branch February 22, 2026 15:42
This was referenced Feb 22, 2026
This was referenced May 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MA0158 is not reported when lock is initialized in .ctor or .cctor

2 participants