Skip to content

Commit 9d73bdc

Browse files
Improve null-conditional await analyzer for nullable refs (#313)
Updated NullConditionalOperatorAnalyzer to use operation analysis and skip diagnostics when nullable reference types are enabled and annotated. Added a corresponding test to ensure no warning is reported in this scenario. Also clarified the EPC37 diagnostic title for async argument validation.
1 parent 3fec13e commit 9d73bdc

3 files changed

Lines changed: 40 additions & 3 deletions

File tree

src/ErrorProne.NET.CoreAnalyzers.Tests/AsyncAnalyzers/NullConditionalOperatorAnalyzerTests.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,22 @@ public async System.Threading.Tasks.Task Foo(MyClass m)
2323
";
2424
await VerifyCS.VerifyAsync(code);
2525
}
26-
}
26+
27+
[Test]
28+
public async Task No_Warn_When_Nullability_Is_Enabled()
29+
{
30+
// In this case the compiler will emit a warning.
31+
string code = @"
32+
#nullable enable
33+
public class MyClass
34+
{
35+
public async System.Threading.Tasks.Task Foo(MyClass? m)
36+
{
37+
await m?.Foo(null);
38+
}
39+
}
40+
";
41+
await VerifyCS.VerifyAsync(code);
42+
}
43+
}
2744
}

src/ErrorProne.NET.CoreAnalyzers/AsyncAnalyzers/NullConditionalOperatorAnalyzer.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.CodeAnalysis.CSharp;
44
using Microsoft.CodeAnalysis.CSharp.Syntax;
55
using Microsoft.CodeAnalysis.Diagnostics;
6+
using Microsoft.CodeAnalysis.Operations;
67

78
namespace ErrorProne.NET.AsyncAnalyzers
89
{
@@ -24,7 +25,26 @@ public NullConditionalOperatorAnalyzer()
2425
/// <inheritdoc />
2526
protected override void InitializeCore(AnalysisContext context)
2627
{
27-
context.RegisterSyntaxNodeAction(AnalyzeAwaitExpression, SyntaxKind.AwaitExpression);
28+
context.RegisterOperationAction(AnalyzeAwaitOperation, OperationKind.Await);
29+
//context.RegisterSyntaxNodeAction(AnalyzeAwaitExpression, SyntaxKind.AwaitExpression);
30+
}
31+
32+
private void AnalyzeAwaitOperation(OperationAnalysisContext context)
33+
{
34+
var operation = (IAwaitOperation) context.Operation;
35+
// Check if the awaited operation is a conditional access operation
36+
if (operation.Operation is IConditionalAccessOperation)
37+
{
38+
if (operation.Operation.Type?.NullableAnnotation == NullableAnnotation.Annotated)
39+
{
40+
// If the type is annotated, we don't report diagnostics.
41+
return;
42+
}
43+
44+
var location = operation.Syntax.GetLocation();
45+
var diagnostic = Diagnostic.Create(Rule, location);
46+
context.ReportDiagnostic(diagnostic);
47+
}
2848
}
2949

3050
private void AnalyzeAwaitExpression(SyntaxNodeAnalysisContext context)

src/ErrorProne.NET.CoreAnalyzers/DiagnosticDescriptors.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ internal static class DiagnosticDescriptors
303303
/// <nodoc />
304304
public static readonly DiagnosticDescriptor EPC37 = new DiagnosticDescriptor(
305305
nameof(EPC37),
306-
title: "Do not validate arguments in async methods",
306+
title: "Do not validate arguments in async methods eagerly",
307307
messageFormat: "Argument validation in async method '{0}' will not fail eagerly. Consider using a wrapper method or Task.FromException.",
308308
category: AsyncCategory,
309309
// Info by default, since it might generate quite a bit of warnings for a codebase.

0 commit comments

Comments
 (0)