From: Krasimir Georgiev Date: Wed, 12 Jul 2017 15:21:43 +0000 (+0000) Subject: [clang-format] Keep level of comment before an empty line X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=059cc9230ce3d0c64b94b96723ed47ed2a53042e;p=clang [clang-format] Keep level of comment before an empty line Summary: This patch fixes bug https://bugs.llvm.org/show_bug.cgi?id=3313: a comment line was aligned with the next #ifdef even in the presence of an empty line between them. Reviewers: djasper, klimek Reviewed By: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D35296 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@307795 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index b4d20a7bd6..c6e90a9175 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -1694,17 +1694,26 @@ void TokenAnnotator::setCommentLineLevels( for (SmallVectorImpl::reverse_iterator I = Lines.rbegin(), E = Lines.rend(); I != E; ++I) { - bool CommentLine = (*I)->First; + bool CommentLine = true; for (const FormatToken *Tok = (*I)->First; Tok; Tok = Tok->Next) { if (!Tok->is(tok::comment)) { CommentLine = false; break; } } - if (NextNonCommentLine && CommentLine) - (*I)->Level = NextNonCommentLine->Level; - else + + if (NextNonCommentLine && CommentLine) { + // If the comment is currently aligned with the line immediately following + // it, that's probably intentional and we should keep it. + bool AlignedWithNextLine = + NextNonCommentLine->First->NewlinesBefore <= 1 && + NextNonCommentLine->First->OriginalColumn == + (*I)->First->OriginalColumn; + if (AlignedWithNextLine) + (*I)->Level = NextNonCommentLine->Level; + } else { NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr; + } setCommentLineLevels((*I)->Children); } diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index b5f959f9c1..937362f5c9 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -825,12 +825,35 @@ TEST_F(FormatTest, FormatsSwitchStatement) { " case A:\n" " f();\n" " break;\n" - " // On B:\n" + " // fallthrough\n" " case B:\n" " g();\n" " break;\n" " }\n" "});"); + EXPECT_EQ("DEBUG({\n" + " switch (x) {\n" + " case A:\n" + " f();\n" + " break;\n" + " // On B:\n" + " case B:\n" + " g();\n" + " break;\n" + " }\n" + "});", + format("DEBUG({\n" + " switch (x) {\n" + " case A:\n" + " f();\n" + " break;\n" + " // On B:\n" + " case B:\n" + " g();\n" + " break;\n" + " }\n" + "});", + getLLVMStyle())); verifyFormat("switch (a) {\n" "case (b):\n" " return;\n" diff --git a/unittests/Format/FormatTestComments.cpp b/unittests/Format/FormatTestComments.cpp index fdb5a08e7a..7916e65e51 100644 --- a/unittests/Format/FormatTestComments.cpp +++ b/unittests/Format/FormatTestComments.cpp @@ -805,6 +805,70 @@ TEST_F(FormatTestComments, ParsesCommentsAdjacentToPPDirectives) { format("namespace {}\n /* Test */ #define A")); } +TEST_F(FormatTestComments, KeepsLevelOfCommentBeforePPDirective) { + // Keep the current level if the comment was originally not aligned with + // the preprocessor directive. + EXPECT_EQ("void f() {\n" + " int i;\n" + " /* comment */\n" + "#ifdef A\n" + " int j;\n" + "}", + format("void f() {\n" + " int i;\n" + " /* comment */\n" + "#ifdef A\n" + " int j;\n" + "}")); + + EXPECT_EQ("void f() {\n" + " int i;\n" + " /* comment */\n" + "\n" + "#ifdef A\n" + " int j;\n" + "}", + format("void f() {\n" + " int i;\n" + " /* comment */\n" + "\n" + "#ifdef A\n" + " int j;\n" + "}")); + + // Keep the current level if there is an empty line between the comment and + // the preprocessor directive. + EXPECT_EQ("void f() {\n" + " int i;\n" + " /* comment */\n" + "\n" + "#ifdef A\n" + " int j;\n" + "}", + format("void f() {\n" + " int i;\n" + "/* comment */\n" + "\n" + "#ifdef A\n" + " int j;\n" + "}")); + + // Align with the preprocessor directive if the comment was originally aligned + // with the preprocessor directive. + EXPECT_EQ("void f() {\n" + " int i;\n" + "/* comment */\n" + "#ifdef A\n" + " int j;\n" + "}", + format("void f() {\n" + " int i;\n" + "/* comment */\n" + "#ifdef A\n" + " int j;\n" + "}")); +} + TEST_F(FormatTestComments, SplitsLongLinesInComments) { EXPECT_EQ("/* This is a long\n" " * comment that\n"