Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -2289,6 +2289,28 @@ For example: BOOST_FOREACH. +**IfMacros** (``std::vector``) + A vector of macros that should be interpreted as conditionals + instead of as function calls. + + These are expected to be macros of the form: + + .. code-block:: c++ + + IF(...) + + else IF(...) + + + In the .clang-format configuration file, this can be configured like: + + .. code-block:: yaml + + IfMacros: ['IF'] + + For example: `KJ_IF_MAYBE + `. + **IncludeBlocks** (``IncludeBlocksStyle``) Dependent on the value, multiple ``#include`` blocks can be sorted as one and divided based on category. Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -248,6 +248,10 @@ accepts ``AllIfsAndElse`` value that allows to put "else if" and "else" short statements on a single line. (Fixes https://llvm.org/PR50019.) +- Option ``IfMacros`` has been added. This lets you define macros that get + formatted like conditionals much like ``ForEachMacros`` get stiled like + foreach loops. + - ``git-clang-format`` no longer formats changes to symbolic links. (Fixes https://llvm.org/PR46992.) Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -2079,6 +2079,26 @@ /// For example: BOOST_FOREACH. std::vector ForEachMacros; + /// A vector of macros that should be interpreted as conditionals + /// instead of as function calls. + /// + /// These are expected to be macros of the form: + /// \code + /// IF(...) { + /// + /// } else { + /// } + /// \endcode + /// + /// In the .clang-format configuration file, this can be configured like: + /// \code{.yaml} + /// IfMacros: ['IF'] + /// \endcode + /// + /// For example: KJ_IF_MAYBE + /// (https://github.com/capnproto/capnproto/blob/master/kjdoc/tour.md#maybes). + std::vector IfMacros; + /// \brief A vector of macros that should be interpreted as type declarations /// instead of as function calls. /// Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -616,6 +616,7 @@ Style.ExperimentalAutoDetectBinPacking); IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments); IO.mapOptional("ForEachMacros", Style.ForEachMacros); + IO.mapOptional("IfMacros", Style.IfMacros); IO.mapOptional("StatementAttributeLikeMacros", Style.StatementAttributeLikeMacros); IO.mapOptional("IncludeBlocks", Style.IncludeStyle.IncludeBlocks); @@ -1007,6 +1008,7 @@ LLVMStyle.ForEachMacros.push_back("foreach"); LLVMStyle.ForEachMacros.push_back("Q_FOREACH"); LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH"); + LLVMStyle.IfMacros.push_back("KJ_IF_MAYBE"); LLVMStyle.IncludeStyle.IncludeCategories = { {"^\"(llvm|llvm-c|clang|clang-c)/", 2, 0, false}, {"^(<|\"(gtest|gmock|isl|json)/)", 3, 0, false}, Index: clang/lib/Format/FormatToken.h =================================================================== --- clang/lib/Format/FormatToken.h +++ clang/lib/Format/FormatToken.h @@ -52,6 +52,7 @@ TYPE(FunctionDeclarationName) \ TYPE(FunctionLBrace) \ TYPE(FunctionTypeLParen) \ + TYPE(IfMacro) \ TYPE(ImplicitStringLiteral) \ TYPE(InheritanceColon) \ TYPE(InheritanceComma) \ Index: clang/lib/Format/FormatTokenLexer.cpp =================================================================== --- clang/lib/Format/FormatTokenLexer.cpp +++ clang/lib/Format/FormatTokenLexer.cpp @@ -39,6 +39,8 @@ for (const std::string &ForEachMacro : Style.ForEachMacros) Macros.insert({&IdentTable.get(ForEachMacro), TT_ForEachMacro}); + for (const std::string &IfMacro : Style.IfMacros) + Macros.insert({&IdentTable.get(IfMacro), TT_IfMacro}); for (const std::string &AttributeMacro : Style.AttributeMacros) Macros.insert({&IdentTable.get(AttributeMacro), TT_AttributeMacro}); for (const std::string &StatementMacro : Style.StatementMacros) @@ -1014,6 +1016,9 @@ tok::pp_define) && it != Macros.end()) { FormatTok->setType(it->second); + if (it->second == TT_IfMacro) { + FormatTok->Tok.setKind(tok::kw_if); + } } else if (FormatTok->is(tok::identifier)) { if (MacroBlockBeginRegex.match(Text)) { FormatTok->setType(TT_MacroBlockBegin); Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -1363,7 +1363,7 @@ // Reset token type in case we have already looked at it and then // recovered from an error (e.g. failure to find the matching >). if (!CurrentToken->isOneOf( - TT_LambdaLSquare, TT_LambdaLBrace, TT_AttributeMacro, + TT_LambdaLSquare, TT_LambdaLBrace, TT_AttributeMacro, TT_IfMacro, TT_ForEachMacro, TT_TypenameMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_FatArrow, TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator, @@ -3022,6 +3022,9 @@ FormatStyle::SBPO_ControlStatementsExceptForEachMacros && Left.is(TT_ForEachMacro)) return false; + if (Left.is(TT_IfMacro)) { + return false; + } return Line.Type == LT_ObjCDecl || Left.is(tok::semi) || (Style.SpaceBeforeParens != FormatStyle::SBPO_Never && (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -17111,6 +17111,11 @@ CHECK_PARSE("ForEachMacros: [BOOST_FOREACH, Q_FOREACH]", ForEachMacros, BoostAndQForeach); + Style.IfMacros.clear(); + std::vector CustomIfs; + CustomIfs.push_back("MYIF"); + CHECK_PARSE("IfMacros: [MYIF]", IfMacros, CustomIfs); + Style.AttributeMacros.clear(); CHECK_PARSE("BasedOnStyle: LLVM", AttributeMacros, std::vector{"__capability"}); @@ -19684,11 +19689,16 @@ TEST_F(FormatTest, SpacesInConditionalStatement) { FormatStyle Spaces = getLLVMStyle(); + Spaces.IfMacros.clear(); + Spaces.IfMacros.push_back("MYIF"); Spaces.SpacesInConditionalStatement = true; verifyFormat("for ( int i = 0; i; i++ )\n continue;", Spaces); verifyFormat("if ( !a )\n return;", Spaces); verifyFormat("if ( a )\n return;", Spaces); verifyFormat("if constexpr ( a )\n return;", Spaces); + verifyFormat("MYIF( a )\n return;", Spaces); + verifyFormat("MYIF( a )\n return;\nelse MYIF( b )\n return;", Spaces); + verifyFormat("MYIF( a )\n return;\nelse\n return;", Spaces); verifyFormat("switch ( a )\ncase 1:\n return;", Spaces); verifyFormat("while ( a )\n return;", Spaces); verifyFormat("while ( (a && b) )\n return;", Spaces);