Skip to content

Commit 63c67a1

Browse files
committed
CA1024: Do not report on awaitable-awaiter
1 parent bc278da commit 63c67a1

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/UsePropertiesWhereAppropriate.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ public override void Initialize(AnalysisContext analysisContext)
5656

5757
var taskTypes = taskTypesBuilder.ToImmutable();
5858

59+
var inotifyCompletionType = context.Compilation.GetOrCreateTypeByMetadataName(
60+
WellKnownTypeNames.SystemRuntimeCompilerServicesINotifyCompletion);
61+
var icriticalNotifyCompletionType = context.Compilation.GetOrCreateTypeByMetadataName(
62+
WellKnownTypeNames.SystemRuntimeCompilerServicesICriticalNotifyCompletion);
63+
5964
context.RegisterOperationBlockStartAction(context =>
6065
{
6166
if (context.OwningSymbol is not IMethodSymbol methodSymbol ||
@@ -73,14 +78,17 @@ public override void Initialize(AnalysisContext analysisContext)
7378
// Ensure that the method is non-generic, non-virtual/override, has no overloads and doesn't have special names: 'GetHashCode' or 'GetEnumerator'.
7479
// Also avoid generating this diagnostic if the method body has any invocation expressions.
7580
// Also avoid implicit interface implementation (explicit are handled through the member accessibility)
81+
// Also avoid GetAwaiter and GetResult from awaitable-awaiter patterns.
7682
if (methodSymbol.IsGenericMethod ||
7783
methodSymbol.IsVirtual ||
7884
methodSymbol.IsOverride ||
7985
methodSymbol.Name == GetHashCodeName ||
8086
methodSymbol.Name == GetEnumeratorName ||
8187
methodSymbol.ContainingType.GetMembers(methodSymbol.Name).Length > 1 ||
8288
taskTypes.Contains(methodSymbol.ReturnType.OriginalDefinition) ||
83-
methodSymbol.IsImplementationOfAnyImplicitInterfaceMember())
89+
methodSymbol.IsImplementationOfAnyImplicitInterfaceMember() ||
90+
methodSymbol.IsGetAwaiterFromAwaitablePattern(inotifyCompletionType, icriticalNotifyCompletionType) ||
91+
methodSymbol.IsGetResultFromAwaiterPattern(inotifyCompletionType, icriticalNotifyCompletionType))
8492
{
8593
return;
8694
}

src/NetAnalyzers/UnitTests/Microsoft.CodeQuality.Analyzers/ApiDesignGuidelines/UsePropertiesWhereAppropriateTests.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,65 @@ End Class
478478
");
479479
}
480480

481+
[Fact, WorkItem(4623, "https://github.com/dotnet/roslyn-analyzers/issues/4623")]
482+
public async Task AwaiterPattern_INotifyCompletion_NoDiagnostic()
483+
{
484+
await VerifyCS.VerifyAnalyzerAsync(@"
485+
using System;
486+
using System.Runtime.CompilerServices;
487+
488+
public class DummyAwaiter : INotifyCompletion
489+
{
490+
public object GetResult() => null;
491+
492+
public bool IsCompleted => false;
493+
494+
public void OnCompleted(Action continuation) => throw null;
495+
}");
496+
}
497+
498+
[Fact, WorkItem(4623, "https://github.com/dotnet/roslyn-analyzers/issues/4623")]
499+
public async Task AwaiterPattern_ICriticalNotifyCompletion_NoDiagnostic()
500+
{
501+
await VerifyCS.VerifyAnalyzerAsync(@"
502+
using System;
503+
using System.Runtime.CompilerServices;
504+
505+
public class DummyAwaiter : ICriticalNotifyCompletion
506+
{
507+
public object GetResult() => null;
508+
509+
public bool IsCompleted => false;
510+
511+
public void OnCompleted(Action continuation) => throw null;
512+
public void UnsafeOnCompleted(Action continuation) => throw null;
513+
}");
514+
}
515+
516+
[Fact, WorkItem(4623, "https://github.com/dotnet/roslyn-analyzers/issues/4623")]
517+
public async Task AwaitablePattern_NoDiagnostic()
518+
{
519+
await VerifyCS.VerifyAnalyzerAsync(@"
520+
using System;
521+
using System.Runtime.CompilerServices;
522+
523+
public class DummyAwaitable
524+
{
525+
public DummyAwaiter GetAwaiter() => new DummyAwaiter();
526+
}
527+
528+
public class DummyAwaiter : INotifyCompletion
529+
{
530+
public void GetResult()
531+
{
532+
}
533+
534+
public bool IsCompleted => false;
535+
536+
public void OnCompleted(Action continuation) => throw null;
537+
}");
538+
}
539+
481540
private static DiagnosticResult GetCA1024CSharpResultAt(int line, int column, string methodName)
482541
=> VerifyCS.Diagnostic()
483542
.WithLocation(line, column)

0 commit comments

Comments
 (0)