[clang] [clang-format] Add support for additional C++ declaration specifiers in QualifierOrder (PR #160853)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 15 13:19:59 PST 2026
https://github.com/Katze719 updated https://github.com/llvm/llvm-project/pull/160853
>From 7fe56cba4a357541f5c2f6607fea46bb74d475f3 Mon Sep 17 00:00:00 2001
From: Katze719 <pauldorn1234 at gmail.com>
Date: Fri, 26 Sep 2025 09:37:35 +0000
Subject: [PATCH 1/6] Add support for new C++ declaration specifiers in
QualifierOrder
---
clang/lib/Format/QualifierAlignmentFixer.cpp | 24 +++
clang/unittests/Format/QualifierFixerTest.cpp | 142 +++++++++++++-----
2 files changed, 131 insertions(+), 35 deletions(-)
diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp
index 441a37a4902b7..823a6e5c8054d 100644
--- a/clang/lib/Format/QualifierAlignmentFixer.cpp
+++ b/clang/lib/Format/QualifierAlignmentFixer.cpp
@@ -169,6 +169,18 @@ static bool isQualifier(const FormatToken *const Tok) {
case tok::kw_constexpr:
case tok::kw_restrict:
case tok::kw_friend:
+ case tok::kw_typedef:
+ case tok::kw_consteval:
+ case tok::kw_constinit:
+ case tok::kw_thread_local:
+ case tok::kw_extern:
+ case tok::kw_mutable:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_long:
+ case tok::kw_short:
+ case tok::kw_decltype:
+ case tok::kw_explicit:
return true;
default:
return false;
@@ -529,6 +541,18 @@ tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier(
.Case("constexpr", tok::kw_constexpr)
.Case("restrict", tok::kw_restrict)
.Case("friend", tok::kw_friend)
+ .Case("typedef", tok::kw_typedef)
+ .Case("consteval", tok::kw_consteval)
+ .Case("constinit", tok::kw_constinit)
+ .Case("thread_local", tok::kw_thread_local)
+ .Case("extern", tok::kw_extern)
+ .Case("mutable", tok::kw_mutable)
+ .Case("signed", tok::kw_signed)
+ .Case("unsigned", tok::kw_unsigned)
+ .Case("long", tok::kw_long)
+ .Case("short", tok::kw_short)
+ .Case("decltype", tok::kw_decltype)
+ .Case("explicit", tok::kw_explicit)
.Default(tok::identifier);
}
diff --git a/clang/unittests/Format/QualifierFixerTest.cpp b/clang/unittests/Format/QualifierFixerTest.cpp
index f42f2e307f713..090a97607c02d 100644
--- a/clang/unittests/Format/QualifierFixerTest.cpp
+++ b/clang/unittests/Format/QualifierFixerTest.cpp
@@ -50,6 +50,30 @@ TEST_F(QualifierFixerTest, RotateTokens) {
tok::kw_restrict);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("friend"),
tok::kw_friend);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("typedef"),
+ tok::kw_typedef);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("consteval"),
+ tok::kw_consteval);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("constinit"),
+ tok::kw_constinit);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("thread_local"),
+ tok::kw_thread_local);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("extern"),
+ tok::kw_extern);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("mutable"),
+ tok::kw_mutable);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("signed"),
+ tok::kw_signed);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("unsigned"),
+ tok::kw_unsigned);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("long"),
+ tok::kw_long);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("short"),
+ tok::kw_short);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("decltype"),
+ tok::kw_decltype);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("explicit"),
+ tok::kw_explicit);
}
TEST_F(QualifierFixerTest, FailQualifierInvalidConfiguration) {
@@ -1057,48 +1081,37 @@ TEST_F(QualifierFixerTest, IsQualifierType) {
ConfiguredTokens.push_back(tok::kw_restrict);
ConfiguredTokens.push_back(tok::kw_constexpr);
ConfiguredTokens.push_back(tok::kw_friend);
+ ConfiguredTokens.push_back(tok::kw_typedef);
+ ConfiguredTokens.push_back(tok::kw_consteval);
+ ConfiguredTokens.push_back(tok::kw_constinit);
+ ConfiguredTokens.push_back(tok::kw_thread_local);
+ ConfiguredTokens.push_back(tok::kw_extern);
+ ConfiguredTokens.push_back(tok::kw_mutable);
+ ConfiguredTokens.push_back(tok::kw_signed);
+ ConfiguredTokens.push_back(tok::kw_unsigned);
+ ConfiguredTokens.push_back(tok::kw_long);
+ ConfiguredTokens.push_back(tok::kw_short);
+ ConfiguredTokens.push_back(tok::kw_decltype);
+ ConfiguredTokens.push_back(tok::kw_explicit);
TestLexer lexer{Allocator, Buffers};
const auto LangOpts = getFormattingLangOpts();
auto Tokens = lexer.lex(
- "const static inline auto restrict int double long constexpr friend");
- ASSERT_EQ(Tokens.size(), 11u) << Tokens;
-
- EXPECT_TRUE(
- isConfiguredQualifierOrType(Tokens[0], ConfiguredTokens, LangOpts));
- EXPECT_TRUE(
- isConfiguredQualifierOrType(Tokens[1], ConfiguredTokens, LangOpts));
- EXPECT_TRUE(
- isConfiguredQualifierOrType(Tokens[2], ConfiguredTokens, LangOpts));
- EXPECT_TRUE(
- isConfiguredQualifierOrType(Tokens[3], ConfiguredTokens, LangOpts));
- EXPECT_TRUE(
- isConfiguredQualifierOrType(Tokens[4], ConfiguredTokens, LangOpts));
- EXPECT_TRUE(
- isConfiguredQualifierOrType(Tokens[5], ConfiguredTokens, LangOpts));
- EXPECT_TRUE(
- isConfiguredQualifierOrType(Tokens[6], ConfiguredTokens, LangOpts));
- EXPECT_TRUE(
- isConfiguredQualifierOrType(Tokens[7], ConfiguredTokens, LangOpts));
- EXPECT_TRUE(
- isConfiguredQualifierOrType(Tokens[8], ConfiguredTokens, LangOpts));
- EXPECT_TRUE(
- isConfiguredQualifierOrType(Tokens[9], ConfiguredTokens, LangOpts));
-
- EXPECT_TRUE(isQualifierOrType(Tokens[0], LangOpts));
- EXPECT_TRUE(isQualifierOrType(Tokens[1], LangOpts));
- EXPECT_TRUE(isQualifierOrType(Tokens[2], LangOpts));
- EXPECT_TRUE(isQualifierOrType(Tokens[3], LangOpts));
- EXPECT_TRUE(isQualifierOrType(Tokens[4], LangOpts));
- EXPECT_TRUE(isQualifierOrType(Tokens[5], LangOpts));
- EXPECT_TRUE(isQualifierOrType(Tokens[6], LangOpts));
- EXPECT_TRUE(isQualifierOrType(Tokens[7], LangOpts));
- EXPECT_TRUE(isQualifierOrType(Tokens[8], LangOpts));
- EXPECT_TRUE(isQualifierOrType(Tokens[9], LangOpts));
+ "const static inline restrict int double long constexpr friend "
+ "typedef consteval constinit thread_local extern mutable signed unsigned short decltype explicit");
+ ASSERT_EQ(Tokens.size(), 20u) << Tokens;
+
+ // Test that all tokens are recognized
+ for (size_t i = 0; i < 20; ++i) {
+ EXPECT_TRUE(isConfiguredQualifierOrType(Tokens[i], ConfiguredTokens, LangOpts))
+ << "Token " << i << " should be recognized";
+ EXPECT_TRUE(isQualifierOrType(Tokens[i], LangOpts))
+ << "Token " << i << " should be recognized by isQualifierOrType";
+ }
auto NotTokens = lexer.lex("for while do Foo Bar ");
- ASSERT_EQ(NotTokens.size(), 6u) << Tokens;
+ ASSERT_EQ(NotTokens.size(), 6u) << NotTokens;
EXPECT_FALSE(
isConfiguredQualifierOrType(NotTokens[0], ConfiguredTokens, LangOpts));
@@ -1384,6 +1397,65 @@ TEST_F(QualifierFixerTest, TemplatesLeft) {
"TemplateType<Container const> t;", Style);
}
+TEST_F(QualifierFixerTest, NewQualifierSupport) {
+ FormatStyle Style = getLLVMStyle();
+ Style.QualifierAlignment = FormatStyle::QAS_Custom;
+
+ // Test typedef qualifier
+ Style.QualifierOrder = {"typedef", "type"};
+ verifyFormat("typedef int MyInt;", Style);
+
+ // Test consteval qualifier
+ Style.QualifierOrder = {"consteval", "type"};
+ verifyFormat("consteval int func();", "int consteval func();", Style);
+
+ // Test constinit qualifier
+ Style.QualifierOrder = {"constinit", "static", "type"};
+ verifyFormat("constinit static int var = 10;", "static constinit int var = 10;", Style);
+
+ // Test thread_local qualifier
+ Style.QualifierOrder = {"thread_local", "static", "type"};
+ verifyFormat("thread_local static int counter;", "static thread_local int counter;", Style);
+
+ // Test extern qualifier
+ Style.QualifierOrder = {"extern", "type"};
+ verifyFormat("extern int global_var;", "int extern global_var;", Style);
+
+ // Test mutable qualifier
+ Style.QualifierOrder = {"mutable", "type"};
+ verifyFormat("mutable int cache;", "int mutable cache;", Style);
+
+ // Test signed/unsigned qualifiers
+ Style.QualifierOrder = {"signed", "type"};
+ verifyFormat("signed int num;", "int signed num;", Style);
+ Style.QualifierOrder = {"unsigned", "type"};
+ verifyFormat("unsigned int num;", "int unsigned num;", Style);
+
+ // Test long/short qualifiers
+ Style.QualifierOrder = {"long", "type"};
+ verifyFormat("long int num;", "int long num;", Style);
+ Style.QualifierOrder = {"short", "type"};
+ verifyFormat("short int num;", "int short num;", Style);
+
+ // Test decltype qualifier
+ Style.QualifierOrder = {"decltype", "type"};
+ // Note: decltype is typically used with parentheses and doesn't usually get reordered
+ // This test mainly verifies it's recognized as a qualifier
+
+ // Test explicit qualifier
+ Style.QualifierOrder = {"explicit", "type"};
+ // Note: explicit is typically used with constructors and doesn't usually get reordered
+ // This test mainly verifies it's recognized as a qualifier
+
+ // Test complex combination with new qualifiers
+ Style.QualifierOrder = {"extern", "thread_local", "static", "constexpr",
+ "inline", "unsigned", "long", "type",
+ "const", "volatile"};
+
+ verifyFormat("extern thread_local static constexpr inline unsigned long int const volatile var;",
+ "volatile const extern constexpr thread_local static inline unsigned long int var;", Style);
+}
+
TEST_F(QualifierFixerTest, Ranges) {
FormatStyle Style = getLLVMStyle();
Style.QualifierAlignment = FormatStyle::QAS_Custom;
>From cf2d2410267e8349173a802c398710627a38013e Mon Sep 17 00:00:00 2001
From: Katze719 <pauldorn1234 at gmail.com>
Date: Sat, 4 Oct 2025 20:46:49 +0200
Subject: [PATCH 2/6] Remove decltype qualifier handling from
QualifierAlignmentFixer
---
clang/lib/Format/QualifierAlignmentFixer.cpp | 2 --
clang/unittests/Format/QualifierFixerTest.cpp | 26 +++----------------
2 files changed, 3 insertions(+), 25 deletions(-)
diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp
index 823a6e5c8054d..6614367106dff 100644
--- a/clang/lib/Format/QualifierAlignmentFixer.cpp
+++ b/clang/lib/Format/QualifierAlignmentFixer.cpp
@@ -179,7 +179,6 @@ static bool isQualifier(const FormatToken *const Tok) {
case tok::kw_unsigned:
case tok::kw_long:
case tok::kw_short:
- case tok::kw_decltype:
case tok::kw_explicit:
return true;
default:
@@ -551,7 +550,6 @@ tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier(
.Case("unsigned", tok::kw_unsigned)
.Case("long", tok::kw_long)
.Case("short", tok::kw_short)
- .Case("decltype", tok::kw_decltype)
.Case("explicit", tok::kw_explicit)
.Default(tok::identifier);
}
diff --git a/clang/unittests/Format/QualifierFixerTest.cpp b/clang/unittests/Format/QualifierFixerTest.cpp
index 090a97607c02d..cb6230fae3004 100644
--- a/clang/unittests/Format/QualifierFixerTest.cpp
+++ b/clang/unittests/Format/QualifierFixerTest.cpp
@@ -70,8 +70,6 @@ TEST_F(QualifierFixerTest, RotateTokens) {
tok::kw_long);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("short"),
tok::kw_short);
- EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("decltype"),
- tok::kw_decltype);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("explicit"),
tok::kw_explicit);
}
@@ -1091,7 +1089,6 @@ TEST_F(QualifierFixerTest, IsQualifierType) {
ConfiguredTokens.push_back(tok::kw_unsigned);
ConfiguredTokens.push_back(tok::kw_long);
ConfiguredTokens.push_back(tok::kw_short);
- ConfiguredTokens.push_back(tok::kw_decltype);
ConfiguredTokens.push_back(tok::kw_explicit);
TestLexer lexer{Allocator, Buffers};
@@ -1099,11 +1096,11 @@ TEST_F(QualifierFixerTest, IsQualifierType) {
auto Tokens = lexer.lex(
"const static inline restrict int double long constexpr friend "
- "typedef consteval constinit thread_local extern mutable signed unsigned short decltype explicit");
- ASSERT_EQ(Tokens.size(), 20u) << Tokens;
+ "typedef consteval constinit thread_local extern mutable signed unsigned short explicit");
+ ASSERT_EQ(Tokens.size(), 19u) << Tokens;
// Test that all tokens are recognized
- for (size_t i = 0; i < 20; ++i) {
+ for (size_t i = 0; i < 19; ++i) {
EXPECT_TRUE(isConfiguredQualifierOrType(Tokens[i], ConfiguredTokens, LangOpts))
<< "Token " << i << " should be recognized";
EXPECT_TRUE(isQualifierOrType(Tokens[i], LangOpts))
@@ -1401,53 +1398,36 @@ TEST_F(QualifierFixerTest, NewQualifierSupport) {
FormatStyle Style = getLLVMStyle();
Style.QualifierAlignment = FormatStyle::QAS_Custom;
- // Test typedef qualifier
Style.QualifierOrder = {"typedef", "type"};
verifyFormat("typedef int MyInt;", Style);
- // Test consteval qualifier
Style.QualifierOrder = {"consteval", "type"};
verifyFormat("consteval int func();", "int consteval func();", Style);
- // Test constinit qualifier
Style.QualifierOrder = {"constinit", "static", "type"};
verifyFormat("constinit static int var = 10;", "static constinit int var = 10;", Style);
- // Test thread_local qualifier
Style.QualifierOrder = {"thread_local", "static", "type"};
verifyFormat("thread_local static int counter;", "static thread_local int counter;", Style);
- // Test extern qualifier
Style.QualifierOrder = {"extern", "type"};
verifyFormat("extern int global_var;", "int extern global_var;", Style);
- // Test mutable qualifier
Style.QualifierOrder = {"mutable", "type"};
verifyFormat("mutable int cache;", "int mutable cache;", Style);
- // Test signed/unsigned qualifiers
Style.QualifierOrder = {"signed", "type"};
verifyFormat("signed int num;", "int signed num;", Style);
Style.QualifierOrder = {"unsigned", "type"};
verifyFormat("unsigned int num;", "int unsigned num;", Style);
- // Test long/short qualifiers
Style.QualifierOrder = {"long", "type"};
verifyFormat("long int num;", "int long num;", Style);
Style.QualifierOrder = {"short", "type"};
verifyFormat("short int num;", "int short num;", Style);
- // Test decltype qualifier
- Style.QualifierOrder = {"decltype", "type"};
- // Note: decltype is typically used with parentheses and doesn't usually get reordered
- // This test mainly verifies it's recognized as a qualifier
-
- // Test explicit qualifier
Style.QualifierOrder = {"explicit", "type"};
- // Note: explicit is typically used with constructors and doesn't usually get reordered
- // This test mainly verifies it's recognized as a qualifier
- // Test complex combination with new qualifiers
Style.QualifierOrder = {"extern", "thread_local", "static", "constexpr",
"inline", "unsigned", "long", "type",
"const", "volatile"};
>From 340f0aaebc821828e6d6e4d049a026341860e523 Mon Sep 17 00:00:00 2001
From: Katze719 <pauldorn1234 at gmail.com>
Date: Wed, 14 Jan 2026 21:09:58 +0100
Subject: [PATCH 3/6] Refactor QualifierFixerTest for improved readability and
support for new qualifiers
---
clang/unittests/Format/QualifierFixerTest.cpp | 78 ++++++++++---------
1 file changed, 41 insertions(+), 37 deletions(-)
diff --git a/clang/unittests/Format/QualifierFixerTest.cpp b/clang/unittests/Format/QualifierFixerTest.cpp
index cb6230fae3004..603a4c0c9a135 100644
--- a/clang/unittests/Format/QualifierFixerTest.cpp
+++ b/clang/unittests/Format/QualifierFixerTest.cpp
@@ -52,12 +52,15 @@ TEST_F(QualifierFixerTest, RotateTokens) {
tok::kw_friend);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("typedef"),
tok::kw_typedef);
- EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("consteval"),
- tok::kw_consteval);
- EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("constinit"),
- tok::kw_constinit);
- EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("thread_local"),
- tok::kw_thread_local);
+ EXPECT_EQ(
+ LeftRightQualifierAlignmentFixer::getTokenFromQualifier("consteval"),
+ tok::kw_consteval);
+ EXPECT_EQ(
+ LeftRightQualifierAlignmentFixer::getTokenFromQualifier("constinit"),
+ tok::kw_constinit);
+ EXPECT_EQ(
+ LeftRightQualifierAlignmentFixer::getTokenFromQualifier("thread_local"),
+ tok::kw_thread_local);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("extern"),
tok::kw_extern);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("mutable"),
@@ -1095,15 +1098,17 @@ TEST_F(QualifierFixerTest, IsQualifierType) {
const auto LangOpts = getFormattingLangOpts();
auto Tokens = lexer.lex(
- "const static inline restrict int double long constexpr friend "
- "typedef consteval constinit thread_local extern mutable signed unsigned short explicit");
- ASSERT_EQ(Tokens.size(), 19u) << Tokens;
+ "const static inline restrict int double constexpr friend "
+ "typedef consteval constinit thread_local extern mutable signed unsigned "
+ "long short explicit");
+ ASSERT_EQ(Tokens.size(), 20u) << Tokens;
// Test that all tokens are recognized
- for (size_t i = 0; i < 19; ++i) {
- EXPECT_TRUE(isConfiguredQualifierOrType(Tokens[i], ConfiguredTokens, LangOpts))
+ for (size_t i = 0; i < 20; ++i) {
+ EXPECT_TRUE(
+ isConfiguredQualifierOrType(Tokens[i], ConfiguredTokens, LangOpts))
<< "Token " << i << " should be recognized";
- EXPECT_TRUE(isQualifierOrType(Tokens[i], LangOpts))
+ EXPECT_TRUE(isQualifierOrType(Tokens[i], LangOpts))
<< "Token " << i << " should be recognized by isQualifierOrType";
}
@@ -1397,43 +1402,42 @@ TEST_F(QualifierFixerTest, TemplatesLeft) {
TEST_F(QualifierFixerTest, NewQualifierSupport) {
FormatStyle Style = getLLVMStyle();
Style.QualifierAlignment = FormatStyle::QAS_Custom;
-
+
Style.QualifierOrder = {"typedef", "type"};
verifyFormat("typedef int MyInt;", Style);
-
+
Style.QualifierOrder = {"consteval", "type"};
verifyFormat("consteval int func();", "int consteval func();", Style);
-
+ verifyFormat("consteval void func();", "void consteval func();", Style);
+
Style.QualifierOrder = {"constinit", "static", "type"};
- verifyFormat("constinit static int var = 10;", "static constinit int var = 10;", Style);
-
+ verifyFormat("constinit static int var = 10;",
+ "static constinit int var = 10;", Style);
+
Style.QualifierOrder = {"thread_local", "static", "type"};
- verifyFormat("thread_local static int counter;", "static thread_local int counter;", Style);
-
+ verifyFormat("thread_local static int counter;",
+ "static thread_local int counter;", Style);
+
Style.QualifierOrder = {"extern", "type"};
verifyFormat("extern int global_var;", "int extern global_var;", Style);
-
+ verifyFormat("extern void func();", "void extern func();", Style);
+
Style.QualifierOrder = {"mutable", "type"};
verifyFormat("mutable int cache;", "int mutable cache;", Style);
-
- Style.QualifierOrder = {"signed", "type"};
- verifyFormat("signed int num;", "int signed num;", Style);
- Style.QualifierOrder = {"unsigned", "type"};
- verifyFormat("unsigned int num;", "int unsigned num;", Style);
-
- Style.QualifierOrder = {"long", "type"};
- verifyFormat("long int num;", "int long num;", Style);
- Style.QualifierOrder = {"short", "type"};
- verifyFormat("short int num;", "int short num;", Style);
-
+
Style.QualifierOrder = {"explicit", "type"};
-
+ verifyFormat("explicit Foo(int x);", Style);
+ verifyFormat("explicit operator bool();", Style);
+
Style.QualifierOrder = {"extern", "thread_local", "static", "constexpr",
- "inline", "unsigned", "long", "type",
- "const", "volatile"};
-
- verifyFormat("extern thread_local static constexpr inline unsigned long int const volatile var;",
- "volatile const extern constexpr thread_local static inline unsigned long int var;", Style);
+ "inline", "unsigned", "long", "type",
+ "const", "volatile"};
+
+ verifyFormat("extern thread_local static constexpr inline unsigned long int "
+ "const volatile var;",
+ "volatile const extern constexpr thread_local static inline "
+ "unsigned long int var;",
+ Style);
}
TEST_F(QualifierFixerTest, Ranges) {
>From 2660b181f20655627a3d489e8ba758fe745f1055 Mon Sep 17 00:00:00 2001
From: Katze719 <pauldorn1234 at gmail.com>
Date: Wed, 14 Jan 2026 21:28:01 +0100
Subject: [PATCH 4/6] Enhance QualifierAlignmentFixer to handle signed
qualifiers alongside unsigned.
---
clang/lib/Format/QualifierAlignmentFixer.cpp | 8 +++-
clang/unittests/Format/QualifierFixerTest.cpp | 39 ++++++++++++++-----
2 files changed, 35 insertions(+), 12 deletions(-)
diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp
index 6614367106dff..af9a7ee5a96b4 100644
--- a/clang/lib/Format/QualifierAlignmentFixer.cpp
+++ b/clang/lib/Format/QualifierAlignmentFixer.cpp
@@ -546,7 +546,6 @@ tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier(
.Case("thread_local", tok::kw_thread_local)
.Case("extern", tok::kw_extern)
.Case("mutable", tok::kw_mutable)
- .Case("signed", tok::kw_signed)
.Case("unsigned", tok::kw_unsigned)
.Case("long", tok::kw_long)
.Case("short", tok::kw_short)
@@ -630,8 +629,13 @@ void prepareLeftRightOrderingForQualifierAlignmentFixer(
tok::TokenKind QualifierToken =
LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s);
- if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier)
+ if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) {
Qualifiers.push_back(QualifierToken);
+ // Handle signed and unsigned together: if unsigned is configured,
+ // also treat signed as configured at the same position.
+ if (QualifierToken == tok::kw_unsigned)
+ Qualifiers.push_back(tok::kw_signed);
+ }
if (left) {
// Reverse the order for left aligned items.
diff --git a/clang/unittests/Format/QualifierFixerTest.cpp b/clang/unittests/Format/QualifierFixerTest.cpp
index 603a4c0c9a135..ebe12c9465d21 100644
--- a/clang/unittests/Format/QualifierFixerTest.cpp
+++ b/clang/unittests/Format/QualifierFixerTest.cpp
@@ -65,8 +65,6 @@ TEST_F(QualifierFixerTest, RotateTokens) {
tok::kw_extern);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("mutable"),
tok::kw_mutable);
- EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("signed"),
- tok::kw_signed);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("unsigned"),
tok::kw_unsigned);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("long"),
@@ -1088,7 +1086,6 @@ TEST_F(QualifierFixerTest, IsQualifierType) {
ConfiguredTokens.push_back(tok::kw_thread_local);
ConfiguredTokens.push_back(tok::kw_extern);
ConfiguredTokens.push_back(tok::kw_mutable);
- ConfiguredTokens.push_back(tok::kw_signed);
ConfiguredTokens.push_back(tok::kw_unsigned);
ConfiguredTokens.push_back(tok::kw_long);
ConfiguredTokens.push_back(tok::kw_short);
@@ -1101,15 +1098,21 @@ TEST_F(QualifierFixerTest, IsQualifierType) {
"const static inline restrict int double constexpr friend "
"typedef consteval constinit thread_local extern mutable signed unsigned "
"long short explicit");
- ASSERT_EQ(Tokens.size(), 20u) << Tokens;
+ ASSERT_EQ(Tokens.size(), 19u) << Tokens;
+
+ for (size_t i = 0; i < 19; ++i) {
+ EXPECT_TRUE(isQualifierOrType(Tokens[i], LangOpts))
+ << "Token " << i << " should be recognized by isQualifierOrType";
+ }
+
+ // When unsigned is configured, signed is automatically added to
+ // ConfiguredTokens to handle them at the same position
+ ConfiguredTokens.push_back(tok::kw_signed);
- // Test that all tokens are recognized
- for (size_t i = 0; i < 20; ++i) {
+ for (size_t i = 0; i < 19; ++i) {
EXPECT_TRUE(
isConfiguredQualifierOrType(Tokens[i], ConfiguredTokens, LangOpts))
<< "Token " << i << " should be recognized";
- EXPECT_TRUE(isQualifierOrType(Tokens[i], LangOpts))
- << "Token " << i << " should be recognized by isQualifierOrType";
}
auto NotTokens = lexer.lex("for while do Foo Bar ");
@@ -1420,14 +1423,30 @@ TEST_F(QualifierFixerTest, NewQualifierSupport) {
Style.QualifierOrder = {"extern", "type"};
verifyFormat("extern int global_var;", "int extern global_var;", Style);
- verifyFormat("extern void func();", "void extern func();", Style);
Style.QualifierOrder = {"mutable", "type"};
verifyFormat("mutable int cache;", "int mutable cache;", Style);
+ Style.QualifierOrder = {"unsigned", "type"};
+ verifyFormat("unsigned int num;", "int unsigned num;", Style);
+ verifyFormat("unsigned long long value;", "long long unsigned value;", Style);
+ // Verify that signed is handled at the same position as unsigned
+ verifyFormat("signed int num;", "int signed num;", Style);
+ verifyFormat("signed long long value;", "long long signed value;", Style);
+
+ Style.QualifierOrder = {"long", "type"};
+ verifyFormat("long int num;", "int long num;", Style);
+ verifyFormat("long unsigned int num;", "unsigned long int num;", Style);
+ verifyFormat("long long int num;", "int long long num;", Style);
+ verifyFormat("long long unsigned int num;", "unsigned long long int num;",
+ Style);
+
+ Style.QualifierOrder = {"short", "type"};
+ verifyFormat("short int num;", "int short num;", Style);
+ verifyFormat("short unsigned value;", "unsigned short value;", Style);
+
Style.QualifierOrder = {"explicit", "type"};
verifyFormat("explicit Foo(int x);", Style);
- verifyFormat("explicit operator bool();", Style);
Style.QualifierOrder = {"extern", "thread_local", "static", "constexpr",
"inline", "unsigned", "long", "type",
>From 6f06a1cb10b4e532fba6114641dfa22c63c7f542 Mon Sep 17 00:00:00 2001
From: Katze719 <pauldorn1234 at gmail.com>
Date: Wed, 14 Jan 2026 22:57:14 +0100
Subject: [PATCH 5/6] Enhance QualifierAlignmentFixer to support paired
qualifiers for signed/unsigned and long/short.
---
clang/lib/Format/QualifierAlignmentFixer.cpp | 27 ++++++++--
clang/unittests/Format/QualifierFixerTest.cpp | 52 ++++++++++++++++++-
2 files changed, 74 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp
index 4de7f722d2fb0..fd9f33dbfe872 100644
--- a/clang/lib/Format/QualifierAlignmentFixer.cpp
+++ b/clang/lib/Format/QualifierAlignmentFixer.cpp
@@ -555,6 +555,7 @@ tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier(
.Case("thread_local", tok::kw_thread_local)
.Case("extern", tok::kw_extern)
.Case("mutable", tok::kw_mutable)
+ .Case("signed", tok::kw_signed)
.Case("unsigned", tok::kw_unsigned)
.Case("long", tok::kw_long)
.Case("short", tok::kw_short)
@@ -640,10 +641,30 @@ void prepareLeftRightOrderingForQualifierAlignmentFixer(
LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s);
if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) {
Qualifiers.push_back(QualifierToken);
- // Handle signed and unsigned together: if unsigned is configured,
- // also treat signed as configured at the same position.
+
+ // Ensure signed/unsigned and long/short qualifier pairs are positioned
+ // together by default unless the user has explicitly specified both in
+ // the QualifierOrder. This allows users to override the default pairing
+ // by listing both qualifiers in the order.
+ auto addPairedQualifier = [&](tok::TokenKind PairedToken,
+ const std::string &PairedName) {
+ if (!llvm::is_contained(Order, PairedName)) {
+ Qualifiers.push_back(PairedToken);
+ if (left)
+ LeftOrder.insert(LeftOrder.begin(), PairedName);
+ else
+ RightOrder.push_back(PairedName);
+ }
+ };
+
if (QualifierToken == tok::kw_unsigned)
- Qualifiers.push_back(tok::kw_signed);
+ addPairedQualifier(tok::kw_signed, "signed");
+ else if (QualifierToken == tok::kw_signed)
+ addPairedQualifier(tok::kw_unsigned, "unsigned");
+ else if (QualifierToken == tok::kw_long)
+ addPairedQualifier(tok::kw_short, "short");
+ else if (QualifierToken == tok::kw_short)
+ addPairedQualifier(tok::kw_long, "long");
}
if (left) {
diff --git a/clang/unittests/Format/QualifierFixerTest.cpp b/clang/unittests/Format/QualifierFixerTest.cpp
index 50f7c3647aba3..7079fef42285f 100644
--- a/clang/unittests/Format/QualifierFixerTest.cpp
+++ b/clang/unittests/Format/QualifierFixerTest.cpp
@@ -65,6 +65,8 @@ TEST_F(QualifierFixerTest, RotateTokens) {
tok::kw_extern);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("mutable"),
tok::kw_mutable);
+ EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("signed"),
+ tok::kw_signed);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("unsigned"),
tok::kw_unsigned);
EXPECT_EQ(LeftRightQualifierAlignmentFixer::getTokenFromQualifier("long"),
@@ -1090,7 +1092,6 @@ TEST_F(QualifierFixerTest, IsQualifierType) {
ConfiguredTokens.push_back(tok::kw_mutable);
ConfiguredTokens.push_back(tok::kw_unsigned);
ConfiguredTokens.push_back(tok::kw_long);
- ConfiguredTokens.push_back(tok::kw_short);
ConfiguredTokens.push_back(tok::kw_explicit);
TestLexer lexer{Allocator, Buffers};
@@ -1110,6 +1111,9 @@ TEST_F(QualifierFixerTest, IsQualifierType) {
// When unsigned is configured, signed is automatically added to
// ConfiguredTokens to handle them at the same position
ConfiguredTokens.push_back(tok::kw_signed);
+ // When long is configured, short is automatically added to
+ // ConfiguredTokens to handle them at the same position
+ ConfiguredTokens.push_back(tok::kw_short);
for (size_t i = 0; i < 19; ++i) {
EXPECT_TRUE(
@@ -1467,7 +1471,6 @@ TEST_F(QualifierFixerTest, NewQualifierSupport) {
Style.QualifierOrder = {"unsigned", "type"};
verifyFormat("unsigned int num;", "int unsigned num;", Style);
verifyFormat("unsigned long long value;", "long long unsigned value;", Style);
- // Verify that signed is handled at the same position as unsigned
verifyFormat("signed int num;", "int signed num;", Style);
verifyFormat("signed long long value;", "long long signed value;", Style);
@@ -1496,6 +1499,51 @@ TEST_F(QualifierFixerTest, NewQualifierSupport) {
Style);
}
+TEST_F(QualifierFixerTest, PairedQualifiersSamePosition) {
+ FormatStyle Style = getLLVMStyle();
+ Style.QualifierAlignment = FormatStyle::QAS_Custom;
+
+ Style.QualifierOrder = {"unsigned", "type"};
+ verifyFormat("unsigned int x;", "int unsigned x;", Style);
+ verifyFormat("signed int x;", "int signed x;", Style);
+ verifyFormat("unsigned long int y;", "long unsigned int y;", Style);
+ verifyFormat("signed long int y;", "long signed int y;", Style);
+
+ Style.QualifierOrder = {"signed", "type"};
+ verifyFormat("signed int x;", "int signed x;", Style);
+ verifyFormat("unsigned int x;", "int unsigned x;", Style);
+
+ Style.QualifierOrder = {"long", "type"};
+ verifyFormat("long int x;", "int long x;", Style);
+ verifyFormat("short int x;", "int short x;", Style);
+ verifyFormat("long unsigned int y;", "unsigned long int y;", Style);
+ verifyFormat("short unsigned int y;", "unsigned short int y;", Style);
+
+ Style.QualifierOrder = {"short", "type"};
+ verifyFormat("short int x;", "int short x;", Style);
+ verifyFormat("long int x;", "int long x;", Style);
+
+ Style.QualifierOrder = {"type", "unsigned"};
+ verifyFormat("int unsigned x;", "unsigned int x;", Style);
+ verifyFormat("int signed x;", "signed int x;", Style);
+
+ Style.QualifierOrder = {"type", "long"};
+ verifyFormat("int long x;", "long int x;", Style);
+ verifyFormat("int short x;", "short int x;", Style);
+
+ Style.QualifierOrder = {"static", "unsigned", "long", "type"};
+ verifyFormat("static unsigned long int x;", "long unsigned static int x;",
+ Style);
+ verifyFormat("static signed short int x;", "short signed static int x;",
+ Style);
+
+ Style.QualifierOrder = {"unsigned", "signed", "type"};
+ verifyFormat("unsigned signed int x;", "signed unsigned int x;", Style);
+
+ Style.QualifierOrder = {"long", "short", "type"};
+ verifyFormat("long short int x;", "short long int x;", Style);
+}
+
TEST_F(QualifierFixerTest, Ranges) {
FormatStyle Style = getLLVMStyle();
Style.QualifierAlignment = FormatStyle::QAS_Custom;
>From b56616c5dc01b4f24e8b43077a3043ba88ba13ef Mon Sep 17 00:00:00 2001
From: Katze719 <pauldorn1234 at gmail.com>
Date: Thu, 15 Jan 2026 22:19:44 +0100
Subject: [PATCH 6/6] Refine QualifierAlignmentFixer to better handle qualifier
inclusion at line start and improve type specifier analysis. To fix Tests
---
clang/lib/Format/QualifierAlignmentFixer.cpp | 31 +++++++++++++++-----
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp
index fd9f33dbfe872..87b977c08adc6 100644
--- a/clang/lib/Format/QualifierAlignmentFixer.cpp
+++ b/clang/lib/Format/QualifierAlignmentFixer.cpp
@@ -408,11 +408,29 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration ||
TypeToken->is(tok::r_square)) {
- // Don't sort past a non-configured qualifier token.
const FormatToken *FirstQual = Tok;
- while (isConfiguredQualifier(FirstQual->getPreviousNonComment(),
- ConfiguredQualifierTokens)) {
- FirstQual = FirstQual->getPreviousNonComment();
+ const FormatToken *Prev = FirstQual->getPreviousNonComment();
+ if (!TypeToken) {
+ // At start of line: include paired qualifiers (long/short with
+ // unsigned/signed) and configured qualifiers, but not unrelated ones.
+ while (Prev &&
+ (isConfiguredQualifier(Prev, ConfiguredQualifierTokens) ||
+ (isQualifier(Prev) &&
+ (((QualifierType == tok::kw_unsigned ||
+ QualifierType == tok::kw_signed) &&
+ (Prev->is(tok::kw_long) || Prev->is(tok::kw_short))) ||
+ ((QualifierType == tok::kw_long ||
+ QualifierType == tok::kw_short) &&
+ (Prev->is(tok::kw_unsigned) || Prev->is(tok::kw_signed))))))) {
+ FirstQual = Prev;
+ Prev = FirstQual->getPreviousNonComment();
+ }
+ } else {
+ // Not at start: only include configured qualifiers
+ while (Prev && isConfiguredQualifier(Prev, ConfiguredQualifierTokens)) {
+ FirstQual = Prev;
+ Prev = FirstQual->getPreviousNonComment();
+ }
}
if (FirstQual != Tok)
@@ -440,9 +458,8 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft(
TypeToken = Prev;
}
const FormatToken *LastSimpleTypeSpecifier = TypeToken;
- while (isConfiguredQualifierOrType(
- LastSimpleTypeSpecifier->getPreviousNonComment(),
- ConfiguredQualifierTokens, LangOpts)) {
+ while (isQualifierOrType(LastSimpleTypeSpecifier->getPreviousNonComment(),
+ LangOpts)) {
LastSimpleTypeSpecifier =
LastSimpleTypeSpecifier->getPreviousNonComment();
}
More information about the cfe-commits
mailing list