From 2e483795624c9f877e24156762fb533d3ef106e4 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:25:50 +0000 Subject: [PATCH] Fix Disposable Analyzer with Primary Constructor (#1398) --- .../DisposableFieldPropertyAnalyzerTests.cs | 36 ++++++++++++++++++- .../DisposableFieldPropertyAnalyzer.cs | 12 ++++++- TUnit.Analyzers/Extensions/TypeExtensions.cs | 2 +- .../Extensions/TypeExtensions.cs | 2 +- 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/TUnit.Analyzers.Tests/DisposableFieldPropertyAnalyzerTests.cs b/TUnit.Analyzers.Tests/DisposableFieldPropertyAnalyzerTests.cs index 6c1fada19f..23a1d66ab8 100644 --- a/TUnit.Analyzers.Tests/DisposableFieldPropertyAnalyzerTests.cs +++ b/TUnit.Analyzers.Tests/DisposableFieldPropertyAnalyzerTests.cs @@ -183,7 +183,41 @@ public void Test1() """ ); } - + + [Test] + public async Task New_Disposable_No_Issue_When_Cleaned_Up_PrimaryConstructor() + { + await Verifier + .VerifyAnalyzerAsync( + """ + using System.Net.Http; + using TUnit.Core; + + public class Test() // note the use of primary constructor here + { + private HttpClient _client = null!; + + [Before(HookType.Test)] + public void Setup() + { + _client = new HttpClient(); + } + + [After(HookType.Test)] + public void Cleanup() + { + _client.Dispose(); + } + + [Test] + public void TestMethod() + { + } + } + """ + ); + } + [Test] public async Task New_Disposable__Static_No_Issue_When_Cleaned_Up_Nullable() { diff --git a/TUnit.Analyzers/DisposableFieldPropertyAnalyzer.cs b/TUnit.Analyzers/DisposableFieldPropertyAnalyzer.cs index bade7ad1b6..5c574a5720 100644 --- a/TUnit.Analyzers/DisposableFieldPropertyAnalyzer.cs +++ b/TUnit.Analyzers/DisposableFieldPropertyAnalyzer.cs @@ -70,7 +70,17 @@ private static void CheckSetUps(SyntaxNodeAnalysisContext context, IMethodSymbol var syntaxNodes = methodSymbol.DeclaringSyntaxReferences .SelectMany(x => x.GetSyntax().DescendantNodesAndSelf()).ToArray(); - methodSymbol.IsHookMethod(context.Compilation, out _, out var level, out _); + var isHookMethod = methodSymbol.IsHookMethod(context.Compilation, out _, out var level, out _); + + if (!isHookMethod && methodSymbol.MethodKind != MethodKind.Constructor) + { + return; + } + + if (methodSymbol.MethodKind == MethodKind.Constructor) + { + level = HookLevel.Test; + } foreach (var assignment in syntaxNodes .Where(x => x.IsKind(SyntaxKind.SimpleAssignmentExpression))) diff --git a/TUnit.Analyzers/Extensions/TypeExtensions.cs b/TUnit.Analyzers/Extensions/TypeExtensions.cs index 2b0f51235f..7735c5069e 100644 --- a/TUnit.Analyzers/Extensions/TypeExtensions.cs +++ b/TUnit.Analyzers/Extensions/TypeExtensions.cs @@ -24,7 +24,7 @@ public static IEnumerable GetSelfAndBaseTypes(this INamedTypeS { var type = namedTypeSymbol; - while (type != null) + while (type != null && type.SpecialType != SpecialType.System_Object) { yield return type; type = type.BaseType; diff --git a/TUnit.Assertions.Analyzers/Extensions/TypeExtensions.cs b/TUnit.Assertions.Analyzers/Extensions/TypeExtensions.cs index 5219c7a52b..c1fdb0b20a 100644 --- a/TUnit.Assertions.Analyzers/Extensions/TypeExtensions.cs +++ b/TUnit.Assertions.Analyzers/Extensions/TypeExtensions.cs @@ -17,7 +17,7 @@ public static IEnumerable GetSelfAndBaseTypes(this ITypeSymbol name { var type = namedTypeSymbol; - while (type != null) + while (type != null && type.SpecialType != SpecialType.System_Object) { yield return type; type = type.BaseType;