[clang-tools-extra] [clang-tidy] Add llvm-regex check (PR #207407)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 19 05:36:06 PDT 2026
https://github.com/furtib updated https://github.com/llvm/llvm-project/pull/207407
>From f52244e33254f5564ce7104d61d96e0bc09f07b4 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Mon, 8 Jun 2026 23:43:38 +0200
Subject: [PATCH 01/22] [clang-tidy] Add llvm-regex check
---
.../clang-tidy/llvm/CMakeLists.txt | 1 +
.../clang-tidy/llvm/LLVMTidyModule.cpp | 2 +
.../clang-tidy/llvm/RegexCheck.cpp | 88 +++++++++++
.../clang-tidy/llvm/RegexCheck.h | 33 +++++
clang-tools-extra/docs/ReleaseNotes.md | 5 +
.../docs/clang-tidy/checks/list.md | 1 +
.../docs/clang-tidy/checks/llvm/regex.rst | 34 +++++
.../test/clang-tidy/checkers/llvm/regex.cpp | 140 ++++++++++++++++++
8 files changed, 304 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/llvm/RegexCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
diff --git a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
index bec3ba50c81c5..2f5d136108191 100644
--- a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_library(clangTidyLLVMModule STATIC
PreferRegisterOverUnsignedCheck.cpp
PreferStaticOverAnonymousNamespaceCheck.cpp
RedundantCastingCheck.cpp
+ RegexCheck.cpp
TwineLocalCheck.cpp
TypeSwitchCaseTypesCheck.cpp
UseNewMLIROpBuilderCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
index 918af88c979e0..16409770f0467 100644
--- a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
@@ -18,6 +18,7 @@
#include "PreferRegisterOverUnsignedCheck.h"
#include "PreferStaticOverAnonymousNamespaceCheck.h"
#include "RedundantCastingCheck.h"
+#include "RegexCheck.h"
#include "TwineLocalCheck.h"
#include "TypeSwitchCaseTypesCheck.h"
#include "UseNewMLIROpBuilderCheck.h"
@@ -48,6 +49,7 @@ class LLVMModule : public ClangTidyModule {
"llvm-qualified-auto");
CheckFactories.registerCheck<RedundantCastingCheck>(
"llvm-redundant-casting");
+ CheckFactories.registerCheck<RegexCheck>("llvm-regex");
CheckFactories.registerCheck<TwineLocalCheck>("llvm-twine-local");
CheckFactories.registerCheck<TypeSwitchCaseTypesCheck>(
"llvm-type-switch-case-types");
diff --git a/clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp b/clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp
new file mode 100644
index 0000000000000..f9f2b58e424f7
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp
@@ -0,0 +1,88 @@
+//===--- RegexCheck.cpp - clang-tidy --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegexCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/Regex.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::llvm_check {
+
+void RegexCheck::registerMatchers(MatchFinder *Finder) {
+ // main matcher
+ auto IsConstllvmStringRef = qualType(
+ isConstQualified(), hasUnqualifiedDesugaredType(recordType(hasDeclaration(
+ cxxRecordDecl(hasName("::llvm::StringRef"))))));
+ auto IsConstStdString = qualType(
+ isConstQualified(), hasUnqualifiedDesugaredType(recordType(hasDeclaration(
+ cxxRecordDecl(hasName("::std::basic_string"))))));
+ auto GetStringLit = ignoringImplicit(stringLiteral().bind("stringLiteral"));
+ auto GetStringLiteralFromObject =
+ ignoringImplicit(cxxConstructExpr(hasAnyArgument(GetStringLit)));
+ auto IsConstCharPtr = pointerType(pointee(builtinType(), isConstQualified()));
+ auto IsStdStringView = qualType(hasUnqualifiedDesugaredType(recordType(
+ hasDeclaration(cxxRecordDecl(hasName("::std::basic_string_view"))))));
+ auto AnyCastedToStringRef = ignoringImplicit(anyOf(
+ stringLiteral().bind("stringLiteral"),
+ declRefExpr(to(varDecl(hasType(IsConstStdString),
+ hasInitializer(GetStringLiteralFromObject)))),
+ declRefExpr(to(varDecl(hasType(IsConstllvmStringRef),
+ hasInitializer(GetStringLiteralFromObject)))),
+ declRefExpr(
+ to(varDecl(hasType(IsConstCharPtr), hasInitializer(GetStringLit)))),
+ declRefExpr(to(varDecl(hasType(IsStdStringView),
+ hasInitializer(GetStringLiteralFromObject)))),
+ memberExpr(
+ member(fieldDecl(hasType(IsConstStdString),
+ hasInClassInitializer(GetStringLiteralFromObject)))),
+ memberExpr(member(fieldDecl(hasType(IsConstCharPtr),
+ hasInClassInitializer(GetStringLit)))),
+ memberExpr(
+ member(fieldDecl(hasType(IsConstllvmStringRef),
+ hasInClassInitializer(GetStringLiteralFromObject)))),
+ memberExpr(member(
+ fieldDecl(hasType(IsStdStringView),
+ hasInClassInitializer(GetStringLiteralFromObject))))));
+
+ auto IsRegexFlagsType = ignoringParenImpCasts(
+ anyOf(integerLiteral().bind("regexFlagsInt"),
+ declRefExpr(to(enumConstantDecl().bind("regexFlagEnum")))));
+ Finder->addMatcher(
+ cxxConstructExpr(
+ hasDeclaration(cxxConstructorDecl(ofClass(hasName("llvm::Regex")))),
+ hasArgument(0, ignoringImplicit(cxxConstructExpr(
+ hasDeclaration(cxxConstructorDecl(
+ ofClass(hasName("::llvm::StringRef")))),
+ hasArgument(0, AnyCastedToStringRef)))),
+ optionally(hasArgument(1, IsRegexFlagsType))),
+ this);
+}
+
+void RegexCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *DetectedPattern =
+ Result.Nodes.getNodeAs<StringLiteral>("stringLiteral");
+ if (DetectedPattern) {
+ const auto *FlagInt =
+ Result.Nodes.getNodeAs<IntegerLiteral>("regexFlagsInt");
+ const auto *FlagEnum =
+ Result.Nodes.getNodeAs<EnumConstantDecl>("regexFlagEnum");
+ uint Flag = llvm::Regex::RegexFlags::NoFlags;
+ if (FlagInt)
+ Flag = FlagInt->getValue().getZExtValue();
+ if (FlagEnum)
+ Flag = FlagEnum->getInitVal().getZExtValue();
+ const llvm::Regex TestRegex(DetectedPattern->getString(), Flag);
+ std::string RegexError;
+ if (!TestRegex.isValid(RegexError))
+ diag(DetectedPattern->getBeginLoc(), "invalid regex pattern: %0")
+ << RegexError << DetectedPattern->getSourceRange();
+ }
+}
+
+} // namespace clang::tidy::llvm_check
diff --git a/clang-tools-extra/clang-tidy/llvm/RegexCheck.h b/clang-tools-extra/clang-tidy/llvm/RegexCheck.h
new file mode 100644
index 0000000000000..17891713e62ee
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/llvm/RegexCheck.h
@@ -0,0 +1,33 @@
+//===--- RegexCheck.h - clang-tidy ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_REGEXCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_REGEXCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::llvm_check {
+
+/// Detects malformed regex patterns used in ``llvm::Regex``.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/llvm/regex.html
+class RegexCheck : public ClangTidyCheck {
+public:
+ RegexCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
+};
+
+} // namespace clang::tidy::llvm_check
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_REGEXCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 28da9da42d8ce..a84d311ddd788 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -98,6 +98,11 @@ infrastructure are described first, followed by tool-specific sections.
Finds calls to `value_or` (and alternative spellings `valueOr`,
`ValueOr`) on optional types where the return type is expensive to copy.
+- New :doc:`llvm-regex
+ <clang-tidy/checks/llvm/regex>` check.
+
+ Detects malformed regex patterns used in `llvm::Regex`.
+
#### New check aliases
#### Changes in existing checks
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.md b/clang-tools-extra/docs/clang-tidy/checks/list.md
index 12d8a48ee8d86..39c42a32a2258 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.md
@@ -251,6 +251,7 @@ zircon/*
| {doc}`llvm-prefer-register-over-unsigned <llvm/prefer-register-over-unsigned>` | Yes |
| {doc}`llvm-prefer-static-over-anonymous-namespace <llvm/prefer-static-over-anonymous-namespace>` | |
| {doc}`llvm-redundant-casting <llvm/redundant-casting>` | Yes |
+| {doc}`llvm-regex <llvm/regex>` | No |
| {doc}`llvm-twine-local <llvm/twine-local>` | Yes |
| {doc}`llvm-type-switch-case-types <llvm/type-switch-case-types>` | Yes |
| {doc}`llvm-use-new-mlir-op-builder <llvm/use-new-mlir-op-builder>` | Yes |
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
new file mode 100644
index 0000000000000..837181a8ea4a6
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
@@ -0,0 +1,34 @@
+.. title:: clang-tidy - llvm-regex
+
+llvm-regex
+==========
+
+The checker detects malformed regex patterns defined in a single string literal
+to catch mistakes at compile time.
+It detects these string literals if they are defined in the regex constructor
+with a string literal, or stored in one of these non mutable container:
+
+- ``const std::string``
+- ``const char*``
+- ``const llvm::StringRef``
+- ``std::string_view``
+
+In the event that the patterns are stored as a class member, the check checks
+the initialization value, if defined, even if its overwritten by the constructor.
+
+Example of detection:
+
+.. code-block:: c++
+ const std::string my_regex_pattern("[0-8"); // invalid regex pattern
+ llvm::Regex my_regex(my_regex_pattern);
+
+Example of member data being overwritten:
+
+.. code-block:: c++
+ class foo{
+ public:
+ foo(llvm::StringRef regex_ptrn) : regex_prtn(regex_prtn){};
+ const llvm_StringRef regex_prtn = "("; // invalid regex pattern
+ };
+ foo bar("[0-9]");
+ llvm::Regex my_regex(bar.regex_prtn);
diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
new file mode 100644
index 0000000000000..229b35f2eb204
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
@@ -0,0 +1,140 @@
+// RUN: %check_clang_tidy -std=c++17 %s llvm-regex %t
+
+namespace std {
+ template <typename T>
+ class basic_string {
+ public:
+ basic_string(const char*);
+ };
+ using string = basic_string<char>;
+
+ template <typename T>
+ class basic_string_view {
+ public:
+ basic_string_view(const char*);
+ const char* begin() const;
+ };
+ using string_view = basic_string_view<char>;
+} // namespace std
+
+namespace llvm {
+ class StringRef {
+ public:
+ StringRef(const char*);
+ StringRef(const std::string&);
+ StringRef(const std::string_view&);
+ };
+
+ class Regex {
+ public:
+ Regex(StringRef, unsigned int i = 0);
+ enum RegexFlags : unsigned {
+ NoFlags = 0,
+ IgnoreCase = 1,
+ Newline = 2,
+ BasicRegex = 4,
+ };
+ };
+} // namespace llvm
+
+void test_detected_faulty_patterns(){
+ llvm::Regex re1("(");
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: invalid regex pattern: parentheses not balanced
+
+ const std::string badStdString("(");
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: invalid regex pattern: parentheses not balanced
+ llvm::Regex re2(badStdString);
+
+ const char* badCharPtr = "[]";
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: invalid regex pattern: brackets ([ ]) not balanced
+ llvm::Regex re3(badCharPtr);
+
+ std::string_view badStrView("+");
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: invalid regex pattern: repetition-operator operand invalid
+ llvm::Regex re4(badStrView);
+
+ const llvm::StringRef badStrRef = "a*?";
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: invalid regex pattern: repetition-operator operand invalid
+ llvm::Regex re5(badStrRef);
+
+ struct RegexPatterns {
+ const char* badMemberChar = "";
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: invalid regex pattern: empty (sub)expression
+
+ const std::string badMemberStr = "(";
+ // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: invalid regex pattern: parentheses not balanced
+
+ std::string_view badMemberStrView = "+";
+ // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: invalid regex pattern: repetition-operator operand invalid
+
+ const llvm::StringRef badMemberStrRef = "a*?";
+ // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: invalid regex pattern: repetition-operator operand invalid
+ };
+
+ RegexPatterns Pats;
+
+ llvm::Regex re6(Pats.badMemberChar);
+ llvm::Regex re7(Pats.badMemberStr);
+ llvm::Regex re8(Pats.badMemberStrView);
+ llvm::Regex re9(Pats.badMemberStrRef);
+}
+
+void test_no_detection_on_mutable(){
+ std::string badMutStdString("(");
+ llvm::Regex re10(badMutStdString);
+
+ char* badMutCharPtr = "[";
+ llvm::Regex re11(badMutCharPtr);
+
+ llvm::StringRef badMutStrRef = "a*?";
+ llvm::Regex re12(badMutStrRef);
+
+ struct RegexMutPatterns {
+ char* badMutMemberChar = "";
+ std::string badMutMemberStr = "(";
+ llvm::StringRef badMutMemberStrRef = "a*?";
+ };
+
+ RegexMutPatterns mutPats;
+
+ llvm::Regex re13(mutPats.badMutMemberChar);
+ llvm::Regex re14(mutPats.badMutMemberStr);
+ llvm::Regex re15(mutPats.badMutMemberStrRef);
+}
+
+void test_no_report_on_correct_patterns(){
+ llvm::Regex re16("[0-9]");
+
+ const std::string goodStdString("test");
+ llvm::Regex re17(goodStdString);
+
+ const char* goodCharPtr = "\\[test\\]";
+ llvm::Regex re18(goodCharPtr);
+
+ std::string_view goodStrView("testi+ng");
+ llvm::Regex re19(goodStrView);
+
+ const llvm::StringRef goodStrRef = "a*b?";
+ llvm::Regex re20(goodStrRef);
+
+ struct GoodRegexPatterns {
+ const char* goodMemberChar = "[0-9]";
+ const std::string goodMemberStr = "test";
+ std::string_view goodMemberStrView = "\[test\]";
+ const llvm::StringRef goodMemberStrRef = "a*b";
+ };
+
+ GoodRegexPatterns goodPats;
+
+ llvm::Regex re21(goodPats.goodMemberChar);
+ llvm::Regex re22(goodPats.goodMemberStr);
+ llvm::Regex re23(goodPats.goodMemberStrView);
+ llvm::Regex re24(goodPats.goodMemberStrRef);
+}
+
+void test_grammar_flags(){
+ llvm::Regex re1_noflag("(", 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: invalid regex pattern: parentheses not balanced
+ llvm::Regex re1_basic("(", 4U);
+ llvm::Regex re2_basic("(", llvm::Regex::RegexFlags::BasicRegex);
+}
>From 52d15ebc61e54aeadb16b8b9422fcb4f5ba4d757 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Sat, 4 Jul 2026 10:57:53 +0200
Subject: [PATCH 02/22] Apply suggestions from code review
Co-authored-by: EugeneZelenko <eugene.zelenko at gmail.com>
Co-authored-by: Zeyi Xu <zeyi2 at nekoarch.cc>
---
clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp | 2 +-
clang-tools-extra/clang-tidy/llvm/RegexCheck.h | 2 +-
clang-tools-extra/docs/clang-tidy/checks/list.md | 2 +-
clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst | 2 +-
clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp b/clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp
index f9f2b58e424f7..57f6fa9588adf 100644
--- a/clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp
@@ -1,4 +1,4 @@
-//===--- RegexCheck.cpp - clang-tidy --------------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/clang-tools-extra/clang-tidy/llvm/RegexCheck.h b/clang-tools-extra/clang-tidy/llvm/RegexCheck.h
index 17891713e62ee..e18bda161ae43 100644
--- a/clang-tools-extra/clang-tidy/llvm/RegexCheck.h
+++ b/clang-tools-extra/clang-tidy/llvm/RegexCheck.h
@@ -1,4 +1,4 @@
-//===--- RegexCheck.h - clang-tidy ------------------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.md b/clang-tools-extra/docs/clang-tidy/checks/list.md
index 39c42a32a2258..2c17452e7c2f9 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.md
@@ -251,7 +251,7 @@ zircon/*
| {doc}`llvm-prefer-register-over-unsigned <llvm/prefer-register-over-unsigned>` | Yes |
| {doc}`llvm-prefer-static-over-anonymous-namespace <llvm/prefer-static-over-anonymous-namespace>` | |
| {doc}`llvm-redundant-casting <llvm/redundant-casting>` | Yes |
-| {doc}`llvm-regex <llvm/regex>` | No |
+| {doc}`llvm-regex <llvm/regex>` | |
| {doc}`llvm-twine-local <llvm/twine-local>` | Yes |
| {doc}`llvm-type-switch-case-types <llvm/type-switch-case-types>` | Yes |
| {doc}`llvm-use-new-mlir-op-builder <llvm/use-new-mlir-op-builder>` | Yes |
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
index 837181a8ea4a6..f570fac85c867 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
@@ -3,7 +3,7 @@
llvm-regex
==========
-The checker detects malformed regex patterns defined in a single string literal
+Detects malformed regex patterns defined in a single string literal
to catch mistakes at compile time.
It detects these string literals if they are defined in the regex constructor
with a string literal, or stored in one of these non mutable container:
diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
index 229b35f2eb204..c83fa9a85c501 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++17 %s llvm-regex %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s llvm-regex %t
namespace std {
template <typename T>
>From ded741a8bb4eddfb4532ff4c8ac3f18e97168c1c Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Sat, 4 Jul 2026 11:20:06 +0200
Subject: [PATCH 03/22] Documentation fixes
---
clang-tools-extra/docs/ReleaseNotes.md | 5 +++--
.../docs/clang-tidy/checks/llvm/regex.rst | 18 ++++++++++--------
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index a84d311ddd788..41db9a1910c5d 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -98,10 +98,11 @@ infrastructure are described first, followed by tool-specific sections.
Finds calls to `value_or` (and alternative spellings `valueOr`,
`ValueOr`) on optional types where the return type is expensive to copy.
-- New :doc:`llvm-regex
+- New {doc}`llvm-regex
<clang-tidy/checks/llvm/regex>` check.
- Detects malformed regex patterns used in `llvm::Regex`.
+ Detects malformed regex patterns defined in a single string literal
+ to catch mistakes at compile time.
#### New check aliases
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
index f570fac85c867..604520f3d979a 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
@@ -13,22 +13,24 @@ with a string literal, or stored in one of these non mutable container:
- ``const llvm::StringRef``
- ``std::string_view``
-In the event that the patterns are stored as a class member, the check checks
+In the event that the patterns are stored as a class member, the check verifies
the initialization value, if defined, even if its overwritten by the constructor.
Example of detection:
.. code-block:: c++
+
const std::string my_regex_pattern("[0-8"); // invalid regex pattern
llvm::Regex my_regex(my_regex_pattern);
Example of member data being overwritten:
.. code-block:: c++
- class foo{
- public:
- foo(llvm::StringRef regex_ptrn) : regex_prtn(regex_prtn){};
- const llvm_StringRef regex_prtn = "("; // invalid regex pattern
- };
- foo bar("[0-9]");
- llvm::Regex my_regex(bar.regex_prtn);
+
+ class foo{
+ public:
+ foo(llvm::StringRef regex_ptrn) : regex_prtn(regex_prtn){};
+ const llvm_StringRef regex_prtn = "("; // invalid regex pattern
+ };
+ foo bar("[0-9]");
+ llvm::Regex my_regex(bar.regex_prtn);
>From c0760c2e725d50581aee34d92cf3de957250638a Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Sat, 4 Jul 2026 11:20:32 +0200
Subject: [PATCH 04/22] Use include <string> in test file
---
.../test/clang-tidy/checkers/llvm/regex.cpp | 17 +----------------
1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
index c83fa9a85c501..88de3539da583 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
@@ -1,21 +1,6 @@
// RUN: %check_clang_tidy -std=c++17-or-later %s llvm-regex %t
-namespace std {
- template <typename T>
- class basic_string {
- public:
- basic_string(const char*);
- };
- using string = basic_string<char>;
-
- template <typename T>
- class basic_string_view {
- public:
- basic_string_view(const char*);
- const char* begin() const;
- };
- using string_view = basic_string_view<char>;
-} // namespace std
+#include <string>
namespace llvm {
class StringRef {
>From d5c64b9ea8603b5561eaff18587e5d2e95c69286 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Sat, 4 Jul 2026 11:36:39 +0200
Subject: [PATCH 05/22] Rename checker to llvm-invalid-regex-pattern
---
clang-tools-extra/clang-tidy/llvm/CMakeLists.txt | 2 +-
.../llvm/{RegexCheck.cpp => InvalidRegexPatternCheck.cpp} | 6 +++---
.../llvm/{RegexCheck.h => InvalidRegexPatternCheck.h} | 6 +++---
clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp | 4 ++--
clang-tools-extra/docs/ReleaseNotes.md | 4 ++--
clang-tools-extra/docs/clang-tidy/checks/list.md | 2 +-
.../checks/llvm/{regex.rst => invalid-regex-pattern.rst} | 6 +++---
clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp | 2 +-
8 files changed, 16 insertions(+), 16 deletions(-)
rename clang-tools-extra/clang-tidy/llvm/{RegexCheck.cpp => InvalidRegexPatternCheck.cpp} (95%)
rename clang-tools-extra/clang-tidy/llvm/{RegexCheck.h => InvalidRegexPatternCheck.h} (84%)
rename clang-tools-extra/docs/clang-tidy/checks/llvm/{regex.rst => invalid-regex-pattern.rst} (90%)
diff --git a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
index 2f5d136108191..563c05d14232a 100644
--- a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
@@ -12,7 +12,7 @@ add_clang_library(clangTidyLLVMModule STATIC
PreferRegisterOverUnsignedCheck.cpp
PreferStaticOverAnonymousNamespaceCheck.cpp
RedundantCastingCheck.cpp
- RegexCheck.cpp
+ InvalidRegexPatternCheck.cpp
TwineLocalCheck.cpp
TypeSwitchCaseTypesCheck.cpp
UseNewMLIROpBuilderCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
similarity index 95%
rename from clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp
rename to clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
index 57f6fa9588adf..ca23dcc8c9650 100644
--- a/clang-tools-extra/clang-tidy/llvm/RegexCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "RegexCheck.h"
+#include "InvalidRegexPatternCheck.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "llvm/Support/Regex.h"
@@ -14,7 +14,7 @@ using namespace clang::ast_matchers;
namespace clang::tidy::llvm_check {
-void RegexCheck::registerMatchers(MatchFinder *Finder) {
+void InvalidRegexPatternCheck::registerMatchers(MatchFinder *Finder) {
// main matcher
auto IsConstllvmStringRef = qualType(
isConstQualified(), hasUnqualifiedDesugaredType(recordType(hasDeclaration(
@@ -64,7 +64,7 @@ void RegexCheck::registerMatchers(MatchFinder *Finder) {
this);
}
-void RegexCheck::check(const MatchFinder::MatchResult &Result) {
+void InvalidRegexPatternCheck::check(const MatchFinder::MatchResult &Result) {
const auto *DetectedPattern =
Result.Nodes.getNodeAs<StringLiteral>("stringLiteral");
if (DetectedPattern) {
diff --git a/clang-tools-extra/clang-tidy/llvm/RegexCheck.h b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
similarity index 84%
rename from clang-tools-extra/clang-tidy/llvm/RegexCheck.h
rename to clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
index e18bda161ae43..177a47b668dc1 100644
--- a/clang-tools-extra/clang-tidy/llvm/RegexCheck.h
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
@@ -17,9 +17,9 @@ namespace clang::tidy::llvm_check {
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/llvm/regex.html
-class RegexCheck : public ClangTidyCheck {
+class InvalidRegexPatternCheck : public ClangTidyCheck {
public:
- RegexCheck(StringRef Name, ClangTidyContext *Context)
+ InvalidRegexPatternCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
@@ -30,4 +30,4 @@ class RegexCheck : public ClangTidyCheck {
} // namespace clang::tidy::llvm_check
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_REGEXCHECK_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_InvalidRegexPatternCheck_H
diff --git a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
index 16409770f0467..549867beec25d 100644
--- a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
@@ -18,7 +18,7 @@
#include "PreferRegisterOverUnsignedCheck.h"
#include "PreferStaticOverAnonymousNamespaceCheck.h"
#include "RedundantCastingCheck.h"
-#include "RegexCheck.h"
+#include "InvalidRegexPatternCheck.h"
#include "TwineLocalCheck.h"
#include "TypeSwitchCaseTypesCheck.h"
#include "UseNewMLIROpBuilderCheck.h"
@@ -49,7 +49,7 @@ class LLVMModule : public ClangTidyModule {
"llvm-qualified-auto");
CheckFactories.registerCheck<RedundantCastingCheck>(
"llvm-redundant-casting");
- CheckFactories.registerCheck<RegexCheck>("llvm-regex");
+ CheckFactories.registerCheck<InvalidRegexPatternCheck>("llvm-invalid-regex-pattern");
CheckFactories.registerCheck<TwineLocalCheck>("llvm-twine-local");
CheckFactories.registerCheck<TypeSwitchCaseTypesCheck>(
"llvm-type-switch-case-types");
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 41db9a1910c5d..ba0db92414488 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -98,8 +98,8 @@ infrastructure are described first, followed by tool-specific sections.
Finds calls to `value_or` (and alternative spellings `valueOr`,
`ValueOr`) on optional types where the return type is expensive to copy.
-- New {doc}`llvm-regex
- <clang-tidy/checks/llvm/regex>` check.
+- New {doc}`llvm-invalid-regex-pattern
+ <clang-tidy/checks/llvm/invalid-regex-pattern>` check.
Detects malformed regex patterns defined in a single string literal
to catch mistakes at compile time.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.md b/clang-tools-extra/docs/clang-tidy/checks/list.md
index 2c17452e7c2f9..a5fb11cfc6de0 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.md
@@ -246,12 +246,12 @@ zircon/*
| {doc}`llvm-formatv-string <llvm/formatv-string>` | |
| {doc}`llvm-header-guard <llvm/header-guard>` | |
| {doc}`llvm-include-order <llvm/include-order>` | Yes |
+| {doc}`llvm-invalid-regex-pattern <llvm/invalid-regex-pattern>` | |
| {doc}`llvm-namespace-comment <llvm/namespace-comment>` | |
| {doc}`llvm-prefer-isa-or-dyn-cast-in-conditionals <llvm/prefer-isa-or-dyn-cast-in-conditionals>` | Yes |
| {doc}`llvm-prefer-register-over-unsigned <llvm/prefer-register-over-unsigned>` | Yes |
| {doc}`llvm-prefer-static-over-anonymous-namespace <llvm/prefer-static-over-anonymous-namespace>` | |
| {doc}`llvm-redundant-casting <llvm/redundant-casting>` | Yes |
-| {doc}`llvm-regex <llvm/regex>` | |
| {doc}`llvm-twine-local <llvm/twine-local>` | Yes |
| {doc}`llvm-type-switch-case-types <llvm/type-switch-case-types>` | Yes |
| {doc}`llvm-use-new-mlir-op-builder <llvm/use-new-mlir-op-builder>` | Yes |
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
similarity index 90%
rename from clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
rename to clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
index 604520f3d979a..2cba3766608e7 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/llvm/regex.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - llvm-regex
+.. title:: clang-tidy - llvm-invalid-regex-pattern
-llvm-regex
-==========
+llvm-invalid-regex-pattern
+==========================
Detects malformed regex patterns defined in a single string literal
to catch mistakes at compile time.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
index 88de3539da583..440c59eea50f0 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++17-or-later %s llvm-regex %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s llvm-invalid-regex-pattern %t
#include <string>
>From b69553bca020fe7cf1eb939d21e781c90cc827aa Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Sat, 4 Jul 2026 11:44:52 +0200
Subject: [PATCH 06/22] Missed a couple of things during renameing
---
.../clang-tidy/llvm/InvalidRegexPatternCheck.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
index 177a47b668dc1..7adb7df285084 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_REGEXCHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_REGEXCHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_INVALIDREGEXPATTERNCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_INVALIDREGEXPATTERNCHECK_H
#include "../ClangTidyCheck.h"
@@ -30,4 +30,4 @@ class InvalidRegexPatternCheck : public ClangTidyCheck {
} // namespace clang::tidy::llvm_check
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_InvalidRegexPatternCheck_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_INVALIDREGEXPATTERNCHECK_H
>From 193f29a69aac74f123eba230cc88513c38946f59 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Sat, 4 Jul 2026 11:55:01 +0200
Subject: [PATCH 07/22] Use unsigned int instead of uint
---
clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
index ca23dcc8c9650..3a357093ffd18 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
@@ -72,7 +72,7 @@ void InvalidRegexPatternCheck::check(const MatchFinder::MatchResult &Result) {
Result.Nodes.getNodeAs<IntegerLiteral>("regexFlagsInt");
const auto *FlagEnum =
Result.Nodes.getNodeAs<EnumConstantDecl>("regexFlagEnum");
- uint Flag = llvm::Regex::RegexFlags::NoFlags;
+ unsigned int Flag = llvm::Regex::RegexFlags::NoFlags;
if (FlagInt)
Flag = FlagInt->getValue().getZExtValue();
if (FlagEnum)
>From 5c5324758339dc857f97f0784b1b4f6cd2850abd Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Sat, 4 Jul 2026 14:40:35 +0200
Subject: [PATCH 08/22] Clang-format
---
clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
index 549867beec25d..ed8d04f22a9e2 100644
--- a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
@@ -14,11 +14,11 @@
#include "FormatvStringCheck.h"
#include "HeaderGuardCheck.h"
#include "IncludeOrderCheck.h"
+#include "InvalidRegexPatternCheck.h"
#include "PreferIsaOrDynCastInConditionalsCheck.h"
#include "PreferRegisterOverUnsignedCheck.h"
#include "PreferStaticOverAnonymousNamespaceCheck.h"
#include "RedundantCastingCheck.h"
-#include "InvalidRegexPatternCheck.h"
#include "TwineLocalCheck.h"
#include "TypeSwitchCaseTypesCheck.h"
#include "UseNewMLIROpBuilderCheck.h"
@@ -49,7 +49,8 @@ class LLVMModule : public ClangTidyModule {
"llvm-qualified-auto");
CheckFactories.registerCheck<RedundantCastingCheck>(
"llvm-redundant-casting");
- CheckFactories.registerCheck<InvalidRegexPatternCheck>("llvm-invalid-regex-pattern");
+ CheckFactories.registerCheck<InvalidRegexPatternCheck>(
+ "llvm-invalid-regex-pattern");
CheckFactories.registerCheck<TwineLocalCheck>("llvm-twine-local");
CheckFactories.registerCheck<TypeSwitchCaseTypesCheck>(
"llvm-type-switch-case-types");
>From 37e4c956b96d9541bf1382798b2e43eb59da0143 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Wed, 5 Aug 2026 13:24:02 +0200
Subject: [PATCH 09/22] Update
clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: DonĂ¡t Nagy <donat.nagy at ericsson.com>
---
.../docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
index 2cba3766608e7..3ce072c193c9c 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
@@ -29,8 +29,8 @@ Example of member data being overwritten:
class foo{
public:
- foo(llvm::StringRef regex_ptrn) : regex_prtn(regex_prtn){};
- const llvm_StringRef regex_prtn = "("; // invalid regex pattern
+ foo(llvm::StringRef regex_pat) : regex_p(regex_pat){};
+ const llvm_StringRef regex_pat = "("; // invalid regex pattern
};
foo bar("[0-9]");
- llvm::Regex my_regex(bar.regex_prtn);
+ llvm::Regex my_regex(bar.regex_pat);
>From 37a01e226e97e094d1880309e80a6203a0a855c1 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Thu, 6 Aug 2026 13:34:17 +0200
Subject: [PATCH 10/22] Reduce code duplication using anyOf
---
.../llvm/InvalidRegexPatternCheck.cpp | 28 ++++++-------------
1 file changed, 9 insertions(+), 19 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
index 3a357093ffd18..048a9c5328c0e 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
@@ -30,25 +30,15 @@ void InvalidRegexPatternCheck::registerMatchers(MatchFinder *Finder) {
hasDeclaration(cxxRecordDecl(hasName("::std::basic_string_view"))))));
auto AnyCastedToStringRef = ignoringImplicit(anyOf(
stringLiteral().bind("stringLiteral"),
- declRefExpr(to(varDecl(hasType(IsConstStdString),
- hasInitializer(GetStringLiteralFromObject)))),
- declRefExpr(to(varDecl(hasType(IsConstllvmStringRef),
- hasInitializer(GetStringLiteralFromObject)))),
- declRefExpr(
- to(varDecl(hasType(IsConstCharPtr), hasInitializer(GetStringLit)))),
- declRefExpr(to(varDecl(hasType(IsStdStringView),
- hasInitializer(GetStringLiteralFromObject)))),
- memberExpr(
- member(fieldDecl(hasType(IsConstStdString),
- hasInClassInitializer(GetStringLiteralFromObject)))),
- memberExpr(member(fieldDecl(hasType(IsConstCharPtr),
- hasInClassInitializer(GetStringLit)))),
- memberExpr(
- member(fieldDecl(hasType(IsConstllvmStringRef),
- hasInClassInitializer(GetStringLiteralFromObject)))),
- memberExpr(member(
- fieldDecl(hasType(IsStdStringView),
- hasInClassInitializer(GetStringLiteralFromObject))))));
+ declRefExpr(to(varDecl(
+ hasType(qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
+ IsStdStringView, IsConstCharPtr))),
+ hasInitializer(anyOf(GetStringLiteralFromObject, GetStringLit))))),
+ memberExpr(member(fieldDecl(
+ hasType(qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
+ IsStdStringView, IsConstCharPtr))),
+ hasInClassInitializer(
+ anyOf(GetStringLiteralFromObject, GetStringLit)))))));
auto IsRegexFlagsType = ignoringParenImpCasts(
anyOf(integerLiteral().bind("regexFlagsInt"),
>From 22b511015b1a5b7582b125e04314bac8bac22b8c Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Thu, 6 Aug 2026 13:52:36 +0200
Subject: [PATCH 11/22] Change supported languages to c++17 since
std::string_view is only available since then
---
clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
index 7adb7df285084..cb6223a668344 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
@@ -24,7 +24,7 @@ class InvalidRegexPatternCheck : public ClangTidyCheck {
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
- return LangOpts.CPlusPlus;
+ return LangOpts.CPlusPlus17;
}
};
>From bd86583bcd9fa84b49900061a000260dfdecfc83 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Fri, 7 Aug 2026 12:36:36 +0200
Subject: [PATCH 12/22] Detect char arrays too (normal, static, const)
---
.../llvm/InvalidRegexPatternCheck.cpp | 7 ++++--
.../checks/llvm/invalid-regex-pattern.rst | 3 +++
.../test/clang-tidy/checkers/llvm/regex.cpp | 24 +++++++++++++++++--
3 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
index 048a9c5328c0e..4fd1d86daf4dd 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
@@ -26,17 +26,20 @@ void InvalidRegexPatternCheck::registerMatchers(MatchFinder *Finder) {
auto GetStringLiteralFromObject =
ignoringImplicit(cxxConstructExpr(hasAnyArgument(GetStringLit)));
auto IsConstCharPtr = pointerType(pointee(builtinType(), isConstQualified()));
+ auto IsCharArray = qualType(
+ hasUnqualifiedDesugaredType(arrayType(hasElementType(builtinType()))));
auto IsStdStringView = qualType(hasUnqualifiedDesugaredType(recordType(
hasDeclaration(cxxRecordDecl(hasName("::std::basic_string_view"))))));
auto AnyCastedToStringRef = ignoringImplicit(anyOf(
stringLiteral().bind("stringLiteral"),
declRefExpr(to(varDecl(
hasType(qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
- IsStdStringView, IsConstCharPtr))),
+ IsStdStringView, IsConstCharPtr,
+ IsCharArray))),
hasInitializer(anyOf(GetStringLiteralFromObject, GetStringLit))))),
memberExpr(member(fieldDecl(
hasType(qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
- IsStdStringView, IsConstCharPtr))),
+ IsStdStringView, IsConstCharPtr, IsCharArray))),
hasInClassInitializer(
anyOf(GetStringLiteralFromObject, GetStringLit)))))));
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
index 3ce072c193c9c..aaec7c456c74e 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
@@ -12,6 +12,9 @@ with a string literal, or stored in one of these non mutable container:
- ``const char*``
- ``const llvm::StringRef``
- ``std::string_view``
+- ``char[]``
+- ``static char[]``
+- ``const char[]``
In the event that the patterns are stored as a class member, the check verifies
the initialization value, if defined, even if its overwritten by the constructor.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
index 440c59eea50f0..2d36fe5d1c5c3 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
@@ -41,6 +41,18 @@ void test_detected_faulty_patterns(){
const llvm::StringRef badStrRef = "a*?";
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: invalid regex pattern: repetition-operator operand invalid
llvm::Regex re5(badStrRef);
+
+ static const char badConstStaticChar[] = "";
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: invalid regex pattern: empty (sub)expression
+ llvm::Regex regex_badConstStaticChar(badConstStaticChar);
+
+ static char badStaticChar[] = "";
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: invalid regex pattern: empty (sub)expression
+ llvm::Regex regex_badStaticChar(badStaticChar);
+
+ char badCharArray[] = "";
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: invalid regex pattern: empty (sub)expression
+ llvm::Regex regex_badCharArray(badCharArray);
struct RegexPatterns {
const char* badMemberChar = "";
@@ -54,14 +66,22 @@ void test_detected_faulty_patterns(){
const llvm::StringRef badMemberStrRef = "a*?";
// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: invalid regex pattern: repetition-operator operand invalid
- };
+ const char badMemberConstChar[1] = "";
+ // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: invalid regex pattern: empty (sub)expression
+
+ char badMemberCharArray[1] = "";
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: invalid regex pattern: empty (sub)expression
+ };
+
RegexPatterns Pats;
-
+
llvm::Regex re6(Pats.badMemberChar);
llvm::Regex re7(Pats.badMemberStr);
llvm::Regex re8(Pats.badMemberStrView);
llvm::Regex re9(Pats.badMemberStrRef);
+ llvm::Regex regex_badMemberConstStaticChar(Pats.badMemberConstChar);
+ llvm::Regex regex_badMemberCharArray(Pats.badMemberCharArray);
}
void test_no_detection_on_mutable(){
>From 2df860e922bbdca30a61d909c6494f30986527a5 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Fri, 7 Aug 2026 12:40:33 +0200
Subject: [PATCH 13/22] Convert documentation to the markdown format
---
.../checks/llvm/invalid-regex-pattern.md | 37 ++++++++++++++++++
.../checks/llvm/invalid-regex-pattern.rst | 39 -------------------
2 files changed, 37 insertions(+), 39 deletions(-)
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.md
delete mode 100644 clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.md b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.md
new file mode 100644
index 0000000000000..ea6af2a1bb27a
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.md
@@ -0,0 +1,37 @@
+# clang-tidy - llvm-invalid-regex-pattern
+
+## llvm-invalid-regex-pattern
+
+Detects malformed regex patterns defined in a single string literal
+to catch mistakes at compile time.
+It detects these string literals if they are defined in the regex constructor
+with a string literal, or stored in one of these non mutable containers:
+
+- `const std::string`
+- `const char*`
+- `const char[]`
+- `static const char[]`
+- `const llvm::StringRef`
+- `std::string_view`
+
+In the event that the patterns are stored as a class member, the check verifies
+the initialization value, if defined, even if its overwritten by the constructor.
+
+Example of detection:
+
+```cpp
+const std::string my_regex_pattern("[0-8"); // invalid regex pattern
+llvm::Regex my_regex(my_regex_pattern);
+```
+
+Example of member data being overwritten:
+
+```cpp
+class foo{
+public:
+ foo(llvm::StringRef regex_pat) : regex_p(regex_pat){};
+ const llvm::StringRef regex_pat = "("; // invalid regex pattern
+};
+foo bar("[0-9]"); // pattern not checked
+llvm::Regex my_regex(bar.regex_pat);
+```
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
deleted file mode 100644
index aaec7c456c74e..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.rst
+++ /dev/null
@@ -1,39 +0,0 @@
-.. title:: clang-tidy - llvm-invalid-regex-pattern
-
-llvm-invalid-regex-pattern
-==========================
-
-Detects malformed regex patterns defined in a single string literal
-to catch mistakes at compile time.
-It detects these string literals if they are defined in the regex constructor
-with a string literal, or stored in one of these non mutable container:
-
-- ``const std::string``
-- ``const char*``
-- ``const llvm::StringRef``
-- ``std::string_view``
-- ``char[]``
-- ``static char[]``
-- ``const char[]``
-
-In the event that the patterns are stored as a class member, the check verifies
-the initialization value, if defined, even if its overwritten by the constructor.
-
-Example of detection:
-
-.. code-block:: c++
-
- const std::string my_regex_pattern("[0-8"); // invalid regex pattern
- llvm::Regex my_regex(my_regex_pattern);
-
-Example of member data being overwritten:
-
-.. code-block:: c++
-
- class foo{
- public:
- foo(llvm::StringRef regex_pat) : regex_p(regex_pat){};
- const llvm_StringRef regex_pat = "("; // invalid regex pattern
- };
- foo bar("[0-9]");
- llvm::Regex my_regex(bar.regex_pat);
>From f617e588cd91244613a9cbed8eb20c5bfbb041a7 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Fri, 7 Aug 2026 14:12:17 +0200
Subject: [PATCH 14/22] Use assert
---
.../clang-tidy/llvm/InvalidRegexPatternCheck.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
index 4fd1d86daf4dd..ca74528332c30 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
@@ -60,7 +60,8 @@ void InvalidRegexPatternCheck::registerMatchers(MatchFinder *Finder) {
void InvalidRegexPatternCheck::check(const MatchFinder::MatchResult &Result) {
const auto *DetectedPattern =
Result.Nodes.getNodeAs<StringLiteral>("stringLiteral");
- if (DetectedPattern) {
+ assert(DetectedPattern && "stringLiteral must be bound in matcher");
+
const auto *FlagInt =
Result.Nodes.getNodeAs<IntegerLiteral>("regexFlagsInt");
const auto *FlagEnum =
@@ -75,7 +76,6 @@ void InvalidRegexPatternCheck::check(const MatchFinder::MatchResult &Result) {
if (!TestRegex.isValid(RegexError))
diag(DetectedPattern->getBeginLoc(), "invalid regex pattern: %0")
<< RegexError << DetectedPattern->getSourceRange();
- }
}
} // namespace clang::tidy::llvm_check
>From 27ab432b4f1366b711e50a77e5e6f29f085a7679 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Fri, 7 Aug 2026 14:15:00 +0200
Subject: [PATCH 15/22] Clang format
---
.../llvm/InvalidRegexPatternCheck.cpp | 46 +++++++++----------
1 file changed, 23 insertions(+), 23 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
index ca74528332c30..3d582ab54d0c4 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
@@ -33,15 +33,16 @@ void InvalidRegexPatternCheck::registerMatchers(MatchFinder *Finder) {
auto AnyCastedToStringRef = ignoringImplicit(anyOf(
stringLiteral().bind("stringLiteral"),
declRefExpr(to(varDecl(
- hasType(qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
- IsStdStringView, IsConstCharPtr,
- IsCharArray))),
+ hasType(
+ qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
+ IsStdStringView, IsConstCharPtr, IsCharArray))),
hasInitializer(anyOf(GetStringLiteralFromObject, GetStringLit))))),
- memberExpr(member(fieldDecl(
- hasType(qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
- IsStdStringView, IsConstCharPtr, IsCharArray))),
- hasInClassInitializer(
- anyOf(GetStringLiteralFromObject, GetStringLit)))))));
+ memberExpr(member(
+ fieldDecl(hasType(qualType(
+ anyOf(IsConstStdString, IsConstllvmStringRef,
+ IsStdStringView, IsConstCharPtr, IsCharArray))),
+ hasInClassInitializer(
+ anyOf(GetStringLiteralFromObject, GetStringLit)))))));
auto IsRegexFlagsType = ignoringParenImpCasts(
anyOf(integerLiteral().bind("regexFlagsInt"),
@@ -60,22 +61,21 @@ void InvalidRegexPatternCheck::registerMatchers(MatchFinder *Finder) {
void InvalidRegexPatternCheck::check(const MatchFinder::MatchResult &Result) {
const auto *DetectedPattern =
Result.Nodes.getNodeAs<StringLiteral>("stringLiteral");
- assert(DetectedPattern && "stringLiteral must be bound in matcher");
+ assert(DetectedPattern && "stringLiteral must be bound in matcher");
- const auto *FlagInt =
- Result.Nodes.getNodeAs<IntegerLiteral>("regexFlagsInt");
- const auto *FlagEnum =
- Result.Nodes.getNodeAs<EnumConstantDecl>("regexFlagEnum");
- unsigned int Flag = llvm::Regex::RegexFlags::NoFlags;
- if (FlagInt)
- Flag = FlagInt->getValue().getZExtValue();
- if (FlagEnum)
- Flag = FlagEnum->getInitVal().getZExtValue();
- const llvm::Regex TestRegex(DetectedPattern->getString(), Flag);
- std::string RegexError;
- if (!TestRegex.isValid(RegexError))
- diag(DetectedPattern->getBeginLoc(), "invalid regex pattern: %0")
- << RegexError << DetectedPattern->getSourceRange();
+ const auto *FlagInt = Result.Nodes.getNodeAs<IntegerLiteral>("regexFlagsInt");
+ const auto *FlagEnum =
+ Result.Nodes.getNodeAs<EnumConstantDecl>("regexFlagEnum");
+ unsigned int Flag = llvm::Regex::RegexFlags::NoFlags;
+ if (FlagInt)
+ Flag = FlagInt->getValue().getZExtValue();
+ if (FlagEnum)
+ Flag = FlagEnum->getInitVal().getZExtValue();
+ const llvm::Regex TestRegex(DetectedPattern->getString(), Flag);
+ std::string RegexError;
+ if (!TestRegex.isValid(RegexError))
+ diag(DetectedPattern->getBeginLoc(), "invalid regex pattern: %0")
+ << RegexError << DetectedPattern->getSourceRange();
}
} // namespace clang::tidy::llvm_check
>From c26e4c953854db9e9cc573e1fe70ac3fa9aef5ef Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Mon, 10 Aug 2026 14:29:20 +0200
Subject: [PATCH 16/22] Update
clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
Co-authored-by: EugeneZelenko <eugene.zelenko at gmail.com>
---
clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
index cb6223a668344..d1b42e3421067 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.h
@@ -16,7 +16,7 @@ namespace clang::tidy::llvm_check {
/// Detects malformed regex patterns used in ``llvm::Regex``.
///
/// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/llvm/regex.html
+/// https://clang.llvm.org/extra/clang-tidy/checks/llvm/regex.html
class InvalidRegexPatternCheck : public ClangTidyCheck {
public:
InvalidRegexPatternCheck(StringRef Name, ClangTidyContext *Context)
>From b8158ca3ed51d89c0fc909d7f9ab519eadd0fb29 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Mon, 10 Aug 2026 14:29:43 +0200
Subject: [PATCH 17/22] Change order of new checks
---
clang-tools-extra/docs/ReleaseNotes.md | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index ba0db92414488..775435fd46eb7 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -92,18 +92,18 @@ infrastructure are described first, followed by tool-specific sections.
#### New checks
-- New {doc}`performance-expensive-value-or
- <clang-tidy/checks/performance/expensive-value-or>` check.
-
- Finds calls to `value_or` (and alternative spellings `valueOr`,
- `ValueOr`) on optional types where the return type is expensive to copy.
-
- New {doc}`llvm-invalid-regex-pattern
<clang-tidy/checks/llvm/invalid-regex-pattern>` check.
Detects malformed regex patterns defined in a single string literal
to catch mistakes at compile time.
+- New {doc}`performance-expensive-value-or
+ <clang-tidy/checks/performance/expensive-value-or>` check.
+
+ Finds calls to `value_or` (and alternative spellings `valueOr`,
+ `ValueOr`) on optional types where the return type is expensive to copy.
+
#### New check aliases
#### Changes in existing checks
>From bde9a4073275d27c6b2791deabf9e6e83e325540 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Wed, 19 Aug 2026 14:30:33 +0200
Subject: [PATCH 18/22] Apply suggestions from code review
Co-authored-by: Baranov Victor <bar.victor.2002 at gmail.com>
---
.../clang-tidy/llvm/InvalidRegexPatternCheck.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
index 3d582ab54d0c4..1481b489649f5 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
@@ -15,14 +15,13 @@ using namespace clang::ast_matchers;
namespace clang::tidy::llvm_check {
void InvalidRegexPatternCheck::registerMatchers(MatchFinder *Finder) {
- // main matcher
auto IsConstllvmStringRef = qualType(
isConstQualified(), hasUnqualifiedDesugaredType(recordType(hasDeclaration(
cxxRecordDecl(hasName("::llvm::StringRef"))))));
auto IsConstStdString = qualType(
isConstQualified(), hasUnqualifiedDesugaredType(recordType(hasDeclaration(
cxxRecordDecl(hasName("::std::basic_string"))))));
- auto GetStringLit = ignoringImplicit(stringLiteral().bind("stringLiteral"));
+ auto GetStringLiteral = ignoringImplicit(stringLiteral().bind("stringLiteral"));
auto GetStringLiteralFromObject =
ignoringImplicit(cxxConstructExpr(hasAnyArgument(GetStringLit)));
auto IsConstCharPtr = pointerType(pointee(builtinType(), isConstQualified()));
@@ -67,9 +66,10 @@ void InvalidRegexPatternCheck::check(const MatchFinder::MatchResult &Result) {
const auto *FlagEnum =
Result.Nodes.getNodeAs<EnumConstantDecl>("regexFlagEnum");
unsigned int Flag = llvm::Regex::RegexFlags::NoFlags;
- if (FlagInt)
+ if (const auto *FlagInt = Result.Nodes.getNodeAs<IntegerLiteral>("regexFlagsInt"))
Flag = FlagInt->getValue().getZExtValue();
- if (FlagEnum)
+ if (const auto *FlagEnum =
+ Result.Nodes.getNodeAs<EnumConstantDecl>("regexFlagEnum"))
Flag = FlagEnum->getInitVal().getZExtValue();
const llvm::Regex TestRegex(DetectedPattern->getString(), Flag);
std::string RegexError;
>From c110025e93ec4324212799b7f0aa97127505083a Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Wed, 19 Aug 2026 14:28:57 +0200
Subject: [PATCH 19/22] Move test to reflect check name
---
.../checkers/llvm/{regex.cpp => invalid-regex-pattern.cpp} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename clang-tools-extra/test/clang-tidy/checkers/llvm/{regex.cpp => invalid-regex-pattern.cpp} (100%)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvm/invalid-regex-pattern.cpp
similarity index 100%
rename from clang-tools-extra/test/clang-tidy/checkers/llvm/regex.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/llvm/invalid-regex-pattern.cpp
>From b4c14c50d063f640a91ce1f08986c42333b2d270 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Wed, 19 Aug 2026 14:29:14 +0200
Subject: [PATCH 20/22] Remove redundand/trivial note from docs
---
clang-tools-extra/docs/ReleaseNotes.md | 3 +--
.../docs/clang-tidy/checks/llvm/invalid-regex-pattern.md | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 775435fd46eb7..781bf6d0b9d24 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -95,8 +95,7 @@ infrastructure are described first, followed by tool-specific sections.
- New {doc}`llvm-invalid-regex-pattern
<clang-tidy/checks/llvm/invalid-regex-pattern>` check.
- Detects malformed regex patterns defined in a single string literal
- to catch mistakes at compile time.
+ Detects malformed regex patterns defined in a single string literal.
- New {doc}`performance-expensive-value-or
<clang-tidy/checks/performance/expensive-value-or>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.md b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.md
index ea6af2a1bb27a..403b19f693bbc 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/invalid-regex-pattern.md
@@ -2,8 +2,7 @@
## llvm-invalid-regex-pattern
-Detects malformed regex patterns defined in a single string literal
-to catch mistakes at compile time.
+Detects malformed regex patterns defined in a single string literal.
It detects these string literals if they are defined in the regex constructor
with a string literal, or stored in one of these non mutable containers:
>From 984cd6db2debbe5a440fd355820023ec71badbc8 Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Wed, 19 Aug 2026 14:29:26 +0200
Subject: [PATCH 21/22] Remove duplication
---
.../llvm/InvalidRegexPatternCheck.cpp | 23 ++++++++-----------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
index 1481b489649f5..5cb5a407a1cc9 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
@@ -29,19 +29,16 @@ void InvalidRegexPatternCheck::registerMatchers(MatchFinder *Finder) {
hasUnqualifiedDesugaredType(arrayType(hasElementType(builtinType()))));
auto IsStdStringView = qualType(hasUnqualifiedDesugaredType(recordType(
hasDeclaration(cxxRecordDecl(hasName("::std::basic_string_view"))))));
- auto AnyCastedToStringRef = ignoringImplicit(anyOf(
- stringLiteral().bind("stringLiteral"),
- declRefExpr(to(varDecl(
- hasType(
- qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
- IsStdStringView, IsConstCharPtr, IsCharArray))),
- hasInitializer(anyOf(GetStringLiteralFromObject, GetStringLit))))),
- memberExpr(member(
- fieldDecl(hasType(qualType(
- anyOf(IsConstStdString, IsConstllvmStringRef,
- IsStdStringView, IsConstCharPtr, IsCharArray))),
- hasInClassInitializer(
- anyOf(GetStringLiteralFromObject, GetStringLit)))))));
+ auto hasStringContainerType =
+ hasType(qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
+ IsStdStringView, IsConstCharPtr, IsCharArray)));
+ auto getString = anyOf(GetStringLiteralFromObject, GetStringLit);
+ auto AnyCastedToStringRef = ignoringImplicit(
+ anyOf(stringLiteral().bind("stringLiteral"),
+ declRefExpr(
+ to(varDecl(hasStringContainerType, hasInitializer(getString)))),
+ memberExpr(member(fieldDecl(hasStringContainerType,
+ hasInClassInitializer(getString))))));
auto IsRegexFlagsType = ignoringParenImpCasts(
anyOf(integerLiteral().bind("regexFlagsInt"),
>From 712b8e9ed73eb507fe5ceb24af4879ca3691b71c Mon Sep 17 00:00:00 2001
From: "F.Tibor" <tibi.furesz at gmail.com>
Date: Wed, 19 Aug 2026 14:35:23 +0200
Subject: [PATCH 22/22] Cleanup after suggestions
---
.../clang-tidy/llvm/InvalidRegexPatternCheck.cpp | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
index 5cb5a407a1cc9..beb76ccb7c1a1 100644
--- a/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/InvalidRegexPatternCheck.cpp
@@ -21,9 +21,10 @@ void InvalidRegexPatternCheck::registerMatchers(MatchFinder *Finder) {
auto IsConstStdString = qualType(
isConstQualified(), hasUnqualifiedDesugaredType(recordType(hasDeclaration(
cxxRecordDecl(hasName("::std::basic_string"))))));
- auto GetStringLiteral = ignoringImplicit(stringLiteral().bind("stringLiteral"));
+ auto GetStringLiteral =
+ ignoringImplicit(stringLiteral().bind("stringLiteral"));
auto GetStringLiteralFromObject =
- ignoringImplicit(cxxConstructExpr(hasAnyArgument(GetStringLit)));
+ ignoringImplicit(cxxConstructExpr(hasAnyArgument(GetStringLiteral)));
auto IsConstCharPtr = pointerType(pointee(builtinType(), isConstQualified()));
auto IsCharArray = qualType(
hasUnqualifiedDesugaredType(arrayType(hasElementType(builtinType()))));
@@ -32,7 +33,7 @@ void InvalidRegexPatternCheck::registerMatchers(MatchFinder *Finder) {
auto hasStringContainerType =
hasType(qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
IsStdStringView, IsConstCharPtr, IsCharArray)));
- auto getString = anyOf(GetStringLiteralFromObject, GetStringLit);
+ auto getString = anyOf(GetStringLiteralFromObject, GetStringLiteral);
auto AnyCastedToStringRef = ignoringImplicit(
anyOf(stringLiteral().bind("stringLiteral"),
declRefExpr(
@@ -59,14 +60,12 @@ void InvalidRegexPatternCheck::check(const MatchFinder::MatchResult &Result) {
Result.Nodes.getNodeAs<StringLiteral>("stringLiteral");
assert(DetectedPattern && "stringLiteral must be bound in matcher");
- const auto *FlagInt = Result.Nodes.getNodeAs<IntegerLiteral>("regexFlagsInt");
- const auto *FlagEnum =
- Result.Nodes.getNodeAs<EnumConstantDecl>("regexFlagEnum");
unsigned int Flag = llvm::Regex::RegexFlags::NoFlags;
- if (const auto *FlagInt = Result.Nodes.getNodeAs<IntegerLiteral>("regexFlagsInt"))
+ if (const auto *FlagInt =
+ Result.Nodes.getNodeAs<IntegerLiteral>("regexFlagsInt"))
Flag = FlagInt->getValue().getZExtValue();
if (const auto *FlagEnum =
- Result.Nodes.getNodeAs<EnumConstantDecl>("regexFlagEnum"))
+ Result.Nodes.getNodeAs<EnumConstantDecl>("regexFlagEnum"))
Flag = FlagEnum->getInitVal().getZExtValue();
const llvm::Regex TestRegex(DetectedPattern->getString(), Flag);
std::string RegexError;
More information about the cfe-commits
mailing list