Report diagnostics from TryFindDisposePatternMethod when binding foreach loop#75422
Conversation
971b422 to
e2dac8f
Compare
TryFindDisposePatternMethod when binding foreach loop
e2dac8f to
44c38f4
Compare
44c38f4 to
9bab481
Compare
| // await foreach (var i in new C()) | ||
| Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.Current").WithLocation(7, 15) | ||
| ); | ||
| // Note: Obsolete on DisposeAsync is not reported since always called through IAsyncDisposable interface |
There was a problem hiding this comment.
So the comment was incorrect - we do not go through IAsyncDisposable interface? #Resolved
There was a problem hiding this comment.
Yes, this was changed in PR but this comment in test was missed
| } | ||
|
|
||
| [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/30257")] | ||
| public void TestWithPatternAndObsolete_WithoutDisposableInterface() |
There was a problem hiding this comment.
Consider testing with explicit interface implementation of the DisposeAsync method. #Resolved
There was a problem hiding this comment.
Did you add this test? I couldn't find it.
| @@ -0,0 +1,46 @@ | |||
| # This document lists known breaking changes in Roslyn after .NET 9 all the way to .NET 10. | |||
|
|
|||
| ## Diagnostics now reported for improper use of pattern-based disposal method in `foreach` | |||
| Debug.Assert(patternDisposeMethod.ParameterRefKinds.IsDefaultOrEmpty || | ||
| patternDisposeMethod.ParameterRefKinds.All(static refKind => refKind is RefKind.None or RefKind.In or RefKind.RefReadOnlyParameter)); | ||
|
|
||
| diagnostics.AddRangeAndFree(patternDiagnostics); |
| Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.MoveNextAsync()").WithLocation(7, 15), | ||
| // (7,15): warning CS0612: 'C.AsyncEnumerator.Current' is obsolete | ||
| // await foreach (var i in new C()) | ||
| Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.Current").WithLocation(7, 15)); |
| // await foreach (var i in new C()) | ||
| Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.Enumerator.Current").WithLocation(8, 15) | ||
| ); | ||
| Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.Enumerator.Current").WithLocation(8, 15)); |
| // [UnmanagedCallersOnly] | ||
| Diagnostic(ErrorCode.ERR_UnmanagedCallersOnlyRequiresStatic, "UnmanagedCallersOnly").WithLocation(14, 6) | ||
| ); | ||
| Diagnostic(ErrorCode.ERR_UnmanagedCallersOnlyRequiresStatic, "UnmanagedCallersOnly").WithLocation(14, 6)); |
| // 0.cs(7,9): error CS8901: 'SEnumerator.Dispose()' is attributed with 'UnmanagedCallersOnly' and cannot be called directly. Obtain a function pointer to this method. | ||
| // foreach (var i in s) {} | ||
| Diagnostic(ErrorCode.ERR_UnmanagedCallersOnlyMethodsCannotBeCalledDirectly, "foreach (var i in s) {}").WithArguments("SEnumerator.Dispose()").WithLocation(7, 9), | ||
| // 0.cs(14,6): error CS8896: 'UnmanagedCallersOnly' can only be applied to ordinary static non-abstract, non-virtual methods or static local functions. |
| { | ||
| public static void M2(S s) | ||
| { | ||
| int[] a = [42, ..s]; |
There was a problem hiding this comment.
I didn't follow. How could that involve binding the Dispose method?
There was a problem hiding this comment.
I didn't follow. How could that involve binding the
Disposemethod?
It looks like TryFindDisposePatternMethod might be reachable from TryGetCollectionIterationType.
There was a problem hiding this comment.
Added a test. The behavior seems fine (because TryGetCollectionIterationType discards diagnostics)
| Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.MoveNextAsync()").WithLocation(7, 15), | ||
| // (7,15): warning CS0612: 'C.AsyncEnumerator.Current' is obsolete | ||
| // await foreach (var i in new C()) | ||
| Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.Current").WithLocation(7, 15)); |
|
Done with review pass (commit 4) |
Fixes #30257
Fixes #73934