[clang] c384ec4 - [clang-format] Add MacrosSkippedByRemoveParentheses option (#148345)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 13 14:29:54 PDT 2025
Author: Owen Pan
Date: 2025-07-13T14:29:51-07:00
New Revision: c384ec431dd7f771c9dd7c462cec5301ac0f32bb
URL: https://github.com/llvm/llvm-project/commit/c384ec431dd7f771c9dd7c462cec5301ac0f32bb
DIFF: https://github.com/llvm/llvm-project/commit/c384ec431dd7f771c9dd7c462cec5301ac0f32bb.diff
LOG: [clang-format] Add MacrosSkippedByRemoveParentheses option (#148345)
This allows RemoveParentheses to skip the invocations of function-like
macros.
Fixes #68354.
Fixes #147780.
Added:
Modified:
clang/docs/ClangFormatStyleOptions.rst
clang/docs/ReleaseNotes.rst
clang/include/clang/Format/Format.h
clang/lib/Format/Format.cpp
clang/lib/Format/FormatToken.h
clang/lib/Format/FormatTokenLexer.cpp
clang/lib/Format/FormatTokenLexer.h
clang/lib/Format/TokenAnnotator.cpp
clang/lib/Format/UnwrappedLineParser.cpp
clang/lib/Format/UnwrappedLineParser.h
clang/unittests/Format/ConfigParseTest.cpp
clang/unittests/Format/FormatTest.cpp
Removed:
################################################################################
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index ab374c1886165..0e21ef0244f78 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -4975,6 +4975,12 @@ the configuration (without a prefix: ``Auto``).
A(z); -> z;
A(a, b); // will not be expanded.
+.. _MacrosSkippedByRemoveParentheses:
+
+**MacrosSkippedByRemoveParentheses** (``List of Strings``) :versionbadge:`clang-format 21` :ref:`¶ <MacrosSkippedByRemoveParentheses>`
+ A vector of function-like macros whose invocations should be skipped by
+ ``RemoveParentheses``.
+
.. _MainIncludeChar:
**MainIncludeChar** (``MainIncludeCharDiscriminator``) :versionbadge:`clang-format 19` :ref:`¶ <MainIncludeChar>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8ba493b2ca89b..e3fd730002b55 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1136,6 +1136,8 @@ clang-format
``enum`` enumerator lists.
- Add ``OneLineFormatOffRegex`` option for turning formatting off for one line.
- Add ``SpaceAfterOperatorKeyword`` option.
+- Add ``MacrosSkippedByRemoveParentheses`` option so that their invocations are
+ skipped by ``RemoveParentheses``.
clang-refactor
--------------
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 74b516fe4f071..b4f2a87fe7e83 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3488,6 +3488,11 @@ struct FormatStyle {
/// \version 17
std::vector<std::string> Macros;
+ /// A vector of function-like macros whose invocations should be skipped by
+ /// ``RemoveParentheses``.
+ /// \version 21
+ std::vector<std::string> MacrosSkippedByRemoveParentheses;
+
/// The maximum number of consecutive empty lines to keep.
/// \code
/// MaxEmptyLinesToKeep: 1 vs. MaxEmptyLinesToKeep: 0
@@ -5410,6 +5415,8 @@ struct FormatStyle {
LambdaBodyIndentation == R.LambdaBodyIndentation &&
LineEnding == R.LineEnding && MacroBlockBegin == R.MacroBlockBegin &&
MacroBlockEnd == R.MacroBlockEnd && Macros == R.Macros &&
+ MacrosSkippedByRemoveParentheses ==
+ R.MacrosSkippedByRemoveParentheses &&
MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
NamespaceIndentation == R.NamespaceIndentation &&
NamespaceMacros == R.NamespaceMacros &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 4956607602be0..78c09be458f0a 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1099,6 +1099,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
IO.mapOptional("Macros", Style.Macros);
+ IO.mapOptional("MacrosSkippedByRemoveParentheses",
+ Style.MacrosSkippedByRemoveParentheses);
IO.mapOptional("MainIncludeChar", Style.IncludeStyle.MainIncludeChar);
IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 94014aee3221f..9252a795a0b5e 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -83,6 +83,7 @@ namespace format {
TYPE(FunctionDeclarationName) \
TYPE(FunctionDeclarationLParen) \
TYPE(FunctionLBrace) \
+ TYPE(FunctionLikeMacro) \
TYPE(FunctionLikeOrFreestandingMacro) \
TYPE(FunctionTypeLParen) \
/* The colons as part of a C11 _Generic selection */ \
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index d8ee5cb90aaa4..49da3160daf50 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -74,6 +74,8 @@ FormatTokenLexer::FormatTokenLexer(
Macros.insert({Identifier, TT_StatementAttributeLikeMacro});
}
+ for (const auto &Macro : Style.MacrosSkippedByRemoveParentheses)
+ MacrosSkippedByRemoveParentheses.insert(&IdentTable.get(Macro));
for (const auto &TemplateName : Style.TemplateNames)
TemplateNames.insert(&IdentTable.get(TemplateName));
for (const auto &TypeName : Style.TypeNames)
@@ -1473,6 +1475,8 @@ FormatToken *FormatTokenLexer::getNextToken() {
FormatTok->setType(TT_MacroBlockBegin);
else if (MacroBlockEndRegex.match(Text))
FormatTok->setType(TT_MacroBlockEnd);
+ else if (MacrosSkippedByRemoveParentheses.contains(Identifier))
+ FormatTok->setFinalizedType(TT_FunctionLikeMacro);
else if (TemplateNames.contains(Identifier))
FormatTok->setFinalizedType(TT_TemplateName);
else if (TypeNames.contains(Identifier))
diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h
index 026383db1fe6c..57c572af3defd 100644
--- a/clang/lib/Format/FormatTokenLexer.h
+++ b/clang/lib/Format/FormatTokenLexer.h
@@ -132,8 +132,8 @@ class FormatTokenLexer {
llvm::SmallMapVector<IdentifierInfo *, TokenType, 8> Macros;
- llvm::SmallPtrSet<IdentifierInfo *, 8> TemplateNames, TypeNames,
- VariableTemplates;
+ llvm::SmallPtrSet<IdentifierInfo *, 8> MacrosSkippedByRemoveParentheses,
+ TemplateNames, TypeNames, VariableTemplates;
bool FormattingDisabled;
llvm::Regex FormatOffRegex; // For one line.
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index aab8f054655fe..739209a5681f8 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -2090,7 +2090,8 @@ class AnnotatingParser {
TT_RecordLBrace, TT_StructLBrace, TT_UnionLBrace, TT_RequiresClause,
TT_RequiresClauseInARequiresExpression, TT_RequiresExpression,
TT_RequiresExpressionLParen, TT_RequiresExpressionLBrace,
- TT_CompoundRequirementLBrace, TT_BracedListLBrace)) {
+ TT_CompoundRequirementLBrace, TT_BracedListLBrace,
+ TT_FunctionLikeMacro)) {
CurrentToken->setType(TT_Unknown);
}
CurrentToken->Role.reset();
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 7e8634aeec4e0..91b8fdc8a3c38 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -2579,30 +2579,34 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) {
/// double ampersands. This applies for all nested scopes as well.
///
/// Returns whether there is a `=` token between the parentheses.
-bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) {
+bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType,
+ bool InMacroCall) {
assert(FormatTok->is(tok::l_paren) && "'(' expected.");
auto *LParen = FormatTok;
+ auto *Prev = FormatTok->Previous;
bool SeenComma = false;
bool SeenEqual = false;
bool MightBeFoldExpr = false;
nextToken();
const bool MightBeStmtExpr = FormatTok->is(tok::l_brace);
+ if (!InMacroCall && Prev && Prev->is(TT_FunctionLikeMacro))
+ InMacroCall = true;
do {
switch (FormatTok->Tok.getKind()) {
case tok::l_paren:
- if (parseParens(AmpAmpTokenType))
+ if (parseParens(AmpAmpTokenType, InMacroCall))
SeenEqual = true;
if (Style.isJava() && FormatTok->is(tok::l_brace))
parseChildBlock();
break;
case tok::r_paren: {
- auto *Prev = LParen->Previous;
auto *RParen = FormatTok;
nextToken();
if (Prev) {
auto OptionalParens = [&] {
- if (MightBeStmtExpr || MightBeFoldExpr || Line->InMacroBody ||
- SeenComma || Style.RemoveParentheses == FormatStyle::RPS_Leave ||
+ if (MightBeStmtExpr || MightBeFoldExpr || SeenComma || InMacroCall ||
+ Line->InMacroBody ||
+ Style.RemoveParentheses == FormatStyle::RPS_Leave ||
RParen->getPreviousNonComment() == LParen) {
return false;
}
diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h
index 2d1492c1a6b8c..8e29680ff244b 100644
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -145,7 +145,8 @@ class UnwrappedLineParser {
bool *HasLabel = nullptr);
bool tryToParseBracedList();
bool parseBracedList(bool IsAngleBracket = false, bool IsEnum = false);
- bool parseParens(TokenType AmpAmpTokenType = TT_Unknown);
+ bool parseParens(TokenType AmpAmpTokenType = TT_Unknown,
+ bool InMacroCall = false);
void parseSquare(bool LambdaIntroducer = false);
void keepAncestorBraces();
void parseUnbracedBody(bool CheckEOF = false);
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index aedfdd151d6d3..d17109aebc0f8 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -942,6 +942,7 @@ TEST(ConfigParseTest, ParsesConfiguration) {
CHECK_PARSE_LIST(JavaImportGroups);
CHECK_PARSE_LIST(Macros);
+ CHECK_PARSE_LIST(MacrosSkippedByRemoveParentheses);
CHECK_PARSE_LIST(NamespaceMacros);
CHECK_PARSE_LIST(ObjCPropertyAttributeOrder);
CHECK_PARSE_LIST(TableGenBreakingDAGArgOperators);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 944e7c3fb152a..0bc1c6d45656e 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -28479,6 +28479,10 @@ TEST_F(FormatTest, RemoveParentheses) {
verifyFormat("MOCK_METHOD(void, Function, (), override);",
"MOCK_METHOD(void, Function, (), (override));", Style);
+ Style.MacrosSkippedByRemoveParentheses.push_back("FOO");
+ verifyFormat("FOO((a && b));", Style);
+ verifyFormat("FOO((int), func, ((std::map<int, int>)), (override));", Style);
+
Style.RemoveParentheses = FormatStyle::RPS_ReturnStatement;
verifyFormat("#define Return0 return (0);", Style);
verifyFormat("return 0;", "return (0);", Style);
More information about the cfe-commits
mailing list