https://github.com/vbvictor updated 
https://github.com/llvm/llvm-project/pull/131455

>From 0b98489770f380f209d7b7a0a9223dd80c782478 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2...@gmail.com>
Date: Sat, 15 Mar 2025 17:36:23 +0300
Subject: [PATCH] add new construct-reusable-objects-once check

---
 .../clang-tidy/performance/CMakeLists.txt     |   1 +
 .../ConstructReusableObjectsOnceCheck.cpp     | 104 +++++
 .../ConstructReusableObjectsOnceCheck.h       |  43 ++
 .../performance/PerformanceTidyModule.cpp     |   3 +
 clang-tools-extra/docs/ReleaseNotes.rst       |   6 +
 .../docs/clang-tidy/checks/list.rst           |   1 +
 .../construct-reusable-objects-once.rst       |  91 +++++
 .../construct-reusable-objects-once/regex.h   |  45 +++
 .../construct-reusable-objects-once.cpp       | 366 ++++++++++++++++++
 9 files changed, 660 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/performance/construct-reusable-objects-once.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/performance/Inputs/construct-reusable-objects-once/regex.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/performance/construct-reusable-objects-once.cpp

diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
index c6e547c5089fb..7e2684a481f2c 100644
--- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_clang_library(clangTidyPerformanceModule STATIC
   AvoidEndlCheck.cpp
+  ConstructReusableObjectsOnceCheck.cpp
   EnumSizeCheck.cpp
   FasterStringFindCheck.cpp
   ForRangeCopyCheck.cpp
diff --git 
a/clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.cpp
 
b/clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.cpp
new file mode 100644
index 0000000000000..afdf9dd0cbf57
--- /dev/null
+++ 
b/clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.cpp
@@ -0,0 +1,104 @@
+//===--- ConstructReusableObjectsOnceCheck.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 "ConstructReusableObjectsOnceCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::performance {
+
+namespace {
+
+const llvm::StringRef DefaultCheckedClasses =
+    "::std::basic_regex;::boost::basic_regex";
+const llvm::StringRef DefaultIgnoredFunctions = "::main";
+
+} // namespace
+
+ConstructReusableObjectsOnceCheck::ConstructReusableObjectsOnceCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      CheckedClasses(utils::options::parseStringList(
+          Options.get("CheckedClasses", DefaultCheckedClasses))),
+      IgnoredFunctions(utils::options::parseStringList(
+          Options.get("IgnoredFunctions", DefaultIgnoredFunctions))) {}
+
+void ConstructReusableObjectsOnceCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "CheckedClasses", DefaultCheckedClasses);
+  Options.store(Opts, "IgnoredFunctions", DefaultIgnoredFunctions);
+}
+
+void ConstructReusableObjectsOnceCheck::registerMatchers(MatchFinder *Finder) {
+  const auto ConstStrLiteralDecl =
+      varDecl(unless(parmVarDecl()), hasType(constantArrayType()),
+              hasType(isConstQualified()),
+              hasInitializer(ignoringParenImpCasts(stringLiteral())));
+  const auto ConstPtrStrLiteralDecl = varDecl(
+      unless(parmVarDecl()),
+      hasType(pointerType(pointee(isAnyCharacter(), isConstQualified()))),
+      hasInitializer(ignoringParenImpCasts(stringLiteral())));
+
+  const auto ConstNumberLiteralDecl =
+      varDecl(hasType(qualType(anyOf(isInteger(), realFloatingPointType()))),
+              hasType(isConstQualified()),
+              hasInitializer(ignoringParenImpCasts(
+                  anyOf(integerLiteral(), floatLiteral()))),
+              unless(parmVarDecl()));
+
+  const auto ConstEnumLiteralDecl = varDecl(
+      unless(parmVarDecl()), hasType(hasUnqualifiedDesugaredType(enumType())),
+      hasType(isConstQualified()),
+      hasInitializer(declRefExpr(to(enumConstantDecl()))));
+
+  const auto ConstLiteralArg = expr(ignoringParenImpCasts(
+      anyOf(stringLiteral(), integerLiteral(), floatLiteral(),
+            declRefExpr(to(enumConstantDecl())),
+            declRefExpr(hasDeclaration(
+                anyOf(ConstNumberLiteralDecl, ConstPtrStrLiteralDecl,
+                      ConstStrLiteralDecl, ConstEnumLiteralDecl))))));
+
+  const auto ConstructorCall = cxxConstructExpr(
+      hasDeclaration(cxxConstructorDecl(
+          ofClass(cxxRecordDecl(hasAnyName(CheckedClasses)).bind("class")))),
+      unless(hasAnyArgument(expr(unless(ConstLiteralArg)))));
+
+  Finder->addMatcher(
+      varDecl(unless(hasGlobalStorage()), hasInitializer(ConstructorCall),
+              hasAncestor(functionDecl(unless(hasAnyName(IgnoredFunctions)))
+                              .bind("function")))
+          .bind("var"),
+      this);
+}
+
+void ConstructReusableObjectsOnceCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  if (const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var")) {
+    const auto *Class = Result.Nodes.getNodeAs<CXXRecordDecl>("class");
+    assert(Class);
+
+    const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("function");
+    assert(Function);
+
+    diag(Var->getLocation(),
+         "variable '%0' of type '%1' is constructed with only constant "
+         "literals on each invocation of '%2'; make this variable 'static', "
+         "declare as a global variable or move to a class member to avoid "
+         "repeated constructions")
+        << Var->getName() << Class->getQualifiedNameAsString()
+        << Function->getQualifiedNameAsString();
+  }
+}
+
+} // namespace clang::tidy::performance
diff --git 
a/clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.h 
b/clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.h
new file mode 100644
index 0000000000000..1af482354625f
--- /dev/null
+++ 
b/clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.h
@@ -0,0 +1,43 @@
+//===--- ConstructReusableObjectsOnceCheck.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_PERFORMANCE_CONSTRUCTREUSABLEOBJECTSONCECHECK_H
+#define 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_CONSTRUCTREUSABLEOBJECTSONCECHECK_H
+
+#include "../ClangTidyCheck.h"
+#include <optional>
+#include <vector>
+
+namespace clang::tidy::performance {
+
+/// Finds variable declarations of expensive-to-construct classes that are
+/// constructed from only constant literals and so can be reused.
+///
+/// For the user-facing documentation see:
+/// 
http://clang.llvm.org/extra/clang-tidy/checks/performance/construct-reusable-objects-once.html
+class ConstructReusableObjectsOnceCheck : public ClangTidyCheck {
+public:
+  ConstructReusableObjectsOnceCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+
+private:
+  std::vector<llvm::StringRef> CheckedClasses;
+  std::vector<llvm::StringRef> IgnoredFunctions;
+};
+
+} // namespace clang::tidy::performance
+
+#endif // 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_CONSTRUCTREUSABLEOBJECTSONCECHECK_H
diff --git a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp 
b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
index 9e0fa6f88b36a..8c1ea1c22cff3 100644
--- a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
@@ -10,6 +10,7 @@
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
 #include "AvoidEndlCheck.h"
+#include "ConstructReusableObjectsOnceCheck.h"
 #include "EnumSizeCheck.h"
 #include "FasterStringFindCheck.h"
 #include "ForRangeCopyCheck.h"
@@ -36,6 +37,8 @@ class PerformanceModule : public ClangTidyModule {
 public:
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
     CheckFactories.registerCheck<AvoidEndlCheck>("performance-avoid-endl");
+    CheckFactories.registerCheck<ConstructReusableObjectsOnceCheck>(
+        "performance-construct-reusable-objects-once");
     CheckFactories.registerCheck<EnumSizeCheck>("performance-enum-size");
     CheckFactories.registerCheck<FasterStringFindCheck>(
         "performance-faster-string-find");
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 0ad52f83fad85..ac4b6b4726073 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -106,6 +106,12 @@ New checks
   Finds unintended character output from ``unsigned char`` and ``signed char``
   to an ``ostream``.
 
+- New :doc:`performance-construct-reusable-objects-once
+  <clang-tidy/checks/performance/construct-reusable-objects-once>` check.
+
+  Finds variable declarations of expensive-to-construct classes that are
+  constructed from only constant literals and so can be reused.
+
 - New :doc:`readability-ambiguous-smartptr-reset-call
   <clang-tidy/checks/readability/ambiguous-smartptr-reset-call>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index c73bc8bff3539..48f99b54fcca7 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -331,6 +331,7 @@ Clang-Tidy Checks
    :doc:`openmp-exception-escape <openmp/exception-escape>`,
    :doc:`openmp-use-default-none <openmp/use-default-none>`,
    :doc:`performance-avoid-endl <performance/avoid-endl>`, "Yes"
+   :doc:`performance-construct-reusable-objects-once 
<performance/construct-reusable-objects-once>`,
    :doc:`performance-enum-size <performance/enum-size>`,
    :doc:`performance-faster-string-find <performance/faster-string-find>`, 
"Yes"
    :doc:`performance-for-range-copy <performance/for-range-copy>`, "Yes"
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/performance/construct-reusable-objects-once.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/performance/construct-reusable-objects-once.rst
new file mode 100644
index 0000000000000..9b02533cd5adb
--- /dev/null
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/performance/construct-reusable-objects-once.rst
@@ -0,0 +1,91 @@
+.. title:: clang-tidy - performance-construct-reusable-objects-once
+
+performance-construct-reusable-objects-once
+===========================================
+
+Finds variable declarations of expensive-to-construct classes that are
+constructed from only constant literals and so can be reused. These objects
+should be made ``static``, declared as a global variable or moved to a class
+member to avoid repeated construction costs on each function invocation.
+
+This check is particularly useful for identifying inefficiently constructed
+regular expressions since their constructors are relatively expensive compared
+to their usage, so creating them repeatedly with the same pattern can
+significantly impact program performance.
+
+Example:
+
+.. code-block:: c++
+
+  void parse() {
+    std::regex r("pattern");  // warning
+    // ...
+  }
+
+The more efficient version could be any of the following:
+
+.. code-block:: c++
+
+  void parse() {
+    static std::regex r("pattern");  // static constructed only once
+    // ...
+  }
+
+.. code-block:: c++
+  
+  std::regex r("pattern");  // global variable constructed only once
+
+  void parse() {
+    // ...
+  }
+
+.. code-block:: c++
+
+  class Parser {
+    void parse() {
+      // ...
+    }
+
+    std::regex r{"pattern"}; // class member constructed only once
+  }
+
+
+Known Limitations
+-----------------
+
+The check will not analyze variables that are template dependent.
+
+.. code-block:: c++
+
+  template <typename T>
+  void parse() {
+    std::basic_regex<T> r("pattern");  // no warning
+  }
+
+The check only warns on variables that are constructed from literals or const
+variables that are directly constructed from literals.
+
+.. code-block:: c++
+
+  void parse() {
+    const int var = 1;
+    const int constructed_from_var = var;
+    std::regex r1("pattern", var);  // warning
+    std::regex r2("pattern", constructed_from_var);  // no warning
+  }
+
+
+Options
+-------
+
+.. option:: CheckedClasses
+
+  Semicolon-separated list of fully qualified class names that are considered
+  expensive to construct and should be flagged by this check. Default is
+  `::std::basic_regex;::boost::basic_regex`.
+
+.. option:: IgnoredFunctions
+
+  Semicolon-separated list of fully qualified function names that are expected
+  to be called once so they should not be flagged by this check. Default is
+  `::main`.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/performance/Inputs/construct-reusable-objects-once/regex.h
 
b/clang-tools-extra/test/clang-tidy/checkers/performance/Inputs/construct-reusable-objects-once/regex.h
new file mode 100644
index 0000000000000..4ccf93775d969
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/performance/Inputs/construct-reusable-objects-once/regex.h
@@ -0,0 +1,45 @@
+#ifndef _REGEX_
+#define _REGEX_
+
+namespace std {
+
+template <typename T>
+class regex_traits {};
+
+namespace regex_constants {
+  enum syntax_option_type : unsigned int {
+    _S_icase           = 1 << 0,
+    _S_nosubs          = 1 << 1,
+    _S_basic           = 1 << 2,
+    _S_ECMAScript = 1 << 3,
+  };
+} // namespace regex_constants
+
+template<class CharT, class Traits = std::regex_traits<CharT>>
+class basic_regex {
+public:
+  typedef regex_constants::syntax_option_type flag_type;
+
+  static constexpr flag_type icase = 
regex_constants::syntax_option_type::_S_icase;
+  static constexpr flag_type nosubs = 
regex_constants::syntax_option_type::_S_nosubs;
+  static constexpr flag_type basic = 
regex_constants::syntax_option_type::_S_basic;
+  static constexpr flag_type ECMAScript = 
regex_constants::syntax_option_type::_S_ECMAScript;
+
+  basic_regex();
+  explicit basic_regex(const CharT* s, flag_type f = ECMAScript);
+  basic_regex(const CharT* s, unsigned int count, 
std::regex_constants::syntax_option_type f = ECMAScript);
+  basic_regex(const basic_regex& other);
+  basic_regex(basic_regex&& other) noexcept;
+  template<class ForwardIt>
+  basic_regex(ForwardIt first, ForwardIt last, 
std::regex_constants::syntax_option_type f = ECMAScript);
+
+  basic_regex& operator=(const basic_regex& other);
+  basic_regex& operator=(basic_regex&& other) noexcept;
+};
+
+typedef basic_regex<char> regex;
+typedef basic_regex<wchar_t> wregex;
+
+} // namespace std
+
+#endif // _REGEX_
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/performance/construct-reusable-objects-once.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/performance/construct-reusable-objects-once.cpp
new file mode 100644
index 0000000000000..622b7d65987df
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/performance/construct-reusable-objects-once.cpp
@@ -0,0 +1,366 @@
+// RUN: %check_clang_tidy %s performance-construct-reusable-objects-once %t -- 
\
+// RUN:   -config='{CheckOptions: { \
+// RUN:     performance-construct-reusable-objects-once.CheckedClasses: 
"::std::basic_regex;ReusableClass", \
+// RUN:     performance-construct-reusable-objects-once.IgnoredFunctions: 
"::main;::global::init;C::C;D::~D;ns::MyClass::foo", \
+// RUN:   }}' \
+// RUN: -- -fno-delayed-template-parsing 
-I%S/Inputs/construct-reusable-objects-once
+
+#include "regex.h"
+
+void PositiveEmpty() {
+  std::regex r1;
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveEmpty';
+  std::wregex wr1;
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: variable 'wr1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveEmpty';
+}
+
+void PositiveSugared() {
+  using my_using_regex = std::regex;
+  my_using_regex r1;
+  // CHECK-MESSAGES: [[@LINE-1]]:18: warning: variable 'r1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveSugared';
+
+  typedef std::wregex my_typedef_regex;
+  my_typedef_regex wr1;
+  // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'wr1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveSugared';
+
+  using std::regex;
+  regex r2;
+  // CHECK-MESSAGES: [[@LINE-1]]:9: warning: variable 'r2' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveSugared';
+}
+
+void PositiveWithLiterals() {
+  std::regex r1("x");
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithLiterals';
+  std::wregex wr1(L"x");
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: variable 'wr1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithLiterals';
+  std::regex r2("x", 1);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r2' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithLiterals';
+  std::wregex wr2(L"x", 2);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: variable 'wr2' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithLiterals';
+}
+
+const char* const text = "";
+const char text2[] = "";
+
+const wchar_t* const wtext = L"";
+const wchar_t wtext2[] = L"";
+
+const int c_i = 1;
+constexpr int ce_i = 1;
+
+void PositiveWithVariables() {
+  std::regex r1("x", c_i);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+  std::regex r2("x", ce_i);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r2' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+
+  std::regex r3(text);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r3' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+  std::wregex wr3(wtext);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: variable 'wr3' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+  std::regex r4(text2);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r4' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+  std::wregex wr4(wtext2);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: variable 'wr4' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+
+  std::regex r5(text, 1);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r5' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+  std::wregex wr5(wtext, 2);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: variable 'wr5' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+  std::regex r6(text2, 3);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r6' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+  std::wregex wr6(wtext2, 4);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: variable 'wr6' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+
+  // Local variables constructed from literals
+  const char* const ltext = "";
+  const wchar_t* const wltext = L"";
+  const int l_i = 1;
+  constexpr int l_ce_i = 1;
+
+  std::regex r7(ltext, 7);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r7' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+  std::wregex wr7(wltext, 8);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: variable 'wr7' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+
+  std::regex r8(text, 1, std::regex::icase);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r8' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+  std::wregex wr8(wtext, 2, std::regex::icase);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: variable 'wr8' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+
+  std::regex r9(text, l_i, std::regex::icase);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r9' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+  std::regex r10(text, l_ce_i, std::regex::icase);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r10' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveWithVariables';
+}
+
+void PositiveNested() {
+  if (true) {
+    const int i = 0;
+    while (true) {
+      std::regex r1("x", i);
+      // CHECK-MESSAGES: [[@LINE-1]]:18: warning: variable 'r1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveNested';
+    }
+  }
+}
+
+void PositiveFromTemporary() {
+  auto r1 = std::regex("x");
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'r1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveFromTemporary';
+  auto wr1 = std::wregex(L"x", 0, std::regex::ECMAScript);
+  // CHECK-MESSAGES: [[@LINE-1]]:8: warning: variable 'wr1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveFromTemporary';
+}
+
+static void PositiveStaticFunction() {
+  const int l_i = 1;
+  constexpr int l_ce_i = 1;
+
+  std::regex r1(text, l_i, std::regex::icase);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveStaticFunction';
+  std::regex r2(text, l_ce_i, std::regex::icase);
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r2' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveStaticFunction';
+}
+
+class PositiveClass {
+  PositiveClass() {
+    std::regex r1("text");
+    // CHECK-MESSAGES: [[@LINE-1]]:16: warning: variable 'r1' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveClass::PositiveClass';
+  }
+
+  void foo() {
+    std::regex r2("text");
+    // CHECK-MESSAGES: [[@LINE-1]]:16: warning: variable 'r2' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveClass::foo';
+  }
+
+  static void bar() {
+    std::regex r3("text");
+    // CHECK-MESSAGES: [[@LINE-1]]:16: warning: variable 'r3' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'PositiveClass::bar';
+  }
+
+};
+
+// All enum variations
+
+enum En1 {
+  e1
+};
+
+enum class En2 {
+  e2
+};
+
+enum class En3 : short {
+  e3
+};
+
+enum En4 : short {
+  e4
+};
+
+template <typename T>
+struct ReusableClass {
+  ReusableClass(float f) {}
+  ReusableClass(const char* ptr) {}
+  ReusableClass(int i) {}
+  ReusableClass(En1 e1) {}
+  ReusableClass(En2 e2) {}
+  ReusableClass(En3 e3) {}
+  ReusableClass(En4 e4) {}
+};
+
+void PositiveAllLiteralTypes() {
+  ReusableClass<int> rc1(1);
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'rc1' of type 
'ReusableClass' is constructed with only constant literals on each invocation 
of 'PositiveAllLiteralTypes';
+  ReusableClass<int> rc2(1.0f);
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'rc2' of type 
'ReusableClass' is constructed with only constant literals on each invocation 
of 'PositiveAllLiteralTypes';
+  ReusableClass<int> rc3("x");
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'rc3' of type 
'ReusableClass' is constructed with only constant literals on each invocation 
of 'PositiveAllLiteralTypes';
+  ReusableClass<int> rc4(e1);
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'rc4' of type 
'ReusableClass' is constructed with only constant literals on each invocation 
of 'PositiveAllLiteralTypes';
+  ReusableClass<int> rc5(En2::e2);
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'rc5' of type 
'ReusableClass' is constructed with only constant literals on each invocation 
of 'PositiveAllLiteralTypes';
+  ReusableClass<int> rc6(En3::e3);
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'rc6' of type 
'ReusableClass' is constructed with only constant literals on each invocation 
of 'PositiveAllLiteralTypes';
+  ReusableClass<int> rc7(e4);
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'rc7' of type 
'ReusableClass' is constructed with only constant literals on each invocation 
of 'PositiveAllLiteralTypes';
+
+  using my_enum = En4;
+  ReusableClass<int> rc8(my_enum::e4);
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'rc8' of type 
'ReusableClass' is constructed with only constant literals on each invocation 
of 'PositiveAllLiteralTypes';
+
+  const En2 my_e2 = En2::e2;
+  ReusableClass<int> rc9(my_e2);
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'rc9' of type 
'ReusableClass' is constructed with only constant literals on each invocation 
of 'PositiveAllLiteralTypes';
+}
+
+template <typename T>
+void PositiveTemplated() {
+  ReusableClass<int> rc1(1); 
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'rc1' of type 
'ReusableClass' is constructed with only constant literals on each invocation 
of 'PositiveTemplated'
+}
+
+// Negative cases
+
+int mi = 0;
+auto fl = std::regex::basic;
+
+// can not detect this case since 'std::regex::basic' is already a const 
variable,
+// and we only match variables constructed from literals
+const auto fl2 = std::regex::basic;
+
+void NegativeVariables() {
+  int l_mi = 1;
+  const auto l_fl = std::regex::ECMAScript;
+  auto l_fl2 = std::regex::basic;
+  
+  std::regex r1("x", mi);
+  std::regex r2("x", l_mi);
+  std::regex r3("x", 0, fl);
+  std::regex r4("x", 0, fl2);
+  std::regex r5("x", 0, l_fl);
+  std::regex r6("x", 0, l_fl2);
+}
+
+void NegativeOperators() {
+  int a = 0;
+  std::regex r("x", a);
+
+  // Can not detect assignment operator calls and copy constructors
+  r = std::regex("x2");
+  std::regex r2(r);
+  r = r2;
+}
+
+template <typename T>
+void NegativeTemplated() {
+  // currently we do not support ParenListExpr that is generated instead of 
ctor-call
+  ReusableClass<T> rc1(1);
+}
+
+struct RegexParamProvider {
+  int get_int() { return 0; }
+  const char* get_char() { return 0; }
+  const char* operator[] (int) {
+    return 0;
+  }
+};
+
+void NegativeWithVariables() {
+  int j = 1;
+  std::regex r1("x", j);
+
+  auto l = std::regex::basic;
+  std::regex r2("x", 1, l);
+
+  char* c;
+  std::regex r3(c, 1);
+
+  RegexParamProvider p;
+
+  std::regex r4("text", p.get_int());
+  std::regex r5(p[1]);
+  std::regex r6(p.get_char());
+}
+
+void NegativeFromFunction1(int i) {
+  std::regex r("x", i);
+}
+
+void NegativeFromFunction2(const int i) {
+  std::regex r("x", i);
+}
+
+void NegativeFromFunction3(const char* c) {
+  std::regex r(c);
+}
+
+void NegativeFromFunction4(const char* c = "default") {
+  std::regex r(c);
+}
+
+// Negative global variables
+
+std::regex gr1("x");
+std::wregex wgr1(L"x");
+
+static std::regex sgr1("x");
+static std::wregex swgr1(L"x");
+
+void NegativeStatic() {
+  static std::regex r("x");
+  static std::wregex wr(L"x");
+  static std::regex r1("x", 1);
+  static std::wregex wr1(L"x", 2);
+}
+
+class NegativeClass {
+  NegativeClass() : r("x") {
+    r = std::regex("x2");
+    static std::regex r2("x");
+  }
+
+  NegativeClass(const char* c) {
+    std::regex r2(c);
+  }
+
+  void NegativeMethod(const char* c = "some value") {
+    std::regex r3(c);
+  }
+
+  std::regex r;
+};
+
+
+// Ignored functions check
+
+int main() {
+  std::regex r1("x");
+}
+
+namespace global {
+
+void init() {
+  std::regex r("x");
+}
+
+} // namespace global 
+
+void init() {
+  std::regex r("x");
+  // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'init';
+}
+
+class C {
+ public:
+  C() {
+    std::regex r("x");
+  }
+
+  ~C() {
+    std::regex r("x");
+    // CHECK-MESSAGES: [[@LINE-1]]:16: warning: variable 'r' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'C::~C';
+  }
+};
+
+class D {
+ public:
+  D() {
+    std::regex r("x");
+    // CHECK-MESSAGES: [[@LINE-1]]:16: warning: variable 'r' of type 
'std::basic_regex' is constructed with only constant literals on each 
invocation of 'D::D';
+  }
+
+  ~D() {
+    std::regex r("x");
+  }
+};
+
+namespace ns {
+
+class MyClass {
+ public:
+  void foo() {
+    std::regex r("x");
+  }
+};
+
+} // namespace ns

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to