https://github.com/AntonyCJ30 updated https://github.com/llvm/llvm-project/pull/203474
>From e2b8ec6eeffa3596b5da8c9a7c6a269f05ca4d27 Mon Sep 17 00:00:00 2001 From: AntonyCJ30 <cj6186609@[email protected]> Date: Fri, 29 May 2026 11:15:32 +0530 Subject: [PATCH] [clang-tidy] Add modernize-default-arg-braced-init check --- .../clang-tidy/modernize/CMakeLists.txt | 1 + .../modernize/DefaultArgBracedInitCheck.cpp | 59 +++++++++ .../modernize/DefaultArgBracedInitCheck.h | 40 +++++++ .../modernize/ModernizeTidyModule.cpp | 3 + clang-tools-extra/docs/ReleaseNotes.rst | 8 ++ .../docs/clang-tidy/checks/list.rst | 1 + .../modernize/default-arg-braced-init.rst | 20 ++++ .../modernize/default-arg-braced-init.cpp | 113 ++++++++++++++++++ 8 files changed, 245 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/default-arg-braced-init.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/default-arg-braced-init.cpp 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..5daba767cb3bc --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/DefaultArgBracedInitCheck.cpp @@ -0,0 +1,59 @@ +//===--- 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" + +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..bfac53a6a5573 --- /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..a088c5200fa73 --- /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 redundant non-explicit default 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())) { +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
