[clang-tools-extra] [clang-tidy] Add new check readability-trailing-comma (PR #173669)
Baranov Victor via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 6 19:14:48 PST 2026
https://github.com/vbvictor updated https://github.com/llvm/llvm-project/pull/173669
>From 60ecb84f835c228fe899eba7c3f0973f802156b4 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Tue, 23 Dec 2025 02:27:23 +0300
Subject: [PATCH 01/10] [clang-tidy] Add new check readability-trailing-comma
---
.../clang-tidy/readability/CMakeLists.txt | 1 +
.../readability/ReadabilityTidyModule.cpp | 3 +
.../readability/TrailingCommaCheck.cpp | 167 ++++++++++++++++++
.../readability/TrailingCommaCheck.h | 54 ++++++
clang-tools-extra/docs/ReleaseNotes.rst | 6 +
.../docs/clang-tidy/checks/list.rst | 1 +
.../checks/readability/trailing-comma.rst | 83 +++++++++
.../trailing-comma-cxx20-remove.cpp | 46 +++++
.../readability/trailing-comma-cxx20.cpp | 46 +++++
.../readability/trailing-comma-remove.cpp | 49 +++++
.../readability/trailing-comma-threshold.cpp | 20 +++
.../checkers/readability/trailing-comma.c | 40 +++++
.../checkers/readability/trailing-comma.cpp | 76 ++++++++
13 files changed, 592 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-threshold.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 161a0d96caf41..79fa4e2273320 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -57,6 +57,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
StaticDefinitionInAnonymousNamespaceCheck.cpp
StringCompareCheck.cpp
SuspiciousCallArgumentCheck.cpp
+ TrailingCommaCheck.cpp
UniqueptrDeleteReleaseCheck.cpp
UppercaseLiteralSuffixCheck.cpp
UseAnyOfAllOfCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index 85b4fa322b263..c3dfd7ecac7a7 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -60,6 +60,7 @@
#include "StaticDefinitionInAnonymousNamespaceCheck.h"
#include "StringCompareCheck.h"
#include "SuspiciousCallArgumentCheck.h"
+#include "TrailingCommaCheck.h"
#include "UniqueptrDeleteReleaseCheck.h"
#include "UppercaseLiteralSuffixCheck.h"
#include "UseAnyOfAllOfCheck.h"
@@ -175,6 +176,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-simplify-boolean-expr");
CheckFactories.registerCheck<SuspiciousCallArgumentCheck>(
"readability-suspicious-call-argument");
+ CheckFactories.registerCheck<TrailingCommaCheck>(
+ "readability-trailing-comma");
CheckFactories.registerCheck<UniqueptrDeleteReleaseCheck>(
"readability-uniqueptr-delete-release");
CheckFactories.registerCheck<UppercaseLiteralSuffixCheck>(
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
new file mode 100644
index 0000000000000..6552e6d540550
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
@@ -0,0 +1,167 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "TrailingCommaCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy {
+
+template <>
+struct OptionEnumMapping<readability::TrailingCommaCheck::CommaPolicyKind> {
+ static llvm::ArrayRef<
+ std::pair<readability::TrailingCommaCheck::CommaPolicyKind, StringRef>>
+ getEnumMapping() {
+ static constexpr std::pair<readability::TrailingCommaCheck::CommaPolicyKind,
+ StringRef>
+ Mapping[] = {
+ {readability::TrailingCommaCheck::CommaPolicyKind::Append,
+ "Append"},
+ {readability::TrailingCommaCheck::CommaPolicyKind::Remove,
+ "Remove"},
+ };
+ return {Mapping};
+ }
+};
+
+} // namespace clang::tidy
+
+namespace clang::tidy::readability {
+
+namespace {
+
+AST_POLYMORPHIC_MATCHER(isMacro,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(EnumDecl,
+ InitListExpr)) {
+ return Node.getBeginLoc().isMacroID() || Node.getEndLoc().isMacroID();
+}
+
+AST_MATCHER(EnumDecl, isEmptyEnum) { return Node.enumerators().empty(); }
+
+AST_MATCHER(InitListExpr, isEmptyInitList) { return Node.getNumInits() == 0; }
+
+} // namespace
+
+TrailingCommaCheck::TrailingCommaCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ CommaPolicy(Options.get("CommaPolicy", CommaPolicyKind::Append)),
+ EnumThreshold(Options.get("EnumThreshold", 1U)),
+ InitListThreshold(Options.get("InitListThreshold", 3U)) {}
+
+void TrailingCommaCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "CommaPolicy", CommaPolicy);
+ Options.store(Opts, "EnumThreshold", EnumThreshold);
+ Options.store(Opts, "InitListThreshold", InitListThreshold);
+}
+
+void TrailingCommaCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ enumDecl(isDefinition(), unless(isEmptyEnum()), unless(isMacro()))
+ .bind("enum"),
+ this);
+
+ Finder->addMatcher(initListExpr(unless(isEmptyInitList()), unless(isMacro()))
+ .bind("initlist"),
+ this);
+}
+
+void TrailingCommaCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Enum = Result.Nodes.getNodeAs<EnumDecl>("enum"))
+ checkEnumDecl(Enum, Result);
+ else if (const auto *InitList =
+ Result.Nodes.getNodeAs<InitListExpr>("initlist"))
+ checkInitListExpr(InitList, Result);
+ else
+ llvm_unreachable("No matches found");
+}
+
+void TrailingCommaCheck::checkEnumDecl(const EnumDecl *Enum,
+ const MatchFinder::MatchResult &Result) {
+ // Count enumerators and get the last one
+ unsigned NumEnumerators = 0;
+ const EnumConstantDecl *LastEnumerator = nullptr;
+ for (const EnumConstantDecl *ECD : Enum->enumerators()) {
+ LastEnumerator = ECD;
+ ++NumEnumerators;
+ }
+ assert(LastEnumerator);
+ assert(NumEnumerators > 0);
+
+ if (NumEnumerators < EnumThreshold)
+ return;
+
+ SourceLocation LastEnumLoc;
+ if (const Expr *Init = LastEnumerator->getInitExpr())
+ LastEnumLoc = Init->getEndLoc();
+ else
+ LastEnumLoc = LastEnumerator->getLocation();
+
+ if (LastEnumLoc.isInvalid())
+ return;
+
+ emitDiag(LastEnumLoc, DiagKind::Enum, Result);
+}
+
+void TrailingCommaCheck::checkInitListExpr(
+ const InitListExpr *InitList, const MatchFinder::MatchResult &Result) {
+ // We need to use the syntactic form for correct source locations.
+ if (InitList->isSemanticForm())
+ if (const InitListExpr *SyntacticForm = InitList->getSyntacticForm())
+ InitList = SyntacticForm;
+
+ const unsigned NumInits = InitList->getNumInits();
+ if (NumInits < InitListThreshold)
+ return;
+
+ const Expr *LastInit = InitList->getInit(NumInits - 1);
+ assert(LastInit);
+
+ // Skip pack expansions - they already have special syntax with '...'
+ if (isa<PackExpansionExpr>(LastInit))
+ return;
+
+ const SourceLocation LastInitLoc = LastInit->getEndLoc();
+ if (LastInitLoc.isInvalid())
+ return;
+
+ emitDiag(LastInitLoc, DiagKind::InitList, Result);
+}
+
+void TrailingCommaCheck::emitDiag(
+ SourceLocation LastLoc, DiagKind Kind,
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ const std::optional<Token> NextToken =
+ utils::lexer::findNextTokenSkippingComments(
+ LastLoc, *Result.SourceManager, getLangOpts());
+ if (!NextToken)
+ return;
+
+ const bool HasTrailingComma = NextToken->is(tok::comma);
+ const SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
+ LastLoc, 0, *Result.SourceManager, getLangOpts());
+
+ if (CommaPolicy == CommaPolicyKind::Append && !HasTrailingComma) {
+ diag(InsertLoc, "%select{initializer list|enum}0 should have "
+ "a trailing comma")
+ << Kind << FixItHint::CreateInsertion(InsertLoc, ",");
+ } else if (CommaPolicy == CommaPolicyKind::Remove && HasTrailingComma) {
+ const SourceLocation CommaLoc = NextToken->getLocation();
+ if (CommaLoc.isInvalid())
+ return;
+ diag(CommaLoc, "%select{initializer list|enum}0 should not have "
+ "a trailing comma")
+ << Kind << FixItHint::CreateRemoval(CommaLoc);
+ }
+}
+
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
new file mode 100644
index 0000000000000..789e4a6d30df4
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_TRAILINGCOMMACHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_TRAILINGCOMMACHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::readability {
+
+/// Checks for presence or absence of trailing commas in enum definitions
+/// and initializer lists.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/readability/trailing-comma.html
+class TrailingCommaCheck : public ClangTidyCheck {
+public:
+ TrailingCommaCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ 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 || LangOpts.C99;
+ }
+ std::optional<TraversalKind> getCheckTraversalKind() const override {
+ return TK_IgnoreUnlessSpelledInSource;
+ }
+
+ enum class CommaPolicyKind { Append, Remove };
+
+private:
+ const CommaPolicyKind CommaPolicy;
+ const unsigned EnumThreshold;
+ const unsigned InitListThreshold;
+
+ void checkEnumDecl(const EnumDecl *Enum,
+ const ast_matchers::MatchFinder::MatchResult &Result);
+ void checkInitListExpr(const InitListExpr *InitList,
+ const ast_matchers::MatchFinder::MatchResult &Result);
+
+ // Values correspond to %select{initializer list|enum}0 indices
+ enum DiagKind { InitList = 0, Enum = 1 };
+ void emitDiag(SourceLocation LastLoc, DiagKind Kind,
+ const ast_matchers::MatchFinder::MatchResult &Result);
+};
+
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_TRAILINGCOMMACHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index e4ff640811933..7b2d7196d14cf 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -271,6 +271,12 @@ New checks
Finds redundant uses of the ``typename`` keyword.
+- New :doc:`readability-trailing-comma
+ <clang-tidy/checks/readability/trailing-comma>` check.
+
+ Checks for presence or absence of trailing commas in enum definitions and
+ initializer lists.
+
New check aliases
^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index e5e77b5cc418b..678ebf09ad444 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -422,6 +422,7 @@ Clang-Tidy Checks
:doc:`readability-static-definition-in-anonymous-namespace <readability/static-definition-in-anonymous-namespace>`, "Yes"
:doc:`readability-string-compare <readability/string-compare>`, "Yes"
:doc:`readability-suspicious-call-argument <readability/suspicious-call-argument>`,
+ :doc:`readability-trailing-comma <readability/trailing-comma>`, "Yes"
:doc:`readability-uniqueptr-delete-release <readability/uniqueptr-delete-release>`, "Yes"
:doc:`readability-uppercase-literal-suffix <readability/uppercase-literal-suffix>`, "Yes"
:doc:`readability-use-anyofallof <readability/use-anyofallof>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst
new file mode 100644
index 0000000000000..f1bd09d5d4e08
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst
@@ -0,0 +1,83 @@
+.. title:: clang-tidy - readability-trailing-comma
+
+readability-trailing-comma
+==========================
+
+Checks for presence or absence of trailing commas in enum definitions and
+initializer lists.
+
+The check can either append trailing commas where they are missing or remove
+them where they are present, based on the configured policy.
+
+Trailing commas offer several benefits:
+
+- Adding or removing elements may only changes a single line, making diffs
+ smaller and easier to read.
+- Formatters may change code to a more desired style.
+- Code generators avoid for need special handling of the last element.
+
+.. code-block:: c++
+
+ // Without trailing commas - adding "Yellow" requires modifying the "Blue" line
+ enum Color {
+ Red,
+ Green,
+ Blue
+ };
+
+ // With trailing commas - adding "Yellow" is a clean, single-line change
+ enum Color {
+ Red,
+ Green,
+ Blue,
+ };
+
+
+Limitations
+-----------
+
+The check currently don't analyze code inside macros.
+
+
+Options
+-------
+
+.. option:: CommaPolicy
+
+ Controls whether to add or remove trailing commas.
+ Valid values are:
+
+ - `Append`: Add trailing commas where missing.
+ - `Remove`: Remove trailing commas where present.
+
+ Example with `CommaPolicy` set to `Append`:
+
+ .. code-block:: c++
+
+ enum Status {
+ OK,
+ Error // warning: enum should have a trailing comma
+ };
+
+ Example with `CommaPolicy` set to `Remove`:
+
+ .. code-block:: c++
+
+ enum Status {
+ OK,
+ Error, // warning: enum should not have a trailing comma
+ };
+
+ Default is `Append`.
+
+.. option:: EnumThreshold
+
+ The minimum number of enumerators required in an enum before the check
+ will warn. This applies to both `Append` and `Remove` policies.
+ Default is `1` (always check enums).
+
+.. option:: InitListThreshold
+
+ The minimum number of elements required in an initializer list before
+ the check will warn. This applies to both `Append` and `Remove` policies.
+ Default is `3`.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp
new file mode 100644
index 0000000000000..7d4a2b1cf3565
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp
@@ -0,0 +1,46 @@
+// RUN: %check_clang_tidy -std=c++20-or-later %s readability-trailing-comma %t -- \
+// RUN: -config='{CheckOptions: {readability-trailing-comma.CommaPolicy: Remove, \
+// RUN: readability-trailing-comma.InitListThreshold: 1}}'
+
+struct S { int x, y; };
+
+void f() {
+ S s1 = {.x = 1, .y = 2,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: S s1 = {.x = 1, .y = 2};
+
+ S s2 = {.x = 1,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: S s2 = {.x = 1};
+
+ int a[3] = {[0] = 1, [2] = 3,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: int a[3] = {[0] = 1, [2] = 3};
+
+ // No warnings
+ S s3 = {.x = 1, .y = 2};
+}
+
+struct N { S a, b; };
+
+void nested() {
+ N n = {.a = {.x = 1, .y = 2,}, .b = {.x = 3, .y = 4,},};
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: initializer list should not have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-2]]:54: warning: initializer list should not have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-3]]:56: warning: initializer list should not have a trailing comma
+
+ N n2 = {.a = {.x = 1, .y = 2}, .b = {.x = 3, .y = 4}};
+}
+
+struct WithArray {
+ int values[3];
+ int count;
+};
+
+void with_array() {
+ WithArray w1 = {.values = {1, 2, 3,}, .count = 3,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: initializer list should not have a trailing comma [readability-trailing-comma]
+ // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: initializer list should not have a trailing comma [readability-trailing-comma]
+
+ WithArray w2 = {.values = {1, 2, 3}, .count = 3};
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20.cpp
new file mode 100644
index 0000000000000..a0b2ce08fce50
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20.cpp
@@ -0,0 +1,46 @@
+// RUN: %check_clang_tidy -std=c++20-or-later %s readability-trailing-comma %t -- \
+// RUN: -config='{CheckOptions: {readability-trailing-comma.InitListThreshold: 1}}'
+
+struct S { int x, y; };
+
+void f() {
+ S s1 = {.x = 1, .y = 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: S s1 = {.x = 1, .y = 2,};
+
+ S s2 = {.x = 1};
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: S s2 = {.x = 1,};
+
+ int a[3] = {[0] = 1, [2] = 3};
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: int a[3] = {[0] = 1, [2] = 3,};
+
+ // No warnings
+ S s3 = {.x = 1, .y = 2,};
+}
+
+struct N { S a, b; };
+
+void nested() {
+ N n = {.a = {.x = 1, .y = 2}, .b = {.x = 3, .y = 4}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: initializer list should have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-2]]:53: warning: initializer list should have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-3]]:54: warning: initializer list should have a trailing comma
+
+ // No warning
+ N n2 = {.a = {.x = 1, .y = 2,}, .b = {.x = 3, .y = 4,},};
+}
+
+struct WithArray {
+ int values[3];
+ int count;
+};
+
+void with_array() {
+ WithArray w1 = {.values = {1, 2, 3}, .count = 3};
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: initializer list should have a trailing comma [readability-trailing-comma]
+ // CHECK-MESSAGES: :[[@LINE-2]]:50: warning: initializer list should have a trailing comma [readability-trailing-comma]
+
+ WithArray w2 = {.values = {1, 2, 3,}, .count = 3,};
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
new file mode 100644
index 0000000000000..501362aed17cd
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
@@ -0,0 +1,49 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t -- \
+// RUN: -config='{CheckOptions: {readability-trailing-comma.CommaPolicy: Remove, \
+// RUN: readability-trailing-comma.InitListThreshold: 1}}'
+
+struct S { int x, y; };
+
+enum E1 { A, B, C, };
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: enum should not have a trailing comma [readability-trailing-comma]
+// CHECK-FIXES: enum E1 { A, B, C };
+
+enum class E2 { X, Y, };
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum class E2 { X, Y };
+
+enum E3 { V = 1, };
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum E3 { V = 1 };
+
+enum E4 { P, Q };
+enum Empty {};
+
+void f() {
+ int a[] = {1, 2,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: int a[] = {1, 2};
+
+ S s = {1, 2,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: S s = {1, 2};
+
+ int b[] = {1,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: int b[] = {1};
+
+ int c[] = {1, 2};
+ S s2 = {1, 2};
+ int d[] = {};
+}
+
+struct N { S a, b; };
+
+void nested() {
+ N n = {{1, 2,}, {3, 4,},};
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: initializer list should not have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-2]]:24: warning: initializer list should not have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-3]]:26: warning: initializer list should not have a trailing comma
+
+ N n2 = {{1, 2}, {3, 4}};
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-threshold.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-threshold.cpp
new file mode 100644
index 0000000000000..3bb4256d6aa9f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-threshold.cpp
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t
+
+enum E0 {};
+
+enum E1 { A };
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: enum should have a trailing comma
+// CHECK-FIXES: enum E1 { A, };
+
+enum E2 { B, C };
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: enum should have a trailing comma
+// CHECK-FIXES: enum E2 { B, C, };
+
+// Init lists: default InitListThreshold=3
+void f() {
+ int a[] = {1}; // No warning - only 1 element
+ int b[] = {1, 2}; // No warning - only 2 elements
+ int c[] = {1, 2, 3};
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: int c[] = {1, 2, 3,};
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
new file mode 100644
index 0000000000000..61b02fa621bd2
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
@@ -0,0 +1,40 @@
+// RUN: %check_clang_tidy %s readability-trailing-comma %t -- \
+// RUN: -config='{CheckOptions: {readability-trailing-comma.InitListThreshold: 1}}'
+
+enum Color { Red, Green, Blue };
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: enum should have a trailing comma
+// CHECK-FIXES: enum Color { Red, Green, Blue, };
+
+enum SingleValue { Only };
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: enum should have a trailing comma
+// CHECK-FIXES: enum SingleValue { Only, };
+
+int arr[] = {1, 2, 3};
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: initializer list should have a trailing comma
+// CHECK-FIXES: int arr[] = {1, 2, 3,};
+
+struct Point {
+ int x;
+ int y;
+};
+
+struct Point p = {10, 20};
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: initializer list should have a trailing comma
+// CHECK-FIXES: struct Point p = {10, 20,};
+
+struct Point p2 = {.x = 1, .y = 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: initializer list should have a trailing comma
+// CHECK-FIXES: struct Point p2 = {.x = 1, .y = 2,};
+
+struct Point p3 = {.x = 5, 10};
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: initializer list should have a trailing comma
+// CHECK-FIXES: struct Point p3 = {.x = 5, 10,};
+
+int arr2[5] = {[0] = 1, [4] = 5};
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: initializer list should have a trailing comma
+// CHECK-FIXES: int arr2[5] = {[0] = 1, [4] = 5,};
+
+int matrix[2][2] = {{1, 2}, {3, 4}};
+// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: initializer list should have a trailing comma
+// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: initializer list should have a trailing comma
+// CHECK-MESSAGES: :[[@LINE-3]]:35: warning: initializer list should have a trailing comma
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
new file mode 100644
index 0000000000000..942d6964da9c1
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
@@ -0,0 +1,76 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t -- \
+// RUN: -config='{CheckOptions: {readability-trailing-comma.InitListThreshold: 1}}'
+
+struct S { int x, y; };
+
+enum E1 { A, B, C };
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: enum should have a trailing comma [readability-trailing-comma]
+// CHECK-FIXES: enum E1 { A, B, C, };
+
+enum class E2 { X, Y };
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: enum should have a trailing comma
+// CHECK-FIXES: enum class E2 { X, Y, };
+
+enum E3 { V = 1 };
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: enum should have a trailing comma
+// CHECK-FIXES: enum E3 { V = 1, };
+
+// No warnings - already have trailing commas or empty
+enum E4 { P, Q, };
+enum Empty {};
+
+void f() {
+ int a[] = {1, 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: int a[] = {1, 2,};
+
+ S s = {1, 2};
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: S s = {1, 2,};
+
+ int b[] = {1};
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: int b[] = {1,};
+
+ int c[] = {1, 2,};
+ S s2 = {1, 2,};
+ int d[] = {};
+}
+
+struct N { S a, b; };
+
+void nested() {
+ N n = {{1, 2}, {3, 4}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: initializer list should have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: initializer list should have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-3]]:24: warning: initializer list should have a trailing comma
+
+ N n2 = {{1, 2,}, {3, 4,},};
+}
+
+#define ENUM(n, a, b) enum n { a, b }
+#define INIT {1, 2}
+
+ENUM(E1M, X, Y);
+int macroArr[] = INIT;
+
+enum E2M { Am, Bm };
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: enum should have a trailing comma
+// CHECK-FIXES: enum E2M { Am, Bm, };
+
+template <typename T, typename... Ts>
+struct Pack {
+ int values[sizeof...(Ts) + 1] = {sizeof(T), sizeof(Ts)...};
+};
+
+Pack<int> single;
+Pack<int, double> two;
+Pack<int, double, char> three;
+
+template <typename... Ts>
+struct PackSingle {
+ int values[sizeof...(Ts)] = {sizeof(Ts)...};
+};
+
+PackSingle<int> p1;
+PackSingle<int, double, char> p3;
>From 1cacab7ffd4c0a390b41fb05bfed509ca294037f Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Fri, 2 Jan 2026 22:23:20 +0300
Subject: [PATCH 02/10] count lines instead of init-expr
---
.../readability/TrailingCommaCheck.cpp | 42 +++----
.../readability/TrailingCommaCheck.h | 2 -
.../trailing-comma-cxx20-remove.cpp | 64 ++++++----
.../readability/trailing-comma-cxx20.cpp | 89 ++++++++++----
.../readability/trailing-comma-remove.cpp | 86 ++++++++-----
.../readability/trailing-comma-threshold.cpp | 20 ---
.../checkers/readability/trailing-comma.c | 81 ++++++++----
.../checkers/readability/trailing-comma.cpp | 115 ++++++++++++------
8 files changed, 315 insertions(+), 184 deletions(-)
delete mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-threshold.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
index 6552e6d540550..5af89698c39f8 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
@@ -37,6 +37,11 @@ struct OptionEnumMapping<readability::TrailingCommaCheck::CommaPolicyKind> {
namespace clang::tidy::readability {
+static bool isSingleLine(SourceLocation Begin, SourceLocation End,
+ const SourceManager &SM) {
+ return SM.getExpansionLineNumber(Begin) == SM.getExpansionLineNumber(End);
+}
+
namespace {
AST_POLYMORPHIC_MATCHER(isMacro,
@@ -54,14 +59,10 @@ AST_MATCHER(InitListExpr, isEmptyInitList) { return Node.getNumInits() == 0; }
TrailingCommaCheck::TrailingCommaCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
- CommaPolicy(Options.get("CommaPolicy", CommaPolicyKind::Append)),
- EnumThreshold(Options.get("EnumThreshold", 1U)),
- InitListThreshold(Options.get("InitListThreshold", 3U)) {}
+ CommaPolicy(Options.get("CommaPolicy", CommaPolicyKind::Append)) {}
void TrailingCommaCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "CommaPolicy", CommaPolicy);
- Options.store(Opts, "EnumThreshold", EnumThreshold);
- Options.store(Opts, "InitListThreshold", InitListThreshold);
}
void TrailingCommaCheck::registerMatchers(MatchFinder *Finder) {
@@ -87,18 +88,15 @@ void TrailingCommaCheck::check(const MatchFinder::MatchResult &Result) {
void TrailingCommaCheck::checkEnumDecl(const EnumDecl *Enum,
const MatchFinder::MatchResult &Result) {
- // Count enumerators and get the last one
- unsigned NumEnumerators = 0;
+ if (isSingleLine(Enum->getBeginLoc(), Enum->getEndLoc(),
+ *Result.SourceManager) &&
+ CommaPolicy == CommaPolicyKind::Append)
+ return;
+
const EnumConstantDecl *LastEnumerator = nullptr;
- for (const EnumConstantDecl *ECD : Enum->enumerators()) {
+ for (const EnumConstantDecl *ECD : Enum->enumerators())
LastEnumerator = ECD;
- ++NumEnumerators;
- }
assert(LastEnumerator);
- assert(NumEnumerators > 0);
-
- if (NumEnumerators < EnumThreshold)
- return;
SourceLocation LastEnumLoc;
if (const Expr *Init = LastEnumerator->getInitExpr())
@@ -114,15 +112,17 @@ void TrailingCommaCheck::checkEnumDecl(const EnumDecl *Enum,
void TrailingCommaCheck::checkInitListExpr(
const InitListExpr *InitList, const MatchFinder::MatchResult &Result) {
- // We need to use the syntactic form for correct source locations.
- if (InitList->isSemanticForm())
- if (const InitListExpr *SyntacticForm = InitList->getSyntacticForm())
- InitList = SyntacticForm;
-
- const unsigned NumInits = InitList->getNumInits();
- if (NumInits < InitListThreshold)
+ // We need to use non-empty syntactic form for correct source locations.
+ if (const InitListExpr *SynInitInitList = InitList->getSyntacticForm();
+ SynInitInitList && SynInitInitList->getNumInits() > 0)
+ InitList = SynInitInitList;
+
+ if (isSingleLine(InitList->getBeginLoc(), InitList->getEndLoc(),
+ *Result.SourceManager) &&
+ CommaPolicy == CommaPolicyKind::Append)
return;
+ const unsigned NumInits = InitList->getNumInits();
const Expr *LastInit = InitList->getInit(NumInits - 1);
assert(LastInit);
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
index 789e4a6d30df4..0b91a05fc14e1 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
@@ -35,8 +35,6 @@ class TrailingCommaCheck : public ClangTidyCheck {
private:
const CommaPolicyKind CommaPolicy;
- const unsigned EnumThreshold;
- const unsigned InitListThreshold;
void checkEnumDecl(const EnumDecl *Enum,
const ast_matchers::MatchFinder::MatchResult &Result);
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp
index 7d4a2b1cf3565..78bc8d96cbf06 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp
@@ -1,35 +1,49 @@
// RUN: %check_clang_tidy -std=c++20-or-later %s readability-trailing-comma %t -- \
-// RUN: -config='{CheckOptions: {readability-trailing-comma.CommaPolicy: Remove, \
-// RUN: readability-trailing-comma.InitListThreshold: 1}}'
+// RUN: -config='{CheckOptions: {readability-trailing-comma.CommaPolicy: Remove}}'
struct S { int x, y; };
void f() {
- S s1 = {.x = 1, .y = 2,};
- // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: initializer list should not have a trailing comma
- // CHECK-FIXES: S s1 = {.x = 1, .y = 2};
+ S s1 = {
+ .x = 1,
+ .y = 2,
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: S s1 = {
+ // CHECK-FIXES-NEXT: .x = 1,
+ // CHECK-FIXES-NEXT: .y = 2
+ // CHECK-FIXES-NEXT: };
- S s2 = {.x = 1,};
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: initializer list should not have a trailing comma
- // CHECK-FIXES: S s2 = {.x = 1};
+ int a[3] = {
+ [0] = 1,
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: int a[3] = {
+ // CHECK-FIXES-NEXT: [0] = 1
+ // CHECK-FIXES-NEXT: };
- int a[3] = {[0] = 1, [2] = 3,};
- // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: initializer list should not have a trailing comma
- // CHECK-FIXES: int a[3] = {[0] = 1, [2] = 3};
+ S s2 = {.x = 1, .y = 2,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: S s2 = {.x = 1, .y = 2};
- // No warnings
- S s3 = {.x = 1, .y = 2};
+ S s3 = {
+ .x = 1,
+ .y = 2
+ };
}
struct N { S a, b; };
-void nested() {
- N n = {.a = {.x = 1, .y = 2,}, .b = {.x = 3, .y = 4,},};
- // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: initializer list should not have a trailing comma
- // CHECK-MESSAGES: :[[@LINE-2]]:54: warning: initializer list should not have a trailing comma
- // CHECK-MESSAGES: :[[@LINE-3]]:56: warning: initializer list should not have a trailing comma
+void nested() {
+ N n1 = {.a = {.x = 1, .y = 2}, .b = {.x = 3, .y = 4,},};
+ // CHECK-MESSAGES: :[[@LINE-1]]:54: warning: initializer list should not have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-2]]:56: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: N n1 = {.a = {.x = 1, .y = 2}, .b = {.x = 3, .y = 4}};
- N n2 = {.a = {.x = 1, .y = 2}, .b = {.x = 3, .y = 4}};
+ N n2 = {
+ .a = {.x = 1, .y = 2},
+ .b = {.x = 3, .y = 4}
+ };
}
struct WithArray {
@@ -38,9 +52,13 @@ struct WithArray {
};
void with_array() {
- WithArray w1 = {.values = {1, 2, 3,}, .count = 3,};
- // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: initializer list should not have a trailing comma [readability-trailing-comma]
- // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: initializer list should not have a trailing comma [readability-trailing-comma]
+ WithArray w2 = {.values = {1, 2, 3,}, .count = 3,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: initializer list should not have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: WithArray w2 = {.values = {1, 2, 3}, .count = 3};
- WithArray w2 = {.values = {1, 2, 3}, .count = 3};
+ WithArray w3 = {
+ .values = {1, 2, 3},
+ .count = 3
+ };
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20.cpp
index a0b2ce08fce50..b2f6ed072563f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20.cpp
@@ -1,35 +1,63 @@
-// RUN: %check_clang_tidy -std=c++20-or-later %s readability-trailing-comma %t -- \
-// RUN: -config='{CheckOptions: {readability-trailing-comma.InitListThreshold: 1}}'
+// RUN: %check_clang_tidy -std=c++20-or-later %s readability-trailing-comma %t
struct S { int x, y; };
void f() {
- S s1 = {.x = 1, .y = 2};
- // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: initializer list should have a trailing comma
- // CHECK-FIXES: S s1 = {.x = 1, .y = 2,};
+ S s1 = {
+ .x = 1,
+ .y = 2
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: S s1 = {
+ // CHECK-FIXES-NEXT: .x = 1,
+ // CHECK-FIXES-NEXT: .y = 2,
+ // CHECK-FIXES-NEXT: };
- S s2 = {.x = 1};
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: initializer list should have a trailing comma
- // CHECK-FIXES: S s2 = {.x = 1,};
+ int a[3] = {
+ [0] = 1
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: int a[3] = {
+ // CHECK-FIXES-NEXT: [0] = 1,
+ // CHECK-FIXES-NEXT: };
- int a[3] = {[0] = 1, [2] = 3};
- // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: initializer list should have a trailing comma
- // CHECK-FIXES: int a[3] = {[0] = 1, [2] = 3,};
+ S s2 = {.x = 1, .y = 2};
+ S s3 = {.x = 1};
- // No warnings
- S s3 = {.x = 1, .y = 2,};
+ S s4 = {
+ .x = 1,
+ };
}
struct N { S a, b; };
void nested() {
- N n = {.a = {.x = 1, .y = 2}, .b = {.x = 3, .y = 4}};
- // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: initializer list should have a trailing comma
- // CHECK-MESSAGES: :[[@LINE-2]]:53: warning: initializer list should have a trailing comma
- // CHECK-MESSAGES: :[[@LINE-3]]:54: warning: initializer list should have a trailing comma
+ N n = {
+ .a = {.x = 1, .y = 2},
+ .b = {
+ .x = 3,
+ .y = 4
+ }
+ };
+ // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: initializer list should have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-3]]:6: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: N n = {
+ // CHECK-FIXES-NEXT: .a = {.x = 1, .y = 2},
+ // CHECK-FIXES-NEXT: .b = {
+ // CHECK-FIXES-NEXT: .x = 3,
+ // CHECK-FIXES-NEXT: .y = 4,
+ // CHECK-FIXES-NEXT: },
+ // CHECK-FIXES-NEXT: };
- // No warning
- N n2 = {.a = {.x = 1, .y = 2,}, .b = {.x = 3, .y = 4,},};
+ N n2 = {.a = {.x = 1, .y = 2}, .b = {.x = 3, .y = 4}};
+
+ N n3 = {
+ .a = {.x = 1, .y = 2},
+ .b = {
+ .x = 3,
+ .y = 4,
+ },
+ };
}
struct WithArray {
@@ -38,9 +66,24 @@ struct WithArray {
};
void with_array() {
- WithArray w1 = {.values = {1, 2, 3}, .count = 3};
- // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: initializer list should have a trailing comma [readability-trailing-comma]
- // CHECK-MESSAGES: :[[@LINE-2]]:50: warning: initializer list should have a trailing comma [readability-trailing-comma]
+ WithArray w1 = {
+ .values = {1, 2,
+ 3
+ },
+ .count = 3
+ };
+ // CHECK-MESSAGES: :[[@LINE-4]]:8: warning: initializer list should have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-3]]:15: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: WithArray w1 = {
+ // CHECK-FIXES-NEXT: .values = {1, 2,
+ // CHECK-FIXES-NEXT: 3,
+ // CHECK-FIXES-NEXT: },
+ // CHECK-FIXES-NEXT: .count = 3,
+ // CHECK-FIXES-NEXT: };
- WithArray w2 = {.values = {1, 2, 3,}, .count = 3,};
+ WithArray w2 = {.values = {1, 2, 3}, .count = 3};
+ WithArray w3 = {
+ .values = {1, 2, 3},
+ .count = 3,
+ };
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
index 501362aed17cd..b74daeee090ad 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
@@ -1,49 +1,79 @@
// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t -- \
-// RUN: -config='{CheckOptions: {readability-trailing-comma.CommaPolicy: Remove, \
-// RUN: readability-trailing-comma.InitListThreshold: 1}}'
+// RUN: -config='{CheckOptions: {readability-trailing-comma.CommaPolicy: Remove}}'
struct S { int x, y; };
-enum E1 { A, B, C, };
-// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: enum should not have a trailing comma [readability-trailing-comma]
-// CHECK-FIXES: enum E1 { A, B, C };
+enum E1 {
+ A,
+ B,
+ C,
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:4: warning: enum should not have a trailing comma [readability-trailing-comma]
+// CHECK-FIXES: enum E1 {
+// CHECK-FIXES-NEXT: A,
+// CHECK-FIXES-NEXT: B,
+// CHECK-FIXES-NEXT: C
+// CHECK-FIXES-NEXT: };
-enum class E2 { X, Y, };
-// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: enum should not have a trailing comma
-// CHECK-FIXES: enum class E2 { X, Y };
+enum E2 {
+ V = 1,
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:8: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum E2 {
+// CHECK-FIXES-NEXT: V = 1
+// CHECK-FIXES-NEXT: };
-enum E3 { V = 1, };
-// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: enum should not have a trailing comma
-// CHECK-FIXES: enum E3 { V = 1 };
+enum SingleLine { A1, B1, C1, };
+// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum SingleLine { A1, B1, C1 };
-enum E4 { P, Q };
+enum E3 {
+ P,
+ Q
+};
enum Empty {};
void f() {
- int a[] = {1, 2,};
- // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: initializer list should not have a trailing comma
- // CHECK-FIXES: int a[] = {1, 2};
+ // Multi-line init lists with trailing commas - should warn to remove
+ int a[] = {
+ 1,
+ 2,
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:6: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: int a[] = {
+ // CHECK-FIXES-NEXT: 1,
+ // CHECK-FIXES-NEXT: 2
+ // CHECK-FIXES-NEXT: };
- S s = {1, 2,};
- // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: initializer list should not have a trailing comma
- // CHECK-FIXES: S s = {1, 2};
+ S s = {
+ 1,
+ 2,
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:6: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: S s = {
+ // CHECK-FIXES-NEXT: 1,
+ // CHECK-FIXES-NEXT: 2
+ // CHECK-FIXES-NEXT: };
- int b[] = {1,};
+ int b[] = {1, 2, 3,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: int b[] = {1, 2, 3};
+ S s2 = {1, 2,};
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: initializer list should not have a trailing comma
- // CHECK-FIXES: int b[] = {1};
+ // CHECK-FIXES: S s2 = {1, 2};
- int c[] = {1, 2};
- S s2 = {1, 2};
+ int c[] = {
+ 1,
+ 2
+ };
int d[] = {};
}
struct N { S a, b; };
-
void nested() {
- N n = {{1, 2,}, {3, 4,},};
+ N n = {{3, 4,},};
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: initializer list should not have a trailing comma
- // CHECK-MESSAGES: :[[@LINE-2]]:24: warning: initializer list should not have a trailing comma
- // CHECK-MESSAGES: :[[@LINE-3]]:26: warning: initializer list should not have a trailing comma
-
- N n2 = {{1, 2}, {3, 4}};
+ // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: N n = {{[{][{]3, 4[}][}]}};
+ N n2 = {{3, 4}};
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-threshold.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-threshold.cpp
deleted file mode 100644
index 3bb4256d6aa9f..0000000000000
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-threshold.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t
-
-enum E0 {};
-
-enum E1 { A };
-// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: enum should have a trailing comma
-// CHECK-FIXES: enum E1 { A, };
-
-enum E2 { B, C };
-// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: enum should have a trailing comma
-// CHECK-FIXES: enum E2 { B, C, };
-
-// Init lists: default InitListThreshold=3
-void f() {
- int a[] = {1}; // No warning - only 1 element
- int b[] = {1, 2}; // No warning - only 2 elements
- int c[] = {1, 2, 3};
- // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: initializer list should have a trailing comma
- // CHECK-FIXES: int c[] = {1, 2, 3,};
-}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
index 61b02fa621bd2..d416f3cc03384 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
@@ -1,40 +1,67 @@
-// RUN: %check_clang_tidy %s readability-trailing-comma %t -- \
-// RUN: -config='{CheckOptions: {readability-trailing-comma.InitListThreshold: 1}}'
+// RUN: %check_clang_tidy %s readability-trailing-comma %t
-enum Color { Red, Green, Blue };
-// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: enum should have a trailing comma
-// CHECK-FIXES: enum Color { Red, Green, Blue, };
-
-enum SingleValue { Only };
-// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: enum should have a trailing comma
-// CHECK-FIXES: enum SingleValue { Only, };
+enum Color {
+ Red,
+ Green,
+ Blue
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:7: warning: enum should have a trailing comma
+// CHECK-FIXES: enum Color {
+// CHECK-FIXES-NEXT: Red,
+// CHECK-FIXES-NEXT: Green,
+// CHECK-FIXES-NEXT: Blue,
+// CHECK-FIXES-NEXT: };
-int arr[] = {1, 2, 3};
-// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: initializer list should have a trailing comma
-// CHECK-FIXES: int arr[] = {1, 2, 3,};
+enum SingleLine { A, B, C };
+enum SingleLine2 { X1, Y1, };
struct Point {
int x;
int y;
};
-struct Point p = {10, 20};
-// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: initializer list should have a trailing comma
-// CHECK-FIXES: struct Point p = {10, 20,};
+struct Point p = {
+ 10,
+ 20
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: initializer list should have a trailing comma
+// CHECK-FIXES: struct Point p = {
+// CHECK-FIXES-NEXT: 10,
+// CHECK-FIXES-NEXT: 20,
+// CHECK-FIXES-NEXT: };
-struct Point p2 = {.x = 1, .y = 2};
-// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: initializer list should have a trailing comma
-// CHECK-FIXES: struct Point p2 = {.x = 1, .y = 2,};
+struct Point p2 = {
+ .x = 1,
+ .y = 2
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: initializer list should have a trailing comma
+// CHECK-FIXES: struct Point p2 = {
+// CHECK-FIXES-NEXT: .x = 1,
+// CHECK-FIXES-NEXT: .y = 2,
+// CHECK-FIXES-NEXT: };
-struct Point p3 = {.x = 5, 10};
-// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: initializer list should have a trailing comma
-// CHECK-FIXES: struct Point p3 = {.x = 5, 10,};
+int arr2[5] = {
+ [0] = 1
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:10: warning: initializer list should have a trailing comma
+// CHECK-FIXES: int arr2[5] = {
+// CHECK-FIXES-NEXT: [0] = 1,
+// CHECK-FIXES-NEXT: };
-int arr2[5] = {[0] = 1, [4] = 5};
-// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: initializer list should have a trailing comma
-// CHECK-FIXES: int arr2[5] = {[0] = 1, [4] = 5,};
+int multiArr[] = {
+ 1
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:4: warning: initializer list should have a trailing comma
+// CHECK-FIXES: int multiArr[] = {
+// CHECK-FIXES-NEXT: 1,
+// CHECK-FIXES-NEXT: };
+int arr[] = {1, 2, 3};
+struct Point p3 = {10, 20};
+struct Point p4 = {.x = 1, .y = 2};
int matrix[2][2] = {{1, 2}, {3, 4}};
-// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: initializer list should have a trailing comma
-// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: initializer list should have a trailing comma
-// CHECK-MESSAGES: :[[@LINE-3]]:35: warning: initializer list should have a trailing comma
+
+enum WithComma {
+ X,
+ Y,
+};
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
index 942d6964da9c1..11cdbd23babcf 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
@@ -1,63 +1,98 @@
-// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t -- \
-// RUN: -config='{CheckOptions: {readability-trailing-comma.InitListThreshold: 1}}'
+// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t
struct S { int x, y; };
-enum E1 { A, B, C };
-// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: enum should have a trailing comma [readability-trailing-comma]
-// CHECK-FIXES: enum E1 { A, B, C, };
-
-enum class E2 { X, Y };
-// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: enum should have a trailing comma
-// CHECK-FIXES: enum class E2 { X, Y, };
-
-enum E3 { V = 1 };
-// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: enum should have a trailing comma
-// CHECK-FIXES: enum E3 { V = 1, };
-
-// No warnings - already have trailing commas or empty
-enum E4 { P, Q, };
+enum E1 {
+ A,
+ B,
+ C
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:4: warning: enum should have a trailing comma [readability-trailing-comma]
+// CHECK-FIXES: enum E1 {
+// CHECK-FIXES-NEXT: A,
+// CHECK-FIXES-NEXT: B,
+// CHECK-FIXES-NEXT: C,
+// CHECK-FIXES-NEXT: };
+
+enum E2 {
+ V = 1
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:8: warning: enum should have a trailing comma
+// CHECK-FIXES: enum E2 {
+// CHECK-FIXES-NEXT: V = 1,
+// CHECK-FIXES-NEXT: };
+
+// Single-line enums - no warnings
+enum SingleLine { A1, B1, C1 };
+enum class SingleLine2 { X1, Y1, };
+
+enum E3 {
+ P,
+ Q,
+};
enum Empty {};
void f() {
- int a[] = {1, 2};
- // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: initializer list should have a trailing comma
- // CHECK-FIXES: int a[] = {1, 2,};
-
- S s = {1, 2};
- // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: initializer list should have a trailing comma
- // CHECK-FIXES: S s = {1, 2,};
-
- int b[] = {1};
- // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: initializer list should have a trailing comma
- // CHECK-FIXES: int b[] = {1,};
-
- int c[] = {1, 2,};
- S s2 = {1, 2,};
+ int a[] = {
+ 1
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:6: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: int a[] = {
+ // CHECK-FIXES-NEXT: 1,
+ // CHECK-FIXES-NEXT: };
+
+ S s = {
+ 1,
+ 2
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:6: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: S s = {
+ // CHECK-FIXES-NEXT: 1,
+ // CHECK-FIXES-NEXT: 2,
+ // CHECK-FIXES-NEXT: };
+
+ // Single-line init lists - no warnings
+ int b[] = {1, 2, 3};
+ S s2 = {1, 2};
+
+ int c[] = {
+ 1,
+ 2,
+ };
int d[] = {};
}
struct N { S a, b; };
-
void nested() {
N n = {{1, 2}, {3, 4}};
- // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: initializer list should have a trailing comma
- // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: initializer list should have a trailing comma
- // CHECK-MESSAGES: :[[@LINE-3]]:24: warning: initializer list should have a trailing comma
-
N n2 = {{1, 2,}, {3, 4,},};
}
+void nestedMultiLine() {
+ N n = {
+ {1, 2},
+ {3, 4}
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: N n = {
+ // CHECK-FIXES-NEXT: {1, 2},
+ // CHECK-FIXES-NEXT: {3, 4},
+ // CHECK-FIXES-NEXT: };
+
+ N n2 = {
+ {1, 2},
+ {3, 4},
+ };
+}
+
+// Macros are ignored
#define ENUM(n, a, b) enum n { a, b }
#define INIT {1, 2}
-ENUM(E1M, X, Y);
+ENUM(E1M, Xm, Ym);
int macroArr[] = INIT;
-enum E2M { Am, Bm };
-// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: enum should have a trailing comma
-// CHECK-FIXES: enum E2M { Am, Bm, };
-
+// Template pack expansions - no warnings
template <typename T, typename... Ts>
struct Pack {
int values[sizeof...(Ts) + 1] = {sizeof(T), sizeof(Ts)...};
>From f93108d6632ea204826aebff905ae598e97e0e7e Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Fri, 2 Jan 2026 23:21:13 +0300
Subject: [PATCH 03/10] added 2 different policies
---
.../readability/TrailingCommaCheck.cpp | 39 +++++++++-----
.../readability/TrailingCommaCheck.h | 8 +--
.../checks/readability/trailing-comma.rst | 53 +++++++------------
.../trailing-comma-cxx20-remove.cpp | 2 +-
.../readability/trailing-comma-remove.cpp | 2 +-
.../checkers/readability/trailing-comma.c | 2 +
.../checkers/readability/trailing-comma.cpp | 13 +++--
7 files changed, 64 insertions(+), 55 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
index 5af89698c39f8..9ba116c8216ef 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
@@ -28,6 +28,8 @@ struct OptionEnumMapping<readability::TrailingCommaCheck::CommaPolicyKind> {
"Append"},
{readability::TrailingCommaCheck::CommaPolicyKind::Remove,
"Remove"},
+ {readability::TrailingCommaCheck::CommaPolicyKind::Ignore,
+ "Ignore"},
};
return {Mapping};
}
@@ -59,10 +61,14 @@ AST_MATCHER(InitListExpr, isEmptyInitList) { return Node.getNumInits() == 0; }
TrailingCommaCheck::TrailingCommaCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
- CommaPolicy(Options.get("CommaPolicy", CommaPolicyKind::Append)) {}
+ SingleLineCommaPolicy(
+ Options.get("SingleLineCommaPolicy", CommaPolicyKind::Remove)),
+ MultiLineCommaPolicy(
+ Options.get("MultiLineCommaPolicy", CommaPolicyKind::Append)) {}
void TrailingCommaCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
- Options.store(Opts, "CommaPolicy", CommaPolicy);
+ Options.store(Opts, "SingleLineCommaPolicy", SingleLineCommaPolicy);
+ Options.store(Opts, "MultiLineCommaPolicy", MultiLineCommaPolicy);
}
void TrailingCommaCheck::registerMatchers(MatchFinder *Finder) {
@@ -88,9 +94,12 @@ void TrailingCommaCheck::check(const MatchFinder::MatchResult &Result) {
void TrailingCommaCheck::checkEnumDecl(const EnumDecl *Enum,
const MatchFinder::MatchResult &Result) {
- if (isSingleLine(Enum->getBeginLoc(), Enum->getEndLoc(),
- *Result.SourceManager) &&
- CommaPolicy == CommaPolicyKind::Append)
+ const bool IsSingleLine = isSingleLine(Enum->getBeginLoc(), Enum->getEndLoc(),
+ *Result.SourceManager);
+ const CommaPolicyKind Policy =
+ IsSingleLine ? SingleLineCommaPolicy : MultiLineCommaPolicy;
+
+ if (Policy == CommaPolicyKind::Ignore)
return;
const EnumConstantDecl *LastEnumerator = nullptr;
@@ -107,7 +116,7 @@ void TrailingCommaCheck::checkEnumDecl(const EnumDecl *Enum,
if (LastEnumLoc.isInvalid())
return;
- emitDiag(LastEnumLoc, DiagKind::Enum, Result);
+ emitDiag(LastEnumLoc, DiagKind::Enum, Result, Policy);
}
void TrailingCommaCheck::checkInitListExpr(
@@ -117,9 +126,12 @@ void TrailingCommaCheck::checkInitListExpr(
SynInitInitList && SynInitInitList->getNumInits() > 0)
InitList = SynInitInitList;
- if (isSingleLine(InitList->getBeginLoc(), InitList->getEndLoc(),
- *Result.SourceManager) &&
- CommaPolicy == CommaPolicyKind::Append)
+ const bool IsSingleLine = isSingleLine(
+ InitList->getBeginLoc(), InitList->getEndLoc(), *Result.SourceManager);
+ const CommaPolicyKind Policy =
+ IsSingleLine ? SingleLineCommaPolicy : MultiLineCommaPolicy;
+
+ if (Policy == CommaPolicyKind::Ignore)
return;
const unsigned NumInits = InitList->getNumInits();
@@ -134,12 +146,13 @@ void TrailingCommaCheck::checkInitListExpr(
if (LastInitLoc.isInvalid())
return;
- emitDiag(LastInitLoc, DiagKind::InitList, Result);
+ emitDiag(LastInitLoc, DiagKind::InitList, Result, Policy);
}
void TrailingCommaCheck::emitDiag(
SourceLocation LastLoc, DiagKind Kind,
- const ast_matchers::MatchFinder::MatchResult &Result) {
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ CommaPolicyKind Policy) {
const std::optional<Token> NextToken =
utils::lexer::findNextTokenSkippingComments(
LastLoc, *Result.SourceManager, getLangOpts());
@@ -150,11 +163,11 @@ void TrailingCommaCheck::emitDiag(
const SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
LastLoc, 0, *Result.SourceManager, getLangOpts());
- if (CommaPolicy == CommaPolicyKind::Append && !HasTrailingComma) {
+ if (Policy == CommaPolicyKind::Append && !HasTrailingComma) {
diag(InsertLoc, "%select{initializer list|enum}0 should have "
"a trailing comma")
<< Kind << FixItHint::CreateInsertion(InsertLoc, ",");
- } else if (CommaPolicy == CommaPolicyKind::Remove && HasTrailingComma) {
+ } else if (Policy == CommaPolicyKind::Remove && HasTrailingComma) {
const SourceLocation CommaLoc = NextToken->getLocation();
if (CommaLoc.isInvalid())
return;
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
index 0b91a05fc14e1..a1adedda6a36c 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
@@ -31,10 +31,11 @@ class TrailingCommaCheck : public ClangTidyCheck {
return TK_IgnoreUnlessSpelledInSource;
}
- enum class CommaPolicyKind { Append, Remove };
+ enum class CommaPolicyKind { Append, Remove, Ignore };
private:
- const CommaPolicyKind CommaPolicy;
+ const CommaPolicyKind SingleLineCommaPolicy;
+ const CommaPolicyKind MultiLineCommaPolicy;
void checkEnumDecl(const EnumDecl *Enum,
const ast_matchers::MatchFinder::MatchResult &Result);
@@ -44,7 +45,8 @@ class TrailingCommaCheck : public ClangTidyCheck {
// Values correspond to %select{initializer list|enum}0 indices
enum DiagKind { InitList = 0, Enum = 1 };
void emitDiag(SourceLocation LastLoc, DiagKind Kind,
- const ast_matchers::MatchFinder::MatchResult &Result);
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ CommaPolicyKind Policy);
};
} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst
index f1bd09d5d4e08..c61b42d21e2a4 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst
@@ -6,15 +6,16 @@ readability-trailing-comma
Checks for presence or absence of trailing commas in enum definitions and
initializer lists.
-The check can either append trailing commas where they are missing or remove
-them where they are present, based on the configured policy.
+The check supports separate policies for single-line and multi-line constructs,
+allowing different styles for each. By default, the check enforces trailing
+commas in multi-line constructs and removes them from single-line constructs.
-Trailing commas offer several benefits:
+Trailing commas in multi-line constructs offer several benefits:
-- Adding or removing elements may only changes a single line, making diffs
- smaller and easier to read.
+- Adding or removing elements only changes a single line, making diffs smaller
+ and easier to read.
- Formatters may change code to a more desired style.
-- Code generators avoid for need special handling of the last element.
+- Code generators avoid the need for special handling of the last element.
.. code-block:: c++
@@ -42,42 +43,26 @@ The check currently don't analyze code inside macros.
Options
-------
-.. option:: CommaPolicy
+.. option:: SingleLineCommaPolicy
- Controls whether to add or remove trailing commas.
+ Controls whether to add, remove, or ignore trailing commas in single-line
+ enum definitions and initializer lists.
Valid values are:
- `Append`: Add trailing commas where missing.
- `Remove`: Remove trailing commas where present.
+ - `Ignore`: Do not check single-line constructs.
- Example with `CommaPolicy` set to `Append`:
+ Default is `Remove`.
- .. code-block:: c++
+.. option:: MultiLineCommaPolicy
- enum Status {
- OK,
- Error // warning: enum should have a trailing comma
- };
-
- Example with `CommaPolicy` set to `Remove`:
-
- .. code-block:: c++
+ Controls whether to add, remove, or ignore trailing commas in multi-line
+ enum definitions and initializer lists.
+ Valid values are:
- enum Status {
- OK,
- Error, // warning: enum should not have a trailing comma
- };
+ - `Append`: Add trailing commas where missing.
+ - `Remove`: Remove trailing commas where present.
+ - `Ignore`: Do not check multi-line constructs.
Default is `Append`.
-
-.. option:: EnumThreshold
-
- The minimum number of enumerators required in an enum before the check
- will warn. This applies to both `Append` and `Remove` policies.
- Default is `1` (always check enums).
-
-.. option:: InitListThreshold
-
- The minimum number of elements required in an initializer list before
- the check will warn. This applies to both `Append` and `Remove` policies.
- Default is `3`.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp
index 78bc8d96cbf06..6c18678f88fec 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx20-remove.cpp
@@ -1,5 +1,5 @@
// RUN: %check_clang_tidy -std=c++20-or-later %s readability-trailing-comma %t -- \
-// RUN: -config='{CheckOptions: {readability-trailing-comma.CommaPolicy: Remove}}'
+// RUN: -config='{CheckOptions: {readability-trailing-comma.SingleLineCommaPolicy: Remove, readability-trailing-comma.MultiLineCommaPolicy: Remove}}'
struct S { int x, y; };
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
index b74daeee090ad..9e1f50253949a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
@@ -1,5 +1,5 @@
// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t -- \
-// RUN: -config='{CheckOptions: {readability-trailing-comma.CommaPolicy: Remove}}'
+// RUN: -config='{CheckOptions: {readability-trailing-comma.SingleLineCommaPolicy: Remove, readability-trailing-comma.MultiLineCommaPolicy: Remove}}'
struct S { int x, y; };
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
index d416f3cc03384..a11222cd0e150 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
@@ -14,6 +14,8 @@ enum Color {
enum SingleLine { A, B, C };
enum SingleLine2 { X1, Y1, };
+// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum SingleLine2 { X1, Y1 };
struct Point {
int x;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
index 11cdbd23babcf..8614dc098ddca 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
@@ -22,9 +22,10 @@ enum E2 {
// CHECK-FIXES-NEXT: V = 1,
// CHECK-FIXES-NEXT: };
-// Single-line enums - no warnings
enum SingleLine { A1, B1, C1 };
enum class SingleLine2 { X1, Y1, };
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum class SingleLine2 { X1, Y1 };
enum E3 {
P,
@@ -51,10 +52,13 @@ void f() {
// CHECK-FIXES-NEXT: 2,
// CHECK-FIXES-NEXT: };
- // Single-line init lists - no warnings
int b[] = {1, 2, 3};
S s2 = {1, 2};
+ int e[] = {1, 2, 3,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: int e[] = {1, 2, 3};
+
int c[] = {
1,
2,
@@ -65,7 +69,10 @@ void f() {
struct N { S a, b; };
void nested() {
N n = {{1, 2}, {3, 4}};
- N n2 = {{1, 2,}, {3, 4,},};
+ N n2 = {{3, 4,},};
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: initializer list should not have a trailing comma
+ // CHECK-MESSAGES: :[[@LINE-2]]:18: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: N n2 = {{[{][{]3, 4[}][}]}};
}
void nestedMultiLine() {
>From f915b8b0aa1d2050eb771104908a28c6a6b2be5b Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Sat, 3 Jan 2026 00:09:33 +0300
Subject: [PATCH 04/10] more tests
---
.../readability/TrailingCommaCheck.cpp | 8 +--
.../checks/readability/trailing-comma.rst | 6 +-
.../checkers/readability/trailing-comma.c | 54 +++++++++++++++++-
.../checkers/readability/trailing-comma.cpp | 57 ++++++++++++++++++-
4 files changed, 113 insertions(+), 12 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
index 9ba116c8216ef..6cf65c0f42561 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
@@ -134,8 +134,7 @@ void TrailingCommaCheck::checkInitListExpr(
if (Policy == CommaPolicyKind::Ignore)
return;
- const unsigned NumInits = InitList->getNumInits();
- const Expr *LastInit = InitList->getInit(NumInits - 1);
+ const Expr *LastInit = LastInit = InitList->inits().back();
assert(LastInit);
// Skip pack expansions - they already have special syntax with '...'
@@ -160,10 +159,9 @@ void TrailingCommaCheck::emitDiag(
return;
const bool HasTrailingComma = NextToken->is(tok::comma);
- const SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
- LastLoc, 0, *Result.SourceManager, getLangOpts());
-
if (Policy == CommaPolicyKind::Append && !HasTrailingComma) {
+ const SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
+ LastLoc, 0, *Result.SourceManager, getLangOpts());
diag(InsertLoc, "%select{initializer list|enum}0 should have "
"a trailing comma")
<< Kind << FixItHint::CreateInsertion(InsertLoc, ",");
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst
index c61b42d21e2a4..83e05fb1bead6 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/trailing-comma.rst
@@ -12,8 +12,8 @@ commas in multi-line constructs and removes them from single-line constructs.
Trailing commas in multi-line constructs offer several benefits:
-- Adding or removing elements only changes a single line, making diffs smaller
- and easier to read.
+- Adding or removing elements at the end only changes a single line, making
+ diffs smaller and easier to read.
- Formatters may change code to a more desired style.
- Code generators avoid the need for special handling of the last element.
@@ -37,7 +37,7 @@ Trailing commas in multi-line constructs offer several benefits:
Limitations
-----------
-The check currently don't analyze code inside macros.
+The check currently doesn't analyze code inside macros.
Options
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
index a11222cd0e150..bdf9912e54155 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.c
@@ -16,6 +16,17 @@ enum SingleLine { A, B, C };
enum SingleLine2 { X1, Y1, };
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: enum should not have a trailing comma
// CHECK-FIXES: enum SingleLine2 { X1, Y1 };
+enum SingleVal { VAL1 };
+enum SingleVal2 { VAL2, };
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum SingleVal2 { VAL2 };
+enum SingleVal3 {
+ VAL3
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:7: warning: enum should have a trailing comma
+// CHECK-FIXES: enum SingleVal3 {
+// CHECK-FIXES-NEXT: VAL3,
+// CHECK-FIXES-NEXT: };
struct Point {
int x;
@@ -62,8 +73,45 @@ int arr[] = {1, 2, 3};
struct Point p3 = {10, 20};
struct Point p4 = {.x = 1, .y = 2};
int matrix[2][2] = {{1, 2}, {3, 4}};
+int single1[1] = {42};
+int single2[1] = {42,};
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: initializer list should not have a trailing comma
+// CHECK-FIXES: int single2[1] = {42};
+int single3[1] = {
+ 42
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: initializer list should have a trailing comma
+// CHECK-FIXES: int single3[1] = {
+// CHECK-FIXES-NEXT: 42,
+// CHECK-FIXES-NEXT: };
+int single4[1] = {
+ 42,
+};
+int empty1[] = {};
+struct Nested { int a[2]; int b; };
+struct Nested nest1 = {{1}, 2};
+struct Nested nest2 = {{1,}, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: initializer list should not have a trailing comma
+// CHECK-FIXES: struct Nested nest2 = {{[{][{]}}1}, 2};
+struct Nested nest3 = {
+ {1},
+ 2
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:4: warning: initializer list should have a trailing comma
+// CHECK-FIXES: struct Nested nest3 = {
+// CHECK-FIXES-NEXT: {1},
+// CHECK-FIXES-NEXT: 2,
+// CHECK-FIXES-NEXT: };
-enum WithComma {
- X,
- Y,
+struct Point singleDesig1 = {.x = 10};
+struct Point singleDesig2 = {.x = 10,};
+// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: initializer list should not have a trailing comma
+// CHECK-FIXES: struct Point singleDesig2 = {.x = 10};
+struct Point singleDesig3 = {};
+struct Point singleDesig4 = {
+ .x = 10
};
+// CHECK-MESSAGES: :[[@LINE-2]]:10: warning: initializer list should have a trailing comma
+// CHECK-FIXES: struct Point singleDesig4 = {
+// CHECK-FIXES-NEXT: .x = 10,
+// CHECK-FIXES-NEXT: };
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
index 8614dc098ddca..c75a4af1df888 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
@@ -31,6 +31,22 @@ enum E3 {
P,
Q,
};
+
+enum SingleEnum1 { ONE };
+enum SingleEnum2 { TWO, };
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum SingleEnum2 { TWO };
+enum SingleEnum3 {
+ THREE
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:8: warning: enum should have a trailing comma
+// CHECK-FIXES: enum SingleEnum3 {
+// CHECK-FIXES-NEXT: THREE,
+// CHECK-FIXES-NEXT: };
+enum SingleEnum4 {
+ FOUR,
+};
+
enum Empty {};
void f() {
@@ -64,6 +80,25 @@ void f() {
2,
};
int d[] = {};
+
+ int single1[] = {1};
+ int single2[] = {1,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: int single2[] = {1};
+ int single3[] = {
+ 1
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:6: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: int single3[] = {
+ // CHECK-FIXES-NEXT: 1,
+ // CHECK-FIXES-NEXT: };
+ int single4[] = {
+ 1,
+ };
+ S singleS1 = {42};
+ S singleS2 = {42,};
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: S singleS2 = {42};
}
struct N { S a, b; };
@@ -90,6 +125,26 @@ void nestedMultiLine() {
{1, 2},
{3, 4},
};
+
+ struct Container { int arr[3]; };
+ Container c1 = {{}};
+ Container c2 = {{},};
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: Container c2 = {{[{][{][}][}]}};
+
+ struct Wrapper { S s; };
+ Wrapper w1 = {{1}};
+ Wrapper w2 = {{1,}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: initializer list should not have a trailing comma
+ // CHECK-FIXES: Wrapper w2 = {{[{][{]1[}][}]}};
+
+ Wrapper w3 = {
+ {1}
+ };
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: initializer list should have a trailing comma
+ // CHECK-FIXES: Wrapper w3 = {
+ // CHECK-FIXES-NEXT: {1},
+ // CHECK-FIXES-NEXT: };
}
// Macros are ignored
@@ -105,7 +160,7 @@ struct Pack {
int values[sizeof...(Ts) + 1] = {sizeof(T), sizeof(Ts)...};
};
-Pack<int> single;
+Pack<int> one;
Pack<int, double> two;
Pack<int, double, char> three;
>From c833bbe1c55e5e504cd19ff4c9520105928b47a9 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Sat, 3 Jan 2026 18:04:08 +0300
Subject: [PATCH 05/10] add tests for attrs and config
---
.../readability/TrailingCommaCheck.cpp | 26 +++++++++++--
.../trailing-comma-wrong-config.cpp | 11 ++++++
.../checkers/readability/trailing-comma.cpp | 39 +++++++++++++++++--
3 files changed, 70 insertions(+), 6 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
index 6cf65c0f42561..67d123dcdab50 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
@@ -64,7 +64,14 @@ TrailingCommaCheck::TrailingCommaCheck(StringRef Name,
SingleLineCommaPolicy(
Options.get("SingleLineCommaPolicy", CommaPolicyKind::Remove)),
MultiLineCommaPolicy(
- Options.get("MultiLineCommaPolicy", CommaPolicyKind::Append)) {}
+ Options.get("MultiLineCommaPolicy", CommaPolicyKind::Append)) {
+ if (SingleLineCommaPolicy == CommaPolicyKind::Ignore &&
+ MultiLineCommaPolicy == CommaPolicyKind::Ignore)
+ configurationDiag("The check '%0' will not perform any analysis because "
+ "'SingleLineCommaPolicy' and 'MultiLineCommaPolicy' are "
+ "both set to 'Ignore'.")
+ << Name;
+}
void TrailingCommaCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "SingleLineCommaPolicy", SingleLineCommaPolicy);
@@ -108,10 +115,23 @@ void TrailingCommaCheck::checkEnumDecl(const EnumDecl *Enum,
assert(LastEnumerator);
SourceLocation LastEnumLoc;
- if (const Expr *Init = LastEnumerator->getInitExpr())
+ if (const Expr *Init = LastEnumerator->getInitExpr()) {
+ // InitExpr goes after attributes, so we don't need to process attributes.
LastEnumLoc = Init->getEndLoc();
- else
+ } else {
LastEnumLoc = LastEnumerator->getLocation();
+ if (LastEnumerator->hasAttrs()) {
+ const Attr *LastAttr = LastEnumerator->getAttrs().back();
+ // Skip ']' tokens at the end of final attribute like '[[deprecated]]'.
+ std::optional<Token> NextTok;
+ while ((NextTok = utils::lexer::findNextTokenSkippingComments(
+ NextTok.has_value() ? NextTok->getEndLoc()
+ : LastAttr->getRange().getEnd(),
+ *Result.SourceManager, getLangOpts())) &&
+ NextTok->is(tok::r_square))
+ LastEnumLoc = NextTok->getEndLoc();
+ }
+ }
if (LastEnumLoc.isInvalid())
return;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp
new file mode 100644
index 0000000000000..ac54916d9dfea
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp
@@ -0,0 +1,11 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t -- \
+// RUN: -config='{CheckOptions: {readability-trailing-comma.SingleLineCommaPolicy: Ignore, readability-trailing-comma.MultiLineCommaPolicy: Ignore}}'
+
+
+// CHECK-MESSAGES: warning: The check 'readability-trailing-comma' will not perform any analysis because 'SingleLineCommaPolicy' and 'MultiLineCommaPolicy' are both set to 'Ignore'. [clang-tidy-config]
+
+enum E1 {
+ A
+};
+
+enum E2 { B, };
\ No newline at end of file
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
index c75a4af1df888..9a8c40257e16a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
@@ -23,9 +23,9 @@ enum E2 {
// CHECK-FIXES-NEXT: };
enum SingleLine { A1, B1, C1 };
-enum class SingleLine2 { X1, Y1, };
-// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: enum should not have a trailing comma
-// CHECK-FIXES: enum class SingleLine2 { X1, Y1 };
+enum class SingleLine2 { X1, Y1 = 1, };
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum class SingleLine2 { X1, Y1 = 1 };
enum E3 {
P,
@@ -49,6 +49,39 @@ enum SingleEnum4 {
enum Empty {};
+enum EnumWithAttrs {
+ E1 [[deprecated]] = 1,
+ E2 [[deprecated]]
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:20: warning: enum should have a trailing comma
+// CHECK-FIXES: enum EnumWithAttrs {
+// CHECK-FIXES-NEXT: E1 {{\[\[}}deprecated{{\]\]}} = 1,
+// CHECK-FIXES-NEXT: E2 {{\[\[}}deprecated{{\]\]}},
+// CHECK-FIXES-NEXT: };
+
+enum EnumWithAttrs2 {
+ E3 [[deprecated]] = 1,
+ E4 [[deprecated]] = 2
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:24: warning: enum should have a trailing comma
+// CHECK-FIXES: enum EnumWithAttrs2 {
+// CHECK-FIXES-NEXT: E3 {{\[\[}}deprecated{{\]\]}} = 1,
+// CHECK-FIXES-NEXT: E4 {{\[\[}}deprecated{{\]\]}} = 2,
+// CHECK-FIXES-NEXT: };
+
+enum EnumWithAttrsTrailing {
+ E5 [[deprecated]] = 1,
+ E6 [[deprecated]],
+};
+
+enum SingleLineAttrs { E7 [[deprecated]], E8 [[deprecated]] [[deprecated ]] , };
+// CHECK-MESSAGES: :[[@LINE-1]]:78: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum SingleLineAttrs { E7 {{\[\[}}deprecated{{\]\]}}, E8 {{\[\[}}deprecated{{\]\]}} {{\[\[}}deprecated {{\]\]}} };
+
+enum SingleLineAttrs2 { E9 [[deprecated]], E10 [[deprecated]] = 1, };
+// CHECK-MESSAGES: :[[@LINE-1]]:66: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum SingleLineAttrs2 { E9 {{\[\[}}deprecated{{\]\]}}, E10 {{\[\[}}deprecated{{\]\]}} = 1 };
+
void f() {
int a[] = {
1
>From e98ae039cebb79573ff555b6685d22edc365b707 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Sat, 3 Jan 2026 20:00:18 +0300
Subject: [PATCH 06/10] enable in cxx98
---
.../readability/TrailingCommaCheck.h | 2 +-
.../readability/trailing-comma-cxx11.cpp | 56 +++++++++++++++++++
.../readability/trailing-comma-remove.cpp | 2 +-
.../trailing-comma-wrong-config.cpp | 2 +-
.../checkers/readability/trailing-comma.cpp | 56 +------------------
5 files changed, 60 insertions(+), 58 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx11.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
index a1adedda6a36c..623aff43dae44 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
@@ -25,7 +25,7 @@ class TrailingCommaCheck : public ClangTidyCheck {
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 || LangOpts.C99;
+ return LangOpts.CPlusPlus || LangOpts.C99;
}
std::optional<TraversalKind> getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx11.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx11.cpp
new file mode 100644
index 0000000000000..a51c14f29d80b
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx11.cpp
@@ -0,0 +1,56 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t
+
+enum class SingleLine2 { X1, Y1 = 1, };
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum class SingleLine2 { X1, Y1 = 1 };
+
+enum EnumWithAttrs {
+ E1 [[deprecated]] = 1,
+ E2 [[deprecated]]
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:20: warning: enum should have a trailing comma
+// CHECK-FIXES: enum EnumWithAttrs {
+// CHECK-FIXES-NEXT: E1 {{\[\[}}deprecated{{\]\]}} = 1,
+// CHECK-FIXES-NEXT: E2 {{\[\[}}deprecated{{\]\]}},
+// CHECK-FIXES-NEXT: };
+
+enum EnumWithAttrs2 {
+ E3 [[deprecated]] = 1,
+ E4 [[deprecated]] = 2
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:24: warning: enum should have a trailing comma
+// CHECK-FIXES: enum EnumWithAttrs2 {
+// CHECK-FIXES-NEXT: E3 {{\[\[}}deprecated{{\]\]}} = 1,
+// CHECK-FIXES-NEXT: E4 {{\[\[}}deprecated{{\]\]}} = 2,
+// CHECK-FIXES-NEXT: };
+
+enum EnumWithAttrsTrailing {
+ E5 [[deprecated]] = 1,
+ E6 [[deprecated]],
+};
+
+enum SingleLineAttrs { E7 [[deprecated]], E8 [[deprecated]] [[deprecated ]] , };
+// CHECK-MESSAGES: :[[@LINE-1]]:78: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum SingleLineAttrs { E7 {{\[\[}}deprecated{{\]\]}}, E8 {{\[\[}}deprecated{{\]\]}} {{\[\[}}deprecated {{\]\]}} };
+
+enum SingleLineAttrs2 { E9 [[deprecated]], E10 [[deprecated]] = 1, };
+// CHECK-MESSAGES: :[[@LINE-1]]:66: warning: enum should not have a trailing comma
+// CHECK-FIXES: enum SingleLineAttrs2 { E9 {{\[\[}}deprecated{{\]\]}}, E10 {{\[\[}}deprecated{{\]\]}} = 1 };
+
+// Template pack expansions - no warnings
+template <typename T, typename... Ts>
+struct Pack {
+ int values[sizeof...(Ts) + 1] = {sizeof(T), sizeof(Ts)...};
+};
+
+Pack<int> one;
+Pack<int, double> two;
+Pack<int, double, char> three;
+
+template <typename... Ts>
+struct PackSingle {
+ int values[sizeof...(Ts)] = {sizeof(Ts)...};
+};
+
+PackSingle<int> p1;
+PackSingle<int, double, char> p3;
\ No newline at end of file
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
index 9e1f50253949a..fadce1808876f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-remove.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t -- \
+// RUN: %check_clang_tidy -std=c++98-or-later %s readability-trailing-comma %t -- \
// RUN: -config='{CheckOptions: {readability-trailing-comma.SingleLineCommaPolicy: Remove, readability-trailing-comma.MultiLineCommaPolicy: Remove}}'
struct S { int x, y; };
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp
index ac54916d9dfea..a59a306b7dacf 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t -- \
+// RUN: %check_clang_tidy -std=c++98-or-later %s readability-trailing-comma %t -- \
// RUN: -config='{CheckOptions: {readability-trailing-comma.SingleLineCommaPolicy: Ignore, readability-trailing-comma.MultiLineCommaPolicy: Ignore}}'
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
index 9a8c40257e16a..82d54591afa3d 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++11-or-later %s readability-trailing-comma %t
+// RUN: %check_clang_tidy -std=c++98-or-later %s readability-trailing-comma %t
struct S { int x, y; };
@@ -23,9 +23,6 @@ enum E2 {
// CHECK-FIXES-NEXT: };
enum SingleLine { A1, B1, C1 };
-enum class SingleLine2 { X1, Y1 = 1, };
-// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: enum should not have a trailing comma
-// CHECK-FIXES: enum class SingleLine2 { X1, Y1 = 1 };
enum E3 {
P,
@@ -49,39 +46,6 @@ enum SingleEnum4 {
enum Empty {};
-enum EnumWithAttrs {
- E1 [[deprecated]] = 1,
- E2 [[deprecated]]
-};
-// CHECK-MESSAGES: :[[@LINE-2]]:20: warning: enum should have a trailing comma
-// CHECK-FIXES: enum EnumWithAttrs {
-// CHECK-FIXES-NEXT: E1 {{\[\[}}deprecated{{\]\]}} = 1,
-// CHECK-FIXES-NEXT: E2 {{\[\[}}deprecated{{\]\]}},
-// CHECK-FIXES-NEXT: };
-
-enum EnumWithAttrs2 {
- E3 [[deprecated]] = 1,
- E4 [[deprecated]] = 2
-};
-// CHECK-MESSAGES: :[[@LINE-2]]:24: warning: enum should have a trailing comma
-// CHECK-FIXES: enum EnumWithAttrs2 {
-// CHECK-FIXES-NEXT: E3 {{\[\[}}deprecated{{\]\]}} = 1,
-// CHECK-FIXES-NEXT: E4 {{\[\[}}deprecated{{\]\]}} = 2,
-// CHECK-FIXES-NEXT: };
-
-enum EnumWithAttrsTrailing {
- E5 [[deprecated]] = 1,
- E6 [[deprecated]],
-};
-
-enum SingleLineAttrs { E7 [[deprecated]], E8 [[deprecated]] [[deprecated ]] , };
-// CHECK-MESSAGES: :[[@LINE-1]]:78: warning: enum should not have a trailing comma
-// CHECK-FIXES: enum SingleLineAttrs { E7 {{\[\[}}deprecated{{\]\]}}, E8 {{\[\[}}deprecated{{\]\]}} {{\[\[}}deprecated {{\]\]}} };
-
-enum SingleLineAttrs2 { E9 [[deprecated]], E10 [[deprecated]] = 1, };
-// CHECK-MESSAGES: :[[@LINE-1]]:66: warning: enum should not have a trailing comma
-// CHECK-FIXES: enum SingleLineAttrs2 { E9 {{\[\[}}deprecated{{\]\]}}, E10 {{\[\[}}deprecated{{\]\]}} = 1 };
-
void f() {
int a[] = {
1
@@ -186,21 +150,3 @@ void nestedMultiLine() {
ENUM(E1M, Xm, Ym);
int macroArr[] = INIT;
-
-// Template pack expansions - no warnings
-template <typename T, typename... Ts>
-struct Pack {
- int values[sizeof...(Ts) + 1] = {sizeof(T), sizeof(Ts)...};
-};
-
-Pack<int> one;
-Pack<int, double> two;
-Pack<int, double, char> three;
-
-template <typename... Ts>
-struct PackSingle {
- int values[sizeof...(Ts)] = {sizeof(Ts)...};
-};
-
-PackSingle<int> p1;
-PackSingle<int, double, char> p3;
>From ce50f8563d51b1c6511e1d3bb7ef21c104638911 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Sat, 3 Jan 2026 20:01:11 +0300
Subject: [PATCH 07/10] newlines
---
.../clang-tidy/checkers/readability/trailing-comma-cxx11.cpp | 2 +-
.../checkers/readability/trailing-comma-wrong-config.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx11.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx11.cpp
index a51c14f29d80b..9f37db2c837c3 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx11.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-cxx11.cpp
@@ -53,4 +53,4 @@ struct PackSingle {
};
PackSingle<int> p1;
-PackSingle<int, double, char> p3;
\ No newline at end of file
+PackSingle<int, double, char> p3;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp
index a59a306b7dacf..a3ce4e70d426a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma-wrong-config.cpp
@@ -8,4 +8,4 @@ enum E1 {
A
};
-enum E2 { B, };
\ No newline at end of file
+enum E2 { B, };
>From 76347c9092fd1460b05f2cc0a250387008595d88 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Sat, 3 Jan 2026 23:26:46 +0300
Subject: [PATCH 08/10] use lexing instead of loop
---
.../readability/TrailingCommaCheck.cpp | 51 +++++--------------
.../readability/TrailingCommaCheck.h | 3 +-
.../clang-tidy/utils/LexerUtils.cpp | 6 +++
.../clang-tidy/utils/LexerUtils.h | 5 ++
4 files changed, 25 insertions(+), 40 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
index 67d123dcdab50..2452581c31d5e 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
@@ -109,34 +109,11 @@ void TrailingCommaCheck::checkEnumDecl(const EnumDecl *Enum,
if (Policy == CommaPolicyKind::Ignore)
return;
- const EnumConstantDecl *LastEnumerator = nullptr;
- for (const EnumConstantDecl *ECD : Enum->enumerators())
- LastEnumerator = ECD;
- assert(LastEnumerator);
-
- SourceLocation LastEnumLoc;
- if (const Expr *Init = LastEnumerator->getInitExpr()) {
- // InitExpr goes after attributes, so we don't need to process attributes.
- LastEnumLoc = Init->getEndLoc();
- } else {
- LastEnumLoc = LastEnumerator->getLocation();
- if (LastEnumerator->hasAttrs()) {
- const Attr *LastAttr = LastEnumerator->getAttrs().back();
- // Skip ']' tokens at the end of final attribute like '[[deprecated]]'.
- std::optional<Token> NextTok;
- while ((NextTok = utils::lexer::findNextTokenSkippingComments(
- NextTok.has_value() ? NextTok->getEndLoc()
- : LastAttr->getRange().getEnd(),
- *Result.SourceManager, getLangOpts())) &&
- NextTok->is(tok::r_square))
- LastEnumLoc = NextTok->getEndLoc();
- }
- }
-
- if (LastEnumLoc.isInvalid())
- return;
+ const std::optional<Token> LastTok =
+ utils::lexer::findPreviousTokenSkippingComments(
+ Enum->getBraceRange().getEnd(), *Result.SourceManager, getLangOpts());
- emitDiag(LastEnumLoc, DiagKind::Enum, Result, Policy);
+ emitDiag(LastTok->getLocation(), LastTok, DiagKind::Enum, Result, Policy);
}
void TrailingCommaCheck::checkInitListExpr(
@@ -161,24 +138,20 @@ void TrailingCommaCheck::checkInitListExpr(
if (isa<PackExpansionExpr>(LastInit))
return;
- const SourceLocation LastInitLoc = LastInit->getEndLoc();
- if (LastInitLoc.isInvalid())
- return;
-
- emitDiag(LastInitLoc, DiagKind::InitList, Result, Policy);
+ emitDiag(LastInit->getEndLoc(),
+ utils::lexer::findNextTokenSkippingComments(
+ LastInit->getEndLoc(), *Result.SourceManager, getLangOpts()),
+ DiagKind::InitList, Result, Policy);
}
void TrailingCommaCheck::emitDiag(
- SourceLocation LastLoc, DiagKind Kind,
+ SourceLocation LastLoc, std::optional<Token> Token, DiagKind Kind,
const ast_matchers::MatchFinder::MatchResult &Result,
CommaPolicyKind Policy) {
- const std::optional<Token> NextToken =
- utils::lexer::findNextTokenSkippingComments(
- LastLoc, *Result.SourceManager, getLangOpts());
- if (!NextToken)
+ if (LastLoc.isInvalid() || !Token)
return;
- const bool HasTrailingComma = NextToken->is(tok::comma);
+ const bool HasTrailingComma = Token->is(tok::comma);
if (Policy == CommaPolicyKind::Append && !HasTrailingComma) {
const SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
LastLoc, 0, *Result.SourceManager, getLangOpts());
@@ -186,7 +159,7 @@ void TrailingCommaCheck::emitDiag(
"a trailing comma")
<< Kind << FixItHint::CreateInsertion(InsertLoc, ",");
} else if (Policy == CommaPolicyKind::Remove && HasTrailingComma) {
- const SourceLocation CommaLoc = NextToken->getLocation();
+ const SourceLocation CommaLoc = Token->getLocation();
if (CommaLoc.isInvalid())
return;
diag(CommaLoc, "%select{initializer list|enum}0 should not have "
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
index 623aff43dae44..f10b3fbdfb142 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.h
@@ -44,7 +44,8 @@ class TrailingCommaCheck : public ClangTidyCheck {
// Values correspond to %select{initializer list|enum}0 indices
enum DiagKind { InitList = 0, Enum = 1 };
- void emitDiag(SourceLocation LastLoc, DiagKind Kind,
+ void emitDiag(SourceLocation LastLoc, std::optional<Token> Token,
+ DiagKind Kind,
const ast_matchers::MatchFinder::MatchResult &Result,
CommaPolicyKind Policy);
};
diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
index 6e93871289ed9..6c57b5fb3cf7a 100644
--- a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
@@ -70,6 +70,12 @@ SourceLocation findPreviousTokenKind(SourceLocation Start,
}
}
+std::optional<Token>
+findPreviousTokenSkippingComments(SourceLocation Start, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ return Lexer::findPreviousToken(Start, SM, LangOpts, false);
+}
+
SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM,
const LangOptions &LangOpts) {
return findNextAnyTokenKind(Start, SM, LangOpts, tok::comma, tok::semi);
diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.h b/clang-tools-extra/clang-tidy/utils/LexerUtils.h
index c5fb646c0efd9..23d7f0219fb94 100644
--- a/clang-tools-extra/clang-tidy/utils/LexerUtils.h
+++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.h
@@ -37,6 +37,11 @@ SourceLocation findPreviousTokenKind(SourceLocation Start,
const LangOptions &LangOpts,
tok::TokenKind TK);
+// Finds previous token that's not a comment.
+std::optional<Token>
+findPreviousTokenSkippingComments(SourceLocation Start, const SourceManager &SM,
+ const LangOptions &LangOpts);
+
SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM,
const LangOptions &LangOpts);
>From 55950c076ad0954b838327786a9be807966a14ad Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Sun, 4 Jan 2026 01:26:47 +0300
Subject: [PATCH 09/10] user regular lexer instead of utils
---
.../clang-tidy/readability/TrailingCommaCheck.cpp | 4 ++--
clang-tools-extra/clang-tidy/utils/LexerUtils.cpp | 6 ------
clang-tools-extra/clang-tidy/utils/LexerUtils.h | 5 -----
3 files changed, 2 insertions(+), 13 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
index 2452581c31d5e..43c685b01e065 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
@@ -110,8 +110,8 @@ void TrailingCommaCheck::checkEnumDecl(const EnumDecl *Enum,
return;
const std::optional<Token> LastTok =
- utils::lexer::findPreviousTokenSkippingComments(
- Enum->getBraceRange().getEnd(), *Result.SourceManager, getLangOpts());
+ Lexer::findPreviousToken(Enum->getBraceRange().getEnd(),
+ *Result.SourceManager, getLangOpts(), false);
emitDiag(LastTok->getLocation(), LastTok, DiagKind::Enum, Result, Policy);
}
diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
index 6c57b5fb3cf7a..6e93871289ed9 100644
--- a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
@@ -70,12 +70,6 @@ SourceLocation findPreviousTokenKind(SourceLocation Start,
}
}
-std::optional<Token>
-findPreviousTokenSkippingComments(SourceLocation Start, const SourceManager &SM,
- const LangOptions &LangOpts) {
- return Lexer::findPreviousToken(Start, SM, LangOpts, false);
-}
-
SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM,
const LangOptions &LangOpts) {
return findNextAnyTokenKind(Start, SM, LangOpts, tok::comma, tok::semi);
diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.h b/clang-tools-extra/clang-tidy/utils/LexerUtils.h
index 23d7f0219fb94..c5fb646c0efd9 100644
--- a/clang-tools-extra/clang-tidy/utils/LexerUtils.h
+++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.h
@@ -37,11 +37,6 @@ SourceLocation findPreviousTokenKind(SourceLocation Start,
const LangOptions &LangOpts,
tok::TokenKind TK);
-// Finds previous token that's not a comment.
-std::optional<Token>
-findPreviousTokenSkippingComments(SourceLocation Start, const SourceManager &SM,
- const LangOptions &LangOpts);
-
SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM,
const LangOptions &LangOpts);
>From 5451cf5163532fd4ce76f538d633811a072fd81f Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Wed, 7 Jan 2026 11:14:26 +0800
Subject: [PATCH 10/10] address feedback
---
clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp | 2 +-
.../test/clang-tidy/checkers/readability/trailing-comma.cpp | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
index 43c685b01e065..dde1ea2e3f7c2 100644
--- a/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/TrailingCommaCheck.cpp
@@ -131,7 +131,7 @@ void TrailingCommaCheck::checkInitListExpr(
if (Policy == CommaPolicyKind::Ignore)
return;
- const Expr *LastInit = LastInit = InitList->inits().back();
+ const Expr *LastInit = InitList->inits().back();
assert(LastInit);
// Skip pack expansions - they already have special syntax with '...'
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
index 82d54591afa3d..f4a0265dd8c3b 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/trailing-comma.cpp
@@ -147,6 +147,8 @@ void nestedMultiLine() {
// Macros are ignored
#define ENUM(n, a, b) enum n { a, b }
#define INIT {1, 2}
+#define ITEMS 1,2
ENUM(E1M, Xm, Ym);
int macroArr[] = INIT;
+int a[] = { ITEMS };
More information about the cfe-commits
mailing list