"Access to displosed closure" false positive with local function + yield return inside using
Completed
The following code returns a false positive, which caused my boss to yell at me for writing sloppy code (and I didn't even write this, it's from Stack Overflow)..
public static class BatchLinq
{
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int size)
{
if (size <= 0)
throw new ArgumentOutOfRangeException("size", "Must be greater than zero.");
using (var enumerator = source.GetEnumerator())
while (enumerator.MoveNext())
{
int i = 0;
// Batch is a local function closing over `i` and `enumerator` that
// executes the inner batch enumeration
IEnumerable<T> Batch()
{
do yield return enumerator.Current; // Access to disposed closure
while (++i < size && enumerator.MoveNext()); // Access to disposed closure
}
yield return Batch();
while (++i < size && enumerator.MoveNext()); // discard skipped items
}
}
}
Related: https://resharper-support.jetbrains.com/hc/en-us/community/posts/206661285-Still-confused-about-Access-to-modified-closure-?input_string=%22Access%20to%20displosed%20closur - which discusses that JetBrains added three annotations to help with this. HOWEVER, this is buried and not searchable via Google when I type "Access to disposed closure" in the search engine, I see nothing about these attributes. Likewise, the ToolTip in Visual Studio 2017 says nothing about these annotaitons, either.
Past instances of false positives:
Please sign in to leave a comment.
Here is a screenshot demonstrating the issue. Note: I can only ToolTip one of the two ToolTips in a single screenshot, but both blue underlined "enumerator" variables in the screenshot indicate the same ReSharper warning. The "i" variable separately warns "Access to modified closure".
I believe this code is correct. Moreover, I do not see how [InstantHandle] can be applied here, since the closure is actually a local function, and as best as I understand the C# language, you cannot apply an InstantHandle to a local function. Moreover, since the C# language specifies that local functions may only be called from within their scope, I do not see a way for the closure created to be accessed from a disposed scope.
Ergo, I believe this is a test case JetBrains ReSharper has not accounted for: local functions with free variables and a yield statement generate false positives inside a using. Note, if you play with my sample, and remove the yield statement (effectively writing non-sensical code for the purpose of Batching, but just to demonstrate the problem with ReSharper code analysis engine), the error goes away despite enumerator.MoveNext staying as a free variable reference inside the local function.
Variation 1: yield return new T() - enumerator.MoveNext() is underlined in blue
Variation 2: remove yield, just return List<T> -- no errors, despite i and enumerator still being free variables
Hello!
Corresponding issue is reported here - https://youtrack.jetbrains.com/issue/RSRP-473776.
Thank you.