[clang] [clang-format] Add support for additional C++ declaration specifiers in QualifierOrder (PR #160853)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 26 03:42:18 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-format
Author: Katze719 (Katze719)
<details>
<summary>Changes</summary>
Fixes #<!-- -->60866
This PR extends clang-formats `QualifierOrder` option to support additional C++ declaration specifiers, addressing the limitation where many common qualifiers were not recognized.
## Problem
Previously, `QualifierOrder` only supported a limited subset of C++ declaration specifiers:
- `const`, `volatile`, `static`, `inline`, `constexpr`, `restrict`, `friend`
This meant that many common C++ qualifiers like `extern`, `mutable`, `typedef`, `unsigned`, etc. were not recognized and could not be properly reordered, limiting the usefulness of the feature.
## Solution
This PR adds support for 11 additional declaration specifiers:
**C++98/C99 specifiers:**
- `typedef` - Type definition specifier
- `extern` - External linkage specifier
- `mutable` - Mutable member specifier
- `signed`, `unsigned` - Integer signedness specifiers
- `long`, `short` - Integer size specifiers
**C++11 specifiers:**
- `thread_local` - Thread-local storage duration specifier
- `decltype` - Decltype type specifier
- `explicit` - Explicit constructor/conversion specifier
**C++20 specifiers:**
- `consteval` - Immediate function specifier
- `constinit` - Constant initialization specifier
---
Full diff: https://github.com/llvm/llvm-project/pull/160853.diff
2 Files Affected:
- (modified) clang/lib/Format/QualifierAlignmentFixer.cpp (+24)
- (modified) clang/unittests/Format/QualifierFixerTest.cpp (+107-35)
``````````diff
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;
``````````
</details>
https://github.com/llvm/llvm-project/pull/160853
More information about the cfe-commits
mailing list