https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/185559
>From cb8e9fdb2c62fc3dfa471ca6cf3392d259c9cb4d Mon Sep 17 00:00:00 2001 From: mtx <[email protected]> Date: Sun, 8 Mar 2026 17:50:48 +0800 Subject: [PATCH 1/4] [clang-tidy] Fix false negatives in performance-faster-string-find with libstdc++ --- .../performance/FasterStringFindCheck.cpp | 15 ++--------- .../performance/FasterStringFindCheck.h | 3 +++ clang-tools-extra/docs/ReleaseNotes.rst | 9 ++++--- .../performance/faster-string-find.cpp | 26 ++++++++++++++++++- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp index 52a4d70e15265..8a96d41944748 100644 --- a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp @@ -42,16 +42,6 @@ makeCharacterLiteral(const StringLiteral *Literal) { return Result; } -namespace { - -AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Expr>, - hasSubstitutedType) { - return hasType(qualType(anyOf(substTemplateTypeParmType(), - hasDescendant(substTemplateTypeParmType())))); -} - -} // namespace - FasterStringFindCheck::FasterStringFindCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), @@ -77,9 +67,8 @@ void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) { callee(functionDecl(InterestingStringFunction).bind("func")), anyOf(argumentCountIs(1), argumentCountIs(2)), hasArgument(0, SingleChar), - on(expr(hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration( - recordDecl(hasAnyName(StringLikeClasses)))))), - unless(hasSubstitutedType())))), + on(expr(hasType(hasUnqualifiedDesugaredType(recordType( + hasDeclaration(recordDecl(hasAnyName(StringLikeClasses))))))))), this); } diff --git a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.h b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.h index 74067c1f5792d..f5d36d805498e 100644 --- a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.h +++ b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.h @@ -28,6 +28,9 @@ class FasterStringFindCheck : public ClangTidyCheck { bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus; } + std::optional<TraversalKind> getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; void storeOptions(ClangTidyOptions::OptionMap &Opts) override; diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index cf8dd0dba9f12..8f4bb6e247ca8 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -231,9 +231,12 @@ 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. + <clang-tidy/checks/performance/faster-string-find>` check: + + - Analyze calls to the ``starts_with``, ``ends_with``, and ``contains`` + string member functions. + + - Fixes false negatives when using ``std::set`` from ``libstdc++``. - Improved :doc:`performance-inefficient-vector-operation <clang-tidy/checks/performance/inefficient-vector-operation>` check by 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..55f52643d89ab 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 @@ -38,6 +38,16 @@ struct basic_string_view { typedef basic_string_view<char> string_view; typedef basic_string_view<wchar_t> wstring_view; + +template <typename T> struct set { + struct iterator { + const T& operator*() const; + iterator& operator++(); + bool operator!=(const iterator&) const; + }; + iterator begin() const; + iterator end() const; +}; } // namespace std namespace llvm { @@ -143,9 +153,14 @@ int FindTemplateDependant(T value) { } template <typename T> int FindTemplateNotDependant(T pos) { + // Ignored since the type of `pos` is dependent, the call cannot be completely resolved without instantiating the template. return std::string().find("A", pos); +} +template <typename T> +int FindTemplateNotDependant2() { + return std::string().find("A"); // CHECK-MESSAGES: [[@LINE-1]]:29: warning: 'find' called with a string literal - // CHECK-FIXES: return std::string().find('A', pos); + // CHECK-FIXES: return std::string().find('A'); } int FindStr() { @@ -160,3 +175,12 @@ int Macros() { // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'find' called with a string literal // CHECK-MESSAGES: [[@LINE-2]]:37: warning: 'find' called with a string literal } + +void IteratorInLibStdCXX() { + std::set<std::string> s; + for (const auto &str : s) { + str.find("a"); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: 'find' called with a string literal + // CHECK-FIXES: str.find('a'); + } +} >From 2dd086b744d6bf89aa8996a16ec49e5a26f1c0ec Mon Sep 17 00:00:00 2001 From: mtx <[email protected]> Date: Tue, 10 Mar 2026 10:51:11 +0800 Subject: [PATCH 2/4] ~ --- .../test/clang-tidy/checkers/performance/faster-string-find.cpp | 1 + 1 file changed, 1 insertion(+) 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 bcc500fc047d3..f358042d426a0 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 @@ -5,6 +5,7 @@ // RUN: '::llvm::StringRef;'}}" #include <string> +// Mock for libstdc++ namespace std { template <typename T> struct set { struct iterator { >From e4583e0d629a0cfb7df65896903994535c319115 Mon Sep 17 00:00:00 2001 From: mtx <[email protected]> Date: Tue, 10 Mar 2026 11:03:05 +0800 Subject: [PATCH 3/4] fixup fixup fixup --- .../clang-tidy/performance/FasterStringFindCheck.cpp | 5 ++--- .../clang-tidy/checkers/performance/faster-string-find.cpp | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp index 96ad60bb2fdd4..1d9325166e341 100644 --- a/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp @@ -58,9 +58,8 @@ void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) { const auto SingleChar = ignoringParenCasts(stringLiteral(hasSize(1)).bind("literal")); - const auto StringExpr = - expr(hasType(hasUnqualifiedDesugaredType(recordType( - hasDeclaration(recordDecl(hasAnyName(StringLikeClasses))))))); + const auto StringExpr = expr(hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(recordDecl(hasAnyName(StringLikeClasses))))))); const auto InterestingStringFunction = hasAnyName( "find", "rfind", "find_first_of", "find_first_not_of", "find_last_of", 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 f358042d426a0..dbb4fb8c1b0ad 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 @@ -5,7 +5,6 @@ // RUN: '::llvm::StringRef;'}}" #include <string> -// Mock for libstdc++ namespace std { template <typename T> struct set { struct iterator { @@ -139,7 +138,7 @@ template <typename T> int FindTemplateNotDependant2() { return std::string().find("A"); // CHECK-MESSAGES: [[@LINE-1]]:29: warning: 'find' called with a string literal - // CHECK-FIXES: return std::string().find('A'); + // CHECK-FIXES: return std::string().find('A'); } int FindStr() { >From f909b404d324bb4c020743ec91da812d5707ecb3 Mon Sep 17 00:00:00 2001 From: mtx <[email protected]> Date: Tue, 10 Mar 2026 14:11:08 +0800 Subject: [PATCH 4/4] try again --- .../performance/faster-string-find.cpp | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) 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 dbb4fb8c1b0ad..63b229ccbb8e6 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 @@ -1,22 +1,10 @@ -// RUN: %check_clang_tidy %s performance-faster-string-find %t +// RUN: %check_clang_tidy %s performance-faster-string-find %t -- -- -fno-delayed-template-parsing // RUN: %check_clang_tidy -check-suffix=CUSTOM %s performance-faster-string-find %t -- \ // RUN: -config="{CheckOptions: \ // RUN: {performance-faster-string-find.StringLikeClasses: \ -// RUN: '::llvm::StringRef;'}}" +// RUN: '::llvm::StringRef;'}}" -- -fno-delayed-template-parsing #include <string> -namespace std { -template <typename T> struct set { - struct iterator { - const T& operator*() const; - iterator& operator++(); - bool operator!=(const iterator&) const; - }; - iterator begin() const; - iterator end() const; -}; -} // namespace std - namespace llvm { struct StringRef { int find(const char *) const; @@ -27,6 +15,10 @@ struct NotStringRef { int find(const char *); }; +template <typename T> struct Wrapper { + T value; +}; + void StringFind() { std::string Str; @@ -138,7 +130,7 @@ template <typename T> int FindTemplateNotDependant2() { return std::string().find("A"); // CHECK-MESSAGES: [[@LINE-1]]:29: warning: 'find' called with a string literal - // CHECK-FIXES: return std::string().find('A'); + // CHECK-FIXES: return std::string().find('A'); } int FindStr() { @@ -154,11 +146,8 @@ int Macros() { // CHECK-MESSAGES: [[@LINE-2]]:37: warning: 'find' called with a string literal } -void IteratorInLibStdCXX() { - std::set<std::string> s; - for (const auto &str : s) { - str.find("a"); - // CHECK-MESSAGES: [[@LINE-1]]:14: warning: 'find' called with a string literal - // CHECK-FIXES: str.find('a'); - } +void SubstitutedTemplateType() { + Wrapper<std::string>().value.find("a"); + // CHECK-MESSAGES: [[@LINE-1]]:37: warning: 'find' called with a string literal + // CHECK-FIXES: Wrapper<std::string>().value.find('a'); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
