Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -236,6 +236,23 @@ ------------ +- Option ``IndentExternBlock`` has been added to optionally apply indenting inside extern "C" blocks. + + The ``BraceWrapping.AfterExternBlock`` option has been modified so it no longer indents when set to true, now it just wraps the braces around extern blocks. + + .. code-block:: c++ + + true: false: + #ifdef __cplusplus #ifdef __cplusplus + extern "C" { extern "C" { + #endif #endif + + void f(void); void f(void); + + #ifdef __cplusplus #ifdef __cplusplus + } } + #endif #endif + - Option ``IndentCaseBlocks`` has been added to support treating the block following a switch case label as a scope block which gets indented itself. It helps avoid having the closing bracket align with the switch statement's Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -948,12 +948,12 @@ /// } /// \endcode bool AfterUnion; - /// Wrap extern blocks. + /// Wrap extern blocks; Deprecated, replaced by ExternBlocks /// \code /// true: /// extern "C" /// { - /// int foo(); + /// int foo(); /// } /// /// false: @@ -962,6 +962,24 @@ /// } /// \endcode bool AfterExternBlock; + enum ExternBlock { + /// Break extern blocks before the curly brace. + /// \code + /// extern "C" + /// { + /// foo(); + /// } + /// \endcode + EB_Before, + /// Break constructor initializers before the colon and commas, and align + /// the commas with the colon. + /// \code + /// extern "C++" { + /// foo(); + /// } + /// \endcode + EB_None + }; /// Wrap before ``catch``. /// \code /// true: @@ -1462,6 +1480,41 @@ /// \endcode bool IndentWrappedFunctionNames; + /// Indents extern blocks + enum IndentExternBlockStyle { + /// Does not indent extern blocks. + /// \code + /// extern "C" { + /// void foo(); + /// } + /// \endcode + IEBS_NoIndent, + /// Indents extern blocks. + /// \code + /// extern "C" { + /// void foo(); + /// } + /// \endcode + IEBS_Indent, + /// Backwards compatible with AfterExternBlock's indenting. + /// AfterExternBlock: true + /// \code + /// extern "C" + /// { + /// void foo(); + /// } + /// \endcode + /// AfterExternBlock: false + /// \code + /// extern "C" { + /// void foo(); + /// } + /// \endcode + IEBS_AfterExternBlock, + }; + + IndentExternBlockStyle IndentExternBlock; + /// A vector of prefixes ordered by the desired groups for Java imports. /// /// Each group is separated by a newline. Static imports will also follow the @@ -2210,6 +2263,7 @@ IndentPPDirectives == R.IndentPPDirectives && IndentWidth == R.IndentWidth && Language == R.Language && IndentWrappedFunctionNames == R.IndentWrappedFunctionNames && + IndentExternBlock == R.IndentExternBlock && JavaImportGroups == R.JavaImportGroups && JavaScriptQuotes == R.JavaScriptQuotes && JavaScriptWrapImports == R.JavaScriptWrapImports && Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -202,6 +202,18 @@ IO.enumCase(Value, "Always", FormatStyle::BWACS_Always); } }; + +template <> +struct ScalarEnumerationTraits { + static void + enumeration(IO &IO, FormatStyle::IndentExternBlockStyle &Value) { + IO.enumCase(Value, "AfterExternBlock", FormatStyle::IEBS_AfterExternBlock); + IO.enumCase(Value, "Indent", FormatStyle::IEBS_Indent); + IO.enumCase(Value, "NoIndent", FormatStyle::IEBS_NoIndent); + IO.enumCase(Value, "true", FormatStyle::IEBS_Indent); + IO.enumCase(Value, "false", FormatStyle::IEBS_NoIndent); + } +}; template <> struct ScalarEnumerationTraits { @@ -494,6 +506,7 @@ IO.mapOptional("IndentWidth", Style.IndentWidth); IO.mapOptional("IndentWrappedFunctionNames", Style.IndentWrappedFunctionNames); + IO.mapOptional("IndentExternBlock", Style.IndentExternBlock); IO.mapOptional("InsertTrailingCommas", Style.InsertTrailingCommas); IO.mapOptional("JavaImportGroups", Style.JavaImportGroups); IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes); Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -1112,11 +1112,11 @@ if (FormatTok->Tok.is(tok::string_literal)) { nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { - if (Style.BraceWrapping.AfterExternBlock) { + if (Style.IndentExternBlock == FormatStyle::IEBS_AfterExternBlock && Style.BraceWrapping.AfterExternBlock) { addUnwrappedLine(); - parseBlock(/*MustBeDeclaration=*/true); + parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/Style.BraceWrapping.AfterExternBlock == true ? true : false); } else { - parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false); + parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/Style.IndentExternBlock == FormatStyle::IEBS_Indent ? true : false); } addUnwrappedLine(); return; Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -2509,10 +2509,43 @@ Style); verifyFormat("extern \"C\"\n" "{\n" - " int foo();\n" + "int foo();\n" "}", Style); } + +TEST_F(FormatTest, IndentExternBlockStyle) { + FormatStyle Style = getLLVMStyle(); + Style.IndentWidth = 2; + + Style.IndentExternBlock = FormatStyle::IEBS_Indent; + verifyFormat("extern \"C\" {}", Style); + verifyFormat("extern \"C\" {\n" + " int foo1();\n" + "}", Style); + + Style.IndentExternBlock = FormatStyle::IEBS_NoIndent; + verifyFormat("extern \"C\" {}", Style); + verifyFormat("extern \"C\" {\n" + "int foo2();\n" + "}", Style); + + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + + Style.BraceWrapping.AfterExternBlock = true; + Style.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; + verifyFormat("extern \"C\" {}", Style); + verifyFormat("extern \"C\"\n{\n" + " int foo3();\n" + "}", Style); + + Style.BraceWrapping.AfterExternBlock = false; + Style.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; + verifyFormat("extern \"C\" {}", Style); + verifyFormat("extern \"C\" {\n" + "int foo4();\n" + "}", Style); +} TEST_F(FormatTest, FormatsInlineASM) { verifyFormat("asm(\"xyz\" : \"=a\"(a), \"=d\"(b) : \"a\"(data));"); @@ -13262,6 +13295,13 @@ CHECK_PARSE("AllowShortIfStatementsOnASingleLine: true", AllowShortIfStatementsOnASingleLine, FormatStyle::SIS_WithoutElse); + + Style.IndentExternBlock = FormatStyle.IEBS_Indent; + CHECK_PARSE("IndentExternBlock: AfterExternBlock", IndentExternBlock, FormatStyle::IEBS_AfterExternBlock); + CHECK_PARSE("IndentExternBlock: Indent", IndentExternBlock, FormatStyle::IEBS_Indent); + CHECK_PARSE("IndentExternBlock: NoIndent", IndentExternBlock, FormatStyle::IEBS_NoIndent); + CHECK_PARSE("IndentExternBlock: true", IndentExternBlock, FormatStyle::IEBS_Indent); + CHECK_PARSE("IndentExternBlock: false", IndentExternBlock, FormatStyle::IEBS_NoIndent); // FIXME: This is required because parsing a configuration simply overwrites // the first N elements of the list instead of resetting it.