Skip to content

Commit b864e75

Browse files
BoukeJohanLarsson
authored andcommitted
Don't trigger IDISP013 when returning ValueTask
1 parent bdc1b69 commit b864e75

4 files changed

Lines changed: 71 additions & 2 deletions

File tree

IDisposableAnalyzers.Test/IDISP013AwaitInUsingTests/Valid.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,29 @@ public Task<int> M()
116116
RoslynAssert.Valid(Analyzer, code);
117117
}
118118

119+
[Test]
120+
public static void ValueTaskFromResult()
121+
{
122+
var code = @"
123+
namespace N
124+
{
125+
using System.IO;
126+
using System.Threading.Tasks;
127+
128+
public class C
129+
{
130+
public ValueTask<int> M()
131+
{
132+
using (var stream = File.OpenRead(string.Empty))
133+
{
134+
return ValueTask.FromResult(1);
135+
}
136+
}
137+
}
138+
}";
139+
RoslynAssert.Valid(Analyzer, code);
140+
}
141+
119142
[Test]
120143
public static void TaskCompletedTask()
121144
{
@@ -139,6 +162,29 @@ public Task M()
139162
RoslynAssert.Valid(Analyzer, code);
140163
}
141164

165+
[Test]
166+
public static void ValueTaskCompletedTask()
167+
{
168+
var code = @"
169+
namespace N
170+
{
171+
using System.IO;
172+
using System.Threading.Tasks;
173+
174+
public class C
175+
{
176+
public ValueTask M()
177+
{
178+
using (var stream = File.OpenRead(string.Empty))
179+
{
180+
return ValueTask.CompletedTask;
181+
}
182+
}
183+
}
184+
}";
185+
RoslynAssert.Valid(Analyzer, code);
186+
}
187+
142188
[Test]
143189
public static void UsingNewMTaskRun()
144190
{

IDisposableAnalyzers/Analyzers/ReturnValueAnalyzer.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,11 @@ private static bool ShouldAwait(SyntaxNodeAnalysisContext context, ExpressionSyn
186186
return returnValue switch
187187
{
188188
InvocationExpressionSyntax invocation
189-
=> !invocation.IsSymbol(KnownSymbols.Task.FromResult, context.SemanticModel, context.CancellationToken),
189+
=> !(invocation.IsSymbol(KnownSymbols.Task.FromResult, context.SemanticModel, context.CancellationToken)
190+
|| invocation.IsSymbol(KnownSymbols.ValueTask.FromResult, context.SemanticModel, context.CancellationToken)),
190191
MemberAccessExpressionSyntax { Name.Identifier.ValueText: "CompletedTask" } memberAccess
191-
=> !memberAccess.IsSymbol(KnownSymbols.Task.CompletedTask, context.SemanticModel, context.CancellationToken),
192+
=> !(memberAccess.IsSymbol(KnownSymbols.Task.CompletedTask, context.SemanticModel, context.CancellationToken)
193+
|| memberAccess.IsSymbol(KnownSymbols.ValueTask.CompletedTask, context.SemanticModel, context.CancellationToken)),
192194
_ => true,
193195
};
194196
}

IDisposableAnalyzers/Helpers/KnownSymbols/KnownSymbols.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ internal static class KnownSymbols
5757
internal static readonly EnumerableType Enumerable = new();
5858
internal static readonly QualifiedType ConditionalWeakTable = Create("System.Runtime.CompilerServices.ConditionalWeakTable`2");
5959
internal static readonly TaskType Task = new();
60+
internal static readonly ValueTaskType ValueTask = new();
6061
internal static readonly QualifiedType ValueTaskOfT = new("System.Threading.Tasks.ValueTask`1");
6162
internal static readonly QualifiedType TaskOfT = new("System.Threading.Tasks.Task`1");
6263
internal static readonly QualifiedType CancellationToken = new("System.Threading.CancellationToken");
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace IDisposableAnalyzers;
2+
3+
using Gu.Roslyn.AnalyzerExtensions;
4+
5+
internal class ValueTaskType : QualifiedType
6+
{
7+
internal readonly QualifiedMethod FromResult;
8+
internal readonly QualifiedMethod Run;
9+
internal readonly QualifiedMethod RunOfT;
10+
internal readonly QualifiedMethod ConfigureAwait;
11+
internal readonly QualifiedProperty CompletedTask;
12+
13+
internal ValueTaskType()
14+
: base("System.Threading.Tasks.ValueTask")
15+
{
16+
this.FromResult = new QualifiedMethod(this, nameof(this.FromResult));
17+
this.ConfigureAwait = new QualifiedMethod(this, nameof(this.ConfigureAwait));
18+
this.CompletedTask = new QualifiedProperty(this, nameof(this.CompletedTask));
19+
}
20+
}

0 commit comments

Comments
 (0)