diff --git a/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs b/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs index 1e08f04434d7a..26129c6aecd02 100644 --- a/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs +++ b/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs @@ -86,9 +86,6 @@ internal static class EnforceOnBuildValues public const EnforceOnBuild ExpressionValueIsUnused = /*IDE0058*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild MakeStructFieldsWritable = /*IDE0064*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild ConvertSwitchStatementToExpression = /*IDE0066*/ EnforceOnBuild.WhenExplicitlyEnabled; - public const EnforceOnBuild DisposeObjectsBeforeLosingScope = /*IDE0067*/ EnforceOnBuild.WhenExplicitlyEnabled; - public const EnforceOnBuild UseRecommendedDisposePattern = /*IDE0068*/ EnforceOnBuild.WhenExplicitlyEnabled; - public const EnforceOnBuild DisposableFieldsShouldBeDisposed = /*IDE0069*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild PopulateSwitchExpression = /*IDE0072*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild Regex = /*RE0001*/ EnforceOnBuild.WhenExplicitlyEnabled; diff --git a/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs b/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs index 6617c2e770323..70e761f1dc2f6 100644 --- a/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs +++ b/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs @@ -113,9 +113,10 @@ internal static class IDEDiagnosticIds public const string ConvertSwitchStatementToExpressionDiagnosticId = "IDE0066"; - public const string DisposeObjectsBeforeLosingScopeDiagnosticId = "IDE0067"; - public const string UseRecommendedDisposePatternDiagnosticId = "IDE0068"; - public const string DisposableFieldsShouldBeDisposedDiagnosticId = "IDE0069"; + // IDE0067-IDE0069 deprecated in favor of CA2000 and CA2213 + // public const string DisposeObjectsBeforeLosingScopeDiagnosticId = "IDE0067"; + // public const string UseRecommendedDisposePatternDiagnosticId = "IDE0068"; + // public const string DisposableFieldsShouldBeDisposedDiagnosticId = "IDE0069"; public const string UseSystemHashCode = "IDE0070"; diff --git a/src/EditorFeatures/CSharpTest/DisposeAnalysis/DisposableFieldsShouldBeDisposedTests.cs b/src/EditorFeatures/CSharpTest/DisposeAnalysis/DisposableFieldsShouldBeDisposedTests.cs deleted file mode 100644 index e908249ee3525..0000000000000 --- a/src/EditorFeatures/CSharpTest/DisposeAnalysis/DisposableFieldsShouldBeDisposedTests.cs +++ /dev/null @@ -1,1486 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.DisposeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Test.Utilities; -using Xunit; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics; -using static Roslyn.Test.Utilities.TestHelpers; -using Roslyn.Test.Utilities; -using Microsoft.CodeAnalysis.CSharp; -using Xunit.Abstractions; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.DisposeAnalysis -{ - [Trait(Traits.Feature, Traits.Features.DisposeAnalysis)] - public sealed class DisposableFieldsShouldBeDisposedTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest - { - public DisposableFieldsShouldBeDisposedTests(ITestOutputHelper logger) - : base(logger) - { - } - - internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) - => (new DisposableFieldsShouldBeDisposedDiagnosticAnalyzer(isEnabledByDefault: true), null); - - private Task TestDiagnosticsAsync(string initialMarkup, params DiagnosticDescription[] expectedDiagnostics) - => TestDiagnosticsAsync(initialMarkup, parseOptions: null, expectedDiagnostics); - private Task TestDiagnosticsAsync(string initialMarkup, CSharpParseOptions parseOptions, params DiagnosticDescription[] expectedDiagnostics) - => TestDiagnosticsAsync(initialMarkup, new TestParameters(parseOptions, retainNonFixableDiagnostics: true), expectedDiagnostics); - private Task TestDiagnosticMissingAsync(string initialMarkup, CSharpParseOptions parseOptions = null) - => TestDiagnosticMissingAsync(initialMarkup, new TestParameters(parseOptions, retainNonFixableDiagnostics: true)); - - [Fact] - public async Task DisposableAllocationInConstructor_AssignedDirectly_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private readonly A a;|] - public B() - { - a = new A(); - } - - public void Dispose() - { - a.Dispose(); - } -} -"); - } - - [Fact] - public async Task DisposableAllocationInConstructor_AssignedDirectly_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - private readonly A [|a|]; - public B() - { - a = new A(); - } - - public void Dispose() - { - } -} -", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)); - } - - [Fact] - public async Task DisposableAllocationInMethod_AssignedDirectly_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a;|] - public void SomeMethod() - { - a = new A(); - } - - public void Dispose() - { - a.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocationInMethod_AssignedDirectly_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - private A [|a|]; - public void SomeMethod() - { - a = new A(); - } - - public void Dispose() - { - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)); - } - - [Fact] - public async Task DisposableAllocationInFieldInitializer_AssignedDirectly_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a = new A(); - private readonly A a2 = new A();|] - - public void Dispose() - { - a.Dispose(); - a2.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocationInFieldInitializer_AssignedDirectly_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a = new A(); - private readonly A a2 = new A();|] - - public void Dispose() - { - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId, "a").WithLocation(13, 15), - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId, "a2").WithLocation(14, 24)); - } - - [Fact] - public async Task StaticField_NotDisposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private static A a = new A(); - private static readonly A a2 = new A();|] - - public void Dispose() - { - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AssignedThroughLocal_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a;|] - public void SomeMethod() - { - var l = new A(); - a = l; - } - - public void Dispose() - { - a.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AssignedThroughLocal_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - private A [|a|]; - public void SomeMethod() - { - var l = new A(); - a = l; - } - - public void Dispose() - { - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)); - } - - [Fact] - public async Task DisposableAllocation_AssignedThroughParameter_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a;|] - public B(A p) - { - p = new A(); - a = p; - } - - public void Dispose() - { - a.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AssignedThroughParameter_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - private A [|a|]; - public B(A p) - { - p = new A(); - a = p; - } - - public void Dispose() - { - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)); - } - - [Fact] - public async Task DisposableSymbolWithoutAllocation_AssignedThroughParameter_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a;|] - public B(A p) - { - a = p; - } - - public void Dispose() - { - a.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableSymbolWithoutAllocation_AssignedThroughParameter_NotDisposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a;|] - public B(A p) - { - a = p; - } - - public void Dispose() - { - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AssignedThroughInstanceInvocation_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a;|] - public B() - { - a = GetA(); - } - - private A GetA() => new A(); - - public void Dispose() - { - a.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AssignedThroughInstanceInvocation_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - private A [|a|]; - public B() - { - a = GetA(); - } - - private A GetA() => new A(); - - public void Dispose() - { - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)); - } - - [Fact] - public async Task DisposableAllocation_AssignedThroughStaticCreateInvocation_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a;|] - public B() - { - a = Create(); - } - - private static A Create() => new A(); - - public void Dispose() - { - a.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AssignedThroughStaticCreateInvocation_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - private A [|a|]; - public B() - { - a = Create(); - } - - private static A Create() => new A(); - - public void Dispose() - { - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)); - } - - [Fact] - public async Task DisposableAllocation_AssignedInDifferentType_DisposedInContainingType_NoDiagnostic() - { - // We don't track disposable field assignments in different type. - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|public A a;|] - public void Dispose() - { - a.Dispose(); - } -} - -class WrapperB -{ - private B b; - public void Create() - { - b.a = new A(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AssignedInDifferentType_DisposedInDifferentNonDisposableType_NoDiagnostic() - { - // We don't track disposable field assignments in different type. - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|public A a;|] - public void Dispose() - { - } -} - -class WrapperB -{ - private B b; - - public void Create() - { - b.a = new A(); - } - - public void Dispose() - { - b.a.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AssignedInDifferentType_NotDisposed_NoDiagnostic() - { - // We don't track disposable field assignments in different type. - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|public A a;|] - public void Dispose() - { - } -} - -class Test -{ - public void M(B b) - { - b.a = new A(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_DisposedWithConditionalAccess_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a = new A();|] - - public void Dispose() - { - a?.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AssignedToLocal_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a = new A();|] - - public void Dispose() - { - A l = a; - l.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AssignedToLocal_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - private A [|a|] = new A(); - - public void Dispose() - { - A l = a; - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)); - } - - [Fact] - public async Task DisposableAllocation_IfElseStatement_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a; - private A b;|] - - public B(bool flag) - { - A l = new A(); - if (flag) - { - a = l; - } - else - { - b = l; - } - } - - public void Dispose() - { - A l = null; - if (a != null) - { - l = a; - } - else if (b != null) - { - l = b; - } - - l.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_IfElseStatement_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a; - private A b;|] - - public B(bool flag) - { - A l = new A(); - if (flag) - { - a = l; - } - else - { - b = l; - } - } - - public void Dispose() - { - A l = null; - if (a != null) - { - l = a; - } - else if (b != null) - { - l = b; - } - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId, "a").WithLocation(13, 15), - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId, "b").WithLocation(14, 15)); - } - - [Fact] - public async Task DisposableAllocation_EscapedField_NotDisposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a = new A();|] - - public void Dispose() - { - DisposeA(ref this.a); - } - - private static void DisposeA(ref A a) - { - a.Dispose(); - a = null; - } -}"); - } - - [Fact] - public async Task DisposableAllocation_OptimisticPointsToAnalysis_NoDiagnostic() - { - // Invoking an instance method may likely invalidate all the instance field analysis state, i.e. - // reference type fields might be re-assigned to point to different objects in the called method. - // An optimistic points to analysis assumes that the points to values of instance fields don't change on invoking an instance method. - // A pessimistic points to analysis resets all the instance state and assumes the instance field might point to any object, hence has unknown state. - // For dispose analysis, we want to perform an optimistic points to analysis as we assume a disposable field is not likely to be re-assigned to a separate object in helper method invocations in Dispose. - - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } - public void PerformSomeCleanup() - { - } -} - -class B : IDisposable -{ - [|private A a = new A();|] - - public void Dispose() - { - a.PerformSomeCleanup(); - ClearMyState(); - a.Dispose(); - } - - private void ClearMyState() - { - } -}"); - } - - [Fact] - public async Task DisposableAllocation_OptimisticPointsToAnalysis_WithReturn_NoDiagnostic() - { - // Invoking an instance method may likely invalidate all the instance field analysis state, i.e. - // reference type fields might be re-assigned to point to different objects in the called method. - // An optimistic points to analysis assumes that the points to values of instance fields don't change on invoking an instance method. - // A pessimistic points to analysis resets all the instance state and assumes the instance field might point to any object, hence has unknown state. - // For dispose analysis, we want to perform an optimistic points to analysis as we assume a disposable field is not likely to be re-assigned to a separate object in helper method invocations in Dispose. - - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } - public void PerformSomeCleanup() - { - } -} - -class B : IDisposable -{ - [|private A a = new A();|] - public bool Disposed; - - public void Dispose() - { - if (Disposed) - { - return; - } - - a.PerformSomeCleanup(); - ClearMyState(); - a.Dispose(); - } - - private void ClearMyState() - { - } -}"); - } - - [Fact] - public async Task DisposableAllocation_IfStatementInDispose_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -public class Test : IDisposable -{ - [|private readonly A a = new A();|] - private bool cancelled; - - public void Dispose() - { - if (cancelled) - { - a.GetType(); - } - - a.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_DisposedinDisposeOverride_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -abstract class Base : IDisposable -{ - public virtual void Dispose() - { - } -} - -class Derived : Base -{ - [|private readonly A a = new A();|] - public override void Dispose() - { - base.Dispose(); - a.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_DisposedWithDisposeBoolInvocation_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } - - public void Dispose(bool disposed) - { - } -} - -class B : IDisposable -{ - [|private A a = new A();|] - - public void Dispose() - { - a.Dispose(true); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_DisposedInsideDisposeBool_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } - - public void Dispose(bool disposed) - { - } -} - -class B : IDisposable -{ - [|private A a = new A();|] - - public void Dispose() - { - Dispose(true); - } - - public void Dispose(bool disposed) - { - a.Dispose(disposed); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_DisposedWithDisposeCloseInvocation_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } - - public void Close() - { - } -} - -class B : IDisposable -{ - [|private A a = new A();|] - - public void Dispose() - { - a.Close(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_AllDisposedMethodsMixed_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } - - public void Dispose(bool disposed) - { - } - - public void Close() - { - } -} - -class B : IDisposable -{ - [|private A a = new A(); - private A a2 = new A(); - private A a3 = new A();|] - - public void Dispose() - { - a.Close(); - } - - public void Dispose(bool disposed) - { - a2.Dispose(); - } - - public void Close() - { - a3.Dispose(true); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_DisposedInsideDisposeClose_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } - - public void Close() - { - } -} - -class B : IDisposable -{ - [|private A a = new A();|] - - public void Dispose() - { - Close(); - } - - public void Close() - { - a.Close(); - } -}"); - } - - [Fact] - public async Task SystemThreadingTask_SpecialCase_NotDisposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Threading.Tasks; - -public class A: IDisposable -{ - [|private readonly Task t;|] - public A() - { - t = new Task(null); - } - public void Dispose() - { - } -}"); - } - - [Fact, WorkItem(1796, "https://github.com/dotnet/roslyn-analyzers/issues/1796")] - public async Task DisposableAllocation_DisposedWithDisposeAsyncInvocation_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Threading.Tasks; - -class A : IDisposable -{ - public void Dispose() => DisposeAsync(); - - public Task DisposeAsync() => Task.CompletedTask; -} - -class B : IDisposable -{ - [|private A a = new A();|] - - public void Dispose() - { - a.DisposeAsync(); - } -}"); - } - - [Fact, WorkItem(1796, "https://github.com/dotnet/roslyn-analyzers/issues/1796")] - public async Task DisposableAllocation_DisposedInsideDisposeCoreAsync_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -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 A2 : A -{ - protected override Task DisposeCoreAsync(bool initialized) - { - return Task.CompletedTask; - } -} - -class B : A -{ - [|private A2 a = new A2();|] - - protected override Task DisposeCoreAsync(bool initialized) - { - return a.DisposeAsync(); - } -}"); - } - - [Fact, WorkItem(1813, "https://github.com/dotnet/roslyn-analyzers/issues/1813")] - public async Task DisposableAllocation_DisposedInInvokedMethod_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private A a = new A();|] - - public void Dispose() - { - DisposeHelper(); - } - - private void DisposeHelper() - { - a.Dispose(); - } -}"); - } - - [Fact, WorkItem(1813, "https://github.com/dotnet/roslyn-analyzers/issues/1813")] - public async Task DisposableAllocation_NotDisposedInInvokedMethod_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - private A [|a|] = new A(); - - public void Dispose() - { - DisposeHelper(); - } - - private void DisposeHelper() - { - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)); - } - - [Fact, WorkItem(1813, "https://github.com/dotnet/roslyn-analyzers/issues/1813")] - public async Task DisposableAllocation_DisposedInInvokedMethod_DisposableTypeInMetadata_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.IO; - -class B : IDisposable -{ - [|private FileStream a = File.Open("""", FileMode.Create);|] - - public void Dispose() - { - DisposeHelper(); - } - - private void DisposeHelper() - { - a.Dispose(); - } -}"); - } - - [Fact, WorkItem(1813, "https://github.com/dotnet/roslyn-analyzers/issues/1813")] - public async Task DisposableAllocation_NotDisposedInInvokedMethod_DisposableTypeInMetadata_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; -using System.IO; - -class B : IDisposable -{ - private FileStream [|a|] = File.Open("""", FileMode.Create); - - public void Dispose() - { - DisposeHelper(); - } - - private void DisposeHelper() - { - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)); - } - - [Fact, WorkItem(1813, "https://github.com/dotnet/roslyn-analyzers/issues/1813")] - public async Task DisposableAllocation_DisposedInInvokedMethodMultipleLevelsDown_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.IO; - -class B : IDisposable -{ - [|private FileStream a = File.Open("""", FileMode.Create);|] - - public void Dispose() - { - DisposeHelper(); - } - - private void DisposeHelper() - { - Helper.PerformDispose(a); - } -} - -static class Helper -{ - public static void PerformDispose(IDisposable a) - { - a.Dispose(); - } -}"); - } - - [Fact, WorkItem(1813, "https://github.com/dotnet/roslyn-analyzers/issues/1813")] - public async Task DisposableAllocation_NotDisposedInInvokedMethodMultipleLevelsDown_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; -using System.IO; - -class B : IDisposable -{ - private FileStream [|a|] = File.Open("""", FileMode.Create); - - public void Dispose() - { - DisposeHelper(); - } - - private void DisposeHelper() - { - Helper.PerformDispose(a); - } -} - -static class Helper -{ - public static void PerformDispose(IDisposable a) - { - } -}", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)); - } - - [Fact, WorkItem(2182, "https://github.com/dotnet/roslyn-analyzers/issues/2182")] - public async Task DisposableAllocation_NonReadOnlyField_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -public sealed class B : IDisposable -{ - public void Dispose() - { - } -} - -public sealed class A : IDisposable -{ - [|private B _b;|] - - public A() - { - _b = new B(); - } - - public void Dispose() - { - if (_b == null) - { - return; - } - - _b.Dispose(); - _b = null; - } -}"); - } - - [Fact, WorkItem(2306, "https://github.com/dotnet/roslyn-analyzers/issues/2306")] - public async Task DisposableAllocationInConstructor_DisposedInGeneratedCodeFile_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - [|private readonly A a;|] - public B() - { - a = new A(); - } - - [System.CodeDom.Compiler.GeneratedCodeAttribute("""", """")] - public void Dispose() - { - a.Dispose(); - } -}"); - } - - [Fact] - public async Task DisposableAllocation_FieldDisposedInOverriddenHelper_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - private readonly object _gate = new object(); - - public void Dispose() - { - lock (_gate) - { - DisposeUnderLock(); - } - } - - protected virtual void DisposeUnderLock() - { - } -} - -class C : B -{ - // Ensure this field is not flagged - [|private readonly A _a = new A();|] - - protected override void DisposeUnderLock() - { - _a.Dispose(); - base.DisposeUnderLock(); - } -}"); - } - } -} diff --git a/src/EditorFeatures/CSharpTest/DisposeAnalysis/DisposeObjectsBeforeLosingScopeTests.cs b/src/EditorFeatures/CSharpTest/DisposeAnalysis/DisposeObjectsBeforeLosingScopeTests.cs deleted file mode 100644 index f24a2bd4d2348..0000000000000 --- a/src/EditorFeatures/CSharpTest/DisposeAnalysis/DisposeObjectsBeforeLosingScopeTests.cs +++ /dev/null @@ -1,5104 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.DisposeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Test.Utilities; -using Xunit; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics; -using static Roslyn.Test.Utilities.TestHelpers; -using Roslyn.Test.Utilities; -using Microsoft.CodeAnalysis.CSharp; -using Xunit.Abstractions; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.DisposeAnalysis -{ - [Trait(Traits.Feature, Traits.Features.DisposeAnalysis)] - public sealed class DisposeObjectsBeforeLosingScopeTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest - { - public DisposeObjectsBeforeLosingScopeTests(ITestOutputHelper logger) - : base(logger) - { - } - - internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) - => (new DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer(isEnabledByDefault: true), null); - - private Task TestDiagnosticsAsync(string initialMarkup, params DiagnosticDescription[] expectedDiagnostics) - => TestDiagnosticsAsync(initialMarkup, parseOptions: null, expectedDiagnostics); - private Task TestDiagnosticsAsync(string initialMarkup, CSharpParseOptions parseOptions, params DiagnosticDescription[] expectedDiagnostics) - => TestDiagnosticsAsync(initialMarkup, new TestParameters(parseOptions, retainNonFixableDiagnostics: true), expectedDiagnostics); - private Task TestDiagnosticMissingAsync(string initialMarkup, CSharpParseOptions parseOptions = null) - => TestDiagnosticMissingAsync(initialMarkup, new TestParameters(parseOptions, retainNonFixableDiagnostics: true)); - - [Fact] - public async Task LocalWithDisposableInitializer_DisposeCall_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [|var a = new A()|]; - a.Dispose(); - } -} -"); - } - - [Fact] - public async Task LocalWithDisposableInitializer_NoDisposeCall_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - var a = [|new A()|]; - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId)); - } - - [Fact] - public async Task LocalWithDisposableAssignment_DisposeCall_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [|A a; - a = new A(); - a.Dispose(); - - A b = new A(); - a = b; - a.Dispose();|] - } -}"); - } - - [Fact] - public async Task LocalWithDisposableAssignment_NoDisposeCall_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - A a; - a = [|new A()|]; - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId)); - } - - [Fact] - public async Task ParameterWithDisposableAssignment_DisposeCall_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(A a) - { - [|a = new A(); - a.Dispose();|] - } -}"); - } - - [Fact] - public async Task ParameterWithDisposableAssignment_NoDisposeCall_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(A a) - { - a = [|new A()|]; - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId)); - } - - [Fact] - public async Task OutAndRefParametersWithDisposableAssignment_NoDisposeCall_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(ref A a1, out A a2) - { - [|a1 = new A(); - a2 = new A();|] - } -}"); - } - - [Fact] - public async Task OutDisposableArgument_NoDisposeCall_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - - } -} - -class Test -{ - void M1(out A param) - { - param = new A(); - } - - void M2(out A param2) - { - M3(out param2); - } - - void M3(out A param3) - { - param3 = new A(); - } - - void Method() - { - [|A a; - M1(out a); - A local = a; - M1(out a); - - M1(out var a2); - - A a3; - M2(out a3)|]; - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out a").WithLocation(32, 12), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out a").WithLocation(34, 12), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out var a2").WithLocation(36, 12), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out a3").WithLocation(39, 12)); - } - - [Fact] - public async Task OutDisposableArgument_DisposeCall_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [| - void M1(out A param) - { - param = new A(); - } - - void M2(out A param2) - { - M3(out param2); - } - - void M3(out A param3) - { - param3 = new A(); - } - - void Method() - { - A a; - M1(out a); - A local = a; - M1(out a); - - M1(out var a2); - - A a3; - M2(out a3); - - local.Dispose(); - a.Dispose(); - a2.Dispose(); - a3.Dispose(); - }|] -}"); - } - - [Fact] - public async Task TryGetSpecialCase_OutDisposableArgument_NoDisposeCall_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Collections.Generic; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class MyCollection -{ - private readonly Dictionary _map; - public MyCollection(Dictionary map) - { - _map = map; - } - - public bool ValueExists(int i) - { - return [|_map.TryGetValue(i, out var value);|] - } -}"); - } - - [Fact, WorkItem(2245, "https://github.com/dotnet/roslyn-analyzers/issues/2245")] - public async Task OutDisposableArgument_StoredIntoField_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - private A _a; - void M(out A param) - { - param = new A(); - } - - void Method() - { - [|M(out _a);|] // This is considered as an escape of interprocedural disposable creation. - } -}"); - } - - [Fact, WorkItem(2245, "https://github.com/dotnet/roslyn-analyzers/issues/2245")] - public async Task OutDisposableArgument_WithinTryXXXInvocation_DisposedOnSuccessPath_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Collections.Concurrent; - -public class C -{ - private readonly ConcurrentDictionary _dictionary; - public C(ConcurrentDictionary dictionary) - { - _dictionary = dictionary; - } - - [|public void Remove1(object key) - { - if (_dictionary.TryRemove(key, out IDisposable value)) - { - value.Dispose(); - } - } - - public void Remove2(object key) - { - if (!_dictionary.TryRemove(key, out IDisposable value)) - { - return; - } - - value.Dispose(); - }|] -}"); - } - - [Fact, WorkItem(2245, "https://github.com/dotnet/roslyn-analyzers/issues/2245")] - public async Task OutDisposableArgument_WithinTryXXXInvocation_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; -using System.Collections.Concurrent; - -public class C -{ - private readonly ConcurrentDictionary _dictionary; - public C(ConcurrentDictionary dictionary) - { - _dictionary = dictionary; - } - - public void Remove(object key) - { - if (_dictionary.TryRemove(key, [|out IDisposable value|])) - { - // value is not disposed. - } - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId)); - } - - [Fact] - public async Task LocalWithMultipleDisposableAssignment_DisposeCallOnSome_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - A a; - [|a = new A(1); - a = new A(2); - a.Dispose(); - a = new A(3);|] - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(17, 13), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(3)").WithLocation(20, 13)); - } - - [Fact] - public async Task FieldWithDisposableAssignment_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - public A a; - void M1(Test p) - { - [|p.a = new A(); - - Test l = new Test(); - l.a = new A(); - - this.a = new A();|] - } -}"); - } - - [Fact] - public async Task PropertyWithDisposableAssignment_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - public A a { get; set; } - void M1(Test p) - { - [|p.a = new A(); - - Test l = new Test(); - l.a = new A(); - - this.a = new A();|] - } -}"); - } - - [Fact] - public async Task Interprocedural_DisposedInHelper_MethodInvocation_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - public A a; - void M1(Test2 t2) - { - [|DisposeHelper(new A()); - t2.DisposeHelper_MethodOnDifferentType(new A()); - DisposeHelper_MultiLevelDown(new A());|] - } - - void DisposeHelper(A a) - { - a.Dispose(); - } - - void DisposeHelper_MultiLevelDown(A a) - { - DisposeHelper(a); - } -} - -class Test2 -{ - public A a; - public void DisposeHelper_MethodOnDifferentType(A a) - { - a.Dispose(); - } -}"); - } - - [Fact] - public async Task Interprocedural_DisposeOwnershipTransfer_MethodInvocation_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - public A a; - void M1() - { - [|DisposeOwnershipTransfer(new A()); - var t2 = new Test2(); - t2.DisposeOwnershipTransfer_MethodOnDifferentType(new A()); - DisposeOwnershipTransfer_MultiLevelDown(new A());|] - } - - void DisposeOwnershipTransfer(A a) - { - this.a = a; - } - - void DisposeOwnershipTransfer_MultiLevelDown(A a) - { - DisposeOwnershipTransfer(a); - } -} - -class Test2 -{ - public A a; - public void DisposeOwnershipTransfer_MethodOnDifferentType(A a) - { - this.a = a; - } -}"); - } - - [Fact] - public async Task Interprocedural_NoDisposeOwnershipTransfer_MethodInvocation_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - public A a; - void M1(Test2 t2) - { - [|NoDisposeOwnershipTransfer(new A(1)); - t2.NoDisposeOwnershipTransfer_MethodOnDifferentType(new A(2)); - NoDisposeOwnershipTransfer_MultiLevelDown(new A(3));|] - } - - void NoDisposeOwnershipTransfer(A a) - { - var str = a.ToString(); - var b = a; - } - - void NoDisposeOwnershipTransfer_MultiLevelDown(A a) - { - NoDisposeOwnershipTransfer(a); - } -} - -class Test2 -{ - public A a; - public void NoDisposeOwnershipTransfer_MethodOnDifferentType(A a) - { - var str = a.ToString(); - var b = a; - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(17, 36), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(18, 61), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(3)").WithLocation(19, 51)); - } - - [Fact, WorkItem(2136, "https://github.com/dotnet/roslyn-analyzers/issues/2136")] - public async Task Interprocedural_DisposedInHelper_ConstructorInvocation_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [|new DisposeHelperType(new A()); - DisposeHelper_MultiLevelDown(new A());|] - } - - void DisposeHelper(A a) - { - new DisposeHelperType(a); - } - - void DisposeHelper_MultiLevelDown(A a) - { - DisposeHelper(a); - } -} - -class DisposeHelperType -{ - public DisposeHelperType(A a) - { - a.Dispose(); - } -}"); - } - - [Fact, WorkItem(2136, "https://github.com/dotnet/roslyn-analyzers/issues/2136")] - public async Task Interprocedural_DisposeOwnershipTransfer_ConstructorInvocation_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [|new DisposableOwnerType(new A()); - DisposeOwnershipTransfer_MultiLevelDown(new A());|] - } - - void DisposeOwnershipTransfer(A a) - { - new DisposableOwnerType(a); - } - - void DisposeOwnershipTransfer_MultiLevelDown(A a) - { - DisposeOwnershipTransfer(a); - } -} - -class DisposableOwnerType -{ - public A a; - public DisposableOwnerType(A a) - { - this.a = a; - } -}"); - } - - [Fact, WorkItem(2136, "https://github.com/dotnet/roslyn-analyzers/issues/2136")] - public async Task Interprocedural_NoDisposeOwnershipTransfer_ConstructorInvocation_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [|new NotDisposableOwnerType(new A(1)); - NoDisposeOwnershipTransfer_MultiLevelDown(new A(2));|] - } - - void NoDisposeOwnershipTransfer(A a) - { - new NotDisposableOwnerType(a); - } - - void NoDisposeOwnershipTransfer_MultiLevelDown(A a) - { - NoDisposeOwnershipTransfer(a); - } -} - -class NotDisposableOwnerType -{ - public A a; - public NotDisposableOwnerType(A a) - { - var str = a.ToString(); - var b = a; - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(16, 36), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(17, 51)); - } - - [Fact] - public async Task DisposeOwnershipTransfer_AtConstructorInvocation_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" - - - A2 - -using System; - -class Test -{ - DisposableOwnerType M1() - { - [|return new DisposableOwnerType(new A());|] - } -} - - - - -using System; - -public class A : IDisposable -{ - public void Dispose() - { - } -} - -public class DisposableOwnerType -{ - public DisposableOwnerType(A a) - { - } -} - - -"); - } - - [Fact] - public async Task LocalWithDisposableAssignment_DisposeBoolCall_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - - } - - public void Dispose(bool b) - { - } -} - -class Test -{ - void M1() - { - [|A a; - a = new A(); - a.Dispose(true); - - A b = new A(); - a = b; - a.Dispose(true);|] - } -}"); - } - - [Fact] - public async Task LocalWithDisposableAssignment_CloseCall_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } - - public void Close() - { - } -} - -class Test -{ - void M1() - { - [|A a; - a = new A(); - a.Close(); - - A b = new A(); - a = b; - a.Close();|] - } -}"); - } - - [Fact, WorkItem(1796, "https://github.com/dotnet/roslyn-analyzers/issues/1796")] - public async Task LocalWithDisposableAssignment_DisposeAsyncCall_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Threading.Tasks; - -class A : IDisposable -{ - public void Dispose() => DisposeAsync(); - - public Task DisposeAsync() => Task.CompletedTask; -} - -class Test -{ - async Task M1() - { - [|A a; - a = new A(); - await a.DisposeAsync(); - - A b = new A(); - a = b; - await a.DisposeAsync();|] - } -}"); - } - - [Fact] - public async Task ArrayElementWithDisposableAssignment_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(A[] a) - { - [|a[0] = new A();|] // TODO: https://github.com/dotnet/roslyn-analyzers/issues/1577 - } -}"); - } - - [Fact] - public async Task ArrayElementWithDisposableAssignment_ConstantIndex_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(A[] a) - { - [|a[0] = new A(); - a[0].Dispose();|] - } -}"); - } - - [Fact] - public async Task ArrayElementWithDisposableAssignment_NonConstantIndex_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(A[] a, int i) - { - [|a[i] = new A(); - a[i].Dispose();|] - } -}"); - } - - [Fact] - public async Task ArrayElementWithDisposableAssignment_NonConstantIndex_02_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(A[] a, int i, int j) - { - [|a[i] = new A(); - i = j; // Value of i is now unknown - a[i].Dispose();|] // We don't know the points to value of a[i], so don't flag 'new A()' - } -}"); - } - - [Fact] - public async Task ArrayInitializer_ElementWithDisposableAssignment_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [| A[] a = new A[] { new A() };|] // TODO: https://github.com/dotnet/roslyn-analyzers/issues/1577 - } -}"); - } - - [Fact] - public async Task ArrayInitializer_ElementWithDisposableAssignment_ConstantIndex_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [|A[] a = new A[] { new A() }; - a[0].Dispose();|] - } -}"); - } - - [Fact] - public async Task ArrayInitializer_ElementWithDisposableAssignment_NonConstantIndex_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(int i) - { - [|A[] a = new A[] { new A() }; - a[i].Dispose();|] - } -}"); - } - - [Fact] - internal async Task CollectionInitializer_ElementWithDisposableAssignment_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Collections.Generic; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [|List a = new List() { new A() };|] // TODO: https://github.com/dotnet/roslyn-analyzers/issues/1577 - } -}"); - } - - [Fact] - internal async Task CollectionInitializer_ElementWithDisposableAssignment_ConstantIndex_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Collections.Generic; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [|List a = new List() { new A() }; - a[0].Dispose();|] - } -}"); - } - - [Fact] - internal async Task CollectionInitializer_ElementWithDisposableAssignment_NonConstantIndex_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Collections.Generic; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(int i) - { - [|List a = new List() { new A() }; - a[i].Dispose();|] - } -}"); - } - - [Fact] - internal async Task CollectionAdd_SpecialCases_ElementWithDisposableAssignment_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Collections; -using System.Collections.Generic; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class NonGenericList : ICollection -{ - public void Add(A item) - { - } - - public int Count => throw new NotImplementedException(); - - public object SyncRoot => throw new NotImplementedException(); - - public bool IsSynchronized => throw new NotImplementedException(); - - public void CopyTo(Array array, int index) - { - throw new NotImplementedException(); - } - - public IEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } -} - -class Test -{ - void M1() - { - [|List a = new List(); - a.Add(new A(1)); - - A b = new A(2); - a.Add(b); - - NonGenericList l = new NonGenericList(); - l.Add(new A(3)); - - b = new A(4); - l.Add(b);|] - } -}"); - } - - [Fact] - internal async Task CollectionAdd_IReadOnlyCollection_SpecialCases_ElementWithDisposableAssignment_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class MyReadOnlyCollection : IReadOnlyCollection -{ - public void Add(A item) - { - } - - public int Count => throw new NotImplementedException(); - - public IEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } -} - -class Test -{ - void M1() - { - [|var myReadOnlyCollection = new MyReadOnlyCollection(); - myReadOnlyCollection.Add(new A(1)); - A a = new A(2); - myReadOnlyCollection.Add(a); - - var bag = new ConcurrentBag(); - bag.Add(new A(3)); - A a2 = new A(4); - bag.Add(a2);|] - } -}"); - } - - [Fact] - public async Task MemberInitializerWithDisposableAssignment_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Collections.Generic; - -class A : IDisposable -{ - public int X; - public void Dispose() - { - } -} - -class Test -{ - public A a; - void M1() - { - [|var a = new Test { a = { X = 0 } };|] - } -}"); - } - - [Fact] - public async Task StructImplementingIDisposable_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -struct A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [|var a = new A();|] - } -}"); - } - - [Fact] - public async Task NonUserDefinedConversions_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : A -{ -} - -class Test -{ - void M1() - { - [|object obj = new A(); // Implicit conversion from A to object - ((A)obj).Dispose(); // Explicit conversion from object to A - - A a = new B(); // Implicit conversion from B to A - a.Dispose();|] - } -}"); - } - - [Fact] - public async Task NonUserDefinedConversions_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : A -{ -} - -class Test -{ - void M1() - { - [|object obj = new A(); // Implicit conversion from A to object - A a = (A)new B();|] // Explicit conversion from B to A - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(19, 22), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new B()").WithLocation(20, 18)); - } - - [Fact] - public async Task UserDefinedConversions_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } - - public static implicit operator A(B value) - { - value.Dispose(); - return null; - } - - public static explicit operator B(A value) - { - value.Dispose(); - return null; - } -} - -class B : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - Test(string s) - { - } - - void M1() - { - [|A a = new B(); // Implicit user defined conversion - B b = (B)new A();|] // Explicit user defined conversion - } -}"); - } - - [Fact] - public async Task LocalWithDisposableAssignment_ByRef_DisposedInCallee_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a = new A(); - M2(ref a); - } - - void M2(ref A a) - { - a.Dispose(); - a = null; - }|] -}"); - } - - [Fact] - public async Task LocalWithDisposableAssignment_ByRefEscape_AbstractVirtualMethod_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -public class A : IDisposable -{ - public void Dispose() - { - } -} - -public abstract class Test -{ - void M1() - { - [|A a = new A(); - M2(ref a); - - a = new A(); - M3(ref a);|] - } - - public virtual void M2(ref A a) - { - } - - public abstract void M3(ref A a); -}"); - } - - [Fact] - public async Task LocalWithDisposableAssignment_OutRefKind_NotDisposed_Diagnostic() - { - // Local/parameter passed as out is not considered escaped. - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a = new A(); - M2(out a); - } - - void M2(out A a) - { - a = new A(); - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(15, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out a").WithLocation(16, 12)); - } - - [Fact] - public async Task LocalWithDefaultOfDisposableAssignment_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1() - { - [|A a = default(A);|] - } -}"); - } - - [Fact] - public async Task NullCoalesce_NoDiagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(A a) - { - [|A b = a ?? new A(); - b.Dispose(); - - A c = new A(); - A d = c ?? a; - d.Dispose(); - - a = new A(); - A e = a ?? new A(); - e.Dispose();|] - } -}"); - } - - [Fact] - public async Task NullCoalesce_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(A a) - { - A b = a ?? [|new A()|]; - a.Dispose(); - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(15, 20)); - } - - [Fact] - public async Task WhileLoop_DisposeOnBackEdge_NoDiagnostic() - { - // Need precise CFG to avoid false reports. - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - void M1(bool flag) - { - [|A a = new A(); - while (true) - { - a.Dispose(); - if (flag) - { - break; // All 'A' instances have been disposed on this path, so no diagnostic should be reported. - } - a = new A(); - }|] - } -}"); - } - - [Fact, WorkItem(1648, "https://github.com/dotnet/roslyn-analyzers/issues/1648")] - public async Task WhileLoop_MissingDisposeOnExit_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a = new A(1); // Allocated outside the loop and disposed inside a loop is not a recommended pattern and is flagged. - while (true) - { - a.Dispose(); - a = new A(2); // This instance will not be disposed on loop exit. - } - }|] -}", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(1)").WithLocation(16, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(20, 17)); - } - - [Fact] - public async Task WhileLoop_MissingDisposeOnEntry_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - public bool Flag; - [|void M1() - { - A a; - while ((a = new A(1)) != null) // This instance will never be disposed, but is not flagged as there is no feasible loop exit. - { - a = new A(2); - a.Dispose(); - } - } - - void M2(bool flag) - { - A a; - while ((a = new A(3)) != null) // This instance will never be disposed on loop exit. - { - if (Flag) - { - break; - } - a = new A(4); - a.Dispose(); - } - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(3)").WithLocation(28, 21)); - } - - [Fact] - public async Task DoWhileLoop_DisposeOnBackEdge_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1(bool flag) - { - A a = new A(); - do - { - a.Dispose(); - if (flag) - { - break; // All 'A' instances have been disposed on this path, so no diagnostic should be reported. - } - a = new A(); - } while (true); - }|] -}"); - } - - [Fact] - public async Task DoWhileLoop_MissingDisposeOnExit_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a = new A(1); - do - { - a.Dispose(); - a = new A(2); // This instance will not be disposed on loop exit. - } while (true); - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(20, 17)); - } - - [Fact] - public async Task DoWhileLoop_MissingDisposeOnEntry_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - do - { - a = new A(1); - a.Dispose(); - } while ((a = new A(2)) != null); // This instance will never be disposed, but it is not flagged as there is no feasible loop exit. - } - - void M2() - { - A a = null; - do - { - if (a != null) - { - break; - } - a = new A(3); - a.Dispose(); - } while ((a = new A(4)) != null); // This instance will never be disposed. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(4)").WithLocation(35, 23)); - } - - [Fact] - public async Task ForLoop_DisposeOnBackEdge_MayBeNotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - [|void M1(bool flag) - { - A a = new A(1); // Allocation outside a loop, dispose inside a loop is not a recommended pattern and should fire diagnostic. - for (int i = 0; i < 10; i++) - { - a.Dispose(); - if (flag) - { - break; // All 'A' instances have been disposed on this path. - } - - a = new A(2); // This can leak on loop exit, and is flagged as a maybe disposed violation. - } - }|] -}", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(1)").WithLocation(16, 15), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(2)").WithLocation(25, 17)); - } - - [Fact] - public async Task ForLoop_MissingDisposeOnExit_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a = new A(1); // Allocation outside a loop, dispose inside a loop is not a recommended pattern and should fire diagnostic. - for (int i = 0; i < 10; i++) - { - a.Dispose(); - a = new A(2); // This instance will not be disposed on loop exit. - } - }|] -}", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(1)").WithLocation(16, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(20, 17)); - } - - [Fact] - public async Task ForLoop_MissingDisposeOnEntry_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - int i; - for (i = 0, a = new A(1); i < 10; i++) // This 'A' instance will never be disposed. - { - a = new A(2); - a.Dispose(); - } - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(18, 25)); - } - - [Fact] - public async Task IfStatement_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : A -{ -} - -class Test -{ - [|void M1(A a, string param) - { - A a1 = new A(); - B a2 = new B(); - A b; - if (param != null) - { - a = a1; - b = new B(); - } - else - { - a = a2; - b = new A(); - } - - a.Dispose(); // a points to either a1 or a2. - b.Dispose(); // b points to either instance created in if or else. - }|] -}"); - } - - [Fact] - public async Task IfStatement_02_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : A -{ -} - -class Test -{ - [|void M1(A a, string param, string param2) - { - A a1 = new A(); - B a2 = new B(); - A b; - if (param != null) - { - a = a1; - b = new B(); - - if (param == """") - { - a = new B(); - } - else - { - if (param2 != null) - { - b = new A(); - } - else - { - b = new B(); - } - } - } - else - { - a = a2; - b = new A(); - } - - a.Dispose(); // a points to either a1 or a2 or instance created in 'if(param == """")'. - b.Dispose(); // b points to either instance created in outer if or outer else or innermost if or innermost else. - }|] -}"); - } - - [Fact] - public async Task IfStatement_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public A() { } - public void Dispose() - { - } -} - -class B : A -{ -} - -class C : B -{ -} - -class D : C -{ -} - -class E : D -{ -} - -class Test -{ - [|void M1(A a, string param, string param2) - { - A a1 = new A(1); // Maybe disposed. - B a2 = new B(); // Never disposed. - A b; - if (param != null) - { - a = a1; - b = new C(); // Never disposed. - } - else - { - a = a2; - b = new D(); // Never disposed. - } - - // a points to either a1 or a2. - // b points to either instance created in if or else. - - if (param != null) - { - A c = new A(2); - a = c; - b = a1; - } - else - { - C d = new E(); - b = d; - a = b; - } - - a.Dispose(); // a points to either c or d. - b.Dispose(); // b points to either a1 or d. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new B()").WithLocation(34, 16), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new C()").WithLocation(39, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new D()").WithLocation(44, 17)); - } - - [Fact] - public async Task IfStatement_02_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public A() { } - public void Dispose() - { - } -} - -class B : A -{ -} - -class C : B -{ -} - -class D : C -{ -} - -class E : D -{ -} - -class Test -{ - [|void M1(A a, string param, string param2) - { - A a1 = new B(); // Never disposed - B a2 = new C(); // Never disposed - A b; - if (param != null) - { - a = a1; - b = new A(1); // Maybe disposed - - if (param == """") - { - a = new D(); // Never disposed - } - else - { - if (param2 != null) - { - b = new A(2); // Maybe disposed - } - else - { - b = new A(3); // Maybe disposed - if (param == """") - { - b = new A(4); // Maybe disposed - } - } - - if (param2 == """") - { - b.Dispose(); // b points to one of the three instances of A created above. - b = new A(5); // Always disposed - } - } - } - else - { - a = a2; - b = new A(6); // Maybe disposed - if (param2 != null) - { - a = new A(7); // Always disposed - } - else - { - a = new A(8); // Always disposed - b = new A(9); // Always disposed - } - - a.Dispose(); - } - - b.Dispose(); - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new B()").WithLocation(33, 16), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new C()").WithLocation(34, 16), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new D()").WithLocation(43, 21)); - } - - [Fact] - public async Task UsingStatement_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - using (var a = new A()) - { - } - - A b; - using (b = new A()) - { - } - - using (A c = new A(), d = new A()) - { - } - - A e = new A(); - using (e) - { - } - - using (A f = null) - { - } - }|] -}"); - } - - [Fact, WorkItem(2201, "https://github.com/dotnet/roslyn-analyzers/issues/2201")] - public async Task UsingStatementInTryCatch_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System.IO; - -class Test -{ - void M1() - { - try - { - [|using (var ms = new MemoryStream())|] - { - } - } - catch - { - } - } -}"); - } - - [Fact, WorkItem(2201, "https://github.com/dotnet/roslyn-analyzers/issues/2201")] - public async Task NestedTryFinallyInTryCatch_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System.IO; - -class Test -{ - void M1() - { - try - { - [|var ms = new MemoryStream();|] - try - { - } - finally - { - ms?.Dispose(); - } - } - catch - { - } - } -}"); - } - - [Fact] - public async Task ReturnStatement_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Collections.Generic; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|A M1() - { - return new A(); - } - - A M2(A a) - { - a = new A(); - return a; - } - - A M3(A a) - { - a = new A(); - A b = a; - return b; - } - - A M4(A a) => new A(); - - IEnumerable M5() - { - yield return new A(); - }|] -}"); - } - - [Fact] - public async Task ReturnStatement_02_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : I, IDisposable -{ - public void Dispose() - { - } -} - -interface I -{ -} - -class Test -{ - [|I M1() - { - return new A(); - } - - I M2() - { - return new A() as I; - }|] -}"); - } - - [Fact] - public async Task LocalFunctionInvocation_EmptyBody_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - a = new A(); - - void MyLocalFunction() - { - }; - - MyLocalFunction(); // This should not change state of 'a'. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(16, 13)); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunctionInvocation_DisposesCapturedValue_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a = new A(); - - void MyLocalFunction() - { - a.Dispose(); - }; - - MyLocalFunction(); // This should change state of 'a' to be Disposed. - }|] -}"); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunctionInvocation_CapturedValueAssignedNewDisposable_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - - void MyLocalFunction() - { - a = new A(); - }; - - MyLocalFunction(); // This should change state of 'a' to be NotDisposed and fire a diagnostic. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(19, 17)); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunctionInvocation_ChangesCapturedValueContextSensitive_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - - void MyLocalFunction(A b) - { - a = b; - }; - - MyLocalFunction(new A()); // This should change state of 'a' to be NotDisposed and fire a diagnostic. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(22, 25)); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunction_DisposableCreationNotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - void MyLocalFunction() - { - A a = new A(); // This should fire a diagnostic. - }; - - MyLocalFunction(); - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(17, 19)); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunction_DisposableCreation_InvokedMultipleTimes_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - void MyLocalFunction(int i) - { - A a = new A(); // This should fire a single diagnostic. - }; - - MyLocalFunction(1); - MyLocalFunction(2); - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(17, 19)); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunction_DisposableCreationReturned_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A MyLocalFunction(int i) - { - return new A(); - }; - - var a = MyLocalFunction(1); // This should fire a diagnostic. - var b = MyLocalFunction(2); // This should fire a diagnostic. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "MyLocalFunction(1)").WithLocation(20, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "MyLocalFunction(2)").WithLocation(21, 17)); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunction_DisposableCreationReturned_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A MyLocalFunction() - { - return new A(); - }; - - var a = MyLocalFunction(); - a.Dispose(); - }|] -}"); - // VB has no local functions. - } - - [Fact] - public async Task LocalFunction_DisposableCreationAssignedToRefOutParameter_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a1 = null, a2; - MyLocalFunction(ref a1, out a2); // This should fire two diagnostics. - return; - - void MyLocalFunction(ref A param1, out A param2) - { - param1 = new A(); - param2 = new A(); - }; - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "ref a1").WithLocation(16, 25), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out a2").WithLocation(16, 33)); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunction_DisposableCreationAssignedToRefOutParameter_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a1 = null, a2; - MyLocalFunction(ref a1, out a2); - a1.Dispose(); - a2.Dispose(); - return; - - void MyLocalFunction(ref A param1, out A param2) - { - param1 = new A(); - param2 = new A(); - }; - }|] -}"); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunction_DisposableCreationAssignedToRefOutParameter_MultipleCalls_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a1 = null, a2; - MyLocalFunction(ref /*1*/a1, out /*2*/a2); // This should fire two diagnostics. - MyLocalFunction(ref /*3*/a1, out /*4*/a2); // No diagnostics. - a1.Dispose(); - a2.Dispose(); - return; - - void MyLocalFunction(ref A param1, out A param2) - { - param1 = new A(); - param2 = new A(); - }; - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "ref /*1*/a1").WithLocation(16, 25), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out /*2*/a2").WithLocation(16, 38)); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunction_DisposableCreation_MultipleLevelsBelow_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a1 = null, a2; - MyLocalFunction1(ref /*1*/a1, out /*2*/a2); // This should fire two diagnostics. - return; - - void MyLocalFunction1(ref A param1, out A param2) - { - MyLocalFunction2(ref /*3*/param1, out /*4*/param2); - }; - - void MyLocalFunction2(ref A param3, out A param4) - { - param3 = new A(); - param4 = new A(); - }; - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "ref /*1*/a1").WithLocation(16, 26), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out /*2*/a2").WithLocation(16, 39)); - - // VB has no local functions. - } - - [Fact] - public async Task LocalFunction_DisposableCreation_MultipleLevelsBelow_Nested_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a1 = null, a2; - MyLocalFunction1(ref /*1*/a1, out /*2*/a2); // This should fire two diagnostics. - return; - - void MyLocalFunction1(ref A param1, out A param2) - { - MyLocalFunction2(ref /*3*/param1, out /*4*/param2); - - void MyLocalFunction2(ref A param3, out A param4) - { - param3 = new A(); - param4 = new A(); - }; - }; - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "ref /*1*/a1").WithLocation(16, 26), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out /*2*/a2").WithLocation(16, 39)); - - // VB has no local functions. - } - - [Fact] - public async Task LambdaInvocation_EmptyBody_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - a = new A(); - - System.Action myLambda = () => - { - }; - - myLambda(); // This should not change state of 'a'. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(16, 13)); - } - - [Fact] - public async Task LambdaInvocation_DisposesCapturedValue_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a = new A(); - - System.Action myLambda = () => - { - a.Dispose(); - }; - - myLambda(); // This should change state of 'a' to be Disposed. - }|] -}"); - } - - [Fact] - public async Task LambdaInvocation_CapturedValueAssignedNewDisposable_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - - System.Action myLambda = () => - { - a = new A(); - }; - - myLambda(); // This should change state of 'a' to be NotDisposed and fire a diagnostic. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(19, 17)); - } - - [Fact] - public async Task LambdaInvocation_ChangesCapturedValueContextSensitive_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - - System.Action myLambda = b => - { - a = b; - }; - - myLambda(new A()); // This should change state of 'a' to be NotDisposed and fire a diagnostic. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(22, 18)); - } - - [Fact] - public async Task Lambda_DisposableCreationNotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - System.Action myLambda = () => - { - A a = new A(); // This should fire a diagnostic. - }; - - myLambda(); - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(17, 19)); - } - - [Fact] - public async Task Lambda_DisposableCreation_InvokedMultipleTimes_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - System.Action myLambda = () => - { - A a = new A(); // This should fire a single diagnostic. - }; - - myLambda(); - myLambda(); - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(17, 19)); - } - - [Fact] - public async Task Lambda_DisposableCreationReturned_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - System.Func myLambda = () => - { - return new A(); - }; - - var a = myLambda(/*1*/); // This should fire a diagnostic. - var b = myLambda(/*2*/); // This should fire a diagnostic. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "myLambda(/*1*/)").WithLocation(20, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "myLambda(/*2*/)").WithLocation(21, 17)); - } - - [Fact] - public async Task Lambda_DisposableCreationReturned_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - System.Func myLambda = () => - { - return new A(); - }; - - var a = myLambda(); - a.Dispose(); - }|] -}"); - } - - [Fact] - public async Task Lambda_DisposableCreationAssignedToRefOutParameter_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - delegate void MyDelegate(ref A a1, out A a2); - [|void M1() - { - MyDelegate myDelegate = (ref A param1, out A param2) => - { - param1 = new A(); - param2 = new A(); - }; - - A a1 = null, a2; - myDelegate(ref a1, out a2); // This should fire two diagnostics. - return; - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "ref a1").WithLocation(23, 20), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out a2").WithLocation(23, 28)); - } - - [Fact] - public async Task Lambda_DisposableCreationAssignedToRefOutParameter_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - delegate void MyDelegate(ref A a1, out A a2); - [|void M1() - { - MyDelegate myDelegate = (ref A param1, out A param2) => - { - param1 = new A(); - param2 = new A(); - }; - - A a1 = null, a2; - myDelegate(ref a1, out a2); - a1.Dispose(); - a2.Dispose(); - return; - }|] -}"); - } - - [Fact] - public async Task Lambda_DisposableCreationAssignedToRefOutParameter_MultipleCalls_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - delegate void MyDelegate(ref A a1, out A a2); - [|void M1() - { - MyDelegate myDelegate = (ref A param1, out A param2) => - { - param1 = new A(); - param2 = new A(); - }; - - A a1 = null, a2; - myDelegate(ref /*1*/a1, out /*2*/a2); // This should fire two diagnostics. - myDelegate(ref /*3*/a1, out /*4*/a2); // No diagnostics. - a1.Dispose(); - a2.Dispose(); - return; - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "ref /*1*/a1").WithLocation(23, 20), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out /*2*/a2").WithLocation(23, 33)); - } - - [Fact] - public async Task Lambda_DisposableCreation_MultipleLevelsBelow_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - delegate void MyDelegate(ref A a1, out A a2); - [|void M1() - { - MyDelegate myDelegate2 = (ref A param3, out A param4) => - { - param3 = new A(); - param4 = new A(); - }; - - MyDelegate myDelegate1 = (ref A param1, out A param2) => - { - myDelegate2(ref /*3*/param1, out /*4*/param2); - }; - - A a1 = null, a2; - myDelegate1(ref /*1*/a1, out /*2*/a2); // This should fire two diagnostics. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "ref /*1*/a1").WithLocation(28, 21), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out /*2*/a2").WithLocation(28, 34)); - } - - [Fact] - public async Task Lambda_DisposableCreation_MultipleLevelsBelow_Nested_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - delegate void MyDelegate(ref A a1, out A a2); - [|void M1() - { - MyDelegate myDelegate1 = (ref A param1, out A param2) => - { - MyDelegate myDelegate2 = (ref A param3, out A param4) => - { - param3 = new A(); - param4 = new A(); - }; - - myDelegate2(ref /*3*/param1, out /*4*/param2); - }; - - A a1 = null, a2; - myDelegate1(ref /*1*/a1, out /*2*/a2); // This should fire two diagnostics. - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "ref /*1*/a1").WithLocation(28, 21), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "out /*2*/a2").WithLocation(28, 34)); - } - - [Fact] - public async Task Lambda_InvokedFromInterprocedural_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a1 = new A(); - M2(() => a1.Dispose()); - } - - void M2(Action disposeCallback) => disposeCallback();|] -}"); - } - - [Fact] - internal async Task Lambda_MayBeInvokedFromInterprocedural_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - public bool Flag; - [|void M1() - { - A a1 = new A(1); - M2(() => a1.Dispose()); - - A a2 = new A(2); - if (Flag) - M3(() => a2.Dispose()); - } - - void M2(Action disposeCallback) - { - if (Flag) - disposeCallback(); - } - - void M3(Action disposeCallback) => disposeCallback();|] -}", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(1)").WithLocation(17, 16), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(2)").WithLocation(20, 16)); - } - - [Fact] - public async Task DelegateInvocation_EmptyBody_NoArguments_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - a = new A(); - - System.Action myDelegate = M2; - myDelegate(); // This should not change state of 'a' as it is not passed as argument. - }|] - - void M2() { } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(16, 13)); - } - - [Fact] - public async Task DelegateInvocation_PassedAsArgumentButNotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - a = new A(); - - System.Action myDelegate = M2; - myDelegate(a); // This should not change state of 'a'. - }|] - - void M2(A a) { } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(16, 13)); - } - - [Fact, WorkItem(1813, "https://github.com/dotnet/roslyn-analyzers/issues/1813")] - public async Task DelegateInvocation_DisposesCapturedValue_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - A a; - a = new A(); - - System.Action myDelegate = M2; - myDelegate(a); // This should change state of 'a' to be disposed as we perform interprocedural analysis. - }|] - - void M2(A a) => a.Dispose(); -}"); - } - - [Fact] - public async Task DisposableCreationNotAssignedToAVariable_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public int X; - public A(int i) { } - - public void Dispose() - { - } - - public void M() - { - } -} - -class Test -{ - [|void M1() - { - new A(1); - new A(2).M(); - var x = new A(3).X; - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(22, 9), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(23, 9), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(3)").WithLocation(24, 17)); - } - - [Fact] - public async Task DisposableCreationPassedToDisposableConstructor_NoDiagnostic() - { - // Dispose ownership transfer - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : IDisposable -{ - private readonly A _a; - public B(A a) - { - _a = a; - } - - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - var b = new B(new A()); - b.Dispose(); - - var a = new A(); - B b2 = null; - try - { - b2 = new B(a); - } - finally - { - if (b2 != null) - { - b2.Dispose(); - } - } - - var a2 = new A(); - B b3 = null; - try - { - b3 = new B(a2); - } - finally - { - if (b3 != null) - { - b3.Dispose(); - } - } - }|] -}"); - } - - [Fact] - public async Task DisposableObjectOnlyDisposedOnExceptionPath_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - var a = new A(1); - try - { - ThrowException(); - } - catch (Exception) - { - a.Dispose(); - } - } - - void M2() - { - var a = new A(2); - try - { - ThrowException(); - } - catch (System.IO.IOException) - { - a.Dispose(); - } - } - - void M3() - { - var a = new A(3); - try - { - ThrowException(); - } - catch (System.IO.IOException) - { - a.Dispose(); - } - catch (Exception) - { - a.Dispose(); - } - } - - void M4(bool flag) - { - var a = new A(4); - try - { - ThrowException(); - } - catch (System.IO.IOException) - { - if (flag) - { - a.Dispose(); - } - } - }|] - - void ThrowException() - { - throw new NotImplementedException(); - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(16, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(29, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(3)").WithLocation(42, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(4)").WithLocation(59, 17)); - } - - [Fact] - public async Task DisposableObjectDisposed_FinallyPath_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - var a = new A(); - try - { - ThrowException(); - } - finally - { - a.Dispose(); - } - } - - void M2() - { - var a = new A(); - try - { - ThrowException(); - } - catch (Exception) - { - } - finally - { - a.Dispose(); - } - } - - void M3() - { - var a = new A(); - try - { - ThrowException(); - a.Dispose(); - a = null; - } - catch (System.IO.IOException) - { - } - finally - { - if (a != null) - { - a.Dispose(); - } - } - }|] - - void ThrowException() - { - throw new NotImplementedException(); - } -}"); - } - - [Fact] - public async Task DelegateCreation_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class Test -{ - [|void M1() - { - Func createA = M2; - A a = createA(); - a.Dispose(); - } - - A M2() - { - return new A(); - }|] -}"); - } - - [Fact] - public async Task MultipleReturnStatements_AllInstancesReturned_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -public class Test -{ - [|A M1(bool flag) - { - A a; - if (flag) - { - A a2 = new A(); - a = a2; - return a; - } - - A a3 = new A(); - a = a3; - return a; - }|] -}"); - } - - [Fact] - public async Task MultipleReturnStatements_AllInstancesEscapedWithOutParameter_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -public class Test -{ - [|void M1(bool flag, out A a) - { - if (flag) - { - A a2 = new A(); - a = a2; - return; - } - - A a3 = new A(); - a = a3; - return; - }|] -}"); - } - - [Fact] - public async Task MultipleReturnStatements_AllButOneInstanceReturned_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -public class Test -{ - [|A M1(int flag, bool flag2, bool flag3) - { - A a = null; - if (flag == 0) - { - A a2 = new A(1); // Escaped with return inside below nested 'if', not disposed on other paths. - a = a2; - - if (!flag2) - { - if (flag3) - { - return a; - } - } - } - else - { - a = new A(2); // Escaped with return inside below nested 'else', not disposed on other paths. - if (flag == 1) - { - a = new A(3); // Never disposed. - } - else - { - if (flag3) - { - a = new A(4); // Escaped with return inside below 'else', not disposed on other paths. - } - - if (flag2) - { - } - else - { - return a; - } - } - } - - A a3 = new A(5); // Always escaped with below return, ensure no diagnostic. - a = a3; - return a; - }|] -}", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(1)").WithLocation(19, 20), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(2)").WithLocation(32, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(3)").WithLocation(35, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(4)").WithLocation(41, 25)); - } - - [Fact] - public async Task MultipleReturnStatements_AllButOneInstanceEscapedWithOutParameter_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -class B : A -{ -} - -public class Test -{ - [|void M1(int flag, bool flag2, bool flag3, out A a) - { - a = null; - if (flag == 0) - { - A a2 = new A(); // Escaped with return inside below nested 'if'. - a = a2; - - if (!flag2) - { - if (flag3) - { - return; - } - } - } - else - { - a = new A(); // Escaped with return inside below nested 'else'. - if (flag == 1) - { - a = new B(); // Never disposed. - } - else - { - if (flag3) - { - a = new A(); // Escaped with return inside below 'else'. - } - - if (flag2) - { - } - else - { - return; - } - } - } - - A a3 = new A(); // Escaped with below return. - a = a3; - return; - }|] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new B()").WithLocation(38, 21)); - } - - [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")] - public async Task DisposableAllocation_AssignedToTuple_Escaped_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -public class Test -{ - [|(A, int) M1() - { - A a = new A(); - return (a, 0); - } - - (A, int) M2() - { - A a = new A(); - (A, int) b = (a, 0); - return b; - }|] -}" + TestResources.NetFX.ValueTuple.tuplelib_cs); - } - - [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")] - internal async Task DisposableAllocation_AssignedToTuple_Escaped_SpecialCases_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -public class Test -{ - [| - // Nested tuple - ((A, int), int) M1() - { - A a = new A(); - ((A, int), int) b = ((a, 0), 1); - return b; - } - - // Declaration expression target - A M2() - { - A a = new A(); - var ((a2, x), y) = ((a, 0), 1); - return a2; - } - - // Declaration expression target with discards - A M3() - { - A a = new A(); - var ((a2, _), _) = ((a, 0), 1); - return a2; - } - - // Declaration expressions in target - A M4() - { - A a = new A(); - ((var a2, var x), var y) = ((a, 0), 1); - return a2; - } - - // Discards in target - A M5() - { - A a = new A(); - ((var a2, _), _) = ((a, 0), 1); - return a2; - } - - // Tuple with multiple disposable escape - (A, A) M6() - { - A a = new A(); - A a2 = new A(); - var b = (a, a2); - return b; - } - |] -}" + TestResources.NetFX.ValueTuple.tuplelib_cs); - } - - [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")] - public async Task DisposableAllocation_AssignedToTuple_NotDisposed_SpecialCases_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - - public void Dispose() - { - } -} - -public class Test -{ - [| - // Nested tuple - ((A, int), (A, int)) M1() - { - A a = new A(1); // Should be flagged. - A a2 = new A(2); - ((A, int), (A, int)) b = ((a2, 0), (a2, 0)); - return b; - } - - // Declaration expression target - A M2() - { - A a = new A(3); // Should be flagged. - var ((a2, x), y) = ((a, 0), 1); - return null; - } - - // Declaration expression target with discards - A M3() - { - A a = new A(4); // Should be flagged. - var ((a2, _), _) = ((a, 0), 1); - return null; - } - - // Declaration expressions in target - A M4() - { - A a = new A(5); // Should be flagged. - ((var a2, var x), var y) = ((a, 0), 1); - return null; - } - - // Discards in target - A M5() - { - A a = new A(6); // Should be flagged. - ((var a2, _), _) = ((a, 0), 1); - return null; - } - - // Tuple with multiple disposable escape - (A, A) M6() - { - A a = new A(7); // Should be flagged. - A a2 = new A(8); - var b = (a2, a2); - return b; - } - |] -}" + TestResources.NetFX.ValueTuple.tuplelib_cs, - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(19, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(3)").WithLocation(28, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(4)").WithLocation(36, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(5)").WithLocation(44, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(6)").WithLocation(52, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(7)").WithLocation(60, 15)); - } - - [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")] - public async Task DisposableAllocation_EscapedTupleLiteral_SpecialCases_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -public class Test -{ - [| - // Tuple literal escaped cases. - ((A, int), int) M1() - { - A a = new A(); - return ((a, 0), 1); - } - - (A, A) M2() - { - A a = new A(); - A a2 = new A(); - return (a, a2); - } - - void M3(out (A, A) arg) - { - A a = new A(); - A a2 = new A(); - arg = (a, a2); - } - - void M4(out (A, A) arg) - { - A a = new A(); - A a2 = new A(); - var a3 = (a, a2); - arg = a3; - } - - void M5(ref (A, A) arg) - { - A a = new A(); - A a2 = new A(); - var a3 = (a, a2); - arg = a3; - } - |] -}" + TestResources.NetFX.ValueTuple.tuplelib_cs); - } - - [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")] - public async Task DisposableAllocation_AddedToTupleLiteral_SpecialCases_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -public class Test -{ - [| - // Tuple literal assignment cases. - void M1() - { - A a = new A(1); - var x = ((a, 0), 1); - } - - void M2() - { - A a = new A(2); - A a2 = new A(3); - var x = (a, a2); - } - - void M3(out (A, A) arg) - { - A a = new A(4); - A a2 = new A(5); - arg = (a, a2); - arg = default((A, A)); - } - - void M4(out (A, A) arg) - { - A a = new A(6); - A a2 = new A(7); - var a3 = (a, a2); - arg = a3; - arg = default((A, A)); - } - |] -}" + TestResources.NetFX.ValueTuple.tuplelib_cs, - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(18, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(24, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(3)").WithLocation(25, 16), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(4)").WithLocation(31, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(5)").WithLocation(32, 16), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(6)").WithLocation(39, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(7)").WithLocation(40, 16)); - } - - [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")] - public async Task DisposableAllocation_AssignedToTuple_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -public class Test -{ - [|void M1() - { - A a = new A(); - var b = (a, 0); - } - - void M2() - { - A a = new A(); - (A, int) b = (a, 0); - }|] -}" + TestResources.NetFX.ValueTuple.tuplelib_cs, - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(15, 15), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A()").WithLocation(21, 15)); - } - - [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")] - public async Task DisposableAllocation_AssignedToTuple_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -public class Test -{ - [|void M1() - { - A a = new A(); - var b = (a, 0); - b.a.Dispose(); - } - - void M2() - { - A a = new A(); - (A, int) b = (a, 0); - a.Dispose(); - }|] -}" + TestResources.NetFX.ValueTuple.tuplelib_cs, - parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)); - } - - [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")] - public async Task DisposableAllocation_AssignedToTuple_Item1_Disposed_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public void Dispose() - { - } -} - -public class Test -{ - [|void M1() - { - A a = new A(); - var b = (a, 0); - b.Item1.Dispose(); - }|] -}" + TestResources.NetFX.ValueTuple.tuplelib_cs, - parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)); - } - - [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")] - public async Task DisposableAllocation_DeconstructionAssignmentToTuple_DeconstructMethod_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; -using System.Collections.Generic; - -internal static class KeyValuePairExtensions -{ - public static void Deconstruct(this KeyValuePair pair, out TKey key, out TValue value) - { - key = pair.Key; - value = pair.Value; - } -} - -class A : IDisposable -{ - public A(int i) { } - public int X { get; } - public void Dispose() - { - } - - public int M() => 0; -} - -public class Test -{ - [|void M1(IDictionary map) - { - foreach ((A a, _) in map) - { - var x = new A(1); - var y = a.M(); - } - } - - void M2(IDictionary map) - { - foreach (var (a, _) in map) - { - var x = new A(2); - var y = a.M(); - } - } - - void M3(KeyValuePair pair, int y) - { - A a; - (a, y) = pair; - var x = new A(3); - }|] -}" + TestResources.NetFX.ValueTuple.tuplelib_cs, - parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(31, 21), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(40, 21), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(3)").WithLocation(49, 17)); - } - - [Fact] - public async Task DifferentDisposePatternsInFinally_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - [| - void M1() - { - // Allocated before try, disposed in finally with conditional access. - A a = new A(1); - try - { - } - finally - { - a?.Dispose(); - } - } - - void M2() - { - // Allocated in try, disposed in finally with conditional access. - A a = null; - try - { - a = new A(2); - } - finally - { - a?.Dispose(); - } - } - - void M3() - { - // Allocated before try, disposed in finally with null check. - A a = new A(3); - try - { - } - finally - { - if (a != null) - { - a.Dispose(); - } - } - } - - void M4() - { - // Allocated in try, disposed in finally with null check. - A a = null; - try - { - a = new A(4); - } - finally - { - if (a != null) - { - a.Dispose(); - } - } - } - - void M5() - { - // Allocated before try, disposed in finally with helper method. - A a = new A(5); - try - { - } - finally - { - DisposeHelper(a); - } - } - - void M6() - { - // Allocated in try, disposed in finally with helper method. - A a = null; - try - { - a = new A(6); - } - finally - { - DisposeHelper(a); - } - } - - void DisposeHelper(IDisposable a) - { - if (a != null) - { - a.Dispose(); - } - } - - void M7(bool flag) - { - // Allocated before try, disposed in try and assigned to null, disposed in finally with conditional access. - A a = new A(7); - try - { - if (flag) - { - a.Dispose(); - a = null; - } - } - finally - { - a?.Dispose(); - } - } - - void M8(bool flag1, bool flag2) - { - // Conditionally allocated in try, disposed in try and assigned to null, disposed in finally with conditional access. - A a = null; - try - { - if (flag1) - { - a = new A(8); - } - - if (flag2) - { - a.Dispose(); - a = null; - } - } - finally - { - a?.Dispose(); - } - } - - void M9(bool flag) - { - // Allocated before try, disposed in catch and all exit points from try, but not in finally. - A a = new A(9); - try - { - if (flag) - { - a.Dispose(); - a = null; - return; - } - - a.Dispose(); - } - catch (Exception ex) - { - a?.Dispose(); - } - finally - { - } - } - - void M10(bool flag1, bool flag2) - { - // Conditionally allocated in try, disposed in catch and all exit points from try, but not in finally. - A a = null; - try - { - if (flag1) - { - a = new A(10); - } - - if (flag2) - { - a?.Dispose(); - return; - } - - if (a != null) - { - a.Dispose(); - } - } - catch (Exception ex) - { - a?.Dispose(); - } - finally - { - } - } - - private IDisposable A; - void M11(bool flag) - { - // Allocated before try, escaped or disposed at all exit points from try, and disposed with conditional access in finally. - A a = new A(9); - try - { - if (flag) - { - a.Dispose(); - a = null; - return; - } - - this.A = a; // Escaped. - a = null; - } - finally - { - a?.Dispose(); - } - } - - void M12(bool flag1, bool flag2) - { - // Conditionally allocated in try, escaped or disposed at all exit points from try, and disposed with conditional access in finally. - A a = null; - try - { - if (flag1) - { - a = new A(10); - } - - if (flag2) - { - this.A = a; // Escaped. - a = null; - return; - } - - if (a != null) - { - a.Dispose(); - a = null; - } - } - finally - { - a?.Dispose(); - } - } - |] -}"); - } - - [Fact] - public async Task DifferentDisposePatternsInFinally_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; - -class A : IDisposable -{ - public A(int i) { } - public void Dispose() - { - } -} - -class Test -{ - [| - void M1(bool flag) - { - // Allocated before try, disposed only on some paths in finally with conditional access. - A a = new A(1); - try - { - } - finally - { - if (flag) - { - a?.Dispose(); - } - } - } - - void M2(bool flag) - { - // Allocated in try, disposed only on some paths in finally with conditional access. - A a = null; - try - { - a = new A(2); - } - finally - { - if (flag) - { - a?.Dispose(); - } - } - } - - void M3(bool flag) - { - // Allocated before try, disposed in finally with null checks on different variable. - // It is not recommended to have dispose logic of a variable depend on multiple variables/flags, as the - // lifetime of allocations might change when code within the try is refactored. - A a = null; - A b = null; - try - { - if (flag) - { - a = new A(3); - b = new A(31); - } - } - finally - { - if (b != null) - { - a.Dispose(); - b.Dispose(); - } - } - } - - void M4(bool flag) - { - // Allocated in try, disposed in finally with null checks on multiple variables. - // It is not recommended to have dispose logic of a variable depend on another variable, as the - // lifetime of allocations might change when code within the try is refactored. - A a = null; - A b = null; - try - { - if (flag) - { - a = new A(4); - b = new A(41); - } - } - finally - { - if (a != null && b != null) - { - a.Dispose(); - b.Dispose(); - } - } - } - - void M5(bool flag) - { - // Allocated before try, disposed on some paths in finally with helper method. - A a = new A(5); - try - { - } - finally - { - DisposeHelper(a, flag); - } - } - - void M6(bool flag) - { - // Allocated in try, disposed in finally with helper method depending on a bool check. - // It is not recommended to have dispose logic of a variable depend on another flag, as the - // lifetime of allocation and flag value might change when code within the try is refactored. - A a = null; - try - { - if (flag) - { - a = new A(6); - } - } - finally - { - DisposeHelper(a, flag); - } - } - - void DisposeHelper(IDisposable a, bool flag) - { - if (flag) - { - a?.Dispose(); - } - } - - void M7(bool flag) - { - // Allocated before try, leaked on some paths in try, disposed in finally with conditional access. - A a = new A(7); - try - { - if (flag) - { - a = null; // Leaked here, but need path sensitive analysis to flag this. - } - } - finally - { - a?.Dispose(); - } - } - - void M8(bool flag1, bool flag2) - { - // Conditionally allocated in try, leaked on some paths in try, disposed in finally with conditional access. - A a = null; - try - { - if (flag1) - { - a = new A(8); - } - - if (flag2) - { - a.Dispose(); - a = null; - } - else - { - a = null; // Leaked here, needs path sensitive analysis. - } - } - finally - { - a?.Dispose(); - } - } - - void M9(bool flag) - { - // Allocated before try, disposed in catch and but leaked from some exit points in try. - A a = new A(9); - try - { - if (flag) - { - a = null; // Leaked here. - return; - } - - a.Dispose(); - } - catch (Exception ex) - { - a?.Dispose(); - } - finally - { - } - } - - void M10(bool flag1, bool flag2) - { - // Conditionally allocated in try, leaked from some exit points in catch. - A a = null; - try - { - if (flag1) - { - a = new A(10); - } - - if (flag2) - { - a?.Dispose(); - return; - } - - if (a != null) - { - a.Dispose(); - } - } - catch (Exception ex) - { - if (flag1) - { - a?.Dispose(); // Leaked here, but need enhanced exceptional path dispose analysis to flag this. - } - } - finally - { - } - } - - private IDisposable A; - void M11(bool flag) - { - // Allocated before try, leaked before escaped at some points in try. - A a = new A(11); - try - { - if (flag) - { - a.Dispose(); - a = null; - return; - } - - a = null; // Leaked here. - this.A = a; // Escaped has no effect as it is already leaked. - } - finally - { - a?.Dispose(); - } - } - - void M12(bool flag1, bool flag2, bool flag3) - { - // Conditionally allocated in try, escaped and leaked on separate exit points from try, and disposed with conditional access in finally. - A a = null; - try - { - if (flag1) - { - a = new A(12); - } - - if (flag2) - { - this.A = a; // Escaped. - a = null; - return; - } - else if (flag3) - { - a = new A(121); // Previous allocation potentially leaked here, but need path sensitive analysis to flag here. - } - } - finally - { - a?.Dispose(); - } - } - |] -}", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(1)").WithLocation(18, 15), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(2)").WithLocation(37, 17), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(3)").WithLocation(59, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(4)").WithLocation(84, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(41)").WithLocation(85, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(5)").WithLocation(101, 15), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(6)").WithLocation(121, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(8)").WithLocation(163, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(9)").WithLocation(185, 15), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "new A(11)").WithLocation(243, 15)); - } - - [Fact, WorkItem(2212, "https://github.com/dotnet/roslyn-analyzers/issues/2212")] - public async Task ReturnDisposableObjectWrappenInTask_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Threading.Tasks; - -class C : IDisposable -{ - public void Dispose() - { - } - - public Task M1_Task() - { - [|return Task.FromResult(new C());|] - } -}"); - } - - [Fact, WorkItem(2212, "https://github.com/dotnet/roslyn-analyzers/issues/2212")] - public async Task AwaitedButNotDisposed_NoDiagnostic() - { - // We are conservative when disposable object gets wrapped in a task and consider it as escaped. - await TestDiagnosticMissingAsync(@" -using System; -using System.Threading.Tasks; - -class C : IDisposable -{ - public void Dispose() - { - } - - [| - public Task M1_Task() - { - return Task.FromResult(new C()); - } - - public async Task M2_Task() - { - var c = await M1_Task().ConfigureAwait(false); - } - |] -}"); - } - - [Fact, WorkItem(2212, "https://github.com/dotnet/roslyn-analyzers/issues/2212")] - public async Task AwaitedButNotDisposed_TaskWrappingField_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Threading.Tasks; - -class C : IDisposable -{ - private C _c; - public void Dispose() - { - } - - [| - public Task M1_Task() - { - return Task.FromResult(_c); - } - - public async Task M2_Task() - { - var c = await M1_Task().ConfigureAwait(false); - } - |] -}"); - } - - [Fact, WorkItem(2347, "https://github.com/dotnet/roslyn-analyzers/issues/2347")] - public async Task ReturnDisposableObjectInAsyncMethod_DisposedInCaller_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Threading.Tasks; - -class C : IDisposable -{ - public void Dispose() - { - } - - [| - public async Task M1_Task(object context) - { - await Task.Yield(); - return new C(); - } - - public async Task M2_Task() - { - var c = await M1_Task(null).ConfigureAwait(false); - c.Dispose(); - } - |] -}"); - } - - [Fact, WorkItem(2347, "https://github.com/dotnet/roslyn-analyzers/issues/2347")] - public async Task ReturnDisposableObjectInAsyncMethod_NotDisposedInCaller_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System; -using System.Threading.Tasks; - -class C : IDisposable -{ - public void Dispose() - { - } - - [| - public async Task M1_Task(object context) - { - await Task.Yield(); - return new C(); - } - - public async Task M2_Task() - { - var c = await M1_Task(null).ConfigureAwait(false); - } - |] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "M1_Task(null)").WithLocation(20, 23)); - } - - [Fact, WorkItem(2361, "https://github.com/dotnet/roslyn-analyzers/issues/2361")] - public async Task ExpressionBodiedMethod_ReturnsDisposableObject_NoDiagnostic() - { - await TestDiagnosticMissingAsync(@" -using System.IO; - -class C -{ - [|Stream M() => File.OpenRead(""C:/somewhere/"");|] -}"); - } - - [Fact, WorkItem(2361, "https://github.com/dotnet/roslyn-analyzers/issues/2361")] - public async Task ReturnsDisposableObject_NotDisposed_Diagnostic() - { - await TestDiagnosticsAsync(@" -using System.IO; - -class C -{ - [| - Stream GetStream() => File.OpenRead(""C:/somewhere/""); - - void M2() - { - var stream = GetStream(); - } - |] -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "GetStream()").WithLocation(11, 22)); - } - - [Fact, WorkItem(2497, "https://github.com/dotnet/roslyn-analyzers/issues/2497")] - public async Task UsingStatementInCatch() - { - await TestDiagnosticsAsync(@" -using System; -class C : IDisposable -{ - public void Dispose() { } - void M1() - { - try - { - } - catch (Exception) - { - [|using (var c = new C())|] - { - } - } - } -}"); - } - - [Fact, WorkItem(2497, "https://github.com/dotnet/roslyn-analyzers/issues/2497")] - public async Task TryFinallyStatementInCatch() - { - await TestDiagnosticsAsync(@" -using System; -class C : IDisposable -{ - public void Dispose() { } - void M1() - { - try - { - } - catch (Exception) - { - C c = null; - try - { - [|c = new C();|] - } - finally - { - c.Dispose(); - } - } - } -}"); - } - - [Fact, WorkItem(2497, "https://github.com/dotnet/roslyn-analyzers/issues/2497")] - public async Task UsingStatementInFinally() - { - await TestDiagnosticsAsync(@" -using System; -class C : IDisposable -{ - public void Dispose() { } - void M1() - { - try - { - } - finally - { - [|using (var c = new C())|] - { - } - } - } -}"); - } - - [Fact, WorkItem(32100, "https://github.com/dotnet/roslyn/issues/32100")] - public async Task UsingDeclaration() - { - await TestDiagnosticsAsync(@" -using System; -class C : IDisposable -{ - public void Dispose() { } - void M1() - { - [|using var c = new C()|]; - } -}", parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)); - } - - [Fact, WorkItem(32100, "https://github.com/dotnet/roslyn/issues/32100")] - public async Task UsingDeclarationWithInitializer() - { - await TestDiagnosticsAsync(@" -using System; -class C : IDisposable -{ - public int P { get; set; } - public void Dispose() { } - void M1() - { - [|using var c = new C() { P = 1 }|]; - } -}", parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)); - } - - [Fact] - public async Task MissingDisposeInMethodWithAttributes() - { - await TestDiagnosticsAsync(@" -using System; -class C : IDisposable -{ - public void Dispose() { } - - [Obsolete()] - void M1() - { - var c = [|new C()|]; - } -}", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId)); - } - - [Fact, WorkItem(36498, "https://github.com/dotnet/roslyn/issues/36498")] - public async Task DisposableObjectPushedToStackIsNotFlagged() - { - await TestDiagnosticMissingAsync(@" -using System; -using System.Collections.Generic; - -class C : IDisposable -{ - public void Dispose() { } - - public void M1(Stack stack) - { - var c = [|new C()|]; - stack.Push(c); - } -}"); - } - } -} diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs index 0f062946d6711..76408ecfea5ca 100644 --- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs @@ -356,15 +356,6 @@ public void CSharp_VerifyIDEDiagnosticSeveritiesAreConfigurable() # IDE0066 dotnet_diagnostic.IDE0066.severity = %value% -# IDE0067 -dotnet_diagnostic.IDE0067.severity = %value% - -# IDE0068 -dotnet_diagnostic.IDE0068.severity = %value% - -# IDE0069 -dotnet_diagnostic.IDE0069.severity = %value% - # IDE0070 dotnet_diagnostic.IDE0070.severity = %value% @@ -532,15 +523,6 @@ public void VisualBasic_VerifyIDEDiagnosticSeveritiesAreConfigurable() # IDE0060 dotnet_diagnostic.IDE0060.severity = %value% -# IDE0067 -dotnet_diagnostic.IDE0067.severity = %value% - -# IDE0068 -dotnet_diagnostic.IDE0068.severity = %value% - -# IDE0069 -dotnet_diagnostic.IDE0069.severity = %value% - # IDE0070 dotnet_diagnostic.IDE0070.severity = %value% @@ -922,15 +904,6 @@ No editorconfig based code style option # IDE0066, PreferSwitchExpression csharp_style_prefer_switch_expression = true -# IDE0067 -No editorconfig based code style option - -# IDE0068 -No editorconfig based code style option - -# IDE0069 -No editorconfig based code style option - # IDE0070 No editorconfig based code style option @@ -1140,15 +1113,6 @@ No editorconfig based code style option # IDE0060, UnusedParameters dotnet_code_quality_unused_parameters = all -# IDE0067 -No editorconfig based code style option - -# IDE0068 -No editorconfig based code style option - -# IDE0069 -No editorconfig based code style option - # IDE0070 No editorconfig based code style option diff --git a/src/EditorFeatures/VisualBasicTest/DisposeAnalysis/DisposableFieldsShouldBeDisposedTests.vb b/src/EditorFeatures/VisualBasicTest/DisposeAnalysis/DisposableFieldsShouldBeDisposedTests.vb deleted file mode 100644 index 226a0067de0b9..0000000000000 --- a/src/EditorFeatures/VisualBasicTest/DisposeAnalysis/DisposableFieldsShouldBeDisposedTests.vb +++ /dev/null @@ -1,1257 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports Microsoft.CodeAnalysis.CodeFixes -Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics -Imports Microsoft.CodeAnalysis.DisposeAnalysis - -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.DisposeAnalysis - Public Class DisposableFieldsShouldBeDisposedTests - Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest - Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) - Return (New DisposableFieldsShouldBeDisposedDiagnosticAnalyzer(isEnabledByDefault:=True), Nothing) - End Function - - ' Ensure that we explicitly test missing diagnostic, which has no corresponding code fix (non-fixable diagnostic). - Private Overloads Function TestDiagnosticMissingAsync(initialMarkup As String) As Task - Return TestDiagnosticMissingAsync(initialMarkup, New TestParameters(retainNonFixableDiagnostics:=True)) - End Function - - Private Overloads Function TestDiagnosticsAsync(initialMarkup As String, ParamArray expected As DiagnosticDescription()) As Task - Return TestDiagnosticsAsync(initialMarkup, New TestParameters(retainNonFixableDiagnostics:=True), expected) - End Function - - Private Shared Function Diagnostic(id As String, Optional sqiggledText As String = Nothing) As DiagnosticDescription - Return TestHelpers.Diagnostic(id, sqiggledText) - End Function - - - Public Async Function DisposableAllocationInConstructor_AssignedDirectly_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private ReadOnly a As A|] - Sub New() - a = New A() - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocationInConstructor_AssignedDirectly_NotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - Private ReadOnly [|a|] As A - Sub New() - a = New A() - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)) - End Function - - - Public Async Function DisposableAllocationInMethod_AssignedDirectly_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A|] - Sub SomeMethod() - a = New A() - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocationInMethod_AssignedDirectly_NotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - Private [|a|] As A - Sub SomeMethod() - a = New A() - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)) - End Function - - - Public Async Function DisposableAllocationInFieldInitializer_AssignedDirectly_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A() - Private ReadOnly a2 As New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose() - a2.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocationInFieldInitializer_AssignedDirectly_NotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A() - Private ReadOnly a2 As New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId, "a").WithLocation(12, 13), - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId, "a2").WithLocation(13, 22)) - End Function - - - Public Async Function StaticField_NotDisposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private Shared a As A = New A() - Private Shared ReadOnly a2 As New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AssignedThroughLocal_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A|] - Sub SomeMethod() - Dim l = New A() - a = l - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AssignedThroughLocal_NotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - Private [|a|] As A - Sub SomeMethod() - Dim l = New A() - a = l - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)) - End Function - - - Public Async Function DisposableAllocation_AssignedThroughParameter_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A|] - Sub New(p As A) - p = New A() - a = p - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AssignedThroughParameter_NotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - Private [|a|] As A - Sub New(p As A) - p = New A() - a = p - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)) - End Function - - - Public Async Function DisposableSymbolWithoutAllocation_AssignedThroughParameter_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A|] - Sub New(p As A) - a = p - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableSymbolWithoutAllocation_AssignedThroughParameter_NotDisposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A|] - Sub New(p As A) - a = p - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AssignedThroughInstanceInvocation_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A|] - Sub New() - a = GetA() - End Sub - - Private Function GetA() As A - Return New A() - End Function - - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AssignedThroughInstanceInvocation_NotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - Private [|a|] As A - Sub New() - a = GetA() - End Sub - - Private Function GetA() As A - Return New A() - End Function - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)) - End Function - - - Public Async Function DisposableAllocation_AssignedThroughStaticCreateInvocation_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A|] - Sub New() - a = Create() - End Sub - - Private Shared Function Create() As A - Return New A() - End Function - - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AssignedThroughStaticCreateInvocation_NotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - Private [|a|] As A - Sub New() - a = Create() - End Sub - - Private Shared Function Create() As A - Return New A() - End Function - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)) - End Function - - - Public Async Function DisposableAllocation_AssignedInDifferentType_DisposedInContainingType_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Public a As A|] - - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose() - End Sub -End Class - -Class WrapperB - Dim b As B - Public Sub Create() - b.a = new A() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AssignedInDifferentType_DisposedInDifferentNonDisposableType_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Public a As A|] - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class WrapperB - Dim b As B - - Public Sub Create() - b.a = new A() - End Sub - - Public Sub Dispose() - b.a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AssignedInDifferentType_NotDisposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Public a As A|] - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Public Sub M(b As B) - b.a = new A() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_DisposedWithConditionalAccess_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - a?.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AssignedToLocal_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - Dim l = a - l.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AssignedToLocal_NotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - Private [|a|] As A = New A() - - Public Sub Dispose() Implements IDisposable.Dispose - Dim l = a - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)) - End Function - - - Public Async Function DisposableAllocation_IfElseStatement_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A - Private b As A|] - - Public Sub New(ByVal flag As Boolean) - Dim l As A = New A() - If flag Then - a = l - Else - b = l - End If - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - Dim l As A = Nothing - If a IsNot Nothing Then - l = a - ElseIf b IsNot Nothing Then - l = b - End If - l.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_IfElseStatement_NotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A - Private b As A|] - - Public Sub New(ByVal flag As Boolean) - Dim l As A = New A() - If flag Then - a = l - Else - b = l - End If - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - Dim l As A = Nothing - If a IsNot Nothing Then - l = a - ElseIf b IsNot Nothing Then - l = b - End If - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId, "a").WithLocation(12, 13), - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId, "b").WithLocation(13, 13)) - End Function - - - Public Async Function DisposableAllocation_EscapedField_NotDisposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - DisposeA(a) - End Sub - - Private Shared Sub DisposeA(ByRef a As A) - a.Dispose() - a = Nothing - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_OptimisticPointsToAnalysis_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - Public Sub PerformSomeCleanup() - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - a.PerformSomeCleanup() - ClearMyState() - a.Dispose() - End Sub - - Private Sub ClearMyState() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_OptimisticPointsToAnalysis_WithReturn_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - Public Sub PerformSomeCleanup() - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - Public Disposed As Boolean - - Public Sub Dispose() Implements IDisposable.Dispose - If Disposed Then - Return - End If - - a.PerformSomeCleanup() - ClearMyState() - a.Dispose() - End Sub - - Private Sub ClearMyState() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_IfStatementInDispose_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Public Class Test - Implements IDisposable - [|Private ReadOnly a As A = New A()|] - Private cancelled As Boolean - - Public Sub Dispose() Implements IDisposable.Dispose - If cancelled Then - a.GetType() - End If - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_DisposedinDisposeOverride_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -MustInherit Class Base - Implements IDisposable - Public Overridable Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Derived - Inherits Base - - [|Private ReadOnly a As A = New A()|] - - Public Overrides Sub Dispose() - MyBase.Dispose() - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_DisposedWithDisposeBoolInvocation_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - Public Sub Dispose(disposed As Boolean) - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose(True) - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_DisposedInsideDisposeBool_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - Public Sub Dispose(disposed As Boolean) - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - Dispose(True) - End Sub - - Public Sub Dispose(disposed As Boolean) - a.Dispose(disposed) - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_DisposedWithDisposeCloseInvocation_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - Public Sub Close() - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - a.Close() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_AllDisposedMethodsMixed_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - Public Sub Dispose(disposed As Boolean) - End Sub - - Public Sub Close() - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A() - Private a2 As A = New A() - Private a3 As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - a.Close() - End Sub - - Public Sub Dispose(disposed As Boolean) - a2.Dispose() - End Sub - - Public Sub Close() - a3.Dispose(True) - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_DisposedInsideDisposeClose_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - Public Sub Dispose(disposed As Boolean) - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - Dispose(True) - End Sub - - Public Sub Dispose(disposed As Boolean) - a.Dispose(disposed) - End Sub -End Class") - End Function - - - Public Async Function SystemThreadingTask_SpecialCase_NotDisposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Threading.Tasks - -Public Class A - Implements IDisposable - - [|Private ReadOnly t As Task|] - - Public Sub New() - t = New Task(Nothing) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_DisposedWithDisposeAsyncInvocation_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Threading.Tasks - -Class A - Implements IDisposable - - Public Sub Dispose() Implements IDisposable.Dispose - DisposeAsync() - End Sub - - Public Function DisposeAsync() As Task - Return Task.CompletedTask - End Function -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - a.DisposeAsync() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_DisposedInsideDisposeCoreAsync_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"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 Task.CompletedTask - End Function - - Protected MustOverride Function DisposeCoreAsync(initialized As Boolean) As Task -End Class - -Class A2 - Inherits A - - Protected Overrides Function DisposeCoreAsync(initialized As Boolean) As Task - Return Task.CompletedTask - End Function -End Class - -Class B - Inherits A - - [|Private a As New A2()|] - - Protected Overrides Function DisposeCoreAsync(initialized As Boolean) As Task - Return a.DisposeAsync() - End Function -End Class") - End Function - - - Public Async Function DisposableAllocation_DisposedInInvokedMethod_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private a As A = New A()|] - - Public Sub Dispose() Implements IDisposable.Dispose - DisposeHelper() - End Sub - - Public Sub DisposeHelper() - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_NotDisposedInInvokedMethod_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - Private [|a|] As A = New A() - - Public Sub Dispose() Implements IDisposable.Dispose - DisposeHelper() - End Sub - - Public Sub DisposeHelper() - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)) - End Function - - - Public Async Function DisposableAllocation_DisposedInInvokedMethod_DisposableTypeInMetadata_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.IO - -Class B - Implements IDisposable - - [|Private a As FileStream = File.Open("""", FileMode.Create)|] - - Public Sub Dispose() Implements IDisposable.Dispose - DisposeHelper() - End Sub - - Private Sub DisposeHelper() - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function DisposableAllocation_NotDisposedInInvokedMethod_DisposableTypeInMetadata_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System -Imports System.IO - -Class B - Implements IDisposable - - Private [|a|] As FileStream = File.Open("""", FileMode.Create) - - Public Sub Dispose() Implements IDisposable.Dispose - DisposeHelper() - End Sub - - Private Sub DisposeHelper() - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)) - End Function - - - Public Async Function DisposableAllocation_DisposedInInvokedMethodMultipleLevelsDown_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.IO - -Class B - Implements IDisposable - - [|Private a As FileStream = File.Open("""", FileMode.Create)|] - - Public Sub Dispose() Implements IDisposable.Dispose - DisposeHelper() - End Sub - - Private Sub DisposeHelper() - Helper.PerformDispose(a) - End Sub -End Class - -Public Module Helper - Public Sub PerformDispose(ByVal a As IDisposable) - a.Dispose() - End Sub -End Module") - End Function - - - Public Async Function DisposableAllocation_NotDisposedInInvokedMethodMultipleLevelsDown_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System -Imports System.IO - -Class B - Implements IDisposable - - Private [|a|] As FileStream = File.Open("""", FileMode.Create) - - Public Sub Dispose() Implements IDisposable.Dispose - DisposeHelper() - End Sub - - Private Sub DisposeHelper() - Helper.PerformDispose(a) - End Sub -End Class - -Public Module Helper - Public Sub PerformDispose(ByVal a As IDisposable) - End Sub -End Module", - Diagnostic(IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId)) - End Function - - - Public Async Function DisposableAllocationInConstructor_DisposedInGeneratedCodeFile_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - [|Private ReadOnly a As A|] - Sub New() - a = New A() - End Sub - - _ - Public Sub Dispose() Implements IDisposable.Dispose - a.Dispose() - End Sub -End Class") - End Function - End Class -End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/DisposeAnalysis/DisposeObjectsBeforeLosingScopeTests.vb b/src/EditorFeatures/VisualBasicTest/DisposeAnalysis/DisposeObjectsBeforeLosingScopeTests.vb deleted file mode 100644 index bb7de88bf3c8d..0000000000000 --- a/src/EditorFeatures/VisualBasicTest/DisposeAnalysis/DisposeObjectsBeforeLosingScopeTests.vb +++ /dev/null @@ -1,2830 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports Microsoft.CodeAnalysis.CodeFixes -Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics -Imports Microsoft.CodeAnalysis.DisposeAnalysis - -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.DisposeAnalysis - Public Class DisposeObjectsBeforeLosingScopeTests - Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest - Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) - Return (New DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer(isEnabledByDefault:=True), Nothing) - End Function - - ' Ensure that we explicitly test missing diagnostic, which has no corresponding code fix (non-fixable diagnostic). - Private Overloads Function TestDiagnosticMissingAsync(initialMarkup As String) As Task - Return TestDiagnosticMissingAsync(initialMarkup, New TestParameters(retainNonFixableDiagnostics:=True)) - End Function - - Private Overloads Function TestDiagnosticsAsync(initialMarkup As String, ParamArray expected As DiagnosticDescription()) As Task - Return TestDiagnosticsAsync(initialMarkup, New TestParameters(retainNonFixableDiagnostics:=True), expected) - End Function - - Private Shared Function Diagnostic(id As String, Optional sqiggledText As String = Nothing) As DiagnosticDescription - Return TestHelpers.Diagnostic(id, sqiggledText) - End Function - - - Public Async Function LocalWithDisposableInitializer_DisposeCall_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - [|Dim a As New A()|] - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function LocalWithDisposableInitializer_NoDisposeCall_Diagnostic() As Task - Await TestDiagnosticsAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - Dim a As [|New A()|] - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId)) - End Function - - - Public Async Function LocalWithDisposableAssignment_DisposeCall_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - [|Dim a As A - a = New A() - a.Dispose() - - Dim b As New A() - a = b - a.Dispose()|] - End Sub -End Class") - End Function - - - Public Async Function LocalWithDisposableAssignment_NoDisposeCall_Diagnostic() As Task - Await TestDiagnosticsAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - Dim a As A - a = [|New A()|] - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId)) - End Function - - - Public Async Function ParameterWithDisposableAssignment_DisposeCall_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1(a As A) - [|a = New A() - a.Dispose()|] - End Sub -End Class") - End Function - - - Public Async Function ParameterWithDisposableAssignment_NoDisposeCall_Diagnostic() As Task - Await TestDiagnosticsAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1(a As A) - a = [|New A()|] - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId)) - End Function - - - Public Async Function RefParametersWithDisposableAssignment_NoDisposeCall_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1(ByRef a As A) - [|a = New A()|] - End Sub -End Class") - End Function - - - Public Async Function LocalWithMultipleDisposableAssignment_DisposeCallOnSome_Diagnostic() As Task - Await TestDiagnosticsAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - Dim a As A - [|a = New A(1) - a = New A(2) - a.Dispose() - a = New A(3)|] - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(1)").WithLocation(15, 13), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(3)").WithLocation(18, 13)) - End Function - - - Public Async Function FieldWithDisposableAssignment_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub -End Class - -Class Test - Public a As A - Sub M1(p As Test) - [|p.a = New A() - - Dim l As New Test() - l.a = New A() - - Me.a = New A()|] - End Sub -End Class") - End Function - - - Public Async Function PropertyWithDisposableAssignment_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub -End Class - -Class Test - Public Property a As A - Sub M1(p As Test) - [|p.a = New A() - - Dim l As New Test() - l.a = New A() - - Me.a = New A()|] - End Sub -End Class") - End Function - - - Public Async Function Interprocedural_DisposedInHelper_MethodInvocation_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1(t2 As Test2) - [|DisposeHelper(new A()) - t2.DisposeHelper_MethodOnDifferentType(new A()) - DisposeHelper_MultiLevelDown(new A())|] - End Sub - - Sub DisposeHelper(a As A) - a.Dispose() - End Sub - - Sub DisposeHelper_MultiLevelDown(a As A) - DisposeHelper(a) - End Sub -End Class - -Class Test2 - Sub DisposeHelper_MethodOnDifferentType(a As A) - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function Interprocedural_DisposeOwnershipTransfer_MethodInvocation_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Public a As A - Sub M1() - [|DisposeOwnershipTransfer(new A()) - Dim t2 = New Test2() - t2.DisposeOwnershipTransfer_MethodOnDifferentType(new A()) - DisposeOwnershipTransfer_MultiLevelDown(new A())|] - End Sub - - Sub DisposeOwnershipTransfer(a As A) - Me.a = a - End Sub - - Sub DisposeOwnershipTransfer_MultiLevelDown(a As A) - DisposeOwnershipTransfer(a) - End Sub -End Class - -Class Test2 - Public a As A - Sub DisposeOwnershipTransfer_MethodOnDifferentType(a As A) - Me.a = a - End Sub -End Class") - End Function - - - Public Async Function Interprocedural_NoDisposeOwnershipTransfer_MethodInvocation_Diagnostic() As Task - Await TestDiagnosticsAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Public a As A - Sub M1(t2 As Test2) - [|NoDisposeOwnershipTransfer(new A(1)) - t2.NoDisposeOwnershipTransfer_MethodOnDifferentType(new A(2)) - NoDisposeOwnershipTransfer_MultiLevelDown(new A(3))|] - End Sub - - Sub NoDisposeOwnershipTransfer(a As A) - Dim str = a.ToString() - Dim b = a - End Sub - - Sub NoDisposeOwnershipTransfer_MultiLevelDown(a As A) - NoDisposeOwnershipTransfer(a) - End Sub -End Class - -Class Test2 - Public a As A - Public Sub NoDisposeOwnershipTransfer_MethodOnDifferentType(a As A) - Dim str = a.ToString() - Dim b = a - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(15, 36), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(16, 61), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(3)").WithLocation(17, 51)) - End Function - - - Public Async Function Interprocedural_DisposedInHelper_ConstructorInvocation_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - [|Dim unused = new DisposeHelperType(new A()) - DisposeHelper_MultiLevelDown(new A())|] - End Sub - - Sub DisposeHelper(a As A) - Dim unused = new DisposeHelperType(a) - End Sub - - Sub DisposeHelper_MultiLevelDown(a As A) - DisposeHelper(a) - End Sub -End Class - -Class DisposeHelperType - Public Sub New(a As A) - a.Dispose() - End Sub -End Class") - End Function - - - Public Async Function Interprocedural_DisposeOwnershipTransfer_ConstructorInvocation_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - [|Dim unused = new DisposableOwnerType(new A()) - DisposeOwnershipTransfer_MultiLevelDown(new A())|] - End Sub - - Sub DisposeOwnershipTransfer(a As A) - Dim unused = new DisposableOwnerType(a) - End Sub - - Sub DisposeOwnershipTransfer_MultiLevelDown(a As A) - DisposeOwnershipTransfer(a) - End Sub -End Class - -Class DisposableOwnerType - Public a As A - Public Sub New(a As A) - Me.a = a - End Sub -End Class") - End Function - - - Public Async Function Interprocedural_NoDisposeOwnershipTransfer_ConstructorInvocation_Diagnostic() As Task - Await TestDiagnosticsAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - [|Dim unused = new NotDisposableOwnerType(new A(1)) - NoDisposeOwnershipTransfer_MultiLevelDown(new A(2))|] - End Sub - - Sub NoDisposeOwnershipTransfer(a As A) - Dim unused = new NotDisposableOwnerType(a) - End Sub - - Sub NoDisposeOwnershipTransfer_MultiLevelDown(a As A) - NoDisposeOwnershipTransfer(a) - End Sub -End Class - -Class NotDisposableOwnerType - Public a As A - Public Sub New(a As A) - Dim str = a.ToString() - Dim b = a - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(1)").WithLocation(14, 49), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "new A(2)").WithLocation(15, 51)) - End Function - - - Public Async Function DisposeOwnershipTransfer_AtConstructorInvocation_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -" - - A2 - -Imports System - -Class Test - Private Function M1() As DisposableOwnerType - Return [|New DisposableOwnerType(New A())|] - End Function -End Class - - - - -Imports System - -Public Class A - Implements IDisposable - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Public Class DisposableOwnerType - Public Sub New(ByVal a As A) - End Sub -End Class - - -") - End Function - - - Public Async Function DisposableCreationInLoop_DisposedInFinally_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class Test - Public Sub M() - [|Dim disposeMe As IDisposable = Nothing - Try - For Each c In ""Foo"" - If disposeMe Is Nothing Then - disposeMe = New A() - End If - Next - Finally - If disposeMe IsNot Nothing Then - disposeMe.Dispose() - End If - End Try|] - End Sub -End Class - -Public Class A - Implements IDisposable - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class") - End Function - - - Public Async Function LocalWithDisposableAssignment_DisposeBoolCall_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub - - Public Sub Dispose(b As Boolean) - End Sub -End Class - -Class Test - Sub M1() - [|Dim a As A - a = New A() - a.Dispose(true) - - Dim b As New A() - a = b - a.Dispose(true)|] - End Sub -End Class") - End Function - - - Public Async Function LocalWithDisposableAssignment_CloseCall_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub - - Public Sub Close() - End Sub -End Class - -Class Test - Sub M1() - [|Dim a As A - a = New A() - a.Close() - - Dim b As New A() - a = b - a.Close()|] - End Sub -End Class") - End Function - - - Public Async Function LocalWithDisposableAssignment_DisposeAsyncCall_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System -Imports System.Threading.Tasks - -Class A - Implements IDisposable - - Public Sub Dispose() Implements IDisposable.Dispose - DisposeAsync() - End Sub - - Public Function DisposeAsync() As Task - Return Task.CompletedTask - End Function -End Class - -Class Test - Async Function M1() As Task - [|Dim a As A - a = New A() - Await a.DisposeAsync() - - Dim b As New A() - a = b - Await a.DisposeAsync()|] - End Function -End Class") - End Function - - - Public Async Function ArrayElementWithDisposableAssignment_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Public Property a As A - Sub M1(a As A()) - [|a(0) = New A()|] ' TODO: https://github.com/dotnet/roslyn-analyzers/issues/1577 - End Sub -End Class") - End Function - - - Public Async Function ArrayElementWithDisposableAssignment_ConstantIndex_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Public Property a As A - Sub M1(a As A()) - [|a(0) = New A() - a(0).Dispose()|] - End Sub -End Class") - End Function - - - Public Async Function ArrayElementWithDisposableAssignment_NonConstantIndex_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Public Property a As A - Sub M1(a As A(), i As Integer) - [|a(i) = New A() - a(i).Dispose()|] - End Sub -End Class") - End Function - - - Public Async Function ArrayElementWithDisposableAssignment_NonConstantIndex_02_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -$"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Public Property a As A - Sub M1(a As A(), i As Integer, j As Integer) - [|a(i) = New A() - i = j ' Value of i is now unknown - a(i).Dispose()|] ' We don't know the points to value of a(i), so don't flag 'New A()' - End Sub -End Class") - End Function - - - Public Async Function ArrayInitializer_ElementWithDisposableAssignment_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - [|Dim a As A() = New A() { New A() }|] ' TODO: https://github.com/dotnet/roslyn-analyzers/issues/1577 - End Sub -End Class") - End Function - - - Public Async Function ArrayInitializer_ElementWithDisposableAssignment_ConstantIndex_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - [|Dim a As A() = New A() {New A()} - a(0).Dispose()|] - End Sub -End Class") - End Function - - - Public Async Function ArrayInitializer_ElementWithDisposableAssignment_NonConstantIndex_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1(i As Integer) - [|Dim a As A() = New A() {New A()} - a(i).Dispose()|] - End Sub -End Class") - End Function - - - Public Async Function CollectionInitializer_ElementWithDisposableAssignment_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Collections.Generic - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub -End Class - -Class Test - Sub M1() - [|Dim a As List(Of A) = New List(Of A) From { New A() }|] ' TODO: https://github.com/dotnet/roslyn-analyzers/issues/1577 - End Sub -End Class") - End Function - - - Public Async Function CollectionInitializer_ElementWithDisposableAssignment_ConstantIndex_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - Imports System.Collections.Generic - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1() - [|Dim a As List(Of A) = New List(Of A) From {New A()} - a(0).Dispose()|] - End Sub -End Class") - End Function - - - Public Async Function CollectionInitializer_ElementWithDisposableAssignment_NonConstantIndex_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Collections.Generic - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub -End Class - -Class Test - Sub M1(i As Integer) - [|Dim a As List(Of A) = New List(Of A) From {New A()} - a(i).Dispose()|] - End Sub -End Class") - End Function - - - Public Async Function CollectionAdd_SpecialCases_ElementWithDisposableAssignment_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Collections -Imports System.Collections.Generic - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class NonGenericList - Implements ICollection - - Public Sub Add(item As A) - End Sub - - Public ReadOnly Property Count As Integer Implements ICollection.Count - Get - Throw New NotImplementedException() - End Get - End Property - - Public ReadOnly Property SyncRoot As Object Implements ICollection.SyncRoot - Get - Throw New NotImplementedException() - End Get - End Property - - Public ReadOnly Property IsSynchronized As Boolean Implements ICollection.IsSynchronized - Get - Throw New NotImplementedException() - End Get - End Property - - Public Sub CopyTo(array As Array, index As Integer) Implements ICollection.CopyTo - Throw New NotImplementedException() - End Sub - - Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator - Throw New NotImplementedException() - End Function -End Class - -Class Test - Private Sub M1() - [|Dim a As New List(Of A)() - a.Add(New A(1)) - - Dim b As A = New A(2) - a.Add(b) - - Dim l As New NonGenericList() - l.Add(New A(3)) - - b = New A(4) - l.Add(b)|] - End Sub -End Class") - End Function - - - Public Async Function CollectionAdd_IReadOnlyCollection_SpecialCases_ElementWithDisposableAssignment_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Collections -Imports System.Collections.Concurrent -Imports System.Collections.Generic - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class MyReadOnlyCollection - Implements IReadOnlyCollection(Of A) - - Public Sub Add(ByVal item As A) - End Sub - - Public ReadOnly Property Count As Integer Implements IReadOnlyCollection(Of A).Count - Get - Throw New NotImplementedException() - End Get - End Property - - Public Function GetEnumerator() As IEnumerator(Of A) Implements IEnumerable(Of A).GetEnumerator - Throw New NotImplementedException() - End Function - - Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator - Throw New NotImplementedException() - End Function -End Class - -Class Test - Private Sub M1() - [|Dim myReadOnlyCollection = New MyReadOnlyCollection() - myReadOnlyCollection.Add(New A(1)) - Dim a As A = New A(2) - myReadOnlyCollection.Add(a) - - Dim bag = New ConcurrentBag(Of A)() - bag.Add(New A(3)) - Dim a2 As A = New A(4) - bag.Add(a2)|] - End Sub -End Class") - End Function - - - Public Async Function MemberInitializerWithDisposableAssignment_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Collections.Generic - -Class A - Implements IDisposable - Public X As Integer - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub -End Class - -Class Test - Public a As A - Sub M1() - [|Dim a = New Test With {.a = New A() With { .X = 1 }} |] - End Sub -End Class") - End Function - - - Public Async Function StructImplementingIDisposable_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Structure A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub -End Structure - -Class Test - Sub M1() - [|Dim a As New A()|] - End Sub -End Class") - End Function - - - Public Async Function NonUserDefinedConversions_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Inherits A -End Class - -Class Test - Sub M1() - [|Dim obj As Object = New A() ' Implicit conversion from A to object - DirectCast(obj, A).Dispose() ' Explicit conversion from object to A - - Dim a As A = new B() ' Implicit conversion from B to A - a.Dispose()|] - End Sub -End Class") - End Function - - - Public Async Function NonUserDefinedConversions_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Inherits A -End Class - -Class Test - Sub M1() - [|Dim obj As Object = New A() ' Implicit conversion from A to object - Dim a As A = DirectCast(New B(), A)|] ' Explicit conversion from B to A - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A()").WithLocation(15, 29), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New B()").WithLocation(16, 33)) - End Function - - - Public Async Function UserDefinedConversions_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - Public Shared Widening Operator CType(ByVal value As A) As B - value.Dispose() - Return Nothing - End Operator - - Public Shared Widening Operator CType(ByVal value As B) As A - value.Dispose() - Return Nothing - End Operator -End Class - -Class B - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Private Sub M1() - [|Dim a As A = New B() ' Implicit user defined conversion - Dim b As B = CType(New A(), B)|] ' Explicit user defined conversion - End Sub -End Class") - End Function - - - Public Async Function LocalWithDisposableAssignment_ByRef_DisposedInCallee_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - [|Sub M1() - Dim a As New A() - M2(a) - End Sub - - Sub M2(ByRef a as A) - a.Dispose() - a = Nothing - End Sub|] -End Class") - End Function - - - Public Async Function LocalWithDisposableAssignment_ByRefEscape_AbstractVirtualMethod_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Public Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Public MustInherit Class Test - Sub M1() - [|Dim a As New A() - M2(a) - - a = New A() - M3(a)|] - End Sub - - Public Overridable Sub M2(ByRef a as A) - End Sub - - Public MustOverride Sub M3(ByRef a as A) -End Class") - End Function - - - Public Async Function LocalWithDefaultOfDisposableAssignment_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - Sub M1() - [|Dim a As A = Nothing|] - End Sub -End Module") - End Function - - - Public Async Function NullCoalesce_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1(a As A) - [|Dim b As A = If(a, New A()) - b.Dispose() - - Dim c As New A() - Dim d As A = If(c, a) - d.Dispose() - - a = New A() - Dim e As A = If(a, New A()) - e.Dispose()|] - End Sub -End Class") - End Function - - - Public Async Function NullCoalesce_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - Sub M1(a As A) - Dim b As A = If(a, [|New A()|]) - a.Dispose() - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A()").WithLocation(11, 28)) - End Function - - - Public Async Function WhileLoop_DisposeOnBackEdge_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - Sub M1(flag As Boolean) - [|Dim a As New A() - While True - a.Dispose() - If flag Then - Exit While ' All 'A' instances have been disposed on this path, so no diagnostic should be reported. - End If - a = New A() - End While|] - End Sub -End Module") - End Function - - - - Public Async Function WhileLoop_MissingDisposeOnExit_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As New A(1) ' Allocated outside the loop and disposed inside a loop is not a recommended pattern and is flagged. - While True - a.Dispose() - a = New A(2) ' This instance will not be disposed on loop exit. - End While - End Sub|] -End Module", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(1)").WithLocation(14, 18), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(2)").WithLocation(17, 17)) - End Function - - - Public Async Function WhileLoop_MissingDisposeOnEntry_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As New A(1) ' This instance will never be disposed. - While True - a = New A(2) - a.Dispose() - End While - End Sub|] -End Module", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(1)").WithLocation(14, 18)) - End Function - - - Public Async Function DoWhileLoop_DisposeOnBackEdge_NoDiagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1(flag As Boolean) - Dim a As New A() - Do While True - a.Dispose() - If flag Then - Exit Do ' All 'A' instances have been disposed on this path, so no diagnostic should be reported. - End If - a = New A() - Loop - End Sub|] -End Module") - End Function - - - Public Async Function DoWhileLoop_MissingDisposeOnExit_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As New A(1) - Do - a.Dispose() - a = New A(2) ' This instance will not be disposed on loop exit. - Loop While True - End Sub|] -End Module", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(2)").WithLocation(17, 17)) - End Function - - - Public Async Function DoWhileLoop_MissingDisposeOnEntry_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As New A(1) ' This instance will never be disposed. - Do While True - a = New A(2) - a.Dispose() - Loop - End Sub|] -End Module", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(1)").WithLocation(14, 18)) - End Function - - - Public Async Function ForLoop_DisposeOnBackEdge_MayBeNotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1(flag As Boolean) - Dim a As New A(1) ' Allocation outside a loop, dispose inside a loop is not a recommended pattern and should fire diagnostic. - For i As Integer = 0 To 10 - a.Dispose() - If flag Then - Exit For ' All 'A' instances have been disposed on this path. - End If - a = New A(2) ' This can leak on loop exit, and is flagged as a maybe disposed violation. - Next - End Sub|] -End Module", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(1)").WithLocation(14, 18), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(2)").WithLocation(20, 17)) - End Function - - - Public Async Function ForLoop_MissingDisposeOnExit_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As New A(1) ' Allocation outside a loop, dispose inside a loop is not a recommended pattern and should fire diagnostic. - For i As Integer = 0 To 10 - a.Dispose() - a = New A(2) ' This instance will not be disposed on loop exit. - Next - End Sub|] -End Module", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(1)").WithLocation(14, 18), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(2)").WithLocation(17, 17)) - End Function - - - Public Async Function ForLoop_MissingDisposeOnEntry_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As New A(1) ' This instance will never be disposed. - For i As Integer = 0 To 10 - a = New A(2) - a.Dispose() - Next - End Sub|] -End Module", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(1)").WithLocation(14, 18)) - End Function - - - Public Async Function IfStatement_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub -End Class - -Class B - Inherits A -End Class - -Class Test - [|Private Sub M1(a As A, param As String) - Dim a1 As New A() - Dim a2 As B = new B() - Dim b As A - If param IsNot Nothing Then - a = a1 - b = new B() - Else - a = a2 - b = new A() - End If - - a.Dispose() ' a points to either a1 or a2. - b.Dispose() ' b points to either instance created in if or else. - End Sub|] -End Class") - End Function - - - Public Async Function IfStatement_02_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Inherits A -End Class - -Class Test - [|Private Sub M1(a As A, param As String, param2 As String) - Dim a1 As New A() - Dim a2 As B = new B() - Dim b As A - If param IsNot Nothing Then - a = a1 - b = new B() - If param = """" Then - a = new B() - Else - If param2 IsNot Nothing Then - b = new A() - Else - b = new B() - End If - End If - Else - a = a2 - b = new A() - End If - - a.Dispose() ' a points to either a1 or a2 or instance created in 'if(param == """")'. - b.Dispose() ' b points to either instance created in outer if or outer else or innermost if or innermost else. - End Sub|] -End Class") - End Function - - - Public Async Function IfStatement_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub New() - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Inherits A -End Class - -Class C - Inherits B -End Class - -Class D - Inherits C -End Class - -Class E - Inherits D -End Class - -Class Test - [|Private Sub M1(ByVal a As A, ByVal param As String, ByVal param2 As String) - Dim a1 As A = New A(1) ' Maybe disposed. - Dim a2 As B = New B() ' Never disposed. - Dim b As A - - If param IsNot Nothing Then - a = a1 - b = New C() ' Never disposed. - Else - a = a2 - b = New D() ' Never disposed. - End If - - ' a points to either a1 or a2. - ' b points to either instance created in if or else. - - If param IsNot Nothing Then - Dim c As A = New A(2) - a = c - b = a1 - Else - Dim d As C = New E() - b = d - a = b - End If - - a.Dispose() ' a points to either c or d. - b.Dispose() ' b points to either a1 or d. - End Sub|] -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New B()").WithLocation(34, 23), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New C()").WithLocation(39, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New D()").WithLocation(42, 17)) - End Function - - - Public Async Function IfStatement_02_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub New() - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Inherits A -End Class - -Class C - Inherits B -End Class - -Class D - Inherits C -End Class - -Class E - Inherits D -End Class - -Class Test - [|Private Sub M1(ByVal a As A, ByVal param As String, ByVal param2 As String) - Dim a1 As A = New B() ' Never disposed - Dim a2 As B = New C() ' Never disposed - Dim b As A - If param IsNot Nothing Then - a = a1 - b = New A(1) ' Always disposed - If param = """" Then - a = New D() ' Never disposed - Else - If param2 IsNot Nothing Then - b = New A(2) ' Maybe disposed - Else - b = New A(3) ' Maybe disposed - If param = """" Then - b = New A(4) ' Maybe disposed - End If - End If - - If param2 = """" Then - b.Dispose() ' b points to one of the three instances of A created above. - b = New A(5) ' Always disposed - End If - End If - Else - a = a2 - b = New A(6) ' Maybe disposed - If param2 IsNot Nothing Then - a = New A(7) ' Always disposed - Else - a = New A(8) ' Always disposed - b = New A(9) ' Always disposed - End If - - a.Dispose() - End If - - b.Dispose() - End Sub|] -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New B()").WithLocation(33, 23), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New C()").WithLocation(34, 23), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New D()").WithLocation(40, 21)) - End Function - - - Public Async Function UsingStatement_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - [|Private Sub M1() - Using a As New A() - End Using - - Dim b As A = New A() - Using b - End Using - - Using c As New A(), d = New A() - End Using - - Using a As A = Nothing - End Using - End Sub|] -End Class") - End Function - - - Public Async Function UsingStatementInTryCatch_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System.IO - -Class Test - Private Sub M1() - Try - [|Using ms = New MemoryStream()|] - End Using - Catch - End Try - End Sub -End Class") - End Function - - - Public Async Function NestedTryFinallyInTryCatch_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System.IO - -Class Test - Private Sub M1() - Try - [|Dim ms = New MemoryStream()|] - Try - Finally - ms?.Dispose() - End Try - Catch - End Try - End Sub -End Class") - End Function - - - Public Async Function ReturnStatement_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Collections.Generic - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - [|Private Function M1() As A - Return New A() - End Function - - Private Function M2(a As A) As A - a = New A() - Return a - End Function - - Private Function M3(a As A) As A - a = New A() - Dim b = a - Return b - End Function - - Public Iterator Function M4() As IEnumerable(Of A) - Yield New A - End Function|] -End Class") - End Function - - - Public Async Function ReturnStatement_02_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Collections.Generic - -Class A - Implements I, IDisposable - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Interface I -End Interface - -Class Test - [|Private Function M1() As I - Return New A() - End Function - - Private Function M2() As I - Return TryCast(New A(), I) - End Function|] -End Class") - End Function - - - Public Async Function LambdaInvocation_EmptyBody_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As A - a = New A() - - Dim myLambda As System.Action = Sub() - End Sub - - myLambda() ' This should not change state of 'a'. - End Sub|] -End Module", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A()").WithLocation(12, 13)) - End Function - - - Public Async Function LambdaInvocation_DisposesCapturedValue_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As New A() - - Dim myLambda As System.Action = Sub() - a.Dispose() - End Sub - - myLambda() ' This should change state of 'a' to be Disposed. - End Sub|] -End Module") - End Function - - - Public Async Function LambdaInvocation_CapturedValueAssignedNewDisposable_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As A - - Dim myLambda As System.Action = Sub() - a = New A() - End Sub - - myLambda() ' This should change state of 'a' to be NotDisposed and fire a diagnostic. - End Sub|] -End Module", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A()").WithLocation(14, 49)) - End Function - - - Public Async Function LambdaInvocation_ChangesCapturedValueContextSensitive_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As A - - Dim myLambda As System.Action(Of A) = Sub(b As A) - a = b - End Sub - - myLambda(New A()) ' This should change state of 'a' to be NotDisposed and fire a diagnostic. - End Sub|] -End Module", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A()").WithLocation(18, 18)) - End Function - - - Public Async Function DelegateInvocation_EmptyBody_NoArguments_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As A - a = New A() - - Dim myDelegate As System.Action = AddressOf M2 - myDelegate() ' This should not change state of 'a' as it is not passed as argument. - End Sub|] - - Sub M2() - End Sub -End Module", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A()").WithLocation(12, 13)) - End Function - - - Public Async Function DelegateInvocation_PassedAsArgumentButNotDisposed_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As A - a = New A() - - Dim myDelegate As System.Action(Of A) = AddressOf M2 - myDelegate(a) ' This should not change state of 'a'. - End Sub|] - - Sub M2(a As A) - End Sub -End Module", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A()").WithLocation(12, 13)) - End Function - - - Public Async Function DelegateInvocation_DisposesCapturedValue_NoDiagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Module Test - [|Sub M1() - Dim a As A - a = New A() - - Dim myDelegate As System.Action(Of A) = AddressOf M2 - myDelegate(a) ' This should change state of 'a' to be disposed as we perform interprocedural analysis. - End Sub|] - - Sub M2(a As A) - a.Dispose() - End Sub -End Module") - End Function - - - Public Async Function DisposableCreationNotAssignedToAVariable_BailOut_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public X As Integer - - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - Public Sub M() - End Sub -End Class - -Class Test - [|Private Sub M1() - New A(1) ' Error - New A(2).M() ' Error - Dim x = New A(3).X - End Sub|] -End Class") - End Function - - - Public Async Function DisposableCreationPassedToDisposableConstructor_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - - Public X As Integer - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Implements IDisposable - - Private ReadOnly _a As A - Public Sub New(ByVal a As A) - _a = a - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - [|Private Sub M1() - Dim b = New B(New A()) - b.Dispose() - Dim a = New A() - Dim b2 As B = Nothing - Try - b2 = New B(a) - Finally - If b2 IsNot Nothing Then - b2.Dispose() - End If - End Try - - Dim a2 = New A() - Dim b3 As B = Nothing - Try - b3 = New B(a2) - Finally - If b3 IsNot Nothing Then - b3.Dispose() - End If - End Try - End Sub|] -End Class") - End Function - - - Public Async Function DisposableObjectOnlyDisposedOnExceptionPath_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - [|Private Sub M1() - Dim a = New A(1) - Try - ThrowException() - Catch ex As Exception - a.Dispose() - End Try - End Sub - - Private Sub M2() - Dim a = New A(2) - Try - ThrowException() - Catch ex As System.IO.IOException - a.Dispose() - End Try - End Sub - - Private Sub M3() - Dim a = New A(3) - Try - ThrowException() - Catch ex As System.IO.IOException - a.Dispose() - Catch ex As Exception - a.Dispose() - End Try - End Sub - - Private Sub M4(flag As Boolean) - Dim a = New A(4) - Try - ThrowException() - Catch ex As System.IO.IOException - If flag Then - a.Dispose() - End If - End Try - End Sub|] - - Private Sub ThrowException() - Throw New NotImplementedException() - End Sub -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(1)").WithLocation(14, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(2)").WithLocation(23, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(3)").WithLocation(32, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(4)").WithLocation(43, 17)) - End Function - - - Public Async Function DisposableObjectDisposed_FinallyPath_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - [|Private Sub M1() - Dim a = New A() - Try - ThrowException() - Finally - a.Dispose() - End Try - End Sub - - Private Sub M2() - Dim a = New A() - Try - ThrowException() - Catch ex As Exception - Finally - a.Dispose() - End Try - End Sub - - Private Sub M3() - Dim a = New A() - Try - ThrowException() - a.Dispose() - a = Nothing - Catch ex As System.IO.IOException - Finally - If a IsNot Nothing Then - a.Dispose() - End If - End Try - End Sub|] - - Private Sub ThrowException() - Throw New NotImplementedException() - End Sub -End Class") - End Function - - - Public Async Function DelegateCreation_Disposed_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - - End Sub -End Class - -Class Test - [|Sub M1() - Dim createA As Func(Of A) = AddressOf M2 - Dim a As A = createA() - a.Dispose() - End Sub - - Function M2() As A - Return New A() - End Function|] -End Class") - End Function - - - Public Async Function MultipleReturnStatements_AllInstancesReturned_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Threading.Tasks -Imports System.Runtime.InteropServices - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Public Class Test - [|Private Function M1(ByVal flag As Boolean) As A - Dim a As A - If flag Then - Dim a2 As New A() - a = a2 - Return a - End If - - Dim a3 As New A() - a = a3 - Return a - End Function|] -End Class") - End Function - - - Public Async Function MultipleReturnStatements_AllInstancesEscapedWithOutParameter_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Threading.Tasks -Imports System.Runtime.InteropServices - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Public Class Test - [|Private Sub M1(ByVal flag As Boolean, ByRef a As A) - If flag Then - Dim a2 As New A() - a = a2 - Return - End If - - Dim a3 As New A() - a = a3 - Return - End Sub|] -End Class") - End Function - - - Public Async Function MultipleReturnStatements_AllButOneInstanceReturned_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System -Imports System.Threading.Tasks -Imports System.Runtime.InteropServices - -Class A - Implements IDisposable - - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Public Class Test - [|Private Function M1(flag As Integer, flag2 As Boolean, flag3 As Boolean) As A - Dim a As A = Nothing - If flag = 0 Then - Dim a2 As A = New A(1) ' Escaped with return inside below nested 'if', not disposed on other paths. - a = a2 - If Not flag2 Then - If flag3 Then - Return a - End If - End If - Else - a = New A(2) ' Escaped with return inside below nested 'else', not disposed on other paths. - If flag = 1 Then - a = New A(3) ' Never disposed on any path. - Else - If flag3 Then - a = New A(4) ' Escaped with return inside below 'else', not disposed on other paths. - End If - - If flag2 Then - Else - Return a - End If - End If - End If - - Dim a3 As A = New A(5) ' Always escaped with below return, ensure no diagnostic. - a = a3 - Return a - End Function|] -End Class", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(1)").WithLocation(19, 27), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(2)").WithLocation(27, 17), - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New A(3)").WithLocation(29, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(4)").WithLocation(32, 25)) - End Function - - - Public Async Function MultipleReturnStatements_AllButOneInstanceEscapedWithOutParameter_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System -Imports System.Threading.Tasks -Imports System.Runtime.InteropServices - -Class A - Implements IDisposable - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class B - Inherits A -End Class - -Public Class Test - [|Private Sub M1(flag As Integer, flag2 As Boolean, flag3 As Boolean, ByRef a As A) - a = Nothing - If flag = 0 Then - Dim a2 As A = New A() ' Escaped with return inside below nested 'if'. - a = a2 - If Not flag2 Then - If flag3 Then - Return - End If - End If - Else - a = New A() ' Escaped with return inside below nested 'else'. - If flag = 1 Then - a = New B() ' Never disposed - Else - If flag3 Then - a = New A() ' Escaped with return inside below 'else'. - End If - - If flag2 Then - Else - Return - End If - End If - End If - - Dim a3 As A = New A() ' Escaped with below return. - a = a3 - Return - End Sub|] -End Class", - Diagnostic(IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, "New B()").WithLocation(29, 21)) - End Function - - - Public Async Function DifferentDisposePatternsInFinally_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System - -Class A - Implements IDisposable - - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - [| - Private Sub M1() - Dim a As A = New A(1) - - Try - Finally - a?.Dispose() - End Try - End Sub - - Private Sub M2() - Dim a As A = Nothing - - Try - a = New A(2) - Finally - a?.Dispose() - End Try - End Sub - - Private Sub M3() - Dim a As A = New A(3) - - Try - Finally - If a IsNot Nothing Then - a?.Dispose() - End If - End Try - End Sub - - Private Sub M4() - Dim a As A = Nothing - - Try - a = New A(4) - Finally - If a IsNot Nothing Then - a?.Dispose() - End If - End Try - End Sub - - Private Sub M5() - Dim a As A = New A(5) - - Try - Finally - DisposeHelper(a) - End Try - End Sub - - Private Sub M6() - Dim a As A = Nothing - - Try - a = New A(6) - Finally - DisposeHelper(a) - End Try - End Sub - - Private Sub DisposeHelper(a As IDisposable) - If a IsNot Nothing Then - a?.Dispose() - End If - End Sub - - Private Sub M7(flag As Boolean) - Dim a As A = New A(7) - - Try - If flag Then - a.Dispose() - a = Nothing - End If - - Finally - a?.Dispose() - End Try - End Sub - - Private Sub M8(flag1 As Boolean, flag2 As Boolean) - Dim a As A = Nothing - - Try - If flag1 Then - a = New A(8) - End If - - If flag2 Then - a.Dispose() - a = Nothing - End If - - Finally - a?.Dispose() - End Try - End Sub - - Private Sub M9(flag As Boolean) - Dim a As A = New A(9) - - Try - If flag Then - a.Dispose() - a = Nothing - Return - End If - - a.Dispose() - Catch ex As Exception - a?.Dispose() - Finally - End Try - End Sub - - Private Sub M10(flag1 As Boolean, flag2 As Boolean) - Dim a As A = Nothing - - Try - If flag1 Then - a = New A(10) - End If - - If flag2 Then - a?.Dispose() - Return - End If - - If a IsNot Nothing Then - a.Dispose() - End If - - Catch ex As Exception - a?.Dispose() - Finally - End Try - End Sub - - Private A As IDisposable - - Private Sub M11(flag As Boolean) - Dim a As A = New A(9) - - Try - If flag Then - a.Dispose() - a = Nothing - Return - End If - - Me.A = a - a = Nothing - Finally - a?.Dispose() - End Try - End Sub - - Private Sub M12(flag1 As Boolean, flag2 As Boolean) - Dim a As A = Nothing - - Try - If flag1 Then - a = New A(10) - End If - - If flag2 Then - Me.A = a - a = Nothing - Return - End If - - If a IsNot Nothing Then - a.Dispose() - a = Nothing - End If - - Finally - a?.Dispose() - End Try - End Sub - |] -End Class") - End Function - - - Public Async Function DifferentDisposePatternsInFinally_Diagnostic() As Task - Await TestDiagnosticsAsync( -"Imports System - -Class A - Implements IDisposable - - Public Sub New(i As Integer) - End Sub - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub -End Class - -Class Test - [| - Private Sub M1(flag As Boolean) - Dim a As A = New A(1) - - Try - Finally - If flag Then - a?.Dispose() - End If - End Try - End Sub - - Private Sub M2(flag As Boolean) - Dim a As A = Nothing - - Try - a = New A(2) - Finally - If flag Then - a?.Dispose() - End If - End Try - End Sub - - Private Sub M3(flag As Boolean) - Dim a As A = Nothing - Dim b As A = Nothing - - Try - If flag Then - a = New A(3) - b = New A(31) - End If - Finally - If b IsNot Nothing Then - a.Dispose() - b.Dispose() - End If - End Try - End Sub - - Private Sub M4(flag As Boolean) - Dim a As A = Nothing - Dim b As A = Nothing - - Try - If flag Then - a = New A(4) - b = New A(41) - End If - Finally - If a IsNot Nothing AndAlso b IsNot Nothing Then - a.Dispose() - b.Dispose() - End If - End Try - End Sub - - Private Sub M5(flag As Boolean) - Dim a As A = New A(5) - - Try - Finally - DisposeHelper(a, flag) - End Try - End Sub - - Private Sub M6(flag As Boolean) - Dim a As A = Nothing - - Try - If flag Then - a = New A(6) - End If - Finally - DisposeHelper(a, flag) - End Try - End Sub - - Private Sub DisposeHelper(a As IDisposable, flag As Boolean) - If flag Then - a?.Dispose() - End If - End Sub - - Private Sub M7(flag As Boolean) - Dim a As A = New A(7) - - Try - If flag Then - a = Nothing - End If - Finally - a?.Dispose() - End Try - End Sub - - Private Sub M8(flag1 As Boolean, flag2 As Boolean) - Dim a As A = Nothing - - Try - If flag1 Then - a = New A(8) - End If - - If flag2 Then - a.Dispose() - a = Nothing - Else - a = Nothing - End If - Finally - a?.Dispose() - End Try - End Sub - - Private Sub M9(flag As Boolean) - Dim a As A = New A(9) - - Try - If flag Then - a = Nothing - Return - End If - - a.Dispose() - Catch ex As Exception - a?.Dispose() - Finally - End Try - End Sub - - Private Sub M10(flag1 As Boolean, flag2 As Boolean) - Dim a As A = Nothing - - Try - If flag1 Then - a = New A(10) - End If - - If flag2 Then - a?.Dispose() - Return - End If - - If a IsNot Nothing Then - a.Dispose() - End If - Catch ex As Exception - If flag1 Then - a?.Dispose() - End If - - Finally - End Try - End Sub - - Private A As IDisposable - - Private Sub M11(flag As Boolean) - Dim a As A = New A(11) - - Try - If flag Then - a.Dispose() - a = Nothing - Return - End If - - a = Nothing - Me.A = a - Finally - a?.Dispose() - End Try - End Sub - - Private Sub M12(flag1 As Boolean, flag2 As Boolean, flag3 As Boolean) - Dim a As A = Nothing - - Try - If flag1 Then - a = New A(12) - End If - - If flag2 Then - Me.A = a - a = Nothing - Return - ElseIf flag3 Then - a = New A(121) - End If - - Finally - a?.Dispose() - End Try - End Sub - |] -End Class", - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(1)").WithLocation(16, 22), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(2)").WithLocation(30, 17), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(3)").WithLocation(44, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(4)").WithLocation(61, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(41)").WithLocation(62, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(5)").WithLocation(73, 22), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(6)").WithLocation(86, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(8)").WithLocation(116, 21), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(9)").WithLocation(131, 22), - Diagnostic(IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, "New A(11)").WithLocation(174, 22)) - End Function - - - Public Async Function ReturnDisposableObjectWrappenInTask_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Threading.Tasks - -Class C - Implements IDisposable - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - Public Function M1_Task() As Task(Of C) - [|Return Task.FromResult(New C())|] - End Function -End Class") - End Function - - - Public Async Function AwaitedButNotDisposed_NoDiagnostic() As Task - ' We are conservative when disposable object gets wrapped in a task and consider it as escaped. - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Threading.Tasks - -Class C - Implements IDisposable - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - [| - Public Function M1_Task() As Task(Of C) - Return Task.FromResult(New C()) - End Function - - Public Async Function M2_Task() As Task - Dim c = Await M1_Task().ConfigureAwait(False) - End Function - |] -End Class") - End Function - - - Public Async Function AwaitedButNotDisposed_TaskWrappingField_NoDiagnostic() As Task - Await TestDiagnosticMissingAsync( -"Imports System -Imports System.Threading.Tasks - -Class C - Implements IDisposable - - Private _c As C - - Public Sub Dispose() Implements IDisposable.Dispose - End Sub - - [| - Public Function M1_Task() As Task(Of C) - Return Task.FromResult(_c) - End Function - - Public Async Function M2_Task() As Task - Dim c = Await M1_Task().ConfigureAwait(False) - End Function - |] -End Class") - End Function - End Class -End Namespace diff --git a/src/Features/Core/Portable/DisposeAnalysis/DisposableFieldsShouldBeDisposedDiagnosticAnalyzer.cs b/src/Features/Core/Portable/DisposeAnalysis/DisposableFieldsShouldBeDisposedDiagnosticAnalyzer.cs deleted file mode 100644 index d45652a312e30..0000000000000 --- a/src/Features/Core/Portable/DisposeAnalysis/DisposableFieldsShouldBeDisposedDiagnosticAnalyzer.cs +++ /dev/null @@ -1,333 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System.Collections.Concurrent; -using System.Collections.Immutable; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Threading; -using Microsoft.CodeAnalysis.CodeQuality; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.FlowAnalysis; -using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow; -using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.DisposeAnalysis; -using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.PointsToAnalysis; -using Microsoft.CodeAnalysis.Operations; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.DisposeAnalysis -{ - [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] - internal sealed class DisposableFieldsShouldBeDisposedDiagnosticAnalyzer - : AbstractCodeQualityDiagnosticAnalyzer - { - private readonly DiagnosticDescriptor _disposableFieldsShouldBeDisposedRule; - - public DisposableFieldsShouldBeDisposedDiagnosticAnalyzer() - : this(isEnabledByDefault: false) - { - } - - // internal for test purposes. - internal DisposableFieldsShouldBeDisposedDiagnosticAnalyzer(bool isEnabledByDefault) - : this(CreateDescriptor(isEnabledByDefault)) - { - } - - private DisposableFieldsShouldBeDisposedDiagnosticAnalyzer(DiagnosticDescriptor descriptor) - : base(ImmutableArray.Create(descriptor), GeneratedCodeAnalysisFlags.Analyze) - { - _disposableFieldsShouldBeDisposedRule = descriptor; - } - - private static DiagnosticDescriptor CreateDescriptor(bool isEnabledByDefault) - => CreateDescriptor( - IDEDiagnosticIds.DisposableFieldsShouldBeDisposedDiagnosticId, - EnforceOnBuildValues.DisposableFieldsShouldBeDisposed, - title: new LocalizableResourceString(nameof(FeaturesResources.Disposable_fields_should_be_disposed), FeaturesResources.ResourceManager, typeof(FeaturesResources)), - messageFormat: new LocalizableResourceString(nameof(FeaturesResources.Disposable_field_0_is_never_disposed), FeaturesResources.ResourceManager, typeof(FeaturesResources)), - description: new LocalizableResourceString(nameof(FeaturesResources.DisposableFieldsShouldBeDisposedDescription), FeaturesResources.ResourceManager, typeof(FeaturesResources)), - isUnnecessary: false, - isEnabledByDefault: isEnabledByDefault); - - public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticDocumentAnalysis; - - protected override void InitializeWorker(AnalysisContext context) - { - context.RegisterCompilationStartAction(compilationContext => - { - if (!DisposeAnalysisHelper.TryCreate(compilationContext.Compilation, out var disposeAnalysisHelper)) - { - return; - } - - // Register a symbol start action to analyze all named types. - compilationContext.RegisterSymbolStartAction( - symbolStartContext => SymbolAnalyzer.OnSymbolStart(symbolStartContext, _disposableFieldsShouldBeDisposedRule, disposeAnalysisHelper), - SymbolKind.NamedType); - }); - } - - private sealed class SymbolAnalyzer - { - private readonly DiagnosticDescriptor _disposableFieldsShouldBeDisposedRule; - private readonly ImmutableHashSet _disposableFields; - private readonly ConcurrentDictionary _fieldDisposeValueMap; - private readonly DisposeAnalysisHelper _disposeAnalysisHelper; - private bool _hasErrors; - private bool _hasDisposeMethod; - - public SymbolAnalyzer(DiagnosticDescriptor disposableFieldsShouldBeDisposedRule, ImmutableHashSet disposableFields, DisposeAnalysisHelper disposeAnalysisHelper) - { - Debug.Assert(!disposableFields.IsEmpty); - - _disposableFieldsShouldBeDisposedRule = disposableFieldsShouldBeDisposedRule; - _disposableFields = disposableFields; - _disposeAnalysisHelper = disposeAnalysisHelper; - _fieldDisposeValueMap = new ConcurrentDictionary(); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public static void OnSymbolStart(SymbolStartAnalysisContext symbolStartContext, DiagnosticDescriptor disposableFieldsShouldBeDisposedRule, DisposeAnalysisHelper disposeAnalysisHelper) - { - // We only want to analyze types which are disposable (implement System.IDisposable directly or indirectly) - // and have at least one disposable field. - var namedType = (INamedTypeSymbol)symbolStartContext.Symbol; - if (!namedType.IsDisposable(disposeAnalysisHelper.IDisposableType)) - { - return; - } - - var disposableFields = disposeAnalysisHelper.GetDisposableFields(namedType); - if (disposableFields.IsEmpty) - { - return; - } - - var analyzer = new SymbolAnalyzer(disposableFieldsShouldBeDisposedRule, disposableFields, disposeAnalysisHelper); - - // Register an operation block action to analyze disposable assignments and dispose invocations for fields. - symbolStartContext.RegisterOperationBlockStartAction(analyzer.OnOperationBlockStart); - - // Register symbol end action for containing type to report non-disposed fields. - // We report fields that have disposable type (implement System.IDisposable directly or indirectly) - // and were assigned a disposable object within this containing type, but were not disposed in - // containing type's Dispose method. - symbolStartContext.RegisterSymbolEndAction(analyzer.OnSymbolEnd); - } - - private void AddOrUpdateFieldDisposedValue(IFieldSymbol field, bool disposed) - { - Debug.Assert(_disposableFields.Contains(field)); - Debug.Assert(!field.IsStatic); - Debug.Assert(field.Type.IsDisposable(_disposeAnalysisHelper.IDisposableType)); - - // Update the dispose value for the field. - // Update value factory delegate ensures that fields for which we have - // already seen dispose invocations, i.e. currentValue = true, continue to be marked as disposed. - _fieldDisposeValueMap.AddOrUpdate(field, - addValue: disposed, - updateValueFactory: (f, currentValue) => currentValue || disposed); - } - - private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext) - { - if (_hasErrors || !_hasDisposeMethod) - { - return; - } - - foreach (var kvp in _fieldDisposeValueMap) - { - var field = kvp.Key; - var disposed = kvp.Value; - if (!disposed) - { - // Disposable field '{0}' is never disposed - var diagnostic = Diagnostic.Create(_disposableFieldsShouldBeDisposedRule, field.Locations[0], field.Name); - symbolEndContext.ReportDiagnostic(diagnostic); - } - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void OnOperationBlockStart(OperationBlockStartAnalysisContext operationBlockStartContext) - { - if (_hasErrors) - { - return; - } - - operationBlockStartContext.RegisterOperationAction(_ => _hasErrors = true, OperationKind.Invalid); - - switch (operationBlockStartContext.OwningSymbol) - { - case IFieldSymbol _: - // Field initializer. - if (operationBlockStartContext.OperationBlocks.Length == 1 && - operationBlockStartContext.OperationBlocks[0] is IFieldInitializerOperation fieldInitializer) - { - foreach (var field in fieldInitializer.InitializedFields) - { - if (!field.IsStatic && _disposableFields.Contains(field)) - { - // Instance field initialized with a disposable object is considered a candidate. - AddOrUpdateFieldDisposedValue(field, disposed: false); - } - } - } - - break; - - case IMethodSymbol containingMethod: - // Method body. - OnMethodOperationBlockStart(operationBlockStartContext, containingMethod); - break; - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void OnMethodOperationBlockStart(OperationBlockStartAnalysisContext operationBlockStartContext, IMethodSymbol containingMethod) - { - // Shared PointsTo dataflow analysis result for all the callbacks to AnalyzeFieldReference - // for this method's executable code. - PointsToAnalysisResult lazyPointsToAnalysisResult = null; - - // If we have any potential disposable object creation descendant within the operation blocks, - // register an operation action to analyze field references where field might be assigned a disposable object. - if (_disposeAnalysisHelper.HasAnyDisposableCreationDescendant(operationBlockStartContext.OperationBlocks, containingMethod)) - { - operationBlockStartContext.RegisterOperationAction(AnalyzeFieldReference, OperationKind.FieldReference); - } - - // If this is a Dispose method, then analyze dispose invocations for fields within this method. - if (_disposeAnalysisHelper.IsAnyDisposeMethod(containingMethod)) - { - AnalyzeDisposeMethod(); - } - - return; - - // Local function - void AnalyzeFieldReference(OperationAnalysisContext operationContext) - { - var fieldReference = (IFieldReferenceOperation)operationContext.Operation; - var field = fieldReference.Field; - - // Check if this is a Disposable field that is not currently being tracked. - if (_fieldDisposeValueMap.ContainsKey(field) || - !_disposableFields.Contains(field) || - _hasErrors) - { - return; - } - - // Only track instance fields on the current instance. - if (field.IsStatic || fieldReference.Instance?.Kind != OperationKind.InstanceReference) - { - return; - } - - // We have a field reference for a disposable field. - // Check if it is being assigned a locally created disposable object. - // PERF: Do not perform interprocedural analysis for this detection. - if (fieldReference.Parent is ISimpleAssignmentOperation simpleAssignmentOperation && - simpleAssignmentOperation.Target == fieldReference) - { - if (lazyPointsToAnalysisResult == null) - { - if (_disposeAnalysisHelper.TryGetOrComputeResult( - operationBlockStartContext, containingMethod, - _disposableFieldsShouldBeDisposedRule, - InterproceduralAnalysisKind.None, - trackInstanceFields: false, - out _, out var pointsToAnalysisResult) && - pointsToAnalysisResult != null) - { - Interlocked.CompareExchange(ref lazyPointsToAnalysisResult, pointsToAnalysisResult, null); - } - else - { - _hasErrors = true; - return; - } - } - - var assignedPointsToValue = lazyPointsToAnalysisResult[simpleAssignmentOperation.Value.Kind, simpleAssignmentOperation.Value.Syntax]; - foreach (var location in assignedPointsToValue.Locations) - { - if (_disposeAnalysisHelper.IsDisposableCreationOrDisposeOwnershipTransfer(location, containingMethod)) - { - AddOrUpdateFieldDisposedValue(field, disposed: false); - break; - } - } - } - } - - void AnalyzeDisposeMethod() - { - _hasDisposeMethod = true; - - if (_hasErrors) - { - return; - } - - // Perform dataflow analysis to compute dispose value of disposable fields at the end of dispose method. - if (_disposeAnalysisHelper.TryGetOrComputeResult(operationBlockStartContext, containingMethod, - _disposableFieldsShouldBeDisposedRule, - InterproceduralAnalysisKind.ContextSensitive, - trackInstanceFields: true, - disposeAnalysisResult: out var disposeAnalysisResult, - pointsToAnalysisResult: out var pointsToAnalysisResult)) - { - var exitBlock = disposeAnalysisResult.ControlFlowGraph.ExitBlock(); - foreach (var fieldWithPointsToValue in disposeAnalysisResult.TrackedInstanceFieldPointsToMap) - { - var field = fieldWithPointsToValue.Key; - var pointsToValue = fieldWithPointsToValue.Value; - - if (!_disposableFields.Contains(field)) - { - continue; - } - - var disposeDataAtExit = disposeAnalysisResult.ExitBlockOutput.Data; - var disposed = false; - foreach (var location in pointsToValue.Locations) - { - if (disposeDataAtExit.TryGetValue(location, out var disposeValue)) - { - switch (disposeValue.Kind) - { - // For MaybeDisposed, conservatively mark the field as disposed as we don't support path sensitive analysis. - case DisposeAbstractValueKind.MaybeDisposed: - case DisposeAbstractValueKind.Unknown: - case DisposeAbstractValueKind.Escaped: - case DisposeAbstractValueKind.Disposed: - disposed = true; - AddOrUpdateFieldDisposedValue(field, disposed); - break; - } - } - - if (disposed) - { - break; - } - } - } - } - else - { - _hasErrors = true; - } - } - } - } - } -} diff --git a/src/Features/Core/Portable/DisposeAnalysis/DisposeAnalysisHelper.cs b/src/Features/Core/Portable/DisposeAnalysis/DisposeAnalysisHelper.cs deleted file mode 100644 index 9ffcbb6748ac6..0000000000000 --- a/src/Features/Core/Portable/DisposeAnalysis/DisposeAnalysisHelper.cs +++ /dev/null @@ -1,331 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System; -using System.Collections.Concurrent; -using System.Collections.Immutable; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow; -using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.DisposeAnalysis; -using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.PointsToAnalysis; -using Microsoft.CodeAnalysis.Operations; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.DisposeAnalysis -{ - /// - /// Helper for DisposeAnalysis. - /// - internal sealed class DisposeAnalysisHelper - { - private static readonly string[] s_disposeOwnershipTransferLikelyTypes = new string[] - { - "System.IO.Stream", - "System.IO.TextReader", - "System.IO.TextWriter", - "System.Resources.IResourceReader", - }; - private static readonly ImmutableHashSet s_DisposableCreationKinds = ImmutableHashSet.Create( - OperationKind.ObjectCreation, - OperationKind.TypeParameterObjectCreation, - OperationKind.DynamicObjectCreation, - OperationKind.Invocation); - - private readonly ImmutableHashSet _disposeOwnershipTransferLikelyTypes; - private ConcurrentDictionary> _lazyDisposableFieldsMap; - public INamedTypeSymbol IDisposableType { get; } - public INamedTypeSymbol TaskType { get; } - - private DisposeAnalysisHelper(INamedTypeSymbol disposableType, INamedTypeSymbol taskType, ImmutableHashSet disposeOwnershipTransferLikelyTypes) - { - IDisposableType = disposableType; - TaskType = taskType; - _disposeOwnershipTransferLikelyTypes = disposeOwnershipTransferLikelyTypes; - } - - public static bool TryCreate(Compilation compilation, out DisposeAnalysisHelper disposeHelper) - { - var disposableType = compilation.SystemIDisposableType(); - if (disposableType == null) - { - disposeHelper = null; - return false; - } - - var taskType = compilation.TaskType(); - var disposeOwnershipTransferLikelyTypes = GetDisposeOwnershipTransferLikelyTypes(compilation); - disposeHelper = new DisposeAnalysisHelper(disposableType, taskType, disposeOwnershipTransferLikelyTypes); - return true; - } - - private static ImmutableHashSet GetDisposeOwnershipTransferLikelyTypes(Compilation compilation) - { - using var _ = PooledHashSet.GetInstance(out var builder); - foreach (var typeName in s_disposeOwnershipTransferLikelyTypes) - { - var typeSymbol = compilation.GetTypeByMetadataName(typeName); - if (typeSymbol != null) - { - builder.Add(typeSymbol); - } - } - - return builder.ToImmutableHashSet(); - } - - private void EnsureDisposableFieldsMap() - { - if (_lazyDisposableFieldsMap == null) - { - Interlocked.CompareExchange(ref _lazyDisposableFieldsMap, new ConcurrentDictionary>(), null); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public bool TryGetOrComputeResult( - OperationBlockAnalysisContext context, - IMethodSymbol containingMethod, - DiagnosticDescriptor rule, - InterproceduralAnalysisKind interproceduralAnalysisKind, - bool trackInstanceFields, - out DisposeAnalysisResult disposeAnalysisResult, - out PointsToAnalysisResult pointsToAnalysisResult, - InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt = null) - { - // Compute the dispose analysis result - skip Attribute blocks (OperationKind.None) - foreach (var operationBlock in context.OperationBlocks.Where(o => o.Kind != OperationKind.None)) - { - var cfg = context.GetControlFlowGraph(operationBlock); - if (cfg != null) - { - var wellKnownTypeProvider = Analyzer.Utilities.WellKnownTypeProvider.GetOrCreate(context.Compilation); - disposeAnalysisResult = FlowAnalysis.DataFlow.DisposeAnalysis.DisposeAnalysis.TryGetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, - context.Options, rule, _disposeOwnershipTransferLikelyTypes, trackInstanceFields, - exceptionPathsAnalysis: false, context.CancellationToken, out pointsToAnalysisResult, - interproceduralAnalysisKind, - interproceduralAnalysisPredicateOpt: interproceduralAnalysisPredicateOpt, - defaultDisposeOwnershipTransferAtConstructor: true, - defaultDisposeOwnershipTransferAtMethodCall: true); - if (disposeAnalysisResult != null) - { - return true; - } - } - } - - disposeAnalysisResult = null; - pointsToAnalysisResult = null; - return false; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public bool TryGetOrComputeResult( - OperationBlockStartAnalysisContext context, - IMethodSymbol containingMethod, - DiagnosticDescriptor rule, - InterproceduralAnalysisKind interproceduralAnalysisKind, - bool trackInstanceFields, - out DisposeAnalysisResult disposeAnalysisResult, - out PointsToAnalysisResult pointsToAnalysisResult, - InterproceduralAnalysisPredicate interproceduralAnalysisPredicateOpt = null) - { - // Compute the dispose analysis result - skip Attribute blocks (OperationKind.None) - foreach (var operationBlock in context.OperationBlocks.Where(o => o.Kind != OperationKind.None)) - { - var cfg = context.GetControlFlowGraph(operationBlock); - if (cfg != null) - { - var wellKnownTypeProvider = Analyzer.Utilities.WellKnownTypeProvider.GetOrCreate(context.Compilation); - disposeAnalysisResult = FlowAnalysis.DataFlow.DisposeAnalysis.DisposeAnalysis.TryGetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, - context.Options, rule, _disposeOwnershipTransferLikelyTypes, trackInstanceFields, - exceptionPathsAnalysis: false, context.CancellationToken, out pointsToAnalysisResult, - interproceduralAnalysisKind, - interproceduralAnalysisPredicateOpt: interproceduralAnalysisPredicateOpt, - defaultDisposeOwnershipTransferAtConstructor: true, - defaultDisposeOwnershipTransferAtMethodCall: true); - if (disposeAnalysisResult != null) - { - return true; - } - } - } - - disposeAnalysisResult = null; - pointsToAnalysisResult = null; - return false; - } - - private bool HasDisposableOwnershipTransferForConstructorParameter(IMethodSymbol containingMethod) => - containingMethod.MethodKind == MethodKind.Constructor && - containingMethod.Parameters.Any(p => _disposeOwnershipTransferLikelyTypes.Contains(p.Type)); - - private bool IsDisposableCreation(IOperation operation) - => (s_DisposableCreationKinds.Contains(operation.Kind) || - operation.Parent is IArgumentOperation argument && argument.Parameter.RefKind == RefKind.Out) && - operation.Type?.IsDisposable(IDisposableType) == true; - - public bool HasAnyDisposableCreationDescendant(ImmutableArray operationBlocks, IMethodSymbol containingMethod) - { - return operationBlocks.HasAnyOperationDescendant(IsDisposableCreation) || - HasDisposableOwnershipTransferForConstructorParameter(containingMethod); - } - - public ImmutableHashSet GetDisposableFields(INamedTypeSymbol namedType) - { - EnsureDisposableFieldsMap(); - if (_lazyDisposableFieldsMap.TryGetValue(namedType, out var disposableFields)) - { - return disposableFields; - } - - if (!namedType.IsDisposable(IDisposableType)) - { - disposableFields = ImmutableHashSet.Empty; - } - else - { - disposableFields = namedType.GetMembers() - .OfType() - .Where(f => f.Type.IsDisposable(IDisposableType) && !f.Type.InheritsFromOrEquals(TaskType)) - .ToImmutableHashSet(); - } - - return _lazyDisposableFieldsMap.GetOrAdd(namedType, disposableFields); - } - - /// - /// Returns true if the given was created for an allocation in the - /// or represents a location created for a constructor parameter whose type indicates dispose ownership transfer. - /// - [MethodImpl(MethodImplOptions.NoInlining)] - public bool IsDisposableCreationOrDisposeOwnershipTransfer(AbstractLocation location, IMethodSymbol containingMethod) - { - if (location.CreationOpt == null) - { - return location.SymbolOpt?.Kind == SymbolKind.Parameter && - HasDisposableOwnershipTransferForConstructorParameter(containingMethod); - } - - return IsDisposableCreation(location.CreationOpt); - } - - /// - /// Checks if the given method implements or overrides an implementation of . - /// - private bool IsDisposeImplementation(IMethodSymbol method) - { - if (method == null) - { - return false; - } - - if (method.IsOverride) - { - return IsDisposeImplementation(method.OverriddenMethod); - } - - // Identify the implementor of IDisposable.Dispose in the given method's containing type and check - // if it is the given method. - return method.ReturnsVoid && - method.Parameters.Length == 0 && - IsImplementationOfInterfaceMethod(method, typeArgument: null, IDisposableType, nameof(IDisposable.Dispose)); - } - - /// - /// Returns true if this method is any Dispose method responsible for disposing the disposable fields - /// of a disposable named type. For example, "void Dispose()", "void Dispose(bool)", "Task DisposeAsync()", etc. - /// - public bool IsAnyDisposeMethod(IMethodSymbol method) - { - if (!method.ContainingType.IsDisposable(IDisposableType)) - { - return false; - } - - return IsDisposeImplementation(method) || - (Equals(method.ContainingType, IDisposableType) && HasDisposeMethodSignature(method)) || - HasDisposeBoolMethodSignature(method) || - HasDisposeAsyncMethodSignature(method) || - HasOverriddenDisposeCoreAsyncMethodSignature(method) || - HasDisposeCloseMethodSignature(method); - } - - /// - /// Checks if the given method has the signature "void Dispose()". - /// - private static bool HasDisposeMethodSignature(IMethodSymbol method) - { - return method.Name == nameof(IDisposable.Dispose) && method.MethodKind == MethodKind.Ordinary && - method.ReturnsVoid && method.Parameters.IsEmpty; - } - - /// - /// Checks if the given method has the signature "void Dispose(bool)". - /// - public static bool HasDisposeBoolMethodSignature(IMethodSymbol method) - { - if (method.Name == nameof(IDisposable.Dispose) && method.MethodKind == MethodKind.Ordinary && - method.ReturnsVoid && method.Parameters.Length == 1) - { - var parameter = method.Parameters[0]; - return parameter.Type != null && - parameter.Type.SpecialType == SpecialType.System_Boolean && - parameter.RefKind == RefKind.None; - } - - return false; - } - - /// - /// Checks if the given method has the signature "void Close()". - /// - private static bool HasDisposeCloseMethodSignature(IMethodSymbol method) - { - return method.Name == "Close" && method.MethodKind == MethodKind.Ordinary && - method.ReturnsVoid && method.Parameters.IsEmpty; - } - - /// - /// Checks if the given method has the signature "Task DisposeAsync()". - /// - private bool HasDisposeAsyncMethodSignature(IMethodSymbol method) - { - return method.Name == "DisposeAsync" && - method.MethodKind == MethodKind.Ordinary && - method.ReturnType.Equals(TaskType) && - method.Parameters.IsEmpty; - } - - /// - /// Checks if the given method has the signature "override Task DisposeCoreAsync(bool)". - /// - private bool HasOverriddenDisposeCoreAsyncMethodSignature(IMethodSymbol method) - { - return method.Name == "DisposeCoreAsync" && - method.MethodKind == MethodKind.Ordinary && - method.IsOverride && - method.ReturnType.Equals(TaskType) && - method.Parameters.Length == 1 && - method.Parameters[0].Type.SpecialType == SpecialType.System_Boolean; - } - - /// - /// Checks if the given method is an implementation of the given interface method - /// Substituted with the given typeargument. - /// - private static bool IsImplementationOfInterfaceMethod(IMethodSymbol method, ITypeSymbol typeArgument, INamedTypeSymbol interfaceType, string interfaceMethodName) - { - var constructedInterface = typeArgument != null ? interfaceType?.Construct(typeArgument) : interfaceType; - - return constructedInterface?.GetMembers(interfaceMethodName).Single() is IMethodSymbol interfaceMethod && method.Equals(method.ContainingType.FindImplementationForInterfaceMember(interfaceMethod)); - } - } -} diff --git a/src/Features/Core/Portable/DisposeAnalysis/DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer.cs b/src/Features/Core/Portable/DisposeAnalysis/DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer.cs deleted file mode 100644 index a2e28bbc1c4a1..0000000000000 --- a/src/Features/Core/Portable/DisposeAnalysis/DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer.cs +++ /dev/null @@ -1,247 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System; -using System.Collections.Concurrent; -using System.Collections.Immutable; -using System.Linq; -using System.Runtime.CompilerServices; -using Microsoft.CodeAnalysis.CodeQuality; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.FlowAnalysis; -using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow; -using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.DisposeAnalysis; -using Microsoft.CodeAnalysis.FlowAnalysis.DataFlow.PointsToAnalysis; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.DisposeAnalysis -{ - [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] - internal sealed class DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer - : AbstractCodeQualityDiagnosticAnalyzer - { - private readonly DiagnosticDescriptor _disposeObjectsBeforeLosingScopeRule; - private readonly DiagnosticDescriptor _useRecommendedDisposePatternRule; - - public DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer() - : this(isEnabledByDefault: false) - { - } - - // internal for test purposes. - internal DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer(bool isEnabledByDefault) - : this(CreateDisposeObjectsBeforeLosingScopeRule(isEnabledByDefault), CreateUseRecommendedDisposePatternRule(isEnabledByDefault)) - { - } - - public DisposeObjectsBeforeLosingScopeDiagnosticAnalyzer(DiagnosticDescriptor disposeObjectsBeforeLosingScopeRule, DiagnosticDescriptor useRecommendedDisposePatternRule) - : base(ImmutableArray.Create(disposeObjectsBeforeLosingScopeRule, useRecommendedDisposePatternRule), GeneratedCodeAnalysisFlags.None) - { - _disposeObjectsBeforeLosingScopeRule = disposeObjectsBeforeLosingScopeRule; - _useRecommendedDisposePatternRule = useRecommendedDisposePatternRule; - } - - private static DiagnosticDescriptor CreateDisposeObjectsBeforeLosingScopeRule(bool isEnabledByDefault) - => CreateDescriptor( - IDEDiagnosticIds.DisposeObjectsBeforeLosingScopeDiagnosticId, - EnforceOnBuildValues.DisposeObjectsBeforeLosingScope, - title: new LocalizableResourceString(nameof(FeaturesResources.Dispose_objects_before_losing_scope), FeaturesResources.ResourceManager, typeof(FeaturesResources)), - messageFormat: new LocalizableResourceString(nameof(FeaturesResources.Disposable_object_created_by_0_is_never_disposed), FeaturesResources.ResourceManager, typeof(FeaturesResources)), - description: new LocalizableResourceString(nameof(FeaturesResources.UseRecommendedDisposePatternDescription), FeaturesResources.ResourceManager, typeof(FeaturesResources)), - isUnnecessary: false, - isEnabledByDefault: isEnabledByDefault); - - private static DiagnosticDescriptor CreateUseRecommendedDisposePatternRule(bool isEnabledByDefault) - => CreateDescriptor( - IDEDiagnosticIds.UseRecommendedDisposePatternDiagnosticId, - EnforceOnBuildValues.UseRecommendedDisposePattern, - title: new LocalizableResourceString(nameof(FeaturesResources.Use_recommended_dispose_pattern), FeaturesResources.ResourceManager, typeof(FeaturesResources)), - messageFormat: new LocalizableResourceString(nameof(FeaturesResources.Use_recommended_dispose_pattern_to_ensure_that_object_created_by_0_is_disposed_on_all_paths_using_statement_declaration_or_try_finally), FeaturesResources.ResourceManager, typeof(FeaturesResources)), - description: new LocalizableResourceString(nameof(FeaturesResources.UseRecommendedDisposePatternDescription), FeaturesResources.ResourceManager, typeof(FeaturesResources)), - isUnnecessary: false, - isEnabledByDefault: isEnabledByDefault); - - public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticDocumentAnalysis; - - protected override void InitializeWorker(AnalysisContext context) - { - context.RegisterCompilationStartAction(compilationContext => - { - if (!DisposeAnalysisHelper.TryCreate(compilationContext.Compilation, out var disposeAnalysisHelper)) - { - return; - } - - // Avoid reporting duplicate diagnostics from interprocedural analysis. - var reportedLocations = new ConcurrentDictionary(); - - compilationContext.RegisterOperationBlockAction( - operationBlockContext => AnalyzeOperationBlock(operationBlockContext, disposeAnalysisHelper, reportedLocations)); - }); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void AnalyzeOperationBlock( - OperationBlockAnalysisContext operationBlockContext, - DisposeAnalysisHelper disposeAnalysisHelper, - ConcurrentDictionary reportedLocations) - { - // We are only intersted in analyzing method bodies that have at least one disposable object creation. - if (!(operationBlockContext.OwningSymbol is IMethodSymbol containingMethod) || - !disposeAnalysisHelper.HasAnyDisposableCreationDescendant(operationBlockContext.OperationBlocks, containingMethod)) - { - return; - } - - PerformFlowAnalysisOnOperationBlock(operationBlockContext, disposeAnalysisHelper, reportedLocations, containingMethod); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void PerformFlowAnalysisOnOperationBlock( - OperationBlockAnalysisContext operationBlockContext, - DisposeAnalysisHelper disposeAnalysisHelper, - ConcurrentDictionary reportedLocations, - IMethodSymbol containingMethod) - { - // We can skip interprocedural analysis for certain invocations. - var interproceduralAnalysisPredicateOpt = new InterproceduralAnalysisPredicate( - skipAnalysisForInvokedMethodPredicateOpt: SkipInterproceduralAnalysis, - skipAnalysisForInvokedLambdaOrLocalFunctionPredicateOpt: null, - skipAnalysisForInvokedContextPredicateOpt: null); - - // Compute dispose dataflow analysis result for the operation block. - if (disposeAnalysisHelper.TryGetOrComputeResult(operationBlockContext, containingMethod, - _disposeObjectsBeforeLosingScopeRule, - InterproceduralAnalysisKind.ContextSensitive, - trackInstanceFields: false, - out var disposeAnalysisResult, out var pointsToAnalysisResult, - interproceduralAnalysisPredicateOpt)) - { - using var _1 = ArrayBuilder.GetInstance(out var notDisposedDiagnostics); - using var _2 = ArrayBuilder.GetInstance(out var mayBeNotDisposedDiagnostics); - - // Compute diagnostics for undisposed objects at exit block. - var exitBlock = disposeAnalysisResult.ControlFlowGraph.ExitBlock(); - var disposeDataAtExit = disposeAnalysisResult.ExitBlockOutput.Data; - ComputeDiagnostics(disposeDataAtExit, notDisposedDiagnostics, mayBeNotDisposedDiagnostics, - disposeAnalysisResult, pointsToAnalysisResult); - - if (disposeAnalysisResult.ControlFlowGraph.OriginalOperation.HasAnyOperationDescendant(o => o.Kind == OperationKind.None)) - { - // Workaround for https://github.com/dotnet/roslyn/issues/32100 - // Bail out in presence of OperationKind.None - not implemented IOperation. - return; - } - - // Report diagnostics preferring *not* disposed diagnostics over may be not disposed diagnostics - // and avoiding duplicates. - foreach (var diagnostic in notDisposedDiagnostics.Concat(mayBeNotDisposedDiagnostics)) - { - if (reportedLocations.TryAdd(diagnostic.Location, true)) - { - operationBlockContext.ReportDiagnostic(diagnostic); - } - } - } - - return; - - // Local functions. - bool SkipInterproceduralAnalysis(IMethodSymbol invokedMethod) - { - // Skip interprocedural analysis if we are invoking a method and not passing any disposable object as an argument - // and not receiving a disposable object as a return value. - // We also check that we are not passing any object type argument which might hold disposable object - // and also check that we are not passing delegate type argument which can - // be a lambda or local function that has access to disposable object in current method's scope. - - if (CanBeDisposable(invokedMethod.ReturnType)) - { - return false; - } - - foreach (var p in invokedMethod.Parameters) - { - if (CanBeDisposable(p.Type)) - { - return false; - } - } - - return true; - - bool CanBeDisposable(ITypeSymbol type) - => type.SpecialType == SpecialType.System_Object || - type.IsDisposable(disposeAnalysisHelper.IDisposableType) || - type.TypeKind == TypeKind.Delegate; - } - - void ComputeDiagnostics( - ImmutableDictionary disposeData, - ArrayBuilder notDisposedDiagnostics, - ArrayBuilder mayBeNotDisposedDiagnostics, - DisposeAnalysisResult disposeAnalysisResult, - PointsToAnalysisResult pointsToAnalysisResult) - { - foreach (var kvp in disposeData) - { - var location = kvp.Key; - var disposeValue = kvp.Value; - - // Ignore non-disposable locations and locations without a Creation operation. - if (disposeValue.Kind == DisposeAbstractValueKind.NotDisposable || - location.CreationOpt == null) - { - continue; - } - - // Check if the disposable creation is definitely not disposed or may be not disposed. - var isNotDisposed = disposeValue.Kind == DisposeAbstractValueKind.NotDisposed || - (disposeValue.DisposingOrEscapingOperations.Count > 0 && - disposeValue.DisposingOrEscapingOperations.All(d => d.IsInsideCatchRegion(disposeAnalysisResult.ControlFlowGraph) && !location.CreationOpt.IsInsideCatchRegion(disposeAnalysisResult.ControlFlowGraph))); - var isMayBeNotDisposed = !isNotDisposed && - (disposeValue.Kind == DisposeAbstractValueKind.MaybeDisposed || disposeValue.Kind == DisposeAbstractValueKind.NotDisposedOrEscaped); - - if (isNotDisposed || isMayBeNotDisposed) - { - var syntax = location.TryGetNodeToReportDiagnostic(pointsToAnalysisResult); - if (syntax == null) - { - continue; - } - - var rule = isNotDisposed ? _disposeObjectsBeforeLosingScopeRule : _useRecommendedDisposePatternRule; - - // Ensure that we do not include multiple lines for the object creation expression in the diagnostic message. - var objectCreationText = syntax.ToString(); - var indexOfNewLine = objectCreationText.IndexOf(Environment.NewLine); - if (indexOfNewLine > 0) - { - objectCreationText = objectCreationText.Substring(0, indexOfNewLine); - } - - var diagnostic = Diagnostic.Create( - rule, - syntax.GetLocation(), - additionalLocations: null, - properties: null, - objectCreationText); - - if (isNotDisposed) - { - notDisposedDiagnostics.Add(diagnostic); - } - else - { - mayBeNotDisposedDiagnostics.Add(diagnostic); - } - } - } - } - } - } -} diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index cb062f5856331..0608913262926 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -1405,31 +1405,6 @@ This version used in: {2} Changes are not allowed while stopped at exception - - Dispose objects before losing scope - - - Disposable object created by '{0}' is never disposed - - - Use recommended dispose pattern - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - - - Disposable fields should be disposed - - - Disposable field '{0}' is never disposed - - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - Wrap and align call chain diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index 1189f83adcc43..5e6f3864dfe59 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -275,31 +275,6 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Vytvořit a přiřadit zbývající položky jako vlastnosti - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - Typ, který implementuje System.IDisposable, deklaruje pole, která mají typ, který IDisposable implementuje taky. Metoda Dispose deklarujícího typu nevolá metodu Dispose daného pole. Pokud chcete porušení tohoto pravidla opravit a je vaší odpovědností přidělovat a uvolňovat nespravované prostředky, které pole uchovává, zavolejte Dispose pro pole s typy, které implementují IDisposable. - - - - Disposable field '{0}' is never disposed - Uvolnitelné pole {0} se nikdy nevyřadí. - - - - Disposable fields should be disposed - Pole, která se dají uvolnit, by se měla uvolňovat - - - - Disposable object created by '{0}' is never disposed - Uvolnitelný objekt vytvořený pomocí {0} se nikdy nevyřadí. - - - - Dispose objects before losing scope - Uvolňujte objekty před ztrátou oboru - - Do not change this code. Put cleanup code in '{0}' method Neměňte tento kód. Kód pro vyčištění vložte do metody {0}. @@ -2005,11 +1980,6 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Pokud se aktualizuje {0} v okolí aktivního příkazu, relace ladění nebude moct pokračovat. - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - Použijte doporučený vzor Dispose, abyste měli jistotu, že objekty, které lze vyřadit v místním oboru, se vyřadí na všech cestách. Pokud je to možné, zabalte vytváření do příkazu nebo deklarace using. Jinak použijte vzor try-finally s vyhrazenou místní proměnnou deklarovanou před oblastí try a nepodmíněným voláním Dispose pro hodnotu, která není null, v oblasti finally, třeba x?.Dispose(). Pokud se objekt explicitně vyřadí v oblasti try nebo se vlastnictví Dispose převede na jiný objekt nebo metodu, přiřaďte ihned po takové operaci místní proměnné hodnotu null, aby ve finally nedošlo k dvojímu Dispose. - - Use block body for lambda expressions Pro lambda výrazy používat text bloku @@ -2025,16 +1995,6 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Použít interpolovaný doslovný řetězec - - Use recommended dispose pattern - Použít doporučený vzor Dispose - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - Použijte doporučený vzor Dispose, abyste měli jistotu, že objekt vytvořený pomocí {0} se vyřadí na všech cestách: příkaz/deklarace using nebo výraz try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: Hodnota: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index 2d80f0fce09d2..47f739e88bd46 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -275,31 +275,6 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Verbleibende Elemente als Eigenschaften erstellen und zuweisen - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - Ein Typ, der System.IDisposable implementiert, deklariert Felder, die Typen aufweisen, die ebenfalls IDisposable implementieren. Die Dispose-Methode des Felds wird nicht von der Dispose-Methode des deklarierenden Typs aufgerufen. Wenn Sie für das Zuordnen und Freigeben nicht verwalteter Ressourcen zuständig sind, die von diesem Feld belegt werden, rufen Sie zum Beheben eines Verstoßes gegen diese Regel Dispose für Felder auf, die Typen aufweisen, welche IDisposable implementieren. - - - - Disposable field '{0}' is never disposed - Das löschbare Feld "{0}" wird niemals gelöscht. - - - - Disposable fields should be disposed - Verwerfbare Felder verwerfen - - - - Disposable object created by '{0}' is never disposed - Das von "{0}" erstellte löschbare Objekt wird niemals gelöscht. - - - - Dispose objects before losing scope - Objekte verwerfen, bevor Bereich verloren geht - - Do not change this code. Put cleanup code in '{0}' method Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "{0}" ein. @@ -2005,11 +1980,6 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Durch Aktualisieren von "{0}" im Kontext einer aktiven Anweisung wird verhindert, dass die Debugsitzung fortgesetzt wird. - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - Verwenden Sie das empfohlene Dispose-Muster, um sicherzustellen, dass löschbare Objekte für den lokalen Bereich in allen Pfaden gelöscht werden. Schließen Sie die Erstellung nach Möglichkeit in einer using-Anweisung oder einer using-Deklaration ein. Verwenden Sie andernfalls ein try-finally-Muster mit einer vor dem try-Bereich deklarierten dedizierten lokalen Variablen und einem Dispose-Aufruf ohne Bedingung für den Nicht-NULL-Wert im finally-Bereich, beispielsweise "x?.Dispose()". Wenn das Objekt explizit innerhalb des try-Bereichs gelöscht oder der Dispose-Besitz auf ein anderes Objekt oder eine andere Methode übertragen wird, weisen Sie der lokalen Variablen gleich nach einem solchen Vorgang NULL zu, um einen doppelten Löschvorgang in "finally" zu vermeiden. - - Use block body for lambda expressions Blocktextkörper für Lambdaausdrücke verwenden @@ -2025,16 +1995,6 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Interpolierte ausführliche Zeichenfolge verwenden - - Use recommended dispose pattern - Empfohlenes Dispose-Muster verwenden - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - Verwenden Sie das empfohlene Dispose-Muster, um sicherzustellen, dass das von "{0}" erstellte Objekt in allen Pfaden gelöscht wird: using-Anweisung/-Deklaration oder try/finally. - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: Wert: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index 6c3a69fc9d979..e8af23447ea31 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -275,31 +275,6 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Crear y asignar el resto como propiedades - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - Un tipo que implementa System.IDisposable declara campos de tipos que también implementan IDisposable. El método Dispose del tipo declarativo no llama al método Dispose del campo. Para corregir una infracción de esta regla, llame a Dispose en campos que sean de tipos que implementan IDisposable si usted es el responsable de asignar y liberar los recursos no administrados que contiene el campo. - - - - Disposable field '{0}' is never disposed - El campo "{0}" descartable nunca se desecha. - - - - Disposable fields should be disposed - Aplique Dispose a los campos a los que se pueda - - - - Disposable object created by '{0}' is never disposed - El objeto descartable creado por "{0}" nunca se desecha. - - - - Dispose objects before losing scope - Desechar (Dispose) objetos antes de perder el ámbito - - Do not change this code. Put cleanup code in '{0}' method No cambie este código. Coloque el código de limpieza en el método "{0}". @@ -2005,11 +1980,6 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Si se actualiza un "{0}" en torno a una instrucción activa, la sesión de depuración no podrá continuar. - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - Use el patrón de Dispose recomendado para asegurarse de que los objetos descartables de ámbito local se desechan en todas las rutas de acceso. Si es posible, incluya la creación en una instrucción "using" o una declaración "using". En caso contrario, use un patrón try-finally, con la declaración de una variable local dedicada antes de la región "try" y una invocación de Dispose incondicional en un valor no nulo en la región "finally", por ejemplo, "x?.Dispose()". Si el objeto se desecha de forma explícita en la región "try" o la pertenencia de Dispose se transfiere a otro objeto o método, asigne "null" a la variable local justo después de tal operación para evitar un doble Dispose en "finally". - - Use block body for lambda expressions Usar cuerpo del bloque para las expresiones lambda @@ -2025,16 +1995,6 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Utilizar cadenas verbatim interpoladas - - Use recommended dispose pattern - Usar el patrón de Dispose recomendado - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - Use el patrón de Dispose recomendado para asegurarse de que el objeto creado por "{0}" se desecha en todas las rutas de acceso: instrucción o declaración using o try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: Valor: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index 9825bfd613695..e2d962657e6df 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -275,31 +275,6 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Créer et affecter ce qui reste en tant que propriétés - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - Un type qui implémente System.IDisposable déclare des champs dont les types implémentent également IDisposable. La méthode Dispose du champ n'est pas appelée par la méthode Dispose du type déclarant. Pour corriger toute violation de cette règle, appelez Dispose sur les champs dont les types implémentent IDisposable si vous êtes responsable de l'allocation et de la libération des ressources non managées détenues par le champ. - - - - Disposable field '{0}' is never disposed - Le champ supprimable '{0}' n'est jamais supprimé - - - - Disposable fields should be disposed - Les champs supprimables doivent l'être - - - - Disposable object created by '{0}' is never disposed - L'objet supprimable créé par '{0}' n'est jamais supprimé - - - - Dispose objects before losing scope - Supprimer les objets avant la mise hors de portée - - Do not change this code. Put cleanup code in '{0}' method Ne changez pas ce code. Placez le code de nettoyage dans la méthode '{0}' @@ -2005,11 +1980,6 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée La mise à jour de '{0}' autour d'une instruction active va empêcher la session de débogage de se poursuivre. - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - Utilisez le modèle Dispose recommandé pour vérifier que les objets supprimables de l'étendue locale sont bien supprimés sur tous les chemins. Si possible, enveloppez la création dans une instruction 'using' ou une déclaration 'using'. Sinon, utilisez un modèle try-finally avec une variable locale dédiée déclarée avant la région try et un appel inconditionnel de Dispose sur une valeur non null dans la région 'finally', par exemple 'x?.Dispose()'. Si l'objet est explicitement supprimé dans la région try ou si la propriété de suppression est transférée vers un autre objet ou une autre méthode, affectez la valeur 'null' à la variable locale juste après cette opération pour éviter une double suppression dans 'finally' - - Use block body for lambda expressions Utiliser le corps de bloc pour les expressions lambda @@ -2025,16 +1995,6 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Utiliser une chaîne verbatim interpolée - - Use recommended dispose pattern - Utilisez le modèle Dispose recommandé - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - Utilisez le modèle Dispose recommandé pour vérifier que l'objet créé par '{0}' est supprimé sur tous les chemins : instruction/déclaration using ou try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: Valeur : diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index 0d28bcd8c0d4d..c9d859fbf8643 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -275,31 +275,6 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Crea e assegna rimanenti come proprietà - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - Un tipo che implementa System.IDisposable dichiara i campi di tipi che implementano anch'essi IDisposable. Il metodo Dispose del campo non viene chiamato dal metodo Dispose del tipo dichiarante. Per correggere una violazione di questa regola, chiamare Dispose su campi di tipi che implementano IDisposable se si è responsabile dell'allocazione e del rilascio delle risorse non gestite utilizzate dal campo. - - - - Disposable field '{0}' is never disposed - Il campo eliminabile '{0}' non viene mai eliminato - - - - Disposable fields should be disposed - I campi eliminabili devono essere eliminati - - - - Disposable object created by '{0}' is never disposed - L'oggetto eliminabile creato da '{0}' non viene mai eliminato - - - - Dispose objects before losing scope - Elimina gli oggetti prima che siano esterni all'ambito - - Do not change this code. Put cleanup code in '{0}' method Non modificare questo codice. Inserire il codice di pulizia nel metodo '{0}' @@ -2005,11 +1980,6 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Se si aggiorna '{0}' in prossimità di un'istruzione attiva, la sessione di debug non potrà continuare. - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - Usare il criterio dispose consigliato per garantire che gli oggetti eliminabili con ambito locale vengano eliminati in tutti i percorsi. Se possibile, eseguire il wrapping della creazione in un'istruzione 'using' o una dichiarazione 'using'. In caso contrario, usare un criterio try-finally, con una variabile locale dedicata dichiarata prima dell'area try e una chiamata Dispose non condizionale al valore non Null nell'area 'finally', ad esempio 'x?.Dispose()'. Se l'oggetto viene eliminato in modo esplicito nell'area try oppure la proprietà di dispose viene trasferita a un altro oggetto o metodo, assegnare 'null' alla variabile locale subito dopo una tale operazione per evitare di raddoppiare dispose in 'finally' - - Use block body for lambda expressions Usa il corpo del blocco per le espressioni lambda @@ -2025,16 +1995,6 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Usa stringa verbatim interpolata - - Use recommended dispose pattern - Usare il criterio dispose consigliato - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - Usare il criterio dispose consigliato per garantire che l'oggetto creato da '{0}' venga eliminato in tutti i percorsi, ovvero istruzione/dichiarazione using o try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: Valore: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index 4e9c3c9e86837..bafb1b4cc0d16 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -275,31 +275,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 残りをプロパティとして作成して割り当てる - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - System.IDisposable を実装する型は、IDisposable も実装する型のフィールドを宣言します。フィールドの Dispose メソッドは、宣言する型の Dispose メソッドによって呼び出されません。フィールドが保持する管理されていないリソースの割り当てと解放を自分が担当している場合、このルールの違反を修正するには、IDisposable を実装する型のフィールドに Dispose を呼び出します。 - - - - Disposable field '{0}' is never disposed - 破棄可能なフィールド '{0}' が破棄されることはありません - - - - Disposable fields should be disposed - 破棄可能なフィールドは破棄しなければなりません - - - - Disposable object created by '{0}' is never disposed - '{0}' が作成した破棄可能なオブジェクトが破棄されることはありません - - - - Dispose objects before losing scope - スコープを失う前にオブジェクトを破棄 - - Do not change this code. Put cleanup code in '{0}' method このコードを変更しないでください。クリーンアップ コードを '{0}' メソッドに記述します @@ -2005,11 +1980,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of アクティブ ステートメントの前後の '{0}' を更新すると、デバッグ セッションは続行されません。 - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - 推奨される破棄パターンを使用して、ローカル スコープの破棄可能なオブジェクトがすべてのパスで破棄されるようにします。可能なら、'using' ステートメントまたは 'using' 宣言内で作成を折り返します。または、try-finally パターンを、try 領域の前で宣言された専用のローカル変数と、'finally' 領域の非 null 値での条件なしの Dispose の呼び出し (例: 'x?.Dispose()') とともに使用します。オブジェクトが try 領域内で明示的に破棄されるか、dispose の所有権が他のオブジェクトまたはメソッドに移される場合、その操作のすぐ後で 'null' をローカル変数に割り当てて、'finally' 内での dispose の重複を回避します - - Use block body for lambda expressions ラムダ式にブロック本体を使用する @@ -2025,16 +1995,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 挿入された逐語的文字列を使用します - - Use recommended dispose pattern - 推奨される破棄パターンを使用する - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - 推奨された破棄パターンを使用して、'{0}' が作成したオブジェクトがすべてのパスで破棄されるようにします: using ステートメント/宣言または try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: 値: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 1414655596e50..04cac0027f5ab 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -275,31 +275,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 나머지를 만들고 속성으로 할당합니다. - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - System.IDisposable을 구현하는 형식은 IDisposable도 구현하는 형식의 필드를 선언합니다. 필드의 Dispose 메서드는 선언 형식의 Dispose 메서드에 의해 호출되지 않습니다. 이 규칙 위반 문제를 해결하려면 필드에 포함되는 비관리형 리소스를 할당 및 해제해야 하는 경우 IDisposable을 구현하는 형식의 필드에서 Dispose를 호출합니다. - - - - Disposable field '{0}' is never disposed - 삭제 가능한 필드 '{0}'이(가) 삭제되지 않습니다. - - - - Disposable fields should be disposed - 삭제 가능한 필드는 삭제해야 합니다. - - - - Disposable object created by '{0}' is never disposed - '{0}'에 의해 만들어진 삭제 가능한 개체가 삭제되지 않습니다. - - - - Dispose objects before losing scope - 범위를 벗어나기 전에 개체를 삭제하십시오. - - Do not change this code. Put cleanup code in '{0}' method 이 코드를 변경하지 마세요. '{0}' 메서드에 정리 코드를 입력합니다. @@ -2005,11 +1980,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 활성 문 주위에서 '{0}'을(를) 업데이트하면 디버그 세션을 계속할 수 없습니다. - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - 권장 dispose 패턴을 사용하여 로컬로 범위가 지정된 삭제 가능한 개체가 모든 경로에서 삭제되도록 합니다. 가능한 경우 'using' 문이나 'using' 선언 내에서 생성을 래핑합니다. 그러지 않으면 try 영역 앞에 선언된 전용 지역 변수 및 'finally' 영역에 있는 null이 아닌 값의 비조건부 Dispose 호출('x?.Dispose()')과 함께 try-finally 패턴을 사용하세요. 개체가 try 영역 내에서 명시적으로 삭제되거나 삭제 소유권이 다른 개체나 메서드로 이전되면 해당 작업 바로 뒤의 지역 변수에 'null'을 할당하여 'finally'에서 이중 삭제를 방지하세요. - - Use block body for lambda expressions 람다 식에 블록 본문 사용 @@ -2025,16 +1995,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 보간된 축자 문자열 사용 - - Use recommended dispose pattern - 권장 dispose 패턴 사용 - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - 권장 dispose 패턴을 사용하여, '{0}'에 의해 만들어진 개체가 모든 경로(using 문/선언 또는 try/finally)에서 삭제되도록 합니다. - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: 값: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index 956ec333601a4..5a25b49f4354f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -275,31 +275,6 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Utwórz i przypisz pozostałe jako właściwości - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - Typ zawierający implementację interfejsu System.IDisposable deklaruje pola, których typy także zawierają implementację interfejsu IDisposable. Metoda Dispose pola nie jest wywoływana przez metodę Dispose typu deklarującego. Aby naprawić naruszenie tej reguły, wywołaj metodę Dispose dla pól, których typy zawierają implementację interfejsu IDisposable, jeśli odpowiadasz za przydzielanie i zwalnianie niezarządzanych zasobów wstrzymywanych przez pole. - - - - Disposable field '{0}' is never disposed - Pole możliwe do likwidacji „{0}” nie jest nigdy likwidowane - - - - Disposable fields should be disposed - Pola możliwe do likwidacji powinny zostać zlikwidowane - - - - Disposable object created by '{0}' is never disposed - Obiekt możliwy do likwidacji utworzony przez element „{0}” nie jest nigdy likwidowany - - - - Dispose objects before losing scope - Likwiduj obiekty przed utratą zakresu - - Do not change this code. Put cleanup code in '{0}' method Nie zmieniaj tego kodu. Umieść kod czyszczący w metodzie „{0}”. @@ -2005,11 +1980,6 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Aktualizacja elementu „{0}” w pobliżu aktywnej instrukcji uniemożliwi kontynuowanie sesji debugowania. - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - Użyj zalecanego wzorca likwidacji, aby upewnić się, że obiekty możliwe do likwidacji w lokalnym zakresie są likwidowane we wszystkich ścieżkach. Jeśli to możliwe, opakuj tworzenie w instrukcji „using” lub deklaracji „using”. W przeciwnym razie użyj wzorca try-finally z dedykowaną zmienną lokalną zadeklarowaną przed regionem try i bezwarunkowym wywołaniem metody Dispose dla wartości innej niż null w regionie „finally”, na przykład „x?.Dispose()”. Jeśli obiekt jest jawnie likwidowany w regionie try lub własność dispose jest przenoszona do innego obiektu lub metody, przypisz wartość „null” do zmiennej lokalnej zaraz po takiej operacji, aby zapobiec podwójnemu wywołaniu dispose w regionie „finally” - - Use block body for lambda expressions Użyj treści bloku dla wyrażeń lambda @@ -2025,16 +1995,6 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Użyj interpolowanego ciągu dosłownego wyrażenia - - Use recommended dispose pattern - Użyj zalecanego wzorca likwidacji - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - Użyj zalecanego wzorca likwidacji, aby upewnić się, że obiekt utworzony przez element „{0}” jest likwidowany we wszystkich ścieżkach: instrukcja/deklaracja using lub try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: Wartość: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index 95ecae0ef0452..8938963591a98 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -275,31 +275,6 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Criar e atribuir os restantes como propriedades - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - Um tipo que implementa System.IDisposable declara campos dos tipos que também implementam IDisposable. O método Dispose do campo não é chamado pelo método Dispose do tipo declarativo. Se você for responsável por alocar e liberar os recursos não gerenciados mantidos pelo campo, chame Dispose nos campos de tipos que implementam IDisposable para corrigir uma violação dessa regra. - - - - Disposable field '{0}' is never disposed - O campo descartável '{0}' nunca é descartado - - - - Disposable fields should be disposed - Campos descartáveis devem ser descartados - - - - Disposable object created by '{0}' is never disposed - O objeto descartável criado por '{0}' nunca é descartado - - - - Dispose objects before losing scope - Descartar objetos antes de perder o escopo - - Do not change this code. Put cleanup code in '{0}' method Não altere este código. Coloque o código de limpeza no método '{0}' @@ -2005,11 +1980,6 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Atualizar um '{0}' ao redor de uma instrução ativa impedirá a continuação da sessão de depuração. - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - Use o padrão de descarte recomendado para garantir que os objetos descartáveis no escopo local sejam descartados em todos os caminhos. Se possível, encapsule a criação em uma instrução 'using' ou em uma declaração 'using'. Caso contrário, use um padrão try-finally, com uma variável local dedicada declarada antes da região try e uma invocação de Dispose incondicional em um valor que não seja nulo na região 'finally', como 'x?.Dispose()'. Se o objeto for descartado explicitamente dentro da região try ou se a propriedade de descarte for transferida para outro objeto ou método, atribua 'null' à variável local logo após essa operação para evitar um descarte duplo em 'finally' - - Use block body for lambda expressions Usar o corpo do bloco para expressões lambda @@ -2025,16 +1995,6 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Usar cadeia de caracteres verbatim interpolada - - Use recommended dispose pattern - Usar o padrão de descarte recomendado - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - Use o padrão de descarte recomendado para garantir que o objeto criado por '{0}' seja descartado em todos os caminhos: instrução/declaração using ou try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: Valor: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index 5469b61533c03..ed247813a2a8f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -275,31 +275,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Создать и назначить оставшиеся как свойства - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - Тип, который реализует System.IDisposable, объявляет поля, относящиеся к типам, которые также реализуют IDisposable. Метод Dispose поля не вызывается методом Dispose объявляющего типа. Чтобы устранить нарушение этого правила, вызовите Dispose для полей, относящихся к типам, которые реализуют IDisposable, если вы отвечаете за выделение и освобождение неуправляемых ресурсов, хранящихся в поле. - - - - Disposable field '{0}' is never disposed - Освобождаемое поле "{0}" никогда не освобождается. - - - - Disposable fields should be disposed - Следует высвобождать высвобождаемые поля - - - - Disposable object created by '{0}' is never disposed - Освобождаемый объект, созданный "{0}", никогда не освобождается. - - - - Dispose objects before losing scope - Ликвидировать объекты перед потерей области - - Do not change this code. Put cleanup code in '{0}' method Не изменяйте этот код. Разместите код очистки в методе "{0}". @@ -2005,11 +1980,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Обновление "{0}" рядом с активной инструкцией сделает продолжение сеанса отладки невозможным. - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - Используйте рекомендуемый шаблон для корректного освобождения объектов в локальной области по всем путям. По возможности создание следует заключить в оператор using или объявление using. Если это невозможно, используйте шаблон try-finally с выделенной локальной переменной, объявляемой до области try, и безусловным вызовом Dispose для отличного от NULL значения в области finally, например: x?.Dispose(). Если объект явно освобождается в области try или владение освобождением передается другому объекту или методу, то сразу после такой операции присвойте локальной переменной значение NULL, чтобы предотвратить двойное освобождение в finally. - - Use block body for lambda expressions Использовать тело блока для лямбда-выражений @@ -2025,16 +1995,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Использовать интерполированную буквальную строку - - Use recommended dispose pattern - Использовать рекомендуемый шаблон освобождения - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - Используйте рекомендуемый шаблон освобождения, чтобы убедиться, что объект, созданный "{0}", освобожден для всех путей: инструкцию или объявление using либо конструкцию try/finally. - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: Значение: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index 3371b57c93be9..5898f4a52f02a 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -275,31 +275,6 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Kalanları özellik olarak oluştur ve ata - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - System.IDisposable uygulayan bir tür, kendileri de IDisposable uygulayan türlerde alanlar bildiriyor. Alanın Dispose metodu, bildirim türünün Dispose metodu tarafından çağrılmıyor. Bu kural ihlalini düzeltmek için, alan tarafından tutulan yönetilmeyen kaynakları ayırmak ve serbest bırakmaktan sorumluysanız, IDisposable uygulayan türlerdeki alanlarda Dispose çağrısı yapın. - - - - Disposable field '{0}' is never disposed - '{0}' atılabilir alanı hiç atılmadı - - - - Disposable fields should be disposed - Atılabilir alanlar atılmalıdır - - - - Disposable object created by '{0}' is never disposed - '{0}' tarafından oluşturulan atılabilir nesne hiç atılmadı - - - - Dispose objects before losing scope - Kapsamı kaybetmeden çnce nesneleri bırakın - - Do not change this code. Put cleanup code in '{0}' method Bu kodu değiştirmeyin. Temizleme kodunu '{0}' metodunun içine yerleştirin. @@ -2005,11 +1980,6 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Etkin bir deyim etrafındaki '{0}' öğesini güncelleştirmek, hata ayıklama oturumunun devam etmesini engeller. - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - Yerel olarak kapsamı oluşturulan atılabilir nesnelerin tüm yollarda atıldığından emin olmak için önerilen atma desenini kullanın. Mümkünse, oluşturulan nesneyi 'using' deyimi veya 'using' bildirimiyle sarmalayın. Aksi halde, try bölgesinden önce bildirilen ayrılmış bir yerel değişkeni ve 'finally' bölgesinde null olmayan değer üzerinde koşulsuz bir Dispose çağrısı (örneğin, 'x?.Dispose()') olan bir try-finally deseni kullanın. Nesne try bölgesi içinde açıkça atıldıysa veya atma sahipliği başka bir nesne ya da metoda aktarıldıysa, 'finally' bölgesinde çift atma gerçekleşmesini önlemek için bu tür bir işlemden hemen sonra yerel değişkene 'null' atayın - - Use block body for lambda expressions Lambda ifadeleri için blok vücut kullanımı @@ -2025,16 +1995,6 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Enterpolasyonlu kelimesi kelimesine dizeyi kullanın - - Use recommended dispose pattern - Önerilen atma desenini kullan - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - '{0}' tarafından oluşturulan nesnenin tüm yollarda atıldığından emin olmak için önerilen atma desenini kullanın: using deyimi/bildirimi veya try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: Değer: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index 0a81bf49d13e2..810a18882ace1 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -275,31 +275,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 创建并分配其余属性 - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - 实现 System.IDisposable 的类型将声明一些字段,这些字段所属的类型还实现 IDisposable。字段的 Dispose 方法不由声明类型的 Dispose 方法调用。若要修复此规则的违规行为,如果你负责分配和释放该字段持有的非托管资源,请在其所属类型实现 IDisposable 的字段上调用 Dispose。 - - - - Disposable field '{0}' is never disposed - 从未释放可释放字段 "{0}" - - - - Disposable fields should be disposed - 应释放可释放的字段 - - - - Disposable object created by '{0}' is never disposed - 从未释放由 "{0}" 创建的可释放对象 - - - - Dispose objects before losing scope - 丢失范围之前释放对象 - - Do not change this code. Put cleanup code in '{0}' method 不要更改此代码。请将清理代码放入“{0}”方法中 @@ -2005,11 +1980,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 更新活动语句周围的“{0}”将阻止调试会话继续执行。 - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - 使用推荐的释放模式以确保在所有路径中释放局部可释放对象。如果可能,请将创建包装在 "using" 语句或 "using" 声明中。否则,请使用 try-finally 模式,在 try 区域之前声明一个专用的局部变量,在 "finally" 区域中对非 null 值进行无条件 Dispose 调用,比如,"x?.Dispose()"。如果对象显式释放在 try 区域内或释放所有权转让给另一个对象或方法,则在这样的操作之后立即将 "null" 分配给局部变量,以防止在 "finally" 中进行双重释放。 - - Use block body for lambda expressions 对 lambda 表达式使用块主体 @@ -2025,16 +1995,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 使用内插的逐字字符串 - - Use recommended dispose pattern - 使用建议的释放模式 - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - 使用建议的释放模式以确保在所有路径上释放由 "{0}" 创建的对象: using 语句/声明或 try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: 值: diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index b5b751493137b..37e625a68db42 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -275,31 +275,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 建立其餘項目並將其指派為屬性 - - A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. To fix a violation of this rule, call Dispose on fields that are of types that implement IDisposable if you are responsible for allocating and releasing the unmanaged resources held by the field. - 實作 System.IDisposable 的類型,宣告的欄位會是也實作 IDisposable 的類型。該欄位的 Dispose 方法,並非由宣告類型的 Dispose 方法呼叫。若要修正此規則違規,如果由您負責配置及釋放由該欄位所保留的非受控資源,則請在會實作 IDisposable 的欄位類型欄位上,呼叫 Dispose。 - - - - Disposable field '{0}' is never disposed - 可處置的欄位 '{0}' 從未經過處置 - - - - Disposable fields should be disposed - 可處置的欄位應受到處置 - - - - Disposable object created by '{0}' is never disposed - '{0}' 建立的可處置物件從未經過處置 - - - - Dispose objects before losing scope - 必須在超出範圍前處置物件 - - Do not change this code. Put cleanup code in '{0}' method 請勿變更此程式碼。請將清除程式碼放入 '{0}' 方法 @@ -2005,11 +1980,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 更新使用中陳述式前後的 '{0}',會造成偵錯工作階段無法繼續。 - - Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a 'using' statement or a 'using' declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the 'finally' region, say 'x?.Dispose()'. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object or method, assign 'null' to the local variable just after such an operation to prevent double dispose in 'finally' - 請使用建議的處置模式,確保區域範圍的可處置物件在所有路徑上均會經過處置。在可能的情況下,請將建立包在 'using' 陳述式或 'using' 宣告內。否則,請使用 try-finally 模式,同時在 try 區域之前先宣告專用的區域變數,並在 'finally' 區域中的非 null 值上,設定無條件 Dispose 引動過程,比如 'x?.Dispose()'。如果 try 區域內已明確地處置了該物件,或是處置擁有權已轉移到另一個物件或方法,則請在這類作業之後,對區域變數指派 'null',以避免在 'finally' 中發生雙重處置 - - Use block body for lambda expressions 使用 Lambda 運算式的區塊主體 @@ -2025,16 +1995,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 使用插入的逐字字串 - - Use recommended dispose pattern - 使用建議的處置模式 - - - - Use recommended dispose pattern to ensure that object created by '{0}' is disposed on all paths: using statement/declaration or try/finally - 請使用建議的處置模式,確保 '{0}' 建立的物件在所有路徑上均會經過處置: using 陳述式/宣告或 try/finally - {Locked="using"}{Locked="try"}{Locked="finally"} "using", "try" and "finally" are C# keywords and should not be localized. - Value: 值: