[clang-tools-extra] [clang-tidy] Add modernize-make-direct check (PR #118120)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 11 12:16:58 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tidy
@llvm/pr-subscribers-clang-tools-extra
Author: Helmut Januschka (hjanuschka)
<details>
<summary>Changes</summary>
Adds a new check that converts std::make_* function calls to direct constructor calls using CTAD. Transforms make_optional, make_unique, make_shared and make_pair into their equivalent direct constructor calls, leveraging C++17's class template argument deduction.
---
Full diff: https://github.com/llvm/llvm-project/pull/118120.diff
7 Files Affected:
- (modified) clang-tools-extra/clang-tidy/modernize/CMakeLists.txt (+1)
- (added) clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.cpp (+78)
- (added) clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.h (+39)
- (modified) clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp (+3)
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+6)
- (added) clang-tools-extra/docs/clang-tidy/checks/modernize/make-direct.rst (+46)
- (added) clang-tools-extra/test/clang-tidy/checkers/modernize/make-direct-check.cpp (+76)
``````````diff
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index bab1167fb15ff..56273f914178b 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -50,6 +50,7 @@ add_clang_library(clangTidyModernizeModule STATIC
UseTransparentFunctorsCheck.cpp
UseUncaughtExceptionsCheck.cpp
UseUsingCheck.cpp
+ MakeFunctionToDirectCheck.cpp
LINK_LIBS
clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.cpp
new file mode 100644
index 0000000000000..f9eabbaefb46f
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.cpp
@@ -0,0 +1,78 @@
+//===--- MakeFunctionToDirectCheck.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 "MakeFunctionToDirectCheck.h"
+#include "../utils/TransformerClangTidyCheck.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
+#include "clang/Tooling/Transformer/RewriteRule.h"
+#include "clang/Tooling/Transformer/Stencil.h"
+
+using namespace ::clang::ast_matchers;
+using namespace ::clang::transformer;
+
+namespace clang::tidy::modernize {
+
+namespace {
+
+RewriteRuleWith<std::string>
+makeFunctionToDirectCheckImpl(bool CheckMakePair, bool CheckMakeOptional,
+ bool CheckMakeTuple) {
+ std::vector<RewriteRuleWith<std::string>> Rules;
+
+ // Helper to create a rule for a specific make_* function
+ auto createRule = [](StringRef MakeFunction, StringRef DirectType) {
+ auto WarningMessage = cat("use class template argument deduction (CTAD) "
+ "instead of ",
+ MakeFunction);
+
+ return makeRule(
+ callExpr(callee(functionDecl(hasName(MakeFunction))),
+ unless(hasParent(implicitCastExpr(hasImplicitDestinationType(
+ qualType(hasCanonicalType(qualType(asString("void")))))))))
+ .bind("make_call"),
+ changeTo(node("make_call"),
+ cat(DirectType, "(", callArgs("make_call"), ")")),
+ WarningMessage);
+ };
+
+ if (CheckMakeOptional) {
+ Rules.push_back(createRule("std::make_optional", "std::optional"));
+ }
+
+ if (CheckMakePair) {
+ Rules.push_back(createRule("std::make_pair", "std::pair"));
+ }
+
+ if (CheckMakeTuple) {
+ Rules.push_back(createRule("std::make_tuple", "std::tuple"));
+ }
+
+ return applyFirst(Rules);
+}
+
+} // namespace
+
+MakeFunctionToDirectCheck::MakeFunctionToDirectCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : utils::TransformerClangTidyCheck(Name, Context),
+ CheckMakePair(Options.get("CheckMakePair", true)),
+ CheckMakeOptional(Options.get("CheckMakeOptional", true)),
+ CheckMakeTuple(Options.get("CheckMakeTuple", true)) {
+ setRule(makeFunctionToDirectCheckImpl(CheckMakePair, CheckMakeOptional,
+ CheckMakeTuple));
+}
+
+void MakeFunctionToDirectCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "CheckMakePair", CheckMakePair);
+ Options.store(Opts, "CheckMakeOptional", CheckMakeOptional);
+ Options.store(Opts, "CheckMakeTuple", CheckMakeTuple);
+}
+
+} // namespace clang::tidy::modernize
\ No newline at end of file
diff --git a/clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.h b/clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.h
new file mode 100644
index 0000000000000..c3637b2bc00dc
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/MakeFunctionToDirectCheck.h
@@ -0,0 +1,39 @@
+//===--- MakeFunctionToDirectCheck.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_MODERNIZE_MAKEFUNCTIONTODIRECTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKEFUNCTIONTODIRECTCHECK_H
+
+#include "../utils/TransformerClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// Converts std::make_* function calls to direct constructor calls using
+/// class template argument deduction (CTAD).
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/make-direct.html
+class MakeFunctionToDirectCheck : public utils::TransformerClangTidyCheck {
+public:
+ MakeFunctionToDirectCheck(StringRef Name, ClangTidyContext *Context);
+
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus17;
+ }
+
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ const bool CheckMakePair;
+ const bool CheckMakeOptional;
+ const bool CheckMakeTuple;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKEFUNCTIONTODIRECTCHECK_H
\ No newline at end of file
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index e872759856f3c..4c6964a729346 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -16,6 +16,7 @@
#include "DeprecatedIosBaseAliasesCheck.h"
#include "LoopConvertCheck.h"
#include "MacroToEnumCheck.h"
+#include "MakeFunctionToDirectCheck.h"
#include "MakeSharedCheck.h"
#include "MakeUniqueCheck.h"
#include "MinMaxUseInitializerListCheck.h"
@@ -125,6 +126,8 @@ class ModernizeModule : public ClangTidyModule {
CheckFactories.registerCheck<UseUncaughtExceptionsCheck>(
"modernize-use-uncaught-exceptions");
CheckFactories.registerCheck<UseUsingCheck>("modernize-use-using");
+ CheckFactories.registerCheck<MakeFunctionToDirectCheck>(
+ "modernize-make-direct");
}
};
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 882ee0015df17..8917627b13ea0 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -124,6 +124,12 @@ New checks
pointer and store it as class members without handle the copy and move
constructors and the assignments.
+- New :doc:`modernize-make-direct <clang-tidy/checks/modernize/make-direct>` check.
+
+ Converts std::make_* function calls to direct constructor calls using CTAD.
+ Transforms make_optional, make_pair, and make_tuple into equivalent
+ direct constructor calls using C++17's class template argument deduction.
+
- New :doc:`bugprone-misleading-setter-of-reference
<clang-tidy/checks/bugprone/misleading-setter-of-reference>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/make-direct.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/make-direct.rst
new file mode 100644
index 0000000000000..b856c150f28cf
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/make-direct.rst
@@ -0,0 +1,46 @@
+.. title:: clang-tidy - modernize-make-direct
+
+modernize-make-direct
+=====================
+
+Replaces ``std::make_*`` function calls with direct constructor calls using class template
+argument deduction (CTAD).
+
+================================== ====================================
+ Before After
+---------------------------------- ------------------------------------
+``std::make_optional<int>(42)`` ``std::optional(42)``
+``std::make_pair(1, "test")`` ``std::pair(1, "test")``
+``std::make_tuple(1, 2.0, "hi")`` ``std::tuple(1, 2.0, "hi")``
+================================== ====================================
+
+.. note::
+
+ This check does not transform ``std::make_unique`` or ``std::make_shared`` because:
+
+ 1. These smart pointer types cannot be constructed using CTAD from raw pointers.
+ 2. ``std::make_shared`` provides performance benefits (single allocation) and
+ exception safety that would be lost with direct construction.
+ 3. Direct use of ``new`` is discouraged in modern C++ code.
+
+ Use the dedicated ``modernize-make-unique`` and ``modernize-make-shared`` checks
+ for transforming these functions.
+
+Options
+-------
+
+.. option:: CheckMakePair
+
+ When `true`, transforms ``std::make_pair`` calls to direct constructor calls.
+ Default is `true`.
+
+.. option:: CheckMakeOptional
+
+ When `true`, transforms ``std::make_optional`` calls to direct constructor calls.
+ Default is `true`.
+
+.. option:: CheckMakeTuple
+
+ When `true`, transforms ``std::make_tuple`` calls to direct constructor calls.
+ Default is `true`.
+
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/make-direct-check.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/make-direct-check.cpp
new file mode 100644
index 0000000000000..2a1fe4713ecb9
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/make-direct-check.cpp
@@ -0,0 +1,76 @@
+// RUN: %check_clang_tidy -std=c++17 %s modernize-make-direct %t
+
+namespace std {
+template<typename T>
+struct optional {
+ optional(const T&) {}
+};
+
+template<typename T>
+optional<T> make_optional(const T& t) { return optional<T>(t); }
+
+template<typename T>
+struct unique_ptr {
+ explicit unique_ptr(T*) {}
+};
+
+template<typename T, typename... Args>
+unique_ptr<T> make_unique(Args&&... args) {
+ return unique_ptr<T>(new T(args...));
+}
+
+template<typename T>
+struct shared_ptr {
+ shared_ptr(T*) {}
+};
+
+template<typename T, typename... Args>
+shared_ptr<T> make_shared(Args&&... args) {
+ return shared_ptr<T>(new T(args...));
+}
+
+template<typename T, typename U>
+struct pair {
+ T first;
+ U second;
+ pair(const T& x, const U& y) : first(x), second(y) {}
+};
+
+template<typename T, typename U>
+pair<T,U> make_pair(T&& t, U&& u) {
+ return pair<T,U>(t, u);
+}
+
+template<typename... T>
+struct tuple {
+ tuple(const T&... args) {}
+};
+
+template<typename... T>
+tuple<T...> make_tuple(T&&... t) {
+ return tuple<T...>(t...);
+}
+}
+
+struct Widget {
+ Widget(int x) {}
+};
+
+
+void basic_tests() {
+ auto o1 = std::make_optional<int>(42);
+ // CHECK-MESSAGES: warning: use class template argument deduction (CTAD) instead of std::make_optional [modernize-make-direct]
+ // CHECK-FIXES: auto o1 = std::optional(42);
+
+ // make_unique and make_shared are not transformed by this check
+ auto u1 = std::make_unique<Widget>(1);
+ auto s1 = std::make_shared<Widget>(2);
+
+ auto p1 = std::make_pair(1, "test");
+ // CHECK-MESSAGES: warning: use class template argument deduction (CTAD) instead of std::make_pair [modernize-make-direct]
+ // CHECK-FIXES: auto p1 = std::pair(1, "test");
+
+ auto t1 = std::make_tuple(1, 2.0, "hi");
+ // CHECK-MESSAGES: warning: use class template argument deduction (CTAD) instead of std::make_tuple [modernize-make-direct]
+ // CHECK-FIXES: auto t1 = std::tuple(1, 2.0, "hi");
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/118120
More information about the cfe-commits
mailing list