-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[clang-tidy] support string::contains #110351
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
base: main
Are you sure you want to change the base?
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
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.
IMO no need to update release notes:
Improved
readability-container-contains
check to let it work on any class that has a contains method.
But I think an example should be added to the check documentation.
@@ -32,7 +33,8 @@ void ContainerContainsCheck::registerMatchers(MatchFinder *Finder) { | |||
|
|||
const auto FindCall = | |||
cxxMemberCallExpr( | |||
argumentCountIs(1), | |||
anyOf(argumentCountIs(1), | |||
allOf(argumentCountIs(2), hasArgument(1, cxxDefaultArgExpr()))), |
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.
Maybe a comment here saying std::string
and std::string_view
take an optional pos
argument on where to start the search. Also match ignoringParenImpCasts(integerLiteral(0))
?
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 tried to match the two arguments but I fail to remove the second argument in the Fixit hint. Could you suggest how to get the location after the first argument. I tried binding the first argument (e.g. "test"), but the source range seems to be the first character (") instead of the whole argument ("test").
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.
Considering str.find('a') != std::string::npos
. Instead of deleting stuff from )
to npos
, you could replace everything from after 'a'
to the end of the comparison with )
, that should work. I wrote something like this here:
llvm-project/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
Lines 159 to 165 in e8f01b0
// Remove possible arguments after search expression and ' [!=]= 0' suffix. | |
Diagnostic << FixItHint::CreateReplacement( | |
CharSourceRange::getTokenRange( | |
Lexer::getLocForEndOfToken(SearchExpr->getEndLoc(), 0, | |
*Result.SourceManager, getLangOpts()), | |
ComparisonExpr->getEndLoc()), | |
")"); |
clang-tools-extra/clang-tidy/readability/ContainerContainsCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/clang-tidy/readability/ContainerContainsCheck.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/test/clang-tidy/checkers/readability/container-contains.cpp
Outdated
Show resolved
Hide resolved
clang-tools-extra/test/clang-tidy/checkers/readability/container-contains.cpp
Show resolved
Hide resolved
bool contains(const C *s) const; | ||
bool contains(C s) const; |
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.
bool contains(const C *s) const; | |
bool contains(C s) const; | |
bool contains(const C *s) const; | |
bool contains(C s) const; | |
bool contains(basic_string_view<C, T> sv) const; |
bool contains(const C *s) const; | ||
bool contains(C s) const; |
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.
bool contains(const C *s) const; | |
bool contains(C s) const; | |
bool contains(const C *s) const; | |
bool contains(C s) const; | |
bool contains(basic_string_view sv) const; |
const auto FindCall = | ||
cxxMemberCallExpr( | ||
argumentCountIs(1), | ||
anyOf(argumentCountIs(1), | ||
allOf(argumentCountIs(2), // string::find takes two arguments |
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.
allOf(argumentCountIs(2), // string::find takes two arguments | |
// `find` for string-like classes often has a second parameter, | |
// indicating where to start the search. We match if it's | |
// the default zero or explicitly equal to zero. | |
allOf(argumentCountIs(2), |
I think a little more detail is good here.
@@ -50,12 +50,16 @@ struct basic_string { | |||
size_type find(const _Type& str, size_type pos = 0) const; | |||
size_type find(const C* s, size_type pos = 0) const; | |||
size_type find(const C* s, size_type pos, size_type n) const; | |||
size_type find(C ch, size_type pos = 0) const; |
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.
size_type find(C ch, size_type pos = 0) const; | |
size_type find(C ch, size_type pos = 0) const; | |
template<class StringViewLike> | |
size_type find(const StringViewLike& t, size_type pos = 0) const; |
Let's cover them all if possible.
This one might cause issues, and is probably not all that common, but let's see.
@@ -453,3 +458,29 @@ void testOperandPermutations(std::map<int, int>& Map) { | |||
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] | |||
// CHECK-FIXES: if (!Map.contains(0)) {}; | |||
} | |||
|
|||
void testStringNops(std::string Str, std::string SubStr, std::string_view StrView) { |
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.
void testStringNops(std::string Str, std::string SubStr, std::string_view StrView) { | |
void testStringNpos(std::string Str, std::string SubStr, std::string_view StrView) { |
Just a typo.
Thanks! |
FYI I'm going to merge #110386 now which will cause conflicts ( |
Starting from c++23, we can replace
std::string::find() == std::string::npos
withstd::string.contains()
. #109327Currently, this is WIP because there are two limitations:
const std::string&
which does not matchstd::string::contains(basic_string_view)
type.std::string::find("test", 0)
is incorrect.