Skip to content

Commit 940c320

Browse files
authored
Fix false positive for PreferTestCleanupOverDispose on non-test classes (#4380)
1 parent 6663992 commit 940c320

2 files changed

Lines changed: 28 additions & 5 deletions

File tree

src/Analyzers/MSTest.Analyzers/PreferTestCleanupOverDisposeAnalyzer.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,28 @@ public override void Initialize(AnalysisContext context)
4040

4141
context.RegisterCompilationStartAction(context =>
4242
{
43-
if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemIDisposable, out INamedTypeSymbol? idisposableSymbol))
43+
if (context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemIDisposable, out INamedTypeSymbol? idisposableSymbol) &&
44+
context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingTestClassAttribute, out INamedTypeSymbol? testClassAttributeSymbol))
4445
{
4546
INamedTypeSymbol? iasyncDisposableSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemIAsyncDisposable);
4647
INamedTypeSymbol? valueTaskSymbol = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingTasksValueTask);
47-
context.RegisterSymbolAction(context => AnalyzeSymbol(context, idisposableSymbol, iasyncDisposableSymbol, valueTaskSymbol), SymbolKind.Method);
48+
context.RegisterSymbolAction(context => AnalyzeSymbol(context, testClassAttributeSymbol, idisposableSymbol, iasyncDisposableSymbol, valueTaskSymbol), SymbolKind.Method);
4849
}
4950
});
5051
}
5152

52-
private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol idisposableSymbol, INamedTypeSymbol? iasyncDisposableSymbol,
53+
private static void AnalyzeSymbol(
54+
SymbolAnalysisContext context,
55+
INamedTypeSymbol testClassAttributeSymbol,
56+
INamedTypeSymbol idisposableSymbol,
57+
INamedTypeSymbol? iasyncDisposableSymbol,
5358
INamedTypeSymbol? valueTaskSymbol)
5459
{
5560
var methodSymbol = (IMethodSymbol)context.Symbol;
5661

57-
if (methodSymbol.IsAsyncDisposeImplementation(iasyncDisposableSymbol, valueTaskSymbol)
58-
|| methodSymbol.IsDisposeImplementation(idisposableSymbol))
62+
if (methodSymbol.ContainingType.GetAttributes().Any(x => x.AttributeClass.Inherits(testClassAttributeSymbol)) &&
63+
(methodSymbol.IsAsyncDisposeImplementation(iasyncDisposableSymbol, valueTaskSymbol)
64+
|| methodSymbol.IsDisposeImplementation(idisposableSymbol)))
5965
{
6066
context.ReportDiagnostic(methodSymbol.CreateDiagnostic(Rule));
6167
}

test/UnitTests/MSTest.Analyzers.UnitTests/PreferTestCleanupOverDisposeAnalyzerTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ namespace MSTest.Analyzers.Test;
1010
[TestGroup]
1111
public sealed class PreferTestCleanupOverDisposeAnalyzerTests(ITestExecutionContext testExecutionContext) : TestBase(testExecutionContext)
1212
{
13+
public async Task WhenNonTestClassHasDispose_NoDiagnostic()
14+
{
15+
string code = """
16+
using System;
17+
using Microsoft.VisualStudio.TestTools.UnitTesting;
18+
19+
public class MyNonTestClass : IDisposable
20+
{
21+
public void Dispose()
22+
{
23+
}
24+
}
25+
""";
26+
27+
await VerifyCS.VerifyCodeFixAsync(code, code);
28+
}
29+
1330
public async Task WhenTestClassHasDispose_Diagnostic()
1431
{
1532
string code = """

0 commit comments

Comments
 (0)