Skip to content
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

[Analyzer] string.ToLower() == otherString.ToLower() #78607

Closed
stephentoub opened this issue Nov 20, 2022 · 14 comments · Fixed by dotnet/roslyn-analyzers#6720
Closed

[Analyzer] string.ToLower() == otherString.ToLower() #78607

stephentoub opened this issue Nov 20, 2022 · 14 comments · Fixed by dotnet/roslyn-analyzers#6720
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-System.Globalization code-analyzer Marks an issue that suggests a Roslyn analyzer code-fixer Marks an issue that suggests a Roslyn code fixer help wanted [up-for-grabs] Good issue for external contributors partner-impact This issue impacts a partner who needs to be kept updated
Milestone

Comments

@stephentoub
Copy link
Member

stephentoub commented Nov 20, 2022

The right way to compare two strings in a case-insensitive manner is via a StringComparer/Comparison that specifies case-insensitivity. But there's are many cases where code is using ToLower() on each string and then comparing those for equality, e.g.

We should write an analyzer that flags such uses and recommends fixing them to use Equals with the appropriate comparison.

This analyzer should cover ToUpper too even if the usage is low for that.

Such analyzers will help avoid the allocations caused by ToLower/ToUpper calls.

Performance rules Category
Severity = suggestion

@stephentoub stephentoub added code-analyzer Marks an issue that suggests a Roslyn analyzer code-fixer Marks an issue that suggests a Roslyn code fixer labels Nov 20, 2022
@stephentoub stephentoub added this to the 8.0.0 milestone Nov 20, 2022
@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@MichalPetryka
Copy link
Contributor

Should the invariant variants be also changed?

@stephentoub
Copy link
Member Author

The intent is all variations of this that make sense. That includes ToLower/UpperInvariant.

@ghost
Copy link

ghost commented Nov 20, 2022

Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.

Issue Details

The right way to compare two strings in a case-insensitive manner is via a StringComparer/Comparison that specifies case-insensitivity. But there's are many cases where code is using ToLower() on each string and then comparing those for equality, e.g.

We should write an analyzer that flags such uses and recommends fixing them to use Equals with the appropriate comparison.

Author: stephentoub
Assignees: -
Labels:

area-System.Runtime, code-analyzer, code-fixer

Milestone: 8.0.0

@stephentoub stephentoub added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Nov 21, 2022
@ghost
Copy link

ghost commented Nov 21, 2022

Tagging subscribers to this area: @dotnet/area-system-globalization
See info in area-owners.md if you want to be subscribed.

Issue Details

The right way to compare two strings in a case-insensitive manner is via a StringComparer/Comparison that specifies case-insensitivity. But there's are many cases where code is using ToLower() on each string and then comparing those for equality, e.g.

We should write an analyzer that flags such uses and recommends fixing them to use Equals with the appropriate comparison.

This analyzer should cover ToUpper too even if the usage is low for that.

Such analyzers will help avoid the allocations caused by ToLower/ToUpper calls.

Performance rules Category
Severity = suggestion

Author: stephentoub
Assignees: -
Labels:

api-suggestion, area-System.Globalization, code-analyzer, code-fixer

Milestone: 8.0.0

@tarekgh tarekgh added blocking Marks issues that we want to fast track in order to unblock other important work api-ready-for-review API is ready for review, it is NOT ready for implementation labels Nov 21, 2022
@tarekgh
Copy link
Member

tarekgh commented Nov 21, 2022

CC @Youssef1313

@bartonjs
Copy link
Member

We should identify any of the equality cases with a string-case transformation

  • a.ToLower() == b.ToLower()
  • a.ToLower() == b.ToLowerInvariant()
  • a.ToLower() == b
  • And all of the above in reverse order, !=, and .Equals; as well as the ToUpper versions.

And replace them with the equivalent call to .Equals(b, StringComparison.IgnoreCase)

This should be merged into the same diagnostic ID as #78606 (if possible).

@bartonjs bartonjs added api-approved API was approved in API review, it can be implemented and removed blocking Marks issues that we want to fast track in order to unblock other important work api-ready-for-review API is ready for review, it is NOT ready for implementation labels Nov 22, 2022
@MichalPetryka
Copy link
Contributor

a.ToLower() == b is not safe to replace since that'd be false when b contains any upper case chars.

@tarekgh
Copy link
Member

tarekgh commented Nov 22, 2022

a.ToLower() == b is not safe to replace since that'd be false when b contains any upper case chars.

I think it will be safe to do it if b is literal string.

@buyaa-n buyaa-n added help wanted [up-for-grabs] Good issue for external contributors and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation labels May 4, 2023
@jeffhandley jeffhandley added the partner-impact This issue impacts a partner who needs to be kept updated label May 17, 2023
@carlossanlop
Copy link
Member

I'll work on this one next. It is closely related to my other one that's almost done: #78606

@carlossanlop
Copy link
Member

@tarekgh -

For this analyzer, should I continue using the same rules I used in my previous PR?:

  • StringComparison.InvariantCultureIgnoreCase for ToLowerInvariant/ToUpperInvariant
  • StringComparison.CurrentCultureIgnoreCase for ToLower/ToUpper

I ask because Jeremy's approval comment mentioned a non-existent comparison:

And replace them with the equivalent call to .Equals(b, StringComparison.IgnoreCase)

But there's also OrdinalIgnoreCase, so I'm unsure.

@tarekgh
Copy link
Member

tarekgh commented Jun 23, 2023

You will use StringComparison.InvariantCultureIgnoreCase and StringComparison.CurrentCultureIgnoreCase as you indicated. ToUpper/ToLower is always linguistic operation. We don't provide any API does ToUpper/ToLower for ordinal cases.

@carlossanlop
Copy link
Member

I submitted a PR to fix this: dotnet/roslyn-analyzers#6720

@tarekgh question: If I have this comparison:

a.ToLower() == a.ToLowerInvariant()`

Am I right to assume that the substitution should be this?:

a.Equals(b, StringComparison.CurrentCultureIgnorecase)

My assumption is that CurrentCulture takes precedence over InvariantCulture. Is this correct?

@tarekgh
Copy link
Member

tarekgh commented Jun 29, 2023

@carlossanlop in such case we shouldn't provide a fix but only diagnostic telling this is can be optimized by using string comparison with ignore casing feature. We cannot know the intention of the caller if want to have the current culture or invariant casing at that time.

@ghost ghost locked as resolved and limited conversation to collaborators Aug 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Globalization code-analyzer Marks an issue that suggests a Roslyn analyzer code-fixer Marks an issue that suggests a Roslyn code fixer help wanted [up-for-grabs] Good issue for external contributors partner-impact This issue impacts a partner who needs to be kept updated
Projects
None yet
8 participants