aboutsummaryrefslogtreecommitdiff
path: root/lib/Format/UnwrappedLineFormatter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Format/UnwrappedLineFormatter.cpp')
-rw-r--r--lib/Format/UnwrappedLineFormatter.cpp259
1 files changed, 189 insertions, 70 deletions
diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
index 2005a2822924..60dc1a7169d1 100644
--- a/lib/Format/UnwrappedLineFormatter.cpp
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -164,8 +164,7 @@ public:
return nullptr;
const AnnotatedLine *Current = *Next;
IndentTracker.nextLine(*Current);
- unsigned MergedLines =
- tryFitMultipleLinesInOne(IndentTracker, Next, End);
+ unsigned MergedLines = tryFitMultipleLinesInOne(IndentTracker, Next, End);
if (MergedLines > 0 && Style.ColumnLimit == 0)
// Disallow line merging if there is a break at the start of one of the
// input lines.
@@ -228,14 +227,16 @@ private:
if (Tok && Tok->getNamespaceToken())
return !Style.BraceWrapping.SplitEmptyNamespace && EmptyBlock
- ? tryMergeSimpleBlock(I, E, Limit) : 0;
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
if (Tok && Tok->is(tok::kw_typedef))
Tok = Tok->getNextNonComment();
if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union,
- Keywords.kw_interface))
+ tok::kw_extern, Keywords.kw_interface))
return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock
- ? tryMergeSimpleBlock(I, E, Limit) : 0;
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
}
// FIXME: TheLine->Level != 0 might or might not be the right check to do.
@@ -279,15 +280,43 @@ private:
}
}
+ // Try to merge a function block with left brace unwrapped
if (TheLine->Last->is(TT_FunctionLBrace) &&
TheLine->First != TheLine->Last) {
return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
}
+ // Try to merge a control statement block with left brace unwrapped
+ if (TheLine->Last->is(tok::l_brace) && TheLine->First != TheLine->Last &&
+ TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
+ return Style.AllowShortBlocksOnASingleLine
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+ }
+ // Try to merge a control statement block with left brace wrapped
+ if (I[1]->First->is(tok::l_brace) &&
+ TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
+ return Style.BraceWrapping.AfterControlStatement
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+ }
+ // Try to merge either empty or one-line block if is precedeed by control
+ // statement token
+ if (TheLine->First->is(tok::l_brace) && TheLine->First == TheLine->Last &&
+ I != AnnotatedLines.begin() &&
+ I[-1]->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
+ return Style.AllowShortBlocksOnASingleLine
+ ? tryMergeSimpleBlock(I - 1, E, Limit)
+ : 0;
+ }
+ // Try to merge a block with left brace wrapped that wasn't yet covered
if (TheLine->Last->is(tok::l_brace)) {
- return !Style.BraceWrapping.AfterFunction
+ return !Style.BraceWrapping.AfterFunction ||
+ (I[1]->First->is(tok::r_brace) &&
+ !Style.BraceWrapping.SplitEmptyRecord)
? tryMergeSimpleBlock(I, E, Limit)
: 0;
}
+ // Try to merge a function block with left brace wrapped
if (I[1]->First->is(TT_FunctionLBrace) &&
Style.BraceWrapping.AfterFunction) {
if (I[1]->Last->is(TT_LineComment))
@@ -382,7 +411,9 @@ private:
return 0;
unsigned NumStmts = 0;
unsigned Length = 0;
+ bool EndsWithComment = false;
bool InPPDirective = I[0]->InPPDirective;
+ const unsigned Level = I[0]->Level;
for (; NumStmts < 3; ++NumStmts) {
if (I + 1 + NumStmts == E)
break;
@@ -392,9 +423,26 @@ private:
if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
break;
if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
- tok::kw_while, tok::comment) ||
- Line->Last->is(tok::comment))
+ tok::kw_while) ||
+ EndsWithComment)
return 0;
+ if (Line->First->is(tok::comment)) {
+ if (Level != Line->Level)
+ return 0;
+ SmallVectorImpl<AnnotatedLine *>::const_iterator J = I + 2 + NumStmts;
+ for (; J != E; ++J) {
+ Line = *J;
+ if (Line->InPPDirective != InPPDirective)
+ break;
+ if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
+ break;
+ if (Line->First->isNot(tok::comment) || Level != Line->Level)
+ return 0;
+ }
+ break;
+ }
+ if (Line->Last->is(tok::comment))
+ EndsWithComment = true;
Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the space.
}
if (NumStmts == 0 || NumStmts == 3 || Length > Limit)
@@ -425,11 +473,27 @@ private:
tok::kw_for, tok::r_brace, Keywords.kw___except)) {
if (!Style.AllowShortBlocksOnASingleLine)
return 0;
+ // Don't merge when we can't except the case when
+ // the control statement block is empty
if (!Style.AllowShortIfStatementsOnASingleLine &&
- Line.startsWith(tok::kw_if))
+ Line.startsWith(tok::kw_if) &&
+ !Style.BraceWrapping.AfterControlStatement &&
+ !I[1]->First->is(tok::r_brace))
+ return 0;
+ if (!Style.AllowShortIfStatementsOnASingleLine &&
+ Line.startsWith(tok::kw_if) &&
+ Style.BraceWrapping.AfterControlStatement && I + 2 != E &&
+ !I[2]->First->is(tok::r_brace))
+ return 0;
+ if (!Style.AllowShortLoopsOnASingleLine &&
+ Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) &&
+ !Style.BraceWrapping.AfterControlStatement &&
+ !I[1]->First->is(tok::r_brace))
return 0;
if (!Style.AllowShortLoopsOnASingleLine &&
- Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))
+ Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) &&
+ Style.BraceWrapping.AfterControlStatement && I + 2 != E &&
+ !I[2]->First->is(tok::r_brace))
return 0;
// FIXME: Consider an option to allow short exception handling clauses on
// a single line.
@@ -441,52 +505,78 @@ private:
return 0;
}
- FormatToken *Tok = I[1]->First;
- if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
- (Tok->getNextNonComment() == nullptr ||
- Tok->getNextNonComment()->is(tok::semi))) {
- // We merge empty blocks even if the line exceeds the column limit.
- Tok->SpacesRequiredBefore = 0;
- Tok->CanBreakBefore = true;
- return 1;
- } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
- !startsExternCBlock(Line)) {
- // We don't merge short records.
- FormatToken *RecordTok =
- Line.First->is(tok::kw_typedef) ? Line.First->Next : Line.First;
- if (RecordTok &&
- RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
- Keywords.kw_interface))
- return 0;
+ if (Line.Last->is(tok::l_brace)) {
+ FormatToken *Tok = I[1]->First;
+ if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
+ (Tok->getNextNonComment() == nullptr ||
+ Tok->getNextNonComment()->is(tok::semi))) {
+ // We merge empty blocks even if the line exceeds the column limit.
+ Tok->SpacesRequiredBefore = 0;
+ Tok->CanBreakBefore = true;
+ return 1;
+ } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
+ !startsExternCBlock(Line)) {
+ // We don't merge short records.
+ FormatToken *RecordTok = Line.First;
+ // Skip record modifiers.
+ while (RecordTok->Next &&
+ RecordTok->isOneOf(tok::kw_typedef, tok::kw_export,
+ Keywords.kw_declare, Keywords.kw_abstract,
+ tok::kw_default))
+ RecordTok = RecordTok->Next;
+ if (RecordTok &&
+ RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
+ Keywords.kw_interface))
+ return 0;
- // Check that we still have three lines and they fit into the limit.
- if (I + 2 == E || I[2]->Type == LT_Invalid)
- return 0;
- Limit = limitConsideringMacros(I + 2, E, Limit);
+ // Check that we still have three lines and they fit into the limit.
+ if (I + 2 == E || I[2]->Type == LT_Invalid)
+ return 0;
+ Limit = limitConsideringMacros(I + 2, E, Limit);
- if (!nextTwoLinesFitInto(I, Limit))
- return 0;
+ if (!nextTwoLinesFitInto(I, Limit))
+ return 0;
- // Second, check that the next line does not contain any braces - if it
- // does, readability declines when putting it into a single line.
- if (I[1]->Last->is(TT_LineComment))
- return 0;
- do {
- if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
+ // Second, check that the next line does not contain any braces - if it
+ // does, readability declines when putting it into a single line.
+ if (I[1]->Last->is(TT_LineComment))
+ return 0;
+ do {
+ if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
+ return 0;
+ Tok = Tok->Next;
+ } while (Tok);
+
+ // Last, check that the third line starts with a closing brace.
+ Tok = I[2]->First;
+ if (Tok->isNot(tok::r_brace))
return 0;
- Tok = Tok->Next;
- } while (Tok);
- // Last, check that the third line starts with a closing brace.
- Tok = I[2]->First;
- if (Tok->isNot(tok::r_brace))
- return 0;
+ // Don't merge "if (a) { .. } else {".
+ if (Tok->Next && Tok->Next->is(tok::kw_else))
+ return 0;
- // Don't merge "if (a) { .. } else {".
- if (Tok->Next && Tok->Next->is(tok::kw_else))
+ return 2;
+ }
+ } else if (I[1]->First->is(tok::l_brace)) {
+ if (I[1]->Last->is(TT_LineComment))
return 0;
- return 2;
+ // Check for Limit <= 2 to account for the " {".
+ if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(*I)))
+ return 0;
+ Limit -= 2;
+ unsigned MergedLines = 0;
+ if (Style.AllowShortBlocksOnASingleLine ||
+ (I[1]->First == I[1]->Last && I + 2 != E &&
+ I[2]->First->is(tok::r_brace))) {
+ MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
+ // If we managed to merge the block, count the statement header, which
+ // is on a separate line.
+ if (MergedLines > 0)
+ ++MergedLines;
+ }
+ return MergedLines;
}
return 0;
}
@@ -574,7 +664,9 @@ public:
/// \brief Formats an \c AnnotatedLine and returns the penalty.
///
/// If \p DryRun is \c false, directly applies the changes.
- virtual unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
+ virtual unsigned formatLine(const AnnotatedLine &Line,
+ unsigned FirstIndent,
+ unsigned FirstStartColumn,
bool DryRun) = 0;
protected:
@@ -645,7 +737,8 @@ protected:
*Child->First, /*Newlines=*/0, /*Spaces=*/1,
/*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
}
- Penalty += formatLine(*Child, State.Column + 1, DryRun);
+ Penalty +=
+ formatLine(*Child, State.Column + 1, /*FirstStartColumn=*/0, DryRun);
State.Column += 1 + Child->Last->TotalLength;
return true;
@@ -671,10 +764,10 @@ public:
/// \brief Formats the line, simply keeping all of the input's line breaking
/// decisions.
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
- bool DryRun) override {
+ unsigned FirstStartColumn, bool DryRun) override {
assert(!DryRun);
- LineState State =
- Indenter->getInitialState(FirstIndent, &Line, /*DryRun=*/false);
+ LineState State = Indenter->getInitialState(FirstIndent, FirstStartColumn,
+ &Line, /*DryRun=*/false);
while (State.NextToken) {
bool Newline =
Indenter->mustBreak(State) ||
@@ -697,9 +790,10 @@ public:
/// \brief Puts all tokens into a single line.
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
- bool DryRun) override {
+ unsigned FirstStartColumn, bool DryRun) override {
unsigned Penalty = 0;
- LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
+ LineState State =
+ Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun);
while (State.NextToken) {
formatChildren(State, /*Newline=*/false, DryRun, Penalty);
Indenter->addTokenToState(
@@ -721,8 +815,9 @@ public:
/// \brief Formats the line by finding the best line breaks with line lengths
/// below the column limit.
unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
- bool DryRun) override {
- LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
+ unsigned FirstStartColumn, bool DryRun) override {
+ LineState State =
+ Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun);
// If the ObjC method declaration does not fit on a line, we should format
// it with one arg per line.
@@ -763,7 +858,8 @@ private:
/// \brief The BFS queue type.
typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
- std::greater<QueueItem>> QueueType;
+ std::greater<QueueItem>>
+ QueueType;
/// \brief Analyze the entire solution space starting from \p InitialState.
///
@@ -888,7 +984,10 @@ private:
unsigned
UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
bool DryRun, int AdditionalIndent,
- bool FixBadIndentation) {
+ bool FixBadIndentation,
+ unsigned FirstStartColumn,
+ unsigned NextStartColumn,
+ unsigned LastStartColumn) {
LineJoiner Joiner(Style, Keywords, Lines);
// Try to look up already computed penalty in DryRun-mode.
@@ -908,9 +1007,10 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
// The minimum level of consecutive lines that have been formatted.
unsigned RangeMinLevel = UINT_MAX;
+ bool FirstLine = true;
for (const AnnotatedLine *Line =
Joiner.getNextMergedLine(DryRun, IndentTracker);
- Line; Line = NextLine) {
+ Line; Line = NextLine, FirstLine = false) {
const AnnotatedLine &TheLine = *Line;
unsigned Indent = IndentTracker.getIndent();
@@ -934,8 +1034,12 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
}
if (ShouldFormat && TheLine.Type != LT_Invalid) {
- if (!DryRun)
- formatFirstToken(TheLine, PreviousLine, Indent);
+ if (!DryRun) {
+ bool LastLine = Line->First->is(tok::eof);
+ formatFirstToken(TheLine, PreviousLine,
+ Indent,
+ LastLine ? LastStartColumn : NextStartColumn + Indent);
+ }
NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine);
@@ -944,16 +1048,18 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
(TheLine.Type == LT_ImportStatement &&
(Style.Language != FormatStyle::LK_JavaScript ||
!Style.JavaScriptWrapImports));
-
if (Style.ColumnLimit == 0)
NoColumnLimitLineFormatter(Indenter, Whitespaces, Style, this)
- .formatLine(TheLine, Indent, DryRun);
+ .formatLine(TheLine, NextStartColumn + Indent,
+ FirstLine ? FirstStartColumn : 0, DryRun);
else if (FitsIntoOneLine)
Penalty += NoLineBreakFormatter(Indenter, Whitespaces, Style, this)
- .formatLine(TheLine, Indent, DryRun);
+ .formatLine(TheLine, NextStartColumn + Indent,
+ FirstLine ? FirstStartColumn : 0, DryRun);
else
Penalty += OptimizingLineFormatter(Indenter, Whitespaces, Style, this)
- .formatLine(TheLine, Indent, DryRun);
+ .formatLine(TheLine, NextStartColumn + Indent,
+ FirstLine ? FirstStartColumn : 0, DryRun);
RangeMinLevel = std::min(RangeMinLevel, TheLine.Level);
} else {
// If no token in the current line is affected, we still need to format
@@ -976,6 +1082,7 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
// Format the first token.
if (ReformatLeadingWhitespace)
formatFirstToken(TheLine, PreviousLine,
+ TheLine.First->OriginalColumn,
TheLine.First->OriginalColumn);
else
Whitespaces->addUntouchableToken(*TheLine.First,
@@ -998,12 +1105,14 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
const AnnotatedLine *PreviousLine,
- unsigned Indent) {
- FormatToken& RootToken = *Line.First;
+ unsigned Indent,
+ unsigned NewlineIndent) {
+ FormatToken &RootToken = *Line.First;
if (RootToken.is(tok::eof)) {
unsigned Newlines = std::min(RootToken.NewlinesBefore, 1u);
- Whitespaces->replaceWhitespace(RootToken, Newlines, /*Spaces=*/0,
- /*StartOfTokenColumn=*/0);
+ unsigned TokenIndent = Newlines ? NewlineIndent : 0;
+ Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent,
+ TokenIndent);
return;
}
unsigned Newlines =
@@ -1013,6 +1122,9 @@ void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
(!RootToken.Next ||
(RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))
Newlines = std::min(Newlines, 1u);
+ // Remove empty lines at the start of nested blocks (lambdas/arrow functions)
+ if (PreviousLine == nullptr && Line.Level > 0)
+ Newlines = std::min(Newlines, 1u);
if (Newlines == 0 && !RootToken.IsFirst)
Newlines = 1;
if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
@@ -1035,6 +1147,13 @@ void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
(!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline))
Newlines = std::min(1u, Newlines);
+ if (Newlines)
+ Indent = NewlineIndent;
+
+ // Preprocessor directives get indented after the hash, if indented.
+ if (Line.Type == LT_PreprocessorDirective || Line.Type == LT_ImportStatement)
+ Indent = 0;
+
Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent,
Line.InPPDirective &&
!RootToken.HasUnescapedNewline);