Skip to content

Commit

Permalink
Test yield in lock
Browse files Browse the repository at this point in the history
  • Loading branch information
jjonescz committed Mar 27, 2024
1 parent 8b055e0 commit c74941c
Showing 1 changed file with 173 additions and 0 deletions.
173 changes: 173 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,179 @@ IEnumerable<int> I()
);
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72443")]
public void YieldInLock_Async()
{
var source = """
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
try
{
await new C().ProcessValueAsync();
}
catch (SynchronizationLockException e)
{
Console.WriteLine(e.Message);
}
public class C
{
public async Task ProcessValueAsync()
{
await foreach (int item in GetValuesAsync())
{
await Task.Delay(1);
}
}
private async IAsyncEnumerable<int> GetValuesAsync()
{
await Task.Yield();
lock (this)
{
for (int i = 0; i < 10; i++)
{
yield return i;
if (i == 8)
{
yield break;
}
}
}
}
}
""" + AsyncStreamsTypes;

var expectedOutput = "Object synchronization method was called from an unsynchronized block of code.";

var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe.WithWarningLevel(8));
CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics();

var expectedDiagnostics = new[]
{
// (32,17): warning CS9230: 'yield return' should not be used in the body of a lock statement
// yield return i;
Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(32, 17)
};

comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe.WithWarningLevel(9));
CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics);

comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe);
CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics);
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72443")]
public void YieldInLock_Sync()
{
var source = """
using System;
using System.Collections.Generic;
using System.Threading;
object o = new object();
Console.WriteLine($"Before: {Monitor.IsEntered(o)}");
using (IEnumerator<int> e = GetValues(o).GetEnumerator())
{
Console.WriteLine($"Inside: {Monitor.IsEntered(o)}");
while (e.MoveNext())
{
Console.WriteLine($"{e.Current}: {Monitor.IsEntered(o)}");
}
Console.WriteLine($"Done: {Monitor.IsEntered(o)}");
}
Console.WriteLine($"After: {Monitor.IsEntered(o)}");
static IEnumerable<int> GetValues(object obj)
{
lock (obj)
{
for (int i = 0; i < 3; i++)
{
yield return i;
if (i == 1)
{
yield break;
}
}
}
}
""";

var expectedOutput = """
Before: False
Inside: False
0: True
1: True
Done: False
After: False
""";

CompileAndVerify(source, options: TestOptions.ReleaseExe.WithWarningLevel(8),
expectedOutput: expectedOutput).VerifyDiagnostics();

var expectedDiagnostics = new[]
{
// (24,13): warning CS9230: 'yield return' should not be used in the body of a lock statement
// yield return i;
Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(24, 13)
};

CompileAndVerify(source, options: TestOptions.ReleaseExe.WithWarningLevel(9),
expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics);

CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics);
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72443")]
public void YieldInLock_Nested()
{
var source = """
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
yield return 1;
lock (this)
{
yield return 2;
local();
IEnumerable<int> local()
{
yield return 3;
lock (this)
{
yield return 4;
yield break;
}
}
yield break;
}
}
}
""";

CreateCompilation(source).VerifyDiagnostics(
// (10,13): warning CS9230: 'yield return' should not be used in the body of a lock statement
// yield return 2;
Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(10, 13),
// (20,21): warning CS9230: 'yield return' should not be used in the body of a lock statement
// yield return 4;
Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(20, 21));
}

[WorkItem(546081, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546081")]
[Fact]
public void IteratorBlockWithUnreachableCode()
Expand Down

0 comments on commit c74941c

Please sign in to comment.