Index: docs/ClangFormatStyleOptions.rst =================================================================== --- docs/ClangFormatStyleOptions.rst +++ docs/ClangFormatStyleOptions.rst @@ -1372,6 +1372,16 @@ # endif #endif + * ``PPDIS_BeforeHash`` (in configuration: ``BeforeHash``) + Indents directives before the hash. + + .. code-block:: c++ + + #if FOO + #if BAR + #include + #endif + #endif **IndentWidth** (``unsigned``) Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -1088,7 +1088,16 @@ /// # endif /// #endif /// \endcode - PPDIS_AfterHash + PPDIS_AfterHash, + /// Indents directives before the hash. + /// \code + /// #if FOO + /// #if BAR + /// #include + /// #endif + /// #endif + /// \endcode + PPDIS_BeforeHash }; /// The preprocessor directive indenting style to use. Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -163,6 +163,7 @@ static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) { IO.enumCase(Value, "None", FormatStyle::PPDIS_None); IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash); + IO.enumCase(Value, "BeforeHash", FormatStyle::PPDIS_BeforeHash); } }; Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -1908,12 +1908,15 @@ NextNonCommentLine->First->NewlinesBefore <= 1 && NextNonCommentLine->First->OriginalColumn == (*I)->First->OriginalColumn) { - // Align comments for preprocessor lines with the # in column 0. - // Otherwise, align with the next line. - (*I)->Level = (NextNonCommentLine->Type == LT_PreprocessorDirective || - NextNonCommentLine->Type == LT_ImportStatement) - ? 0 - : NextNonCommentLine->Level; + // Align comments for preprocessor lines with the # in column 0 if + // preprocessor lines are not indented. Otherwise, align with the next + // line. + (*I)->Level = + (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && + (NextNonCommentLine->Type == LT_PreprocessorDirective || + NextNonCommentLine->Type == LT_ImportStatement)) + ? 0 + : NextNonCommentLine->Level; } else { NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr; } Index: lib/Format/UnwrappedLineFormatter.cpp =================================================================== --- lib/Format/UnwrappedLineFormatter.cpp +++ lib/Format/UnwrappedLineFormatter.cpp @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "NamespaceEndCommentsFixer.h" #include "UnwrappedLineFormatter.h" +#include "NamespaceEndCommentsFixer.h" #include "WhitespaceManager.h" #include "llvm/Support/Debug.h" #include @@ -685,10 +685,8 @@ /// Formats an \c AnnotatedLine and returns the penalty. /// /// If \p DryRun is \c false, directly applies the changes. - virtual unsigned formatLine(const AnnotatedLine &Line, - unsigned FirstIndent, - unsigned FirstStartColumn, - bool DryRun) = 0; + virtual unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent, + unsigned FirstStartColumn, bool DryRun) = 0; protected: /// If the \p State's next token is an r_brace closing a nested block, @@ -1004,13 +1002,10 @@ } // anonymous namespace -unsigned -UnwrappedLineFormatter::format(const SmallVectorImpl &Lines, - bool DryRun, int AdditionalIndent, - bool FixBadIndentation, - unsigned FirstStartColumn, - unsigned NextStartColumn, - unsigned LastStartColumn) { +unsigned UnwrappedLineFormatter::format( + const SmallVectorImpl &Lines, bool DryRun, + int AdditionalIndent, bool FixBadIndentation, unsigned FirstStartColumn, + unsigned NextStartColumn, unsigned LastStartColumn) { LineJoiner Joiner(Style, Keywords, Lines); // Try to look up already computed penalty in DryRun-mode. @@ -1177,8 +1172,10 @@ if (Newlines) Indent = NewlineIndent; - // Preprocessor directives get indented after the hash, if indented. - if (Line.Type == LT_PreprocessorDirective || Line.Type == LT_ImportStatement) + // Preprocessor directives get indented before the hash only if specified + if (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && + (Line.Type == LT_PreprocessorDirective || + Line.Type == LT_ImportStatement)) Indent = 0; Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent, Index: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -652,6 +652,7 @@ void UnwrappedLineParser::parsePPDirective() { assert(FormatTok->Tok.is(tok::hash) && "'#' expected"); ScopedMacroState MacroState(*Line, Tokens, FormatTok); + nextToken(); if (!FormatTok->Tok.getIdentifierInfo()) { @@ -820,7 +821,7 @@ FormatTok->WhitespaceRange.getEnd()) { parseParens(); } - if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash) + if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) Line->Level += PPBranchLevel + 1; addUnwrappedLine(); ++Line->Level; @@ -837,7 +838,7 @@ do { nextToken(); } while (!eof()); - if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash) + if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) Line->Level += PPBranchLevel + 1; addUnwrappedLine(); } @@ -1155,8 +1156,8 @@ case tok::objc_synchronized: nextToken(); if (FormatTok->Tok.is(tok::l_paren)) - // Skip synchronization object - parseParens(); + // Skip synchronization object + parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { if (Style.BraceWrapping.AfterControlStatement) addUnwrappedLine(); @@ -2600,6 +2601,9 @@ // Comments stored before the preprocessor directive need to be output // before the preprocessor directive, at the same level as the // preprocessor directive, as we consider them to apply to the directive. + if (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && + PPBranchLevel > 0) + Line->Level += PPBranchLevel; flushComments(isOnNewLine(*FormatTok)); parsePPDirective(); } Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -1754,8 +1754,8 @@ Style.CompactNamespaces = true; verifyFormat("namespace A { namespace B {\n" - "}} // namespace A::B", - Style); + "}} // namespace A::B", + Style); EXPECT_EQ("namespace out { namespace in {\n" "}} // namespace out::in", @@ -2846,22 +2846,25 @@ EXPECT_EQ(Expected, format(ToFormat, Style)); EXPECT_EQ(Expected, format(Expected, Style)); } - // Test with tabs. - Style.UseTab = FormatStyle::UT_Always; - Style.IndentWidth = 8; - Style.TabWidth = 8; - verifyFormat("#ifdef _WIN32\n" - "#\tdefine A 0\n" - "#\tifdef VAR2\n" - "#\t\tdefine B 1\n" - "#\t\tinclude \n" - "#\t\tdefine MACRO \\\n" - "\t\t\tsome_very_long_func_aaaaaaaaaa();\n" - "#\tendif\n" - "#else\n" - "#\tdefine A 1\n" - "#endif", - Style); + // Test AfterHash with tabs. + { + FormatStyle Tabbed = Style; + Tabbed.UseTab = FormatStyle::UT_Always; + Tabbed.IndentWidth = 8; + Tabbed.TabWidth = 8; + verifyFormat("#ifdef _WIN32\n" + "#\tdefine A 0\n" + "#\tifdef VAR2\n" + "#\t\tdefine B 1\n" + "#\t\tinclude \n" + "#\t\tdefine MACRO \\\n" + "\t\t\tsome_very_long_func_aaaaaaaaaa();\n" + "#\tendif\n" + "#else\n" + "#\tdefine A 1\n" + "#endif", + Tabbed); + } // Regression test: Multiline-macro inside include guards. verifyFormat("#ifndef HEADER_H\n" @@ -2871,6 +2874,102 @@ " int j;\n" "#endif // HEADER_H", getLLVMStyleWithColumns(20)); + + Style.IndentPPDirectives = FormatStyle::PPDIS_BeforeHash; + // Basic before hash indent tests + verifyFormat("#ifdef _WIN32\n" + " #define A 0\n" + " #ifdef VAR2\n" + " #define B 1\n" + " #include \n" + " #define MACRO \\\n" + " some_very_long_func_aaaaaaaaaa();\n" + " #endif\n" + "#else\n" + " #define A 1\n" + "#endif", + Style); + verifyFormat("#if A\n" + " #define MACRO \\\n" + " void a(int x) { \\\n" + " b(); \\\n" + " c(); \\\n" + " d(); \\\n" + " e(); \\\n" + " f(); \\\n" + " }\n" + "#endif", + Style); + // Keep comments aligned with indented directives. These + // tests cannot use verifyFormat because messUp manipulates leading + // whitespace. + { + const char *Expected = "void f() {\n" + "// Aligned to preprocessor.\n" + "#if 1\n" + " // Aligned to code.\n" + " int a;\n" + " #if 1\n" + " // Aligned to preprocessor.\n" + " #define A 0\n" + " // Aligned to code.\n" + " int b;\n" + " #endif\n" + "#endif\n" + "}"; + const char *ToFormat = "void f() {\n" + "// Aligned to preprocessor.\n" + "#if 1\n" + "// Aligned to code.\n" + "int a;\n" + "#if 1\n" + "// Aligned to preprocessor.\n" + "#define A 0\n" + "// Aligned to code.\n" + "int b;\n" + "#endif\n" + "#endif\n" + "}"; + EXPECT_EQ(Expected, format(ToFormat, Style)); + EXPECT_EQ(Expected, format(Expected, Style)); + } + { + const char *Expected = "void f() {\n" + "/* Aligned to preprocessor. */\n" + "#if 1\n" + " /* Aligned to code. */\n" + " int a;\n" + " #if 1\n" + " /* Aligned to preprocessor. */\n" + " #define A 0\n" + " /* Aligned to code. */\n" + " int b;\n" + " #endif\n" + "#endif\n" + "}"; + const char *ToFormat = "void f() {\n" + "/* Aligned to preprocessor. */\n" + "#if 1\n" + "/* Aligned to code. */\n" + "int a;\n" + "#if 1\n" + "/* Aligned to preprocessor. */\n" + "#define A 0\n" + "/* Aligned to code. */\n" + "int b;\n" + "#endif\n" + "#endif\n" + "}"; + EXPECT_EQ(Expected, format(ToFormat, Style)); + EXPECT_EQ(Expected, format(Expected, Style)); + } + + // Test single comment before preprocessor + verifyFormat("// Comment\n" + "\n" + "#if 1\n" + "#endif", + Style); } TEST_F(FormatTest, FormatHashIfNotAtStartOfLine) { @@ -3730,39 +3829,39 @@ verifyFormat( "SomeClass::Constructor() :\n" " aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}", - Style); + Style); verifyFormat( "SomeClass::Constructor() :\n" " aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n" " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}", - Style); + Style); verifyFormat( "SomeClass::Constructor() :\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n" " aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}", - Style); + Style); verifyFormat("Constructor(aaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" " aaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) :\n" " aaaaaaaaaa(aaaaaa) {}", - Style); + Style); verifyFormat("Constructor() :\n" " aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa),\n" " aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaa),\n" " aaaaaaaaaaaaaaaaaaaaaaa() {}", - Style); + Style); verifyFormat("Constructor() :\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}", - Style); + Style); verifyFormat("Constructor(int Parameter = 0) :\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaa),\n" " aaaaaaaaaaaa(aaaaaaaaaaaaaaaaa) {}", - Style); + Style); verifyFormat("Constructor() :\n" " aaaaaaaaaaaaaaaaaaaaaa(a), bbbbbbbbbbbbbbbbbbbbbbbb(b) {\n" "}", @@ -3770,7 +3869,7 @@ verifyFormat("Constructor() :\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaaaaaaaaaaaaaaaa(aaaa, aaaa)) {}", - Style); + Style); // Here a line could be saved by splitting the second initializer onto two // lines, but that is not desirable. @@ -3778,7 +3877,7 @@ " aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaa),\n" " aaaaaaaaaaa(aaaaaaaaaaa),\n" " aaaaaaaaaaaaaaaaaaaaat(aaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}", - Style); + Style); FormatStyle OnePerLine = Style; OnePerLine.ConstructorInitializerAllOnOneLineOrOnePerLine = true; @@ -3828,7 +3927,7 @@ format("Constructor() :\n" " // Comment forcing unwanted break.\n" " aaaa(aaaa) {}", - Style)); + Style)); Style.ColumnLimit = 0; verifyFormat("SomeClass::Constructor() :\n" @@ -3838,7 +3937,7 @@ " a(a) {}", Style); verifyFormat("SomeClass::Constructor() :\n" - " a(a), b(b), c(c) {}", + " a(a), b(b), c(c) {}", Style); verifyFormat("SomeClass::Constructor() :\n" " a(a) {\n" @@ -3849,12 +3948,12 @@ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; verifyFormat("SomeClass::Constructor() :\n" - " a(a), b(b), c(c) {\n" - "}", + " a(a), b(b), c(c) {\n" + "}", Style); verifyFormat("SomeClass::Constructor() :\n" " a(a) {\n" - "}", + "}", Style); Style.ColumnLimit = 80; @@ -6966,7 +7065,7 @@ // Binpacking only if there is no trailing comma verifyFormat("const Aaaaaa aaaaa = {aaaaaaaaaa, bbbbbbbbbb,\n" " cccccccccc, dddddddddd};", - getLLVMStyleWithColumns(50)); + getLLVMStyleWithColumns(50)); verifyFormat("const Aaaaaa aaaaa = {\n" " aaaaaaaaaaa,\n" " bbbbbbbbbbb,\n"