-
Notifications
You must be signed in to change notification settings - Fork 470
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
CA1853: Fix incorrect code fixes #6770
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #6770 +/- ##
========================================
Coverage 96.33% 96.34%
========================================
Files 1386 1386
Lines 325659 325886 +227
Branches 10718 10715 -3
========================================
+ Hits 313732 313969 +237
+ Misses 9215 9210 -5
+ Partials 2712 2707 -5 |
return true; | ||
if (conditionalSyntax is IfStatementSyntax ifStatementSyntax) | ||
{ | ||
return ifStatementSyntax.Condition.RawKind != (int)SyntaxKind.LogicalNotExpression && |
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.
Consider adding a comment why we are skipping the case where the condition is a logical not expression.
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.
Also added one to the VB fixer.
@@ -16,11 +17,11 @@ public sealed class CSharpDoNotGuardDictionaryRemoveByContainsKeyFixer : DoNotGu | |||
{ | |||
protected override bool SyntaxSupportedByFixer(SyntaxNode conditionalSyntax) | |||
{ | |||
if (conditionalSyntax is ConditionalExpressionSyntax conditionalExpressionSyntax) |
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.
I looked at the code for the analyzer and it seems the first additional location for the diagnostic is the conditional operation syntax, which can either be an if statement syntax OR a conditional expression syntax (ternary operator):
Line 81 in adcbeee
additionalLocation.Add(conditionalOperation.Syntax.GetLocation()); |
I think your change here to exclude ConditionalExpressionSyntax
has identified a test hole. Please add a test for ternary operators to confirm the old behavior, the new behavior and which one is more preferable.
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 analyzer never triggered for conditional expression syntax (even though the C# fixer had that case in mind).
This is due to the following switch always matching the default case for ternary operators:
Lines 83 to 114 in 20ba369
switch (conditionalOperation.WhenTrue.Children.First()) | |
{ | |
case IInvocationOperation childInvocationOperation: | |
if ((childInvocationOperation.TargetMethod.OriginalDefinition.Equals(remove1Param, SymbolEqualityComparer.Default) || | |
childInvocationOperation.TargetMethod.OriginalDefinition.Equals(remove2Param, SymbolEqualityComparer.Default)) && | |
AreInvocationsOnSameInstance(childInvocationOperation, invocationOperation)) | |
{ | |
additionalLocation.Add(childInvocationOperation.Syntax.Parent!.GetLocation()); | |
context.ReportDiagnostic(invocationOperation.CreateDiagnostic(Rule, additionalLocations: additionalLocation.ToImmutable(), null)); | |
} | |
break; | |
case IExpressionStatementOperation childStatementOperation: | |
/* | |
* If the if statement contains a block, only proceed if one of the methods calls Remove. | |
* However, a fixer is only offered if there is a single method in the block. | |
*/ | |
var nestedInvocationOperation = childStatementOperation.Children.OfType<IInvocationOperation>() | |
.FirstOrDefault(op => op.TargetMethod.OriginalDefinition.Equals(remove1Param, SymbolEqualityComparer.Default) || | |
op.TargetMethod.OriginalDefinition.Equals(remove2Param, SymbolEqualityComparer.Default)); | |
if (nestedInvocationOperation != null && AreInvocationsOnSameInstance(nestedInvocationOperation, invocationOperation)) | |
{ | |
additionalLocation.Add(nestedInvocationOperation.Syntax.Parent!.GetLocation()); | |
context.ReportDiagnostic(invocationOperation.CreateDiagnostic(Rule, additionalLocations: additionalLocation.ToImmutable(), null)); | |
} | |
break; | |
default: | |
break; | |
} |
I am not sure how a conditional expression syntax would look like that we want to fix.
Something like this comes to my mind:
bool removed = MyDictionary.ContainsKey("Key") ? MyDictionary.Remove("Key") : false;
But the above already uses the return value of Dictionary.Remove
, so I think it is not likely someone would write it as a ternary expression.
I will keep the occurrence of ConditionalExpressionSyntax
removed in the C# fixer (as it was not supported anyway) and add a test as you suggested.
CA1853: Fix incorrect code fixes
This PR will fix missing and incorrectly applied code fixes and adds additional tests to cover these cases.
The following has been changed:
dictionary.ContainsKey
calls now only report a diagnostic (added a wrong fix before). SeeNegatedCondition_ReportsDiagnostic_CS
andNegatedCondition_ReportsDiagnostic_VB
.AdditionalStatements_ReportsDiagnostic_CS
andAdditionalStatements_ReportsDiagnostic_VB
.HasElseStatement_OffersFixer_VB
.TriviaIsPreserved_VB
andRemoveIsTheOnlyStatementInABlock_OffersFixer_VB
.ConditionalExpressionSyntax
check for CS fixer as conditional expressions are not reported by the analyzer.Fixes #6274