From 221c2b68ddc6efc97739ab8ab8e41f1a086fef6c Mon Sep 17 00:00:00 2001 From: owenca Date: Wed, 20 Apr 2022 23:53:17 -0700 Subject: [PATCH] [clang-format] Fix a crash on AllowShortFunctionsOnASingleLine Fixes #55008. Differential Revision: https://reviews.llvm.org/D124152 --- clang/lib/Format/TokenAnnotator.h | 4 ++++ clang/lib/Format/UnwrappedLineFormatter.cpp | 18 ++++++++++-------- clang/unittests/Format/FormatTest.cpp | 8 ++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h index 96e0396..3da68a1 100644 --- a/clang/lib/Format/TokenAnnotator.h +++ b/clang/lib/Format/TokenAnnotator.h @@ -76,6 +76,10 @@ public: } } + bool isComment() const { + return First && First->is(tok::comment) && !First->getNextNonComment(); + } + /// \c true if this line starts with the given tokens in order, ignoring /// comments. template bool startsWith(Ts... Tokens) const { diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 6137cdf..30755ef 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -306,24 +306,26 @@ private: // TODO: Use IndentTracker to avoid loop? // Find the last line with lower level. - auto J = I - 1; - if (!TheLine->InPPDirective) { - for (; J != AnnotatedLines.begin(); --J) { - if (!(*J)->InPPDirective && (*J)->Level < TheLine->Level) - break; + const AnnotatedLine *Line = nullptr; + for (auto J = I - 1; J >= AnnotatedLines.begin(); --J) { + assert(*J); + if (!(*J)->InPPDirective && !(*J)->isComment() && + (*J)->Level < TheLine->Level) { + Line = *J; + break; } } - if ((*J)->Level >= TheLine->Level) + if (!Line) return false; // Check if the found line starts a record. - const FormatToken *LastNonComment = (*J)->Last; + const FormatToken *LastNonComment = Line->Last; assert(LastNonComment); if (LastNonComment->is(tok::comment)) { LastNonComment = LastNonComment->getPreviousNonComment(); // There must be another token (usually `{`), because we chose a - // line that has a smaller level. + // non-PPDirective and non-comment line that has a smaller level. assert(LastNonComment); } return isRecordLBrace(*LastNonComment); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index d727ef2..a805f8e 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -12773,6 +12773,14 @@ TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) { "};", MergeInlineOnly); + verifyFormat("struct S {\n" + "// comment\n" + "#ifdef FOO\n" + " int foo() { bar(); }\n" + "#endif\n" + "};", + MergeInlineOnly); + // Also verify behavior when BraceWrapping.AfterFunction = true MergeInlineOnly.BreakBeforeBraces = FormatStyle::BS_Custom; MergeInlineOnly.BraceWrapping.AfterFunction = true; -- 2.7.4