https://github.com/localspook created https://github.com/llvm/llvm-project/pull/182697
This is a followup to #182633. Like in that PR, `operator+=` doesn't fit with the check name, but the same optimization is applicable to it: https://en.cppreference.com/w/cpp/string/basic_string/operator+=.html >From 7eff94f01a9a6e2fbf787c1170715208646fc9e3 Mon Sep 17 00:00:00 2001 From: Victor Chernyakin <[email protected]> Date: Fri, 20 Feb 2026 21:02:57 -0800 Subject: [PATCH] [clang-tidy] Teach `performance-faster-string-find` about `operator+=` --- .../performance/FasterStringFindCheck.cpp | 19 +++++++++++++------ clang-tools-extra/docs/ReleaseNotes.rst | 4 ++-- .../checks/performance/faster-string-find.rst | 4 ++-- .../performance/faster-string-find.cpp | 12 ++++++++++++ 4 files changed, 29 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..5c36bd02a9e8a 100644 --- a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp @@ -66,21 +66,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 cf8dd0dba9f12..faf8a58863fe9 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -232,8 +232,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..091c6783a78af 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,17 @@ 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 += "a") += "b") += "c"; + // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'operator+=' called with a + // CHECK-MESSAGES: [[@LINE-2]]:20: warning: 'operator+=' called with a + // CHECK-MESSAGES: [[@LINE-3]]:28: warning: 'operator+=' called with a + // CHECK-FIXES: ((Str += 'a') += 'b') += 'c'; + 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
