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); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits