https://github.com/davidmenggx updated https://github.com/llvm/llvm-project/pull/209367
>From 969a71708aa62007a8877f443e748a31633babb2 Mon Sep 17 00:00:00 2001 From: David Meng <[email protected]> Date: Tue, 4 Aug 2026 09:21:37 -0700 Subject: [PATCH 1/2] Fix merge conflicts --- .../clang-tidy/readability/CMakeLists.txt | 1 + .../readability/ReadabilityTidyModule.cpp | 3 + .../RedundantZeroInitializerCheck.cpp | 65 +++++++++ .../RedundantZeroInitializerCheck.h | 38 +++++ clang-tools-extra/docs/ReleaseNotes.rst | 6 + .../docs/clang-tidy/checks/list.md | 1 + .../readability/redundant-zero-initializer.md | 36 +++++ .../readability/redundant-zero-initializer.c | 16 ++ .../redundant-zero-initializer.cpp | 138 ++++++++++++++++++ 9 files changed, 304 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantZeroInitializerCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantZeroInitializerCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/readability/redundant-zero-initializer.md create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.c create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.cpp diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt index 8a4b5753de890..11cadf9f39879 100644 --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -54,6 +54,7 @@ add_clang_library(clangTidyReadabilityModule STATIC RedundantStringCStrCheck.cpp RedundantStringInitCheck.cpp RedundantTypenameCheck.cpp + RedundantZeroInitializerCheck.cpp ReferenceToConstructedTemporaryCheck.cpp SimplifyBooleanExprCheck.cpp SimplifySubscriptExprCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp index 69b31d6711bcd..0592ae5f1bf60 100644 --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -56,6 +56,7 @@ #include "RedundantStringCStrCheck.h" #include "RedundantStringInitCheck.h" #include "RedundantTypenameCheck.h" +#include "RedundantZeroInitializerCheck.h" #include "ReferenceToConstructedTemporaryCheck.h" #include "SimplifyBooleanExprCheck.h" #include "SimplifySubscriptExprCheck.h" @@ -160,6 +161,8 @@ class ReadabilityModule : public ClangTidyModule { "readability-redundant-qualified-alias"); CheckFactories.registerCheck<RedundantTypenameCheck>( "readability-redundant-typename"); + CheckFactories.registerCheck<RedundantZeroInitializerCheck>( + "readability-redundant-zero-initializer"); CheckFactories.registerCheck<ReferenceToConstructedTemporaryCheck>( "readability-reference-to-constructed-temporary"); CheckFactories.registerCheck<SimplifySubscriptExprCheck>( diff --git a/clang-tools-extra/clang-tidy/readability/RedundantZeroInitializerCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantZeroInitializerCheck.cpp new file mode 100644 index 0000000000000..342ee2930995b --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantZeroInitializerCheck.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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 "RedundantZeroInitializerCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::readability { + +namespace { +AST_MATCHER(InitListExpr, isSingleElementBracedList) { + return Node.isExplicit() && Node.getNumInits() == 1; +} + +AST_MATCHER(InitListExpr, isInMacro) { + return Node.getBeginLoc().isMacroID() || Node.getEndLoc().isMacroID(); +} + +AST_MATCHER(InitListExpr, hasScalarArrayType) { + const ConstantArrayType *CAT = + Finder->getASTContext().getAsConstantArrayType(Node.getType()); + return CAT && CAT->getElementType()->isScalarType(); +} + +// Matches an array type location whose bound is deduced from the initializer +// (``T a[]``); replacing ``{0}`` with ``{}`` there would change the size. +AST_MATCHER(ArrayTypeLoc, hasDeducedArrayBound) { + return Node.getSizeExpr() == nullptr; +} +} // namespace + +void RedundantZeroInitializerCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + initListExpr(hasScalarArrayType(), isSingleElementBracedList(), + hasInit(0, ignoringParenImpCasts(integerLiteral(equals(0)))), + unless(isInMacro()), + unless(hasAncestor(cxxStdInitializerListExpr())), + unless(hasParent(varDecl( + hasTypeLoc(arrayTypeLoc(hasDeducedArrayBound())))))) + .bind("init"), + this); +} + +void RedundantZeroInitializerCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *ILE = Result.Nodes.getNodeAs<InitListExpr>("init"); + const SourceRange Range = ILE->getSourceRange(); + diag(Range.getBegin(), + "redundant zero initializer; replace with empty braces") + << FixItHint::CreateReplacement(Range, "{}"); +} + +} // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/readability/RedundantZeroInitializerCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantZeroInitializerCheck.h new file mode 100644 index 0000000000000..54906c4e07977 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantZeroInitializerCheck.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// 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_READABILITY_REDUNDANTZEROINITIALIZERCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTZEROINITIALIZERCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::readability { + +/// Finds explicit zero initializers of arrays that can be replaced with empty +/// braces, e.g. ``char a[12] = {0};`` becomes ``char a[12] = {};``. +/// +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-zero-initializer.html +class RedundantZeroInitializerCheck : public ClangTidyCheck { +public: + RedundantZeroInitializerCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + // Empty braces are only valid in C++ and, for C, since C23. + return LangOpts.CPlusPlus || LangOpts.C23; + } + std::optional<TraversalKind> getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } +}; + +} // namespace clang::tidy::readability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTZEROINITIALIZERCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 0dcf2ea1f21c7..0ad39617e097f 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -107,6 +107,12 @@ New checks Finds calls to ``value_or`` (and alternative spellings ``valueOr``, ``ValueOr``) on optional types where the return type is expensive to copy. +- New :doc:`readability-redundant-zero-initializer + <clang-tidy/checks/readability/redundant-zero-initializer>` check. + + Finds explicit zero initializers of arrays that can be replaced with empty + braces. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.md b/clang-tools-extra/docs/clang-tidy/checks/list.md index 12d8a48ee8d86..5dd3d4ddef963 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.md +++ b/clang-tools-extra/docs/clang-tidy/checks/list.md @@ -427,6 +427,7 @@ zircon/* | {doc}`readability-redundant-string-cstr <readability/redundant-string-cstr>` | Yes | | {doc}`readability-redundant-string-init <readability/redundant-string-init>` | Yes | | {doc}`readability-redundant-typename <readability/redundant-typename>` | Yes | +| {doc}`readability-redundant-zero-initializer <readability/redundant-zero-initializer>` | Yes | | {doc}`readability-reference-to-constructed-temporary <readability/reference-to-constructed-temporary>` | | | {doc}`readability-simplify-boolean-expr <readability/simplify-boolean-expr>` | Yes | | {doc}`readability-simplify-subscript-expr <readability/simplify-subscript-expr>` | Yes | diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-zero-initializer.md b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-zero-initializer.md new file mode 100644 index 0000000000000..88d7b074d27aa --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-zero-initializer.md @@ -0,0 +1,36 @@ +```{title} clang-tidy - readability-redundant-zero-initializer +``` + +# readability-redundant-zero-initializer + +Finds explicit zero initializers of arrays that can be replaced with empty +braces. + +In C++ and since C23, an empty braced initializer zero-initializes every element +of an array, so an explicit `{0}` is redundant. + +```cpp +char a[12] = {0}; +int b[5] = {0}; + +// becomes + +char a[12] = {}; +int b[5] = {}; +``` + +The check is only enabled in C++ and in C23 or later. + +## Limitations + +To keep the fix always safe, the check is intentionally conservative and only +handles single-element `{0}` initializers of arrays with an explicit bound. +It does not flag, among others: + +- scalars (`int x = {0};`) and class or struct types (`S s = {0};`); +- arrays whose bound is deduced from the initializer (`char a[] = {0};`), + where `{}` would change the deduced size; +- multi-dimensional arrays (`int m[2][3] = {0};`); +- initializers with more than one element (`int a[3] = {0, 0};`); +- zero written as something other than the integer literal `0`, for example + `'\0'`, `0.0` or `nullptr`. diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.c b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.c new file mode 100644 index 0000000000000..64986a3d53907 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.c @@ -0,0 +1,16 @@ +// RUN: %check_clang_tidy -std=c90,c99,c11,c17 -check-suffixes=C17 %s readability-redundant-zero-initializer %t +// RUN: %check_clang_tidy -std=c23-or-later -check-suffixes=C23 %s readability-redundant-zero-initializer %t + +char a[12] = {0}; +// CHECK-MESSAGES-C23: :[[@LINE-1]]:14: warning: redundant zero initializer; replace with empty braces [readability-redundant-zero-initializer] +// CHECK-FIXES-C23: char a[12] = {}; + +int b[5] = {0}; +// CHECK-MESSAGES-C23: :[[@LINE-1]]:12: warning: redundant zero initializer; replace with empty braces +// CHECK-FIXES-C23: int b[5] = {}; + +char deduced[] = {0}; +int multiZero[3] = {0, 0}; +int mixed[4] = {0, 5}; +int oneByOne[1][1] = {0}; +char nullChar[4] = {'\0'}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.cpp new file mode 100644 index 0000000000000..dd2d0ace4e2aa --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.cpp @@ -0,0 +1,138 @@ +// RUN: %check_clang_tidy -std=c++98,c++03 %s readability-redundant-zero-initializer %t +// RUN: %check_clang_tidy -std=c++11 -check-suffixes=,CXX11 %s readability-redundant-zero-initializer %t +// RUN: %check_clang_tidy -std=c++14-or-later -check-suffixes=,CXX11 %s readability-redundant-zero-initializer %t + +char a[12] = {0}; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant zero initializer; replace with empty braces [readability-redundant-zero-initializer] +// CHECK-FIXES: char a[12] = {}; + +int b[5] = {0}; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant zero initializer; replace with empty braces +// CHECK-FIXES: int b[5] = {}; + +double d[3] = {0}; +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: redundant zero initializer; replace with empty braces +// CHECK-FIXES: double d[3] = {}; + +void *p[4] = {0}; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant zero initializer; replace with empty braces +// CHECK-FIXES: void *p[4] = {}; + +const char cq[8] = {0}; +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: redundant zero initializer; replace with empty braces +// CHECK-FIXES: const char cq[8] = {}; + +int spaced[2] = { 0 }; +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: redundant zero initializer; replace with empty braces +// CHECK-FIXES: int spaced[2] = {}; + +int trailingComma[3] = {0,}; +// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: redundant zero initializer; replace with empty braces +// CHECK-FIXES: int trailingComma[3] = {}; + +int paren[2] = {(0)}; +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant zero initializer; replace with empty braces +// CHECK-FIXES: int paren[2] = {}; + +double nestedParen[2] = {((0))}; +// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: redundant zero initializer; replace with empty braces +// CHECK-FIXES: double nestedParen[2] = {}; + +void localVariables() { + int local[4] = {0}; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: redundant zero initializer; replace with empty braces + // CHECK-FIXES: int local[4] = {}; + static int staticLocal[2] = {0}; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: redundant zero initializer; replace with empty braces + // CHECK-FIXES: static int staticLocal[2] = {}; +} + +char emptyBraces[12] = {}; +int nonZero[3] = {1}; +int multiZero[3] = {0, 0}; +int mixed[4] = {0, 5}; +int noInit[3]; + +// Multi-dimensional arrays without inner braces: the single `0` initializes a +// subobject through brace elision, so there is no written single-element `{0}` +// list to rewrite. +int twoD[2][3] = {0}; +int oneByOne[1][1] = {0}; +int rowVector[1][3] = {0}; +int columnVector[3][1] = {0}; + +// The array bound is deduced from the initializer, `{}` would change the size. +char deduced[] = {0}; + +char nullChar[4] = {'\0'}; +double zeroDouble[3] = {0.0}; + +int scalar = {0}; + +struct P { int x; int y; }; +P pod = {0}; + +#if __cplusplus >= 201103L + +struct S { + char buf[4] = {0}; + // CHECK-MESSAGES-CXX11: :[[@LINE-1]]:17: warning: redundant zero initializer; replace with empty braces + // CHECK-FIXES-CXX11: char buf[4] = {}; +}; + +void *nullPtr[4] = {nullptr}; + +using Arr = int[2]; +void use(const int (&)[2]); +void arrayPrvalue() { + use(Arr{0}); + // CHECK-MESSAGES-CXX11: :[[@LINE-1]]:10: warning: redundant zero initializer; replace with empty braces + // CHECK-FIXES-CXX11: use(Arr{}); +} + +// Template instantiations share the pattern's written braces. Rewriting `{0}` +// in the pattern would break the `templateFn<X>` instantiation, whose element +// type is not default-constructible, so neither the pattern nor any of its +// instantiations may be flagged. +struct X { + X(int); + X() = delete; +}; + +template <class T> +void templateFn() { + T arr[1] = {0}; +} + +void instantiate() { + templateFn<int>(); + templateFn<X>(); +} + +// The `const T[N]` backing array of a `std::initializer_list` is an element +// list, so `{0}` (one element) must not become `{}` (an empty list). +namespace std { +template <class T> class initializer_list { + const T *Data; + __SIZE_TYPE__ Size; + initializer_list(const T *D, __SIZE_TYPE__ S) : Data(D), Size(S) {} + +public: + initializer_list() : Data(nullptr), Size(0) {} +}; +} // namespace std + +struct IntList { + IntList(std::initializer_list<int>); +}; +IntList returnsList() { return {0}; } +IntList variableList = {0}; +#endif + +#if __cplusplus >= 201402L +// An array of a class type with a default member initializer is an aggregate +// since C++14. `{0}` and `{}` are not equivalent, so it must not be +// rewritten. +struct WithDefault { int v = 7; }; +WithDefault wd[2] = {0}; +#endif >From d0ca7aefc233b310fc63d3c1738c0dbc66f8edcf Mon Sep 17 00:00:00 2001 From: David Meng <[email protected]> Date: Wed, 5 Aug 2026 06:59:40 -0700 Subject: [PATCH 2/2] Update clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.c Co-authored-by: Baranov Victor <[email protected]> --- .../checkers/readability/redundant-zero-initializer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.c b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.c index 64986a3d53907..bcf839f7f2bb9 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.c +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-zero-initializer.c @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy -std=c90,c99,c11,c17 -check-suffixes=C17 %s readability-redundant-zero-initializer %t +// RUN: %check_clang_tidy -std=c17-or-earlier %s readability-redundant-zero-initializer %t // RUN: %check_clang_tidy -std=c23-or-later -check-suffixes=C23 %s readability-redundant-zero-initializer %t char a[12] = {0}; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
