-
Notifications
You must be signed in to change notification settings - Fork 466
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
False positive in CA1307 for string.IndexOf(char) #2581
Comments
The same is true for |
The premise of the rule is to pass in an explicit value for |
That may be true, but it is not what I said. The diagnostic reports "The behavior of 'string.IndexOf(char)' could vary based on the current user's locale settings." That is simply not true. Reporting incorrect information in a diagnostic message seems undesirable. |
From @mavasani in dotnet/runtime#30740 (comment):
|
Here's my proposal for how to modify the rule to increase the signal to noise ratio. For the methods
For the methods
For the method
For the method
No method on The intent of this proposal is to identify places in the |
@GrabYourPitchforks I like your proposal a lot. Seems a lot better than the current behavior. I just want to point out that I think that |
Ho @KrisVandermotten, thanks for the feedback! In my proposal I had suggested not triggering on |
That makes a lot of sense. Thanks for explaining. |
I was going to suggest adding a separate CA number that warns when not being explicit even for String methods where the default is ordinal, but I'd even be turning that off if I wasn't multitargeting. I expected the analyzer to help me navigate which methods have which default, by not warning on the ones that default to ordinal. |
That's an interesting idea, but I don't know if we would turn such an analyzer on by default. Experience has told us that the reason people trip up is that they expect the default behavior to be an exact match, since that's what most other languages also do by default. |
It seems reasonable to switch the rule defaults as per #2581 (comment), and then have a user option to be able to switch to the current behavior (always requiring an explicit StringComparison argument where an overload that takes one is available). |
Also tagging @Evangelink in case he is interested in picking this one... |
@GrabYourPitchforks Sorry about the confusing wording. What I meant was that I'd prefer to be explicit for non-ordinal comparisons and to be implicit where possible for ordinal comparisons, since ordinal is what everyone expects the default to be. |
@Evangelink Let me know if you'd like to pick this up, otherwise I can take it up early next week. |
Is there any progress on resolving this bug? It' been well over a year now since it was reported. It would be great to see it fixed, if possible no later than in the .NET 5 wave. Again, this is a bug report, not a feature request. A diagnostic message that claims that "The behavior of 'string.IndexOf(char)' could vary based on the current user's locale settings." is simply not correct. Correct behavior has been described six months ago. |
Would we then also need a new rule where the previous fixes for CA1307 are marked as unnecessary or more explicitly: any place for StringComparison.Ordinal is passed in when that is the default for the method. |
Fixes dotnet#2581 When we know that a comparison is between a string type receiver and a non-string type parameter, do not report CA1307
@manfred-brands Feel free to file a separate feature request for it. |
@mavasani, you said
Unless I'm mistaken, that is not what happened in #4035. Did you change your mind, and if so, why? Just to be clear, if I understand #4035 correctly, the analyzer will still report that "The behavior of 'string.Contains(string)' could vary based on the current user's locale settings." This is not true, and producing such a message is a bug. @GrabYourPitchforks provided a good description of what the behavior of the rule should be. |
@KrisVandermotten The rule is now much more conservative - for any invocations to string APIs, other then the known signatures (Compare and CompareTo), analyzer bails out if the target overload's first parameter type is not string type or has no parameters. It should handle all false positives - can you point out any specific CA1307 false positives after the fix? |
|
I don't believe that is a false positive or noise - I agree that string methods that do not take a string parameter the rule was generating some noise, but for places where we are doing string-to-string checks or comparisons, we absolutely want to recommend use of StringComparison. |
I am actually reading through https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings#specifying-string-comparisons-explicitly and it seems that section explicitly suggested sticking to the prior implementation of CA1307, and never rely on the default StringComparison of any string API. It confused me to find out why The changes recommended on this issue seem to indicate the analyzer mostly hardcodes the methods where culture dependent StringComparison is the default (basically the list here: https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings#string-comparisons-that-use-the-current-culture), but the doc then states: In any case, we recommend that you call an overload that has a StringComparison parameter to make the intent of the method call clear. So, my core question is:
|
The downside of relying on a default instead of explicitly specifying this is that there is no consistent default, it is different even for methods in the same class. As it says in your referenced article: It is difficult to remember which method uses which default value, and easy to confuse the overloads. If for whatever reason the default gets changed in a future version it would break that code that doesn't specify the default, but not the code that has explicitly stated the comparison making the latter future proof. My vote would be for keeping CA1307 as it was and fix the code fix for CA2249 (#3839) |
My main problem with the current rule is not what it recommends. I see value in a rule that helps people write readable code. My main problem with this rule is that it provides incorrect information in the diagnostic message. I do think that reporting "The behavior of 'string.Contains(string)' could vary based on the current user's locale settings." is a bug, but it can be fixed in two different ways:
I'm fine with the second option: just have a message that says that it is better for the readability of the code to be explicit about the comparison being used. Just to be clear: the first option is what I would prefer. Put differently: we have disabled CA1307 in our entire codebase. If it would be changed as proposed by @GrabYourPitchforks, we would reenable it, because then it becomes a rule that helps prevent bugs. It's about correctness then, rather then about maintainability. If only the message is changed, I'm not so sure. |
Fixes dotnet#2581, again! 1. CA1310: Correctness rule that only flags string compare methods that are known to use culture specific string comparison by default 2. CA1307: Maintainability/Readability rule that flags the remainder methods that have an overload with an additional StringComparison parameter at the end. This rule does not care about the defaault string comparison used by the API.
https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1310 is very pleasant to use. Thanks very much, everyone! |
Analyzer package
Microsoft.CodeAnalysis.FxCopAnalyzers
Package Version
v2.9.3
Diagnostic ID
CA1307: Specify StringComparison
Repro steps
Compile the following code against .NET Core 2.2:
Expected behavior
No warning.
Actual behavior
Warning: The behavior of 'string.IndexOf(char)' could vary based on the current user's locale settings. Replace this call in 'C.M(string)' with a call to 'string.IndexOf(char, System.StringComparison)'.
The premisse of the diagnostic, that string.indexOf(char) could vary is incorrect. The method documentation clearly states:
Note also that replacing the
s.IndexOf('?')
bys.IndexOf('?', StringComparison.Ordinal)
is undesirable, as the method is less efficient.The text was updated successfully, but these errors were encountered: