diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -180,6 +180,12 @@ /// before the token. bool MustBreakBefore = false; + /// Whether to not align across this token + /// + /// This happens for example when a preprocessor directive ended directly + /// before the token, but very rarely otherwise. + bool MustBreakAlignBefore = false; + /// The raw text of the token. /// /// Contains the raw token text without leading whitespace and without leading diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2959,6 +2959,7 @@ } FormatTok = Tokens->getNextToken(); FormatTok->MustBreakBefore = true; + FormatTok->MustBreakAlignBefore = true; } if (!PPStack.empty() && (PPStack.back().Kind == PP_Unreachable) && @@ -2983,6 +2984,7 @@ Line->Tokens.push_back(UnwrappedLineNode(Tok)); if (MustBreakBeforeNextToken) { Line->Tokens.back().Tok->MustBreakBefore = true; + Line->Tokens.back().Tok->MustBreakAlignBefore = true; MustBreakBeforeNextToken = false; } } diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -377,9 +377,11 @@ if (Changes[i].NewlinesBefore != 0) { CommasBeforeMatch = 0; EndOfSequence = i; - // If there is a blank line, or if the last line didn't contain any - // matching token, the sequence ends here. - if (Changes[i].NewlinesBefore > 1 || !FoundMatchOnLine) + // If there is a blank line, there is a forced-align-break (eg, + // preprocessor), or if the last line didn't contain any matching token, + // the sequence ends here. + if (Changes[i].NewlinesBefore > 1 || + Changes[i].Tok->MustBreakAlignBefore || !FoundMatchOnLine) AlignCurrentSequence(); FoundMatchOnLine = false; @@ -618,6 +620,8 @@ if (Changes[i].StartOfBlockComment) continue; Newlines += Changes[i].NewlinesBefore; + if (Changes[i].Tok->MustBreakAlignBefore) + BreakBeforeNext = true; if (!Changes[i].IsTrailingComment) continue; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -11429,6 +11429,29 @@ verifyFormat("int oneTwoThree = 123; // comment\n" "int oneTwo = 12; // comment", Alignment); + + // Bug 25167 + verifyFormat("#if A\n" + "#else\n" + "int aaaaaaaa = 12;\n" + "#endif\n" + "#if B\n" + "#else\n" + "int a = 12;\n" + "#endif\n", + Alignment); + verifyFormat("enum foo {\n" + "#if A\n" + "#else\n" + " aaaaaaaa = 12;\n" + "#endif\n" + "#if B\n" + "#else\n" + " a = 12;\n" + "#endif\n" + "};\n", + Alignment); + EXPECT_EQ("int a = 5;\n" "\n" "int oneTwoThree = 123;", diff --git a/clang/unittests/Format/FormatTestComments.cpp b/clang/unittests/Format/FormatTestComments.cpp --- a/clang/unittests/Format/FormatTestComments.cpp +++ b/clang/unittests/Format/FormatTestComments.cpp @@ -2780,6 +2780,27 @@ " // line 2 about b\n" " long b;", getLLVMStyleWithColumns(80))); + + // Checks an edge case in preprocessor handling. + // These comments should *not* be aligned + EXPECT_EQ( + "#if FOO\n" + "#else\n" + "long a; // Line about a\n" + "#endif\n" + "#if BAR\n" + "#else\n" + "long b_long_name; // Line about b\n" + "#endif\n", + format("#if FOO\n" + "#else\n" + "long a; // Line about a\n" // Previous (bad) behavior + "#endif\n" + "#if BAR\n" + "#else\n" + "long b_long_name; // Line about b\n" + "#endif\n", + getLLVMStyleWithColumns(80))); } TEST_F(FormatTestComments, AlignsBlockCommentDecorations) {