Skip to content

Report diagnostics from TryFindDisposePatternMethod when binding foreach loop#75422

Merged
jcouv merged 8 commits into
dotnet:mainfrom
jcouv:obsolete-dispose
Oct 16, 2024
Merged

Report diagnostics from TryFindDisposePatternMethod when binding foreach loop#75422
jcouv merged 8 commits into
dotnet:mainfrom
jcouv:obsolete-dispose

Conversation

@jcouv

@jcouv jcouv commented Oct 7, 2024

Copy link
Copy Markdown
Member

Fixes #30257
Fixes #73934

@jcouv jcouv self-assigned this Oct 7, 2024
@ghost ghost 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
// 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

@jjonescz jjonescz Oct 9, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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()

@jjonescz jjonescz Oct 9, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
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`

@AlekseyTs AlekseyTs Oct 9, 2024

Copy link
Copy Markdown
Contributor

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

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

diagnostics.AddRangeAndFree(patternDiagnostics);

@AlekseyTs AlekseyTs Oct 9, 2024

Copy link
Copy Markdown
Contributor

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));

@AlekseyTs AlekseyTs Oct 9, 2024

Copy link
Copy Markdown
Contributor

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

// 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));

@AlekseyTs AlekseyTs Oct 9, 2024

Copy link
Copy Markdown
Contributor

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));

@AlekseyTs AlekseyTs Oct 9, 2024

Copy link
Copy Markdown
Contributor

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.

@AlekseyTs AlekseyTs Oct 9, 2024

Copy link
Copy Markdown
Contributor

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];

@AlekseyTs AlekseyTs Oct 11, 2024

Copy link
Copy Markdown
Contributor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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));

@AlekseyTs AlekseyTs Oct 11, 2024

Copy link
Copy Markdown
Contributor

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
Copy Markdown
Contributor

Done with review pass (commit 4)

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

@AlekseyTs AlekseyTs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM (commit 8)

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