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