Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -112,6 +112,13 @@ /// single line. bool AllowShortLoopsOnASingleLine; + /// \brief If \c true, + /// \code + /// namespace a { class b; } + /// \endcode + /// can be put on a single line + bool AllowShortNamespacesOnASingleLine; + /// \brief Different ways to break after the function definition return type. enum DefinitionReturnTypeBreakingStyle { /// Break after return type automatically. Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -212,6 +212,8 @@ Style.AllowShortIfStatementsOnASingleLine); IO.mapOptional("AllowShortLoopsOnASingleLine", Style.AllowShortLoopsOnASingleLine); + IO.mapOptional("AllowShortNamespacesOnASingleLine", + Style.AllowShortNamespacesOnASingleLine); IO.mapOptional("AlwaysBreakAfterDefinitionReturnType", Style.AlwaysBreakAfterDefinitionReturnType); IO.mapOptional("AlwaysBreakBeforeMultilineStrings", @@ -354,6 +356,7 @@ LLVMStyle.AllowShortCaseLabelsOnASingleLine = false; LLVMStyle.AllowShortIfStatementsOnASingleLine = false; LLVMStyle.AllowShortLoopsOnASingleLine = false; + LLVMStyle.AllowShortNamespacesOnASingleLine = false; LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; LLVMStyle.AlwaysBreakBeforeMultilineStrings = false; LLVMStyle.AlwaysBreakTemplateDeclarations = false; Index: lib/Format/UnwrappedLineFormatter.cpp =================================================================== --- lib/Format/UnwrappedLineFormatter.cpp +++ lib/Format/UnwrappedLineFormatter.cpp @@ -199,6 +199,11 @@ return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0; } if (TheLine->Last->is(tok::l_brace)) { + if (Style.AllowShortNamespacesOnASingleLine && + TheLine->First->is(tok::kw_namespace)) { + if (unsigned result = tryMergeNamespace(I, E, Limit)) + return result; + } return Style.BreakBeforeBraces == FormatStyle::BS_Attach ? tryMergeSimpleBlock(I, E, Limit) : 0; @@ -258,6 +263,65 @@ return 1; } + unsigned tryMergeNamespace(SmallVectorImpl::const_iterator I, + SmallVectorImpl::const_iterator E, + unsigned Limit) { + if (Limit == 0) + return 0; + if (I[1]->InPPDirective != (*I)->InPPDirective || + (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline)) + return 0; + + Limit = limitConsideringMacros(I + 1, E, Limit); + + if (1 + I[1]->Last->TotalLength > Limit) + return 0; + + // An assumption of the function is that the first line begins with + // keyword namespace (i.e. I[0]->First->is(tok::kw_namespace)) + // Check also that the second token after 'namespace' exists and is an + // l_brace which we aren't requried to break before + if (!I[0]->First->Next || !I[0]->First->Next->Next) + return 0; + FormatToken *Tok = I[0]->First->Next->Next; + if (!Tok->is(tok::l_brace) || Tok->MustBreakBefore) + return 0; + + // Check if it's a namespace inside a namespace, and call recursively if so + // 10 + 2 + 2 is the sizes of the strings "namespace " " {" and " }" + if (I[1]->First->is(tok::kw_namespace)) { + unsigned inner_limit = + Limit - 10 - 2 - 2 - + (I[0]->First->Next ? I[0]->First->Next->TotalLength : 0); + unsigned inner_result = tryMergeNamespace(I + 1, E, inner_limit); + if (!inner_result) + return 0; + // check if there is even a line after the inner result + if (I + 2 + inner_result >= E) + return 0; + // check that the line after the inner result starts with a closing brace + // which we are permitted to merge into one line + if (I[2 + inner_result]->First->is(tok::r_brace) && + !I[2 + inner_result]->First->MustBreakBefore) + return 2 + inner_result; + return 0; + } + + // There's no inner namespace, so we are considering to merge at most one + // line. + + // The line which is in the namespace should end with semicolon + if (I[1]->Last->isNot(tok::semi)) + return 0; + + // Last, check that the third line starts with a closing brace. + if (I[2]->First->isNot(tok::r_brace) || I[2]->First->MustBreakBefore) + return 0; + + // If so, merge all three lines. + return 2; + } + unsigned tryMergeSimpleControlStatement( SmallVectorImpl::const_iterator I, SmallVectorImpl::const_iterator E, unsigned Limit) { Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -3226,16 +3226,19 @@ Style.MacroBlockEnd = "^[A-Z_]+_END$"; verifyFormat("FOO_BEGIN\n" " FOO_ENTRY\n" - "FOO_END", Style); + "FOO_END", + Style); verifyFormat("FOO_BEGIN\n" " NESTED_FOO_BEGIN\n" " NESTED_FOO_ENTRY\n" " NESTED_FOO_END\n" - "FOO_END", Style); + "FOO_END", + Style); verifyFormat("FOO_BEGIN(Foo, Bar)\n" " int x;\n" " x = 1;\n" - "FOO_END(Baz)", Style); + "FOO_END(Baz)", + Style); } //===----------------------------------------------------------------------===// @@ -7649,14 +7652,13 @@ // Verify that splitting the strings understands // Style::AlwaysBreakBeforeMultilineStrings. - EXPECT_EQ( - "aaaaaaaaaaaa(\n" - " \"aaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa \"\n" - " \"aaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa\");", - format("aaaaaaaaaaaa(\"aaaaaaaaaaaaaaaaaaaaaaaaaa " - "aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaa " - "aaaaaaaaaaaaaaaaaaaaaa\");", - getGoogleStyle())); + EXPECT_EQ("aaaaaaaaaaaa(\n" + " \"aaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa \"\n" + " \"aaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa\");", + format("aaaaaaaaaaaa(\"aaaaaaaaaaaaaaaaaaaaaaaaaa " + "aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaa " + "aaaaaaaaaaaaaaaaaaaaaa\");", + getGoogleStyle())); EXPECT_EQ("return \"aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaa \"\n" " \"aaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa\";", format("return \"aaaaaaaaaaaaaaaaaaaaaa " @@ -10433,6 +10435,45 @@ verifyNoCrash("#define a\\\n /**/}"); } +TEST_F(FormatTest, ShortNamespacesOption) { + FormatStyle style = getLLVMStyle(); + style.AllowShortNamespacesOnASingleLine = true; + + verifyFormat("namespace foo { class bar; }", style); + verifyFormat("namespace foo {\n" + "class bar;\n" + "class baz;\n" + "}", + style); + verifyFormat("namespace foo { namespace bar { class baz; } }", style); + verifyFormat("namespace foo {\n" + "namespace bar { class baz; }\n" + "namespace quar { class quaz; }\n" + "}", + style); + verifyFormat("namespace foo {\n" + "int f() { return 5; }\n" + "}", + style); + verifyFormat("namespace foo { template struct bar; }", style); + verifyFormat("namespace foo { constexpr int num = 42; }", style); + + // test column limit + verifyFormat("namespace boost {\n" + "namespace spirit {\n" + "namespace qi {\n" + "namespace unicode { namespace foo { class bar; } }\n" + "}\n" + "}\n" + "}", + style); + + style.ColumnLimit = 0; + verifyFormat("namespace boost { namespace spirit { namespace qi { namespace " + "unicode { namespace foo { class bar; } } } } }", + style); +} + } // end namespace } // end namespace format } // end namespace clang