https://github.com/unterumarmung updated https://github.com/llvm/llvm-project/pull/180408
>From 144e2d14cf255dd6dbc2e513fb3aa4e866060c03 Mon Sep 17 00:00:00 2001 From: Daniil Dudkin <[email protected]> Date: Sun, 8 Feb 2026 16:23:22 +0300 Subject: [PATCH] clang-tidy: comment braced-init list arguments Handle braced-init list arguments in bugprone-argument-comment and\nadd coverage for initializer_list and designated initializers. clang-tidy: gate braced-init argument comments behind options clang-tidy: split argument-comment init-list tests --- .../bugprone/ArgumentCommentCheck.cpp | 54 ++++++- .../bugprone/ArgumentCommentCheck.h | 2 + clang-tools-extra/docs/ReleaseNotes.rst | 7 +- .../checks/bugprone/argument-comment.rst | 44 ++++++ .../bugprone/argument-comment-init-list.cpp | 143 ++++++++++++++++++ .../bugprone/argument-comment-literals.cpp | 1 - 6 files changed, 244 insertions(+), 7 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-init-list.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp index e3139f96cfb09..9747f690819a0 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp @@ -43,6 +43,9 @@ ArgumentCommentCheck::ArgumentCommentCheck(StringRef Name, CommentUserDefinedLiterals( Options.get("CommentUserDefinedLiterals", false)), CommentCharacterLiterals(Options.get("CommentCharacterLiterals", false)), + CommentAnonymousInitLists( + Options.get("CommentAnonymousInitLists", false)), + CommentTypedInitLists(Options.get("CommentTypedInitLists", false)), CommentNullPtrs(Options.get("CommentNullPtrs", false)), IdentRE("^(/\\* *)([_A-Za-z][_A-Za-z0-9]*)( *= *\\*/)$") {} @@ -55,6 +58,8 @@ void ArgumentCommentCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "CommentStringLiterals", CommentStringLiterals); Options.store(Opts, "CommentUserDefinedLiterals", CommentUserDefinedLiterals); Options.store(Opts, "CommentCharacterLiterals", CommentCharacterLiterals); + Options.store(Opts, "CommentAnonymousInitLists", CommentAnonymousInitLists); + Options.store(Opts, "CommentTypedInitLists", CommentTypedInitLists); Options.store(Opts, "CommentNullPtrs", CommentNullPtrs); } @@ -199,15 +204,56 @@ static const FunctionDecl *resolveMocks(const FunctionDecl *Func) { return Func; } +enum class InitListKind { + None, + Anonymous, + Typed, +}; + +static InitListKind getInitListKind(const Expr *Arg) { + Arg = Arg->IgnoreImplicit(); + + if (const auto *StdInit = dyn_cast<CXXStdInitializerListExpr>(Arg)) + return getInitListKind(StdInit->getSubExpr()); + + if (isa<InitListExpr>(Arg)) + return InitListKind::Anonymous; + + if (const auto *Ctor = dyn_cast<CXXConstructExpr>(Arg)) { + if (!Ctor->isListInitialization()) + return InitListKind::None; + // CXXTemporaryObjectExpr corresponds to explicit Type{...} syntax. + if (isa<CXXTemporaryObjectExpr>(Ctor)) + return InitListKind::Typed; + // Other list-initialized constructions (for example '{}') have no + // explicit type at the call site. + return InitListKind::Anonymous; + } + + if (const auto *FuncCast = dyn_cast<CXXFunctionalCastExpr>(Arg)) { + if (FuncCast->isListInitialization()) + return InitListKind::Typed; + } + + return InitListKind::None; +} + // Given the argument type and the options determine if we should // be adding an argument comment. bool ArgumentCommentCheck::shouldAddComment(const Expr *Arg) const { - Arg = Arg->IgnoreImpCasts(); - if (isa<UnaryOperator>(Arg)) - Arg = cast<UnaryOperator>(Arg)->getSubExpr(); + // Strip implicit wrappers so brace-init arguments bound to references still + // look like list-initialization at this point. + Arg = Arg->IgnoreImplicit(); + if (const auto *UO = dyn_cast<UnaryOperator>(Arg)) + Arg = UO->getSubExpr()->IgnoreImplicit(); if (Arg->getExprLoc().isMacroID()) return false; - return (CommentBoolLiterals && isa<CXXBoolLiteralExpr>(Arg)) || + + const InitListKind Kind = getInitListKind(Arg); + + return (CommentAnonymousInitLists && Kind == InitListKind::Anonymous) || + (CommentTypedInitLists && Kind == InitListKind::Typed) || + (CommentBoolLiterals && isa<CXXBoolLiteralExpr>(Arg)) || (CommentIntegerLiterals && isa<IntegerLiteral>(Arg)) || (CommentFloatLiterals && isa<FloatingLiteral>(Arg)) || (CommentUserDefinedLiterals && isa<UserDefinedLiteral>(Arg)) || diff --git a/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.h b/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.h index 30fa32fad72e7..60a1338233f66 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.h @@ -46,6 +46,8 @@ class ArgumentCommentCheck : public ClangTidyCheck { const unsigned CommentStringLiterals : 1; const unsigned CommentUserDefinedLiterals : 1; const unsigned CommentCharacterLiterals : 1; + const unsigned CommentAnonymousInitLists : 1; + const unsigned CommentTypedInitLists : 1; const unsigned CommentNullPtrs : 1; llvm::Regex IdentRE; diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 059e48b512adf..b50b035273992 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -190,8 +190,11 @@ Changes in existing checks ^^^^^^^^^^^^^^^^^^^^^^^^^^ - Improved :doc:`bugprone-argument-comment - <clang-tidy/checks/bugprone/argument-comment>` to also check for C++11 - inherited constructors. + <clang-tidy/checks/bugprone/argument-comment>`: + - Checks for C++11 inherited constructors. + - Adds `CommentAnonymousInitLists` and `CommentTypedInitLists` options + to comment braced-init list arguments (for example, ``{}`` and + ``Type{}``). - Improved :doc:`bugprone-bad-signal-to-kill-thread <clang-tidy/checks/bugprone/bad-signal-to-kill-thread>` check by fixing false diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/argument-comment.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/argument-comment.rst index 8770d7224137a..dc028cde2fcc4 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/argument-comment.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/argument-comment.rst @@ -146,6 +146,50 @@ After: foo(/*Character=*/'A'); +.. option:: CommentAnonymousInitLists + + When `true`, the check will add argument comments in the format + ``/*ParameterName=*/`` right before anonymous braced-init list arguments + such as ``{}`` and ``{1, 2, 3}``. Default is `false`. + +Before: + +.. code-block:: c++ + + void foo(const std::vector<int> &Dims); + + foo({}); + +After: + +.. code-block:: c++ + + void foo(const std::vector<int> &Dims); + + foo(/*Dims=*/{}); + +.. option:: CommentTypedInitLists + + When `true`, the check will add argument comments in the format + ``/*ParameterName=*/`` right before typed braced-init list arguments such + as ``Type{}``. Default is `false`. + +Before: + +.. code-block:: c++ + + void foo(const std::vector<int> &Dims); + + foo(std::vector<int>{}); + +After: + +.. code-block:: c++ + + void foo(const std::vector<int> &Dims); + + foo(/*Dims=*/std::vector<int>{}); + .. option:: CommentUserDefinedLiterals When `true`, the check will add argument comments in the format diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-init-list.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-init-list.cpp new file mode 100644 index 0000000000000..62c27c775396a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-init-list.cpp @@ -0,0 +1,143 @@ +// RUN: %check_clang_tidy -check-suffix=OFF -std=c++11,c++14,c++17 %s bugprone-argument-comment %t +// RUN: %check_clang_tidy -check-suffix=ANON -std=c++11,c++14,c++17 %s bugprone-argument-comment %t -- \ +// RUN: -config="{CheckOptions: { \ +// RUN: bugprone-argument-comment.CommentAnonymousInitLists: true}}" -- +// RUN: %check_clang_tidy -check-suffix=TYPED -std=c++11,c++14,c++17 %s bugprone-argument-comment %t -- \ +// RUN: -config="{CheckOptions: { \ +// RUN: bugprone-argument-comment.CommentTypedInitLists: true}}" -- +// RUN: %check_clang_tidy -check-suffix=BOTH -std=c++11,c++14,c++17 %s bugprone-argument-comment %t -- \ +// RUN: -config="{CheckOptions: { \ +// RUN: bugprone-argument-comment.CommentAnonymousInitLists: true, \ +// RUN: bugprone-argument-comment.CommentTypedInitLists: true}}" -- +// RUN: %check_clang_tidy -check-suffixes=BOTH,BOTH-CXX20 -std=c++20-or-later %s bugprone-argument-comment %t -- \ +// RUN: -config="{CheckOptions: { \ +// RUN: bugprone-argument-comment.CommentAnonymousInitLists: true, \ +// RUN: bugprone-argument-comment.CommentTypedInitLists: true}}" -- + +namespace std { +using size_t = decltype(sizeof(0)); + +template <typename T> +class vector { +public: + vector(); +}; + +template <typename T> +class initializer_list { + const T *Begin; + const T *End; + +public: + initializer_list() : Begin(nullptr), End(nullptr) {} + const T *begin() const { return Begin; } + const T *end() const { return End; } + size_t size() const { return static_cast<size_t>(End - Begin); } +}; +} // namespace std + +namespace GH171842 { + +struct T { + int value; +}; + +struct Agg { + int x; + int y; +}; + +void foo(T some_arg, const std::vector<int> &dims); +void foo_init_list(T some_arg, std::initializer_list<int> dims); +void foo_designated(T some_arg, const Agg &dims); +template <typename ElemTy> +void foo_template(T some_arg, const std::vector<ElemTy> &dims); + +void test_braced_init_list() { + T some_arg{0}; + + // Mismatched explicit argument comments are validated independently of the + // init-list literal comment options. + foo(some_arg, /*dim=*/{}); + // CHECK-MESSAGES-OFF: warning: argument name 'dim' in comment does not match parameter name 'dims' + // CHECK-FIXES-OFF: foo(some_arg, /*dims=*/{}); + // CHECK-MESSAGES-ANON: warning: argument name 'dim' in comment does not match parameter name 'dims' + // CHECK-FIXES-ANON: foo(some_arg, /*dims=*/{}); + // CHECK-MESSAGES-TYPED: warning: argument name 'dim' in comment does not match parameter name 'dims' + // CHECK-FIXES-TYPED: foo(some_arg, /*dims=*/{}); + // CHECK-MESSAGES-BOTH: warning: argument name 'dim' in comment does not match parameter name 'dims' + // CHECK-FIXES-BOTH: foo(some_arg, /*dims=*/{}); + + foo(some_arg, /*dim=*/std::vector<int>{}); + // CHECK-MESSAGES-OFF: warning: argument name 'dim' in comment does not match parameter name 'dims' + // CHECK-FIXES-OFF: foo(some_arg, /*dims=*/std::vector<int>{}); + // CHECK-MESSAGES-ANON: warning: argument name 'dim' in comment does not match parameter name 'dims' + // CHECK-FIXES-ANON: foo(some_arg, /*dims=*/std::vector<int>{}); + // CHECK-MESSAGES-TYPED: warning: argument name 'dim' in comment does not match parameter name 'dims' + // CHECK-FIXES-TYPED: foo(some_arg, /*dims=*/std::vector<int>{}); + // CHECK-MESSAGES-BOTH: warning: argument name 'dim' in comment does not match parameter name 'dims' + // CHECK-FIXES-BOTH: foo(some_arg, /*dims=*/std::vector<int>{}); + + foo(some_arg, {}); + // CHECK-FIXES-OFF: foo(some_arg, {}); + // CHECK-MESSAGES-ANON: [[@LINE-2]]:17: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-ANON: foo(some_arg, /*dims=*/{}); + // CHECK-FIXES-TYPED: foo(some_arg, {}); + // CHECK-MESSAGES-BOTH: [[@LINE-5]]:17: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-BOTH: foo(some_arg, /*dims=*/{}); + + foo(some_arg, std::vector<int>{}); + // CHECK-FIXES-OFF: foo(some_arg, std::vector<int>{}); + // CHECK-FIXES-ANON: foo(some_arg, std::vector<int>{}); + // CHECK-MESSAGES-TYPED: [[@LINE-3]]:17: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-TYPED: foo(some_arg, /*dims=*/std::vector<int>{}); + // CHECK-MESSAGES-BOTH: [[@LINE-5]]:17: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-BOTH: foo(some_arg, /*dims=*/std::vector<int>{}); +} + +void test_initializer_list() { + T some_arg{0}; + + foo_init_list(some_arg, {1, 2, 3}); + // CHECK-FIXES-OFF: foo_init_list(some_arg, {1, 2, 3}); + // CHECK-MESSAGES-ANON: [[@LINE-2]]:27: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-ANON: foo_init_list(some_arg, /*dims=*/{1, 2, 3}); + // CHECK-FIXES-TYPED: foo_init_list(some_arg, {1, 2, 3}); + // CHECK-MESSAGES-BOTH: [[@LINE-5]]:27: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-BOTH: foo_init_list(some_arg, /*dims=*/{1, 2, 3}); +} + +template <typename ElemTy> +void test_template_dependent_init_list() { + T some_arg{0}; + + foo_template<ElemTy>(some_arg, {}); + // CHECK-FIXES-OFF: foo_template<ElemTy>(some_arg, {}); + // CHECK-MESSAGES-ANON: [[@LINE-2]]:34: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-ANON: foo_template<ElemTy>(some_arg, /*dims=*/{}); + // CHECK-FIXES-TYPED: foo_template<ElemTy>(some_arg, {}); + // CHECK-MESSAGES-BOTH: [[@LINE-5]]:34: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-BOTH: foo_template<ElemTy>(some_arg, /*dims=*/{}); + + foo_template<ElemTy>(some_arg, std::vector<ElemTy>{}); + // CHECK-FIXES-OFF: foo_template<ElemTy>(some_arg, std::vector<ElemTy>{}); + // CHECK-FIXES-ANON: foo_template<ElemTy>(some_arg, std::vector<ElemTy>{}); + // CHECK-MESSAGES-TYPED: [[@LINE-3]]:34: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-TYPED: foo_template<ElemTy>(some_arg, /*dims=*/std::vector<ElemTy>{}); + // CHECK-MESSAGES-BOTH: [[@LINE-5]]:34: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-BOTH: foo_template<ElemTy>(some_arg, /*dims=*/std::vector<ElemTy>{}); +} + +template void test_template_dependent_init_list<int>(); + +#if __cplusplus >= 202002L +void test_designated_init() { + T some_arg{0}; + + foo_designated(some_arg, Agg{.x = 1}); + // CHECK-MESSAGES-BOTH-CXX20: [[@LINE-1]]:28: warning: argument comment missing for literal argument 'dims' [bugprone-argument-comment] + // CHECK-FIXES-BOTH-CXX20: foo_designated(some_arg, /*dims=*/Agg{.x = 1}); +} +#endif + +} // namespace GH171842 diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-literals.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-literals.cpp index f03488a14d9f5..41283f66a2f26 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-literals.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/argument-comment-literals.cpp @@ -7,7 +7,6 @@ // RUN: bugprone-argument-comment.CommentStringLiterals: true, \ // RUN: bugprone-argument-comment.CommentNullPtrs: true, \ // RUN: bugprone-argument-comment.CommentCharacterLiterals: true}}" -- - struct A { void foo(bool abc); void foo(bool abc, bool cde); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
