diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1,4 +1,4 @@ -======================================== +q======================================== Clang 13.0.0 (In-Progress) Release Notes ======================================== @@ -239,6 +239,10 @@ - Option ``SpacesInAngles`` has been improved, it now accepts ``Leave`` value that allows to keep spaces where they are already present. +- Option ``AllowShortIfStatementsOnASingleLine`` has been improved, it now + accepts ``AllIfsAndElse`` value that allows to put "else if" and "else" short + statements on a single line. (Fixes https://llvm.org/PR50019.) + libclang -------- diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -620,37 +620,74 @@ /// single line. ShortFunctionStyle AllowShortFunctionsOnASingleLine; - /// Different styles for handling short if lines + /// Different styles for handling short if statements. enum ShortIfStyle : unsigned char { /// Never put short ifs on the same line. /// \code /// if (a) - /// return ; + /// return; + /// + /// if (b) + /// return; + /// else + /// return; + /// + /// if (c) + /// return; /// else { /// return; /// } /// \endcode SIS_Never, - /// Without else put short ifs on the same line only if - /// the else is not a compound statement. + /// Put short ifs on the same line only if there is no else statement. /// \code /// if (a) return; + /// + /// if (b) + /// return; /// else /// return; + /// + /// if (c) + /// return; + /// else { + /// return; + /// } /// \endcode SIS_WithoutElse, - /// Always put short ifs on the same line if - /// the else is not a compound statement or not. + /// Put short ifs, but not else ifs nor else statements, on the same line. /// \code /// if (a) return; + /// + /// if (b) return; + /// else if (b) + /// return; + /// else + /// return; + /// + /// if (c) return; + /// else { + /// return; + /// } + /// \endcode + SIS_OnlyFirstIf, + /// Always put short ifs, else ifs and else statements on the same + /// line. + /// \code + /// if (a) return; + /// + /// if (b) return; + /// else return; + /// + /// if (c) return; /// else { /// return; /// } /// \endcode - SIS_Always, + SIS_AllIfsAndElse, }; - /// If ``true``, ``if (a) return;`` can be put on a single line. + /// Dependent on the value, ``if (a) return;`` can be put on a single line. ShortIfStyle AllowShortIfStatementsOnASingleLine; /// Different styles for merging short lambdas containing at most one diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -146,10 +146,12 @@ template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::ShortIfStyle &Value) { IO.enumCase(Value, "Never", FormatStyle::SIS_Never); - IO.enumCase(Value, "Always", FormatStyle::SIS_Always); IO.enumCase(Value, "WithoutElse", FormatStyle::SIS_WithoutElse); + IO.enumCase(Value, "OnlyFirstIf", FormatStyle::SIS_OnlyFirstIf); + IO.enumCase(Value, "AllIfsAndElse", FormatStyle::SIS_AllIfsAndElse); // For backward compatibility. + IO.enumCase(Value, "Always", FormatStyle::SIS_OnlyFirstIf); IO.enumCase(Value, "false", FormatStyle::SIS_Never); IO.enumCase(Value, "true", FormatStyle::SIS_WithoutElse); } diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -421,7 +421,16 @@ } return MergedLines; } - if (TheLine->First->is(tok::kw_if)) { + auto IsElseLine = [&First = TheLine->First]() -> bool { + if (First->is(tok::kw_else)) + return true; + + return First->is(tok::r_brace) && First->Next && + First->Next->is(tok::kw_else); + }; + if (TheLine->First->is(tok::kw_if) || + (IsElseLine() && (Style.AllowShortIfStatementsOnASingleLine == + FormatStyle::SIS_AllIfsAndElse))) { return Style.AllowShortIfStatementsOnASingleLine ? tryMergeSimpleControlStatement(I, E, Limit) : 0; @@ -471,7 +480,8 @@ return 0; Limit = limitConsideringMacros(I + 1, E, Limit); AnnotatedLine &Line = **I; - if (!Line.First->is(tok::kw_do) && Line.Last->isNot(tok::r_paren)) + if (!Line.First->is(tok::kw_do) && !Line.First->is(tok::kw_else) && + !Line.Last->is(tok::kw_else) && Line.Last->isNot(tok::r_paren)) return 0; // Only merge do while if do is the only statement on the line. if (Line.First->is(tok::kw_do) && !Line.Last->is(tok::kw_do)) @@ -482,7 +492,8 @@ TT_LineComment)) return 0; // Only inline simple if's (no nested if or else), unless specified - if (Style.AllowShortIfStatementsOnASingleLine != FormatStyle::SIS_Always) { + if (Style.AllowShortIfStatementsOnASingleLine == + FormatStyle::SIS_WithoutElse) { if (I + 2 != E && Line.startsWith(tok::kw_if) && I[2]->First->is(tok::kw_else)) return 0; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -461,6 +461,69 @@ " }\n" "g();"); + verifyFormat("if (a)\n" + " g();"); + verifyFormat("if (a) {\n" + " g()\n" + "};"); + verifyFormat("if (a)\n" + " g();\n" + "else\n" + " g();"); + verifyFormat("if (a) {\n" + " g();\n" + "} else\n" + " g();"); + verifyFormat("if (a)\n" + " g();\n" + "else {\n" + " g();\n" + "}"); + verifyFormat("if (a) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}"); + verifyFormat("if (a)\n" + " g();\n" + "else if (b)\n" + " g();\n" + "else\n" + " g();"); + verifyFormat("if (a) {\n" + " g();\n" + "} else if (b)\n" + " g();\n" + "else\n" + " g();"); + verifyFormat("if (a)\n" + " g();\n" + "else if (b) {\n" + " g();\n" + "} else\n" + " g();"); + verifyFormat("if (a)\n" + " g();\n" + "else if (b)\n" + " g();\n" + "else {\n" + " g();\n" + "}"); + verifyFormat("if (a)\n" + " g();\n" + "else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}"); + verifyFormat("if (a) {\n" + " g();\n" + "} else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}"); + FormatStyle AllowsMergedIf = getLLVMStyle(); AllowsMergedIf.AlignEscapedNewlines = FormatStyle::ENAS_Left; AllowsMergedIf.AllowShortIfStatementsOnASingleLine = @@ -510,6 +573,59 @@ AllowsMergedIf.ColumnLimit = 13; verifyFormat("if (a)\n return;", AllowsMergedIf); + + FormatStyle AllowsMergedIfElse = getLLVMStyle(); + AllowsMergedIfElse.AllowShortIfStatementsOnASingleLine = + FormatStyle::SIS_AllIfsAndElse; + verifyFormat("if (a)\n" + " // comment\n" + " f();\n" + "else\n" + " // comment\n" + " f();", + AllowsMergedIfElse); + verifyFormat("{\n" + " if (a)\n" + " label:\n" + " f();\n" + " else\n" + " label:\n" + " f();\n" + "}", + AllowsMergedIfElse); + verifyFormat("if (a)\n" + " ;\n" + "else\n" + " ;", + AllowsMergedIfElse); + verifyFormat("if (a) {\n" + "} else {\n" + "}", + AllowsMergedIfElse); + verifyFormat("if (a) return;\n" + "else if (b) return;\n" + "else return;", + AllowsMergedIfElse); + verifyFormat("if (a) {\n" + "} else return;", + AllowsMergedIfElse); + verifyFormat("if (a) {\n" + "} else if (b) return;\n" + "else return;", + AllowsMergedIfElse); + verifyFormat("if (a) return;\n" + "else if (b) {\n" + "} else return;", + AllowsMergedIfElse); + verifyFormat("if (a)\n" + " if (b) return;\n" + " else return;", + AllowsMergedIfElse); + verifyFormat("if constexpr (a)\n" + " if constexpr (b) return;\n" + " else if constexpr (c) return;\n" + " else return;", + AllowsMergedIfElse); } TEST_F(FormatTest, FormatIfWithoutCompoundStatementButElseWith) { @@ -529,7 +645,166 @@ " g();\n", AllowsMergedIf); - AllowsMergedIf.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Always; + verifyFormat("if (a) g();", AllowsMergedIf); + verifyFormat("if (a) {\n" + " g()\n" + "};", + AllowsMergedIf); + verifyFormat("if (a)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else\n" + " g();", + AllowsMergedIf); + verifyFormat("if (a)\n" + " g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a)\n" + " g();\n" + "else if (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else if (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("if (a)\n" + " g();\n" + "else if (b) {\n" + " g();\n" + "} else\n" + " g();", + AllowsMergedIf); + verifyFormat("if (a)\n" + " g();\n" + "else if (b)\n" + " g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a)\n" + " g();\n" + "else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + + AllowsMergedIf.AllowShortIfStatementsOnASingleLine = + FormatStyle::SIS_OnlyFirstIf; + + verifyFormat("if (a) f();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) f();\n" + "else {\n" + " if (a) f();\n" + " else {\n" + " g();\n" + " }\n" + " g();\n" + "}", + AllowsMergedIf); + + verifyFormat("if (a) g();", AllowsMergedIf); + verifyFormat("if (a) {\n" + " g()\n" + "};", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else\n" + " g();", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else if (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else if (b)\n" + " g();\n" + "else\n" + " g();", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else if (b) {\n" + " g();\n" + "} else\n" + " g();", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else if (b)\n" + " g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + + AllowsMergedIf.AllowShortIfStatementsOnASingleLine = + FormatStyle::SIS_AllIfsAndElse; verifyFormat("if (a) f();\n" "else {\n" @@ -545,6 +820,65 @@ " g();\n" "}", AllowsMergedIf); + + verifyFormat("if (a) g();", AllowsMergedIf); + verifyFormat("if (a) {\n" + " g()\n" + "};", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else g();", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else g();", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else if (b) g();\n" + "else g();", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else if (b) g();\n" + "else g();", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else if (b) {\n" + " g();\n" + "} else g();", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else if (b) g();\n" + "else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) g();\n" + "else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); + verifyFormat("if (a) {\n" + " g();\n" + "} else if (b) {\n" + " g();\n" + "} else {\n" + " g();\n" + "}", + AllowsMergedIf); } TEST_F(FormatTest, FormatLoopsWithoutCompoundStatement) { @@ -15814,7 +16148,7 @@ FormatStyle BreakBeforeBraceShortIfs = WhitesmithsBraceStyle; BreakBeforeBraceShortIfs.AllowShortIfStatementsOnASingleLine = - FormatStyle::SIS_Always; + FormatStyle::SIS_OnlyFirstIf; BreakBeforeBraceShortIfs.AllowShortLoopsOnASingleLine = true; verifyFormat("void f(bool b)\n" " {\n" @@ -16694,14 +17028,21 @@ CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation, FormatStyle::NI_All); - Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Always; + Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_OnlyFirstIf; CHECK_PARSE("AllowShortIfStatementsOnASingleLine: Never", AllowShortIfStatementsOnASingleLine, FormatStyle::SIS_Never); CHECK_PARSE("AllowShortIfStatementsOnASingleLine: WithoutElse", AllowShortIfStatementsOnASingleLine, FormatStyle::SIS_WithoutElse); + CHECK_PARSE("AllowShortIfStatementsOnASingleLine: OnlyFirstIf", + AllowShortIfStatementsOnASingleLine, + FormatStyle::SIS_OnlyFirstIf); + CHECK_PARSE("AllowShortIfStatementsOnASingleLine: AllIfsAndElse", + AllowShortIfStatementsOnASingleLine, + FormatStyle::SIS_AllIfsAndElse); CHECK_PARSE("AllowShortIfStatementsOnASingleLine: Always", - AllowShortIfStatementsOnASingleLine, FormatStyle::SIS_Always); + AllowShortIfStatementsOnASingleLine, + FormatStyle::SIS_OnlyFirstIf); CHECK_PARSE("AllowShortIfStatementsOnASingleLine: false", AllowShortIfStatementsOnASingleLine, FormatStyle::SIS_Never); CHECK_PARSE("AllowShortIfStatementsOnASingleLine: true",