-
Notifications
You must be signed in to change notification settings - Fork 458
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
Fix CA2016 when used on instance method with generic types #4974
Conversation
Codecov Report
@@ Coverage Diff @@
## main #4974 +/- ##
==========================================
+ Coverage 95.52% 95.58% +0.05%
==========================================
Files 1200 1190 -10
Lines 274867 273033 -1834
Branches 16622 16486 -136
==========================================
- Hits 262571 260974 -1597
+ Misses 10112 9921 -191
+ Partials 2184 2138 -46 |
case IConditionalAccessInstanceOperation: | ||
newInstance = GetConditionalOperationInvocationExpression(invocation.Syntax); | ||
break; | ||
default: | ||
if (invocation.Instance.IsImplicit) | ||
{ | ||
newInstance = invocation.GetInstanceSyntax()!; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adds a test case for a static generic method, which was green before applying the fix, to guard against regressions in that behavior
The CI is still passing because apparently I forgot to add unit tests for all three cases you removed.
- It seems we don't have a conditional operation case in the unit tests. Can you please add one?
- I'm trying to remember what
IsImplicit
is referring to. It's either:- An invocation of a method from an explicit interface implementation, or
- An invocation of a method passed as a callback to another method (a
Func
or anAction
).
Independently if it's one or the other, we don't have unit tests for any of them. Would you mind adding one to make sure that functionality is not regressed?
Thanks for adding a method for the static case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the IConditionalAccessInstanceOperation Interface docs it sounds like you're referring to a call like someExpression?.Method()
. Isn't that covered by CS_Diagnostic_DereferencePossibleNullReference?
IsImplicit
seems to refer to the "this" object passed to the method, either the instance or null if it's a static method. In any case, when I tried adding this block to the fixer:
if (invocation.Instance != null && invocation.Instance.IsImplicit)
{
throw new Exception("Implicit");
}
…the result was that 73 tests failed. First one was CS_Diagnostic_ActionDelegateAwait where MethodAsync()
is being called without this.
, which seems to track. So I think it's safe to say that test case is covered.
While the removal of that code looks scary, I think it makes sense philisophically. The fixer is only trying to adjust what's going on in the ArgumentList. So trying to rebuild the part of the invocation "outside" the parens from scratch based on a number of conditions doesn't really make sense when expression
is already going to contain whatever that outside part was originally highlighted by the red squiggly.
To illustrate that point further, I added 2 additional tests CS_Diagnostic_NullCoalescedDelegates
and CS_Diagnostic_NullCoalescedDelegatesWithInvoke
, both of which have 2 delegates and call either (f1 ?? f2)()
or (f1 ?? f2).Invoke()
. The current version on main
will rewrite (f1 ?? f2)()
to (f1 ?? f2).Invoke(c)
, adding the explicit Invoke
where none was there before. I assume it's preferable for a fixer to do the bare minimum to implement the fix without changing any other code, and this PR respects whether or not the explicit Invoke
is used in the expression.
@@ -2229,6 +2229,78 @@ void LocalMethod() | |||
return CS8VerifyCodeFixAsync(originalCode, fixedCode); | |||
} | |||
|
|||
[Fact] | |||
[WorkItem(4870, "https://github.com/dotnet/roslyn-analyzers/issues/4870")] | |||
public Task CS_Diagnostic_GenericTypeParamOnInstanceMethod() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please also add VB unit tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added VB versions of the test. Dislcaimer: not a VB developer. I leaned on the online Telerik code converter and a bunch of guess & check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We all use Telerik 😄 .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the change, @DavidBoike . I left a couple of requests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@carlossanlop ready for another review.
@@ -2229,6 +2229,78 @@ void LocalMethod() | |||
return CS8VerifyCodeFixAsync(originalCode, fixedCode); | |||
} | |||
|
|||
[Fact] | |||
[WorkItem(4870, "https://github.com/dotnet/roslyn-analyzers/issues/4870")] | |||
public Task CS_Diagnostic_GenericTypeParamOnInstanceMethod() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added VB versions of the test. Dislcaimer: not a VB developer. I leaned on the online Telerik code converter and a bunch of guess & check.
case IConditionalAccessInstanceOperation: | ||
newInstance = GetConditionalOperationInvocationExpression(invocation.Syntax); | ||
break; | ||
default: | ||
if (invocation.Instance.IsImplicit) | ||
{ | ||
newInstance = invocation.GetInstanceSyntax()!; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the IConditionalAccessInstanceOperation Interface docs it sounds like you're referring to a call like someExpression?.Method()
. Isn't that covered by CS_Diagnostic_DereferencePossibleNullReference?
IsImplicit
seems to refer to the "this" object passed to the method, either the instance or null if it's a static method. In any case, when I tried adding this block to the fixer:
if (invocation.Instance != null && invocation.Instance.IsImplicit)
{
throw new Exception("Implicit");
}
…the result was that 73 tests failed. First one was CS_Diagnostic_ActionDelegateAwait where MethodAsync()
is being called without this.
, which seems to track. So I think it's safe to say that test case is covered.
While the removal of that code looks scary, I think it makes sense philisophically. The fixer is only trying to adjust what's going on in the ArgumentList. So trying to rebuild the part of the invocation "outside" the parens from scratch based on a number of conditions doesn't really make sense when expression
is already going to contain whatever that outside part was originally highlighted by the red squiggly.
To illustrate that point further, I added 2 additional tests CS_Diagnostic_NullCoalescedDelegates
and CS_Diagnostic_NullCoalescedDelegatesWithInvoke
, both of which have 2 delegates and call either (f1 ?? f2)()
or (f1 ?? f2).Invoke()
. The current version on main
will rewrite (f1 ?? f2)()
to (f1 ?? f2).Invoke(c)
, adding the explicit Invoke
where none was there before. I assume it's preferable for a fixer to do the bare minimum to implement the fix without changing any other code, and this PR respects whether or not the explicit Invoke
is used in the expression.
Anything else I can do here? |
@carlossanlop Can you please help review the PR again? We already have multiple users reporting this bug. |
I rebased the PR to make it easier to review. |
Checking in again. What can I do here? |
@mavasani @carlossanlop @buyaa-n Please let me know how I can help drive this forward. I'm willing to add more test cases or get on a call or whatever, just let me know. |
@mavasani @carlossanlop is there anything that I, @DavidBoike, or anyone else can do to help move this forward? It would be a shame to abandon it after the non-trivial effort that's already been made by @DavidBoike and @carlossanlop. And as mentioned above, multiple users have reported this problem. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fix looks good to me, I will merge it on Monday if @carlossanlop will not add any other comments/concerns
CC @mavasani
@carlossanlop won't be available to review on Monday. LGTM. |
🎉 which SDK version is this scheduled for? |
This will be included in .NET 6 Preview 7. |
Fixes #4870