Clang-Tidy: Introducing modernize-use-starts-ends-with
C++20 introduced two new methods on std::string
and std::string_view
: starts_with
and ends_with
. These two
methods do exactly what their name implies: they check wether a string starts or ends with a given prefix or suffix.
Until now, many roundabount ways were used to do this operation:
// 1.
haystack.find("needle") == 0;
// 2.
haystack.rfind("needle") == 0;
// 3.
haystack.compare(0, strlen("needle"), "needle") == 0;
// 4.
strncmp(haystack.c_str(), "needle", strlen("needle")) == 0;
// 5.
haystack.compare(haystack.length() - needle.length(), needle.length(), needle) == 0;
// 6.
std::equal(needle.rbegin(), needle.rend(), haystack.rbegin());
// 7.
haystack.rfind(needle) == (haystack.size() - needle.size());
Cases 1 through 4 can be improved using starts_with
, cases 5 through 7 using ends_with
.
While some cases are just less readable ways of expressing the operation, some also introduce a performance issue: there is no need to search the whole string if we can find early that there is no match!
abseil-string-find-startswith
Clang-Tidy has a related check, which was written before the introduction of those functions:
abseil-string-find-startswith
.
This check replaces example cases 1 and 2 above with the library function absl::StartsWith
. It used to only work with
std::string
; I added support for std::string_view
.
Introducing modernize-use-starts-ends-with
🎉
I wrote a new check,
modernize-use-starts-ends-with
,
which has been abailable in Clang-Tidy as of version 18.1. It works on any object having the necessary starts_with
and
ends_with
methods, including std::string
and std::string_view
, but also custom string types such as
llvm::StringRef
or folly::StringPiece
. It currently covers cases 1 through 3, with improvements planned in the
future, and can be run as a codemod to fix any existing cases.
Update 2024-10-14: All cases but 4 and 6, which are less common, are covered as of Clang-Tidy 20!