Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report diagnostics from TryFindDisposePatternMethod when binding foreach loop #75422

Merged
merged 8 commits into from
Oct 16, 2024

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Oct 7, 2024

Fixes #30257
Fixes #73934

@jcouv jcouv self-assigned this Oct 7, 2024
@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged Issues and PRs which have not yet been triaged by a lead label Oct 7, 2024
@jcouv jcouv force-pushed the obsolete-dispose branch 2 times, most recently from 971b422 to e2dac8f Compare October 8, 2024 17:00
@jcouv jcouv changed the title Report obsolete DisposeAsync method in await foreach Report diagnostics from TryFindDisposePatternMethod when binding foreach loop Oct 8, 2024
@jcouv jcouv force-pushed the obsolete-dispose branch from e2dac8f to 44c38f4 Compare October 8, 2024 17:06
@jcouv jcouv force-pushed the obsolete-dispose branch from 44c38f4 to 9bab481 Compare October 8, 2024 17:08
@jcouv jcouv marked this pull request as ready for review October 8, 2024 17:08
@jcouv jcouv requested a review from a team as a code owner October 8, 2024 17:08
@@ -4860,9 +4863,52 @@ public sealed class AsyncEnumerator : System.IAsyncDisposable
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)
);
// Note: Obsolete on DisposeAsync is not reported since always called through IAsyncDisposable interface
Copy link
Member

@jjonescz jjonescz Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the comment was incorrect - we do not go through IAsyncDisposable interface? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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()
Copy link
Member

@jjonescz jjonescz Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider testing with explicit interface implementation of the DisposeAsync method. #Resolved

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you add this test? I couldn't find it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake. Added now :-)

@@ -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`
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for improper use

I think we should be specific here. If we are talking about Obsolete diagnostics, we should say that. In general, I wouldn't call a usage of an obsolete API as an improper use. #Closed

if (patternDisposeMethod is object)
{
Debug.Assert(!patternDisposeMethod.IsExtensionMethod);
Debug.Assert(patternDisposeMethod.ParameterRefKinds.IsDefaultOrEmpty ||
patternDisposeMethod.ParameterRefKinds.All(static refKind => refKind is RefKind.None or RefKind.In or RefKind.RefReadOnlyParameter));

diagnostics.AddRangeAndFree(patternDiagnostics);
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

diagnostics.AddRangeAndFree(patternDiagnostics);

I am curious what effect this is going to have on collection expressions and params collections. Is this diagnostics going to be meaningful for them? Consider adding tests. #Closed

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));
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.AsyncEnumerator.Current").WithLocation(7, 15));

Consider reverting changes on this line and reducing unnecessary diff. #Closed

@@ -8503,8 +8552,7 @@ public static class Extensions
Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "foreach").WithArguments("C.Enumerator.MoveNextAsync()").WithLocation(8, 15),
// (8,15): warning CS0612: 'C.Enumerator.Current' is obsolete
// 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));
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

);

Consider reverting changes on this line and reducing unnecessary diff. #Closed

// [UnmanagedCallersOnly]
Diagnostic(ErrorCode.ERR_UnmanagedCallersOnlyRequiresStatic, "UnmanagedCallersOnly").WithLocation(14, 6)
);
Diagnostic(ErrorCode.ERR_UnmanagedCallersOnlyRequiresStatic, "UnmanagedCallersOnly").WithLocation(14, 6));
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

);

Consider reverting changes on this line and reducing unnecessary diff. #Closed

// 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.
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.cs

Consider reverting changes on this line and reducing unnecessary diff. #Closed

{
public static void M2(S s)
{
int[] a = [42, ..s];
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

..s

This is an interesting scenario, but it is not quite the scenario I had in mind. I was referring to a check for a creatable collection, which involves determination of an element type (foreach element type). #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't follow. How could that involve binding the Dispose method?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't follow. How could that involve binding the Dispose method?

It looks like TryFindDisposePatternMethod might be reachable from TryGetCollectionIterationType.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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));
Copy link
Contributor

@AlekseyTs AlekseyTs Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

);

Consider reverting changes on this line and reducing unnecessary diff. #Closed

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 4)

@jcouv jcouv requested a review from AlekseyTs October 15, 2024 21:17
Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (commit 8)

@jcouv jcouv merged commit f89ffba into dotnet:main Oct 16, 2024
24 checks passed
@jcouv jcouv deleted the obsolete-dispose branch October 16, 2024 16:55
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Oct 16, 2024
@akhera99 akhera99 modified the milestones: Next, 17.13 P1 Oct 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
4 participants