diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -95,6 +95,7 @@ bool parseLevel(bool HasOpeningBrace, bool CanContainBracedList, IfStmtKind *IfKind = nullptr, TokenType NextLBracesType = TT_Unknown); + bool mightFitOnOneLine(UnwrappedLine &Line) const; IfStmtKind parseBlock(bool MustBeDeclaration = false, unsigned AddLevels = 1u, bool MunchSemi = true, bool UnindentWhitesmithsBraces = false, 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 @@ -14,6 +14,7 @@ #include "UnwrappedLineParser.h" #include "FormatToken.h" +#include "TokenAnnotator.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -460,6 +461,7 @@ return Previous && Previous->is(tok::comment) && (Previous->IsMultiline || Previous->NewlinesBefore > 0); } + /// \brief Parses a level, that is ???. /// \param HasOpeningBrace If that level is started by an opening brace. /// \param CanContainBracedList If the content can contain (at any level) a @@ -751,6 +753,50 @@ return h; } +// Checks whether \p ParsedLine might fit on a single line. We must clone the +// tokens of \p ParsedLine before running the token annotator on it so that we +// can restore them afterward. +bool UnwrappedLineParser::mightFitOnOneLine(UnwrappedLine &ParsedLine) const { + const auto ColumnLimit = Style.ColumnLimit; + if (ColumnLimit == 0) + return true; + + auto &Tokens = ParsedLine.Tokens; + assert(!Tokens.empty()); + const auto *LastToken = Tokens.back().Tok; + assert(LastToken); + + SmallVector SavedTokens(Tokens.size()); + + int Index = 0; + for (const auto &Token : Tokens) { + assert(Token.Tok); + auto &SavedToken = SavedTokens[Index++]; + SavedToken.Tok = new FormatToken; + SavedToken.Tok->copyFrom(*Token.Tok); + SavedToken.Children = std::move(Token.Children); + } + + AnnotatedLine Line(ParsedLine); + assert(Line.Last == LastToken); + + TokenAnnotator Annotator(Style, Keywords); + Annotator.annotate(Line); + Annotator.calculateFormattingInformation(Line); + + const int Length = LastToken->TotalLength; + + Index = 0; + for (auto &Token : Tokens) { + const auto &SavedToken = SavedTokens[Index++]; + Token.Tok->copyFrom(*SavedToken.Tok); + Token.Children = std::move(SavedToken.Children); + delete SavedToken.Tok; + } + + return Line.Level * Style.IndentWidth + Length <= ColumnLimit; +} + UnwrappedLineParser::IfStmtKind UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, bool MunchSemi, bool UnindentWhitesmithsBraces, @@ -813,8 +859,11 @@ const FormatToken *Previous = Tokens->getPreviousToken(); assert(Previous); if (Previous->isNot(tok::r_brace) || Previous->Optional) { - Tok->MatchingParen = FormatTok; - FormatTok->MatchingParen = Tok; + assert(!CurrentLines->empty()); + if (mightFitOnOneLine(CurrentLines->back())) { + Tok->MatchingParen = FormatTok; + FormatTok->MatchingParen = Tok; + } } } 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 @@ -25365,8 +25365,6 @@ "}", Style); - // FIXME: See https://github.com/llvm/llvm-project/issues/53543. -#if 0 Style.ColumnLimit = 65; verifyFormat("if (condition) {\n" @@ -25380,6 +25378,15 @@ Style.ColumnLimit = 20; + verifyFormat("int ab = [](int i) {\n" + " if (i > 0) {\n" + " i = 12345678 -\n" + " i;\n" + " }\n" + " return i;\n" + "};", + Style); + verifyFormat("if (a) {\n" " b = c + // 1 -\n" " d;\n" @@ -25394,9 +25401,6 @@ " b = c >= 0 ? d : e;\n" "}", Style); -#endif - - Style.ColumnLimit = 20; verifyFormat("if (a)\n" " b = c > 0 ? d : e;",