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++ @@ -1712,6 +1712,46 @@ plop(); plop(); } } +**IndentExternBlock** (``IndentExternBlockStyle``) + The IndentExternBlockStyle to use for indenting extern blocks. + + Possible values: + + * ``IEBS_AfterExternBlock`` (in configuration: ``AfterExternBlock``) + Backwards compatible with AfterExternBlock's indenting. + + .. code-block:: c++ + + AfterExternBlock: true + extern "C" + { + void foo(); + } + AfterExternBlock: false + extern "C" { + void foo(); + } + + * ``IEBS_NoIndent`` (in configuration: ``NoIndent``) + Does not indent extern blocks. + + .. code-block:: c++ + + extern "C" { + void foo(); + } + + * ``IEBS_Indent`` (in configuration: ``Indent``) + Indents extern blocks. + + .. code-block:: c++ + + extern "C" { + void foo(); + } + + + **IndentGotoLabels** (``bool``) Indent goto labels. 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 #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 @@ -1004,7 +1004,7 @@ /// } /// \endcode bool AfterUnion; - /// Wrap extern blocks. + /// Wrap extern blocks; Partially superseded by IndentExternBlock /// \code /// true: /// extern "C" @@ -1518,6 +1518,40 @@ /// \endcode bool IndentWrappedFunctionNames; + /// Indents extern blocks + enum IndentExternBlockStyle { + /// Backwards compatible with AfterExternBlock's indenting. + /// \code + /// AfterExternBlock: true + /// extern "C" + /// { + /// void foo(); + /// } + /// AfterExternBlock: false + /// extern "C" { + /// void foo(); + /// } + /// \endcode + IEBS_AfterExternBlock, + /// Does not indent extern blocks. + /// \code + /// extern "C" { + /// void foo(); + /// } + /// \endcode + IEBS_NoIndent, + /// Indents extern blocks. + /// \code + /// extern "C" { + /// void foo(); + /// } + /// \endcode + IEBS_Indent, + }; + + /// The IndentExternBlockStyle to use for indenting extern blocks. + 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 @@ -2011,8 +2045,8 @@ /// \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 macros. This is useful in projects where ForEach macros are + /// treated as function calls instead of control statements. /// \code /// void f() { /// Q_FOREACH(...) { @@ -2278,6 +2312,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 @@ -205,6 +205,17 @@ } }; +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 { static void @@ -513,6 +524,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); @@ -693,11 +705,13 @@ true, true}; switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: + Expanded.IndentExternBlock = FormatStyle::IEBS_NoIndent; Expanded.BraceWrapping.AfterClass = true; Expanded.BraceWrapping.AfterFunction = true; Expanded.BraceWrapping.AfterNamespace = true; break; case FormatStyle::BS_Mozilla: + Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; Expanded.BraceWrapping.AfterClass = true; Expanded.BraceWrapping.AfterEnum = true; Expanded.BraceWrapping.AfterFunction = true; @@ -708,11 +722,13 @@ Expanded.BraceWrapping.SplitEmptyRecord = false; break; case FormatStyle::BS_Stroustrup: + Expanded.IndentExternBlock = FormatStyle::IEBS_NoIndent; Expanded.BraceWrapping.AfterFunction = true; Expanded.BraceWrapping.BeforeCatch = true; Expanded.BraceWrapping.BeforeElse = true; break; case FormatStyle::BS_Allman: + Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; Expanded.BraceWrapping.AfterCaseLabel = true; Expanded.BraceWrapping.AfterClass = true; Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; @@ -727,6 +743,7 @@ Expanded.BraceWrapping.BeforeElse = true; break; case FormatStyle::BS_Whitesmiths: + Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; Expanded.BraceWrapping.AfterCaseLabel = true; Expanded.BraceWrapping.AfterClass = true; Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; @@ -741,6 +758,7 @@ Expanded.BraceWrapping.BeforeLambdaBody = true; break; case FormatStyle::BS_GNU: + Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; Expanded.BraceWrapping = {true, true, FormatStyle::BWACS_Always, true, true, true, true, true, true, @@ -819,6 +837,7 @@ LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve; LLVMStyle.IndentCaseLabels = false; LLVMStyle.IndentCaseBlocks = false; + LLVMStyle.IndentExternBlock = FormatStyle::IEBS_NoIndent; LLVMStyle.IndentGotoLabels = true; LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None; LLVMStyle.IndentWrappedFunctionNames = false; @@ -909,6 +928,7 @@ GoogleStyle.IncludeStyle.IncludeIsMainRegex = "([-_](test|unittest))?$"; GoogleStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; GoogleStyle.IndentCaseLabels = true; + GoogleStyle.IndentExternBlock = FormatStyle::IEBS_NoIndent; GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false; GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never; GoogleStyle.ObjCSpaceAfterProperty = false; @@ -1044,6 +1064,7 @@ ChromiumStyle.BreakAfterJavaFieldAnnotations = true; ChromiumStyle.ContinuationIndentWidth = 8; ChromiumStyle.IndentWidth = 4; + ChromiumStyle.IndentExternBlock = FormatStyle::IEBS_NoIndent; // See styleguide for import groups: // https://chromium.googlesource.com/chromium/src/+/master/styleguide/java/java.md#Import-Order ChromiumStyle.JavaImportGroups = { @@ -1093,6 +1114,7 @@ MozillaStyle.Cpp11BracedListStyle = false; MozillaStyle.FixNamespaceComments = false; MozillaStyle.IndentCaseLabels = true; + MozillaStyle.IndentExternBlock = FormatStyle::IEBS_NoIndent; MozillaStyle.ObjCSpaceAfterProperty = true; MozillaStyle.ObjCSpaceBeforeProtocolList = false; MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; @@ -1115,6 +1137,7 @@ Style.ColumnLimit = 0; Style.FixNamespaceComments = false; Style.IndentWidth = 4; + Style.IndentExternBlock = FormatStyle::IEBS_NoIndent; Style.NamespaceIndentation = FormatStyle::NI_Inner; Style.ObjCBlockIndentWidth = 4; Style.ObjCSpaceAfterProperty = true; @@ -1133,6 +1156,7 @@ Style.BreakBeforeTernaryOperators = true; Style.Cpp11BracedListStyle = false; Style.ColumnLimit = 79; + Style.IndentExternBlock = FormatStyle::IEBS_NoIndent; Style.FixNamespaceComments = false; Style.SpaceBeforeParens = FormatStyle::SBPO_Always; Style.Standard = FormatStyle::LS_Cpp03; @@ -1156,6 +1180,7 @@ Style.BraceWrapping.AfterExternBlock = true; Style.BraceWrapping.BeforeCatch = true; Style.BraceWrapping.BeforeElse = true; + Style.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; Style.PenaltyReturnTypeOnItsOwnLine = 1000; Style.AllowShortEnumsOnASingleLine = false; Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; @@ -1172,6 +1197,7 @@ NoStyle.DisableFormat = true; NoStyle.SortIncludes = false; NoStyle.SortUsingDeclarations = false; + NoStyle.IndentExternBlock = FormatStyle::IEBS_NoIndent; return NoStyle; } Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -1113,11 +1113,16 @@ if (FormatTok->Tok.is(tok::string_literal)) { nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { - if (Style.BraceWrapping.AfterExternBlock) { - addUnwrappedLine(); - parseBlock(/*MustBeDeclaration=*/true); + if (!Style.IndentExternBlock) { + if (Style.BraceWrapping.AfterExternBlock) { + addUnwrappedLine(); + } + 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 @@ -2539,6 +2539,43 @@ 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.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + Style.BraceWrapping.AfterExternBlock = true; + verifyFormat("extern \"C\"\n{ /*13*/\n}", Style); + verifyFormat("extern \"C\"\n{\n" + " int foo14();\n" + "}", + Style); + + Style.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + Style.BraceWrapping.AfterExternBlock = false; + 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));"); verifyFormat("asm(\"nop\" ::: \"memory\");"); @@ -13716,6 +13753,18 @@ 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. Style.ForEachMacros.clear();