[clang] [clang-format] Add FunctionLikeMacros option (PR #148345)

via cfe-commits cfe-commits at lists.llvm.org
Sat Jul 12 00:16:20 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-format

Author: Owen Pan (owenca)

<details>
<summary>Changes</summary>

This allows RemoveParentheses to skip the invocations of function-like macros.

Fixes #<!-- -->68354.
Fixes #<!-- -->147780.

---
Full diff: https://github.com/llvm/llvm-project/pull/148345.diff


11 Files Affected:

- (modified) clang/docs/ClangFormatStyleOptions.rst (+6) 
- (modified) clang/docs/ReleaseNotes.rst (+2) 
- (modified) clang/include/clang/Format/Format.h (+6) 
- (modified) clang/lib/Format/Format.cpp (+1) 
- (modified) clang/lib/Format/FormatToken.h (+1) 
- (modified) clang/lib/Format/FormatTokenLexer.cpp (+4) 
- (modified) clang/lib/Format/TokenAnnotator.cpp (+2-1) 
- (modified) clang/lib/Format/UnwrappedLineParser.cpp (+9-5) 
- (modified) clang/lib/Format/UnwrappedLineParser.h (+2-1) 
- (modified) clang/unittests/Format/ConfigParseTest.cpp (+1) 
- (modified) clang/unittests/Format/FormatTest.cpp (+4) 


``````````diff
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index ab374c1886165..b2fb14c1b3011 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -4073,6 +4073,12 @@ the configuration (without a prefix: ``Auto``).
 
   For example: BOOST_FOREACH.
 
+.. _FunctionLikeMacros:
+
+**FunctionLikeMacros** (``List of Strings``) :versionbadge:`clang-format 21` :ref:`¶ <FunctionLikeMacros>`
+  A vector of function-like macros whose invocations should be skipped by
+  ``RemoveParentheses``.
+
 .. _IfMacros:
 
 **IfMacros** (``List of Strings``) :versionbadge:`clang-format 13` :ref:`¶ <IfMacros>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e81a3d4976cf8..a26b0e4cc8d2c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1132,6 +1132,8 @@ clang-format
   ``enum`` enumerator lists.
 - Add ``OneLineFormatOffRegex`` option for turning formatting off for one line.
 - Add ``SpaceAfterOperatorKeyword`` option.
+- Add ``FunctionLikeMacros`` 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..7e7eb21e2a3ba 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2786,6 +2786,11 @@ struct FormatStyle {
   /// \version 3.7
   std::vector<std::string> ForEachMacros;
 
+  /// A vector of function-like macros whose invocations should be skipped by
+  /// ``RemoveParentheses``.
+  /// \version 21
+  std::vector<std::string> FunctionLikeMacros;
+
   tooling::IncludeStyle IncludeStyle;
 
   /// A vector of macros that should be interpreted as conditionals
@@ -5382,6 +5387,7 @@ struct FormatStyle {
                R.ExperimentalAutoDetectBinPacking &&
            FixNamespaceComments == R.FixNamespaceComments &&
            ForEachMacros == R.ForEachMacros &&
+           FunctionLikeMacros == R.FunctionLikeMacros &&
            IncludeStyle.IncludeBlocks == R.IncludeStyle.IncludeBlocks &&
            IncludeStyle.IncludeCategories == R.IncludeStyle.IncludeCategories &&
            IncludeStyle.IncludeIsMainRegex ==
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 4956607602be0..30eab05117b76 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1068,6 +1068,7 @@ template <> struct MappingTraits<FormatStyle> {
                    Style.ExperimentalAutoDetectBinPacking);
     IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
     IO.mapOptional("ForEachMacros", Style.ForEachMacros);
+    IO.mapOptional("FunctionLikeMacros", Style.FunctionLikeMacros);
     IO.mapOptional("IfMacros", Style.IfMacros);
     IO.mapOptional("IncludeBlocks", Style.IncludeStyle.IncludeBlocks);
     IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories);
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..3cdcbd15cd739 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -43,6 +43,10 @@ FormatTokenLexer::FormatTokenLexer(
     auto Identifier = &IdentTable.get(ForEachMacro);
     Macros.insert({Identifier, TT_ForEachMacro});
   }
+  for (const std::string &FunctionLikeMacro : Style.FunctionLikeMacros) {
+    auto Identifier = &IdentTable.get(FunctionLikeMacro);
+    Macros.insert({Identifier, TT_FunctionLikeMacro});
+  }
   for (const std::string &IfMacro : Style.IfMacros) {
     auto Identifier = &IdentTable.get(IfMacro);
     Macros.insert({Identifier, TT_IfMacro});
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..c2058fb46cc45 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -940,6 +940,7 @@ TEST(ConfigParseTest, ParsesConfiguration) {
   CHECK_PARSE("StatementMacros: [QUNUSED, QT_REQUIRE_VERSION]", StatementMacros,
               std::vector<std::string>({"QUNUSED", "QT_REQUIRE_VERSION"}));
 
+  CHECK_PARSE_LIST(FunctionLikeMacros);
   CHECK_PARSE_LIST(JavaImportGroups);
   CHECK_PARSE_LIST(Macros);
   CHECK_PARSE_LIST(NamespaceMacros);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 944e7c3fb152a..789d822853e26 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.FunctionLikeMacros.push_back("MOCK_METHOD");
+  verifyFormat("MOCK_METHOD((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);

``````````

</details>


https://github.com/llvm/llvm-project/pull/148345


More information about the cfe-commits mailing list