Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -948,7 +948,7 @@ int x; } - * ``bool AfterExternBlock`` Wrap extern blocks. + * ``bool AfterExternBlock`` Wrap extern blocks; Partially superseded by IndentExternBlock .. code-block:: c++ Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -256,6 +256,23 @@ ------------ +- Option ``IndentExternBlock`` has been added to optionally apply indenting inside ``extern "C"`` and ``extern "C++"`` blocks. + +- ``IndentExternBlock`` option accepts ``AfterExternBlock`` to use the old behavior, as well as Indent and NoIndent options, which map to true and false, respectively. + + .. code-block:: c++ + + Indent: NoIndent: + #ifdef __cplusplus extern "C++" { + extern "C" { + #endif + + void f(void); void f(void); + + #ifdef __cplusplus + } } + #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 @@ -1004,7 +1004,7 @@ /// } /// \endcode bool AfterUnion; - /// Wrap extern blocks. + /// Wrap extern blocks; Partially superseded by IndentExternBlock /// \code /// true: /// extern "C" @@ -1518,6 +1518,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 @@ -2278,6 +2313,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 @@ -204,6 +204,19 @@ IO.enumCase(Value, "true", 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, "Noindent", FormatStyle::IEBS_NoIndent); + IO.enumCase(Value, "true", FormatStyle::IEBS_Indent); + IO.enumCase(Value, "false", FormatStyle::IEBS_NoIndent); + } +}; template <> struct ScalarEnumerationTraits { @@ -513,6 +526,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 @@ -1113,11 +1113,11 @@ if (FormatTok->Tok.is(tok::string_literal)) { nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { - if (Style.BraceWrapping.AfterExternBlock) { + if (Style.BraceWrapping.AfterExternBlock) { // Style.IndentExternBlock == FormatStyle::IEBS_AfterExternBlock && addUnwrappedLine(); - parseBlock(/*MustBeDeclaration=*/true); + parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/Style.BraceWrapping.AfterExternBlock); } else { - parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/false); + parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/Style.IndentExternBlock == FormatStyle::IEBS_Indent); } addUnwrappedLine(); return; Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -2538,6 +2538,39 @@ "}", Style); } + +TEST_F(FormatTest, IndentExternBlockStyle) { + FormatStyle Style = getLLVMStyle(); + Style.IndentWidth = 2; + + Style.IndentExternBlock = FormatStyle::IEBS_Indent; + verifyFormat("extern \"C\" { /*9*/\n}", Style); + verifyFormat("extern \"C\" {\n" + " int foo10();\n" + "}", Style); + + Style.IndentExternBlock = FormatStyle::IEBS_NoIndent; + verifyFormat("extern \"C\" { /*11*/\n}", Style); + verifyFormat("extern \"C\" {\n" + "int foo12();\n" + "}", Style); + + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + + Style.BraceWrapping.AfterExternBlock = true; + Style.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; + verifyFormat("extern \"C\"\n{ /*13*/\n}", Style); + verifyFormat("extern \"C\"\n{\n" + " int foo14();\n" + "}", Style); + + Style.BraceWrapping.AfterExternBlock = false; + Style.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; + verifyFormat("extern \"C\" { /*15*/\n}", Style); + verifyFormat("extern \"C\" {\n" + "int foo16();\n" + "}", Style); +} TEST_F(FormatTest, FormatsInlineASM) { verifyFormat("asm(\"xyz\" : \"=a\"(a), \"=d\"(b) : \"a\"(data));"); @@ -13715,6 +13748,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.