diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers/VSTHRD200UseAsyncNamingConventionAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers/VSTHRD200UseAsyncNamingConventionAnalyzer.cs index 9e5c92b5e..4b0a28cf2 100644 --- a/src/Microsoft.VisualStudio.Threading.Analyzers/VSTHRD200UseAsyncNamingConventionAnalyzer.cs +++ b/src/Microsoft.VisualStudio.Threading.Analyzers/VSTHRD200UseAsyncNamingConventionAnalyzer.cs @@ -72,6 +72,12 @@ private void AnalyzeNode(SymbolAnalysisContext context, CommonInterest.Awaitable return; } + // Skip the method of the recommended dispose pattern. + if (methodSymbol.Name == "DisposeAsyncCore") + { + return; + } + bool hasAsyncFocusedReturnType = Utils.HasAsyncCompatibleReturnType(methodSymbol); bool actuallyEndsWithAsync = methodSymbol.Name.EndsWith(MandatoryAsyncSuffix, StringComparison.CurrentCulture); diff --git a/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/VSTHRD200UseAsyncNamingConventionAnalyzerTests.cs b/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/VSTHRD200UseAsyncNamingConventionAnalyzerTests.cs index 6033b321f..c05cb25a8 100644 --- a/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/VSTHRD200UseAsyncNamingConventionAnalyzerTests.cs +++ b/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/VSTHRD200UseAsyncNamingConventionAnalyzerTests.cs @@ -558,6 +558,29 @@ public async Task TaskReturningPropertyWithoutSuffix_GeneratesNoWarning() class Test { Task Foo => null; } +"; + await CSVerify.VerifyAnalyzerAsync(test); + } + + [Fact] + public async Task MethodDisposeAsyncCore_GeneratesNoWarning() + { + var test = @" +using System; +using System.Threading.Tasks; + +class Test : IAsyncDisposable +{ + public async ValueTask DisposeAsync() + { + await DisposeAsyncCore().ConfigureAwait(false); + GC.SuppressFinalize(this); + } + + protected virtual async ValueTask DisposeAsyncCore() + { + } +} "; await CSVerify.VerifyAnalyzerAsync(test); }