diff --git a/clang-tools-extra/clang-tidy/abseil/StringFindStartswithCheck.cpp b/clang-tools-extra/clang-tidy/abseil/StringFindStartswithCheck.cpp index b36144d1912fc..221e924c10f62 100644 --- a/clang-tools-extra/clang-tidy/abseil/StringFindStartswithCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/StringFindStartswithCheck.cpp @@ -19,11 +19,14 @@ using namespace clang::ast_matchers; namespace clang::tidy::abseil { +const auto DefaultStringLikeClasses = + "::std::basic_string;::std::basic_string_view"; + StringFindStartswithCheck::StringFindStartswithCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), StringLikeClasses(utils::options::parseStringList( - Options.get("StringLikeClasses", "::std::basic_string"))), + Options.get("StringLikeClasses", DefaultStringLikeClasses))), IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", utils::IncludeSorter::IS_LLVM), areDiagsSelfContained()), diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index a24e3a735d2d2..caf4569670720 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -208,6 +208,10 @@ New check aliases Changes in existing checks ^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Improved :doc:`abseil-string-find-startswith + ` check to also consider + ``std::basic_string_view`` in addition to ``std::basic_string`` by default. + - Improved :doc:`bugprone-dangling-handle ` check to support functional casting during type conversions at variable initialization, now with improved diff --git a/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-startswith.rst b/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-startswith.rst index 8224c37a087b8..c82c38772a5c9 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-startswith.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/abseil/string-find-startswith.rst @@ -3,9 +3,10 @@ abseil-string-find-startswith ============================= -Checks whether a ``std::string::find()`` or ``std::string::rfind()`` result is -compared with 0, and suggests replacing with ``absl::StartsWith()``. This is -both a readability and performance issue. +Checks whether a ``std::string::find()`` or ``std::string::rfind()`` (and +corresponding ``std::string_view`` methods) result is compared with 0, and +suggests replacing with ``absl::StartsWith()``. This is both a readability and +performance issue. .. code-block:: c++ @@ -28,9 +29,9 @@ Options .. option:: StringLikeClasses - Semicolon-separated list of names of string-like classes. By default only - ``std::basic_string`` is considered. The list of methods to considered is - fixed. + Semicolon-separated list of names of string-like classes. By default both + ``std::basic_string`` and ``std::basic_string_view`` are considered. The list + of methods to be considered is fixed. .. option:: IncludeStyle diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string index 6f569655e6762..d0aac7b78ec93 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string @@ -43,6 +43,11 @@ struct basic_string { 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 rfind(const _Type& str, size_type pos = npos) const; + size_type rfind(const C* s, size_type pos, size_type count) const; + size_type rfind(const C* s, size_type pos = npos) const; + size_type rfind(C ch, size_type pos = npos) const; + _Type& insert(size_type pos, const _Type& str); _Type& insert(size_type pos, const C* s); _Type& insert(size_type pos, const C* s, size_type n); @@ -54,6 +59,8 @@ struct basic_string { _Type& operator+=(const C* s); _Type& operator=(const _Type& str); _Type& operator=(const C* s); + + static constexpr size_t npos = -1; }; typedef basic_string string; @@ -63,8 +70,23 @@ typedef basic_string u32string; template > struct basic_string_view { + typedef size_t size_type; + typedef basic_string_view _Type; + const C *str; constexpr basic_string_view(const C* s) : str(s) {} + + size_type find(_Type v, size_type pos = 0) const; + size_type find(C ch, size_type pos = 0) const; + size_type find(const C* s, size_type pos, size_type count) const; + size_type find(const C* s, size_type pos = 0) const; + + size_type rfind(_Type v, size_type pos = npos) const; + size_type rfind(C ch, size_type pos = npos) const; + size_type rfind(const C* s, size_type pos, size_type count) const; + size_type rfind(const C* s, size_type pos = npos) const; + + static constexpr size_t npos = -1; }; typedef basic_string_view string_view; typedef basic_string_view wstring_view; diff --git a/clang-tools-extra/test/clang-tidy/checkers/abseil/string-find-startswith.cpp b/clang-tools-extra/test/clang-tidy/checkers/abseil/string-find-startswith.cpp index e51568077eda1..417598790bc00 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/abseil/string-find-startswith.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/abseil/string-find-startswith.cpp @@ -1,27 +1,14 @@ // RUN: %check_clang_tidy %s abseil-string-find-startswith %t -- \ -// RUN: -config="{CheckOptions: {abseil-string-find-startswith.StringLikeClasses: '::std::basic_string;::basic_string'}}" +// RUN: -config="{CheckOptions: \ +// RUN: {abseil-string-find-startswith.StringLikeClasses: \ +// RUN: '::std::basic_string;::std::basic_string_view;::basic_string'}}" \ +// RUN: -- -isystem %clang_tidy_headers + +#include using size_t = decltype(sizeof(int)); namespace std { -template class allocator {}; -template class char_traits {}; -template , - typename A = std::allocator> -struct basic_string { - basic_string(); - basic_string(const basic_string &); - basic_string(const C *, const A &a = A()); - ~basic_string(); - int find(basic_string s, int pos = 0); - int find(const char *s, int pos = 0); - int rfind(basic_string s, int pos = npos); - int rfind(const char *s, int pos = npos); - static constexpr size_t npos = -1; -}; -typedef basic_string string; -typedef basic_string wstring; - struct cxx_string { int find(const char *s, int pos = 0); int rfind(const char *s, int pos = npos); @@ -39,7 +26,7 @@ std::string bar(); #define A_MACRO(x, y) ((x) == (y)) -void tests(std::string s, global_string s2) { +void tests(std::string s, global_string s2, std::string_view sv) { s.find("a") == 0; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith instead of find() == 0 [abseil-string-find-startswith] // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s, "a");{{$}} @@ -96,6 +83,14 @@ void tests(std::string s, global_string s2) { // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s2, "a");{{$}} + sv.find("a") == 0; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith + // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(sv, "a");{{$}} + + sv.rfind("a", 0) != 0; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith + // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(sv, "a");{{$}} + // expressions that don't trigger the check are here. A_MACRO(s.find("a"), 0); A_MACRO(s.rfind("a", 0), 0);