Skip to content

Commit 0d669ae

Browse files
committed
BUIGFIX: Infinite recursion when comparing generic parameter.
Fix #212
1 parent d778e00 commit 0d669ae

File tree

6 files changed

+75
-7
lines changed

6 files changed

+75
-7
lines changed

IDisposableAnalyzers.Test/Helpers/AssignedValueWalkerTests/AssignedValueWalkerTests.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace IDisposableAnalyzers.Test.Helpers.AssignedValueWalkerTests
1+
namespace IDisposableAnalyzers.Test.Helpers.AssignedValueWalkerTests
22
{
33
using System.Threading;
44
using Gu.Roslyn.Asserts;
@@ -43,5 +43,33 @@ internal void M()
4343
var actual = string.Join(", ", assignedValues);
4444
Assert.AreEqual(expected, actual);
4545
}
46+
47+
[Test]
48+
public static void GenericOut()
49+
{
50+
var syntaxTree = CSharpSyntaxTree.ParseText(@"
51+
namespace N
52+
{
53+
public sealed class C
54+
{
55+
public T M<T>(out T t1)
56+
{
57+
return M(0, out t1);
58+
}
59+
60+
public T M<T>(int _, out T t2)
61+
{
62+
t2 = default;
63+
return default;
64+
}
65+
}
66+
}");
67+
var compilation = CSharpCompilation.Create("test", new[] { syntaxTree }, MetadataReferences.FromAttributes());
68+
var semanticModel = compilation.GetSemanticModel(syntaxTree);
69+
var argument = syntaxTree.FindArgument("t1");
70+
using var assignedValues = AssignedValueWalker.Borrow(argument.Expression, semanticModel, CancellationToken.None);
71+
var actual = string.Join(", ", assignedValues);
72+
Assert.AreEqual("default", actual);
73+
}
4674
}
4775
}

IDisposableAnalyzers.Test/IDISP001DisposeCreatedTests/Valid.Recursion.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,29 @@ private static IDisposable WithOptionalParameter(IDisposable value, IEnumerable<
153153
return value;
154154
}
155155
}
156+
}";
157+
RoslynAssert.Valid(Analyzer, code);
158+
}
159+
160+
[Test]
161+
public static void GenericOut()
162+
{
163+
var code = @"
164+
namespace N
165+
{
166+
public sealed class C
167+
{
168+
public T M<T>(out T t)
169+
{
170+
return M(0, out t);
171+
}
172+
173+
public T M<T>(int _, out T t)
174+
{
175+
t = default;
176+
return default;
177+
}
178+
}
156179
}";
157180
RoslynAssert.Valid(Analyzer, code);
158181
}

IDisposableAnalyzers/Analyzers/ArgumentAnalyzer.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ private static void Handle(SyntaxNodeAnalysisContext context)
4747

4848
private static bool IsCreation(ArgumentSyntax candidate, SemanticModel semanticModel, CancellationToken cancellationToken)
4949
{
50-
if (candidate.Parent is ArgumentListSyntax argumentList &&
51-
argumentList.Parent is InvocationExpressionSyntax invocation &&
50+
if (candidate.Parent is ArgumentListSyntax { Parent: InvocationExpressionSyntax invocation } &&
5251
semanticModel.TryGetSymbol(invocation, cancellationToken, out var method) &&
5352
method.TryFindParameter(candidate, out var parameter) &&
5453
Disposable.IsPotentiallyAssignableFrom(parameter.Type, semanticModel.Compilation))

IDisposableAnalyzers/Helpers/Walkers/AssignedValueWalker.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections;
55
using System.Collections.Generic;
66
using System.Diagnostics.CodeAnalysis;
7+
using System.Linq;
78
using System.Threading;
89
using Gu.Roslyn.AnalyzerExtensions;
910
using Microsoft.CodeAnalysis;
@@ -15,8 +16,8 @@ internal sealed class AssignedValueWalker : PooledWalker<AssignedValueWalker>, I
1516
private readonly List<ExpressionSyntax> values = new List<ExpressionSyntax>();
1617
private readonly List<ExpressionSyntax> outValues = new List<ExpressionSyntax>();
1718
private readonly MemberWalkers memberWalkers = new MemberWalkers();
18-
private readonly HashSet<IParameterSymbol> refParameters = new HashSet<IParameterSymbol>(SymbolComparer.Default);
19-
private readonly HashSet<IParameterSymbol> outParameters = new HashSet<IParameterSymbol>(SymbolComparer.Default);
19+
private readonly HashSet<IParameterSymbol> refParameters = new HashSet<IParameterSymbol>(ParameterSymbolComparer.Default);
20+
private readonly HashSet<IParameterSymbol> outParameters = new HashSet<IParameterSymbol>(ParameterSymbolComparer.Default);
2021
private readonly PublicMemberWalker publicMemberWalker;
2122
private readonly CtorArgWalker ctorArgWalker;
2223

@@ -711,7 +712,7 @@ bool TryGetProperty(out IPropertySymbol? result)
711712
}
712713
}
713714

714-
private struct Context
715+
private readonly struct Context
715716
{
716717
internal readonly SyntaxNode Node;
717718
private readonly StatementSyntax? stopAt;

IDisposableAnalyzers/IDisposableAnalyzers.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545

4646
<ItemGroup>
4747
<PackageReference Include="Gu.Analyzers" Version="1.6.7-dev" PrivateAssets="all" />
48-
<PackageReference Include="Gu.Roslyn.Extensions" Version="0.12.5-dev" />
48+
<PackageReference Include="Gu.Roslyn.Extensions" Version="0.12.6-dev" />
4949
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.3.1" />
5050
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="all" />
5151
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.164" PrivateAssets="all" />

ValidCode/Recursion/Issue212.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace ValidCode.Recursion
2+
{
3+
class Issue212
4+
{
5+
public void M<T>(out T str)
6+
{
7+
str = default;
8+
//return M(0, out str);
9+
}
10+
11+
public T M<T>(int _, out T str)
12+
{
13+
str = default;
14+
return default;
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)