From: Paul Hoad Date: Wed, 20 Mar 2019 20:49:43 +0000 (+0000) Subject: [clang-format] BeforeHash added to IndentPPDirectives X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9c0f34221d0091db37913871cdcd7b0c425d9ad9;p=clang [clang-format] BeforeHash added to IndentPPDirectives Summary: The option BeforeHash added to IndentPPDirectives. Fixes Bug 36019. https://bugs.llvm.org/show_bug.cgi?id=36019 Reviewers: djasper, klimek, krasimir, sammccall, mprobst, Nicola, MyDeveloperDay Reviewed By: klimek, MyDeveloperDay Subscribers: kadircet, MyDeveloperDay, mnussbaum, geleji, ufna, cfe-commits Patch by to-mix. Differential Revision: https://reviews.llvm.org/D52150 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@356613 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst index d4a56d3bb3..7cd11c7aa7 100644 --- a/docs/ClangFormatStyleOptions.rst +++ b/docs/ClangFormatStyleOptions.rst @@ -1411,6 +1411,16 @@ the configuration (without a prefix: ``Auto``). # endif #endif + * ``PPDIS_BeforeHash`` (in configuration: ``BeforeHash``) + Indents directives before the hash. + + .. code-block:: c++ + + #if FOO + #if BAR + #include + #endif + #endif **IndentWidth** (``unsigned``) diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index 14f5f5e21a..cd51330fcc 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -170,8 +170,8 @@ AST Matchers clang-format ------------ - -- ... +- Added new option `PPDIS_BeforeHash` (in configuration: `BeforeHash`) to + `IndentPPDirectives` which indents preprocessor directives before the hash. libclang -------- diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index d02f706a62..13e36ea7cf 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -1126,7 +1126,16 @@ struct FormatStyle { /// # 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. diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index e73bcba795..5e8a2497fe 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -174,6 +174,7 @@ struct ScalarEnumerationTraits { 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); } }; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index bd4591189f..eeaceb82f9 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -1924,12 +1924,15 @@ void TokenAnnotator::setCommentLineLevels( 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; } diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp index f14e3851c8..5d8142a1cf 100644 --- a/lib/Format/UnwrappedLineFormatter.cpp +++ b/lib/Format/UnwrappedLineFormatter.cpp @@ -1178,8 +1178,10 @@ void UnwrappedLineFormatter::formatFirstToken( 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, diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 3abb6f40d7..4bd71aa26d 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -655,6 +655,7 @@ void UnwrappedLineParser::parseChildBlock() { void UnwrappedLineParser::parsePPDirective() { assert(FormatTok->Tok.is(tok::hash) && "'#' expected"); ScopedMacroState MacroState(*Line, Tokens, FormatTok); + nextToken(); if (!FormatTok->Tok.getIdentifierInfo()) { @@ -823,7 +824,7 @@ void UnwrappedLineParser::parsePPDefine() { FormatTok->WhitespaceRange.getEnd()) { parseParens(); } - if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash) + if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) Line->Level += PPBranchLevel + 1; addUnwrappedLine(); ++Line->Level; @@ -840,7 +841,7 @@ void UnwrappedLineParser::parsePPUnknown() { do { nextToken(); } while (!eof()); - if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash) + if (Style.IndentPPDirectives != FormatStyle::PPDIS_None) Line->Level += PPBranchLevel + 1; addUnwrappedLine(); } @@ -2671,6 +2672,9 @@ void UnwrappedLineParser::readToken(int LevelDifference) { // 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(); } diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 23ea8a8d8e..eaf818c16c 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -2993,22 +2993,25 @@ TEST_F(FormatTest, IndentPreprocessorDirectives) { 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" @@ -3018,6 +3021,102 @@ TEST_F(FormatTest, IndentPreprocessorDirectives) { " 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) {