File: Microsoft.NetCore.Analyzers\Runtime\DisposableTypesShouldDeclareFinalizerTests.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 Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
    Microsoft.NetCore.Analyzers.Runtime.DisposableTypesShouldDeclareFinalizerAnalyzer,
    Microsoft.NetCore.CSharp.Analyzers.Runtime.CSharpDisposableTypesShouldDeclareFinalizerFixer>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.NetCore.Analyzers.Runtime.DisposableTypesShouldDeclareFinalizerAnalyzer,
    Microsoft.NetCore.VisualBasic.Analyzers.Runtime.BasicDisposableTypesShouldDeclareFinalizerFixer>;
 
namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
{
    public class DisposableTypesShouldDeclareFinalizerTests
    {
        [Fact]
        public async Task CSharpDiagnosticIfIntPtrFieldIsAssignedFromNativeCodeAndNoFinalizerExistsAsync()
        {
            var code = @"
using System;
using System.Runtime.InteropServices;
 
internal static class NativeMethods
{
    [DllImport(""native.dll"")]
    internal static extern IntPtr AllocateResource();
}
 
public class A : IDisposable
{
    private readonly IntPtr _pi;
 
    public A()
    {
        _pi = NativeMethods.AllocateResource();
    }
 
    public void Dispose()
    {
    }
}
";
            await VerifyCS.VerifyAnalyzerAsync(code,
                GetCSharpDiagnostic(11, 14));
        }
 
        [Fact]
        public async Task BasicDiagnosticIfIntPtrFieldIsAssignedFromNativeCodeAndNoFinalizerExistsAsync()
        {
            var code = @"
Imports System
Imports System.Runtime.InteropServices
 
Friend Class NativeMethods
    <DllImport(""native.dll"")>
    Friend Shared Function AllocateResource() As IntPtr
    End Function
End Class
 
Public Class A
    Implements IDisposable
 
    Private ReadOnly _pi As IntPtr
 
    Public Sub New()
        _pi = NativeMethods.AllocateResource()
    End Sub
 
    Public Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
";
            await VerifyVB.VerifyAnalyzerAsync(code,
                GetBasicDiagnostic(11, 14));
        }
 
        [Fact]
        public async Task CSharpNoDiagnosticIfIntPtrFieldIsAssignedFromNativeCodeAndFinalizerExistsAsync()
        {
            var code = @"
using System;
using System.Runtime.InteropServices;
 
internal static class NativeMethods
{
    [DllImport(""native.dll"")]
    internal static extern IntPtr AllocateResource();
}
 
public class A : IDisposable
{
    private readonly IntPtr _pi;
 
    public A()
    {
        _pi = NativeMethods.AllocateResource();
    }
 
    public void Dispose()
    {
    }
 
    ~A()
    {
    }
}
";
            await VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Fact]
        public async Task BasicNoDiagnosticIfIntPtrFieldIsAssignedFromNativeCodeAndFinalizerExistsAsync()
        {
            var code = @"
Imports System
Imports System.Runtime.InteropServices
 
Friend Class NativeMethods
    <DllImport(""native.dll"")>
    Friend Shared Function AllocateResource() As IntPtr
    End Function
End Class
 
Public Class A
    Implements IDisposable
 
    Private ReadOnly _pi As IntPtr
 
    Public Sub New()
        _pi = NativeMethods.AllocateResource()
    End Sub
 
    Public Sub Dispose() Implements IDisposable.Dispose
    End Sub
 
    Protected Overrides Sub Finalize()
    End Sub
End Class
";
            await VerifyVB.VerifyAnalyzerAsync(code);
        }
 
        [Fact]
        public async Task CSharpNoDiagnosticIfIntPtrFieldInValueTypeIsAssignedFromNativeCodeAsync()
        {
            var code = @"
using System;
using System.Runtime.InteropServices;
 
internal static class NativeMethods
{
    [DllImport(""native.dll"")]
    internal static extern IntPtr AllocateResource();
}
 
public struct A : IDisposable // Although disposable structs are evil
{
    private readonly IntPtr _pi;
 
    public A(int i)
    {
        _pi = NativeMethods.AllocateResource();
    }
 
    public void Dispose()
    {
    }
}
";
            await VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Fact]
        public async Task BasicNoDiagnosticIfIntPtrFieldInValueTypeIsAssignedFromNativeCodeAsync()
        {
            var code = @"
Imports System
Imports System.Runtime.InteropServices
 
Friend Class NativeMethods
    <DllImport(""native.dll"")>
    Friend Shared Function AllocateResource() As IntPtr
    End Function
End Class
 
Public Structure A
    Implements IDisposable ' Although disposable structs are evil
 
    Private ReadOnly _pi As IntPtr
 
    Public Sub New(i As Integer)
        _pi = NativeMethods.AllocateResource()
    End Sub
 
    Public Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Structure
";
            await VerifyVB.VerifyAnalyzerAsync(code);
        }
 
        [Fact]
        public async Task CSharpNoDiagnosticIfIntPtrFieldInNonDisposableTypeIsAssignedFromNativeCodeAsync()
        {
            var code = @"
using System;
using System.Runtime.InteropServices;
 
internal static class NativeMethods
{
    [DllImport(""native.dll"")]
    internal static extern IntPtr AllocateResource();
}
 
public class A
{
    private readonly IntPtr _pi;
 
    public A()
    {
        _pi = NativeMethods.AllocateResource();
    }
}
";
            await VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Fact]
        public async Task BasicNoDiagnosticIfIntPtrFieldInNonDisposableTypeIsAssignedFromNativeCodeAsync()
        {
            var code = @"
Imports System
Imports System.Runtime.InteropServices
 
Friend Class NativeMethods
    <DllImport(""native.dll"")>
    Friend Shared Function AllocateResource() As IntPtr
    End Function
End Class
 
Public Class A
    Private ReadOnly _pi As IntPtr
 
    Public Sub New()
        _pi = NativeMethods.AllocateResource()
    End Sub
 
    Public Sub Dispose()
    End Sub
End Class
";
            await VerifyVB.VerifyAnalyzerAsync(code);
        }
 
        [Fact]
        public async Task CSharpNoDiagnosticIfIntPtrFieldIsAssignedFromManagedCodeAsync()
        {
            var code = @"
using System;
 
internal static class ManagedMethods
{
    internal static IntPtr AllocateResource()
    {
        return IntPtr.Zero;
    }
}
 
public class A : IDisposable
{
    private readonly IntPtr _pi;
 
    public A()
    {
        _pi = ManagedMethods.AllocateResource();
    }
 
    public void Dispose()
    {
    }
}
";
            await VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Fact]
        public async Task BasicNoDiagnosticIfIntPtrFieldIsAssignedFromManagedCodeAsync()
        {
            var code = @"
Imports System
 
Friend NotInheritable Class ManagedMethods
    Friend Shared Function AllocateResource() As IntPtr
        Return IntPtr.Zero
    End Function
End Class
 
Public Class A
    Implements IDisposable
 
    Private ReadOnly _pi As IntPtr
 
    Public Sub New()
        _pi = ManagedMethods.AllocateResource()
    End Sub
 
    Public Overloads Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
";
            await VerifyVB.VerifyAnalyzerAsync(code);
        }
 
        [Fact]
        public async Task CSharpDiagnosticIfUIntPtrFieldIsAssignedFromNativeCodeAsync()
        {
            var code = @"
using System;
using System.Runtime.InteropServices;
 
internal static class NativeMethods
{
    [DllImport(""native.dll"")]
    internal static extern UIntPtr AllocateResource();
}
 
public class A : IDisposable
{
    private readonly UIntPtr _pu;
 
    public A()
    {
        _pu = NativeMethods.AllocateResource();
    }
 
    public void Dispose()
    {
    }
}
";
            await VerifyCS.VerifyAnalyzerAsync(code,
                GetCSharpDiagnostic(11, 14));
        }
 
        [Fact]
        public async Task BasicDiagnosticIfUIntPtrFieldIsAssignedFromNativeCodeAsync()
        {
            var code = @"
Imports System
Imports System.Runtime.InteropServices
 
Friend Class NativeMethods
    <DllImport(""native.dll"")>
    Friend Shared Function AllocateResource() As UIntPtr
    End Function
End Class
 
Public Class A
    Implements IDisposable
 
    Private ReadOnly _pu As UIntPtr
 
    Public Sub New()
        _pu = NativeMethods.AllocateResource()
    End Sub
 
    Public Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
";
            await VerifyVB.VerifyAnalyzerAsync(code,
                GetBasicDiagnostic(11, 14));
        }
 
        [Fact]
        public async Task CSharpDiagnosticIfHandleRefFieldIsAssignedFromNativeCodeAsync()
        {
            var code = @"
using System;
using System.Runtime.InteropServices;
 
internal static class NativeMethods
{
    [DllImport(""native.dll"")]
    internal static extern HandleRef AllocateResource();
}
 
public class A : IDisposable
{
    private readonly HandleRef _hr;
 
    public A()
    {
        _hr = NativeMethods.AllocateResource();
    }
 
    public void Dispose()
    {
    }
}
";
            await VerifyCS.VerifyAnalyzerAsync(code,
                GetCSharpDiagnostic(11, 14));
        }
 
        [Fact]
        public async Task BasicDiagnosticIfHandleRefFieldIsAssignedFromNativeCodeAsync()
        {
            var code = @"
Imports System
Imports System.Runtime.InteropServices
 
Friend Class NativeMethods
    <DllImport(""native.dll"")>
    Friend Shared Function AllocateResource() As HandleRef
    End Function
End Class
 
Public Class A
    Implements IDisposable
 
    Private ReadOnly _hr As HandleRef
 
    Public Sub New()
        _hr = NativeMethods.AllocateResource()
    End Sub
 
    Public Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
";
            await VerifyVB.VerifyAnalyzerAsync(code,
                GetBasicDiagnostic(11, 14));
        }
 
        [Fact]
        public async Task CSharpNoDiagnosticIfNonNativeResourceFieldIsAssignedFromNativeCodeAsync()
        {
            var code = @"
using System;
using System.Runtime.InteropServices;
 
internal static class NativeMethods
{
    [DllImport(""native.dll"")]
    internal static extern int AllocateResource();
}
 
public class A : IDisposable
{
    private readonly int _i;
 
    public A()
    {
        _i = NativeMethods.AllocateResource();
    }
 
    public void Dispose()
    {
    }
}
";
            await VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Fact]
        public async Task BasicNoDiagnosticIfNonNativeResourceFieldIsAssignedFromNativeCodeAsync()
        {
            var code = @"
Imports System
Imports System.Runtime.InteropServices
 
Friend Class NativeMethods
    <DllImport(""native.dll"")>
    Friend Shared Function AllocateResource() As Integer
    End Function
End Class
 
Public Class A
    Implements IDisposable
 
    Private ReadOnly _i As Integer
 
    Public Sub New()
        _i = NativeMethods.AllocateResource()
    End Sub
 
    Public Sub Dispose() Implements IDisposable.Dispose
    End Sub
End Class
";
            await VerifyVB.VerifyAnalyzerAsync(code);
        }
 
        private static DiagnosticResult GetCSharpDiagnostic(int line, int column) =>
#pragma warning disable RS0030 // Do not use banned APIs
            VerifyCS.Diagnostic().WithLocation(line, column);
#pragma warning restore RS0030 // Do not use banned APIs
 
        private static DiagnosticResult GetBasicDiagnostic(int line, int column) =>
#pragma warning disable RS0030 // Do not use banned APIs
            VerifyVB.Diagnostic().WithLocation(line, column);
#pragma warning restore RS0030 // Do not use banned APIs
    }
}