Skip to content

Commit 4dbb0b0

Browse files
Fix LINQ chain diagnostics (#287)
1 parent e544c8c commit 4dbb0b0

File tree

3 files changed

+52
-18
lines changed

3 files changed

+52
-18
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88

99
## Unreleased
1010

11+
### Fixed
12+
13+
- PR [#287](https://github.com/marinasundstrom/CheckedExceptions/pull/287) Fix LINQ chain diagnostics
14+
1115
## [2.1.2] - 2025-08-22
1216

1317
### Added

CheckedExceptions.Tests/CheckedExceptionsAnalyzerTests.Linq.cs

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ await Verifier.VerifyAnalyzerAsync(test, setup: o =>
104104
}
105105

106106
[Fact]
107-
public async Task PassDelegateByVariable()
108-
{
107+
public async Task PassDelegateByVariable()
108+
{
109109
var test = /* lang=c#-test */ """
110110
#nullable enable
111111
using System;
@@ -124,11 +124,38 @@ public async Task PassDelegateByVariable()
124124
var expected2 = Verifier.UnhandledException("OverflowException")
125125
.WithSpan(9, 22, 9, 27);
126126

127-
await Verifier.VerifyAnalyzerAsync(test, setup: o =>
128-
{
129-
o.ExpectedDiagnostics.AddRange(expected, expected2);
130-
}, executable: true);
131-
}
127+
await Verifier.VerifyAnalyzerAsync(test, setup: o =>
128+
{
129+
o.ExpectedDiagnostics.AddRange(expected, expected2);
130+
}, executable: true);
131+
}
132+
133+
[Fact]
134+
public async Task PassDelegateByVariable_Chained()
135+
{
136+
var test = /* lang=c#-test */ """
137+
#nullable enable
138+
using System;
139+
using System.Collections.Generic;
140+
using System.Linq;
141+
142+
IEnumerable<int> items = [];
143+
Func<int, bool> pred = [Throws(typeof(FormatException), typeof(OverflowException))] (z) => int.Parse("10") == z;
144+
var query = items.Where(pred).Where(x => x is 0);
145+
foreach (var item in query) { }
146+
""";
147+
148+
var expected = Verifier.UnhandledException("FormatException")
149+
.WithSpan(9, 22, 9, 27);
150+
151+
var expected2 = Verifier.UnhandledException("OverflowException")
152+
.WithSpan(9, 22, 9, 27);
153+
154+
await Verifier.VerifyAnalyzerAsync(test, setup: o =>
155+
{
156+
o.ExpectedDiagnostics.AddRange(expected, expected2);
157+
}, executable: true);
158+
}
132159

133160
[Fact]
134161
public async Task CastOperator()
@@ -156,17 +183,11 @@ public async Task CastOperator()
156183
var expected3 = Verifier.UnhandledException("InvalidCastException")
157184
.WithSpan(11, 22, 11, 27);
158185

159-
var expected4 = Verifier.UnhandledException("FormatException")
160-
.WithSpan(8, 6, 8, 94);
161-
162-
var expected5 = Verifier.UnhandledException("OverflowException")
163-
.WithSpan(8, 6, 8, 94);
164-
165-
await Verifier.VerifyAnalyzerAsync(test, setup: o =>
166-
{
167-
o.ExpectedDiagnostics.AddRange(expected, expected2, expected3, expected4, expected5);
168-
}, executable: true);
169-
}
186+
await Verifier.VerifyAnalyzerAsync(test, setup: o =>
187+
{
188+
o.ExpectedDiagnostics.AddRange(expected, expected2, expected3);
189+
}, executable: true);
190+
}
170191

171192
[Fact]
172193
public async Task QueryAsArgument()

CheckedExceptions/CheckedExceptionsAnalyzer.Linq.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ private static void CollectLinqExceptions(
2828

2929
if (!isTerminal)
3030
{
31+
// If this invocation is the source in a chained LINQ call (e.g., xs.Where(...).Where(...)),
32+
// defer handling until the outermost call is analyzed.
33+
if (invocationSyntax.Parent is MemberAccessExpressionSyntax { Parent: InvocationExpressionSyntax outer } &&
34+
semanticModel.GetOperation(outer, ct) is IInvocationOperation outerOp &&
35+
IsLinqExtension(outerOp.TargetMethod))
36+
{
37+
return;
38+
}
39+
3140
// Deferred invocation inside an argument/return is handled at the boundary.
3241
if (invocationSyntax.FirstAncestorOrSelf<ReturnStatementSyntax>() is not null)
3342
return;

0 commit comments

Comments
 (0)