-
Notifications
You must be signed in to change notification settings - Fork 229
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 S2219 FP: "Use the is operator" reports "unfixable" code #6675
Fix S2219 FP: "Use the is operator" reports "unfixable" code #6675
Conversation
9d626ae
to
f172b9b
Compare
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.
Let's try to do this on syntax level
analyzers/src/SonarAnalyzer.CSharp/Rules/GetTypeWithIsAssignableFrom.cs
Outdated
Show resolved
Hide resolved
analyzers/src/SonarAnalyzer.CSharp/Rules/GetTypeWithIsAssignableFrom.cs
Outdated
Show resolved
Hide resolved
_ = typeof(ISet<int>).IsInstanceOfType(obj); // Noncompliant, bounded generic type | ||
_ = typeof(ISet<>).IsInstanceOfType(obj); // Compliant, unbonded generic type | ||
_ = typeof(IDictionary<int, int>).IsInstanceOfType(obj); // Noncompliant, bounded generic type | ||
_ = typeof(IDictionary<,>).IsInstanceOfType(obj); // Compliant, unbonded generic type |
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.
These comments would be way more readable when aligned on the same tab ditance
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.
Same below
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 have tried to line those comments up, but I bumped into the following issue by the code fix test GetTypeWithIsAssignableFrom_CodeFix
: Expected ActualCodeWithReplacedComments().ToUnixLineEndings() to be X with a length of 5756 because VerifyWhileDocumentChanges updates the document until all issues are fixed, even if the fix itself creates a new issue again. Language: CSharp7, but Y has a length of 5819, differs near " " (index 3683)
, where the only differences are in whitespaces:
I think that the test just preserves whitespaces when replacing // Noncompliant
with // Fixed
on a per-line basis, so lines end up misaligned in GetTypeWithIsAssignableFrom.Fixed.cs
and GetTypeWithIsAssignableFrom.Fixed.Batch.cs
(because fixes are of different length) and comparisons are sensitive to the difference in the number of whitespaces.
So we basically:
- either have comments lined up in the main test-case file, and scrambled in
Fixed.cs
andFixed.Batch.cs
; - or have comments starting 1 chars from the
;
(end of instruction), on the three files.
While not optimal, I think option 2 is more consistent and makes Fixed.cs
and Fixed.Batch.cs
easier to edit.
If you still prefer option 1, I can make the change.
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.
Having the // Fixed
stuff misaligned is (not nice but) acceptable. We'll eventually improve the test framework to ignore the whitespace differences for these comments (for other comments, it might be significant)
So let's go for 1.
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.
Basically the reasoning is that now, it's not readable anywhere. After, it will be readable at least on the main source. While we don't care too much about the comments of the fixed part.
analyzers/tests/SonarAnalyzer.UnitTest/TestCases/GetTypeWithIsAssignableFrom.cs
Outdated
Show resolved
Hide resolved
analyzers/tests/SonarAnalyzer.UnitTest/TestCases/GetTypeWithIsAssignableFrom.cs
Outdated
Show resolved
Hide resolved
analyzers/tests/SonarAnalyzer.UnitTest/TestCases/GetTypeWithIsAssignableFrom.cs
Outdated
Show resolved
Hide resolved
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.
LGTM. There's whitespace and one more UT to be added before merging
@@ -136,6 +141,9 @@ private static void CheckForIsAssignableFrom(SonarSyntaxNodeReportingContext con | |||
} | |||
} | |||
|
|||
private static bool IsUnboundedGenericType(TypeOfExpressionSyntax typeOf) => | |||
typeOf.DescendantNodes().Any(x => x is OmittedTypeArgumentSyntax); |
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.
DescendantNodes()
is typically an expensive operation. Especially on a method level. Inside a typeof
, it's fine, as we're sure that it will not contain a large sub-tree. So the implementation is good here.
The question is then, what about nested generic types? Can you have IDictionary<string, ISet<>>
? Let's add UT
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.
Tests added.
I've found a property of GenericNameSyntax
called IsUnboundGenericName
:
public bool IsUnboundGenericName
{
get
{
return this.TypeArgumentList.Arguments.Any(SyntaxKind.OmittedTypeArgument);
}
}
The method above has a very similar implementation to the one we have drafted together. I used that method instead.
One additional note: the actual check is slightly more complex since a QualifiedNameSyntax
does not derive from GenericNameSyntax
, but contains it as Right
member for namespaced type:
Kudos, SonarCloud Quality Gate passed! |
Kudos, SonarCloud Quality Gate passed! |
Fixes #6616
Made into a draft because it should be merged after the release.Remark:
As stated in the reporting of #6616, conditionals like
typeof(ISet<>).IsInstanceOfType(obj)
are guaranteed to always returnfalse
for anyobj
.While this PR disables the rule (and related quick fix) in such scenarios, another approach could be to report that the check is always false.
This seems, however, a different rule, since it doesn't involve the
is
operator, and would not offer a quickfix.