Skip to content

Commit

Permalink
xUnit1030/xUnit1031 should not trigger inside local functions (#178)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartyIX authored Jan 7, 2024
1 parent 5e8ac1f commit b13d87c
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.CodeAnalysis.CSharp;
using Xunit;
using Verify = CSharpVerifier<Xunit.Analyzers.DoNotUseBlockingTaskOperations>;

Expand Down Expand Up @@ -35,10 +36,13 @@ public class TestClass {
public void TestMethod() {
default(IValueTaskSource).[|GetResult(0)|];
Action<IValueTaskSource> _ = vts => vts.GetResult(0);
void LocalFunction() {
default(IValueTaskSource).GetResult(0);
}
}
}";

await Verify.VerifyAnalyzer(source);
await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}
}

Expand All @@ -57,10 +61,13 @@ public class TestClass {
public void TestMethod() {
default(IValueTaskSource<int>).[|GetResult(0)|];
Func<IValueTaskSource<int>, int> _ = vts => vts.GetResult(0);
void LocalFunction() {
default(IValueTaskSource<int>).GetResult(0);
}
}
}";

await Verify.VerifyAnalyzer(source);
await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}
}

Expand All @@ -81,10 +88,13 @@ public class TestClass {
public void TestMethod() {
Task.Delay(1).[|Wait()|];
Action<Task> _ = t => t.Wait();
void LocalFunction() {
Task.Delay(1).Wait();
}
}
}";

await Verify.VerifyAnalyzer(source);
await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}

[Fact]
Expand Down Expand Up @@ -211,10 +221,13 @@ public class TestClass {{
public void TestMethod() {{
Task.[|{waitMethod}(Task.Delay(1))|];
Action<Task> _ = t => Task.{waitMethod}(t);
void LocalFunction() {{
Task.{waitMethod}(Task.Delay(1));
}}
}}
}}";

await Verify.VerifyAnalyzer(source);
await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}

[Theory]
Expand Down Expand Up @@ -351,10 +364,13 @@ public class TestClass {
public void TestMethod() {
Task.CompletedTask.GetAwaiter().[|GetResult()|];
Action<Task> _ = t => t.GetAwaiter().GetResult();
void LocalFunction() {
Task.CompletedTask.GetAwaiter().GetResult();
}
}
}";

await Verify.VerifyAnalyzer(source);
await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}

[Fact]
Expand Down Expand Up @@ -482,10 +498,13 @@ public class TestClass {
public void TestMethod() {
var _ = Task.FromResult(42).[|Result|];
Func<Task<int>, int> _2 = t => t.Result;
void LocalFunction() {
var _3 = Task.FromResult(42).Result;
}
}
}";

await Verify.VerifyAnalyzer(source);
await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}

[Fact]
Expand Down Expand Up @@ -612,10 +631,13 @@ public class TestClass {
public void TestMethod() {
var _ = Task.FromResult(42).GetAwaiter().[|GetResult()|];
Func<Task<int>, int> _2 = t => t.GetAwaiter().GetResult();
void LocalFunction() {
var _3 = Task.FromResult(42).GetAwaiter().GetResult();
}
}
}";

await Verify.VerifyAnalyzer(source);
await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}

[Fact]
Expand Down Expand Up @@ -743,10 +765,13 @@ public class TestClass {
public void TestMethod() {
default(ValueTask).GetAwaiter().[|GetResult()|];
Action<ValueTask> _ = vt => vt.GetAwaiter().GetResult();
void LocalFunction() {
default(ValueTask).GetAwaiter().GetResult();
}
}
}";

await Verify.VerifyAnalyzer(source);
await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}
}

Expand All @@ -765,10 +790,13 @@ public class TestClass {
public void TestMethod() {
var _ = new ValueTask<int>(42).[|Result|];
Func<ValueTask<int>, int> _2 = vt => vt.Result;
void LocalFunction() {
var _3 = new ValueTask<int>(42).Result;
}
}
}";

await Verify.VerifyAnalyzer(source);
await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}

[Fact]
Expand All @@ -784,10 +812,13 @@ public class TestClass {
public void TestMethod() {
var _ = new ValueTask<int>(42).GetAwaiter().[|GetResult()|];
Func<ValueTask<int>, int> _2 = vt => vt.GetAwaiter().GetResult();
void LocalFunction() {
var _3 = new ValueTask<int>(42).GetAwaiter().GetResult();
}
}
}";

await Verify.VerifyAnalyzer(source);
await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.CodeAnalysis.CSharp;
using Xunit;
using Verify = CSharpVerifier<Xunit.Analyzers.DoNotUseConfigureAwait>;

Expand Down Expand Up @@ -85,6 +86,27 @@ public async Task TestMethod() {{
await Verify.VerifyAnalyzer(source);
}

[Theory]
[MemberData(nameof(InvalidValues))]
public async void InvalidValue_InsideLocalFunction_DoesNotTrigger(string argumentValue)
{
var source = @$"
using System.Threading.Tasks;
using Xunit;
public class TestClass {{
[Fact]
public async Task TestMethod() {{
var booleanVar = true;
async Task AssertEventStateAsync() {{
await Task.Delay(1).ConfigureAwait({argumentValue});
}}
}}
}}";

await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}

[Theory]
[MemberData(nameof(InvalidValues))]
public async void InvalidValue_TaskWithAwait_Triggers(string argumentValue)
Expand Down Expand Up @@ -281,6 +303,27 @@ public async Task TestMethod() {{
await Verify.VerifyAnalyzer(source);
}

[Theory]
[MemberData(nameof(InvalidValues))]
public async void InvalidValue_InsideLocalFunction_DoesNotTrigger(string argumentValue)
{
var source = @$"
using System.Threading.Tasks;
using Xunit;
public class TestClass {{
[Fact]
public async Task TestMethod() {{
var enumVar = ConfigureAwaitOptions.ContinueOnCapturedContext;
async Task AssertEventStateAsync() {{
await Task.Delay(1).ConfigureAwait({argumentValue});
}}
}}
}}";

await Verify.VerifyAnalyzer(LanguageVersion.CSharp7, source);
}

[Theory]
[MemberData(nameof(InvalidValues))]
public async void InvalidValue_TaskWithAwait_Triggers(string enumValue)
Expand Down
8 changes: 4 additions & 4 deletions src/xunit.analyzers/X1000/DoNotUseBlockingTaskOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ public override void AnalyzeCompilation(
if (!foundSymbol)
return;

// Ignore anything inside a lambda expression
// Ignore anything inside a lambda expression or a local function
for (var current = context.Operation; current is not null; current = current.Parent)
if (current is IAnonymousFunctionOperation)
if (current is IAnonymousFunctionOperation || current is ILocalFunctionOperation)
return;

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

// Ignore anything inside a lambda expression
// Ignore anything inside a lambda expression or a local function
for (var current = context.Operation; current is not null; current = current.Parent)
if (current is IAnonymousFunctionOperation)
if (current is IAnonymousFunctionOperation || current is ILocalFunctionOperation)
return;

if (foundSymbolName == nameof(Task<int>.Result) &&
Expand Down
4 changes: 2 additions & 2 deletions src/xunit.analyzers/X1000/DoNotUseConfigureAwait.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ public override void AnalyzeCompilation(
if (!invocation.IsInTestMethod(xunitContext))
return;

// Ignore anything inside a lambda expression
// Ignore anything inside a lambda expression or a local function
for (var current = context.Operation; current is not null; current = current.Parent)
if (current is IAnonymousFunctionOperation)
if (current is IAnonymousFunctionOperation || current is ILocalFunctionOperation)
return;

// invocation should be two nodes: "(some other code).ConfigureAwait" and the arguments (like "(false)")
Expand Down

0 comments on commit b13d87c

Please sign in to comment.