Skip to content

Commit 5ae611b

Browse files
committed
BUGFIX IDISP003 don't warn when assigned with null.
Fix #197
1 parent 4a85314 commit 5ae611b

2 files changed

Lines changed: 63 additions & 10 deletions

File tree

IDisposableAnalyzers.Test/IDISP003DisposeBeforeReassigningTests/Valid.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,30 @@ public void M()
7070
RoslynAssert.Valid(Analyzer, code);
7171
}
7272

73+
[Test]
74+
public static void LocalAssignDisposeAssignNullAssign()
75+
{
76+
var code = @"
77+
namespace N
78+
{
79+
using System;
80+
using System.IO;
81+
82+
public class C
83+
{
84+
public void M()
85+
{
86+
var stream = File.OpenRead(string.Empty);
87+
stream.Dispose();
88+
stream = null;
89+
stream = File.OpenRead(string.Empty);
90+
}
91+
}
92+
}";
93+
94+
RoslynAssert.Valid(Analyzer, code);
95+
}
96+
7397
[Test]
7498
public static void LocalAssignedInSwitch()
7599
{
@@ -378,6 +402,32 @@ public C()
378402
RoslynAssert.Valid(Analyzer, code);
379403
}
380404

405+
[Test]
406+
public static void FieldAssignDisposeAssignNullAssignInCtor()
407+
{
408+
var code = @"
409+
namespace N
410+
{
411+
using System;
412+
using System.IO;
413+
414+
public class C
415+
{
416+
private readonly Stream stream;
417+
418+
public C()
419+
{
420+
this.stream = File.OpenRead(string.Empty);
421+
this.stream.Dispose();
422+
this.stream = null;
423+
this.stream = File.OpenRead(string.Empty);
424+
}
425+
}
426+
}";
427+
428+
RoslynAssert.Valid(Analyzer, code);
429+
}
430+
381431
[Test]
382432
public static void FieldSwapCached()
383433
{

IDisposableAnalyzers/Helpers/Disposable.IsDisposed.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,14 @@ static bool TryGetScope(SyntaxNode node, out BlockSyntax result)
5252
result = lambdaBody;
5353
return true;
5454
}
55-
else if (node.FirstAncestor<AccessorDeclarationSyntax>() is { Body: BlockSyntax accessorBody })
55+
56+
if (node.FirstAncestor<AccessorDeclarationSyntax>() is { Body: BlockSyntax accessorBody })
5657
{
5758
result = accessorBody;
5859
return true;
5960
}
60-
else if (node.FirstAncestor<BaseMethodDeclarationSyntax>() is { Body: BlockSyntax methodBody })
61+
62+
if (node.FirstAncestor<BaseMethodDeclarationSyntax>() is { Body: BlockSyntax methodBody })
6163
{
6264
result = methodBody;
6365
return true;
@@ -69,16 +71,17 @@ static bool TryGetScope(SyntaxNode node, out BlockSyntax result)
6971

7072
bool IsReassignedAfter(SyntaxNode scope, InvocationExpressionSyntax disposeCall)
7173
{
72-
using (var walker = MutationWalker.Borrow(scope, SearchScope.Member, semanticModel, cancellationToken))
74+
using var walker = AssignmentWalker.Borrow(scope);
75+
foreach (var assignment in walker.Assignments)
7376
{
74-
foreach (var mutation in walker.All())
77+
if (assignment.TryFirstAncestor(out StatementSyntax? statement) &&
78+
disposeCall.IsExecutedBefore(statement) == ExecutedBefore.Yes &&
79+
statement.IsExecutedBefore(expression) == ExecutedBefore.Yes &&
80+
semanticModel.TryGetSymbol(assignment.Left, cancellationToken, out var assigned) &&
81+
Equals(assigned, symbol) &&
82+
IsCreation(assignment.Right, semanticModel, cancellationToken).IsEither(Result.Yes, Result.AssumeYes))
7583
{
76-
if (mutation.TryFirstAncestor(out StatementSyntax? statement) &&
77-
disposeCall.IsExecutedBefore(statement) == ExecutedBefore.Yes &&
78-
statement.IsExecutedBefore(expression) == ExecutedBefore.Yes)
79-
{
80-
return true;
81-
}
84+
return true;
8285
}
8386
}
8487

0 commit comments

Comments
 (0)