Skip to content

Commit

Permalink
xunit/xunit#2856: xUnit1031 should not apply when syntax is part of a…
Browse files Browse the repository at this point in the history
…n expression tree
  • Loading branch information
bradwilson committed Dec 28, 2023
1 parent ead9a3b commit a39562e
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ public class IValueTaskSource_NonGeneric
public async void FailureCase_GetResult()
{
var source = @"
using System;
using System.Threading.Tasks.Sources;
using Xunit;
public class TestClass {
[Fact]
public void TestMethod() {
default(IValueTaskSource).[|GetResult(0)|];
Action<IValueTaskSource> _ = vts => vts.GetResult(0);
}
}";

Expand All @@ -46,13 +48,15 @@ public class IValueTaskSource_Generic
public async void FailureCase_GetResult()
{
var source = @"
using System;
using System.Threading.Tasks.Sources;
using Xunit;
public class TestClass {
[Fact]
public void TestMethod() {
default(IValueTaskSource<int>).[|GetResult(0)|];
Func<IValueTaskSource<int>, int> _ = vts => vts.GetResult(0);
}
}";

Expand All @@ -68,13 +72,15 @@ public class Wait
public async void FailureCase()
{
var source = @"
using System;
using System.Threading.Tasks;
using Xunit;
public class TestClass {
[Fact]
public void TestMethod() {
Task.Delay(1).[|Wait()|];
Action<Task> _ = t => t.Wait();
}
}";

Expand Down Expand Up @@ -196,13 +202,15 @@ public class WaitAny_WaitAll
public async void FailureCase(string waitMethod)
{
var source = @$"
using System;
using System.Threading.Tasks;
using Xunit;
public class TestClass {{
[Fact]
public void TestMethod() {{
Task.[|{waitMethod}(Task.Delay(1))|];
Action<Task> _ = t => Task.{waitMethod}(t);
}}
}}";

Expand Down Expand Up @@ -334,13 +342,15 @@ public class GetAwaiterGetResult
public async void FailureCase()
{
var source = @"
using System;
using System.Threading.Tasks;
using Xunit;
public class TestClass {
[Fact]
public void TestMethod() {
Task.CompletedTask.GetAwaiter().[|GetResult()|];
Action<Task> _ = t => t.GetAwaiter().GetResult();
}
}";

Expand Down Expand Up @@ -463,13 +473,15 @@ public class Result
public async void FailureCase()
{
var source = @"
using System;
using System.Threading.Tasks;
using Xunit;
public class TestClass {
[Fact]
public void TestMethod() {
var _ = Task.FromResult(42).[|Result|];
Func<Task<int>, int> _2 = t => t.Result;
}
}";

Expand Down Expand Up @@ -591,13 +603,15 @@ public class GetAwaiterGetResult
public async void FailureCase()
{
var source = @"
using System;
using System.Threading.Tasks;
using Xunit;
public class TestClass {
[Fact]
public void TestMethod() {
var _ = Task.FromResult(42).GetAwaiter().[|GetResult()|];
Func<Task<int>, int> _2 = t => t.GetAwaiter().GetResult();
}
}";

Expand Down Expand Up @@ -720,13 +734,15 @@ public class ValueTask_NonGeneric
public async void FailureCase_GetAwaiterGetResult()
{
var source = @"
using System;
using System.Threading.Tasks;
using Xunit;
public class TestClass {
[Fact]
public void TestMethod() {
default(ValueTask).GetAwaiter().[|GetResult()|];
Action<ValueTask> _ = vt => vt.GetAwaiter().GetResult();
}
}";

Expand All @@ -740,13 +756,15 @@ public class ValueTask_Generic
public async void FailureCase_Result()
{
var source = @"
using System;
using System.Threading.Tasks;
using Xunit;
public class TestClass {
[Fact]
public void TestMethod() {
var _ = new ValueTask<int>(42).[|Result|];
Func<ValueTask<int>, int> _2 = vt => vt.Result;
}
}";

Expand All @@ -757,13 +775,15 @@ public void TestMethod() {
public async void FailureCase_GetAwaiterGetResult()
{
var source = @"
using System;
using System.Threading.Tasks;
using Xunit;
public class TestClass {
[Fact]
public void TestMethod() {
var _ = new ValueTask<int>(42).GetAwaiter().[|GetResult()|];
Func<ValueTask<int>, int> _2 = vt => vt.GetAwaiter().GetResult();
}
}";

Expand Down
33 changes: 8 additions & 25 deletions src/xunit.analyzers/X1000/DoNotUseBlockingTaskOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ public class DoNotUseBlockingTaskOperations : XunitDiagnosticAnalyzer
// These are on both Task<T> and ValueTask<T>
nameof(Task<int>.Result),
};
static readonly string[] continueWith = new[]
{
nameof(Task<int>.ContinueWith),
};
static readonly string[] whenAll = new[]
{
nameof(Task.WhenAll),
Expand Down Expand Up @@ -90,8 +86,10 @@ public override void AnalyzeCompilation(
if (!foundSymbol)
return;

if (WrappedInContinueWith(invocation, taskType, xunitContext))
return;
// Ignore anything inside a lambda expression
for (var current = context.Operation; current is not null; current = current.Parent)
if (current is IAnonymousFunctionOperation)
return;

var symbolsForSearch = default(IEnumerable<ILocalSymbol>);
switch (foundSymbolName)
Expand Down Expand Up @@ -160,8 +158,10 @@ invocation.Arguments[0].Value is IArrayCreationOperation arrayCreationOperation
if (!foundSymbol)
return;

if (WrappedInContinueWith(reference, taskType, xunitContext))
return;
// Ignore anything inside a lambda expression
for (var current = context.Operation; current is not null; current = current.Parent)
if (current is IAnonymousFunctionOperation)
return;

if (foundSymbolName == nameof(Task<int>.Result) &&
reference.Instance is ILocalReferenceOperation localReferenceOperation &&
Expand Down Expand Up @@ -300,21 +300,4 @@ static void ValidateTasksInWhenAll(
foreach (var arrayElement in arrayCreation.Initializer.ElementValues.OfType<ILocalReferenceOperation>())
unfoundSymbols.Remove(arrayElement.Local);
}

static bool WrappedInContinueWith(
IOperation? operation,
INamedTypeSymbol taskType,
XunitContext xunitContext)
{
for (; operation is not null; operation = operation.Parent)
{
if (operation is not IInvocationOperation invocation)
continue;

if (FindSymbol(invocation.TargetMethod, invocation, taskType, continueWith, xunitContext, out var _))
return true;
}

return false;
}
}

0 comments on commit a39562e

Please sign in to comment.