diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DisposableFieldsShouldBeDisposedTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DisposableFieldsShouldBeDisposedTests.cs
index b76092366e..3b8aa6afc1 100644
--- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DisposableFieldsShouldBeDisposedTests.cs
+++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DisposableFieldsShouldBeDisposedTests.cs
@@ -727,6 +727,45 @@ function DisposeAsync() as ValueTask implements IAsyncDisposable.DisposeAsync
return stream.DisposeAsync()
end function
end class
+"
+ }.RunAsync();
+
+ await new VerifyVB.Test
+ {
+ ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithAsyncInterfaces,
+ TestCode = @"
+Imports System
+Imports System.IO
+Imports System.Net.Http
+Imports System.Threading.Tasks
+
+class FileStream2
+ implements IAsyncDisposable
+ public function DisposeAsync() as ValueTask implements IAsyncDisposable.DisposeAsync
+ return nothing
+ end function
+end class
+
+public class Test
+ implements IAsyncDisposable, IDisposable
+
+ private readonly client as HttpClient
+ private readonly stream as FileStream2
+
+ public sub new()
+ client = new HttpClient
+ stream = new FileStream2
+ end sub
+
+ public sub Dispose() implements IDisposable.Dispose
+ client.Dispose()
+ end sub
+
+ rem arbitrary implementation name
+ function DisposeOtherAsync() as ValueTask implements IAsyncDisposable.DisposeAsync
+ return stream.DisposeAsync()
+ end function
+end class
"
}.RunAsync();
}
diff --git a/src/Utilities/Compiler/Extensions/IMethodSymbolExtensions.cs b/src/Utilities/Compiler/Extensions/IMethodSymbolExtensions.cs
index 37c015a102..3c9cd76252 100644
--- a/src/Utilities/Compiler/Extensions/IMethodSymbolExtensions.cs
+++ b/src/Utilities/Compiler/Extensions/IMethodSymbolExtensions.cs
@@ -219,19 +219,12 @@ public static bool IsAsyncDisposeImplementation([NotNullWhen(returnValue: true)]
method.IsImplementationOfInterfaceMethod(null, iAsyncDisposable, "DisposeAsync");
}
- ///
- /// Checks the name of the method of an implicit interface implementation (so, as is) or an explicit interface implementation (which also contains the interface as a prefix).
- ///
- private static bool IsImplicitOrExplicitInterfaceImplementationName(this IMethodSymbol method, string name, string interfacePrefix)
- => (method.Name == name && method.MethodKind is MethodKind.Ordinary) ||
- (method.Name == $"{interfacePrefix}.{name}" && method.MethodKind is MethodKind.ExplicitInterfaceImplementation);
-
///
/// Checks if the given method has the signature "void Dispose()".
///
private static bool HasDisposeMethodSignature(this IMethodSymbol method)
{
- return method.IsImplicitOrExplicitInterfaceImplementationName("Dispose", "System.IDisposable") &&
+ return method.Name == "Dispose" && method.MethodKind == MethodKind.Ordinary &&
method.ReturnsVoid && method.Parameters.IsEmpty;
}
@@ -250,7 +243,7 @@ public static bool HasDisposeSignatureByConvention(this IMethodSymbol method)
///
public static bool HasDisposeBoolMethodSignature(this IMethodSymbol method)
{
- if (method.IsImplicitOrExplicitInterfaceImplementationName("Dispose", "System.IDisposable") &&
+ if (method.Name == "Dispose" && method.MethodKind == MethodKind.Ordinary &&
method.ReturnsVoid && method.Parameters.Length == 1)
{
IParameterSymbol parameter = method.Parameters[0];
@@ -267,8 +260,7 @@ public static bool HasDisposeBoolMethodSignature(this IMethodSymbol method)
///
private static bool HasDisposeCloseMethodSignature(this IMethodSymbol method)
{
- return method.Name == "Close" &&
- method.MethodKind is MethodKind.Ordinary &&
+ return method.Name == "Close" && method.MethodKind == MethodKind.Ordinary &&
method.ReturnsVoid && method.Parameters.IsEmpty;
}
@@ -286,7 +278,8 @@ private static bool HasDisposeAsyncMethodSignature(this IMethodSymbol method,
INamedTypeSymbol? task,
INamedTypeSymbol? valueTask)
{
- return method.IsImplicitOrExplicitInterfaceImplementationName("DisposeAsync", "System.IAsyncDisposable") &&
+ return method.Name == "DisposeAsync" &&
+ method.MethodKind == MethodKind.Ordinary &&
method.Parameters.IsEmpty &&
(SymbolEqualityComparer.Default.Equals(method.ReturnType, task) ||
SymbolEqualityComparer.Default.Equals(method.ReturnType, valueTask));
@@ -298,7 +291,7 @@ private static bool HasDisposeAsyncMethodSignature(this IMethodSymbol method,
private static bool HasOverriddenDisposeCoreAsyncMethodSignature(this IMethodSymbol method, [NotNullWhen(returnValue: true)] INamedTypeSymbol? task)
{
return method.Name == "DisposeCoreAsync" &&
- method.MethodKind is MethodKind.Ordinary &&
+ method.MethodKind == MethodKind.Ordinary &&
method.IsOverride &&
SymbolEqualityComparer.Default.Equals(method.ReturnType, task) &&
method.Parameters.Length == 1 &&
@@ -344,7 +337,7 @@ public static DisposeMethodKind GetDisposeMethodKind(
{
return DisposeMethodKind.DisposeBool;
}
- else if (method.HasDisposeAsyncMethodSignature(task, valueTask))
+ else if (method.IsAsyncDisposeImplementation(iAsyncDisposable, valueTask) || method.HasDisposeAsyncMethodSignature(task, valueTask))
{
return DisposeMethodKind.DisposeAsync;
}