llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tools-extra
@llvm/pr-subscribers-clang-tidy
Author: AntonyCJ30
<details>
<summary>Changes</summary>
Fixes #<!-- -->165328
Adds a new clang-tidy check `modernize-default-arg-braced-init` that transforms
redundant constructor calls in default arguments to braced initializer lists.
**Example:**
```cpp
// Before
void bar(Box b = Box()) {}
// After
void bar(Box b = {}) {}
---
Full diff: https://github.com/llvm/llvm-project/pull/203474.diff
8 Files Affected:
- (modified) clang-tools-extra/clang-tidy/modernize/CMakeLists.txt (+1)
- (added) clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.cpp
(+62)
- (added) clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.h
(+40)
- (modified) clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
(+3)
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+8)
- (modified) clang-tools-extra/docs/clang-tidy/checks/list.rst (+1)
- (added)
clang-tools-extra/docs/clang-tidy/checks/modernize/default-arg-braced-init.rst
(+20)
- (added)
clang-tools-extra/test/clang-tidy/checkers/modernize/default-arg-braced-init.cpp
(+113)
``````````diff
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 2c5c44db587fe..4f27cfd776594 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -10,6 +10,7 @@ add_clang_library(clangTidyModernizeModule STATIC
AvoidSetjmpLongjmpCheck.cpp
AvoidVariadicFunctionsCheck.cpp
ConcatNestedNamespacesCheck.cpp
+ DefaultArgBracedInitCheck.cpp
DeprecatedHeadersCheck.cpp
DeprecatedIosBaseAliasesCheck.cpp
IntegralLiteralExpressionMatcher.cpp
diff --git
a/clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.cpp
b/clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.cpp
new file mode 100644
index 0000000000000..4b5bbd39f1d01
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.cpp
@@ -0,0 +1,62 @@
+//===--- DefaultArgBracedInitCheck.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 "DefaultArgBracedInitCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void DefaultArgBracedInitCheck::registerMatchers(MatchFinder *Finder) {
+
+Finder->addMatcher(
+ parmVarDecl(hasInitializer(cxxTemporaryObjectExpr(
+ argumentCountIs(0),
+ unless(hasDeclaration(cxxConstructorDecl(isExplicit())))
+ ).bind("ctor")))
+ .bind("param"),
+ this);
+}
+
+void DefaultArgBracedInitCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Ctor = Result.Nodes.getNodeAs<CXXTemporaryObjectExpr>("ctor");
+ const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("param");
+
+ if (!Ctor || !Param)
+ return;
+
+ // Skip if inside a macro
+ SourceLocation Loc = Ctor->getExprLoc();
+ if (Loc.isMacroID())
+ return;
+
+
+
+ // Type safety check
+ QualType ParamType = Param->getType()
+ .getCanonicalType()
+ .getNonReferenceType()
+ .getUnqualifiedType();
+
+ QualType CtorType = Ctor->getType()
+ .getCanonicalType()
+ .getNonReferenceType()
+ .getUnqualifiedType();
+
+ if (ParamType != CtorType)
+ return;
+
+ auto Diag = diag(Loc, "use braced initializer list for default argument");
+ CharSourceRange Range =
+ CharSourceRange::getTokenRange(Ctor->getBeginLoc(), Ctor->getEndLoc());
+ Diag << FixItHint::CreateReplacement(Range, "{}");
+}
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.h
b/clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.h
new file mode 100644
index 0000000000000..9e758c5344ff2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.h
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_DEFAULTARGBRACEDINITCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_DEFAULTARGBRACEDINITCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// Replaces redundant constructor calls in default arguments with braced
+/// initializer lists. For example, ``void bar(Box b = Box()) {}`` becomes
+/// ``void bar(Box b = {}) {}``.
+///
+/// For the user-facing documentation see:
+///
https://clang.llvm.org/extra/clang-tidy/checks/modernize/default-arg-braced-init.html
+class DefaultArgBracedInitCheck : public ClangTidyCheck {
+public:
+ DefaultArgBracedInitCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+ std::optional<TraversalKind> getCheckTraversalKind() const override {
+ return TK_IgnoreUnlessSpelledInSource;
+ }
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus11;
+ }
+};
+
+} // namespace clang::tidy::modernize
+
+#endif //
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_DEFAULTARGBRACEDINITCHECK_H
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index cc13da7535bcb..c5dea91e88025 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -14,6 +14,7 @@
#include "AvoidSetjmpLongjmpCheck.h"
#include "AvoidVariadicFunctionsCheck.h"
#include "ConcatNestedNamespacesCheck.h"
+#include "DefaultArgBracedInitCheck.h"
#include "DeprecatedHeadersCheck.h"
#include "DeprecatedIosBaseAliasesCheck.h"
#include "LoopConvertCheck.h"
@@ -77,6 +78,8 @@ class ModernizeModule : public ClangTidyModule {
"modernize-avoid-variadic-functions");
CheckFactories.registerCheck<ConcatNestedNamespacesCheck>(
"modernize-concat-nested-namespaces");
+ CheckFactories.registerCheck<DefaultArgBracedInitCheck>(
+ "modernize-default-arg-braced-init");
CheckFactories.registerCheck<DeprecatedHeadersCheck>(
"modernize-deprecated-headers");
CheckFactories.registerCheck<DeprecatedIosBaseAliasesCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst
b/clang-tools-extra/docs/ReleaseNotes.rst
index f1b49e2cb6056..b6fcc43dc74be 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -257,6 +257,14 @@ New checks
Finds cyclical initialization of static variables.
+- New :doc:`modernize-default-arg-braced-init
+ <clang-tidy/checks/modernize/default-arg-braced-init>` check.
+
+ Replaces redundant constructor calls in default arguments with braced
+ initializer lists. For example, ``void bar(Box b = Box()) {}`` becomes
+ ``void bar(Box b = {}) {}``. The check safely skips explicit constructors,
+ constructors with arguments, type mismatches, and macro expansions.
+
- New :doc:`modernize-use-std-bit
<clang-tidy/checks/modernize/use-std-bit>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 937b80da9b601..9537264de1272 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -294,6 +294,7 @@ Clang-Tidy Checks
:doc:`modernize-avoid-setjmp-longjmp <modernize/avoid-setjmp-longjmp>`,
:doc:`modernize-avoid-variadic-functions
<modernize/avoid-variadic-functions>`,
:doc:`modernize-concat-nested-namespaces
<modernize/concat-nested-namespaces>`, "Yes"
+ :doc:`modernize-default-arg-braced-init
<modernize/default-arg-braced-init>`, "Yes"
:doc:`modernize-deprecated-headers <modernize/deprecated-headers>`, "Yes"
:doc:`modernize-deprecated-ios-base-aliases
<modernize/deprecated-ios-base-aliases>`, "Yes"
:doc:`modernize-loop-convert <modernize/loop-convert>`, "Yes"
diff --git
a/clang-tools-extra/docs/clang-tidy/checks/modernize/default-arg-braced-init.rst
b/clang-tools-extra/docs/clang-tidy/checks/modernize/default-arg-braced-init.rst
new file mode 100644
index 0000000000000..c81be3f9bf368
--- /dev/null
+++
b/clang-tools-extra/docs/clang-tidy/checks/modernize/default-arg-braced-init.rst
@@ -0,0 +1,20 @@
+.. title:: clang-tidy - modernize-default-arg-braced-init
+
+modernize-default-arg-braced-init
+=================================
+
+Replaces explicit constructor calls in default arguments with a braced
+initializer list. This avoids unnecessarily repeating the type name in the
+function declaration.
+
+.. code:: c++
+
+ void func(std::string s = std::string());
+ void handle(Widget w = Widget());
+ void process(Box b = Box());
+
+ // transforms to:
+
+ void func(std::string s = {});
+ void handle(Widget w = {});
+ void process(Box b = {});
diff --git
a/clang-tools-extra/test/clang-tidy/checkers/modernize/default-arg-braced-init.cpp
b/clang-tools-extra/test/clang-tidy/checkers/modernize/default-arg-braced-init.cpp
new file mode 100644
index 0000000000000..f9b7e7829c9ab
--- /dev/null
+++
b/clang-tools-extra/test/clang-tidy/checkers/modernize/default-arg-braced-init.cpp
@@ -0,0 +1,113 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s
modernize-default-arg-braced-init %t
+
+struct Box {
+ Box() = default;
+ Box(int x) {}
+ Box(const Box&) {}
+};
+
+struct ExplicitBox {
+ explicit ExplicitBox() {}
+};
+
+struct Base {
+ Base() = default;
+};
+
+struct Derived : Base {
+ Derived() = default;
+};
+
+
+
+// Helper function for testing nested calls
+Box makeBox(Box b) { return b; }
+
+// ========== CASES THAT SHOULD TRANSFORM ==========
+
+// Case 1: Basic transformation
+// CHECK-MESSAGES: :[[@LINE+2]]:25: warning: use braced initializer list for
default argument [modernize-default-arg-braced-init]
+// CHECK-FIXES: void basic_case(Box b = {}) {
+void basic_case(Box b = Box()) {
+}
+
+// Case 2: Multiple Box parameters
+// CHECK-MESSAGES: :[[@LINE+3]]:36: warning: use braced initializer list for
default argument [modernize-default-arg-braced-init]
+// CHECK-MESSAGES: :[[@LINE+2]]:52: warning: use braced initializer list for
default argument [modernize-default-arg-braced-init]
+// CHECK-FIXES: void multiple_params_case(Box b1 = {}, Box b2 = {}) {
+void multiple_params_case(Box b1 = Box(), Box b2 = Box()) {
+}
+
+// Case 3: Mixed parameter types (int, Box, double)
+// CHECK-MESSAGES: :[[@LINE+2]]:44: warning: use braced initializer list for
default argument [modernize-default-arg-braced-init]
+// CHECK-FIXES: void mixed_params_case(int x = 10, Box b = {}, double d =
3.14) {
+void mixed_params_case(int x = 10, Box b = Box(), double d = 3.14) {
+}
+
+
+
+// Case 4: Template with concrete type (Box) - SHOULD transform
+// CHECK-MESSAGES: :[[@LINE+3]]:37: warning: use braced initializer list for
default argument [modernize-default-arg-braced-init]
+// CHECK-FIXES: void template_concrete_case(Box b = {}) {
+template<typename T>
+void template_concrete_case(Box b = Box()) {
+}
+
+// Case 5: const, const&, && parameters (all should transform)
+// CHECK-MESSAGES: :[[@LINE+4]]:38: warning: use braced initializer list for
default argument [modernize-default-arg-braced-init]
+// CHECK-MESSAGES: :[[@LINE+3]]:61: warning: use braced initializer list for
default argument [modernize-default-arg-braced-init]
+// CHECK-MESSAGES: :[[@LINE+2]]:79: warning: use braced initializer list for
default argument [modernize-default-arg-braced-init]
+// CHECK-FIXES: void const_ref_params(const Box b1 = {}, const Box& b2 = {},
Box&& b3 = {}) {
+void const_ref_params(const Box b1 = Box(), const Box& b2 = Box(), Box&& b3 =
Box()) {
+}
+
+// Case 6: Constructor default argument (should transform)
+struct S {
+ // CHECK-MESSAGES: :[[@LINE+2]]:13: warning: use braced initializer list for
default argument [modernize-default-arg-braced-init]
+ // CHECK-FIXES: S(Box b = {}) {}
+ S(Box b = Box()) {}
+};
+
+// Case 7: Typedef alias (should transform)
+using MyBox = Box;
+// CHECK-MESSAGES: :[[@LINE+2]]:29: warning: use braced initializer list for
default argument [modernize-default-arg-braced-init]
+// CHECK-FIXES: void typedef_case(MyBox b = {}) {
+void typedef_case(MyBox b = Box()) {
+}
+
+// ========== CASES THAT SHOULD NOT TRANSFORM (SKIP) ==========
+
+// Case 8: Explicit constructor (skip)
+void explicit_case(ExplicitBox e = ExplicitBox()) {
+}
+
+// Case 9: Constructor with arguments (skip)
+void with_args_case(Box b = Box(5)) {
+}
+
+// Case 10: Type mismatch (skip)
+void type_mismatch_case(Base b = Derived()) {
+}
+
+// Case 11: Already braced (skip)
+void already_braced_case(Box b = {}) {
+}
+
+// Case 12: Template with dependent type T() - SHOULD NOT transform
+template<typename T>
+void template_dependent_case(T t = T()) {
+}
+
+// Case 13: Macro expansion (skip)
+#define DEFAULT_BOX Box()
+void macro_case(Box b = DEFAULT_BOX) {
+}
+#undef DEFAULT_BOX
+
+// Case 14: Ternary operator with Box() (skip - nested)
+void ternary_case(Box b = true ? Box() : Box()) {
+}
+
+// Case 15: Nested function call (skip - nested)
+void nested_call_case(Box b = makeBox(Box())) {
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/203474
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits