<div dir="ltr">For what it's worth, I would find it super helpful if there were class-level comments on the classes in lib/Format that briefly describe the main responsibility of each class and explain terminology ("An unwrapped line is a $concise explanation"). There are now enough classes in lib/Format that I'm always a bit confused about this when reading this code.</div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Dec 10, 2014 at 11:00 AM, Daniel Jasper <span dir="ltr"><<a href="mailto:djasper@google.com" target="_blank">djasper@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: djasper<br>
Date: Wed Dec 10 13:00:42 2014<br>
New Revision: 223936<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=223936&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=223936&view=rev</a><br>
Log:<br>
clang-format: Factor out UnwrappedLineFormatter into a separate file.<br>
<br>
No functional changes intended.<br>
<br>
Added:<br>
cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp<br>
cfe/trunk/lib/Format/UnwrappedLineFormatter.h<br>
Modified:<br>
cfe/trunk/lib/Format/CMakeLists.txt<br>
cfe/trunk/lib/Format/Format.cpp<br>
<br>
Modified: cfe/trunk/lib/Format/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/CMakeLists.txt?rev=223936&r1=223935&r2=223936&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/CMakeLists.txt?rev=223936&r1=223935&r2=223936&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Format/CMakeLists.txt (original)<br>
+++ cfe/trunk/lib/Format/CMakeLists.txt Wed Dec 10 13:00:42 2014<br>
@@ -6,6 +6,7 @@ add_clang_library(clangFormat<br>
Format.cpp<br>
FormatToken.cpp<br>
TokenAnnotator.cpp<br>
+ UnwrappedLineFormatter.cpp<br>
UnwrappedLineParser.cpp<br>
WhitespaceManager.cpp<br>
<br>
<br>
Modified: cfe/trunk/lib/Format/Format.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=223936&r1=223935&r2=223936&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=223936&r1=223935&r2=223936&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Format/Format.cpp (original)<br>
+++ cfe/trunk/lib/Format/Format.cpp Wed Dec 10 13:00:42 2014<br>
@@ -15,6 +15,7 @@<br>
<br>
#include "ContinuationIndenter.h"<br>
#include "TokenAnnotator.h"<br>
+#include "UnwrappedLineFormatter.h"<br>
#include "UnwrappedLineParser.h"<br>
#include "WhitespaceManager.h"<br>
#include "clang/Basic/Diagnostic.h"<br>
@@ -589,779 +590,6 @@ std::string configurationAsText(const Fo<br>
<br>
namespace {<br>
<br>
-bool startsExternCBlock(const AnnotatedLine &Line) {<br>
- const FormatToken *Next = Line.First->getNextNonComment();<br>
- const FormatToken *NextNext = Next ? Next->getNextNonComment() : nullptr;<br>
- return Line.First->is(tok::kw_extern) && Next && Next->isStringLiteral() &&<br>
- NextNext && NextNext->is(tok::l_brace);<br>
-}<br>
-<br>
-class NoColumnLimitFormatter {<br>
-public:<br>
- NoColumnLimitFormatter(ContinuationIndenter *Indenter) : Indenter(Indenter) {}<br>
-<br>
- /// \brief Formats the line starting at \p State, simply keeping all of the<br>
- /// input's line breaking decisions.<br>
- void format(unsigned FirstIndent, const AnnotatedLine *Line) {<br>
- LineState State =<br>
- Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);<br>
- while (State.NextToken) {<br>
- bool Newline =<br>
- Indenter->mustBreak(State) ||<br>
- (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);<br>
- Indenter->addTokenToState(State, Newline, /*DryRun=*/false);<br>
- }<br>
- }<br>
-<br>
-private:<br>
- ContinuationIndenter *Indenter;<br>
-};<br>
-<br>
-class LineJoiner {<br>
-public:<br>
- LineJoiner(const FormatStyle &Style) : Style(Style) {}<br>
-<br>
- /// \brief Calculates how many lines can be merged into 1 starting at \p I.<br>
- unsigned<br>
- tryFitMultipleLinesInOne(unsigned Indent,<br>
- SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
- SmallVectorImpl<AnnotatedLine *>::const_iterator E) {<br>
- // We can never merge stuff if there are trailing line comments.<br>
- const AnnotatedLine *TheLine = *I;<br>
- if (TheLine->Last->is(TT_LineComment))<br>
- return 0;<br>
-<br>
- if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)<br>
- return 0;<br>
-<br>
- unsigned Limit =<br>
- Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;<br>
- // If we already exceed the column limit, we set 'Limit' to 0. The different<br>
- // tryMerge..() functions can then decide whether to still do merging.<br>
- Limit = TheLine->Last->TotalLength > Limit<br>
- ? 0<br>
- : Limit - TheLine->Last->TotalLength;<br>
-<br>
- if (I + 1 == E || I[1]->Type == LT_Invalid || I[1]->First->MustBreakBefore)<br>
- return 0;<br>
-<br>
- // FIXME: TheLine->Level != 0 might or might not be the right check to do.<br>
- // If necessary, change to something smarter.<br>
- bool MergeShortFunctions =<br>
- Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||<br>
- (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty &&<br>
- I[1]->First->is(tok::r_brace)) ||<br>
- (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&<br>
- TheLine->Level != 0);<br>
-<br>
- if (TheLine->Last->is(TT_FunctionLBrace) &&<br>
- TheLine->First != TheLine->Last) {<br>
- return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;<br>
- }<br>
- if (TheLine->Last->is(tok::l_brace)) {<br>
- return Style.BreakBeforeBraces == FormatStyle::BS_Attach<br>
- ? tryMergeSimpleBlock(I, E, Limit)<br>
- : 0;<br>
- }<br>
- if (I[1]->First->is(TT_FunctionLBrace) &&<br>
- Style.BreakBeforeBraces != FormatStyle::BS_Attach) {<br>
- if (I[1]->Last->is(TT_LineComment))<br>
- return 0;<br>
-<br>
- // Check for Limit <= 2 to account for the " {".<br>
- if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))<br>
- return 0;<br>
- Limit -= 2;<br>
-<br>
- unsigned MergedLines = 0;<br>
- if (MergeShortFunctions) {<br>
- MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);<br>
- // If we managed to merge the block, count the function header, which is<br>
- // on a separate line.<br>
- if (MergedLines > 0)<br>
- ++MergedLines;<br>
- }<br>
- return MergedLines;<br>
- }<br>
- if (TheLine->First->is(tok::kw_if)) {<br>
- return Style.AllowShortIfStatementsOnASingleLine<br>
- ? tryMergeSimpleControlStatement(I, E, Limit)<br>
- : 0;<br>
- }<br>
- if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {<br>
- return Style.AllowShortLoopsOnASingleLine<br>
- ? tryMergeSimpleControlStatement(I, E, Limit)<br>
- : 0;<br>
- }<br>
- if (TheLine->First->isOneOf(tok::kw_case, tok::kw_default)) {<br>
- return Style.AllowShortCaseLabelsOnASingleLine<br>
- ? tryMergeShortCaseLabels(I, E, Limit)<br>
- : 0;<br>
- }<br>
- if (TheLine->InPPDirective &&<br>
- (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {<br>
- return tryMergeSimplePPDirective(I, E, Limit);<br>
- }<br>
- return 0;<br>
- }<br>
-<br>
-private:<br>
- unsigned<br>
- tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,<br>
- unsigned Limit) {<br>
- if (Limit == 0)<br>
- return 0;<br>
- if (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline)<br>
- return 0;<br>
- if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)<br>
- return 0;<br>
- if (1 + I[1]->Last->TotalLength > Limit)<br>
- return 0;<br>
- return 1;<br>
- }<br>
-<br>
- unsigned tryMergeSimpleControlStatement(<br>
- SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
- SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {<br>
- if (Limit == 0)<br>
- return 0;<br>
- if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||<br>
- Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&<br>
- (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))<br>
- return 0;<br>
- if (I[1]->InPPDirective != (*I)->InPPDirective ||<br>
- (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))<br>
- return 0;<br>
- Limit = limitConsideringMacros(I + 1, E, Limit);<br>
- AnnotatedLine &Line = **I;<br>
- if (Line.Last->isNot(tok::r_paren))<br>
- return 0;<br>
- if (1 + I[1]->Last->TotalLength > Limit)<br>
- return 0;<br>
- if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,<br>
- tok::kw_while, TT_LineComment))<br>
- return 0;<br>
- // Only inline simple if's (no nested if or else).<br>
- if (I + 2 != E && Line.First->is(tok::kw_if) &&<br>
- I[2]->First->is(tok::kw_else))<br>
- return 0;<br>
- return 1;<br>
- }<br>
-<br>
- unsigned tryMergeShortCaseLabels(<br>
- SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
- SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {<br>
- if (Limit == 0 || I + 1 == E ||<br>
- I[1]->First->isOneOf(tok::kw_case, tok::kw_default))<br>
- return 0;<br>
- unsigned NumStmts = 0;<br>
- unsigned Length = 0;<br>
- bool InPPDirective = I[0]->InPPDirective;<br>
- for (; NumStmts < 3; ++NumStmts) {<br>
- if (I + 1 + NumStmts == E)<br>
- break;<br>
- const AnnotatedLine *Line = I[1 + NumStmts];<br>
- if (Line->InPPDirective != InPPDirective)<br>
- break;<br>
- if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))<br>
- break;<br>
- if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,<br>
- tok::kw_while, tok::comment))<br>
- return 0;<br>
- Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the space.<br>
- }<br>
- if (NumStmts == 0 || NumStmts == 3 || Length > Limit)<br>
- return 0;<br>
- return NumStmts;<br>
- }<br>
-<br>
- unsigned<br>
- tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,<br>
- unsigned Limit) {<br>
- AnnotatedLine &Line = **I;<br>
-<br>
- // Don't merge ObjC @ keywords and methods.<br>
- if (Style.Language != FormatStyle::LK_Java &&<br>
- Line.First->isOneOf(tok::at, tok::minus, tok::plus))<br>
- return 0;<br>
-<br>
- // Check that the current line allows merging. This depends on whether we<br>
- // are in a control flow statements as well as several style flags.<br>
- if (Line.First->isOneOf(tok::kw_else, tok::kw_case))<br>
- return 0;<br>
- if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,<br>
- tok::kw_catch, tok::kw_for, tok::r_brace)) {<br>
- if (!Style.AllowShortBlocksOnASingleLine)<br>
- return 0;<br>
- if (!Style.AllowShortIfStatementsOnASingleLine &&<br>
- Line.First->is(tok::kw_if))<br>
- return 0;<br>
- if (!Style.AllowShortLoopsOnASingleLine &&<br>
- Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))<br>
- return 0;<br>
- // FIXME: Consider an option to allow short exception handling clauses on<br>
- // a single line.<br>
- if (Line.First->isOneOf(tok::kw_try, tok::kw_catch))<br>
- return 0;<br>
- }<br>
-<br>
- FormatToken *Tok = I[1]->First;<br>
- if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&<br>
- (Tok->getNextNonComment() == nullptr ||<br>
- Tok->getNextNonComment()->is(tok::semi))) {<br>
- // We merge empty blocks even if the line exceeds the column limit.<br>
- Tok->SpacesRequiredBefore = 0;<br>
- Tok->CanBreakBefore = true;<br>
- return 1;<br>
- } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace) &&<br>
- !startsExternCBlock(Line)) {<br>
- // We don't merge short records.<br>
- if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct))<br>
- return 0;<br>
-<br>
- // Check that we still have three lines and they fit into the limit.<br>
- if (I + 2 == E || I[2]->Type == LT_Invalid)<br>
- return 0;<br>
- Limit = limitConsideringMacros(I + 2, E, Limit);<br>
-<br>
- if (!nextTwoLinesFitInto(I, Limit))<br>
- return 0;<br>
-<br>
- // Second, check that the next line does not contain any braces - if it<br>
- // does, readability declines when putting it into a single line.<br>
- if (I[1]->Last->is(TT_LineComment))<br>
- return 0;<br>
- do {<br>
- if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)<br>
- return 0;<br>
- Tok = Tok->Next;<br>
- } while (Tok);<br>
-<br>
- // Last, check that the third line starts with a closing brace.<br>
- Tok = I[2]->First;<br>
- if (Tok->isNot(tok::r_brace))<br>
- return 0;<br>
-<br>
- return 2;<br>
- }<br>
- return 0;<br>
- }<br>
-<br>
- /// Returns the modified column limit for \p I if it is inside a macro and<br>
- /// needs a trailing '\'.<br>
- unsigned<br>
- limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,<br>
- unsigned Limit) {<br>
- if (I[0]->InPPDirective && I + 1 != E &&<br>
- !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {<br>
- return Limit < 2 ? 0 : Limit - 2;<br>
- }<br>
- return Limit;<br>
- }<br>
-<br>
- bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
- unsigned Limit) {<br>
- if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)<br>
- return false;<br>
- return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;<br>
- }<br>
-<br>
- bool containsMustBreak(const AnnotatedLine *Line) {<br>
- for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {<br>
- if (Tok->MustBreakBefore)<br>
- return true;<br>
- }<br>
- return false;<br>
- }<br>
-<br>
- const FormatStyle &Style;<br>
-};<br>
-<br>
-class UnwrappedLineFormatter {<br>
-public:<br>
- UnwrappedLineFormatter(ContinuationIndenter *Indenter,<br>
- WhitespaceManager *Whitespaces,<br>
- const FormatStyle &Style)<br>
- : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),<br>
- Joiner(Style) {}<br>
-<br>
- unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,<br>
- int AdditionalIndent = 0, bool FixBadIndentation = false) {<br>
- // Try to look up already computed penalty in DryRun-mode.<br>
- std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(<br>
- &Lines, AdditionalIndent);<br>
- auto CacheIt = PenaltyCache.find(CacheKey);<br>
- if (DryRun && CacheIt != PenaltyCache.end())<br>
- return CacheIt->second;<br>
-<br>
- assert(!Lines.empty());<br>
- unsigned Penalty = 0;<br>
- std::vector<int> IndentForLevel;<br>
- for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)<br>
- IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);<br>
- const AnnotatedLine *PreviousLine = nullptr;<br>
- for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),<br>
- E = Lines.end();<br>
- I != E; ++I) {<br>
- const AnnotatedLine &TheLine = **I;<br>
- const FormatToken *FirstTok = TheLine.First;<br>
- int Offset = getIndentOffset(*FirstTok);<br>
-<br>
- // Determine indent and try to merge multiple unwrapped lines.<br>
- unsigned Indent;<br>
- if (TheLine.InPPDirective) {<br>
- Indent = TheLine.Level * Style.IndentWidth;<br>
- } else {<br>
- while (IndentForLevel.size() <= TheLine.Level)<br>
- IndentForLevel.push_back(-1);<br>
- IndentForLevel.resize(TheLine.Level + 1);<br>
- Indent = getIndent(IndentForLevel, TheLine.Level);<br>
- }<br>
- unsigned LevelIndent = Indent;<br>
- if (static_cast<int>(Indent) + Offset >= 0)<br>
- Indent += Offset;<br>
-<br>
- // Merge multiple lines if possible.<br>
- unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E);<br>
- if (MergedLines > 0 && Style.ColumnLimit == 0) {<br>
- // Disallow line merging if there is a break at the start of one of the<br>
- // input lines.<br>
- for (unsigned i = 0; i < MergedLines; ++i) {<br>
- if (I[i + 1]->First->NewlinesBefore > 0)<br>
- MergedLines = 0;<br>
- }<br>
- }<br>
- if (!DryRun) {<br>
- for (unsigned i = 0; i < MergedLines; ++i) {<br>
- join(*I[i], *I[i + 1]);<br>
- }<br>
- }<br>
- I += MergedLines;<br>
-<br>
- bool FixIndentation =<br>
- FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);<br>
- if (TheLine.First->is(tok::eof)) {<br>
- if (PreviousLine && PreviousLine->Affected && !DryRun) {<br>
- // Remove the file's trailing whitespace.<br>
- unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);<br>
- Whitespaces->replaceWhitespace(*TheLine.First, Newlines,<br>
- /*IndentLevel=*/0, /*Spaces=*/0,<br>
- /*TargetColumn=*/0);<br>
- }<br>
- } else if (TheLine.Type != LT_Invalid &&<br>
- (TheLine.Affected || FixIndentation)) {<br>
- if (FirstTok->WhitespaceRange.isValid()) {<br>
- if (!DryRun)<br>
- formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level,<br>
- Indent, TheLine.InPPDirective);<br>
- } else {<br>
- Indent = LevelIndent = FirstTok->OriginalColumn;<br>
- }<br>
-<br>
- // If everything fits on a single line, just put it there.<br>
- unsigned ColumnLimit = Style.ColumnLimit;<br>
- if (I + 1 != E) {<br>
- AnnotatedLine *NextLine = I[1];<br>
- if (NextLine->InPPDirective && !NextLine->First->HasUnescapedNewline)<br>
- ColumnLimit = getColumnLimit(TheLine.InPPDirective);<br>
- }<br>
-<br>
- if (TheLine.Last->TotalLength + Indent <= ColumnLimit ||<br>
- TheLine.Type == LT_ImportStatement) {<br>
- LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun);<br>
- while (State.NextToken) {<br>
- formatChildren(State, /*Newline=*/false, /*DryRun=*/false, Penalty);<br>
- Indenter->addTokenToState(State, /*Newline=*/false, DryRun);<br>
- }<br>
- } else if (Style.ColumnLimit == 0) {<br>
- // FIXME: Implement nested blocks for ColumnLimit = 0.<br>
- NoColumnLimitFormatter Formatter(Indenter);<br>
- if (!DryRun)<br>
- Formatter.format(Indent, &TheLine);<br>
- } else {<br>
- Penalty += format(TheLine, Indent, DryRun);<br>
- }<br>
-<br>
- if (!TheLine.InPPDirective)<br>
- IndentForLevel[TheLine.Level] = LevelIndent;<br>
- } else if (TheLine.ChildrenAffected) {<br>
- format(TheLine.Children, DryRun);<br>
- } else {<br>
- // Format the first token if necessary, and notify the WhitespaceManager<br>
- // about the unchanged whitespace.<br>
- for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {<br>
- if (Tok == TheLine.First &&<br>
- (Tok->NewlinesBefore > 0 || Tok->IsFirst)) {<br>
- unsigned LevelIndent = Tok->OriginalColumn;<br>
- if (!DryRun) {<br>
- // Remove trailing whitespace of the previous line.<br>
- if ((PreviousLine && PreviousLine->Affected) ||<br>
- TheLine.LeadingEmptyLinesAffected) {<br>
- formatFirstToken(*Tok, PreviousLine, TheLine.Level, LevelIndent,<br>
- TheLine.InPPDirective);<br>
- } else {<br>
- Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);<br>
- }<br>
- }<br>
-<br>
- if (static_cast<int>(LevelIndent) - Offset >= 0)<br>
- LevelIndent -= Offset;<br>
- if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)<br>
- IndentForLevel[TheLine.Level] = LevelIndent;<br>
- } else if (!DryRun) {<br>
- Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);<br>
- }<br>
- }<br>
- }<br>
- if (!DryRun) {<br>
- for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {<br>
- Tok->Finalized = true;<br>
- }<br>
- }<br>
- PreviousLine = *I;<br>
- }<br>
- PenaltyCache[CacheKey] = Penalty;<br>
- return Penalty;<br>
- }<br>
-<br>
-private:<br>
- /// \brief Formats an \c AnnotatedLine and returns the penalty.<br>
- ///<br>
- /// If \p DryRun is \c false, directly applies the changes.<br>
- unsigned format(const AnnotatedLine &Line, unsigned FirstIndent,<br>
- bool DryRun) {<br>
- LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);<br>
-<br>
- // If the ObjC method declaration does not fit on a line, we should format<br>
- // it with one arg per line.<br>
- if (State.Line->Type == LT_ObjCMethodDecl)<br>
- State.Stack.back().BreakBeforeParameter = true;<br>
-<br>
- // Find best solution in solution space.<br>
- return analyzeSolutionSpace(State, DryRun);<br>
- }<br>
-<br>
- /// \brief An edge in the solution space from \c Previous->State to \c State,<br>
- /// inserting a newline dependent on the \c NewLine.<br>
- struct StateNode {<br>
- StateNode(const LineState &State, bool NewLine, StateNode *Previous)<br>
- : State(State), NewLine(NewLine), Previous(Previous) {}<br>
- LineState State;<br>
- bool NewLine;<br>
- StateNode *Previous;<br>
- };<br>
-<br>
- /// \brief A pair of <penalty, count> that is used to prioritize the BFS on.<br>
- ///<br>
- /// In case of equal penalties, we want to prefer states that were inserted<br>
- /// first. During state generation we make sure that we insert states first<br>
- /// that break the line as late as possible.<br>
- typedef std::pair<unsigned, unsigned> OrderedPenalty;<br>
-<br>
- /// \brief An item in the prioritized BFS search queue. The \c StateNode's<br>
- /// \c State has the given \c OrderedPenalty.<br>
- typedef std::pair<OrderedPenalty, StateNode *> QueueItem;<br>
-<br>
- /// \brief The BFS queue type.<br>
- typedef std::priority_queue<QueueItem, std::vector<QueueItem>,<br>
- std::greater<QueueItem> > QueueType;<br>
-<br>
- /// \brief Get the offset of the line relatively to the level.<br>
- ///<br>
- /// For example, 'public:' labels in classes are offset by 1 or 2<br>
- /// characters to the left from their level.<br>
- int getIndentOffset(const FormatToken &RootToken) {<br>
- if (Style.Language == FormatStyle::LK_Java)<br>
- return 0;<br>
- if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())<br>
- return Style.AccessModifierOffset;<br>
- return 0;<br>
- }<br>
-<br>
- /// \brief Add a new line and the required indent before the first Token<br>
- /// of the \c UnwrappedLine if there was no structural parsing error.<br>
- void formatFirstToken(FormatToken &RootToken,<br>
- const AnnotatedLine *PreviousLine, unsigned IndentLevel,<br>
- unsigned Indent, bool InPPDirective) {<br>
- unsigned Newlines =<br>
- std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);<br>
- // Remove empty lines before "}" where applicable.<br>
- if (RootToken.is(tok::r_brace) &&<br>
- (!RootToken.Next ||<br>
- (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))<br>
- Newlines = std::min(Newlines, 1u);<br>
- if (Newlines == 0 && !RootToken.IsFirst)<br>
- Newlines = 1;<br>
- if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)<br>
- Newlines = 0;<br>
-<br>
- // Remove empty lines after "{".<br>
- if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&<br>
- PreviousLine->Last->is(tok::l_brace) &&<br>
- PreviousLine->First->isNot(tok::kw_namespace) &&<br>
- !startsExternCBlock(*PreviousLine))<br>
- Newlines = 1;<br>
-<br>
- // Insert extra new line before access specifiers.<br>
- if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&<br>
- RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)<br>
- ++Newlines;<br>
-<br>
- // Remove empty lines after access specifiers.<br>
- if (PreviousLine && PreviousLine->First->isAccessSpecifier())<br>
- Newlines = std::min(1u, Newlines);<br>
-<br>
- Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,<br>
- Indent, InPPDirective &&<br>
- !RootToken.HasUnescapedNewline);<br>
- }<br>
-<br>
- /// \brief Get the indent of \p Level from \p IndentForLevel.<br>
- ///<br>
- /// \p IndentForLevel must contain the indent for the level \c l<br>
- /// at \p IndentForLevel[l], or a value < 0 if the indent for<br>
- /// that level is unknown.<br>
- unsigned getIndent(ArrayRef<int> IndentForLevel, unsigned Level) {<br>
- if (IndentForLevel[Level] != -1)<br>
- return IndentForLevel[Level];<br>
- if (Level == 0)<br>
- return 0;<br>
- return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;<br>
- }<br>
-<br>
- void join(AnnotatedLine &A, const AnnotatedLine &B) {<br>
- assert(!A.Last->Next);<br>
- assert(!B.First->Previous);<br>
- if (B.Affected)<br>
- A.Affected = true;<br>
- A.Last->Next = B.First;<br>
- B.First->Previous = A.Last;<br>
- B.First->CanBreakBefore = true;<br>
- unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;<br>
- for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {<br>
- Tok->TotalLength += LengthA;<br>
- A.Last = Tok;<br>
- }<br>
- }<br>
-<br>
- unsigned getColumnLimit(bool InPPDirective) const {<br>
- // In preprocessor directives reserve two chars for trailing " \"<br>
- return Style.ColumnLimit - (InPPDirective ? 2 : 0);<br>
- }<br>
-<br>
- struct CompareLineStatePointers {<br>
- bool operator()(LineState *obj1, LineState *obj2) const {<br>
- return *obj1 < *obj2;<br>
- }<br>
- };<br>
-<br>
- /// \brief Analyze the entire solution space starting from \p InitialState.<br>
- ///<br>
- /// This implements a variant of Dijkstra's algorithm on the graph that spans<br>
- /// the solution space (\c LineStates are the nodes). The algorithm tries to<br>
- /// find the shortest path (the one with lowest penalty) from \p InitialState<br>
- /// to a state where all tokens are placed. Returns the penalty.<br>
- ///<br>
- /// If \p DryRun is \c false, directly applies the changes.<br>
- unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false) {<br>
- std::set<LineState *, CompareLineStatePointers> Seen;<br>
-<br>
- // Increasing count of \c StateNode items we have created. This is used to<br>
- // create a deterministic order independent of the container.<br>
- unsigned Count = 0;<br>
- QueueType Queue;<br>
-<br>
- // Insert start element into queue.<br>
- StateNode *Node =<br>
- new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);<br>
- Queue.push(QueueItem(OrderedPenalty(0, Count), Node));<br>
- ++Count;<br>
-<br>
- unsigned Penalty = 0;<br>
-<br>
- // While not empty, take first element and follow edges.<br>
- while (!Queue.empty()) {<br>
- Penalty = Queue.top().first.first;<br>
- StateNode *Node = Queue.top().second;<br>
- if (!Node->State.NextToken) {<br>
- DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");<br>
- break;<br>
- }<br>
- Queue.pop();<br>
-<br>
- // Cut off the analysis of certain solutions if the analysis gets too<br>
- // complex. See description of IgnoreStackForComparison.<br>
- if (Count > 10000)<br>
- Node->State.IgnoreStackForComparison = true;<br>
-<br>
- if (!Seen.insert(&Node->State).second)<br>
- // State already examined with lower penalty.<br>
- continue;<br>
-<br>
- FormatDecision LastFormat = Node->State.NextToken->Decision;<br>
- if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)<br>
- addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue);<br>
- if (LastFormat == FD_Unformatted || LastFormat == FD_Break)<br>
- addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue);<br>
- }<br>
-<br>
- if (Queue.empty()) {<br>
- // We were unable to find a solution, do nothing.<br>
- // FIXME: Add diagnostic?<br>
- DEBUG(llvm::dbgs() << "Could not find a solution.\n");<br>
- return 0;<br>
- }<br>
-<br>
- // Reconstruct the solution.<br>
- if (!DryRun)<br>
- reconstructPath(InitialState, Queue.top().second);<br>
-<br>
- DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count << "\n");<br>
- DEBUG(llvm::dbgs() << "---\n");<br>
-<br>
- return Penalty;<br>
- }<br>
-<br>
- void reconstructPath(LineState &State, StateNode *Current) {<br>
- std::deque<StateNode *> Path;<br>
- // We do not need a break before the initial token.<br>
- while (Current->Previous) {<br>
- Path.push_front(Current);<br>
- Current = Current->Previous;<br>
- }<br>
- for (std::deque<StateNode *>::iterator I = Path.begin(), E = Path.end();<br>
- I != E; ++I) {<br>
- unsigned Penalty = 0;<br>
- formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);<br>
- Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);<br>
-<br>
- DEBUG({<br>
- if ((*I)->NewLine) {<br>
- llvm::dbgs() << "Penalty for placing "<br>
- << (*I)->Previous->State.NextToken->Tok.getName() << ": "<br>
- << Penalty << "\n";<br>
- }<br>
- });<br>
- }<br>
- }<br>
-<br>
- /// \brief Add the following state to the analysis queue \c Queue.<br>
- ///<br>
- /// Assume the current state is \p PreviousNode and has been reached with a<br>
- /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.<br>
- void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,<br>
- bool NewLine, unsigned *Count, QueueType *Queue) {<br>
- if (NewLine && !Indenter->canBreak(PreviousNode->State))<br>
- return;<br>
- if (!NewLine && Indenter->mustBreak(PreviousNode->State))<br>
- return;<br>
-<br>
- StateNode *Node = new (Allocator.Allocate())<br>
- StateNode(PreviousNode->State, NewLine, PreviousNode);<br>
- if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))<br>
- return;<br>
-<br>
- Penalty += Indenter->addTokenToState(Node->State, NewLine, true);<br>
-<br>
- Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));<br>
- ++(*Count);<br>
- }<br>
-<br>
- /// \brief If the \p State's next token is an r_brace closing a nested block,<br>
- /// format the nested block before it.<br>
- ///<br>
- /// Returns \c true if all children could be placed successfully and adapts<br>
- /// \p Penalty as well as \p State. If \p DryRun is false, also directly<br>
- /// creates changes using \c Whitespaces.<br>
- ///<br>
- /// The crucial idea here is that children always get formatted upon<br>
- /// encountering the closing brace right after the nested block. Now, if we<br>
- /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is<br>
- /// \c false), the entire block has to be kept on the same line (which is only<br>
- /// possible if it fits on the line, only contains a single statement, etc.<br>
- ///<br>
- /// If \p NewLine is true, we format the nested block on separate lines, i.e.<br>
- /// break after the "{", format all lines with correct indentation and the put<br>
- /// the closing "}" on yet another new line.<br>
- ///<br>
- /// This enables us to keep the simple structure of the<br>
- /// \c UnwrappedLineFormatter, where we only have two options for each token:<br>
- /// break or don't break.<br>
- bool formatChildren(LineState &State, bool NewLine, bool DryRun,<br>
- unsigned &Penalty) {<br>
- FormatToken &Previous = *State.NextToken->Previous;<br>
- const FormatToken *LBrace = State.NextToken->getPreviousNonComment();<br>
- if (!LBrace || LBrace->isNot(tok::l_brace) ||<br>
- LBrace->BlockKind != BK_Block || Previous.Children.size() == 0)<br>
- // The previous token does not open a block. Nothing to do. We don't<br>
- // assert so that we can simply call this function for all tokens.<br>
- return true;<br>
-<br>
- if (NewLine) {<br>
- int AdditionalIndent =<br>
- State.FirstIndent - State.Line->Level * Style.IndentWidth;<br>
- if (State.Stack.size() < 2 ||<br>
- !State.Stack[State.Stack.size() - 2].NestedBlockInlined) {<br>
- AdditionalIndent = State.Stack.back().Indent -<br>
- Previous.Children[0]->Level * Style.IndentWidth;<br>
- }<br>
-<br>
- Penalty += format(Previous.Children, DryRun, AdditionalIndent,<br>
- /*FixBadIndentation=*/true);<br>
- return true;<br>
- }<br>
-<br>
- if (Previous.Children[0]->First->MustBreakBefore)<br>
- return false;<br>
-<br>
- // Cannot merge multiple statements into a single line.<br>
- if (Previous.Children.size() > 1)<br>
- return false;<br>
-<br>
- // Cannot merge into one line if this line ends on a comment.<br>
- if (Previous.is(tok::comment))<br>
- return false;<br>
-<br>
- // We can't put the closing "}" on a line with a trailing comment.<br>
- if (Previous.Children[0]->Last->isTrailingComment())<br>
- return false;<br>
-<br>
- // If the child line exceeds the column limit, we wouldn't want to merge it.<br>
- // We add +2 for the trailing " }".<br>
- if (Style.ColumnLimit > 0 &&<br>
- Previous.Children[0]->Last->TotalLength + State.Column + 2 ><br>
- Style.ColumnLimit)<br>
- return false;<br>
-<br>
- if (!DryRun) {<br>
- Whitespaces->replaceWhitespace(<br>
- *Previous.Children[0]->First,<br>
- /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,<br>
- /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);<br>
- }<br>
- Penalty += format(*Previous.Children[0], State.Column + 1, DryRun);<br>
-<br>
- State.Column += 1 + Previous.Children[0]->Last->TotalLength;<br>
- return true;<br>
- }<br>
-<br>
- ContinuationIndenter *Indenter;<br>
- WhitespaceManager *Whitespaces;<br>
- FormatStyle Style;<br>
- LineJoiner Joiner;<br>
-<br>
- llvm::SpecificBumpPtrAllocator<StateNode> Allocator;<br>
-<br>
- // Cache to store the penalty of formatting a vector of AnnotatedLines<br>
- // starting from a specific additional offset. Improves performance if there<br>
- // are many nested blocks.<br>
- std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,<br>
- unsigned> PenaltyCache;<br>
-};<br>
-<br>
class FormatTokenLexer {<br>
public:<br>
FormatTokenLexer(SourceManager &SourceMgr, FileID ID, FormatStyle &Style,<br>
<br>
Added: cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp?rev=223936&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp?rev=223936&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp (added)<br>
+++ cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp Wed Dec 10 13:00:42 2014<br>
@@ -0,0 +1,699 @@<br>
+//===--- UnwrappedLineFormatter.cpp - Format C++ code ---------------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "UnwrappedLineFormatter.h"<br>
+#include "WhitespaceManager.h"<br>
+#include "llvm/Support/Debug.h"<br>
+<br>
+#define DEBUG_TYPE "format-formatter"<br>
+<br>
+namespace clang {<br>
+namespace format {<br>
+<br>
+namespace {<br>
+<br>
+bool startsExternCBlock(const AnnotatedLine &Line) {<br>
+ const FormatToken *Next = Line.First->getNextNonComment();<br>
+ const FormatToken *NextNext = Next ? Next->getNextNonComment() : nullptr;<br>
+ return Line.First->is(tok::kw_extern) && Next && Next->isStringLiteral() &&<br>
+ NextNext && NextNext->is(tok::l_brace);<br>
+}<br>
+<br>
+class LineJoiner {<br>
+public:<br>
+ LineJoiner(const FormatStyle &Style) : Style(Style) {}<br>
+<br>
+ /// \brief Calculates how many lines can be merged into 1 starting at \p I.<br>
+ unsigned<br>
+ tryFitMultipleLinesInOne(unsigned Indent,<br>
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E) {<br>
+ // We can never merge stuff if there are trailing line comments.<br>
+ const AnnotatedLine *TheLine = *I;<br>
+ if (TheLine->Last->is(TT_LineComment))<br>
+ return 0;<br>
+<br>
+ if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)<br>
+ return 0;<br>
+<br>
+ unsigned Limit =<br>
+ Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;<br>
+ // If we already exceed the column limit, we set 'Limit' to 0. The different<br>
+ // tryMerge..() functions can then decide whether to still do merging.<br>
+ Limit = TheLine->Last->TotalLength > Limit<br>
+ ? 0<br>
+ : Limit - TheLine->Last->TotalLength;<br>
+<br>
+ if (I + 1 == E || I[1]->Type == LT_Invalid || I[1]->First->MustBreakBefore)<br>
+ return 0;<br>
+<br>
+ // FIXME: TheLine->Level != 0 might or might not be the right check to do.<br>
+ // If necessary, change to something smarter.<br>
+ bool MergeShortFunctions =<br>
+ Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||<br>
+ (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty &&<br>
+ I[1]->First->is(tok::r_brace)) ||<br>
+ (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&<br>
+ TheLine->Level != 0);<br>
+<br>
+ if (TheLine->Last->is(TT_FunctionLBrace) &&<br>
+ TheLine->First != TheLine->Last) {<br>
+ return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;<br>
+ }<br>
+ if (TheLine->Last->is(tok::l_brace)) {<br>
+ return Style.BreakBeforeBraces == FormatStyle::BS_Attach<br>
+ ? tryMergeSimpleBlock(I, E, Limit)<br>
+ : 0;<br>
+ }<br>
+ if (I[1]->First->is(TT_FunctionLBrace) &&<br>
+ Style.BreakBeforeBraces != FormatStyle::BS_Attach) {<br>
+ if (I[1]->Last->is(TT_LineComment))<br>
+ return 0;<br>
+<br>
+ // Check for Limit <= 2 to account for the " {".<br>
+ if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))<br>
+ return 0;<br>
+ Limit -= 2;<br>
+<br>
+ unsigned MergedLines = 0;<br>
+ if (MergeShortFunctions) {<br>
+ MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);<br>
+ // If we managed to merge the block, count the function header, which is<br>
+ // on a separate line.<br>
+ if (MergedLines > 0)<br>
+ ++MergedLines;<br>
+ }<br>
+ return MergedLines;<br>
+ }<br>
+ if (TheLine->First->is(tok::kw_if)) {<br>
+ return Style.AllowShortIfStatementsOnASingleLine<br>
+ ? tryMergeSimpleControlStatement(I, E, Limit)<br>
+ : 0;<br>
+ }<br>
+ if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {<br>
+ return Style.AllowShortLoopsOnASingleLine<br>
+ ? tryMergeSimpleControlStatement(I, E, Limit)<br>
+ : 0;<br>
+ }<br>
+ if (TheLine->First->isOneOf(tok::kw_case, tok::kw_default)) {<br>
+ return Style.AllowShortCaseLabelsOnASingleLine<br>
+ ? tryMergeShortCaseLabels(I, E, Limit)<br>
+ : 0;<br>
+ }<br>
+ if (TheLine->InPPDirective &&<br>
+ (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {<br>
+ return tryMergeSimplePPDirective(I, E, Limit);<br>
+ }<br>
+ return 0;<br>
+ }<br>
+<br>
+private:<br>
+ unsigned<br>
+ tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,<br>
+ unsigned Limit) {<br>
+ if (Limit == 0)<br>
+ return 0;<br>
+ if (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline)<br>
+ return 0;<br>
+ if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)<br>
+ return 0;<br>
+ if (1 + I[1]->Last->TotalLength > Limit)<br>
+ return 0;<br>
+ return 1;<br>
+ }<br>
+<br>
+ unsigned tryMergeSimpleControlStatement(<br>
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {<br>
+ if (Limit == 0)<br>
+ return 0;<br>
+ if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||<br>
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&<br>
+ (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))<br>
+ return 0;<br>
+ if (I[1]->InPPDirective != (*I)->InPPDirective ||<br>
+ (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))<br>
+ return 0;<br>
+ Limit = limitConsideringMacros(I + 1, E, Limit);<br>
+ AnnotatedLine &Line = **I;<br>
+ if (Line.Last->isNot(tok::r_paren))<br>
+ return 0;<br>
+ if (1 + I[1]->Last->TotalLength > Limit)<br>
+ return 0;<br>
+ if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,<br>
+ tok::kw_while, TT_LineComment))<br>
+ return 0;<br>
+ // Only inline simple if's (no nested if or else).<br>
+ if (I + 2 != E && Line.First->is(tok::kw_if) &&<br>
+ I[2]->First->is(tok::kw_else))<br>
+ return 0;<br>
+ return 1;<br>
+ }<br>
+<br>
+ unsigned tryMergeShortCaseLabels(<br>
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {<br>
+ if (Limit == 0 || I + 1 == E ||<br>
+ I[1]->First->isOneOf(tok::kw_case, tok::kw_default))<br>
+ return 0;<br>
+ unsigned NumStmts = 0;<br>
+ unsigned Length = 0;<br>
+ bool InPPDirective = I[0]->InPPDirective;<br>
+ for (; NumStmts < 3; ++NumStmts) {<br>
+ if (I + 1 + NumStmts == E)<br>
+ break;<br>
+ const AnnotatedLine *Line = I[1 + NumStmts];<br>
+ if (Line->InPPDirective != InPPDirective)<br>
+ break;<br>
+ if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))<br>
+ break;<br>
+ if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,<br>
+ tok::kw_while, tok::comment))<br>
+ return 0;<br>
+ Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the space.<br>
+ }<br>
+ if (NumStmts == 0 || NumStmts == 3 || Length > Limit)<br>
+ return 0;<br>
+ return NumStmts;<br>
+ }<br>
+<br>
+ unsigned<br>
+ tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,<br>
+ unsigned Limit) {<br>
+ AnnotatedLine &Line = **I;<br>
+<br>
+ // Don't merge ObjC @ keywords and methods.<br>
+ if (Style.Language != FormatStyle::LK_Java &&<br>
+ Line.First->isOneOf(tok::at, tok::minus, tok::plus))<br>
+ return 0;<br>
+<br>
+ // Check that the current line allows merging. This depends on whether we<br>
+ // are in a control flow statements as well as several style flags.<br>
+ if (Line.First->isOneOf(tok::kw_else, tok::kw_case))<br>
+ return 0;<br>
+ if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,<br>
+ tok::kw_catch, tok::kw_for, tok::r_brace)) {<br>
+ if (!Style.AllowShortBlocksOnASingleLine)<br>
+ return 0;<br>
+ if (!Style.AllowShortIfStatementsOnASingleLine &&<br>
+ Line.First->is(tok::kw_if))<br>
+ return 0;<br>
+ if (!Style.AllowShortLoopsOnASingleLine &&<br>
+ Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))<br>
+ return 0;<br>
+ // FIXME: Consider an option to allow short exception handling clauses on<br>
+ // a single line.<br>
+ if (Line.First->isOneOf(tok::kw_try, tok::kw_catch))<br>
+ return 0;<br>
+ }<br>
+<br>
+ FormatToken *Tok = I[1]->First;<br>
+ if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&<br>
+ (Tok->getNextNonComment() == nullptr ||<br>
+ Tok->getNextNonComment()->is(tok::semi))) {<br>
+ // We merge empty blocks even if the line exceeds the column limit.<br>
+ Tok->SpacesRequiredBefore = 0;<br>
+ Tok->CanBreakBefore = true;<br>
+ return 1;<br>
+ } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace) &&<br>
+ !startsExternCBlock(Line)) {<br>
+ // We don't merge short records.<br>
+ if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct))<br>
+ return 0;<br>
+<br>
+ // Check that we still have three lines and they fit into the limit.<br>
+ if (I + 2 == E || I[2]->Type == LT_Invalid)<br>
+ return 0;<br>
+ Limit = limitConsideringMacros(I + 2, E, Limit);<br>
+<br>
+ if (!nextTwoLinesFitInto(I, Limit))<br>
+ return 0;<br>
+<br>
+ // Second, check that the next line does not contain any braces - if it<br>
+ // does, readability declines when putting it into a single line.<br>
+ if (I[1]->Last->is(TT_LineComment))<br>
+ return 0;<br>
+ do {<br>
+ if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)<br>
+ return 0;<br>
+ Tok = Tok->Next;<br>
+ } while (Tok);<br>
+<br>
+ // Last, check that the third line starts with a closing brace.<br>
+ Tok = I[2]->First;<br>
+ if (Tok->isNot(tok::r_brace))<br>
+ return 0;<br>
+<br>
+ return 2;<br>
+ }<br>
+ return 0;<br>
+ }<br>
+<br>
+ /// Returns the modified column limit for \p I if it is inside a macro and<br>
+ /// needs a trailing '\'.<br>
+ unsigned<br>
+ limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,<br>
+ unsigned Limit) {<br>
+ if (I[0]->InPPDirective && I + 1 != E &&<br>
+ !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {<br>
+ return Limit < 2 ? 0 : Limit - 2;<br>
+ }<br>
+ return Limit;<br>
+ }<br>
+<br>
+ bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,<br>
+ unsigned Limit) {<br>
+ if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)<br>
+ return false;<br>
+ return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;<br>
+ }<br>
+<br>
+ bool containsMustBreak(const AnnotatedLine *Line) {<br>
+ for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {<br>
+ if (Tok->MustBreakBefore)<br>
+ return true;<br>
+ }<br>
+ return false;<br>
+ }<br>
+<br>
+ const FormatStyle &Style;<br>
+};<br>
+<br>
+class NoColumnLimitFormatter {<br>
+public:<br>
+ NoColumnLimitFormatter(ContinuationIndenter *Indenter) : Indenter(Indenter) {}<br>
+<br>
+ /// \brief Formats the line starting at \p State, simply keeping all of the<br>
+ /// input's line breaking decisions.<br>
+ void format(unsigned FirstIndent, const AnnotatedLine *Line) {<br>
+ LineState State =<br>
+ Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);<br>
+ while (State.NextToken) {<br>
+ bool Newline =<br>
+ Indenter->mustBreak(State) ||<br>
+ (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);<br>
+ Indenter->addTokenToState(State, Newline, /*DryRun=*/false);<br>
+ }<br>
+ }<br>
+<br>
+private:<br>
+ ContinuationIndenter *Indenter;<br>
+};<br>
+<br>
+} // namespace<br>
+<br>
+unsigned<br>
+UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,<br>
+ bool DryRun, int AdditionalIndent,<br>
+ bool FixBadIndentation) {<br>
+ LineJoiner Joiner(Style);<br>
+<br>
+ // Try to look up already computed penalty in DryRun-mode.<br>
+ std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(<br>
+ &Lines, AdditionalIndent);<br>
+ auto CacheIt = PenaltyCache.find(CacheKey);<br>
+ if (DryRun && CacheIt != PenaltyCache.end())<br>
+ return CacheIt->second;<br>
+<br>
+ assert(!Lines.empty());<br>
+ unsigned Penalty = 0;<br>
+ std::vector<int> IndentForLevel;<br>
+ for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)<br>
+ IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);<br>
+ const AnnotatedLine *PreviousLine = nullptr;<br>
+ for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),<br>
+ E = Lines.end();<br>
+ I != E; ++I) {<br>
+ const AnnotatedLine &TheLine = **I;<br>
+ const FormatToken *FirstTok = TheLine.First;<br>
+ int Offset = getIndentOffset(*FirstTok);<br>
+<br>
+ // Determine indent and try to merge multiple unwrapped lines.<br>
+ unsigned Indent;<br>
+ if (TheLine.InPPDirective) {<br>
+ Indent = TheLine.Level * Style.IndentWidth;<br>
+ } else {<br>
+ while (IndentForLevel.size() <= TheLine.Level)<br>
+ IndentForLevel.push_back(-1);<br>
+ IndentForLevel.resize(TheLine.Level + 1);<br>
+ Indent = getIndent(IndentForLevel, TheLine.Level);<br>
+ }<br>
+ unsigned LevelIndent = Indent;<br>
+ if (static_cast<int>(Indent) + Offset >= 0)<br>
+ Indent += Offset;<br>
+<br>
+ // Merge multiple lines if possible.<br>
+ unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E);<br>
+ if (MergedLines > 0 && Style.ColumnLimit == 0) {<br>
+ // Disallow line merging if there is a break at the start of one of the<br>
+ // input lines.<br>
+ for (unsigned i = 0; i < MergedLines; ++i) {<br>
+ if (I[i + 1]->First->NewlinesBefore > 0)<br>
+ MergedLines = 0;<br>
+ }<br>
+ }<br>
+ if (!DryRun) {<br>
+ for (unsigned i = 0; i < MergedLines; ++i) {<br>
+ join(*I[i], *I[i + 1]);<br>
+ }<br>
+ }<br>
+ I += MergedLines;<br>
+<br>
+ bool FixIndentation =<br>
+ FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);<br>
+ if (TheLine.First->is(tok::eof)) {<br>
+ if (PreviousLine && PreviousLine->Affected && !DryRun) {<br>
+ // Remove the file's trailing whitespace.<br>
+ unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);<br>
+ Whitespaces->replaceWhitespace(*TheLine.First, Newlines,<br>
+ /*IndentLevel=*/0, /*Spaces=*/0,<br>
+ /*TargetColumn=*/0);<br>
+ }<br>
+ } else if (TheLine.Type != LT_Invalid &&<br>
+ (TheLine.Affected || FixIndentation)) {<br>
+ if (FirstTok->WhitespaceRange.isValid()) {<br>
+ if (!DryRun)<br>
+ formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level, Indent,<br>
+ TheLine.InPPDirective);<br>
+ } else {<br>
+ Indent = LevelIndent = FirstTok->OriginalColumn;<br>
+ }<br>
+<br>
+ // If everything fits on a single line, just put it there.<br>
+ unsigned ColumnLimit = Style.ColumnLimit;<br>
+ if (I + 1 != E) {<br>
+ AnnotatedLine *NextLine = I[1];<br>
+ if (NextLine->InPPDirective && !NextLine->First->HasUnescapedNewline)<br>
+ ColumnLimit = getColumnLimit(TheLine.InPPDirective);<br>
+ }<br>
+<br>
+ if (TheLine.Last->TotalLength + Indent <= ColumnLimit ||<br>
+ TheLine.Type == LT_ImportStatement) {<br>
+ LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun);<br>
+ while (State.NextToken) {<br>
+ formatChildren(State, /*Newline=*/false, /*DryRun=*/false, Penalty);<br>
+ Indenter->addTokenToState(State, /*Newline=*/false, DryRun);<br>
+ }<br>
+ } else if (Style.ColumnLimit == 0) {<br>
+ // FIXME: Implement nested blocks for ColumnLimit = 0.<br>
+ NoColumnLimitFormatter Formatter(Indenter);<br>
+ if (!DryRun)<br>
+ Formatter.format(Indent, &TheLine);<br>
+ } else {<br>
+ Penalty += format(TheLine, Indent, DryRun);<br>
+ }<br>
+<br>
+ if (!TheLine.InPPDirective)<br>
+ IndentForLevel[TheLine.Level] = LevelIndent;<br>
+ } else if (TheLine.ChildrenAffected) {<br>
+ format(TheLine.Children, DryRun);<br>
+ } else {<br>
+ // Format the first token if necessary, and notify the WhitespaceManager<br>
+ // about the unchanged whitespace.<br>
+ for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {<br>
+ if (Tok == TheLine.First && (Tok->NewlinesBefore > 0 || Tok->IsFirst)) {<br>
+ unsigned LevelIndent = Tok->OriginalColumn;<br>
+ if (!DryRun) {<br>
+ // Remove trailing whitespace of the previous line.<br>
+ if ((PreviousLine && PreviousLine->Affected) ||<br>
+ TheLine.LeadingEmptyLinesAffected) {<br>
+ formatFirstToken(*Tok, PreviousLine, TheLine.Level, LevelIndent,<br>
+ TheLine.InPPDirective);<br>
+ } else {<br>
+ Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);<br>
+ }<br>
+ }<br>
+<br>
+ if (static_cast<int>(LevelIndent) - Offset >= 0)<br>
+ LevelIndent -= Offset;<br>
+ if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)<br>
+ IndentForLevel[TheLine.Level] = LevelIndent;<br>
+ } else if (!DryRun) {<br>
+ Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);<br>
+ }<br>
+ }<br>
+ }<br>
+ if (!DryRun) {<br>
+ for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {<br>
+ Tok->Finalized = true;<br>
+ }<br>
+ }<br>
+ PreviousLine = *I;<br>
+ }<br>
+ PenaltyCache[CacheKey] = Penalty;<br>
+ return Penalty;<br>
+}<br>
+<br>
+unsigned UnwrappedLineFormatter::format(const AnnotatedLine &Line,<br>
+ unsigned FirstIndent, bool DryRun) {<br>
+ LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);<br>
+<br>
+ // If the ObjC method declaration does not fit on a line, we should format<br>
+ // it with one arg per line.<br>
+ if (State.Line->Type == LT_ObjCMethodDecl)<br>
+ State.Stack.back().BreakBeforeParameter = true;<br>
+<br>
+ // Find best solution in solution space.<br>
+ return analyzeSolutionSpace(State, DryRun);<br>
+}<br>
+<br>
+void UnwrappedLineFormatter::formatFirstToken(FormatToken &RootToken,<br>
+ const AnnotatedLine *PreviousLine,<br>
+ unsigned IndentLevel,<br>
+ unsigned Indent,<br>
+ bool InPPDirective) {<br>
+ unsigned Newlines =<br>
+ std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);<br>
+ // Remove empty lines before "}" where applicable.<br>
+ if (RootToken.is(tok::r_brace) &&<br>
+ (!RootToken.Next ||<br>
+ (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))<br>
+ Newlines = std::min(Newlines, 1u);<br>
+ if (Newlines == 0 && !RootToken.IsFirst)<br>
+ Newlines = 1;<br>
+ if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)<br>
+ Newlines = 0;<br>
+<br>
+ // Remove empty lines after "{".<br>
+ if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&<br>
+ PreviousLine->Last->is(tok::l_brace) &&<br>
+ PreviousLine->First->isNot(tok::kw_namespace) &&<br>
+ !startsExternCBlock(*PreviousLine))<br>
+ Newlines = 1;<br>
+<br>
+ // Insert extra new line before access specifiers.<br>
+ if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&<br>
+ RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)<br>
+ ++Newlines;<br>
+<br>
+ // Remove empty lines after access specifiers.<br>
+ if (PreviousLine && PreviousLine->First->isAccessSpecifier())<br>
+ Newlines = std::min(1u, Newlines);<br>
+<br>
+ Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,<br>
+ Indent, InPPDirective &&<br>
+ !RootToken.HasUnescapedNewline);<br>
+}<br>
+<br>
+/// \brief Get the indent of \p Level from \p IndentForLevel.<br>
+///<br>
+/// \p IndentForLevel must contain the indent for the level \c l<br>
+/// at \p IndentForLevel[l], or a value < 0 if the indent for<br>
+/// that level is unknown.<br>
+unsigned UnwrappedLineFormatter::getIndent(ArrayRef<int> IndentForLevel,<br>
+ unsigned Level) {<br>
+ if (IndentForLevel[Level] != -1)<br>
+ return IndentForLevel[Level];<br>
+ if (Level == 0)<br>
+ return 0;<br>
+ return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;<br>
+}<br>
+<br>
+void UnwrappedLineFormatter::join(AnnotatedLine &A, const AnnotatedLine &B) {<br>
+ assert(!A.Last->Next);<br>
+ assert(!B.First->Previous);<br>
+ if (B.Affected)<br>
+ A.Affected = true;<br>
+ A.Last->Next = B.First;<br>
+ B.First->Previous = A.Last;<br>
+ B.First->CanBreakBefore = true;<br>
+ unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;<br>
+ for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {<br>
+ Tok->TotalLength += LengthA;<br>
+ A.Last = Tok;<br>
+ }<br>
+}<br>
+<br>
+unsigned UnwrappedLineFormatter::analyzeSolutionSpace(LineState &InitialState,<br>
+ bool DryRun) {<br>
+ std::set<LineState *, CompareLineStatePointers> Seen;<br>
+<br>
+ // Increasing count of \c StateNode items we have created. This is used to<br>
+ // create a deterministic order independent of the container.<br>
+ unsigned Count = 0;<br>
+ QueueType Queue;<br>
+<br>
+ // Insert start element into queue.<br>
+ StateNode *Node =<br>
+ new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);<br>
+ Queue.push(QueueItem(OrderedPenalty(0, Count), Node));<br>
+ ++Count;<br>
+<br>
+ unsigned Penalty = 0;<br>
+<br>
+ // While not empty, take first element and follow edges.<br>
+ while (!Queue.empty()) {<br>
+ Penalty = Queue.top().first.first;<br>
+ StateNode *Node = Queue.top().second;<br>
+ if (!Node->State.NextToken) {<br>
+ DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");<br>
+ break;<br>
+ }<br>
+ Queue.pop();<br>
+<br>
+ // Cut off the analysis of certain solutions if the analysis gets too<br>
+ // complex. See description of IgnoreStackForComparison.<br>
+ if (Count > 10000)<br>
+ Node->State.IgnoreStackForComparison = true;<br>
+<br>
+ if (!Seen.insert(&Node->State).second)<br>
+ // State already examined with lower penalty.<br>
+ continue;<br>
+<br>
+ FormatDecision LastFormat = Node->State.NextToken->Decision;<br>
+ if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)<br>
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue);<br>
+ if (LastFormat == FD_Unformatted || LastFormat == FD_Break)<br>
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue);<br>
+ }<br>
+<br>
+ if (Queue.empty()) {<br>
+ // We were unable to find a solution, do nothing.<br>
+ // FIXME: Add diagnostic?<br>
+ DEBUG(llvm::dbgs() << "Could not find a solution.\n");<br>
+ return 0;<br>
+ }<br>
+<br>
+ // Reconstruct the solution.<br>
+ if (!DryRun)<br>
+ reconstructPath(InitialState, Queue.top().second);<br>
+<br>
+ DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count << "\n");<br>
+ DEBUG(llvm::dbgs() << "---\n");<br>
+<br>
+ return Penalty;<br>
+}<br>
+<br>
+void UnwrappedLineFormatter::reconstructPath(LineState &State,<br>
+ StateNode *Current) {<br>
+ std::deque<StateNode *> Path;<br>
+ // We do not need a break before the initial token.<br>
+ while (Current->Previous) {<br>
+ Path.push_front(Current);<br>
+ Current = Current->Previous;<br>
+ }<br>
+ for (std::deque<StateNode *>::iterator I = Path.begin(), E = Path.end();<br>
+ I != E; ++I) {<br>
+ unsigned Penalty = 0;<br>
+ formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);<br>
+ Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);<br>
+<br>
+ DEBUG({<br>
+ if ((*I)->NewLine) {<br>
+ llvm::dbgs() << "Penalty for placing "<br>
+ << (*I)->Previous->State.NextToken->Tok.getName() << ": "<br>
+ << Penalty << "\n";<br>
+ }<br>
+ });<br>
+ }<br>
+}<br>
+<br>
+void UnwrappedLineFormatter::addNextStateToQueue(unsigned Penalty,<br>
+ StateNode *PreviousNode,<br>
+ bool NewLine, unsigned *Count,<br>
+ QueueType *Queue) {<br>
+ if (NewLine && !Indenter->canBreak(PreviousNode->State))<br>
+ return;<br>
+ if (!NewLine && Indenter->mustBreak(PreviousNode->State))<br>
+ return;<br>
+<br>
+ StateNode *Node = new (Allocator.Allocate())<br>
+ StateNode(PreviousNode->State, NewLine, PreviousNode);<br>
+ if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))<br>
+ return;<br>
+<br>
+ Penalty += Indenter->addTokenToState(Node->State, NewLine, true);<br>
+<br>
+ Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));<br>
+ ++(*Count);<br>
+}<br>
+<br>
+bool UnwrappedLineFormatter::formatChildren(LineState &State, bool NewLine,<br>
+ bool DryRun, unsigned &Penalty) {<br>
+ FormatToken &Previous = *State.NextToken->Previous;<br>
+ const FormatToken *LBrace = State.NextToken->getPreviousNonComment();<br>
+ if (!LBrace || LBrace->isNot(tok::l_brace) || LBrace->BlockKind != BK_Block ||<br>
+ Previous.Children.size() == 0)<br>
+ // The previous token does not open a block. Nothing to do. We don't<br>
+ // assert so that we can simply call this function for all tokens.<br>
+ return true;<br>
+<br>
+ if (NewLine) {<br>
+ int AdditionalIndent =<br>
+ State.FirstIndent - State.Line->Level * Style.IndentWidth;<br>
+ if (State.Stack.size() < 2 ||<br>
+ !State.Stack[State.Stack.size() - 2].NestedBlockInlined) {<br>
+ AdditionalIndent = State.Stack.back().Indent -<br>
+ Previous.Children[0]->Level * Style.IndentWidth;<br>
+ }<br>
+<br>
+ Penalty += format(Previous.Children, DryRun, AdditionalIndent,<br>
+ /*FixBadIndentation=*/true);<br>
+ return true;<br>
+ }<br>
+<br>
+ if (Previous.Children[0]->First->MustBreakBefore)<br>
+ return false;<br>
+<br>
+ // Cannot merge multiple statements into a single line.<br>
+ if (Previous.Children.size() > 1)<br>
+ return false;<br>
+<br>
+ // Cannot merge into one line if this line ends on a comment.<br>
+ if (Previous.is(tok::comment))<br>
+ return false;<br>
+<br>
+ // We can't put the closing "}" on a line with a trailing comment.<br>
+ if (Previous.Children[0]->Last->isTrailingComment())<br>
+ return false;<br>
+<br>
+ // If the child line exceeds the column limit, we wouldn't want to merge it.<br>
+ // We add +2 for the trailing " }".<br>
+ if (Style.ColumnLimit > 0 &&<br>
+ Previous.Children[0]->Last->TotalLength + State.Column + 2 ><br>
+ Style.ColumnLimit)<br>
+ return false;<br>
+<br>
+ if (!DryRun) {<br>
+ Whitespaces->replaceWhitespace(<br>
+ *Previous.Children[0]->First,<br>
+ /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,<br>
+ /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);<br>
+ }<br>
+ Penalty += format(*Previous.Children[0], State.Column + 1, DryRun);<br>
+<br>
+ State.Column += 1 + Previous.Children[0]->Last->TotalLength;<br>
+ return true;<br>
+}<br>
+<br>
+} // namespace format<br>
+} // namespace clang<br>
<br>
Added: cfe/trunk/lib/Format/UnwrappedLineFormatter.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.h?rev=223936&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.h?rev=223936&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Format/UnwrappedLineFormatter.h (added)<br>
+++ cfe/trunk/lib/Format/UnwrappedLineFormatter.h Wed Dec 10 13:00:42 2014<br>
@@ -0,0 +1,168 @@<br>
+//===--- UnwrappedLineFormatter.h - Format C++ code -------------*- C++ -*-===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+///<br>
+/// \file<br>
+/// \brief Implements a combinartorial exploration of all the different<br>
+/// linebreaks unwrapped lines can be formatted in.<br>
+///<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H<br>
+#define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H<br>
+<br>
+#include "ContinuationIndenter.h"<br>
+#include "clang/Format/Format.h"<br>
+#include <map><br>
+#include <queue><br>
+#include <string><br>
+<br>
+namespace clang {<br>
+namespace format {<br>
+<br>
+class ContinuationIndenter;<br>
+class WhitespaceManager;<br>
+<br>
+class UnwrappedLineFormatter {<br>
+public:<br>
+ UnwrappedLineFormatter(ContinuationIndenter *Indenter,<br>
+ WhitespaceManager *Whitespaces,<br>
+ const FormatStyle &Style)<br>
+ : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style) {}<br>
+<br>
+ unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,<br>
+ int AdditionalIndent = 0, bool FixBadIndentation = false);<br>
+<br>
+private:<br>
+ /// \brief Formats an \c AnnotatedLine and returns the penalty.<br>
+ ///<br>
+ /// If \p DryRun is \c false, directly applies the changes.<br>
+ unsigned format(const AnnotatedLine &Line, unsigned FirstIndent,<br>
+ bool DryRun);<br>
+<br>
+ /// \brief An edge in the solution space from \c Previous->State to \c State,<br>
+ /// inserting a newline dependent on the \c NewLine.<br>
+ struct StateNode {<br>
+ StateNode(const LineState &State, bool NewLine, StateNode *Previous)<br>
+ : State(State), NewLine(NewLine), Previous(Previous) {}<br>
+ LineState State;<br>
+ bool NewLine;<br>
+ StateNode *Previous;<br>
+ };<br>
+<br>
+ /// \brief A pair of <penalty, count> that is used to prioritize the BFS on.<br>
+ ///<br>
+ /// In case of equal penalties, we want to prefer states that were inserted<br>
+ /// first. During state generation we make sure that we insert states first<br>
+ /// that break the line as late as possible.<br>
+ typedef std::pair<unsigned, unsigned> OrderedPenalty;<br>
+<br>
+ /// \brief An item in the prioritized BFS search queue. The \c StateNode's<br>
+ /// \c State has the given \c OrderedPenalty.<br>
+ typedef std::pair<OrderedPenalty, StateNode *> QueueItem;<br>
+<br>
+ /// \brief The BFS queue type.<br>
+ typedef std::priority_queue<QueueItem, std::vector<QueueItem>,<br>
+ std::greater<QueueItem> > QueueType;<br>
+<br>
+ /// \brief Get the offset of the line relatively to the level.<br>
+ ///<br>
+ /// For example, 'public:' labels in classes are offset by 1 or 2<br>
+ /// characters to the left from their level.<br>
+ int getIndentOffset(const FormatToken &RootToken) {<br>
+ if (Style.Language == FormatStyle::LK_Java)<br>
+ return 0;<br>
+ if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())<br>
+ return Style.AccessModifierOffset;<br>
+ return 0;<br>
+ }<br>
+<br>
+ /// \brief Add a new line and the required indent before the first Token<br>
+ /// of the \c UnwrappedLine if there was no structural parsing error.<br>
+ void formatFirstToken(FormatToken &RootToken,<br>
+ const AnnotatedLine *PreviousLine, unsigned IndentLevel,<br>
+ unsigned Indent, bool InPPDirective);<br>
+<br>
+ /// \brief Get the indent of \p Level from \p IndentForLevel.<br>
+ ///<br>
+ /// \p IndentForLevel must contain the indent for the level \c l<br>
+ /// at \p IndentForLevel[l], or a value < 0 if the indent for<br>
+ /// that level is unknown.<br>
+ unsigned getIndent(ArrayRef<int> IndentForLevel, unsigned Level);<br>
+<br>
+ void join(AnnotatedLine &A, const AnnotatedLine &B);<br>
+<br>
+ unsigned getColumnLimit(bool InPPDirective) const {<br>
+ // In preprocessor directives reserve two chars for trailing " \"<br>
+ return Style.ColumnLimit - (InPPDirective ? 2 : 0);<br>
+ }<br>
+<br>
+ struct CompareLineStatePointers {<br>
+ bool operator()(LineState *obj1, LineState *obj2) const {<br>
+ return *obj1 < *obj2;<br>
+ }<br>
+ };<br>
+<br>
+ /// \brief Analyze the entire solution space starting from \p InitialState.<br>
+ ///<br>
+ /// This implements a variant of Dijkstra's algorithm on the graph that spans<br>
+ /// the solution space (\c LineStates are the nodes). The algorithm tries to<br>
+ /// find the shortest path (the one with lowest penalty) from \p InitialState<br>
+ /// to a state where all tokens are placed. Returns the penalty.<br>
+ ///<br>
+ /// If \p DryRun is \c false, directly applies the changes.<br>
+ unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false);<br>
+<br>
+ void reconstructPath(LineState &State, StateNode *Current);<br>
+<br>
+ /// \brief Add the following state to the analysis queue \c Queue.<br>
+ ///<br>
+ /// Assume the current state is \p PreviousNode and has been reached with a<br>
+ /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.<br>
+ void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,<br>
+ bool NewLine, unsigned *Count, QueueType *Queue);<br>
+<br>
+ /// \brief If the \p State's next token is an r_brace closing a nested block,<br>
+ /// format the nested block before it.<br>
+ ///<br>
+ /// Returns \c true if all children could be placed successfully and adapts<br>
+ /// \p Penalty as well as \p State. If \p DryRun is false, also directly<br>
+ /// creates changes using \c Whitespaces.<br>
+ ///<br>
+ /// The crucial idea here is that children always get formatted upon<br>
+ /// encountering the closing brace right after the nested block. Now, if we<br>
+ /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is<br>
+ /// \c false), the entire block has to be kept on the same line (which is only<br>
+ /// possible if it fits on the line, only contains a single statement, etc.<br>
+ ///<br>
+ /// If \p NewLine is true, we format the nested block on separate lines, i.e.<br>
+ /// break after the "{", format all lines with correct indentation and the put<br>
+ /// the closing "}" on yet another new line.<br>
+ ///<br>
+ /// This enables us to keep the simple structure of the<br>
+ /// \c UnwrappedLineFormatter, where we only have two options for each token:<br>
+ /// break or don't break.<br>
+ bool formatChildren(LineState &State, bool NewLine, bool DryRun,<br>
+ unsigned &Penalty);<br>
+<br>
+ ContinuationIndenter *Indenter;<br>
+ WhitespaceManager *Whitespaces;<br>
+ FormatStyle Style;<br>
+<br>
+ llvm::SpecificBumpPtrAllocator<StateNode> Allocator;<br>
+<br>
+ // Cache to store the penalty of formatting a vector of AnnotatedLines<br>
+ // starting from a specific additional offset. Improves performance if there<br>
+ // are many nested blocks.<br>
+ std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,<br>
+ unsigned> PenaltyCache;<br>
+};<br>
+} // end namespace format<br>
+} // end namespace clang<br>
+<br>
+#endif // LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>