Skip to content

Fix code fix crash when adding an argument to a conditional access invocation - #1617

Merged
meziantou merged 1 commit into
mainfrom
feature/cranky-banach-a7e7b4
Sep 23, 2026
Merged

meziantou merged 1 commit into
mainfrom
feature/cranky-banach-a7e7b4

Conversation

@meziantou

Copy link
Copy Markdown
Owner

Problem

ArgumentListHelper.BindingContext.GetTargetMethod binds the new invocation with GetSpeculativeSymbolInfo at the position of the original invocation. When the original invocation is part of a conditional access (x?.M()), the expression of the new invocation starts with a MemberBindingExpressionSyntax (or ElementBindingExpressionSyntax) that has no parent ConditionalAccessExpressionSyntax, and Roslyn throws a NullReferenceException in SyntaxFactory.FindConditionalAccessNodeForBinding.

This crashes every code fixer that uses ArgumentListHelper.AddArgument or ArgumentListHelper.GetTargetMethod: UseIFormatProviderFixer (MA0011), UseStringComparisonFixer (MA0074), UseAnOverloadThatHasCancellationTokenFixer_Argument (MA0040), UseAnOverloadThatHasTimeProviderFixer and UseAnOverloadThatHasMidpointRoundingFixer.

System.DateTime? dt = null;
_ = dt?.ToString(); // MA0011 code fix throws NullReferenceException

Fix

  • BindingContext detects when the invocation's expression starts with a member or element binding. It follows chains such as x?.A.B(), x?[0].M(), x?.a!.M() and nested conditional accesses.
  • In that case, each new invocation is bound in a copy of the compilation where it replaces the original invocation. The conditional access is then available, whatever the enclosing context: method body, lambda, field initializer or expression-bodied member.
  • When the fix imports a namespace, the using directive is added in the same copy.
  • Other invocations still use the cheaper speculative binding at the position of the original invocation.

Notes for reviewers

  • Binding a single statement speculatively (TryGetSpeculativeSemanticModel) would be cheaper, but it doesn't cover invocations in field or property initializers or expression bodies. The copy of the compilation is created only for invocations that are part of a conditional access, up to 3 times per diagnostic in AddArgument.
  • ((string)null)?.ToLower() doesn't reach this code: MA0011 offers no fix for ToLower even without a conditional access, as the CultureInfo parameter doesn't pass the fixer's IFormatProvider check.

Tests

  • MA0011: nullable value type (dt?.ToString()), element binding (values?[0].ToString()), conditional access in a field initializer
  • MA0074: value?.IndexOf("v"), a call in a member access chain (sample?.Value.IndexOf("v").ToString()), an extension method whose namespace is imported by the fix
  • MA0040: sample?.Run()

All 7 new tests fail without the fix. dotnet test --max-parallel-test-modules 2 passes for every Roslyn version (26,824 tests), and dotnet run --project src/DocumentationGenerator produces no changes.

…vocation

ArgumentListHelper bound the new invocation speculatively at the position of
the original one. When the invocation is part of a conditional access (x?.M()),
its expression starts with a member or element binding whose receiver is only
known in the enclosing conditional access, and Roslyn throws a
NullReferenceException in SyntaxFactory.FindConditionalAccessNodeForBinding.

The new invocation is now bound in a copy of the compilation where it replaces
the original invocation, so the conditional access is available.
@meziantou
meziantou marked this pull request as ready for review September 23, 2026 18:20
@meziantou
meziantou merged commit 1bb7696 into main Sep 23, 2026
14 checks passed
@meziantou
meziantou deleted the feature/cranky-banach-a7e7b4 branch September 23, 2026 18:20
This was referenced Sep 23, 2026
IhateTrains pushed a commit to ParadoxGameConverters/ImperatorToCK3 that referenced this pull request Sep 26, 2026
Updated
[Meziantou.Analyzer](https://github.com/meziantou/Meziantou.Analyzer)
from 3.0.266 to 3.0.290.

<details>
<summary>Release notes</summary>

_Sourced from [Meziantou.Analyzer's
releases](https://github.com/meziantou/Meziantou.Analyzer/releases)._

## 3.0.290

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.290>

## What's Changed
* Use IsAssignableTo where IsOrInheritsFrom was meant to check
assignability by @​meziantou in
meziantou/Meziantou.Analyzer#1616


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.289...3.0.290

## 3.0.289

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.289>

## What's Changed
* Fix code fix crash when adding an argument to a conditional access
invocation by @​meziantou in
meziantou/Meziantou.Analyzer#1617
* Share the search of available CancellationToken and TimeProvider
values by @​meziantou in
meziantou/Meziantou.Analyzer#1612
* Use IOperation instead of SyntaxNode in MA0050 by @​meziantou in
meziantou/Meziantou.Analyzer#1613
* Remove MA0212 by @​meziantou in
meziantou/Meziantou.Analyzer#1615
* Skip every special type when searching for
CancellationToken/TimeProvider members by @​meziantou in
meziantou/Meziantou.Analyzer#1614


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.288...3.0.289

## 3.0.288

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.288>

## What's Changed
* Add MA0242: Use a value factory with
ConcurrentDictionary.GetOrAdd/AddOrUpdate when the value is expensive by
@​meziantou in meziantou/Meziantou.Analyzer#1611


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.287...3.0.288

## 3.0.287

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.287>

## What's Changed
* Test and document the records in MA0197, MA0198 and MA0199 by
@​meziantou in meziantou/Meziantou.Analyzer#1555
* Fix MA0042 false positives, false negatives and code fix crashes by
@​meziantou in meziantou/Meziantou.Analyzer#1560


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.286...3.0.287

## 3.0.286

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.286>

## What's Changed
* Fix MA0171 false positives in nameof and conditional access by
@​meziantou in meziantou/Meziantou.Analyzer#1562


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.285...3.0.286

## 3.0.285

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.285>

## What's Changed
* Fix MA0071 code fix when the locals of the else clause conflict with
other identifiers by @​meziantou in
meziantou/Meziantou.Analyzer#1565
* Fix MA0150 false positive on user-defined operators returning a string
by @​meziantou in
meziantou/Meziantou.Analyzer#1596
* Fix MA0214 false positives in unsafe contexts and after using
declarations by @​meziantou in
meziantou/Meziantou.Analyzer#1602
* Fix MA0028 code fixes for AppendLine with a one-char interpolated
string, no-op calls, and char[].ToString() by @​meziantou in
meziantou/Meziantou.Analyzer#1603


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.284...3.0.285

## 3.0.284

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.284>

## What's Changed
* Fix MA0003 code fix not applied to the arguments of indexers by
@​meziantou in meziantou/Meziantou.Analyzer#1609


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.283...3.0.284

## 3.0.283

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.283>

## What's Changed
* Do not offer the MA0202 code fix to merge non-adjacent branches by
@​meziantou in meziantou/Meziantou.Analyzer#1580
* Fix the LINQ optimization rules on predicates, casts, ordering and
collection interfaces by @​meziantou in
meziantou/Meziantou.Analyzer#1585
* Fix MA0003 exclusions applied to the arguments of target-typed new
expressions by @​meziantou in
meziantou/Meziantou.Analyzer#1594
* Fix MA0123 checking the wrong argument when the arguments are named by
@​meziantou in meziantou/Meziantou.Analyzer#1564


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.282...3.0.283

## 3.0.282

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.282>

## What's Changed
* Fix MA0070 not reported on field-targeted attributes of
auto-properties by @​meziantou in
meziantou/Meziantou.Analyzer#1601
* Fix MA0090 code fix changing the if statement an outer else belongs to
by @​meziantou in
meziantou/Meziantou.Analyzer#1574
* Fix MA0096 code fix when CompareTo is implemented explicitly by
@​meziantou in meziantou/Meziantou.Analyzer#1579
* Fix MA0145 on non-static accessors and MA0146 on constructor accessors
by @​meziantou in
meziantou/Meziantou.Analyzer#1575


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.281...3.0.282

## 3.0.281

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.281>

## What's Changed
* Fix MA0061 code fix for default values declared in a referenced
assembly by @​meziantou in
meziantou/Meziantou.Analyzer#1605
* Fix MA0137 false positive on user-defined operators and conversions by
@​meziantou in meziantou/Meziantou.Analyzer#1606
* Fix MA0139 false positive when the Serilog params array is passed as
an array by @​meziantou in
meziantou/Meziantou.Analyzer#1607


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.280...3.0.281

## 3.0.280

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.280>

## What's Changed
* Fix MA0004 using the ConfigureAwait of nested functions to detect the
context by @​meziantou in
meziantou/Meziantou.Analyzer#1593
* Fix MA0172 false positive on operands with side effects by @​meziantou
in meziantou/Meziantou.Analyzer#1578
* Fix MA0151 false positive on members of containing types and
namespaces by @​meziantou in
meziantou/Meziantou.Analyzer#1592
* Fix MA0128 behavior change when a string span is compared to an empty
string by @​meziantou in
meziantou/Meziantou.Analyzer#1591
* Fix MA0040 suggesting static, write-only, and indexer members as
cancellation tokens by @​meziantou in
meziantou/Meziantou.Analyzer#1577
* Fix MA0036 false positive on classes used as a type in declarations by
@​meziantou in meziantou/Meziantou.Analyzer#1576
* Fix MA0163 false positive when the ProcessStartInfo is assigned to
Process.StartInfo by @​meziantou in
meziantou/Meziantou.Analyzer#1586
* Fix MA0048 only_validate_first_type when the first type is a delegate
by @​meziantou in
meziantou/Meziantou.Analyzer#1595
* Fix MA0194 merging is expressions on values converted by a cast by
@​meziantou in meziantou/Meziantou.Analyzer#1608


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.279...3.0.280

## 3.0.279

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.279>

## What's Changed
* Fix MA0100 false positive on returns nested before a using declaration
by @​meziantou in
meziantou/Meziantou.Analyzer#1572
* Fix MA0056 false positive on members accessed with base by @​meziantou
in meziantou/Meziantou.Analyzer#1584
* Fix MA0091 false positive on instance events raised from a static
context by @​meziantou in
meziantou/Meziantou.Analyzer#1588
* Fix MA0054 false negative on exceptions of a derived type by
@​meziantou in meziantou/Meziantou.Analyzer#1590
* Fix MA0102 code fix copying the modifiers of the reported accessor to
the other accessor by @​meziantou in
meziantou/Meziantou.Analyzer#1598
* Fix MA0046 reporting override events by @​meziantou in
meziantou/Meziantou.Analyzer#1599


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.278...3.0.279

## 3.0.278

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.278>

## What's Changed
* Fix the MA0082 code fix for operands of another type or nullable
operands by @​meziantou in
meziantou/Meziantou.Analyzer#1570
* Fix MA0103 code fix when the left operand is implicitly converted to a
span by @​meziantou in
meziantou/Meziantou.Analyzer#1566
* Fix MA0141, MA0142, MA0148 and MA0149 false positives on dynamic
operands by @​meziantou in
meziantou/Meziantou.Analyzer#1567
* Fix MA0037 code fix crash on embedded empty statements by @​meziantou
in meziantou/Meziantou.Analyzer#1568


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.277...3.0.278

## 3.0.277

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.277>

## What's Changed
* Fix MA0170 on non-public setters and System.Enum parameters by
@​meziantou in meziantou/Meziantou.Analyzer#1571


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.276...3.0.277

## 3.0.276

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.276>

## What's Changed
* Fix MA0022 code fix dropping non-null branches and false positive in
async methods by @​meziantou in
meziantou/Meziantou.Analyzer#1558
* Fix MA0204 false positive on types with partial members by @​meziantou
in meziantou/Meziantou.Analyzer#1559
* Fix MA0109 false positive on generic methods with a Span overload by
@​meziantou in meziantou/Meziantou.Analyzer#1561
* Fix MA0173 when the value contains an await or an out variable
declaration by @​meziantou in
meziantou/Meziantou.Analyzer#1563
* Fix MA0050 when an await precedes the argument validation by
@​meziantou in meziantou/Meziantou.Analyzer#1583
* Fix MA0166 on types that derive from TimeProvider and on non-readable
members by @​meziantou in
meziantou/Meziantou.Analyzer#1582
* Fix MA0110 code fix referencing local constants in the GeneratedRegex
attribute by @​meziantou in
meziantou/Meziantou.Analyzer#1581


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.275...3.0.276

## 3.0.275

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.275>

## What's Changed
* chore(deps): update dependency microsoft.bcl.asyncinterfaces to
10.0.12 by @​renovate[bot] in
meziantou/Meziantou.Analyzer#1546
* Fix MA0182 false positives on types used in nested patterns, events
and self-referencing types by @​meziantou in
meziantou/Meziantou.Analyzer#1549
* Fix MA0215 false positives on await foreach, await using, and
top-level statements by @​meziantou in
meziantou/Meziantou.Analyzer#1550
* Fix MA0009 and MA0023 with named arguments and GeneratedRegex culture
name by @​meziantou in
meziantou/Meziantou.Analyzer#1552
* Fix MA0067 false positive on default parameter values by @​meziantou
in meziantou/Meziantou.Analyzer#1553
* Fix duplicate diagnostics of the XML comment rules on shared
documentation comments by @​meziantou in
meziantou/Meziantou.Analyzer#1554
* Fix MA0073 false positive on user-defined equality operators by
@​meziantou in meziantou/Meziantou.Analyzer#1556


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.274...3.0.275

## 3.0.274

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.274>

## What's Changed
* Add semantic functions to the XPath queries of MA0240 by @​meziantou
in meziantou/Meziantou.Analyzer#1548


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.273...3.0.274

## 3.0.273

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.273>

## What's Changed
* Expose the kind-specific modifiers of the symbols in the XPath queries
of MA0240 by @​meziantou in
meziantou/Meziantou.Analyzer#1547


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.272...3.0.273

## 3.0.272

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.272>

## What's Changed
* Query the symbols with the XPath queries of MA0240 by @​meziantou in
meziantou/Meziantou.Analyzer#1545


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.271...3.0.272

## 3.0.271

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.271>

## What's Changed
* Expose more of Roslyn to the XPath queries of MA0240 by @​meziantou in
meziantou/Meziantou.Analyzer#1544


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.270...3.0.271

## 3.0.270

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.270>

## What's Changed
* Reduce the CPU and the memory used by the rules by @​meziantou in
meziantou/Meziantou.Analyzer#1542
* chore(deps): update dependency dotnet-sdk to v10.0.401 by
@​renovate[bot] in
meziantou/Meziantou.Analyzer#1543


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.269...3.0.270

## 3.0.269

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.269>

## What's Changed
* Reduce the cost of the XPath queries of MA0240 by @​meziantou in
meziantou/Meziantou.Analyzer#1541


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.268...3.0.269

## 3.0.268

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.268>

## What's Changed
* Query the operations with the XPath queries of MA0240 by @​meziantou
in meziantou/Meziantou.Analyzer#1540


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.267...3.0.268

## 3.0.267

NuGet package:
<https://www.nuget.org/packages/Meziantou.Analyzer/3.0.267>

## What's Changed
* Support a custom severity in the banned syntax entries of MA0240 by
@​meziantou in meziantou/Meziantou.Analyzer#1539


**Full Changelog**:
meziantou/Meziantou.Analyzer@3.0.266...3.0.267

Commits viewable in [compare
view](meziantou/Meziantou.Analyzer@3.0.266...3.0.290).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Meziantou.Analyzer&package-manager=nuget&previous-version=3.0.266&new-version=3.0.290)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This was referenced Sep 26, 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.

1 participant