diff options
author | Daniel Jasper <djasper@google.com> | 2013-11-06 23:12:09 +0000 |
---|---|---|
committer | Daniel Jasper <djasper@google.com> | 2013-11-06 23:12:09 +0000 |
commit | 56f8b439410f701e173c11f72b944ce21c5d194c (patch) | |
tree | 2ee4ae6a1fe0cf6179f40fca9bc31aad23f0949e | |
parent | 671a1e4b373ec6bf996a77d8718fde19433c9fc1 (diff) | |
download | bcm5719-llvm-56f8b439410f701e173c11f72b944ce21c5d194c.tar.gz bcm5719-llvm-56f8b439410f701e173c11f72b944ce21c5d194c.zip |
clang-format: Separate line-merging logic into its own class.
No functional changes (intended).
llvm-svn: 194179
-rw-r--r-- | clang/lib/Format/Format.cpp | 315 |
1 files changed, 164 insertions, 151 deletions
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 10d07df90f3..9443a60aa6d 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -370,6 +370,158 @@ private: ContinuationIndenter *Indenter; }; +class LineJoiner { +public: + LineJoiner(const FormatStyle &Style) : Style(Style) {} + + /// \brief Calculates how many lines can be merged into 1 starting at \p I. + unsigned + tryFitMultipleLinesInOne(unsigned Indent, + SmallVectorImpl<AnnotatedLine *>::const_iterator &I, + SmallVectorImpl<AnnotatedLine *>::const_iterator E) { + // We can never merge stuff if there are trailing line comments. + AnnotatedLine *TheLine = *I; + if (TheLine->Last->Type == TT_LineComment) + return 0; + + if (Indent > Style.ColumnLimit) + return 0; + + unsigned Limit = Style.ColumnLimit - Indent; + // If we already exceed the column limit, we set 'Limit' to 0. The different + // tryMerge..() functions can then decide whether to still do merging. + Limit = TheLine->Last->TotalLength > Limit + ? 0 + : Limit - TheLine->Last->TotalLength; + + if (I + 1 == E || (*(I + 1))->Type == LT_Invalid) + return 0; + + if (TheLine->Last->is(tok::l_brace)) { + return tryMergeSimpleBlock(I, E, Limit); + } else if (Style.AllowShortIfStatementsOnASingleLine && + TheLine->First->is(tok::kw_if)) { + return tryMergeSimpleControlStatement(I, E, Limit); + } else if (Style.AllowShortLoopsOnASingleLine && + TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) { + return tryMergeSimpleControlStatement(I, E, Limit); + } else if (TheLine->InPPDirective && (TheLine->First->HasUnescapedNewline || + TheLine->First->IsFirst)) { + return tryMergeSimplePPDirective(I, E, Limit); + } + return 0; + } + +private: + unsigned + tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator &I, + SmallVectorImpl<AnnotatedLine *>::const_iterator E, + unsigned Limit) { + if (Limit == 0) + return 0; + if (!(*(I + 1))->InPPDirective || (*(I + 1))->First->HasUnescapedNewline) + return 0; + if (I + 2 != E && (*(I + 2))->InPPDirective && + !(*(I + 2))->First->HasUnescapedNewline) + return 0; + if (1 + (*(I + 1))->Last->TotalLength > Limit) + return 0; + return 1; + } + + unsigned tryMergeSimpleControlStatement( + SmallVectorImpl<AnnotatedLine *>::const_iterator &I, + SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) { + if (Limit == 0) + return 0; + if (Style.BreakBeforeBraces == FormatStyle::BS_Allman && + (*(I + 1))->First->is(tok::l_brace)) + return 0; + if ((*(I + 1))->InPPDirective != (*I)->InPPDirective || + ((*(I + 1))->InPPDirective && (*(I + 1))->First->HasUnescapedNewline)) + return 0; + AnnotatedLine &Line = **I; + if (Line.Last->isNot(tok::r_paren)) + return 0; + if (1 + (*(I + 1))->Last->TotalLength > Limit) + return 0; + if ((*(I + 1))->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for, + tok::kw_while) || + (*(I + 1))->First->Type == TT_LineComment) + return 0; + // Only inline simple if's (no nested if or else). + if (I + 2 != E && Line.First->is(tok::kw_if) && + (*(I + 2))->First->is(tok::kw_else)) + return 0; + return 1; + } + + unsigned + tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator &I, + SmallVectorImpl<AnnotatedLine *>::const_iterator E, + unsigned Limit) { + // No merging if the brace already is on the next line. + if (Style.BreakBeforeBraces != FormatStyle::BS_Attach) + return 0; + + // First, check that the current line allows merging. This is the case if + // we're not in a control flow statement and the last token is an opening + // brace. + AnnotatedLine &Line = **I; + if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace, + tok::kw_else, tok::kw_try, tok::kw_catch, + tok::kw_for, + // This gets rid of all ObjC @ keywords and methods. + tok::at, tok::minus, tok::plus)) + return 0; + + FormatToken *Tok = (*(I + 1))->First; + if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore && + (Tok->getNextNonComment() == NULL || + 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.First->isNot(tok::kw_namespace)) { + // Check that we still have three lines and they fit into the limit. + if (I + 2 == E || (*(I + 2))->Type == LT_Invalid) + 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->Type == TT_LineComment || Tok->MustBreakBefore) + return 0; + do { + if (Tok->isOneOf(tok::l_brace, tok::r_brace)) + return 0; + Tok = Tok->Next; + } while (Tok != NULL); + + // Last, check that the third line contains a single closing brace. + Tok = (*(I + 2))->First; + if (Tok->getNextNonComment() != NULL || Tok->isNot(tok::r_brace) || + Tok->MustBreakBefore) + return 0; + + return 2; + } + return 0; + } + + bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I, + unsigned Limit) { + return 1 + (*(I + 1))->Last->TotalLength + 1 + + (*(I + 2))->Last->TotalLength <= + Limit; + } + + const FormatStyle &Style; +}; + class UnwrappedLineFormatter { public: UnwrappedLineFormatter(SourceManager &SourceMgr, @@ -378,9 +530,9 @@ public: WhitespaceManager *Whitespaces, const FormatStyle &Style) : SourceMgr(SourceMgr), Ranges(Ranges), Indenter(Indenter), - Whitespaces(Whitespaces), Style(Style) {} + Whitespaces(Whitespaces), Style(Style), Joiner(Style) {} - unsigned format(SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun, + unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun, int AdditionalIndent = 0) { assert(!Lines.empty()); unsigned Penalty = 0; @@ -390,8 +542,8 @@ public: bool PreviousLineWasTouched = false; const AnnotatedLine *PreviousLine = NULL; bool FormatPPDirective = false; - for (SmallVectorImpl<AnnotatedLine *>::iterator I = Lines.begin(), - E = Lines.end(); + for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(), + E = Lines.end(); I != E; ++I) { const AnnotatedLine &TheLine = **I; const FormatToken *FirstTok = TheLine.First; @@ -411,8 +563,13 @@ public: unsigned Indent = getIndent(IndentForLevel, TheLine.Level); if (static_cast<int>(Indent) + Offset >= 0) Indent += Offset; - if (!DryRun) - tryFitMultipleLinesInOne(Indent, I, E); + unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E); + if (!DryRun) { + for (unsigned i = 0; i < MergedLines; ++i) { + join(**(I + i), **(I + i + 1)); + } + } + I += MergedLines; bool WasMoved = PreviousLineWasTouched && FirstTok->NewlinesBefore == 0; if (TheLine.First->is(tok::eof)) { @@ -591,151 +748,6 @@ private: return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth; } - /// \brief Tries to merge lines into one. - /// - /// This will change \c Line and \c AnnotatedLine to contain the merged line, - /// if possible; note that \c I will be incremented when lines are merged. - void tryFitMultipleLinesInOne(unsigned Indent, - SmallVectorImpl<AnnotatedLine *>::iterator &I, - SmallVectorImpl<AnnotatedLine *>::iterator E) { - // We can never merge stuff if there are trailing line comments. - AnnotatedLine *TheLine = *I; - if (TheLine->Last->Type == TT_LineComment) - return; - - if (Indent > Style.ColumnLimit) - return; - - unsigned Limit = Style.ColumnLimit - Indent; - // If we already exceed the column limit, we set 'Limit' to 0. The different - // tryMerge..() functions can then decide whether to still do merging. - Limit = TheLine->Last->TotalLength > Limit - ? 0 - : Limit - TheLine->Last->TotalLength; - - if (I + 1 == E || (*(I + 1))->Type == LT_Invalid) - return; - - if (TheLine->Last->is(tok::l_brace)) { - tryMergeSimpleBlock(I, E, Limit); - } else if (Style.AllowShortIfStatementsOnASingleLine && - TheLine->First->is(tok::kw_if)) { - tryMergeSimpleControlStatement(I, E, Limit); - } else if (Style.AllowShortLoopsOnASingleLine && - TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) { - tryMergeSimpleControlStatement(I, E, Limit); - } else if (TheLine->InPPDirective && (TheLine->First->HasUnescapedNewline || - TheLine->First->IsFirst)) { - tryMergeSimplePPDirective(I, E, Limit); - } - } - - void tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::iterator &I, - SmallVectorImpl<AnnotatedLine *>::iterator E, - unsigned Limit) { - if (Limit == 0) - return; - AnnotatedLine &Line = **I; - if (!(*(I + 1))->InPPDirective || (*(I + 1))->First->HasUnescapedNewline) - return; - if (I + 2 != E && (*(I + 2))->InPPDirective && - !(*(I + 2))->First->HasUnescapedNewline) - return; - if (1 + (*(I + 1))->Last->TotalLength > Limit) - return; - join(Line, **(++I)); - } - - void - tryMergeSimpleControlStatement(SmallVectorImpl<AnnotatedLine *>::iterator &I, - SmallVectorImpl<AnnotatedLine *>::iterator E, - unsigned Limit) { - if (Limit == 0) - return; - if (Style.BreakBeforeBraces == FormatStyle::BS_Allman && - (*(I + 1))->First->is(tok::l_brace)) - return; - if ((*(I + 1))->InPPDirective != (*I)->InPPDirective || - ((*(I + 1))->InPPDirective && (*(I + 1))->First->HasUnescapedNewline)) - return; - AnnotatedLine &Line = **I; - if (Line.Last->isNot(tok::r_paren)) - return; - if (1 + (*(I + 1))->Last->TotalLength > Limit) - return; - if ((*(I + 1))->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for, - tok::kw_while) || - (*(I + 1))->First->Type == TT_LineComment) - return; - // Only inline simple if's (no nested if or else). - if (I + 2 != E && Line.First->is(tok::kw_if) && - (*(I + 2))->First->is(tok::kw_else)) - return; - join(Line, **(++I)); - } - - void tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::iterator &I, - SmallVectorImpl<AnnotatedLine *>::iterator E, - unsigned Limit) { - // No merging if the brace already is on the next line. - if (Style.BreakBeforeBraces != FormatStyle::BS_Attach) - return; - - // First, check that the current line allows merging. This is the case if - // we're not in a control flow statement and the last token is an opening - // brace. - AnnotatedLine &Line = **I; - if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace, - tok::kw_else, tok::kw_try, tok::kw_catch, - tok::kw_for, - // This gets rid of all ObjC @ keywords and methods. - tok::at, tok::minus, tok::plus)) - return; - - FormatToken *Tok = (*(I + 1))->First; - if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore && - (Tok->getNextNonComment() == NULL || - Tok->getNextNonComment()->is(tok::semi))) { - // We merge empty blocks even if the line exceeds the column limit. - Tok->SpacesRequiredBefore = 0; - Tok->CanBreakBefore = true; - join(Line, **(I + 1)); - I += 1; - } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace)) { - // Check that we still have three lines and they fit into the limit. - if (I + 2 == E || (*(I + 2))->Type == LT_Invalid || - !nextTwoLinesFitInto(I, Limit)) - return; - - // 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->Type == TT_LineComment || Tok->MustBreakBefore) - return; - do { - if (Tok->isOneOf(tok::l_brace, tok::r_brace)) - return; - Tok = Tok->Next; - } while (Tok != NULL); - - // Last, check that the third line contains a single closing brace. - Tok = (*(I + 2))->First; - if (Tok->getNextNonComment() != NULL || Tok->isNot(tok::r_brace) || - Tok->MustBreakBefore) - return; - - join(Line, **(I + 1)); - join(Line, **(I + 2)); - I += 2; - } - } - - bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::iterator I, - unsigned Limit) { - return 1 + (*(I + 1))->Last->TotalLength + 1 + - (*(I + 2))->Last->TotalLength <= - Limit; - } - void join(AnnotatedLine &A, const AnnotatedLine &B) { assert(!A.Last->Next); assert(!B.First->Previous); @@ -969,6 +981,7 @@ private: ContinuationIndenter *Indenter; WhitespaceManager *Whitespaces; FormatStyle Style; + LineJoiner Joiner; llvm::SpecificBumpPtrAllocator<StateNode> Allocator; }; |