https://github.com/localspook updated https://github.com/llvm/llvm-project/pull/182633
>From be680e5dee3af09eeca33577a312dab4be8892bd Mon Sep 17 00:00:00 2001 From: Victor Chernyakin <[email protected]> Date: Fri, 20 Feb 2026 16:29:03 -0800 Subject: [PATCH 1/2] [clang-tidy] Teach `performance-faster-string-find` about `starts_with`, `ends_with`, and `contains` --- .../performance/FasterStringFindCheck.cpp | 14 ++++++-------- clang-tools-extra/docs/ReleaseNotes.rst | 5 +++++ .../checks/performance/faster-string-find.rst | 7 ++++--- .../checkers/performance/faster-string-find.cpp | 15 +++++++++++++++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp index 7c90130c826f0..52a4d70e15265 100644 --- a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp @@ -67,13 +67,14 @@ void FasterStringFindCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) { const auto SingleChar = expr(ignoringParenCasts(stringLiteral(hasSize(1)).bind("literal"))); - const auto StringFindFunctions = - hasAnyName("find", "rfind", "find_first_of", "find_first_not_of", - "find_last_of", "find_last_not_of"); + + const auto InterestingStringFunction = hasAnyName( + "find", "rfind", "find_first_of", "find_first_not_of", "find_last_of", + "find_last_not_of", "starts_with", "ends_with", "contains"); Finder->addMatcher( cxxMemberCallExpr( - callee(functionDecl(StringFindFunctions).bind("func")), + callee(functionDecl(InterestingStringFunction).bind("func")), anyOf(argumentCountIs(1), argumentCountIs(2)), hasArgument(0, SingleChar), on(expr(hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration( @@ -94,10 +95,7 @@ void FasterStringFindCheck::check(const MatchFinder::MatchResult &Result) { "a single character; consider using the more " "effective overload accepting a character") << FindFunc - << FixItHint::CreateReplacement( - CharSourceRange::getTokenRange(Literal->getBeginLoc(), - Literal->getEndLoc()), - *Replacement); + << FixItHint::CreateReplacement(Literal->getSourceRange(), *Replacement); } } // namespace clang::tidy::performance diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 68bab88146241..b0a49b139e65e 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -224,6 +224,11 @@ Changes in existing checks - Improved the ignore list to correctly handle ``typedef`` and ``enum``. +- Improved :doc:`performance-faster-string-find + <clang-tidy/checks/performance/faster-string-find>` check to + analyze calls to the ``starts_with``, ``ends_with``, and ``contains`` + string member functions. + - Improved :doc:`performance-inefficient-vector-operation <clang-tidy/checks/performance/inefficient-vector-operation>` check by correctly handling vector-like classes when ``push_back``/``emplace_back`` are diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/faster-string-find.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/faster-string-find.rst index 28bd08d8aaa11..a7fb97197460e 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/performance/faster-string-find.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/performance/faster-string-find.rst @@ -24,6 +24,7 @@ Options Semicolon-separated list of names of string-like classes. By default only ``::std::basic_string`` and ``::std::basic_string_view`` are considered. - The check will only consider member functions named ``find``, ``rfind``, - ``find_first_of``, ``find_first_not_of``, ``find_last_of``, or - ``find_last_not_of`` within these classes. + Within these classes, the check will only consider member functions named + ``find``, ``rfind``, ``find_first_of``, ``find_first_not_of``, + ``find_last_of``, ``find_last_not_of``, ``starts_with``, ``ends_with``, or + ``contains``. diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp index e52441035e15f..83824c62494e7 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp @@ -14,6 +14,9 @@ struct basic_string { int find_first_not_of(const Char *) const; int find_last_of(const Char *) const; int find_last_not_of(const Char *) const; + bool starts_with(const Char *) const; + bool ends_with(const Char *) const; + bool contains(const Char *) const; }; typedef basic_string<char> string; @@ -28,6 +31,9 @@ struct basic_string_view { int find_first_not_of(const Char *) const; int find_last_of(const Char *) const; int find_last_not_of(const Char *) const; + bool starts_with(const Char *) const; + bool ends_with(const Char *) const; + bool contains(const Char *) const; }; typedef basic_string_view<char> string_view; @@ -87,6 +93,15 @@ void StringFind() { Str.find_last_not_of("a"); // CHECK-MESSAGES: [[@LINE-1]]:24: warning: 'find_last_not_of' called with a // CHECK-FIXES: Str.find_last_not_of('a'); + Str.starts_with("a"); + // CHECK-MESSAGES: [[@LINE-1]]:19: warning: 'starts_with' called with a + // CHECK-FIXES: Str.starts_with('a'); + Str.ends_with("a"); + // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'ends_with' called with a string + // CHECK-FIXES: Str.ends_with('a'); + Str.contains("a"); + // CHECK-MESSAGES: [[@LINE-1]]:16: warning: 'contains' called with a + // CHECK-FIXES: Str.contains('a'); // std::wstring should work. std::wstring WStr; >From cfd715e652d743316c9c8e9b44c1d56eb9555a2b Mon Sep 17 00:00:00 2001 From: Victor Chernyakin <[email protected]> Date: Fri, 20 Feb 2026 21:02:57 -0800 Subject: [PATCH 2/2] [clang-tidy] Teach `performance-faster-string-find` about `operator+=` --- .../performance/FasterStringFindCheck.cpp | 20 +++++++++++++------ clang-tools-extra/docs/ReleaseNotes.rst | 4 ++-- .../checks/performance/faster-string-find.rst | 4 ++-- .../performance/faster-string-find.cpp | 7 +++++++ 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp index 52a4d70e15265..4cba1d00edbb0 100644 --- a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp @@ -10,6 +10,7 @@ #include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "llvm/Support/raw_ostream.h" #include <optional> @@ -66,21 +67,28 @@ void FasterStringFindCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) { const auto SingleChar = - expr(ignoringParenCasts(stringLiteral(hasSize(1)).bind("literal"))); + ignoringParenCasts(stringLiteral(hasSize(1)).bind("literal")); + + const auto StringExpr = + expr(hasType(hasUnqualifiedDesugaredType(recordType( + hasDeclaration(recordDecl(hasAnyName(StringLikeClasses)))))), + unless(hasSubstitutedType())); const auto InterestingStringFunction = hasAnyName( "find", "rfind", "find_first_of", "find_first_not_of", "find_last_of", - "find_last_not_of", "starts_with", "ends_with", "contains"); + "find_last_not_of", "starts_with", "ends_with", "contains", "operator+="); Finder->addMatcher( cxxMemberCallExpr( callee(functionDecl(InterestingStringFunction).bind("func")), anyOf(argumentCountIs(1), argumentCountIs(2)), - hasArgument(0, SingleChar), - on(expr(hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration( - recordDecl(hasAnyName(StringLikeClasses)))))), - unless(hasSubstitutedType())))), + hasArgument(0, SingleChar), on(StringExpr)), this); + + Finder->addMatcher(cxxOperatorCallExpr(hasOperatorName("+="), + hasLHS(StringExpr), hasRHS(SingleChar), + callee(functionDecl().bind("func"))), + this); } void FasterStringFindCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index b0a49b139e65e..cecb7eb638d0d 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -226,8 +226,8 @@ Changes in existing checks - Improved :doc:`performance-faster-string-find <clang-tidy/checks/performance/faster-string-find>` check to - analyze calls to the ``starts_with``, ``ends_with``, and ``contains`` - string member functions. + analyze calls to the ``starts_with``, ``ends_with``, ``contains``, + and ``operator+=`` string member functions. - Improved :doc:`performance-inefficient-vector-operation <clang-tidy/checks/performance/inefficient-vector-operation>` check by diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/faster-string-find.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/faster-string-find.rst index a7fb97197460e..e7ed869acc8ad 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/performance/faster-string-find.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/performance/faster-string-find.rst @@ -26,5 +26,5 @@ Options ``::std::basic_string`` and ``::std::basic_string_view`` are considered. Within these classes, the check will only consider member functions named ``find``, ``rfind``, ``find_first_of``, ``find_first_not_of``, - ``find_last_of``, ``find_last_not_of``, ``starts_with``, ``ends_with``, or - ``contains``. + ``find_last_of``, ``find_last_not_of``, ``starts_with``, ``ends_with``, + ``contains``, or ``operator+=``. diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp index 83824c62494e7..437e95053660f 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/faster-string-find.cpp @@ -17,6 +17,7 @@ struct basic_string { bool starts_with(const Char *) const; bool ends_with(const Char *) const; bool contains(const Char *) const; + basic_string& operator+=(const Char *); }; typedef basic_string<char> string; @@ -102,6 +103,12 @@ void StringFind() { Str.contains("a"); // CHECK-MESSAGES: [[@LINE-1]]:16: warning: 'contains' called with a // CHECK-FIXES: Str.contains('a'); + Str += "a"; + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'operator+=' called with a + // CHECK-FIXES: Str += 'a'; + Str.operator+=("a"); + // CHECK-MESSAGES: [[@LINE-1]]:18: warning: 'operator+=' called with a + // CHECK-FIXES: Str.operator+=('a'); // std::wstring should work. std::wstring WStr; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
