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!
