Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracks disposed objects through implicit interface implementations #6147

Merged
merged 3 commits into from
Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,186 @@ End Function
}.RunAsync();
}

[Fact, WorkItem(6075, "https://github.com/dotnet/roslyn-analyzers/issues/6075")]
public async Task AsyncDisposableDisposedInExplicitAsyncDisposable_Disposed_NoDiagnosticAsync()
{
await new VerifyCS.Test
{
ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithAsyncInterfaces,
TestCode = @"
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

class FileStream2 : IAsyncDisposable
{
public ValueTask DisposeAsync() => default;
}

public sealed class Test : IAsyncDisposable, IDisposable
{
private readonly HttpClient client;
private readonly FileStream2 stream;

public Test()
{
client = new HttpClient();
stream = new FileStream2();
}

public void Dispose()
{
client.Dispose();
}

async ValueTask IAsyncDisposable.DisposeAsync()
{
await stream.DisposeAsync();
}
}
"
}.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

function DisposeAsync() as ValueTask implements IAsyncDisposable.DisposeAsync
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For VB, the implementing method name can be an arbitrary one, say

function DisposeSomethingAsync() as ValueTask implements IAsyncDisposable.DisposeAsync

Will your logic work for the above?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to add the test case for future reference.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh its been ages since I saw use of rem instead of the ' for VB comments :-)!! Good old days...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to google how to do a struct in VB, I haven't used it since like VB6 lol

function DisposeOtherAsync() as ValueTask implements IAsyncDisposable.DisposeAsync
return stream.DisposeAsync()
end function
end class
"
}.RunAsync();
}

[Fact, WorkItem(6075, "https://github.com/dotnet/roslyn-analyzers/issues/6075")]
public async Task DisposableDisposedInExplicitDisposable_Disposed_NoDiagnosticAsync()
{
await new VerifyCS.Test
{
ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithAsyncInterfaces,
TestCode = @"
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

public sealed class Test : IDisposable
{
private readonly HttpClient client;
private readonly FileStream stream;

public Test()
{
client = new HttpClient();
stream = new FileStream(""C://some-path"", FileMode.CreateNew);
}

void IDisposable.Dispose()
{
client.Dispose();
stream.Dispose();
}
}
"
}.RunAsync();

await new VerifyVB.Test
{
ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithAsyncInterfaces,
TestCode = @"
Imports System
Imports System.IO
Imports System.Net.Http
Imports System.Threading.Tasks

public class Test
implements IDisposable

private readonly client as HttpClient
private readonly stream as FileStream

public sub new()
client = new HttpClient
stream = new FileStream(""C://some-path"", FileMode.CreateNew)
end sub

public sub Dispose() implements IDisposable.Dispose
client.Dispose()
stream.Dispose()
end sub
end class
"
}.RunAsync();
}

[Fact]
public async Task DisposableAllocation_AssignedThroughLocal_Disposed_NoDiagnosticAsync()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,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;
}
Expand Down