File: Microsoft.NetCore.Analyzers\Runtime\DisposeMethodsShouldCallBaseClassDisposeTests.cs
Web Access
Project: ..\..\..\src\Microsoft.CodeAnalysis.NetAnalyzers\tests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests.csproj (Microsoft.CodeAnalysis.NetAnalyzers.UnitTests)
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the MIT license.  See License.txt in the project root for license information.
 
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
using Test.Utilities;
using Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
    Microsoft.NetCore.Analyzers.Runtime.DisposeMethodsShouldCallBaseClassDispose,
    Microsoft.NetCore.CSharp.Analyzers.Runtime.CSharpDisposeMethodsShouldCallBaseClassDisposeFixer>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.NetCore.Analyzers.Runtime.DisposeMethodsShouldCallBaseClassDispose,
    Microsoft.NetCore.VisualBasic.Analyzers.Runtime.BasicDisposeMethodsShouldCallBaseClassDisposeFixer>;
 
namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
{
    public class DisposeMethodsShouldCallBaseClassDisposeTests
    {
        private static DiagnosticResult GetCSharpResultAt(int line, int column, params string[] arguments)
#pragma warning disable RS0030 // Do not use banned APIs
           => VerifyCS.Diagnostic()
               .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
               .WithArguments(arguments);
 
        private static DiagnosticResult GetBasicResultAt(int line, int column, params string[] arguments)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyVB.Diagnostic()
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(arguments);
 
        [Fact]
        public async Task NoBaseDisposeImplementation_NoBaseDisposeCall_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A 
{
}
 
class B : A, IDisposable
{
    public void Dispose()
    {
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
End Class
 
Class B
    Inherits A
    Implements IDisposable
 
    Public Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class");
        }
 
        [Fact]
        public async Task NoBaseDisposeImplementation_NoBaseDisposeCall_02_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A 
{
    public virtual void Dispose()
    {
    }
}
 
class B : A, IDisposable
{
    public override void Dispose()
    {
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Public Overridable Sub Dispose()
    End Sub
End Class
 
Class B
    Inherits A
    Implements IDisposable
 
    Public Overrides Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class");
        }
 
        [Fact]
        public async Task BaseDisposeCall_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
}
 
class B : A
{
    public override void Dispose()
    {
        base.Dispose();
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Dispose()
        MyBase.Dispose()
    End Sub
End Class");
        }
 
        [Fact]
        public async Task NoBaseDisposeCall_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
}
 
class B : A
{
    public override void Dispose()
    {
    }
}
",
            // Test0.cs(13,26): warning CA2215: Ensure that method 'void B.Dispose()' calls 'base.Dispose()' in all possible control flow paths.
            GetCSharpResultAt(13, 26, "void B.Dispose()", "base.Dispose()"));
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Dispose()
    End Sub
End Class",
            // Test0.vb(14,26): warning CA2215: Ensure that method 'Sub B.Dispose()' calls 'MyBase.Dispose()' in all possible control flow paths.
            GetBasicResultAt(14, 26, "Sub B.Dispose()", "MyBase.Dispose()"));
        }
 
        [Fact]
        public async Task BaseDisposeCall_IgnoreCase_VB_NoDiagnosticAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Dispose()
        myBasE.Dispose()
    End Sub
End Class");
        }
 
        [Fact]
        public async Task BaseDisposeBoolCall_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose(bool b)
    {
    }
 
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}
 
class B : A
{
    public override void Dispose(bool b)
    {
        base.Dispose(b);
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose(b As Boolean)
    End Sub
 
    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Dispose(b As Boolean)
        MyBase.Dispose(b)
    End Sub
End Class");
        }
 
        [Fact]
        public async Task NoBaseDisposeBoolCall_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose(bool b)
    {
    }
 
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}
 
class B : A
{
    public override void Dispose(bool b)
    {
    }
}
",
            // Test0.cs(19,26): warning CA2215: Ensure that method 'void B.Dispose(bool b)' calls 'base.Dispose(bool)' in all possible control flow paths.
            GetCSharpResultAt(19, 26, "void B.Dispose(bool b)", "base.Dispose(bool)"));
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose(b As Boolean)
    End Sub
 
    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Dispose(b As Boolean)
    End Sub
End Class",
            // Test0.vb(19,26): warning CA2215: Ensure that method 'Sub B.Dispose(b As Boolean)' calls 'MyBase.Dispose(Boolean)' in all possible control flow paths.
            GetBasicResultAt(19, 26, "Sub B.Dispose(b As Boolean)", "MyBase.Dispose(Boolean)"));
        }
 
        [Fact]
        public async Task NoBaseDisposeCloseCall_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Close()
    {
    }
 
    public void Dispose()
    {
        Close();
        GC.SuppressFinalize(this);
    }
}
 
class B : A
{
    public override void Close()
    {
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Close()
    End Sub
 
    Public Sub Dispose() Implements IDisposable.Dispose
        Close()
        GC.SuppressFinalize(Me)
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Close()
    End Sub
End Class");
        }
 
        [Fact, WorkItem(1796, "https://github.com/dotnet/roslyn-analyzers/issues/1796")]
        public async Task BaseDisposeAsyncCall_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
using System.Threading.Tasks;
 
class A : IDisposable
{
    public void Dispose() => DisposeAsync();
 
    public virtual Task DisposeAsync()
    {
        return Task.CompletedTask;
    }
}
 
class B : A
{
    public override Task DisposeAsync()
    {
        return base.DisposeAsync();
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
Imports System.Threading.Tasks
 
Class A
    Implements IDisposable
 
    Public Sub Dispose() Implements IDisposable.Dispose
        DisposeAsync()
    End Sub
 
    Public Overridable Function DisposeAsync() As Task
        Return Task.CompletedTask
    End Function
End Class
 
Class B
    Inherits A
 
    Public Overrides Function DisposeAsync() As Task
        Return MyBase.DisposeAsync()
    End Function
End Class");
        }
 
        [Fact, WorkItem(1796, "https://github.com/dotnet/roslyn-analyzers/issues/1796")]
        public async Task NoBaseDisposeAsyncCall_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
using System.Threading.Tasks;
 
class A : IDisposable
{
    public void Dispose() => DisposeAsync();
 
    public virtual Task DisposeAsync()
    {
        return Task.CompletedTask;
    }
}
 
class B : A
{
    public override Task DisposeAsync()
    {
        return Task.CompletedTask;
    }
}
",
            // Test0.cs(17,26): warning CA2215: Ensure that method 'Task B.DisposeAsync()' calls 'base.DisposeAsync()' in all possible control flow paths.
            GetCSharpResultAt(17, 26, "Task B.DisposeAsync()", "base.DisposeAsync()"));
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
Imports System.Threading.Tasks
 
Class A
    Implements IDisposable
 
    Public Sub Dispose() Implements IDisposable.Dispose
        DisposeAsync()
    End Sub
 
    Public Overridable Function DisposeAsync() As Task
        Return Task.CompletedTask
    End Function
End Class
 
Class B
    Inherits A
 
    Public Overrides Function DisposeAsync() As Task
        Return Task.CompletedTask
    End Function
End Class",
            // Test0.vb(20,31): warning CA2215: Ensure that method 'Function B.DisposeAsync() As Task' calls 'MyBase.DisposeAsync()' in all possible control flow paths.
            GetBasicResultAt(20, 31, "Function B.DisposeAsync() As Task", "MyBase.DisposeAsync()"));
        }
 
        [Fact, WorkItem(1796, "https://github.com/dotnet/roslyn-analyzers/issues/1796")]
        public async Task BaseDisposeCoreAsyncCall_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
using System.Threading.Tasks;
 
abstract class A : IDisposable
{
    public void Dispose() => DisposeAsync();
 
    public Task DisposeAsync() => DisposeCoreAsync(true);
 
    protected abstract Task DisposeCoreAsync(bool initialized);
}
 
class B : A
{
    protected override Task DisposeCoreAsync(bool initialized)
    {
        return Task.CompletedTask;
    }
}
 
class C : B
{
    protected override Task DisposeCoreAsync(bool initialized)
    {
        return base.DisposeCoreAsync(initialized);
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
Imports System.Threading.Tasks
 
MustInherit Class A
    Implements IDisposable
 
    Public Sub Dispose() Implements IDisposable.Dispose
        DisposeAsync()
    End Sub
 
    Public Function DisposeAsync() As Task
        Return DisposeCoreAsync(True)
    End Function
 
    Protected MustOverride Function DisposeCoreAsync(initialized As Boolean) As Task
End Class
 
Class B
    Inherits A
 
    Protected Overrides Function DisposeCoreAsync(initialized As Boolean) As Task
        Return Task.CompletedTask
    End Function
End Class
 
Class C
    Inherits B
 
    Protected Overrides Function DisposeCoreAsync(initialized As Boolean) As Task
        Return MyBase.DisposeCoreAsync(initialized)
    End Function
End Class");
        }
 
        [Fact, WorkItem(1796, "https://github.com/dotnet/roslyn-analyzers/issues/1796")]
        public async Task NoBaseDisposeCoreAsyncCall_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
using System.Threading.Tasks;
 
abstract class A : IDisposable
{
    public void Dispose() => DisposeAsync();
 
    public Task DisposeAsync() => DisposeCoreAsync(true);
 
    protected abstract Task DisposeCoreAsync(bool initialized);
}
 
class B : A
{
    protected override Task DisposeCoreAsync(bool initialized)
    {
        return Task.CompletedTask;
    }
}
 
class C : B
{
    protected override Task DisposeCoreAsync(bool initialized)
    {
        return Task.CompletedTask;
    }
}
",
            // Test0.cs(24,29): warning CA2215: Ensure that method 'Task C.DisposeCoreAsync(bool initialized)' calls 'base.DisposeCoreAsync(bool)' in all possible control flow paths.
            GetCSharpResultAt(24, 29, "Task C.DisposeCoreAsync(bool initialized)", "base.DisposeCoreAsync(bool)"));
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
Imports System.Threading.Tasks
 
MustInherit Class A
    Implements IDisposable
 
    Public Sub Dispose() Implements IDisposable.Dispose
        DisposeAsync()
    End Sub
 
    Public Function DisposeAsync() As Task
        Return DisposeCoreAsync(True)
    End Function
 
    Protected MustOverride Function DisposeCoreAsync(initialized As Boolean) As Task
End Class
 
Class B
    Inherits A
 
    Protected Overrides Function DisposeCoreAsync(initialized As Boolean) As Task
        Return Task.CompletedTask
    End Function
End Class
 
Class C
    Inherits B
 
    Protected Overrides Function DisposeCoreAsync(initialized As Boolean) As Task
        Return Task.CompletedTask
    End Function
End Class",
            // Test0.vb(30,34): warning CA2215: Ensure that method 'Function C.DisposeCoreAsync(initialized As Boolean) As Task' calls 'MyBase.DisposeCoreAsync(Boolean)' in all possible control flow paths.
            GetBasicResultAt(30, 34, "Function C.DisposeCoreAsync(initialized As Boolean) As Task", "MyBase.DisposeCoreAsync(Boolean)"));
        }
 
        [Fact]
        public async Task AbstractBaseDisposeMethod_NoBaseDisposeCall_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
abstract class A : IDisposable
{
    public abstract void Dispose();
}
 
class B : A
{
    public override void Dispose()
    {
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
MustInherit Class A
    Implements IDisposable
 
    Public MustOverride Sub Dispose() Implements IDisposable.Dispose
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Dispose()
    End Sub
End Class");
        }
 
        [Fact]
        public async Task ShadowsBaseDisposeMethod_NoBaseDisposeCall_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
}
 
class B : A
{
    public new void Dispose()
    {
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Shadows Sub Dispose()
    End Sub
End Class");
        }
 
        [Fact]
        public async Task Multiple_BaseDisposeCalls_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
}
 
class B : A
{
    public override void Dispose()
    {
        base.Dispose();
        base.Dispose();
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Dispose()
        MyBase.Dispose()
        MyBase.Dispose()
    End Sub
End Class");
        }
 
        [Fact]
        public async Task BaseDisposeCalls_AllPaths_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
}
 
class B : A
{
    private readonly bool flag;
    public override void Dispose()
    {
        if (flag)
        {
            base.Dispose();
        }
        else
        {
            base.Dispose();
        }
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
 
Class B
    Inherits A
 
    Private ReadOnly flag As Boolean
    Public Overrides Sub Dispose()
        If flag Then
            MyBase.Dispose()
        Else 
            MyBase.Dispose()
        End If
    End Sub
End Class");
        }
 
        [Fact(Skip = "Analyzer isn't yet flow based."), WorkItem(1654, "https://github.com/dotnet/roslyn-analyzers/issues/1654")]
        public async Task BaseDisposeCalls_SomePaths_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
}
 
class B : A
{
    private readonly A a;
    public override void Dispose()
    {
        if (a != null)
        {
            base.Dispose();
        }
    }
}
",
            // Test0.cs(14,26): warning CA2215: Ensure that method 'void B.Dispose()' calls 'base.Dispose()' in all possible control flow paths.
            GetCSharpResultAt(14, 26, "void B.Dispose()", "base.Dispose()"));
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
 
Class B
    Inherits A
 
    Private ReadOnly a As A
    Public Overrides Sub Dispose()
        If a IsNot Nothing Then
            MyBase.Dispose()
        End If
    End Sub
End Class",
            // Test0.vb(15,26): warning CA2215: Ensure that method 'Sub B.Dispose()' calls 'MyBase.Dispose()' in all possible control flow paths.
            GetBasicResultAt(15, 26, "Sub B.Dispose()", "MyBase.Dispose()"));
        }
 
        [Fact]
        public async Task BaseDisposeCall_GuardedWithBoolField_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
}
 
class B : A
{
    private bool disposed;
 
    public override void Dispose()
    {
        if (disposed)
        {
            return;
        }
 
        base.Dispose();
        disposed = true;
    }
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
 
Class B
    Inherits A
 
    Private disposed As Boolean
 
    Public Overrides Sub Dispose()
        If disposed Then
            Return
        End If
 
        MyBase.Dispose()
        disposed = True
    End Sub
End Class");
        }
 
        [Fact]
        public async Task BaseDisposeCall_DifferentOverload_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
 
    public void Dispose(int i)
    {
    }
}
 
class B : A
{
    public override void Dispose()
    {
        Dispose(0);
    }
}
",
            // Test0.cs(17,26): warning CA2215: Ensure that method 'void B.Dispose()' calls 'base.Dispose()' in all possible control flow paths.
            GetCSharpResultAt(17, 26, "void B.Dispose()", "base.Dispose()"));
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
 
    Public Overridable Sub Dispose(i As Integer)
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Dispose()
        Dispose(0)
    End Sub
End Class",
            // Test0.vb(17,26): warning CA2215: Ensure that method 'Sub B.Dispose()' calls 'MyBase.Dispose()' in all possible control flow paths.
            GetBasicResultAt(17, 26, "Sub B.Dispose()", "MyBase.Dispose()"));
        }
 
        [Fact]
        public async Task DisposeCall_DifferentInstance_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
}
 
class B : A
{
    private readonly A a;
    public override void Dispose()
    {
        a.Dispose();
    }
}
",
            // Test0.cs(14,26): warning CA2215: Ensure that method 'void B.Dispose()' calls 'base.Dispose()' in all possible control flow paths.
            GetCSharpResultAt(14, 26, "void B.Dispose()", "base.Dispose()"));
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
 
Class B
    Inherits A
 
    Private ReadOnly a As A
    Public Overrides Sub Dispose()
        a.Dispose()
    End Sub
End Class",
            // Test0.vb(15,26): warning CA2215: Ensure that method 'Sub B.Dispose()' calls 'MyBase.Dispose()' in all possible control flow paths.
            GetBasicResultAt(15, 26, "Sub B.Dispose()", "MyBase.Dispose()"));
        }
 
        [Fact]
        public async Task DisposeCall_StaticMethod_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
 
    public static void Dispose(bool b)
    {
    }
}
 
class B : A
{
    public override void Dispose()
    {
        A.Dispose(true);
    }
}
",
            // Test0.cs(17,26): warning CA2215: Ensure that method 'void B.Dispose()' calls 'base.Dispose()' in all possible control flow paths.
            GetCSharpResultAt(17, 26, "void B.Dispose()", "base.Dispose()"));
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
 
    Public Shared Sub Dispose(b As Boolean)
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Dispose()
        A.Dispose(True)
    End Sub
End Class",
            // Test0.vb(17,26): warning CA2215: Ensure that method 'Sub B.Dispose()' calls 'MyBase.Dispose()' in all possible control flow paths.
            GetBasicResultAt(17, 26, "Sub B.Dispose()", "MyBase.Dispose()"));
        }
 
        [Fact]
        public async Task DisposeCall_ThisOrMeInstance_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
class A : IDisposable
{
    public virtual void Dispose()
    {
    }
}
 
class B : A
{
    public override void Dispose()
    {
        this.Dispose();
    }
}
",
            // Test0.cs(13,26): warning CA2215: Ensure that method 'void B.Dispose()' calls 'base.Dispose()' in all possible control flow paths.
            GetCSharpResultAt(13, 26, "void B.Dispose()", "base.Dispose()"));
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Class A
    Implements IDisposable
 
    Public Overridable Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
 
Class B
    Inherits A
 
    Public Overrides Sub Dispose()
        Me.Dispose()
    End Sub
End Class",
            // Test0.vb(14,26): warning CA2215: Ensure that method 'Sub B.Dispose()' calls 'MyBase.Dispose()' in all possible control flow paths.
            GetBasicResultAt(14, 26, "Sub B.Dispose()", "MyBase.Dispose()"));
        }
    }
}