From be9a87fe9bc395074c383c07fbd9c0bce953985f Mon Sep 17 00:00:00 2001 From: Vitali Lovich Date: Tue, 18 May 2021 13:57:07 -0700 Subject: [PATCH] [clang-format] Add IfMacros option https://bugs.llvm.org/show_bug.cgi?id=49354 Differential Revision: https://reviews.llvm.org/D102730 --- clang/docs/ClangFormatStyleOptions.rst | 30 +- clang/docs/ReleaseNotes.rst | 4 + clang/include/clang/Format/Format.h | 28 +- clang/lib/Format/Format.cpp | 11 +- clang/lib/Format/FormatToken.h | 1 + clang/lib/Format/FormatTokenLexer.cpp | 9 + clang/lib/Format/TokenAnnotator.cpp | 8 +- clang/unittests/Format/FormatTest.cpp | 577 ++++++++++++++++++++++++- 8 files changed, 656 insertions(+), 12 deletions(-) mode change 100755 => 100644 clang/lib/Format/TokenAnnotator.cpp diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index f05e11469a7b..77c07284085c 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2377,6 +2377,28 @@ the configuration (without a prefix: ``Auto``). 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. @@ -3480,10 +3502,12 @@ the configuration (without a prefix: ``Auto``). } } - * ``SBPO_ControlStatementsExceptForEachMacros`` (in configuration: ``ControlStatementsExceptForEachMacros``) + * ``SBPO_ControlStatementsExceptControlMacros`` (in configuration: ``ControlStatementsExceptControlMacros``) Same as ``SBPO_ControlStatements`` except this option doesn't apply to - ForEach macros. This is useful in projects where ForEach macros are - treated as function calls instead of control statements. + ForEach and If macros. This is useful in projects where ForEach/If + macros are treated as function calls instead of control statements. + ``SBPO_ControlStatementsExceptForEachMacros`` remains an alias for + backward compatability. .. code-block:: c++ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4b432c1f3bb8..7b23c1ef77af 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -265,6 +265,10 @@ clang-format change that so that the lambda body is indented one level relative to the scope containing the lambda, regardless of where the lambda signature was placed. +- Option ``IfMacros`` has been added. This lets you define macros that get + formatted like conditionals much like ``ForEachMacros`` get styled like + foreach loops. + - ``git-clang-format`` no longer formats changes to symbolic links. (Fixes https://llvm.org/PR46992.) diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index d51666fe9a1b..506feea26e8d 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -2117,6 +2117,26 @@ struct FormatStyle { /// 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 IF(...) + /// + /// \endcode + /// + /// In the .clang-format configuration file, this can be configured like: + /// \code{.yaml} + /// IfMacros: ['IF'] + /// \endcode + /// + /// For example: `KJ_IF_MAYBE + /// `_ + std::vector IfMacros; + /// \brief A vector of macros that should be interpreted as type declarations /// instead of as function calls. /// @@ -3033,8 +3053,10 @@ struct FormatStyle { /// \endcode SBPO_ControlStatements, /// Same as ``SBPO_ControlStatements`` except this option doesn't apply to - /// ForEach macros. This is useful in projects where ForEach macros are - /// treated as function calls instead of control statements. + /// ForEach and If macros. This is useful in projects where ForEach/If + /// macros are treated as function calls instead of control statements. + /// ``SBPO_ControlStatementsExceptForEachMacros`` remains an alias for + /// backward compatability. /// \code /// void f() { /// Q_FOREACH(...) { @@ -3042,7 +3064,7 @@ struct FormatStyle { /// } /// } /// \endcode - SBPO_ControlStatementsExceptForEachMacros, + SBPO_ControlStatementsExceptControlMacros, /// Put a space before opening parentheses only if the parentheses are not /// empty i.e. '()' /// \code diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b83fcaebf18c..bfd4d8b5af50 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -424,8 +424,8 @@ struct ScalarEnumerationTraits { IO.enumCase(Value, "Never", FormatStyle::SBPO_Never); IO.enumCase(Value, "ControlStatements", FormatStyle::SBPO_ControlStatements); - IO.enumCase(Value, "ControlStatementsExceptForEachMacros", - FormatStyle::SBPO_ControlStatementsExceptForEachMacros); + IO.enumCase(Value, "ControlStatementsExceptControlMacros", + FormatStyle::SBPO_ControlStatementsExceptControlMacros); IO.enumCase(Value, "NonEmptyParentheses", FormatStyle::SBPO_NonEmptyParentheses); IO.enumCase(Value, "Always", FormatStyle::SBPO_Always); @@ -433,6 +433,8 @@ struct ScalarEnumerationTraits { // For backward compatibility. IO.enumCase(Value, "false", FormatStyle::SBPO_Never); IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements); + IO.enumCase(Value, "ControlStatementsExceptForEachMacros", + FormatStyle::SBPO_ControlStatementsExceptControlMacros); } }; @@ -637,6 +639,8 @@ template <> struct MappingTraits { Style.ExperimentalAutoDetectBinPacking); IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments); IO.mapOptional("ForEachMacros", Style.ForEachMacros); + IO.mapOptional("IfMacros", Style.IfMacros); + IO.mapOptional("IncludeBlocks", Style.IncludeStyle.IncludeBlocks); IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories); IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex); @@ -1031,6 +1035,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { 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}, @@ -3143,4 +3148,4 @@ llvm::Expected getStyle(StringRef StyleName, StringRef FileName, } } // namespace format -} // namespace clang +} // namespace clang \ No newline at end of file diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 57c5eeb5a091..0506cd554bcb 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -52,6 +52,7 @@ namespace format { TYPE(FunctionDeclarationName) \ TYPE(FunctionLBrace) \ TYPE(FunctionTypeLParen) \ + TYPE(IfMacro) \ TYPE(ImplicitStringLiteral) \ TYPE(InheritanceColon) \ TYPE(InheritanceComma) \ diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 0faa18c34828..a9cfb4a247f0 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -39,6 +39,8 @@ FormatTokenLexer::FormatTokenLexer( 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,13 @@ FormatToken *FormatTokenLexer::getNextToken() { tok::pp_define) && it != Macros.end()) { FormatTok->setType(it->second); + if (it->second == TT_IfMacro) { + // The lexer token currently has type tok::kw_unknown. However, for this + // substitution to be treated correctly in the TokenAnnotator, faking + // the tok value seems to be needed. Not sure if there's a more elegant + // way. + FormatTok->Tok.setKind(tok::kw_if); + } } else if (FormatTok->is(tok::identifier)) { if (MacroBlockBeginRegex.match(Text)) { FormatTok->setType(TT_MacroBlockBegin); diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp old mode 100755 new mode 100644 index 48309af24aa8..92fb1b14056a --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1409,7 +1409,7 @@ private: // 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, @@ -3120,9 +3120,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, (Left.is(tok::r_square) && Left.is(TT_AttributeSquare))) return true; if (Style.SpaceBeforeParens == - FormatStyle::SBPO_ControlStatementsExceptForEachMacros && + FormatStyle::SBPO_ControlStatementsExceptControlMacros && Left.is(TT_ForEachMacro)) return false; + if (Style.SpaceBeforeParens == + FormatStyle::SBPO_ControlStatementsExceptControlMacros && + 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, diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 59690c722a9e..cc702e81c2c3 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -525,6 +525,7 @@ TEST_F(FormatTest, FormatIfWithoutCompoundStatement) { "}"); FormatStyle AllowsMergedIf = getLLVMStyle(); + AllowsMergedIf.IfMacros.push_back("MYIF"); AllowsMergedIf.AlignEscapedNewlines = FormatStyle::ENAS_Left; AllowsMergedIf.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_WithoutElse; @@ -564,17 +565,62 @@ TEST_F(FormatTest, FormatIfWithoutCompoundStatement) { " f();\n" "}", AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " // comment\n" + " f();", + AllowsMergedIf); + verifyFormat("{\n" + " MYIF (a)\n" + " label:\n" + " f();\n" + "}", + AllowsMergedIf); + verifyFormat("#define A \\\n" + " MYIF (a) \\\n" + " label: \\\n" + " f()", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " ;", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " MYIF (b) return;", + AllowsMergedIf); + + verifyFormat("MYIF (a) // Can't merge this\n" + " f();\n", + AllowsMergedIf); + verifyFormat("MYIF (a) /* still don't merge */\n" + " f();", + AllowsMergedIf); + verifyFormat("MYIF (a) { // Never merge this\n" + " f();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) { /* Never merge this */\n" + " f();\n" + "}", + AllowsMergedIf); AllowsMergedIf.ColumnLimit = 14; + // Where line-lengths matter, a 2-letter synonym that maintains line length. + // Not IF to avoid any confusion that IF is somehow special. + AllowsMergedIf.IfMacros.push_back("FI"); verifyFormat("if (a) return;", AllowsMergedIf); verifyFormat("if (aaaaaaaaa)\n" " return;", AllowsMergedIf); + verifyFormat("FI (a) return;", AllowsMergedIf); + verifyFormat("FI (aaaaaaaaa)\n" + " return;", + AllowsMergedIf); AllowsMergedIf.ColumnLimit = 13; verifyFormat("if (a)\n return;", AllowsMergedIf); + verifyFormat("FI (a)\n return;", AllowsMergedIf); FormatStyle AllowsMergedIfElse = getLLVMStyle(); + AllowsMergedIfElse.IfMacros.push_back("MYIF"); AllowsMergedIfElse.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_AllIfsAndElse; verifyFormat("if (a)\n" @@ -626,10 +672,60 @@ TEST_F(FormatTest, FormatIfWithoutCompoundStatement) { " else if constexpr (c) return;\n" " else return;", AllowsMergedIfElse); + verifyFormat("MYIF (a)\n" + " // comment\n" + " f();\n" + "else\n" + " // comment\n" + " f();", + AllowsMergedIfElse); + verifyFormat("{\n" + " MYIF (a)\n" + " label:\n" + " f();\n" + " else\n" + " label:\n" + " f();\n" + "}", + AllowsMergedIfElse); + verifyFormat("MYIF (a)\n" + " ;\n" + "else\n" + " ;", + AllowsMergedIfElse); + verifyFormat("MYIF (a) {\n" + "} else {\n" + "}", + AllowsMergedIfElse); + verifyFormat("MYIF (a) return;\n" + "else MYIF (b) return;\n" + "else return;", + AllowsMergedIfElse); + verifyFormat("MYIF (a) {\n" + "} else return;", + AllowsMergedIfElse); + verifyFormat("MYIF (a) {\n" + "} else MYIF (b) return;\n" + "else return;", + AllowsMergedIfElse); + verifyFormat("MYIF (a) return;\n" + "else MYIF (b) {\n" + "} else return;", + AllowsMergedIfElse); + verifyFormat("MYIF (a)\n" + " MYIF (b) return;\n" + " else return;", + AllowsMergedIfElse); + verifyFormat("MYIF constexpr (a)\n" + " MYIF constexpr (b) return;\n" + " else MYIF constexpr (c) return;\n" + " else return;", + AllowsMergedIfElse); } TEST_F(FormatTest, FormatIfWithoutCompoundStatementButElseWith) { FormatStyle AllowsMergedIf = getLLVMStyle(); + AllowsMergedIf.IfMacros.push_back("MYIF"); AllowsMergedIf.AlignEscapedNewlines = FormatStyle::ENAS_Left; AllowsMergedIf.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_WithoutElse; @@ -717,6 +813,135 @@ TEST_F(FormatTest, FormatIfWithoutCompoundStatementButElseWith) { " g();\n" "}", AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " f();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " f();\n" + "else\n" + " g();\n", + AllowsMergedIf); + + verifyFormat("MYIF (a) g();", AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g()\n" + "};", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " g();\n" + "else MYIF (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " g();\n" + "else if (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else MYIF (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else if (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " g();\n" + "else MYIF (b) {\n" + " g();\n" + "} else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " g();\n" + "else if (b) {\n" + " g();\n" + "} else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " g();\n" + "else MYIF (b)\n" + " g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " g();\n" + "else if (b)\n" + " g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " g();\n" + "else MYIF (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a)\n" + " g();\n" + "else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else MYIF (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); AllowsMergedIf.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_OnlyFirstIf; @@ -802,6 +1027,128 @@ TEST_F(FormatTest, FormatIfWithoutCompoundStatementButElseWith) { " g();\n" "}", AllowsMergedIf); + verifyFormat("MYIF (a) f();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) f();\n" + "else {\n" + " if (a) f();\n" + " else {\n" + " g();\n" + " }\n" + " g();\n" + "}", + AllowsMergedIf); + + verifyFormat("MYIF (a) g();", AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g()\n" + "};", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else MYIF (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else if (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else MYIF (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else if (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else MYIF (b) {\n" + " g();\n" + "} else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else if (b) {\n" + " g();\n" + "} else\n" + " g();", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else MYIF (b)\n" + " g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else if (b)\n" + " g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else MYIF (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else MYIF (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); AllowsMergedIf.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_AllIfsAndElse; @@ -879,6 +1226,114 @@ TEST_F(FormatTest, FormatIfWithoutCompoundStatementButElseWith) { " g();\n" "}", AllowsMergedIf); + verifyFormat("MYIF (a) f();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) f();\n" + "else {\n" + " if (a) f();\n" + " else {\n" + " g();\n" + " }\n" + " g();\n" + "}", + AllowsMergedIf); + + verifyFormat("MYIF (a) g();", AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g()\n" + "};", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else g();", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else g();", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else MYIF (b) g();\n" + "else g();", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else if (b) g();\n" + "else g();", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else MYIF (b) g();\n" + "else g();", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else if (b) g();\n" + "else g();", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else MYIF (b) {\n" + " g();\n" + "} else g();", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else if (b) {\n" + " g();\n" + "} else g();", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else MYIF (b) g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else if (b) g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else MYIF (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) g();\n" + "else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else MYIF (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("MYIF (a) {\n" + " g();\n" + "} else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); } TEST_F(FormatTest, FormatLoopsWithoutCompoundStatement) { @@ -930,6 +1385,10 @@ TEST_F(FormatTest, FormatLoopsWithoutCompoundStatement) { TEST_F(FormatTest, FormatShortBracedStatements) { FormatStyle AllowSimpleBracedStatements = getLLVMStyle(); + AllowSimpleBracedStatements.IfMacros.push_back("MYIF"); + // Where line-lengths matter, a 2-letter synonym that maintains line length. + // Not IF to avoid any confusion that IF is somehow special. + AllowSimpleBracedStatements.IfMacros.push_back("FI"); AllowSimpleBracedStatements.ColumnLimit = 40; AllowSimpleBracedStatements.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Always; @@ -945,11 +1404,17 @@ TEST_F(FormatTest, FormatShortBracedStatements) { verifyFormat("if (true) {}", AllowSimpleBracedStatements); verifyFormat("if constexpr (true) {}", AllowSimpleBracedStatements); verifyFormat("if CONSTEXPR (true) {}", AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {}", AllowSimpleBracedStatements); + verifyFormat("MYIF constexpr (true) {}", AllowSimpleBracedStatements); + verifyFormat("MYIF CONSTEXPR (true) {}", AllowSimpleBracedStatements); verifyFormat("while (true) {}", AllowSimpleBracedStatements); verifyFormat("for (;;) {}", AllowSimpleBracedStatements); verifyFormat("if (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("if constexpr (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("if CONSTEXPR (true) { f(); }", AllowSimpleBracedStatements); + verifyFormat("MYIF (true) { f(); }", AllowSimpleBracedStatements); + verifyFormat("MYIF constexpr (true) { f(); }", AllowSimpleBracedStatements); + verifyFormat("MYIF CONSTEXPR (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("while (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("for (;;) { f(); }", AllowSimpleBracedStatements); verifyFormat("if (true) { fffffffffffffffffffffff(); }", @@ -977,6 +1442,31 @@ TEST_F(FormatTest, FormatShortBracedStatements) { " f();\n" "}", AllowSimpleBracedStatements); + verifyFormat("FI (true) { fffffffffffffffffffffff(); }", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {\n" + " ffffffffffffffffffffffff();\n" + "}", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {\n" + " ffffffffffffffffffffffffffffffffffffffffffffffffffffff();\n" + "}", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true) { //\n" + " f();\n" + "}", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {\n" + " f();\n" + " f();\n" + "}", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {\n" + " f();\n" + "} else {\n" + " f();\n" + "}", + AllowSimpleBracedStatements); verifyFormat("struct A2 {\n" " int X;\n" @@ -1004,6 +1494,17 @@ TEST_F(FormatTest, FormatShortBracedStatements) { " f();\n" "}", AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {}", AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {\n" + " f();\n" + "}", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {\n" + " f();\n" + "} else {\n" + " f();\n" + "}", + AllowSimpleBracedStatements); AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = false; verifyFormat("while (true) {}", AllowSimpleBracedStatements); @@ -1026,11 +1527,17 @@ TEST_F(FormatTest, FormatShortBracedStatements) { verifyFormat("if (true) {}", AllowSimpleBracedStatements); verifyFormat("if constexpr (true) {}", AllowSimpleBracedStatements); verifyFormat("if CONSTEXPR (true) {}", AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {}", AllowSimpleBracedStatements); + verifyFormat("MYIF constexpr (true) {}", AllowSimpleBracedStatements); + verifyFormat("MYIF CONSTEXPR (true) {}", AllowSimpleBracedStatements); verifyFormat("while (true) {}", AllowSimpleBracedStatements); verifyFormat("for (;;) {}", AllowSimpleBracedStatements); verifyFormat("if (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("if constexpr (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("if CONSTEXPR (true) { f(); }", AllowSimpleBracedStatements); + verifyFormat("MYIF (true) { f(); }", AllowSimpleBracedStatements); + verifyFormat("MYIF constexpr (true) { f(); }", AllowSimpleBracedStatements); + verifyFormat("MYIF CONSTEXPR (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("while (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("for (;;) { f(); }", AllowSimpleBracedStatements); verifyFormat("if (true) { fffffffffffffffffffffff(); }", @@ -1064,6 +1571,37 @@ TEST_F(FormatTest, FormatShortBracedStatements) { " f();\n" "}", AllowSimpleBracedStatements); + verifyFormat("FI (true) { fffffffffffffffffffffff(); }", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true)\n" + "{\n" + " ffffffffffffffffffffffff();\n" + "}", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true)\n" + "{\n" + " ffffffffffffffffffffffffffffffffffffffffffffffffffffff();\n" + "}", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true)\n" + "{ //\n" + " f();\n" + "}", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true)\n" + "{\n" + " f();\n" + " f();\n" + "}", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true)\n" + "{\n" + " f();\n" + "} else\n" + "{\n" + " f();\n" + "}", + AllowSimpleBracedStatements); AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; @@ -1081,6 +1619,20 @@ TEST_F(FormatTest, FormatShortBracedStatements) { " f();\n" "}", AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {}", AllowSimpleBracedStatements); + verifyFormat("MYIF (true)\n" + "{\n" + " f();\n" + "}", + AllowSimpleBracedStatements); + verifyFormat("MYIF (true)\n" + "{\n" + " f();\n" + "} else\n" + "{\n" + " f();\n" + "}", + AllowSimpleBracedStatements); AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = false; verifyFormat("while (true) {}", AllowSimpleBracedStatements); @@ -1342,7 +1894,7 @@ TEST_F(FormatTest, ForEachLoops) { FormatStyle Style = getLLVMStyle(); Style.SpaceBeforeParens = - FormatStyle::SBPO_ControlStatementsExceptForEachMacros; + FormatStyle::SBPO_ControlStatementsExceptControlMacros; verifyFormat("void f() {\n" " foreach(Item *item, itemlist) {}\n" " Q_FOREACH(Item *item, itemlist) {}\n" @@ -17624,6 +18176,9 @@ TEST_F(FormatTest, ParsesConfiguration) { FormatStyle::SBPO_Always); CHECK_PARSE("SpaceBeforeParens: ControlStatements", SpaceBeforeParens, FormatStyle::SBPO_ControlStatements); + CHECK_PARSE("SpaceBeforeParens: ControlStatementsExceptControlMacros", + SpaceBeforeParens, + FormatStyle::SBPO_ControlStatementsExceptControlMacros); CHECK_PARSE("SpaceBeforeParens: NonEmptyParentheses", SpaceBeforeParens, FormatStyle::SBPO_NonEmptyParentheses); // For backward compatibility: @@ -17631,6 +18186,9 @@ TEST_F(FormatTest, ParsesConfiguration) { FormatStyle::SBPO_Never); CHECK_PARSE("SpaceAfterControlStatementKeyword: true", SpaceBeforeParens, FormatStyle::SBPO_ControlStatements); + CHECK_PARSE("SpaceBeforeParens: ControlStatementsExceptForEachMacros", + SpaceBeforeParens, + FormatStyle::SBPO_ControlStatementsExceptControlMacros); Style.ColumnLimit = 123; FormatStyle BaseStyle = getLLVMStyle(); @@ -17778,6 +18336,11 @@ TEST_F(FormatTest, ParsesConfiguration) { 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"}); @@ -20463,11 +21026,16 @@ TEST_F(FormatTest, AmbersandInLamda) { 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); @@ -20476,6 +21044,13 @@ TEST_F(FormatTest, SpacesInConditionalStatement) { // Check that space on the left of "::" is inserted as expected at beginning // of condition. verifyFormat("while ( ::func() )\n return;", Spaces); + + // Check impact of ControlStatementsExceptControlMacros is honored. + Spaces.SpaceBeforeParens = + FormatStyle::SBPO_ControlStatementsExceptControlMacros; + 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); } TEST_F(FormatTest, AlternativeOperators) {