[clang-tools-extra] [clang-tidy] Add new `construct-reusable-objects-once` check (PR #131455)
Baranov Victor via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 28 09:44:44 PDT 2025
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.2002 at gmail.com>
Date: Sat, 15 Mar 2025 17:36:23 +0300
Subject: [PATCH 1/2] 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
>From a0885161f67a866df33e4fd23dd6854de5d741a8 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Fri, 28 Mar 2025 19:44:31 +0300
Subject: [PATCH 2/2] WIP: added `const` for variable declarations
---
.../ConstructReusableObjectsOnceCheck.cpp | 1 +
.../construct-reusable-objects-once.cpp | 266 +++++++++---------
2 files changed, 135 insertions(+), 132 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.cpp b/clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.cpp
index afdf9dd0cbf57..2c31f54c8e2f7 100644
--- a/clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/ConstructReusableObjectsOnceCheck.cpp
@@ -76,6 +76,7 @@ void ConstructReusableObjectsOnceCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
varDecl(unless(hasGlobalStorage()), hasInitializer(ConstructorCall),
+ hasType(isConstQualified()),
hasAncestor(functionDecl(unless(hasAnyName(IgnoredFunctions)))
.bind("function")))
.bind("var"),
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
index 622b7d65987df..4cbf7931227df 100644
--- 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
@@ -8,35 +8,35 @@
#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';
+ const std::regex r1;
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r1' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveEmpty';
+ const std::wregex wr1;
+ // CHECK-MESSAGES: [[@LINE-1]]:21: 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';
+ const my_using_regex r1;
+ // CHECK-MESSAGES: [[@LINE-1]]:24: 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';
+ const my_typedef_regex wr1;
+ // CHECK-MESSAGES: [[@LINE-1]]:26: 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';
+ const regex r2;
+ // CHECK-MESSAGES: [[@LINE-1]]:15: 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 std::regex r1("x");
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r1' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithLiterals';
+ const std::wregex wr1(L"x");
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: variable 'wr1' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithLiterals';
+ const std::regex r2("x", 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r2' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithLiterals';
+ const std::wregex wr2(L"x", 2);
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: variable 'wr2' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithLiterals';
}
const char* const text = "";
@@ -49,28 +49,28 @@ 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';
+ const std::regex r1("x", c_i);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r1' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+ const std::regex r2("x", ce_i);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r2' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+
+ const std::regex r3(text);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r3' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+ const std::wregex wr3(wtext);
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: variable 'wr3' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+ const std::regex r4(text2);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r4' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+ const std::wregex wr4(wtext2);
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: variable 'wr4' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+
+ const std::regex r5(text, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r5' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+ const std::wregex wr5(wtext, 2);
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: variable 'wr5' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+ const std::regex r6(text2, 3);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r6' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+ const std::wregex wr6(wtext2, 4);
+ // CHECK-MESSAGES: [[@LINE-1]]:21: 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 = "";
@@ -78,63 +78,63 @@ void PositiveWithVariables() {
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';
+ const std::regex r7(ltext, 7);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r7' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+ const std::wregex wr7(wltext, 8);
+ // CHECK-MESSAGES: [[@LINE-1]]:21: 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';
+ const std::regex r8(text, 1, std::regex::icase);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r8' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+ const std::wregex wr8(wtext, 2, std::regex::icase);
+ // CHECK-MESSAGES: [[@LINE-1]]:21: 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';
+ const std::regex r9(text, l_i, std::regex::icase);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r9' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveWithVariables';
+ const std::regex r10(text, l_ce_i, std::regex::icase);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: 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';
+ const std::regex r1("x", i);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: 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';
+ const auto r1 = std::regex("x");
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: variable 'r1' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveFromTemporary';
+ const auto wr1 = std::wregex(L"x", 0, std::regex::ECMAScript);
+ // CHECK-MESSAGES: [[@LINE-1]]:14: 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';
+ const std::regex r1(text, l_i, std::regex::icase);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: variable 'r1' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveStaticFunction';
+ const std::regex r2(text, l_ce_i, std::regex::icase);
+ // CHECK-MESSAGES: [[@LINE-1]]:20: 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';
+ const std::regex r1("text");
+ // CHECK-MESSAGES: [[@LINE-1]]:22: 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';
+ const std::regex r2("text");
+ // CHECK-MESSAGES: [[@LINE-1]]:22: 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';
+ const std::regex r3("text");
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: variable 'r3' of type 'std::basic_regex' is constructed with only constant literals on each invocation of 'PositiveClass::bar';
}
};
@@ -169,38 +169,43 @@ struct ReusableClass {
};
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';
+ const ReusableClass<int> rc1(1);
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: variable 'rc1' of type 'ReusableClass' is constructed with only constant literals on each invocation of 'PositiveAllLiteralTypes';
+ const ReusableClass<int> rc2(1.0f);
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: variable 'rc2' of type 'ReusableClass' is constructed with only constant literals on each invocation of 'PositiveAllLiteralTypes';
+ const ReusableClass<int> rc3("x");
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: variable 'rc3' of type 'ReusableClass' is constructed with only constant literals on each invocation of 'PositiveAllLiteralTypes';
+ const ReusableClass<int> rc4(e1);
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: variable 'rc4' of type 'ReusableClass' is constructed with only constant literals on each invocation of 'PositiveAllLiteralTypes';
+ const ReusableClass<int> rc5(En2::e2);
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: variable 'rc5' of type 'ReusableClass' is constructed with only constant literals on each invocation of 'PositiveAllLiteralTypes';
+ const ReusableClass<int> rc6(En3::e3);
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: variable 'rc6' of type 'ReusableClass' is constructed with only constant literals on each invocation of 'PositiveAllLiteralTypes';
+ const ReusableClass<int> rc7(e4);
+ // CHECK-MESSAGES: [[@LINE-1]]:28: 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 ReusableClass<int> rc8(my_enum::e4);
+ // CHECK-MESSAGES: [[@LINE-1]]:28: 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';
+ const ReusableClass<int> rc9(my_e2);
+ // CHECK-MESSAGES: [[@LINE-1]]:28: 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'
+ const ReusableClass<int> rc1(1);
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: variable 'rc1' of type 'ReusableClass' is constructed with only constant literals on each invocation of 'PositiveTemplated'
}
// Negative cases
+void NegativeNonConst() {
+ std::regex r1("x");
+ ReusableClass<int> rc1(1);
+}
+
int mi = 0;
auto fl = std::regex::basic;
@@ -213,28 +218,25 @@ void NegativeVariables() {
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);
+ const std::regex r1("x", mi);
+ const std::regex r2("x", l_mi);
+ const std::regex r3("x", 0, fl);
+ const std::regex r4("x", 0, fl2);
+ const std::regex r5("x", 0, l_fl);
+ const std::regex r6("x", 0, l_fl2);
}
void NegativeOperators() {
int a = 0;
- std::regex r("x", a);
+ const std::regex r("x", a);
- // Can not detect assignment operator calls and copy constructors
- r = std::regex("x2");
- std::regex r2(r);
- r = r2;
+ const std::regex r2(r);
}
template <typename T>
void NegativeTemplated() {
// currently we do not support ParenListExpr that is generated instead of ctor-call
- ReusableClass<T> rc1(1);
+ const ReusableClass<T> rc1(1);
}
struct RegexParamProvider {
@@ -247,64 +249,64 @@ struct RegexParamProvider {
void NegativeWithVariables() {
int j = 1;
- std::regex r1("x", j);
+ const std::regex r1("x", j);
auto l = std::regex::basic;
- std::regex r2("x", 1, l);
+ const std::regex r2("x", 1, l);
char* c;
- std::regex r3(c, 1);
+ const 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());
+ const std::regex r4("text", p.get_int());
+ const std::regex r5(p[1]);
+ const std::regex r6(p.get_char());
}
void NegativeFromFunction1(int i) {
- std::regex r("x", i);
+ const std::regex r("x", i);
}
void NegativeFromFunction2(const int i) {
- std::regex r("x", i);
+ const std::regex r("x", i);
}
void NegativeFromFunction3(const char* c) {
- std::regex r(c);
+ const std::regex r(c);
}
void NegativeFromFunction4(const char* c = "default") {
- std::regex r(c);
+ const std::regex r(c);
}
// Negative global variables
-std::regex gr1("x");
-std::wregex wgr1(L"x");
+const std::regex gr1("x");
+const std::wregex wgr1(L"x");
-static std::regex sgr1("x");
-static std::wregex swgr1(L"x");
+static const std::regex sgr1("x");
+static const 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);
+ static const std::regex r("x");
+ static const std::wregex wr(L"x");
+ static const std::regex r1("x", 1);
+ static const std::wregex wr1(L"x", 2);
}
class NegativeClass {
NegativeClass() : r("x") {
r = std::regex("x2");
- static std::regex r2("x");
+ static const std::regex r2("x");
}
NegativeClass(const char* c) {
- std::regex r2(c);
+ const std::regex r2(c);
}
void NegativeMethod(const char* c = "some value") {
- std::regex r3(c);
+ const std::regex r3(c);
}
std::regex r;
@@ -314,43 +316,43 @@ class NegativeClass {
// Ignored functions check
int main() {
- std::regex r1("x");
+ const std::regex r1("x");
}
namespace global {
void init() {
- std::regex r("x");
+ const 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';
+ const std::regex r("x");
+ // CHECK-MESSAGES: [[@LINE-1]]:20: 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");
+ const 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';
+ const std::regex r("x");
+ // CHECK-MESSAGES: [[@LINE-1]]:22: 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';
+ const std::regex r("x");
+ // CHECK-MESSAGES: [[@LINE-1]]:22: 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");
+ const std::regex r("x");
}
};
@@ -359,7 +361,7 @@ namespace ns {
class MyClass {
public:
void foo() {
- std::regex r("x");
+ const std::regex r("x");
}
};
More information about the cfe-commits
mailing list