10df50938SDaniel Jasper //===--- UnwrappedLineFormatter.cpp - Format C++ code ---------------------===//
20df50938SDaniel Jasper //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60df50938SDaniel Jasper //
70df50938SDaniel Jasper //===----------------------------------------------------------------------===//
80df50938SDaniel Jasper 
90df50938SDaniel Jasper #include "UnwrappedLineFormatter.h"
105bcf99b4SPaul Hoad #include "NamespaceEndCommentsFixer.h"
110df50938SDaniel Jasper #include "WhitespaceManager.h"
120df50938SDaniel Jasper #include "llvm/Support/Debug.h"
139670f847SMehdi Amini #include <queue>
140df50938SDaniel Jasper 
150df50938SDaniel Jasper #define DEBUG_TYPE "format-formatter"
160df50938SDaniel Jasper 
170df50938SDaniel Jasper namespace clang {
180df50938SDaniel Jasper namespace format {
190df50938SDaniel Jasper 
200df50938SDaniel Jasper namespace {
210df50938SDaniel Jasper 
startsExternCBlock(const AnnotatedLine & Line)220df50938SDaniel Jasper bool startsExternCBlock(const AnnotatedLine &Line) {
230df50938SDaniel Jasper   const FormatToken *Next = Line.First->getNextNonComment();
240df50938SDaniel Jasper   const FormatToken *NextNext = Next ? Next->getNextNonComment() : nullptr;
25e285b8ddSDaniel Jasper   return Line.startsWith(tok::kw_extern) && Next && Next->isStringLiteral() &&
260df50938SDaniel Jasper          NextNext && NextNext->is(tok::l_brace);
270df50938SDaniel Jasper }
280df50938SDaniel Jasper 
isRecordLBrace(const FormatToken & Tok)29d81f003cSMarek Kurdej bool isRecordLBrace(const FormatToken &Tok) {
30d81f003cSMarek Kurdej   return Tok.isOneOf(TT_ClassLBrace, TT_EnumLBrace, TT_RecordLBrace,
31d81f003cSMarek Kurdej                      TT_StructLBrace, TT_UnionLBrace);
32d81f003cSMarek Kurdej }
33d81f003cSMarek Kurdej 
349fc8faf9SAdrian Prantl /// Tracks the indent level of \c AnnotatedLines across levels.
353d3ea84aSManuel Klimek ///
363d3ea84aSManuel Klimek /// \c nextLine must be called for each \c AnnotatedLine, after which \c
373d3ea84aSManuel Klimek /// getIndent() will return the indent for the last line \c nextLine was called
383d3ea84aSManuel Klimek /// with.
393d3ea84aSManuel Klimek /// If the line is not formatted (and thus the indent does not change), calling
403d3ea84aSManuel Klimek /// \c adjustToUnmodifiedLine after the call to \c nextLine will cause
413d3ea84aSManuel Klimek /// subsequent lines on the same level to be indented at the same level as the
423d3ea84aSManuel Klimek /// given line.
433d3ea84aSManuel Klimek class LevelIndentTracker {
443d3ea84aSManuel Klimek public:
LevelIndentTracker(const FormatStyle & Style,const AdditionalKeywords & Keywords,unsigned StartLevel,int AdditionalIndent)453d3ea84aSManuel Klimek   LevelIndentTracker(const FormatStyle &Style,
463d3ea84aSManuel Klimek                      const AdditionalKeywords &Keywords, unsigned StartLevel,
473d3ea84aSManuel Klimek                      int AdditionalIndent)
485fc133e7SDaniel Jasper       : Style(Style), Keywords(Keywords), AdditionalIndent(AdditionalIndent) {
493d3ea84aSManuel Klimek     for (unsigned i = 0; i != StartLevel; ++i)
503d3ea84aSManuel Klimek       IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
513d3ea84aSManuel Klimek   }
523d3ea84aSManuel Klimek 
539fc8faf9SAdrian Prantl   /// Returns the indent for the current line.
getIndent() const543d3ea84aSManuel Klimek   unsigned getIndent() const { return Indent; }
553d3ea84aSManuel Klimek 
569fc8faf9SAdrian Prantl   /// Update the indent state given that \p Line is going to be formatted
573d3ea84aSManuel Klimek   /// next.
nextLine(const AnnotatedLine & Line)583d3ea84aSManuel Klimek   void nextLine(const AnnotatedLine &Line) {
593d3ea84aSManuel Klimek     Offset = getIndentOffset(*Line.First);
60f0c95b32SManuel Klimek     // Update the indent level cache size so that we can rely on it
61f0c95b32SManuel Klimek     // having the right size in adjustToUnmodifiedline.
62c84d29acSowenca     skipLine(Line, /*UnknownIndent=*/true);
633d3ea84aSManuel Klimek     if (Line.InPPDirective) {
646f605b8dSGerhard Gappmeier       unsigned IndentWidth =
656f605b8dSGerhard Gappmeier           (Style.PPIndentWidth >= 0) ? Style.PPIndentWidth : Style.IndentWidth;
666f605b8dSGerhard Gappmeier       Indent = Line.Level * IndentWidth + AdditionalIndent;
673d3ea84aSManuel Klimek     } else {
686e867890SBjörn Schäpers       Indent = getIndent(Line.Level);
693d3ea84aSManuel Klimek     }
703d3ea84aSManuel Klimek     if (static_cast<int>(Indent) + Offset >= 0)
713d3ea84aSManuel Klimek       Indent += Offset;
72dcbcec48SJonathan Coe     if (Line.First->is(TT_CSharpGenericTypeConstraint))
73dcbcec48SJonathan Coe       Indent = Line.Level * Style.IndentWidth + Style.ContinuationIndentWidth;
743d3ea84aSManuel Klimek   }
753d3ea84aSManuel Klimek 
769fc8faf9SAdrian Prantl   /// Update the indent state given that \p Line indent should be
77e56a829eSFrancois Ferrand   /// skipped.
skipLine(const AnnotatedLine & Line,bool UnknownIndent=false)78c84d29acSowenca   void skipLine(const AnnotatedLine &Line, bool UnknownIndent = false) {
79c84d29acSowenca     if (Line.Level >= IndentForLevel.size())
80c84d29acSowenca       IndentForLevel.resize(Line.Level + 1, UnknownIndent ? -1 : Indent);
81e56a829eSFrancois Ferrand   }
82e56a829eSFrancois Ferrand 
839fc8faf9SAdrian Prantl   /// Update the level indent to adapt to the given \p Line.
843d3ea84aSManuel Klimek   ///
853d3ea84aSManuel Klimek   /// When a line is not formatted, we move the subsequent lines on the same
863d3ea84aSManuel Klimek   /// level to the same indent.
873d3ea84aSManuel Klimek   /// Note that \c nextLine must have been called before this method.
adjustToUnmodifiedLine(const AnnotatedLine & Line)883d3ea84aSManuel Klimek   void adjustToUnmodifiedLine(const AnnotatedLine &Line) {
893d3ea84aSManuel Klimek     unsigned LevelIndent = Line.First->OriginalColumn;
903d3ea84aSManuel Klimek     if (static_cast<int>(LevelIndent) - Offset >= 0)
913d3ea84aSManuel Klimek       LevelIndent -= Offset;
9214c30c70SMarek Kurdej     assert(Line.Level < IndentForLevel.size());
93e285b8ddSDaniel Jasper     if ((!Line.First->is(tok::comment) || IndentForLevel[Line.Level] == -1) &&
94bebf7bdfSowenca         !Line.InPPDirective) {
953d3ea84aSManuel Klimek       IndentForLevel[Line.Level] = LevelIndent;
963d3ea84aSManuel Klimek     }
97bebf7bdfSowenca   }
983d3ea84aSManuel Klimek 
993d3ea84aSManuel Klimek private:
1009fc8faf9SAdrian Prantl   /// Get the offset of the line relatively to the level.
1013d3ea84aSManuel Klimek   ///
1023d3ea84aSManuel Klimek   /// For example, 'public:' labels in classes are offset by 1 or 2
1033d3ea84aSManuel Klimek   /// characters to the left from their level.
getIndentOffset(const FormatToken & RootToken)1043d3ea84aSManuel Klimek   int getIndentOffset(const FormatToken &RootToken) {
105142e79b8Smydeveloperday     if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() ||
106bebf7bdfSowenca         Style.isCSharp()) {
1073d3ea84aSManuel Klimek       return 0;
108bebf7bdfSowenca     }
109d1aed486SPhilip Sigillito 
110d1aed486SPhilip Sigillito     auto IsAccessModifier = [this, &RootToken]() {
111bebf7bdfSowenca       if (RootToken.isAccessSpecifier(Style.isCpp())) {
112d1aed486SPhilip Sigillito         return true;
113bebf7bdfSowenca       } else if (RootToken.isObjCAccessSpecifier()) {
114d1aed486SPhilip Sigillito         return true;
115bebf7bdfSowenca       }
116d1aed486SPhilip Sigillito       // Handle Qt signals.
117d1aed486SPhilip Sigillito       else if ((RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) &&
118bebf7bdfSowenca                 RootToken.Next && RootToken.Next->is(tok::colon))) {
119d1aed486SPhilip Sigillito         return true;
120bebf7bdfSowenca       } else if (RootToken.Next &&
121bebf7bdfSowenca                  RootToken.Next->isOneOf(Keywords.kw_slots,
122bebf7bdfSowenca                                          Keywords.kw_qslots) &&
123bebf7bdfSowenca                  RootToken.Next->Next && RootToken.Next->Next->is(tok::colon)) {
124d1aed486SPhilip Sigillito         return true;
125bebf7bdfSowenca       }
126d1aed486SPhilip Sigillito       // Handle malformed access specifier e.g. 'private' without trailing ':'.
127bebf7bdfSowenca       else if (!RootToken.Next && RootToken.isAccessSpecifier(false)) {
128d1aed486SPhilip Sigillito         return true;
129bebf7bdfSowenca       }
130d1aed486SPhilip Sigillito       return false;
131d1aed486SPhilip Sigillito     };
132d1aed486SPhilip Sigillito 
133d1aed486SPhilip Sigillito     if (IsAccessModifier()) {
134f1191705SNico Weber       // The AccessModifierOffset may be overridden by IndentAccessModifiers,
1352a42c759SJakub Budiský       // in which case we take a negative value of the IndentWidth to simulate
1362a42c759SJakub Budiský       // the upper indent level.
1372a42c759SJakub Budiský       return Style.IndentAccessModifiers ? -Style.IndentWidth
1382a42c759SJakub Budiský                                          : Style.AccessModifierOffset;
1392a42c759SJakub Budiský     }
1403d3ea84aSManuel Klimek     return 0;
1413d3ea84aSManuel Klimek   }
1423d3ea84aSManuel Klimek 
1439fc8faf9SAdrian Prantl   /// Get the indent of \p Level from \p IndentForLevel.
1443d3ea84aSManuel Klimek   ///
1453d3ea84aSManuel Klimek   /// \p IndentForLevel must contain the indent for the level \c l
1463d3ea84aSManuel Klimek   /// at \p IndentForLevel[l], or a value < 0 if the indent for
1473d3ea84aSManuel Klimek   /// that level is unknown.
getIndent(unsigned Level) const1486e867890SBjörn Schäpers   unsigned getIndent(unsigned Level) const {
1493d3ea84aSManuel Klimek     if (IndentForLevel[Level] != -1)
1503d3ea84aSManuel Klimek       return IndentForLevel[Level];
1513d3ea84aSManuel Klimek     if (Level == 0)
1523d3ea84aSManuel Klimek       return 0;
1536e867890SBjörn Schäpers     return getIndent(Level - 1) + Style.IndentWidth;
1543d3ea84aSManuel Klimek   }
1553d3ea84aSManuel Klimek 
1563d3ea84aSManuel Klimek   const FormatStyle &Style;
1573d3ea84aSManuel Klimek   const AdditionalKeywords &Keywords;
15856807c19SDaniel Jasper   const unsigned AdditionalIndent;
1595fc133e7SDaniel Jasper 
1609fc8faf9SAdrian Prantl   /// The indent in characters for each level.
161c84d29acSowenca   SmallVector<int> IndentForLevel;
1623d3ea84aSManuel Klimek 
1639fc8faf9SAdrian Prantl   /// Offset of the current line relative to the indent level.
1643d3ea84aSManuel Klimek   ///
1653d3ea84aSManuel Klimek   /// For example, the 'public' keywords is often indented with a negative
1663d3ea84aSManuel Klimek   /// offset.
1673d3ea84aSManuel Klimek   int Offset = 0;
1683d3ea84aSManuel Klimek 
1699fc8faf9SAdrian Prantl   /// The current line's indent.
1703d3ea84aSManuel Klimek   unsigned Indent = 0;
1713d3ea84aSManuel Klimek };
1723d3ea84aSManuel Klimek 
getMatchingNamespaceToken(const AnnotatedLine * Line,const SmallVectorImpl<AnnotatedLine * > & AnnotatedLines)173e8a301f8SFrancois Ferrand const FormatToken *getMatchingNamespaceToken(
174e8a301f8SFrancois Ferrand     const AnnotatedLine *Line,
175e56a829eSFrancois Ferrand     const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
176e56a829eSFrancois Ferrand   if (!Line->startsWith(tok::r_brace))
177e8a301f8SFrancois Ferrand     return nullptr;
178e56a829eSFrancois Ferrand   size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex;
179e56a829eSFrancois Ferrand   if (StartLineIndex == UnwrappedLine::kInvalidIndex)
180e8a301f8SFrancois Ferrand     return nullptr;
181e56a829eSFrancois Ferrand   assert(StartLineIndex < AnnotatedLines.size());
182e8a301f8SFrancois Ferrand   return AnnotatedLines[StartLineIndex]->First->getNamespaceToken();
183e8a301f8SFrancois Ferrand }
184e8a301f8SFrancois Ferrand 
getNamespaceTokenText(const AnnotatedLine * Line)185e8a301f8SFrancois Ferrand StringRef getNamespaceTokenText(const AnnotatedLine *Line) {
186e8a301f8SFrancois Ferrand   const FormatToken *NamespaceToken = Line->First->getNamespaceToken();
187e8a301f8SFrancois Ferrand   return NamespaceToken ? NamespaceToken->TokenText : StringRef();
188e8a301f8SFrancois Ferrand }
189e8a301f8SFrancois Ferrand 
getMatchingNamespaceTokenText(const AnnotatedLine * Line,const SmallVectorImpl<AnnotatedLine * > & AnnotatedLines)190e8a301f8SFrancois Ferrand StringRef getMatchingNamespaceTokenText(
191e8a301f8SFrancois Ferrand     const AnnotatedLine *Line,
192e8a301f8SFrancois Ferrand     const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
193e8a301f8SFrancois Ferrand   const FormatToken *NamespaceToken =
194e8a301f8SFrancois Ferrand       getMatchingNamespaceToken(Line, AnnotatedLines);
195e8a301f8SFrancois Ferrand   return NamespaceToken ? NamespaceToken->TokenText : StringRef();
196e56a829eSFrancois Ferrand }
197e56a829eSFrancois Ferrand 
1980df50938SDaniel Jasper class LineJoiner {
1990df50938SDaniel Jasper public:
LineJoiner(const FormatStyle & Style,const AdditionalKeywords & Keywords,const SmallVectorImpl<AnnotatedLine * > & Lines)2003d3ea84aSManuel Klimek   LineJoiner(const FormatStyle &Style, const AdditionalKeywords &Keywords,
2013d3ea84aSManuel Klimek              const SmallVectorImpl<AnnotatedLine *> &Lines)
202e56a829eSFrancois Ferrand       : Style(Style), Keywords(Keywords), End(Lines.end()), Next(Lines.begin()),
203e56a829eSFrancois Ferrand         AnnotatedLines(Lines) {}
2040df50938SDaniel Jasper 
2059fc8faf9SAdrian Prantl   /// Returns the next line, merging multiple lines into one if possible.
getNextMergedLine(bool DryRun,LevelIndentTracker & IndentTracker)2063d3ea84aSManuel Klimek   const AnnotatedLine *getNextMergedLine(bool DryRun,
2073d3ea84aSManuel Klimek                                          LevelIndentTracker &IndentTracker) {
2083d3ea84aSManuel Klimek     if (Next == End)
2093d3ea84aSManuel Klimek       return nullptr;
2103d3ea84aSManuel Klimek     const AnnotatedLine *Current = *Next;
2113d3ea84aSManuel Klimek     IndentTracker.nextLine(*Current);
21289628f64SManuel Klimek     unsigned MergedLines = tryFitMultipleLinesInOne(IndentTracker, Next, End);
213bebf7bdfSowenca     if (MergedLines > 0 && Style.ColumnLimit == 0) {
2143d3ea84aSManuel Klimek       // Disallow line merging if there is a break at the start of one of the
2153d3ea84aSManuel Klimek       // input lines.
2163d3ea84aSManuel Klimek       for (unsigned i = 0; i < MergedLines; ++i)
2173d3ea84aSManuel Klimek         if (Next[i + 1]->First->NewlinesBefore > 0)
2183d3ea84aSManuel Klimek           MergedLines = 0;
219bebf7bdfSowenca     }
2203d3ea84aSManuel Klimek     if (!DryRun)
2213d3ea84aSManuel Klimek       for (unsigned i = 0; i < MergedLines; ++i)
2221991e5d6SCameron Desrochers         join(*Next[0], *Next[i + 1]);
2233d3ea84aSManuel Klimek     Next = Next + MergedLines + 1;
2243d3ea84aSManuel Klimek     return Current;
2253d3ea84aSManuel Klimek   }
2263d3ea84aSManuel Klimek 
2273d3ea84aSManuel Klimek private:
2289fc8faf9SAdrian Prantl   /// Calculates how many lines can be merged into 1 starting at \p I.
2290df50938SDaniel Jasper   unsigned
tryFitMultipleLinesInOne(LevelIndentTracker & IndentTracker,SmallVectorImpl<AnnotatedLine * >::const_iterator I,SmallVectorImpl<AnnotatedLine * >::const_iterator E)230e56a829eSFrancois Ferrand   tryFitMultipleLinesInOne(LevelIndentTracker &IndentTracker,
2310df50938SDaniel Jasper                            SmallVectorImpl<AnnotatedLine *>::const_iterator I,
2320df50938SDaniel Jasper                            SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
233e56a829eSFrancois Ferrand     const unsigned Indent = IndentTracker.getIndent();
234e56a829eSFrancois Ferrand 
2359ecb0e96SDaniel Jasper     // Can't join the last line with anything.
2369ecb0e96SDaniel Jasper     if (I + 1 == E)
2379ecb0e96SDaniel Jasper       return 0;
2380df50938SDaniel Jasper     // We can never merge stuff if there are trailing line comments.
2390df50938SDaniel Jasper     const AnnotatedLine *TheLine = *I;
2400df50938SDaniel Jasper     if (TheLine->Last->is(TT_LineComment))
2410df50938SDaniel Jasper       return 0;
2423d0b6192SBjörn Schäpers     const auto &NextLine = *I[1];
2433d0b6192SBjörn Schäpers     if (NextLine.Type == LT_Invalid || NextLine.First->MustBreakBefore)
2449ecb0e96SDaniel Jasper       return 0;
2459ecb0e96SDaniel Jasper     if (TheLine->InPPDirective &&
246bebf7bdfSowenca         (!NextLine.InPPDirective || NextLine.First->HasUnescapedNewline)) {
2479ecb0e96SDaniel Jasper       return 0;
248bebf7bdfSowenca     }
2490df50938SDaniel Jasper 
2500df50938SDaniel Jasper     if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
2510df50938SDaniel Jasper       return 0;
2520df50938SDaniel Jasper 
2530df50938SDaniel Jasper     unsigned Limit =
2540df50938SDaniel Jasper         Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;
2550df50938SDaniel Jasper     // If we already exceed the column limit, we set 'Limit' to 0. The different
2560df50938SDaniel Jasper     // tryMerge..() functions can then decide whether to still do merging.
2570df50938SDaniel Jasper     Limit = TheLine->Last->TotalLength > Limit
2580df50938SDaniel Jasper                 ? 0
2590df50938SDaniel Jasper                 : Limit - TheLine->Last->TotalLength;
2600df50938SDaniel Jasper 
2612a81ca8dSFrancois Ferrand     if (TheLine->Last->is(TT_FunctionLBrace) &&
2622a81ca8dSFrancois Ferrand         TheLine->First == TheLine->Last &&
263ad72256dSFrancois Ferrand         !Style.BraceWrapping.SplitEmptyFunction &&
264bebf7bdfSowenca         NextLine.First->is(tok::r_brace)) {
2652a81ca8dSFrancois Ferrand       return tryMergeSimpleBlock(I, E, Limit);
266bebf7bdfSowenca     }
2672a81ca8dSFrancois Ferrand 
2683d0b6192SBjörn Schäpers     const auto *PreviousLine = I != AnnotatedLines.begin() ? I[-1] : nullptr;
2693d0b6192SBjörn Schäpers     // Handle empty record blocks where the brace has already been wrapped.
2703d0b6192SBjörn Schäpers     if (PreviousLine && TheLine->Last->is(tok::l_brace) &&
2713d0b6192SBjörn Schäpers         TheLine->First == TheLine->Last) {
2723d0b6192SBjörn Schäpers       bool EmptyBlock = NextLine.First->is(tok::r_brace);
273ad72256dSFrancois Ferrand 
2743d0b6192SBjörn Schäpers       const FormatToken *Tok = PreviousLine->First;
275ad72256dSFrancois Ferrand       if (Tok && Tok->is(tok::comment))
276ad72256dSFrancois Ferrand         Tok = Tok->getNextNonComment();
277ad72256dSFrancois Ferrand 
278bebf7bdfSowenca       if (Tok && Tok->getNamespaceToken()) {
279ad72256dSFrancois Ferrand         return !Style.BraceWrapping.SplitEmptyNamespace && EmptyBlock
28089628f64SManuel Klimek                    ? tryMergeSimpleBlock(I, E, Limit)
28189628f64SManuel Klimek                    : 0;
282bebf7bdfSowenca       }
283ad72256dSFrancois Ferrand 
284ad72256dSFrancois Ferrand       if (Tok && Tok->is(tok::kw_typedef))
285ad72256dSFrancois Ferrand         Tok = Tok->getNextNonComment();
286ad72256dSFrancois Ferrand       if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union,
287bebf7bdfSowenca                               tok::kw_extern, Keywords.kw_interface)) {
288ad72256dSFrancois Ferrand         return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock
289d6ce937fSKrasimir Georgiev                    ? tryMergeSimpleBlock(I, E, Limit)
290d6ce937fSKrasimir Georgiev                    : 0;
291bebf7bdfSowenca       }
29200dc97f1Smydeveloperday 
29300dc97f1Smydeveloperday       if (Tok && Tok->is(tok::kw_template) &&
294bebf7bdfSowenca           Style.BraceWrapping.SplitEmptyRecord && EmptyBlock) {
29500dc97f1Smydeveloperday         return 0;
29600dc97f1Smydeveloperday       }
297bebf7bdfSowenca     }
298ad72256dSFrancois Ferrand 
2993d0b6192SBjörn Schäpers     auto ShouldMergeShortFunctions = [this, &I, &NextLine, PreviousLine,
3003d0b6192SBjörn Schäpers                                       TheLine]() {
3017af11989SMarek Kurdej       if (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All)
3027af11989SMarek Kurdej         return true;
3033d0b6192SBjörn Schäpers       if (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
304bebf7bdfSowenca           NextLine.First->is(tok::r_brace)) {
3057af11989SMarek Kurdej         return true;
306bebf7bdfSowenca       }
3077af11989SMarek Kurdej 
3087af11989SMarek Kurdej       if (Style.AllowShortFunctionsOnASingleLine &
3097af11989SMarek Kurdej           FormatStyle::SFS_InlineOnly) {
3107af11989SMarek Kurdej         // Just checking TheLine->Level != 0 is not enough, because it
3117af11989SMarek Kurdej         // provokes treating functions inside indented namespaces as short.
3123d0b6192SBjörn Schäpers         if (Style.isJavaScript() && TheLine->Last->is(TT_FunctionLBrace))
31336622c4eSMarek Kurdej           return true;
31436622c4eSMarek Kurdej 
3153d0b6192SBjörn Schäpers         if (TheLine->Level != 0) {
3163d0b6192SBjörn Schäpers           if (!PreviousLine)
3177af11989SMarek Kurdej             return false;
3187af11989SMarek Kurdej 
3197af11989SMarek Kurdej           // TODO: Use IndentTracker to avoid loop?
3207af11989SMarek Kurdej           // Find the last line with lower level.
321221c2b68Sowenca           const AnnotatedLine *Line = nullptr;
322221c2b68Sowenca           for (auto J = I - 1; J >= AnnotatedLines.begin(); --J) {
323221c2b68Sowenca             assert(*J);
324221c2b68Sowenca             if (!(*J)->InPPDirective && !(*J)->isComment() &&
325221c2b68Sowenca                 (*J)->Level < TheLine->Level) {
326221c2b68Sowenca               Line = *J;
3277af11989SMarek Kurdej               break;
32819884d62SArthur Eubanks             }
32919884d62SArthur Eubanks           }
33019884d62SArthur Eubanks 
331221c2b68Sowenca           if (!Line)
332d03e3428SMarek Kurdej             return false;
3337af11989SMarek Kurdej 
3347af11989SMarek Kurdej           // Check if the found line starts a record.
335221c2b68Sowenca           const FormatToken *LastNonComment = Line->Last;
336ef39235cSMarek Kurdej           assert(LastNonComment);
337ef39235cSMarek Kurdej           if (LastNonComment->is(tok::comment)) {
338ef39235cSMarek Kurdej             LastNonComment = LastNonComment->getPreviousNonComment();
339ef39235cSMarek Kurdej             // There must be another token (usually `{`), because we chose a
340221c2b68Sowenca             // non-PPDirective and non-comment line that has a smaller level.
341ef39235cSMarek Kurdej             assert(LastNonComment);
342ef39235cSMarek Kurdej           }
343ef39235cSMarek Kurdej           return isRecordLBrace(*LastNonComment);
3447af11989SMarek Kurdej         }
3457af11989SMarek Kurdej       }
3467af11989SMarek Kurdej 
3477af11989SMarek Kurdej       return false;
3487af11989SMarek Kurdej     };
3497af11989SMarek Kurdej 
3503d0b6192SBjörn Schäpers     bool MergeShortFunctions = ShouldMergeShortFunctions();
3510df50938SDaniel Jasper 
3529cb94459SMarek Kurdej     const FormatToken *FirstNonComment = TheLine->First;
3539cb94459SMarek Kurdej     if (FirstNonComment->is(tok::comment)) {
3549cb94459SMarek Kurdej       FirstNonComment = FirstNonComment->getNextNonComment();
3559cb94459SMarek Kurdej       if (!FirstNonComment)
3569cb94459SMarek Kurdej         return 0;
3579cb94459SMarek Kurdej     }
3589cb94459SMarek Kurdej     // FIXME: There are probably cases where we should use FirstNonComment
3599cb94459SMarek Kurdej     // instead of TheLine->First.
3609cb94459SMarek Kurdej 
361e56a829eSFrancois Ferrand     if (Style.CompactNamespaces) {
362e8a301f8SFrancois Ferrand       if (auto nsToken = TheLine->First->getNamespaceToken()) {
363e56a829eSFrancois Ferrand         int i = 0;
3640dddcf78SManuel Klimek         unsigned closingLine = TheLine->MatchingClosingBlockLineIndex - 1;
365e8a301f8SFrancois Ferrand         for (; I + 1 + i != E &&
366e8a301f8SFrancois Ferrand                nsToken->TokenText == getNamespaceTokenText(I[i + 1]) &&
3670dddcf78SManuel Klimek                closingLine == I[i + 1]->MatchingClosingBlockLineIndex &&
368e56a829eSFrancois Ferrand                I[i + 1]->Last->TotalLength < Limit;
369574ad2a8SMarek Kurdej              i++, --closingLine) {
3703d0b6192SBjörn Schäpers           // No extra indent for compacted namespaces.
371e56a829eSFrancois Ferrand           IndentTracker.skipLine(*I[i + 1]);
372e56a829eSFrancois Ferrand 
373e56a829eSFrancois Ferrand           Limit -= I[i + 1]->Last->TotalLength;
374e56a829eSFrancois Ferrand         }
375e56a829eSFrancois Ferrand         return i;
376e56a829eSFrancois Ferrand       }
377e56a829eSFrancois Ferrand 
378e8a301f8SFrancois Ferrand       if (auto nsToken = getMatchingNamespaceToken(TheLine, AnnotatedLines)) {
379e56a829eSFrancois Ferrand         int i = 0;
380e56a829eSFrancois Ferrand         unsigned openingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
381e8a301f8SFrancois Ferrand         for (; I + 1 + i != E &&
382e8a301f8SFrancois Ferrand                nsToken->TokenText ==
383e8a301f8SFrancois Ferrand                    getMatchingNamespaceTokenText(I[i + 1], AnnotatedLines) &&
384e56a829eSFrancois Ferrand                openingLine == I[i + 1]->MatchingOpeningBlockLineIndex;
385574ad2a8SMarek Kurdej              i++, --openingLine) {
3863d0b6192SBjörn Schäpers           // No space between consecutive braces.
387e56a829eSFrancois Ferrand           I[i + 1]->First->SpacesRequiredBefore = !I[i]->Last->is(tok::r_brace);
388e56a829eSFrancois Ferrand 
3893d0b6192SBjörn Schäpers           // Indent like the outer-most namespace.
390e56a829eSFrancois Ferrand           IndentTracker.nextLine(*I[i + 1]);
391e56a829eSFrancois Ferrand         }
392e56a829eSFrancois Ferrand         return i;
393e56a829eSFrancois Ferrand       }
394e56a829eSFrancois Ferrand     }
395e56a829eSFrancois Ferrand 
3963d0b6192SBjörn Schäpers     // Try to merge a function block with left brace unwrapped.
397d079995dSMarek Kurdej     if (TheLine->Last->is(TT_FunctionLBrace) && TheLine->First != TheLine->Last)
3980df50938SDaniel Jasper       return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
3993d0b6192SBjörn Schäpers     // Try to merge a control statement block with left brace unwrapped.
4009cb94459SMarek Kurdej     if (TheLine->Last->is(tok::l_brace) && FirstNonComment != TheLine->Last &&
4019cb94459SMarek Kurdej         FirstNonComment->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for,
4021e512f02SMarek Kurdej                                  TT_ForEachMacro)) {
40310234da7SOwen Pan       return Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never
4040df50938SDaniel Jasper                  ? tryMergeSimpleBlock(I, E, Limit)
4050df50938SDaniel Jasper                  : 0;
4060df50938SDaniel Jasper     }
4073d0b6192SBjörn Schäpers     // Try to merge a control statement block with left brace wrapped.
4083d0b6192SBjörn Schäpers     if (NextLine.First->is(tok::l_brace)) {
4093d0b6192SBjörn Schäpers       if ((TheLine->First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while,
410813d486cSJesses Gott                                    tok::kw_for, tok::kw_switch, tok::kw_try,
411813d486cSJesses Gott                                    tok::kw_do, TT_ForEachMacro) ||
412fb13e65aSPaul Hoad            (TheLine->First->is(tok::r_brace) && TheLine->First->Next &&
413fb13e65aSPaul Hoad             TheLine->First->Next->isOneOf(tok::kw_else, tok::kw_catch))) &&
414fb13e65aSPaul Hoad           Style.BraceWrapping.AfterControlStatement ==
415fb13e65aSPaul Hoad               FormatStyle::BWACS_MultiLine) {
4163d0b6192SBjörn Schäpers         // If possible, merge the next line's wrapped left brace with the
4173d0b6192SBjörn Schäpers         // current line. Otherwise, leave it on the next line, as this is a
4183d0b6192SBjörn Schäpers         // multi-line control statement.
419f4d52cadSowenca         return (Style.ColumnLimit == 0 || TheLine->Level * Style.IndentWidth +
420f4d52cadSowenca                                                   TheLine->Last->TotalLength <=
421f4d52cadSowenca                                               Style.ColumnLimit)
422fb13e65aSPaul Hoad                    ? 1
423fb13e65aSPaul Hoad                    : 0;
4243d0b6192SBjörn Schäpers       }
4253d0b6192SBjörn Schäpers       if (TheLine->First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while,
4261e512f02SMarek Kurdej                                   tok::kw_for, TT_ForEachMacro)) {
427fb13e65aSPaul Hoad         return (Style.BraceWrapping.AfterControlStatement ==
428fb13e65aSPaul Hoad                 FormatStyle::BWACS_Always)
4293b0b50baSKrasimir Georgiev                    ? tryMergeSimpleBlock(I, E, Limit)
4303b0b50baSKrasimir Georgiev                    : 0;
4313d0b6192SBjörn Schäpers       }
4323d0b6192SBjörn Schäpers       if (TheLine->First->isOneOf(tok::kw_else, tok::kw_catch) &&
433d45aafa2SMitchell Balan           Style.BraceWrapping.AfterControlStatement ==
434d45aafa2SMitchell Balan               FormatStyle::BWACS_MultiLine) {
435d45aafa2SMitchell Balan         // This case if different from the upper BWACS_MultiLine processing
436d45aafa2SMitchell Balan         // in that a preceding r_brace is not on the same line as else/catch
437d45aafa2SMitchell Balan         // most likely because of BeforeElse/BeforeCatch set to true.
438d45aafa2SMitchell Balan         // If the line length doesn't fit ColumnLimit, leave l_brace on the
439d45aafa2SMitchell Balan         // next line to respect the BWACS_MultiLine.
440d45aafa2SMitchell Balan         return (Style.ColumnLimit == 0 ||
441d45aafa2SMitchell Balan                 TheLine->Last->TotalLength <= Style.ColumnLimit)
442d45aafa2SMitchell Balan                    ? 1
443d45aafa2SMitchell Balan                    : 0;
4443b0b50baSKrasimir Georgiev       }
4453d0b6192SBjörn Schäpers     }
4463d0b6192SBjörn Schäpers     if (PreviousLine && TheLine->First->is(tok::l_brace)) {
4473d0b6192SBjörn Schäpers       switch (PreviousLine->First->Tok.getKind()) {
4483d0b6192SBjörn Schäpers       case tok::at:
4493d0b6192SBjörn Schäpers         // Don't merge block with left brace wrapped after ObjC special blocks.
4503d0b6192SBjörn Schäpers         if (PreviousLine->First->Next) {
4513d0b6192SBjörn Schäpers           tok::ObjCKeywordKind kwId =
4523d0b6192SBjörn Schäpers               PreviousLine->First->Next->Tok.getObjCKeywordID();
4533d0b6192SBjörn Schäpers           if (kwId == tok::objc_autoreleasepool ||
454bebf7bdfSowenca               kwId == tok::objc_synchronized) {
455a2484b25SFrancois Ferrand             return 0;
456a2484b25SFrancois Ferrand           }
457bebf7bdfSowenca         }
4583d0b6192SBjörn Schäpers         break;
4593d0b6192SBjörn Schäpers 
4603d0b6192SBjörn Schäpers       case tok::kw_case:
4613d0b6192SBjörn Schäpers       case tok::kw_default:
4623d0b6192SBjörn Schäpers         // Don't merge block with left brace wrapped after case labels.
46358c3dee3SOwen Pan         return 0;
46400dc97f1Smydeveloperday 
4653d0b6192SBjörn Schäpers       default:
4663d0b6192SBjörn Schäpers         break;
4673d0b6192SBjörn Schäpers       }
4683d0b6192SBjörn Schäpers     }
4693d0b6192SBjörn Schäpers 
47000dc97f1Smydeveloperday     // Don't merge an empty template class or struct if SplitEmptyRecords
47100dc97f1Smydeveloperday     // is defined.
4723d0b6192SBjörn Schäpers     if (PreviousLine && Style.BraceWrapping.SplitEmptyRecord &&
4733d0b6192SBjörn Schäpers         TheLine->Last->is(tok::l_brace) && PreviousLine->Last) {
4743d0b6192SBjörn Schäpers       const FormatToken *Previous = PreviousLine->Last;
47500dc97f1Smydeveloperday       if (Previous) {
47600dc97f1Smydeveloperday         if (Previous->is(tok::comment))
47700dc97f1Smydeveloperday           Previous = Previous->getPreviousNonComment();
47800dc97f1Smydeveloperday         if (Previous) {
4793d0b6192SBjörn Schäpers           if (Previous->is(tok::greater) && !PreviousLine->InPPDirective)
48000dc97f1Smydeveloperday             return 0;
48100dc97f1Smydeveloperday           if (Previous->is(tok::identifier)) {
48200dc97f1Smydeveloperday             const FormatToken *PreviousPrevious =
48300dc97f1Smydeveloperday                 Previous->getPreviousNonComment();
48400dc97f1Smydeveloperday             if (PreviousPrevious &&
485bebf7bdfSowenca                 PreviousPrevious->isOneOf(tok::kw_class, tok::kw_struct)) {
48600dc97f1Smydeveloperday               return 0;
48700dc97f1Smydeveloperday             }
48800dc97f1Smydeveloperday           }
48900dc97f1Smydeveloperday         }
49000dc97f1Smydeveloperday       }
491bebf7bdfSowenca     }
49200dc97f1Smydeveloperday 
4933b0b50baSKrasimir Georgiev     if (TheLine->Last->is(tok::l_brace)) {
49407fe4513SMarek Kurdej       bool ShouldMerge = false;
495d81f003cSMarek Kurdej       // Try to merge records.
496d81f003cSMarek Kurdej       if (TheLine->Last->is(TT_EnumLBrace)) {
497d81f003cSMarek Kurdej         ShouldMerge = Style.AllowShortEnumsOnASingleLine;
498d81f003cSMarek Kurdej       } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace)) {
499d81f003cSMarek Kurdej         // NOTE: We use AfterClass (whereas AfterStruct exists) for both classes
500d81f003cSMarek Kurdej         // and structs, but it seems that wrapping is still handled correctly
501d81f003cSMarek Kurdej         // elsewhere.
50207fe4513SMarek Kurdej         ShouldMerge = !Style.BraceWrapping.AfterClass ||
5033d0b6192SBjörn Schäpers                       (NextLine.First->is(tok::r_brace) &&
50407fe4513SMarek Kurdej                        !Style.BraceWrapping.SplitEmptyRecord);
50507fe4513SMarek Kurdej       } else {
506d81f003cSMarek Kurdej         // Try to merge a block with left brace unwrapped that wasn't yet
507d81f003cSMarek Kurdej         // covered.
5080570af17SMarek Kurdej         assert(TheLine->InPPDirective ||
5090570af17SMarek Kurdej                !TheLine->First->isOneOf(tok::kw_class, tok::kw_enum,
510d81f003cSMarek Kurdej                                         tok::kw_struct));
51107fe4513SMarek Kurdej         ShouldMerge = !Style.BraceWrapping.AfterFunction ||
5123d0b6192SBjörn Schäpers                       (NextLine.First->is(tok::r_brace) &&
51307fe4513SMarek Kurdej                        !Style.BraceWrapping.SplitEmptyFunction);
51407fe4513SMarek Kurdej       }
51507fe4513SMarek Kurdej       return ShouldMerge ? tryMergeSimpleBlock(I, E, Limit) : 0;
5163b0b50baSKrasimir Georgiev     }
517d81f003cSMarek Kurdej 
5183d0b6192SBjörn Schäpers     // Try to merge a function block with left brace wrapped.
5193d0b6192SBjörn Schäpers     if (NextLine.First->is(TT_FunctionLBrace) &&
520c1bc38edSDaniel Jasper         Style.BraceWrapping.AfterFunction) {
5213d0b6192SBjörn Schäpers       if (NextLine.Last->is(TT_LineComment))
5220df50938SDaniel Jasper         return 0;
5230df50938SDaniel Jasper 
5240df50938SDaniel Jasper       // Check for Limit <= 2 to account for the " {".
5250df50938SDaniel Jasper       if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))
5260df50938SDaniel Jasper         return 0;
5270df50938SDaniel Jasper       Limit -= 2;
5280df50938SDaniel Jasper 
5290df50938SDaniel Jasper       unsigned MergedLines = 0;
5302a81ca8dSFrancois Ferrand       if (MergeShortFunctions ||
5312a81ca8dSFrancois Ferrand           (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
5323d0b6192SBjörn Schäpers            NextLine.First == NextLine.Last && I + 2 != E &&
5332a81ca8dSFrancois Ferrand            I[2]->First->is(tok::r_brace))) {
5340df50938SDaniel Jasper         MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
5350df50938SDaniel Jasper         // If we managed to merge the block, count the function header, which is
5360df50938SDaniel Jasper         // on a separate line.
5370df50938SDaniel Jasper         if (MergedLines > 0)
5380df50938SDaniel Jasper           ++MergedLines;
5390df50938SDaniel Jasper       }
5400df50938SDaniel Jasper       return MergedLines;
5410df50938SDaniel Jasper     }
54231751ce1SMarek Kurdej     auto IsElseLine = [&TheLine]() -> bool {
54331751ce1SMarek Kurdej       const FormatToken *First = TheLine->First;
5448d93d7ffSMarek Kurdej       if (First->is(tok::kw_else))
5458d93d7ffSMarek Kurdej         return true;
5468d93d7ffSMarek Kurdej 
5478d93d7ffSMarek Kurdej       return First->is(tok::r_brace) && First->Next &&
5488d93d7ffSMarek Kurdej              First->Next->is(tok::kw_else);
5498d93d7ffSMarek Kurdej     };
5508d93d7ffSMarek Kurdej     if (TheLine->First->is(tok::kw_if) ||
5518d93d7ffSMarek Kurdej         (IsElseLine() && (Style.AllowShortIfStatementsOnASingleLine ==
5528d93d7ffSMarek Kurdej                           FormatStyle::SIS_AllIfsAndElse))) {
5530df50938SDaniel Jasper       return Style.AllowShortIfStatementsOnASingleLine
5540df50938SDaniel Jasper                  ? tryMergeSimpleControlStatement(I, E, Limit)
5550df50938SDaniel Jasper                  : 0;
5560df50938SDaniel Jasper     }
5571e512f02SMarek Kurdej     if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while, tok::kw_do,
5581e512f02SMarek Kurdej                                 TT_ForEachMacro)) {
5590df50938SDaniel Jasper       return Style.AllowShortLoopsOnASingleLine
5600df50938SDaniel Jasper                  ? tryMergeSimpleControlStatement(I, E, Limit)
5610df50938SDaniel Jasper                  : 0;
5620df50938SDaniel Jasper     }
5630df50938SDaniel Jasper     if (TheLine->First->isOneOf(tok::kw_case, tok::kw_default)) {
5640df50938SDaniel Jasper       return Style.AllowShortCaseLabelsOnASingleLine
5650df50938SDaniel Jasper                  ? tryMergeShortCaseLabels(I, E, Limit)
5660df50938SDaniel Jasper                  : 0;
5670df50938SDaniel Jasper     }
5680df50938SDaniel Jasper     if (TheLine->InPPDirective &&
569bebf7bdfSowenca         (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {
5700df50938SDaniel Jasper       return tryMergeSimplePPDirective(I, E, Limit);
571bebf7bdfSowenca     }
5720df50938SDaniel Jasper     return 0;
5730df50938SDaniel Jasper   }
5740df50938SDaniel Jasper 
5750df50938SDaniel Jasper   unsigned
tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine * >::const_iterator I,SmallVectorImpl<AnnotatedLine * >::const_iterator E,unsigned Limit)5760df50938SDaniel Jasper   tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
5770df50938SDaniel Jasper                             SmallVectorImpl<AnnotatedLine *>::const_iterator E,
5780df50938SDaniel Jasper                             unsigned Limit) {
5790df50938SDaniel Jasper     if (Limit == 0)
5800df50938SDaniel Jasper       return 0;
5810df50938SDaniel Jasper     if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)
5820df50938SDaniel Jasper       return 0;
5830df50938SDaniel Jasper     if (1 + I[1]->Last->TotalLength > Limit)
5840df50938SDaniel Jasper       return 0;
5850df50938SDaniel Jasper     return 1;
5860df50938SDaniel Jasper   }
5870df50938SDaniel Jasper 
tryMergeSimpleControlStatement(SmallVectorImpl<AnnotatedLine * >::const_iterator I,SmallVectorImpl<AnnotatedLine * >::const_iterator E,unsigned Limit)5880df50938SDaniel Jasper   unsigned tryMergeSimpleControlStatement(
5890df50938SDaniel Jasper       SmallVectorImpl<AnnotatedLine *>::const_iterator I,
5900df50938SDaniel Jasper       SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
5910df50938SDaniel Jasper     if (Limit == 0)
5920df50938SDaniel Jasper       return 0;
593fb13e65aSPaul Hoad     if (Style.BraceWrapping.AfterControlStatement ==
594fb13e65aSPaul Hoad             FormatStyle::BWACS_Always &&
59510234da7SOwen Pan         I[1]->First->is(tok::l_brace) &&
596bebf7bdfSowenca         Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) {
5970df50938SDaniel Jasper       return 0;
598bebf7bdfSowenca     }
5990df50938SDaniel Jasper     if (I[1]->InPPDirective != (*I)->InPPDirective ||
600bebf7bdfSowenca         (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline)) {
6010df50938SDaniel Jasper       return 0;
602bebf7bdfSowenca     }
6030df50938SDaniel Jasper     Limit = limitConsideringMacros(I + 1, E, Limit);
6040df50938SDaniel Jasper     AnnotatedLine &Line = **I;
6058d93d7ffSMarek Kurdej     if (!Line.First->is(tok::kw_do) && !Line.First->is(tok::kw_else) &&
606bebf7bdfSowenca         !Line.Last->is(tok::kw_else) && Line.Last->isNot(tok::r_paren)) {
6072eff1c3cSMitchell Balan       return 0;
608bebf7bdfSowenca     }
6091e512f02SMarek Kurdej     // Only merge `do while` if `do` is the only statement on the line.
6102eff1c3cSMitchell Balan     if (Line.First->is(tok::kw_do) && !Line.Last->is(tok::kw_do))
6110df50938SDaniel Jasper       return 0;
6120df50938SDaniel Jasper     if (1 + I[1]->Last->TotalLength > Limit)
6130df50938SDaniel Jasper       return 0;
6141e512f02SMarek Kurdej     // Don't merge with loops, ifs, a single semicolon or a line comment.
615d3585dbdSManuel Klimek     if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for, tok::kw_while,
616bebf7bdfSowenca                              TT_ForEachMacro, TT_LineComment)) {
6170df50938SDaniel Jasper       return 0;
618bebf7bdfSowenca     }
61915000a12SPaul Hoad     // Only inline simple if's (no nested if or else), unless specified
6208d93d7ffSMarek Kurdej     if (Style.AllowShortIfStatementsOnASingleLine ==
6218d93d7ffSMarek Kurdej         FormatStyle::SIS_WithoutElse) {
622e285b8ddSDaniel Jasper       if (I + 2 != E && Line.startsWith(tok::kw_if) &&
623bebf7bdfSowenca           I[2]->First->is(tok::kw_else)) {
6240df50938SDaniel Jasper         return 0;
62515000a12SPaul Hoad       }
626bebf7bdfSowenca     }
6270df50938SDaniel Jasper     return 1;
6280df50938SDaniel Jasper   }
6290df50938SDaniel Jasper 
630d3585dbdSManuel Klimek   unsigned
tryMergeShortCaseLabels(SmallVectorImpl<AnnotatedLine * >::const_iterator I,SmallVectorImpl<AnnotatedLine * >::const_iterator E,unsigned Limit)631d3585dbdSManuel Klimek   tryMergeShortCaseLabels(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
632d3585dbdSManuel Klimek                           SmallVectorImpl<AnnotatedLine *>::const_iterator E,
633d3585dbdSManuel Klimek                           unsigned Limit) {
6340df50938SDaniel Jasper     if (Limit == 0 || I + 1 == E ||
635bebf7bdfSowenca         I[1]->First->isOneOf(tok::kw_case, tok::kw_default)) {
6360df50938SDaniel Jasper       return 0;
637bebf7bdfSowenca     }
6389da65a3aSOwen Pan     if (I[0]->Last->is(tok::l_brace) || I[1]->First->is(tok::l_brace))
6399da65a3aSOwen Pan       return 0;
6400df50938SDaniel Jasper     unsigned NumStmts = 0;
6410df50938SDaniel Jasper     unsigned Length = 0;
642a64ba701SFrancois Ferrand     bool EndsWithComment = false;
6430df50938SDaniel Jasper     bool InPPDirective = I[0]->InPPDirective;
644a64ba701SFrancois Ferrand     const unsigned Level = I[0]->Level;
6450df50938SDaniel Jasper     for (; NumStmts < 3; ++NumStmts) {
6460df50938SDaniel Jasper       if (I + 1 + NumStmts == E)
6470df50938SDaniel Jasper         break;
6480df50938SDaniel Jasper       const AnnotatedLine *Line = I[1 + NumStmts];
6490df50938SDaniel Jasper       if (Line->InPPDirective != InPPDirective)
6500df50938SDaniel Jasper         break;
6510df50938SDaniel Jasper       if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
6520df50938SDaniel Jasper         break;
6530df50938SDaniel Jasper       if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
654a64ba701SFrancois Ferrand                                tok::kw_while) ||
655bebf7bdfSowenca           EndsWithComment) {
6560df50938SDaniel Jasper         return 0;
657bebf7bdfSowenca       }
658a64ba701SFrancois Ferrand       if (Line->First->is(tok::comment)) {
659a64ba701SFrancois Ferrand         if (Level != Line->Level)
660a64ba701SFrancois Ferrand           return 0;
661a64ba701SFrancois Ferrand         SmallVectorImpl<AnnotatedLine *>::const_iterator J = I + 2 + NumStmts;
662a64ba701SFrancois Ferrand         for (; J != E; ++J) {
663a64ba701SFrancois Ferrand           Line = *J;
664a64ba701SFrancois Ferrand           if (Line->InPPDirective != InPPDirective)
665a64ba701SFrancois Ferrand             break;
666a64ba701SFrancois Ferrand           if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
667a64ba701SFrancois Ferrand             break;
668a64ba701SFrancois Ferrand           if (Line->First->isNot(tok::comment) || Level != Line->Level)
669a64ba701SFrancois Ferrand             return 0;
670a64ba701SFrancois Ferrand         }
671a64ba701SFrancois Ferrand         break;
672a64ba701SFrancois Ferrand       }
673a64ba701SFrancois Ferrand       if (Line->Last->is(tok::comment))
674a64ba701SFrancois Ferrand         EndsWithComment = true;
6750df50938SDaniel Jasper       Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the space.
6760df50938SDaniel Jasper     }
6770df50938SDaniel Jasper     if (NumStmts == 0 || NumStmts == 3 || Length > Limit)
6780df50938SDaniel Jasper       return 0;
6790df50938SDaniel Jasper     return NumStmts;
6800df50938SDaniel Jasper   }
6810df50938SDaniel Jasper 
6820df50938SDaniel Jasper   unsigned
tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine * >::const_iterator I,SmallVectorImpl<AnnotatedLine * >::const_iterator E,unsigned Limit)6830df50938SDaniel Jasper   tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
6840df50938SDaniel Jasper                       SmallVectorImpl<AnnotatedLine *>::const_iterator E,
6850df50938SDaniel Jasper                       unsigned Limit) {
686ca0d9707SMarek Kurdej     // Don't merge with a preprocessor directive.
687ca0d9707SMarek Kurdej     if (I[1]->Type == LT_PreprocessorDirective)
688ca0d9707SMarek Kurdej       return 0;
689ca0d9707SMarek Kurdej 
6900df50938SDaniel Jasper     AnnotatedLine &Line = **I;
6910df50938SDaniel Jasper 
6920df50938SDaniel Jasper     // Don't merge ObjC @ keywords and methods.
69333381f5eSNico Weber     // FIXME: If an option to allow short exception handling clauses on a single
69433381f5eSNico Weber     // line is added, change this to not return for @try and friends.
6950df50938SDaniel Jasper     if (Style.Language != FormatStyle::LK_Java &&
696bebf7bdfSowenca         Line.First->isOneOf(tok::at, tok::minus, tok::plus)) {
6970df50938SDaniel Jasper       return 0;
698bebf7bdfSowenca     }
6990df50938SDaniel Jasper 
7000df50938SDaniel Jasper     // Check that the current line allows merging. This depends on whether we
7010df50938SDaniel Jasper     // are in a control flow statements as well as several style flags.
702813d486cSJesses Gott     if (Line.First->is(tok::kw_case) ||
703bebf7bdfSowenca         (Line.First->Next && Line.First->Next->is(tok::kw_else))) {
7040df50938SDaniel Jasper       return 0;
705bebf7bdfSowenca     }
70681b61a82SJonas Toth     // default: in switch statement
70781b61a82SJonas Toth     if (Line.First->is(tok::kw_default)) {
70881b61a82SJonas Toth       const FormatToken *Tok = Line.First->getNextNonComment();
70981b61a82SJonas Toth       if (Tok && Tok->is(tok::colon))
71081b61a82SJonas Toth         return 0;
71181b61a82SJonas Toth     }
712813d486cSJesses Gott     if (Line.First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while, tok::kw_do,
713813d486cSJesses Gott                             tok::kw_try, tok::kw___try, tok::kw_catch,
7141e512f02SMarek Kurdej                             tok::kw___finally, tok::kw_for, TT_ForEachMacro,
7151e512f02SMarek Kurdej                             tok::r_brace, Keywords.kw___except)) {
71610234da7SOwen Pan       if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never)
7170df50938SDaniel Jasper         return 0;
718a94aab12Smydeveloperday       if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Empty &&
719bebf7bdfSowenca           !I[1]->First->is(tok::r_brace)) {
720a94aab12Smydeveloperday         return 0;
721bebf7bdfSowenca       }
7223b0b50baSKrasimir Georgiev       // Don't merge when we can't except the case when
7233b0b50baSKrasimir Georgiev       // the control statement block is empty
7240df50938SDaniel Jasper       if (!Style.AllowShortIfStatementsOnASingleLine &&
725813d486cSJesses Gott           Line.First->isOneOf(tok::kw_if, tok::kw_else) &&
7263b0b50baSKrasimir Georgiev           !Style.BraceWrapping.AfterControlStatement &&
727bebf7bdfSowenca           !I[1]->First->is(tok::r_brace)) {
7283b0b50baSKrasimir Georgiev         return 0;
729bebf7bdfSowenca       }
7303b0b50baSKrasimir Georgiev       if (!Style.AllowShortIfStatementsOnASingleLine &&
731813d486cSJesses Gott           Line.First->isOneOf(tok::kw_if, tok::kw_else) &&
732fb13e65aSPaul Hoad           Style.BraceWrapping.AfterControlStatement ==
733fb13e65aSPaul Hoad               FormatStyle::BWACS_Always &&
734bebf7bdfSowenca           I + 2 != E && !I[2]->First->is(tok::r_brace)) {
7350df50938SDaniel Jasper         return 0;
736bebf7bdfSowenca       }
7370df50938SDaniel Jasper       if (!Style.AllowShortLoopsOnASingleLine &&
7381e512f02SMarek Kurdej           Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for,
7391e512f02SMarek Kurdej                               TT_ForEachMacro) &&
7403b0b50baSKrasimir Georgiev           !Style.BraceWrapping.AfterControlStatement &&
741bebf7bdfSowenca           !I[1]->First->is(tok::r_brace)) {
7423b0b50baSKrasimir Georgiev         return 0;
743bebf7bdfSowenca       }
7443b0b50baSKrasimir Georgiev       if (!Style.AllowShortLoopsOnASingleLine &&
7451e512f02SMarek Kurdej           Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for,
7461e512f02SMarek Kurdej                               TT_ForEachMacro) &&
747fb13e65aSPaul Hoad           Style.BraceWrapping.AfterControlStatement ==
748fb13e65aSPaul Hoad               FormatStyle::BWACS_Always &&
749bebf7bdfSowenca           I + 2 != E && !I[2]->First->is(tok::r_brace)) {
7500df50938SDaniel Jasper         return 0;
751bebf7bdfSowenca       }
7520df50938SDaniel Jasper       // FIXME: Consider an option to allow short exception handling clauses on
7530df50938SDaniel Jasper       // a single line.
754fac2371bSNico Weber       // FIXME: This isn't covered by tests.
755fac2371bSNico Weber       // FIXME: For catch, __except, __finally the first token on the line
756fac2371bSNico Weber       // is '}', so this isn't correct here.
757fac2371bSNico Weber       if (Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch,
758bebf7bdfSowenca                               Keywords.kw___except, tok::kw___finally)) {
7590df50938SDaniel Jasper         return 0;
7600df50938SDaniel Jasper       }
761bebf7bdfSowenca     }
7620df50938SDaniel Jasper 
7633b0b50baSKrasimir Georgiev     if (Line.Last->is(tok::l_brace)) {
7640df50938SDaniel Jasper       FormatToken *Tok = I[1]->First;
76523f27850SMarek Kurdej       auto ShouldMerge = [Tok]() {
76623f27850SMarek Kurdej         if (Tok->isNot(tok::r_brace) || Tok->MustBreakBefore)
76723f27850SMarek Kurdej           return false;
76823f27850SMarek Kurdej         const FormatToken *Next = Tok->getNextNonComment();
76923f27850SMarek Kurdej         return !Next || Next->is(tok::semi);
77023f27850SMarek Kurdej       };
771d81f003cSMarek Kurdej 
77223f27850SMarek Kurdej       if (ShouldMerge()) {
7730df50938SDaniel Jasper         // We merge empty blocks even if the line exceeds the column limit.
774db4ad360SOwen Pan         Tok->SpacesRequiredBefore = Style.SpaceInEmptyBlock ? 1 : 0;
7750df50938SDaniel Jasper         Tok->CanBreakBefore = true;
7760df50938SDaniel Jasper         return 1;
7776f3778c3SSam McCall       } else if (Limit != 0 && !Line.startsWithNamespace() &&
7780df50938SDaniel Jasper                  !startsExternCBlock(Line)) {
7790df50938SDaniel Jasper         // We don't merge short records.
780d81f003cSMarek Kurdej         if (isRecordLBrace(*Line.Last))
7810df50938SDaniel Jasper           return 0;
7820df50938SDaniel Jasper 
7830df50938SDaniel Jasper         // Check that we still have three lines and they fit into the limit.
7840df50938SDaniel Jasper         if (I + 2 == E || I[2]->Type == LT_Invalid)
7850df50938SDaniel Jasper           return 0;
7860df50938SDaniel Jasper         Limit = limitConsideringMacros(I + 2, E, Limit);
7870df50938SDaniel Jasper 
7880df50938SDaniel Jasper         if (!nextTwoLinesFitInto(I, Limit))
7890df50938SDaniel Jasper           return 0;
7900df50938SDaniel Jasper 
7910df50938SDaniel Jasper         // Second, check that the next line does not contain any braces - if it
7920df50938SDaniel Jasper         // does, readability declines when putting it into a single line.
7930df50938SDaniel Jasper         if (I[1]->Last->is(TT_LineComment))
7940df50938SDaniel Jasper           return 0;
7950df50938SDaniel Jasper         do {
796f5acd11dSBruno Ricci           if (Tok->is(tok::l_brace) && Tok->isNot(BK_BracedInit))
7970df50938SDaniel Jasper             return 0;
7980df50938SDaniel Jasper           Tok = Tok->Next;
7990df50938SDaniel Jasper         } while (Tok);
8000df50938SDaniel Jasper 
8010df50938SDaniel Jasper         // Last, check that the third line starts with a closing brace.
8020df50938SDaniel Jasper         Tok = I[2]->First;
8030df50938SDaniel Jasper         if (Tok->isNot(tok::r_brace))
8040df50938SDaniel Jasper           return 0;
8050df50938SDaniel Jasper 
806e9f5357fSDaniel Jasper         // Don't merge "if (a) { .. } else {".
807e9f5357fSDaniel Jasper         if (Tok->Next && Tok->Next->is(tok::kw_else))
808e9f5357fSDaniel Jasper           return 0;
809e9f5357fSDaniel Jasper 
810fb13e65aSPaul Hoad         // Don't merge a trailing multi-line control statement block like:
811fb13e65aSPaul Hoad         // } else if (foo &&
812fb13e65aSPaul Hoad         //            bar)
813fb13e65aSPaul Hoad         // { <-- current Line
814fb13e65aSPaul Hoad         //   baz();
815fb13e65aSPaul Hoad         // }
81672e4f4a2Smydeveloperday         if (Line.First == Line.Last && Line.First->isNot(TT_FunctionLBrace) &&
817fb13e65aSPaul Hoad             Style.BraceWrapping.AfterControlStatement ==
818bebf7bdfSowenca                 FormatStyle::BWACS_MultiLine) {
819fb13e65aSPaul Hoad           return 0;
820bebf7bdfSowenca         }
821fb13e65aSPaul Hoad 
8220df50938SDaniel Jasper         return 2;
8230df50938SDaniel Jasper       }
8243b0b50baSKrasimir Georgiev     } else if (I[1]->First->is(tok::l_brace)) {
8253b0b50baSKrasimir Georgiev       if (I[1]->Last->is(TT_LineComment))
8263b0b50baSKrasimir Georgiev         return 0;
8273b0b50baSKrasimir Georgiev 
8283b0b50baSKrasimir Georgiev       // Check for Limit <= 2 to account for the " {".
8293b0b50baSKrasimir Georgiev       if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(*I)))
8303b0b50baSKrasimir Georgiev         return 0;
8313b0b50baSKrasimir Georgiev       Limit -= 2;
8323b0b50baSKrasimir Georgiev       unsigned MergedLines = 0;
83310234da7SOwen Pan       if (Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never ||
8343b0b50baSKrasimir Georgiev           (I[1]->First == I[1]->Last && I + 2 != E &&
8353b0b50baSKrasimir Georgiev            I[2]->First->is(tok::r_brace))) {
8363b0b50baSKrasimir Georgiev         MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
8373b0b50baSKrasimir Georgiev         // If we managed to merge the block, count the statement header, which
8383b0b50baSKrasimir Georgiev         // is on a separate line.
8393b0b50baSKrasimir Georgiev         if (MergedLines > 0)
8403b0b50baSKrasimir Georgiev           ++MergedLines;
8413b0b50baSKrasimir Georgiev       }
8423b0b50baSKrasimir Georgiev       return MergedLines;
8433b0b50baSKrasimir Georgiev     }
8440df50938SDaniel Jasper     return 0;
8450df50938SDaniel Jasper   }
8460df50938SDaniel Jasper 
8470df50938SDaniel Jasper   /// Returns the modified column limit for \p I if it is inside a macro and
8480df50938SDaniel Jasper   /// needs a trailing '\'.
8490df50938SDaniel Jasper   unsigned
limitConsideringMacros(SmallVectorImpl<AnnotatedLine * >::const_iterator I,SmallVectorImpl<AnnotatedLine * >::const_iterator E,unsigned Limit)8500df50938SDaniel Jasper   limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
8510df50938SDaniel Jasper                          SmallVectorImpl<AnnotatedLine *>::const_iterator E,
8520df50938SDaniel Jasper                          unsigned Limit) {
8530df50938SDaniel Jasper     if (I[0]->InPPDirective && I + 1 != E &&
854bebf7bdfSowenca         !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {
8550df50938SDaniel Jasper       return Limit < 2 ? 0 : Limit - 2;
856bebf7bdfSowenca     }
8570df50938SDaniel Jasper     return Limit;
8580df50938SDaniel Jasper   }
8590df50938SDaniel Jasper 
nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine * >::const_iterator I,unsigned Limit)8600df50938SDaniel Jasper   bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
8610df50938SDaniel Jasper                            unsigned Limit) {
8620df50938SDaniel Jasper     if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
8630df50938SDaniel Jasper       return false;
8640df50938SDaniel Jasper     return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
8650df50938SDaniel Jasper   }
8660df50938SDaniel Jasper 
containsMustBreak(const AnnotatedLine * Line)8670df50938SDaniel Jasper   bool containsMustBreak(const AnnotatedLine *Line) {
868d079995dSMarek Kurdej     for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next)
8690df50938SDaniel Jasper       if (Tok->MustBreakBefore)
8700df50938SDaniel Jasper         return true;
8710df50938SDaniel Jasper     return false;
8720df50938SDaniel Jasper   }
8730df50938SDaniel Jasper 
join(AnnotatedLine & A,const AnnotatedLine & B)8743d3ea84aSManuel Klimek   void join(AnnotatedLine &A, const AnnotatedLine &B) {
8753d3ea84aSManuel Klimek     assert(!A.Last->Next);
8763d3ea84aSManuel Klimek     assert(!B.First->Previous);
8773d3ea84aSManuel Klimek     if (B.Affected)
8783d3ea84aSManuel Klimek       A.Affected = true;
8793d3ea84aSManuel Klimek     A.Last->Next = B.First;
8803d3ea84aSManuel Klimek     B.First->Previous = A.Last;
8813d3ea84aSManuel Klimek     B.First->CanBreakBefore = true;
8823d3ea84aSManuel Klimek     unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;
8833d3ea84aSManuel Klimek     for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {
8843d3ea84aSManuel Klimek       Tok->TotalLength += LengthA;
8853d3ea84aSManuel Klimek       A.Last = Tok;
8863d3ea84aSManuel Klimek     }
8873d3ea84aSManuel Klimek   }
8883d3ea84aSManuel Klimek 
8890df50938SDaniel Jasper   const FormatStyle &Style;
890fac2371bSNico Weber   const AdditionalKeywords &Keywords;
8913d3ea84aSManuel Klimek   const SmallVectorImpl<AnnotatedLine *>::const_iterator End;
8923d3ea84aSManuel Klimek 
8933d3ea84aSManuel Klimek   SmallVectorImpl<AnnotatedLine *>::const_iterator Next;
894e56a829eSFrancois Ferrand   const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines;
8950df50938SDaniel Jasper };
8960df50938SDaniel Jasper 
markFinalized(FormatToken * Tok)897d1c13736SDaniel Jasper static void markFinalized(FormatToken *Tok) {
898d1c13736SDaniel Jasper   for (; Tok; Tok = Tok->Next) {
899d1c13736SDaniel Jasper     Tok->Finalized = true;
900d1c13736SDaniel Jasper     for (AnnotatedLine *Child : Tok->Children)
901d1c13736SDaniel Jasper       markFinalized(Child->First);
902d1c13736SDaniel Jasper   }
903d1c13736SDaniel Jasper }
904d1c13736SDaniel Jasper 
905d3585dbdSManuel Klimek #ifndef NDEBUG
printLineState(const LineState & State)906d3585dbdSManuel Klimek static void printLineState(const LineState &State) {
907d3585dbdSManuel Klimek   llvm::dbgs() << "State: ";
908d3585dbdSManuel Klimek   for (const ParenState &P : State.Stack) {
9098b4bc76aSKrasimir Georgiev     llvm::dbgs() << (P.Tok ? P.Tok->TokenText : "F") << "|" << P.Indent << "|"
9108b4bc76aSKrasimir Georgiev                  << P.LastSpace << "|" << P.NestedBlockIndent << " ";
911d3585dbdSManuel Klimek   }
912d3585dbdSManuel Klimek   llvm::dbgs() << State.NextToken->TokenText << "\n";
913d3585dbdSManuel Klimek }
914d3585dbdSManuel Klimek #endif
915d3585dbdSManuel Klimek 
9169fc8faf9SAdrian Prantl /// Base class for classes that format one \c AnnotatedLine.
917d3585dbdSManuel Klimek class LineFormatter {
918d3585dbdSManuel Klimek public:
LineFormatter(ContinuationIndenter * Indenter,WhitespaceManager * Whitespaces,const FormatStyle & Style,UnwrappedLineFormatter * BlockFormatter)919d3585dbdSManuel Klimek   LineFormatter(ContinuationIndenter *Indenter, WhitespaceManager *Whitespaces,
920d3585dbdSManuel Klimek                 const FormatStyle &Style,
921d3585dbdSManuel Klimek                 UnwrappedLineFormatter *BlockFormatter)
922d3585dbdSManuel Klimek       : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
923d3585dbdSManuel Klimek         BlockFormatter(BlockFormatter) {}
~LineFormatter()924637d1e66SAngel Garcia Gomez   virtual ~LineFormatter() {}
925d3585dbdSManuel Klimek 
9269fc8faf9SAdrian Prantl   /// Formats an \c AnnotatedLine and returns the penalty.
927d3585dbdSManuel Klimek   ///
928d3585dbdSManuel Klimek   /// If \p DryRun is \c false, directly applies the changes.
9295bcf99b4SPaul Hoad   virtual unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
9305bcf99b4SPaul Hoad                               unsigned FirstStartColumn, bool DryRun) = 0;
931d3585dbdSManuel Klimek 
932d3585dbdSManuel Klimek protected:
9339fc8faf9SAdrian Prantl   /// If the \p State's next token is an r_brace closing a nested block,
934d3585dbdSManuel Klimek   /// format the nested block before it.
935d3585dbdSManuel Klimek   ///
936d3585dbdSManuel Klimek   /// Returns \c true if all children could be placed successfully and adapts
937d3585dbdSManuel Klimek   /// \p Penalty as well as \p State. If \p DryRun is false, also directly
938d3585dbdSManuel Klimek   /// creates changes using \c Whitespaces.
939d3585dbdSManuel Klimek   ///
940d3585dbdSManuel Klimek   /// The crucial idea here is that children always get formatted upon
941d3585dbdSManuel Klimek   /// encountering the closing brace right after the nested block. Now, if we
942d3585dbdSManuel Klimek   /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is
943d3585dbdSManuel Klimek   /// \c false), the entire block has to be kept on the same line (which is only
944d3585dbdSManuel Klimek   /// possible if it fits on the line, only contains a single statement, etc.
945d3585dbdSManuel Klimek   ///
946d3585dbdSManuel Klimek   /// If \p NewLine is true, we format the nested block on separate lines, i.e.
947d3585dbdSManuel Klimek   /// break after the "{", format all lines with correct indentation and the put
948d3585dbdSManuel Klimek   /// the closing "}" on yet another new line.
949d3585dbdSManuel Klimek   ///
950d3585dbdSManuel Klimek   /// This enables us to keep the simple structure of the
951d3585dbdSManuel Klimek   /// \c UnwrappedLineFormatter, where we only have two options for each token:
952d3585dbdSManuel Klimek   /// break or don't break.
formatChildren(LineState & State,bool NewLine,bool DryRun,unsigned & Penalty)953d3585dbdSManuel Klimek   bool formatChildren(LineState &State, bool NewLine, bool DryRun,
954d3585dbdSManuel Klimek                       unsigned &Penalty) {
955d3585dbdSManuel Klimek     const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
956d3585dbdSManuel Klimek     FormatToken &Previous = *State.NextToken->Previous;
957f5acd11dSBruno Ricci     if (!LBrace || LBrace->isNot(tok::l_brace) || LBrace->isNot(BK_Block) ||
958bebf7bdfSowenca         Previous.Children.size() == 0) {
959d3585dbdSManuel Klimek       // The previous token does not open a block. Nothing to do. We don't
960d3585dbdSManuel Klimek       // assert so that we can simply call this function for all tokens.
961d3585dbdSManuel Klimek       return true;
962bebf7bdfSowenca     }
963d3585dbdSManuel Klimek 
964d3585dbdSManuel Klimek     if (NewLine) {
96564cf5ebaSVitali Lovich       const ParenState &P = State.Stack.back();
96664cf5ebaSVitali Lovich 
96764cf5ebaSVitali Lovich       int AdditionalIndent =
96864cf5ebaSVitali Lovich           P.Indent - Previous.Children[0]->Level * Style.IndentWidth;
96964cf5ebaSVitali Lovich 
97064cf5ebaSVitali Lovich       if (Style.LambdaBodyIndentation == FormatStyle::LBI_OuterScope &&
97164cf5ebaSVitali Lovich           P.NestedBlockIndent == P.LastSpace) {
97264cf5ebaSVitali Lovich         if (State.NextToken->MatchingParen &&
973bebf7bdfSowenca             State.NextToken->MatchingParen->is(TT_LambdaLBrace)) {
97464cf5ebaSVitali Lovich           State.Stack.pop_back();
975bebf7bdfSowenca         }
97664cf5ebaSVitali Lovich         if (LBrace->is(TT_LambdaLBrace))
97764cf5ebaSVitali Lovich           AdditionalIndent = 0;
97864cf5ebaSVitali Lovich       }
979d3585dbdSManuel Klimek 
980d3585dbdSManuel Klimek       Penalty +=
981d3585dbdSManuel Klimek           BlockFormatter->format(Previous.Children, DryRun, AdditionalIndent,
982d3585dbdSManuel Klimek                                  /*FixBadIndentation=*/true);
983d3585dbdSManuel Klimek       return true;
984d3585dbdSManuel Klimek     }
985d3585dbdSManuel Klimek 
986d3585dbdSManuel Klimek     if (Previous.Children[0]->First->MustBreakBefore)
987d3585dbdSManuel Klimek       return false;
988d3585dbdSManuel Klimek 
989d3585dbdSManuel Klimek     // Cannot merge into one line if this line ends on a comment.
990d3585dbdSManuel Klimek     if (Previous.is(tok::comment))
991d3585dbdSManuel Klimek       return false;
992d3585dbdSManuel Klimek 
9937d42f3f7SDaniel Jasper     // Cannot merge multiple statements into a single line.
9947d42f3f7SDaniel Jasper     if (Previous.Children.size() > 1)
9957d42f3f7SDaniel Jasper       return false;
9967d42f3f7SDaniel Jasper 
9977d42f3f7SDaniel Jasper     const AnnotatedLine *Child = Previous.Children[0];
998d3585dbdSManuel Klimek     // We can't put the closing "}" on a line with a trailing comment.
9997d42f3f7SDaniel Jasper     if (Child->Last->isTrailingComment())
1000d3585dbdSManuel Klimek       return false;
1001d3585dbdSManuel Klimek 
1002d3585dbdSManuel Klimek     // If the child line exceeds the column limit, we wouldn't want to merge it.
1003d3585dbdSManuel Klimek     // We add +2 for the trailing " }".
1004d3585dbdSManuel Klimek     if (Style.ColumnLimit > 0 &&
1005bebf7bdfSowenca         Child->Last->TotalLength + State.Column + 2 > Style.ColumnLimit) {
1006d3585dbdSManuel Klimek       return false;
1007bebf7bdfSowenca     }
1008d3585dbdSManuel Klimek 
1009d3585dbdSManuel Klimek     if (!DryRun) {
1010d3585dbdSManuel Klimek       Whitespaces->replaceWhitespace(
10117d42f3f7SDaniel Jasper           *Child->First, /*Newlines=*/0, /*Spaces=*/1,
1012e8111502Smydeveloperday           /*StartOfTokenColumn=*/State.Column, /*IsAligned=*/false,
1013e8111502Smydeveloperday           State.Line->InPPDirective);
1014d3585dbdSManuel Klimek     }
10159ad83fe7SKrasimir Georgiev     Penalty +=
10169ad83fe7SKrasimir Georgiev         formatLine(*Child, State.Column + 1, /*FirstStartColumn=*/0, DryRun);
1017d3585dbdSManuel Klimek 
10187d42f3f7SDaniel Jasper     State.Column += 1 + Child->Last->TotalLength;
1019d3585dbdSManuel Klimek     return true;
1020d3585dbdSManuel Klimek   }
1021d3585dbdSManuel Klimek 
1022d3585dbdSManuel Klimek   ContinuationIndenter *Indenter;
1023d3585dbdSManuel Klimek 
1024d3585dbdSManuel Klimek private:
1025d3585dbdSManuel Klimek   WhitespaceManager *Whitespaces;
1026d3585dbdSManuel Klimek   const FormatStyle &Style;
1027d3585dbdSManuel Klimek   UnwrappedLineFormatter *BlockFormatter;
1028d3585dbdSManuel Klimek };
1029d3585dbdSManuel Klimek 
10309fc8faf9SAdrian Prantl /// Formatter that keeps the existing line breaks.
1031d3585dbdSManuel Klimek class NoColumnLimitLineFormatter : public LineFormatter {
1032d3585dbdSManuel Klimek public:
NoColumnLimitLineFormatter(ContinuationIndenter * Indenter,WhitespaceManager * Whitespaces,const FormatStyle & Style,UnwrappedLineFormatter * BlockFormatter)1033d3585dbdSManuel Klimek   NoColumnLimitLineFormatter(ContinuationIndenter *Indenter,
1034d3585dbdSManuel Klimek                              WhitespaceManager *Whitespaces,
1035d3585dbdSManuel Klimek                              const FormatStyle &Style,
1036d3585dbdSManuel Klimek                              UnwrappedLineFormatter *BlockFormatter)
1037d3585dbdSManuel Klimek       : LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
1038d3585dbdSManuel Klimek 
10399fc8faf9SAdrian Prantl   /// Formats the line, simply keeping all of the input's line breaking
1040d3585dbdSManuel Klimek   /// decisions.
formatLine(const AnnotatedLine & Line,unsigned FirstIndent,unsigned FirstStartColumn,bool DryRun)1041d3585dbdSManuel Klimek   unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
10429ad83fe7SKrasimir Georgiev                       unsigned FirstStartColumn, bool DryRun) override {
1043d3585dbdSManuel Klimek     assert(!DryRun);
10449ad83fe7SKrasimir Georgiev     LineState State = Indenter->getInitialState(FirstIndent, FirstStartColumn,
10459ad83fe7SKrasimir Georgiev                                                 &Line, /*DryRun=*/false);
1046d3585dbdSManuel Klimek     while (State.NextToken) {
1047d3585dbdSManuel Klimek       bool Newline =
1048d3585dbdSManuel Klimek           Indenter->mustBreak(State) ||
1049d3585dbdSManuel Klimek           (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
1050d3585dbdSManuel Klimek       unsigned Penalty = 0;
1051d3585dbdSManuel Klimek       formatChildren(State, Newline, /*DryRun=*/false, Penalty);
1052d3585dbdSManuel Klimek       Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
1053d3585dbdSManuel Klimek     }
1054d3585dbdSManuel Klimek     return 0;
1055d3585dbdSManuel Klimek   }
1056d3585dbdSManuel Klimek };
1057d3585dbdSManuel Klimek 
10589fc8faf9SAdrian Prantl /// Formatter that puts all tokens into a single line without breaks.
1059d3585dbdSManuel Klimek class NoLineBreakFormatter : public LineFormatter {
1060d3585dbdSManuel Klimek public:
NoLineBreakFormatter(ContinuationIndenter * Indenter,WhitespaceManager * Whitespaces,const FormatStyle & Style,UnwrappedLineFormatter * BlockFormatter)1061d3585dbdSManuel Klimek   NoLineBreakFormatter(ContinuationIndenter *Indenter,
1062d3585dbdSManuel Klimek                        WhitespaceManager *Whitespaces, const FormatStyle &Style,
1063d3585dbdSManuel Klimek                        UnwrappedLineFormatter *BlockFormatter)
1064d3585dbdSManuel Klimek       : LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
1065d3585dbdSManuel Klimek 
10669fc8faf9SAdrian Prantl   /// Puts all tokens into a single line.
formatLine(const AnnotatedLine & Line,unsigned FirstIndent,unsigned FirstStartColumn,bool DryRun)1067d3585dbdSManuel Klimek   unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
10689ad83fe7SKrasimir Georgiev                       unsigned FirstStartColumn, bool DryRun) override {
1069d3585dbdSManuel Klimek     unsigned Penalty = 0;
10709ad83fe7SKrasimir Georgiev     LineState State =
10719ad83fe7SKrasimir Georgiev         Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun);
1072d3585dbdSManuel Klimek     while (State.NextToken) {
107349a3ad21SRui Ueyama       formatChildren(State, /*NewLine=*/false, DryRun, Penalty);
1074994b6c9bSKrasimir Georgiev       Indenter->addTokenToState(
1075994b6c9bSKrasimir Georgiev           State, /*Newline=*/State.NextToken->MustBreakBefore, DryRun);
1076d3585dbdSManuel Klimek     }
1077d3585dbdSManuel Klimek     return Penalty;
1078d3585dbdSManuel Klimek   }
1079d3585dbdSManuel Klimek };
1080d3585dbdSManuel Klimek 
10819fc8faf9SAdrian Prantl /// Finds the best way to break lines.
1082d3585dbdSManuel Klimek class OptimizingLineFormatter : public LineFormatter {
1083d3585dbdSManuel Klimek public:
OptimizingLineFormatter(ContinuationIndenter * Indenter,WhitespaceManager * Whitespaces,const FormatStyle & Style,UnwrappedLineFormatter * BlockFormatter)1084d3585dbdSManuel Klimek   OptimizingLineFormatter(ContinuationIndenter *Indenter,
1085d3585dbdSManuel Klimek                           WhitespaceManager *Whitespaces,
1086d3585dbdSManuel Klimek                           const FormatStyle &Style,
1087d3585dbdSManuel Klimek                           UnwrappedLineFormatter *BlockFormatter)
1088d3585dbdSManuel Klimek       : LineFormatter(Indenter, Whitespaces, Style, BlockFormatter) {}
1089d3585dbdSManuel Klimek 
10909fc8faf9SAdrian Prantl   /// Formats the line by finding the best line breaks with line lengths
1091d3585dbdSManuel Klimek   /// below the column limit.
formatLine(const AnnotatedLine & Line,unsigned FirstIndent,unsigned FirstStartColumn,bool DryRun)1092d3585dbdSManuel Klimek   unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
10939ad83fe7SKrasimir Georgiev                       unsigned FirstStartColumn, bool DryRun) override {
10949ad83fe7SKrasimir Georgiev     LineState State =
10959ad83fe7SKrasimir Georgiev         Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun);
1096d3585dbdSManuel Klimek 
1097d3585dbdSManuel Klimek     // If the ObjC method declaration does not fit on a line, we should format
1098d3585dbdSManuel Klimek     // it with one arg per line.
1099d3585dbdSManuel Klimek     if (State.Line->Type == LT_ObjCMethodDecl)
1100d3585dbdSManuel Klimek       State.Stack.back().BreakBeforeParameter = true;
1101d3585dbdSManuel Klimek 
1102d3585dbdSManuel Klimek     // Find best solution in solution space.
1103d3585dbdSManuel Klimek     return analyzeSolutionSpace(State, DryRun);
1104d3585dbdSManuel Klimek   }
1105d3585dbdSManuel Klimek 
1106d3585dbdSManuel Klimek private:
1107d3585dbdSManuel Klimek   struct CompareLineStatePointers {
operator ()clang::format::__anon8a591c740111::OptimizingLineFormatter::CompareLineStatePointers1108d3585dbdSManuel Klimek     bool operator()(LineState *obj1, LineState *obj2) const {
1109d3585dbdSManuel Klimek       return *obj1 < *obj2;
1110d3585dbdSManuel Klimek     }
1111d3585dbdSManuel Klimek   };
1112d3585dbdSManuel Klimek 
11139fc8faf9SAdrian Prantl   /// A pair of <penalty, count> that is used to prioritize the BFS on.
1114d3585dbdSManuel Klimek   ///
1115d3585dbdSManuel Klimek   /// In case of equal penalties, we want to prefer states that were inserted
1116d3585dbdSManuel Klimek   /// first. During state generation we make sure that we insert states first
1117d3585dbdSManuel Klimek   /// that break the line as late as possible.
1118d3585dbdSManuel Klimek   typedef std::pair<unsigned, unsigned> OrderedPenalty;
1119d3585dbdSManuel Klimek 
11209fc8faf9SAdrian Prantl   /// An edge in the solution space from \c Previous->State to \c State,
1121d3585dbdSManuel Klimek   /// inserting a newline dependent on the \c NewLine.
1122d3585dbdSManuel Klimek   struct StateNode {
StateNodeclang::format::__anon8a591c740111::OptimizingLineFormatter::StateNode1123d3585dbdSManuel Klimek     StateNode(const LineState &State, bool NewLine, StateNode *Previous)
1124d3585dbdSManuel Klimek         : State(State), NewLine(NewLine), Previous(Previous) {}
1125d3585dbdSManuel Klimek     LineState State;
1126d3585dbdSManuel Klimek     bool NewLine;
1127d3585dbdSManuel Klimek     StateNode *Previous;
1128d3585dbdSManuel Klimek   };
1129d3585dbdSManuel Klimek 
11309fc8faf9SAdrian Prantl   /// An item in the prioritized BFS search queue. The \c StateNode's
1131d3585dbdSManuel Klimek   /// \c State has the given \c OrderedPenalty.
1132d3585dbdSManuel Klimek   typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
1133d3585dbdSManuel Klimek 
11349fc8faf9SAdrian Prantl   /// The BFS queue type.
1135*36229fa3Sowenca   typedef std::priority_queue<QueueItem, SmallVector<QueueItem>,
113689628f64SManuel Klimek                               std::greater<QueueItem>>
113789628f64SManuel Klimek       QueueType;
1138d3585dbdSManuel Klimek 
11399fc8faf9SAdrian Prantl   /// Analyze the entire solution space starting from \p InitialState.
1140d3585dbdSManuel Klimek   ///
1141d3585dbdSManuel Klimek   /// This implements a variant of Dijkstra's algorithm on the graph that spans
1142d3585dbdSManuel Klimek   /// the solution space (\c LineStates are the nodes). The algorithm tries to
1143d3585dbdSManuel Klimek   /// find the shortest path (the one with lowest penalty) from \p InitialState
1144d3585dbdSManuel Klimek   /// to a state where all tokens are placed. Returns the penalty.
1145d3585dbdSManuel Klimek   ///
1146d3585dbdSManuel Klimek   /// If \p DryRun is \c false, directly applies the changes.
analyzeSolutionSpace(LineState & InitialState,bool DryRun)1147d3585dbdSManuel Klimek   unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun) {
1148d3585dbdSManuel Klimek     std::set<LineState *, CompareLineStatePointers> Seen;
1149d3585dbdSManuel Klimek 
1150d3585dbdSManuel Klimek     // Increasing count of \c StateNode items we have created. This is used to
1151d3585dbdSManuel Klimek     // create a deterministic order independent of the container.
1152d3585dbdSManuel Klimek     unsigned Count = 0;
1153d3585dbdSManuel Klimek     QueueType Queue;
1154d3585dbdSManuel Klimek 
1155d3585dbdSManuel Klimek     // Insert start element into queue.
1156e7fdeda2SBjörn Schäpers     StateNode *RootNode =
1157d3585dbdSManuel Klimek         new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);
1158e7fdeda2SBjörn Schäpers     Queue.push(QueueItem(OrderedPenalty(0, Count), RootNode));
1159d3585dbdSManuel Klimek     ++Count;
1160d3585dbdSManuel Klimek 
1161d3585dbdSManuel Klimek     unsigned Penalty = 0;
1162d3585dbdSManuel Klimek 
1163d3585dbdSManuel Klimek     // While not empty, take first element and follow edges.
1164d3585dbdSManuel Klimek     while (!Queue.empty()) {
1165664ce34eSowenca       // Quit if we still haven't found a solution by now.
1166664ce34eSowenca       if (Count > 25000000)
1167664ce34eSowenca         return 0;
1168664ce34eSowenca 
1169d3585dbdSManuel Klimek       Penalty = Queue.top().first.first;
1170d3585dbdSManuel Klimek       StateNode *Node = Queue.top().second;
1171d3585dbdSManuel Klimek       if (!Node->State.NextToken) {
11723538b39eSNicola Zaghen         LLVM_DEBUG(llvm::dbgs()
11733538b39eSNicola Zaghen                    << "\n---\nPenalty for line: " << Penalty << "\n");
1174d3585dbdSManuel Klimek         break;
1175d3585dbdSManuel Klimek       }
1176d3585dbdSManuel Klimek       Queue.pop();
1177d3585dbdSManuel Klimek 
1178d3585dbdSManuel Klimek       // Cut off the analysis of certain solutions if the analysis gets too
1179d3585dbdSManuel Klimek       // complex. See description of IgnoreStackForComparison.
118075bf203dSDaniel Jasper       if (Count > 50000)
1181d3585dbdSManuel Klimek         Node->State.IgnoreStackForComparison = true;
1182d3585dbdSManuel Klimek 
1183bebf7bdfSowenca       if (!Seen.insert(&Node->State).second) {
1184d3585dbdSManuel Klimek         // State already examined with lower penalty.
1185d3585dbdSManuel Klimek         continue;
1186bebf7bdfSowenca       }
1187d3585dbdSManuel Klimek 
1188f5acd11dSBruno Ricci       FormatDecision LastFormat = Node->State.NextToken->getDecision();
1189d3585dbdSManuel Klimek       if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
11901188f241SBjörn Schäpers         addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue);
1191d3585dbdSManuel Klimek       if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
11921188f241SBjörn Schäpers         addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue);
1193d3585dbdSManuel Klimek     }
1194d3585dbdSManuel Klimek 
1195d3585dbdSManuel Klimek     if (Queue.empty()) {
1196d3585dbdSManuel Klimek       // We were unable to find a solution, do nothing.
1197d3585dbdSManuel Klimek       // FIXME: Add diagnostic?
11983538b39eSNicola Zaghen       LLVM_DEBUG(llvm::dbgs() << "Could not find a solution.\n");
1199d3585dbdSManuel Klimek       return 0;
1200d3585dbdSManuel Klimek     }
1201d3585dbdSManuel Klimek 
1202d3585dbdSManuel Klimek     // Reconstruct the solution.
1203d3585dbdSManuel Klimek     if (!DryRun)
1204d3585dbdSManuel Klimek       reconstructPath(InitialState, Queue.top().second);
1205d3585dbdSManuel Klimek 
12063538b39eSNicola Zaghen     LLVM_DEBUG(llvm::dbgs()
12073538b39eSNicola Zaghen                << "Total number of analyzed states: " << Count << "\n");
12083538b39eSNicola Zaghen     LLVM_DEBUG(llvm::dbgs() << "---\n");
1209d3585dbdSManuel Klimek 
1210d3585dbdSManuel Klimek     return Penalty;
1211d3585dbdSManuel Klimek   }
1212d3585dbdSManuel Klimek 
12139fc8faf9SAdrian Prantl   /// Add the following state to the analysis queue \c Queue.
1214d3585dbdSManuel Klimek   ///
1215d3585dbdSManuel Klimek   /// Assume the current state is \p PreviousNode and has been reached with a
1216d3585dbdSManuel Klimek   /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
addNextStateToQueue(unsigned Penalty,StateNode * PreviousNode,bool NewLine,unsigned * Count,QueueType * Queue)1217d3585dbdSManuel Klimek   void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
12181188f241SBjörn Schäpers                            bool NewLine, unsigned *Count, QueueType *Queue) {
1219d3585dbdSManuel Klimek     if (NewLine && !Indenter->canBreak(PreviousNode->State))
1220d3585dbdSManuel Klimek       return;
1221d3585dbdSManuel Klimek     if (!NewLine && Indenter->mustBreak(PreviousNode->State))
1222d3585dbdSManuel Klimek       return;
1223d3585dbdSManuel Klimek 
1224d3585dbdSManuel Klimek     StateNode *Node = new (Allocator.Allocate())
1225d3585dbdSManuel Klimek         StateNode(PreviousNode->State, NewLine, PreviousNode);
1226d3585dbdSManuel Klimek     if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))
1227d3585dbdSManuel Klimek       return;
1228d3585dbdSManuel Klimek 
1229d3585dbdSManuel Klimek     Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
1230d3585dbdSManuel Klimek 
12311188f241SBjörn Schäpers     Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
12321188f241SBjörn Schäpers     ++(*Count);
1233d3585dbdSManuel Klimek   }
1234d3585dbdSManuel Klimek 
12359fc8faf9SAdrian Prantl   /// Applies the best formatting by reconstructing the path in the
1236d3585dbdSManuel Klimek   /// solution space that leads to \c Best.
reconstructPath(LineState & State,StateNode * Best)1237d3585dbdSManuel Klimek   void reconstructPath(LineState &State, StateNode *Best) {
123835493b45SBjörn Schäpers     llvm::SmallVector<StateNode *> Path;
1239d3585dbdSManuel Klimek     // We do not need a break before the initial token.
1240d3585dbdSManuel Klimek     while (Best->Previous) {
124135493b45SBjörn Schäpers       Path.push_back(Best);
1242d3585dbdSManuel Klimek       Best = Best->Previous;
1243d3585dbdSManuel Klimek     }
124435493b45SBjörn Schäpers     for (const auto &Node : llvm::reverse(Path)) {
1245d3585dbdSManuel Klimek       unsigned Penalty = 0;
124635493b45SBjörn Schäpers       formatChildren(State, Node->NewLine, /*DryRun=*/false, Penalty);
124735493b45SBjörn Schäpers       Penalty += Indenter->addTokenToState(State, Node->NewLine, false);
1248d3585dbdSManuel Klimek 
12493538b39eSNicola Zaghen       LLVM_DEBUG({
125035493b45SBjörn Schäpers         printLineState(Node->Previous->State);
1251bebf7bdfSowenca         if (Node->NewLine) {
1252d3585dbdSManuel Klimek           llvm::dbgs() << "Penalty for placing "
125335493b45SBjörn Schäpers                        << Node->Previous->State.NextToken->Tok.getName()
12545528caceSKrasimir Georgiev                        << " on a new line: " << Penalty << "\n";
1255bebf7bdfSowenca         }
1256d3585dbdSManuel Klimek       });
1257d3585dbdSManuel Klimek     }
1258d3585dbdSManuel Klimek   }
1259d3585dbdSManuel Klimek 
1260d3585dbdSManuel Klimek   llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
1261d3585dbdSManuel Klimek };
1262d3585dbdSManuel Klimek 
12637eb5464bSHans Wennborg } // anonymous namespace
12640df50938SDaniel Jasper 
format(const SmallVectorImpl<AnnotatedLine * > & Lines,bool DryRun,int AdditionalIndent,bool FixBadIndentation,unsigned FirstStartColumn,unsigned NextStartColumn,unsigned LastStartColumn)12655bcf99b4SPaul Hoad unsigned UnwrappedLineFormatter::format(
12665bcf99b4SPaul Hoad     const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
12675bcf99b4SPaul Hoad     int AdditionalIndent, bool FixBadIndentation, unsigned FirstStartColumn,
12685bcf99b4SPaul Hoad     unsigned NextStartColumn, unsigned LastStartColumn) {
12693d3ea84aSManuel Klimek   LineJoiner Joiner(Style, Keywords, Lines);
12700df50938SDaniel Jasper 
12710df50938SDaniel Jasper   // Try to look up already computed penalty in DryRun-mode.
12720df50938SDaniel Jasper   std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
12730df50938SDaniel Jasper       &Lines, AdditionalIndent);
12740df50938SDaniel Jasper   auto CacheIt = PenaltyCache.find(CacheKey);
12750df50938SDaniel Jasper   if (DryRun && CacheIt != PenaltyCache.end())
12760df50938SDaniel Jasper     return CacheIt->second;
12770df50938SDaniel Jasper 
12780df50938SDaniel Jasper   assert(!Lines.empty());
12790df50938SDaniel Jasper   unsigned Penalty = 0;
12803d3ea84aSManuel Klimek   LevelIndentTracker IndentTracker(Style, Keywords, Lines[0]->Level,
12813d3ea84aSManuel Klimek                                    AdditionalIndent);
1282e5a8f230SDarwin Xu   const AnnotatedLine *PrevPrevLine = nullptr;
12830df50938SDaniel Jasper   const AnnotatedLine *PreviousLine = nullptr;
12843d3ea84aSManuel Klimek   const AnnotatedLine *NextLine = nullptr;
1285f67c3246SDaniel Jasper 
1286f67c3246SDaniel Jasper   // The minimum level of consecutive lines that have been formatted.
1287f67c3246SDaniel Jasper   unsigned RangeMinLevel = UINT_MAX;
1288f67c3246SDaniel Jasper 
12899ad83fe7SKrasimir Georgiev   bool FirstLine = true;
12903d3ea84aSManuel Klimek   for (const AnnotatedLine *Line =
12913d3ea84aSManuel Klimek            Joiner.getNextMergedLine(DryRun, IndentTracker);
12928f6af1d4SBjörn Schäpers        Line; PrevPrevLine = PreviousLine, PreviousLine = Line, Line = NextLine,
12938f6af1d4SBjörn Schäpers                            FirstLine = false) {
1294670a721dSMarek Kurdej     assert(Line->First);
12953d3ea84aSManuel Klimek     const AnnotatedLine &TheLine = *Line;
12963d3ea84aSManuel Klimek     unsigned Indent = IndentTracker.getIndent();
1297f67c3246SDaniel Jasper 
1298f67c3246SDaniel Jasper     // We continue formatting unchanged lines to adjust their indent, e.g. if a
1299f67c3246SDaniel Jasper     // scope was added. However, we need to carefully stop doing this when we
1300f67c3246SDaniel Jasper     // exit the scope of affected lines to prevent indenting a the entire
1301f67c3246SDaniel Jasper     // remaining file if it currently missing a closing brace.
13020dddcf78SManuel Klimek     bool PreviousRBrace =
13030dddcf78SManuel Klimek         PreviousLine && PreviousLine->startsWith(tok::r_brace);
1304f67c3246SDaniel Jasper     bool ContinueFormatting =
1305f67c3246SDaniel Jasper         TheLine.Level > RangeMinLevel ||
13060dddcf78SManuel Klimek         (TheLine.Level == RangeMinLevel && !PreviousRBrace &&
13070dddcf78SManuel Klimek          !TheLine.startsWith(tok::r_brace));
1308f67c3246SDaniel Jasper 
1309f67c3246SDaniel Jasper     bool FixIndentation = (FixBadIndentation || ContinueFormatting) &&
1310a1036e5dSDaniel Jasper                           Indent != TheLine.First->OriginalColumn;
1311ec5c3db7SManuel Klimek     bool ShouldFormat = TheLine.Affected || FixIndentation;
13123d3ea84aSManuel Klimek     // We cannot format this line; if the reason is that the line had a
13133d3ea84aSManuel Klimek     // parsing error, remember that.
1314bcda54b6SKrasimir Georgiev     if (ShouldFormat && TheLine.Type == LT_Invalid && Status) {
1315bcda54b6SKrasimir Georgiev       Status->FormatComplete = false;
1316bcda54b6SKrasimir Georgiev       Status->Line =
1317bcda54b6SKrasimir Georgiev           SourceMgr.getSpellingLineNumber(TheLine.First->Tok.getLocation());
1318bcda54b6SKrasimir Georgiev     }
13193d3ea84aSManuel Klimek 
13203d3ea84aSManuel Klimek     if (ShouldFormat && TheLine.Type != LT_Invalid) {
13219ad83fe7SKrasimir Georgiev       if (!DryRun) {
1322670a721dSMarek Kurdej         bool LastLine = TheLine.First->is(tok::eof);
1323e5a8f230SDarwin Xu         formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines, Indent,
13249ad83fe7SKrasimir Georgiev                          LastLine ? LastStartColumn : NextStartColumn + Indent);
13259ad83fe7SKrasimir Georgiev       }
13260df50938SDaniel Jasper 
13273d3ea84aSManuel Klimek       NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
13283d3ea84aSManuel Klimek       unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine);
13293d3ea84aSManuel Klimek       bool FitsIntoOneLine =
13303d3ea84aSManuel Klimek           TheLine.Last->TotalLength + Indent <= ColumnLimit ||
13310cd74ee8SMartin Probst           (TheLine.Type == LT_ImportStatement &&
1332142e79b8Smydeveloperday            (!Style.isJavaScript() || !Style.JavaScriptWrapImports)) ||
1333cbb726d0SPaul Hoad           (Style.isCSharp() &&
1334cbb726d0SPaul Hoad            TheLine.InPPDirective); // don't split #regions in C#
1335bebf7bdfSowenca       if (Style.ColumnLimit == 0) {
1336d3585dbdSManuel Klimek         NoColumnLimitLineFormatter(Indenter, Whitespaces, Style, this)
13379ad83fe7SKrasimir Georgiev             .formatLine(TheLine, NextStartColumn + Indent,
13389ad83fe7SKrasimir Georgiev                         FirstLine ? FirstStartColumn : 0, DryRun);
1339bebf7bdfSowenca       } else if (FitsIntoOneLine) {
13403d3ea84aSManuel Klimek         Penalty += NoLineBreakFormatter(Indenter, Whitespaces, Style, this)
13419ad83fe7SKrasimir Georgiev                        .formatLine(TheLine, NextStartColumn + Indent,
13429ad83fe7SKrasimir Georgiev                                    FirstLine ? FirstStartColumn : 0, DryRun);
1343bebf7bdfSowenca       } else {
1344d3585dbdSManuel Klimek         Penalty += OptimizingLineFormatter(Indenter, Whitespaces, Style, this)
13459ad83fe7SKrasimir Georgiev                        .formatLine(TheLine, NextStartColumn + Indent,
13469ad83fe7SKrasimir Georgiev                                    FirstLine ? FirstStartColumn : 0, DryRun);
1347bebf7bdfSowenca       }
1348f67c3246SDaniel Jasper       RangeMinLevel = std::min(RangeMinLevel, TheLine.Level);
13493d3ea84aSManuel Klimek     } else {
13503d3ea84aSManuel Klimek       // If no token in the current line is affected, we still need to format
13513d3ea84aSManuel Klimek       // affected children.
1352bebf7bdfSowenca       if (TheLine.ChildrenAffected) {
135335ca66deSDaniel Jasper         for (const FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next)
135435ca66deSDaniel Jasper           if (!Tok->Children.empty())
135535ca66deSDaniel Jasper             format(Tok->Children, DryRun);
1356bebf7bdfSowenca       }
13570df50938SDaniel Jasper 
13583d3ea84aSManuel Klimek       // Adapt following lines on the current indent level to the same level
13593d3ea84aSManuel Klimek       // unless the current \c AnnotatedLine is not at the beginning of a line.
13603d3ea84aSManuel Klimek       bool StartsNewLine =
13613d3ea84aSManuel Klimek           TheLine.First->NewlinesBefore > 0 || TheLine.First->IsFirst;
13623d3ea84aSManuel Klimek       if (StartsNewLine)
13633d3ea84aSManuel Klimek         IndentTracker.adjustToUnmodifiedLine(TheLine);
13643d3ea84aSManuel Klimek       if (!DryRun) {
13653d3ea84aSManuel Klimek         bool ReformatLeadingWhitespace =
13663d3ea84aSManuel Klimek             StartsNewLine && ((PreviousLine && PreviousLine->Affected) ||
13673d3ea84aSManuel Klimek                               TheLine.LeadingEmptyLinesAffected);
13683d3ea84aSManuel Klimek         // Format the first token.
1369bebf7bdfSowenca         if (ReformatLeadingWhitespace) {
1370e5a8f230SDarwin Xu           formatFirstToken(TheLine, PreviousLine, PrevPrevLine, Lines,
13719ad83fe7SKrasimir Georgiev                            TheLine.First->OriginalColumn,
13727d42f3f7SDaniel Jasper                            TheLine.First->OriginalColumn);
1373bebf7bdfSowenca         } else {
13743d3ea84aSManuel Klimek           Whitespaces->addUntouchableToken(*TheLine.First,
13753d3ea84aSManuel Klimek                                            TheLine.InPPDirective);
1376bebf7bdfSowenca         }
13773d3ea84aSManuel Klimek 
13783d3ea84aSManuel Klimek         // Notify the WhitespaceManager about the unchanged whitespace.
13793d3ea84aSManuel Klimek         for (FormatToken *Tok = TheLine.First->Next; Tok; Tok = Tok->Next)
13800df50938SDaniel Jasper           Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
13810df50938SDaniel Jasper       }
13823d3ea84aSManuel Klimek       NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
1383f67c3246SDaniel Jasper       RangeMinLevel = UINT_MAX;
13840df50938SDaniel Jasper     }
1385d1c13736SDaniel Jasper     if (!DryRun)
1386d1c13736SDaniel Jasper       markFinalized(TheLine.First);
13870df50938SDaniel Jasper   }
13880df50938SDaniel Jasper   PenaltyCache[CacheKey] = Penalty;
13890df50938SDaniel Jasper   return Penalty;
13900df50938SDaniel Jasper }
13910df50938SDaniel Jasper 
formatFirstToken(const AnnotatedLine & Line,const AnnotatedLine * PreviousLine,const AnnotatedLine * PrevPrevLine,const SmallVectorImpl<AnnotatedLine * > & Lines,unsigned Indent,unsigned NewlineIndent)139262103052SKrasimir Georgiev void UnwrappedLineFormatter::formatFirstToken(
139362103052SKrasimir Georgiev     const AnnotatedLine &Line, const AnnotatedLine *PreviousLine,
1394e5a8f230SDarwin Xu     const AnnotatedLine *PrevPrevLine,
139562103052SKrasimir Georgiev     const SmallVectorImpl<AnnotatedLine *> &Lines, unsigned Indent,
13969ad83fe7SKrasimir Georgiev     unsigned NewlineIndent) {
13977d42f3f7SDaniel Jasper   FormatToken &RootToken = *Line.First;
13983d3ea84aSManuel Klimek   if (RootToken.is(tok::eof)) {
13993d3ea84aSManuel Klimek     unsigned Newlines = std::min(RootToken.NewlinesBefore, 1u);
14009ad83fe7SKrasimir Georgiev     unsigned TokenIndent = Newlines ? NewlineIndent : 0;
14019ad83fe7SKrasimir Georgiev     Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent,
14029ad83fe7SKrasimir Georgiev                                    TokenIndent);
14033d3ea84aSManuel Klimek     return;
14043d3ea84aSManuel Klimek   }
14050df50938SDaniel Jasper   unsigned Newlines =
14060df50938SDaniel Jasper       std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
14070df50938SDaniel Jasper   // Remove empty lines before "}" where applicable.
14080df50938SDaniel Jasper   if (RootToken.is(tok::r_brace) &&
14090df50938SDaniel Jasper       (!RootToken.Next ||
141062103052SKrasimir Georgiev        (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)) &&
141162103052SKrasimir Georgiev       // Do not remove empty lines before namespace closing "}".
1412bebf7bdfSowenca       !getNamespaceToken(&Line, Lines)) {
14130df50938SDaniel Jasper     Newlines = std::min(Newlines, 1u);
1414bebf7bdfSowenca   }
1415a004b3f5SMartin Probst   // Remove empty lines at the start of nested blocks (lambdas/arrow functions)
1416a004b3f5SMartin Probst   if (PreviousLine == nullptr && Line.Level > 0)
1417a004b3f5SMartin Probst     Newlines = std::min(Newlines, 1u);
14180df50938SDaniel Jasper   if (Newlines == 0 && !RootToken.IsFirst)
14190df50938SDaniel Jasper     Newlines = 1;
14200df50938SDaniel Jasper   if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
14210df50938SDaniel Jasper     Newlines = 0;
14220df50938SDaniel Jasper 
14230df50938SDaniel Jasper   // Remove empty lines after "{".
14240df50938SDaniel Jasper   if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
14250df50938SDaniel Jasper       PreviousLine->Last->is(tok::l_brace) &&
14266f3778c3SSam McCall       !PreviousLine->startsWithNamespace() &&
1427e5a8f230SDarwin Xu       !(PrevPrevLine && PrevPrevLine->startsWithNamespace() &&
1428e5a8f230SDarwin Xu         PreviousLine->startsWith(tok::l_brace)) &&
1429bebf7bdfSowenca       !startsExternCBlock(*PreviousLine)) {
14300df50938SDaniel Jasper     Newlines = 1;
1431bebf7bdfSowenca   }
14320df50938SDaniel Jasper 
143360bf5826SAlbertas Vyšniauskas   // Insert or remove empty line before access specifiers.
143460bf5826SAlbertas Vyšniauskas   if (PreviousLine && RootToken.isAccessSpecifier()) {
143560bf5826SAlbertas Vyšniauskas     switch (Style.EmptyLineBeforeAccessModifier) {
143660bf5826SAlbertas Vyšniauskas     case FormatStyle::ELBAMS_Never:
1437fd4e08aaSMax Sagebaum       if (Newlines > 1)
143860bf5826SAlbertas Vyšniauskas         Newlines = 1;
143960bf5826SAlbertas Vyšniauskas       break;
144060bf5826SAlbertas Vyšniauskas     case FormatStyle::ELBAMS_Leave:
144160bf5826SAlbertas Vyšniauskas       Newlines = std::max(RootToken.NewlinesBefore, 1u);
144260bf5826SAlbertas Vyšniauskas       break;
144360bf5826SAlbertas Vyšniauskas     case FormatStyle::ELBAMS_LogicalBlock:
1444fd4e08aaSMax Sagebaum       if (PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) && Newlines <= 1)
144560bf5826SAlbertas Vyšniauskas         Newlines = 2;
1446dda978eeSMax Sagebaum       if (PreviousLine->First->isAccessSpecifier())
1447dda978eeSMax Sagebaum         Newlines = 1; // Previous is an access modifier remove all new lines.
144860bf5826SAlbertas Vyšniauskas       break;
144960bf5826SAlbertas Vyšniauskas     case FormatStyle::ELBAMS_Always: {
145060bf5826SAlbertas Vyšniauskas       const FormatToken *previousToken;
145160bf5826SAlbertas Vyšniauskas       if (PreviousLine->Last->is(tok::comment))
145260bf5826SAlbertas Vyšniauskas         previousToken = PreviousLine->Last->getPreviousNonComment();
145360bf5826SAlbertas Vyšniauskas       else
145460bf5826SAlbertas Vyšniauskas         previousToken = PreviousLine->Last;
1455fd4e08aaSMax Sagebaum       if ((!previousToken || !previousToken->is(tok::l_brace)) && Newlines <= 1)
145660bf5826SAlbertas Vyšniauskas         Newlines = 2;
145760bf5826SAlbertas Vyšniauskas     } break;
145860bf5826SAlbertas Vyšniauskas     }
145960bf5826SAlbertas Vyšniauskas   }
14600df50938SDaniel Jasper 
1461dda978eeSMax Sagebaum   // Insert or remove empty line after access specifiers.
1462ac5c97e3SDaniel Jasper   if (PreviousLine && PreviousLine->First->isAccessSpecifier() &&
1463dda978eeSMax Sagebaum       (!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline)) {
1464dda978eeSMax Sagebaum     // EmptyLineBeforeAccessModifier is handling the case when two access
1465dda978eeSMax Sagebaum     // modifiers follow each other.
1466dda978eeSMax Sagebaum     if (!RootToken.isAccessSpecifier()) {
1467dda978eeSMax Sagebaum       switch (Style.EmptyLineAfterAccessModifier) {
1468dda978eeSMax Sagebaum       case FormatStyle::ELAAMS_Never:
1469dda978eeSMax Sagebaum         Newlines = 1;
1470dda978eeSMax Sagebaum         break;
1471dda978eeSMax Sagebaum       case FormatStyle::ELAAMS_Leave:
1472dda978eeSMax Sagebaum         Newlines = std::max(Newlines, 1u);
1473dda978eeSMax Sagebaum         break;
1474dda978eeSMax Sagebaum       case FormatStyle::ELAAMS_Always:
1475dda978eeSMax Sagebaum         if (RootToken.is(tok::r_brace)) // Do not add at end of class.
1476dda978eeSMax Sagebaum           Newlines = 1u;
1477dda978eeSMax Sagebaum         else
1478dda978eeSMax Sagebaum           Newlines = std::max(Newlines, 2u);
1479dda978eeSMax Sagebaum         break;
1480dda978eeSMax Sagebaum       }
1481dda978eeSMax Sagebaum     }
1482dda978eeSMax Sagebaum   }
14830df50938SDaniel Jasper 
14849ad83fe7SKrasimir Georgiev   if (Newlines)
14859ad83fe7SKrasimir Georgiev     Indent = NewlineIndent;
14869ad83fe7SKrasimir Georgiev 
1487f6740fe4Ssstwcw   // Preprocessor directives get indented before the hash only if specified. In
1488f6740fe4Ssstwcw   // Javascript import statements are indented like normal statements.
1489f6740fe4Ssstwcw   if (!Style.isJavaScript() &&
1490f6740fe4Ssstwcw       Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash &&
14919af03864Smydeveloperday       (Line.Type == LT_PreprocessorDirective ||
1492bebf7bdfSowenca        Line.Type == LT_ImportStatement)) {
14939ad83fe7SKrasimir Georgiev     Indent = 0;
1494bebf7bdfSowenca   }
14959ad83fe7SKrasimir Georgiev 
14967d42f3f7SDaniel Jasper   Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent,
1497e8111502Smydeveloperday                                  /*IsAligned=*/false,
14987d42f3f7SDaniel Jasper                                  Line.InPPDirective &&
14990df50938SDaniel Jasper                                      !RootToken.HasUnescapedNewline);
15000df50938SDaniel Jasper }
15010df50938SDaniel Jasper 
15023d3ea84aSManuel Klimek unsigned
getColumnLimit(bool InPPDirective,const AnnotatedLine * NextLine) const15033d3ea84aSManuel Klimek UnwrappedLineFormatter::getColumnLimit(bool InPPDirective,
15043d3ea84aSManuel Klimek                                        const AnnotatedLine *NextLine) const {
15053d3ea84aSManuel Klimek   // In preprocessor directives reserve two chars for trailing " \" if the
15063d3ea84aSManuel Klimek   // next line continues the preprocessor directive.
15073d3ea84aSManuel Klimek   bool ContinuesPPDirective =
15081a028227SDaniel Jasper       InPPDirective &&
15091a028227SDaniel Jasper       // If there is no next line, this is likely a child line and the parent
15101a028227SDaniel Jasper       // continues the preprocessor directive.
15111a028227SDaniel Jasper       (!NextLine ||
15121a028227SDaniel Jasper        (NextLine->InPPDirective &&
15133d3ea84aSManuel Klimek         // If there is an unescaped newline between this line and the next, the
15143d3ea84aSManuel Klimek         // next line starts a new preprocessor directive.
15151a028227SDaniel Jasper         !NextLine->First->HasUnescapedNewline));
15163d3ea84aSManuel Klimek   return Style.ColumnLimit - (ContinuesPPDirective ? 2 : 0);
15170df50938SDaniel Jasper }
15180df50938SDaniel Jasper 
15190df50938SDaniel Jasper } // namespace format
15200df50938SDaniel Jasper } // namespace clang
1521