r188543 - Split UnwrappedLineFormatter into individual components.
Daniel Jasper
djasper at google.com
Fri Aug 16 04:20:30 PDT 2013
Author: djasper
Date: Fri Aug 16 06:20:30 2013
New Revision: 188543
URL: http://llvm.org/viewvc/llvm-project?rev=188543&view=rev
Log:
Split UnwrappedLineFormatter into individual components.
Goals: Structure code better and make components easier to use for
future features (e.g. column layout for long braced initializers).
No functional changes intended.
Added:
cfe/trunk/lib/Format/ContinuationIndenter.cpp
cfe/trunk/lib/Format/ContinuationIndenter.h
Modified:
cfe/trunk/lib/Format/CMakeLists.txt
cfe/trunk/lib/Format/Format.cpp
Modified: cfe/trunk/lib/Format/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/CMakeLists.txt?rev=188543&r1=188542&r2=188543&view=diff
==============================================================================
--- cfe/trunk/lib/Format/CMakeLists.txt (original)
+++ cfe/trunk/lib/Format/CMakeLists.txt Fri Aug 16 06:20:30 2013
@@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangFormat
BreakableToken.cpp
+ ContinuationIndenter.cpp
Format.cpp
TokenAnnotator.cpp
UnwrappedLineParser.cpp
Added: cfe/trunk/lib/Format/ContinuationIndenter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=188543&view=auto
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp (added)
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Fri Aug 16 06:20:30 2013
@@ -0,0 +1,670 @@
+//===--- ContinuationIndenter.cpp - Format C++ code -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements the continuation indenter.
+///
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "format-formatter"
+
+#include "BreakableToken.h"
+#include "ContinuationIndenter.h"
+#include "WhitespaceManager.h"
+#include "clang/Basic/OperatorPrecedence.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "llvm/Support/Debug.h"
+#include <string>
+
+namespace clang {
+namespace format {
+
+// Returns the length of everything up to the first possible line break after
+// the ), ], } or > matching \c Tok.
+static unsigned getLengthToMatchingParen(const FormatToken &Tok) {
+ if (Tok.MatchingParen == NULL)
+ return 0;
+ FormatToken *End = Tok.MatchingParen;
+ while (End->Next && !End->Next->CanBreakBefore) {
+ End = End->Next;
+ }
+ return End->TotalLength - Tok.TotalLength + 1;
+}
+
+ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
+ SourceManager &SourceMgr,
+ const AnnotatedLine &Line,
+ unsigned FirstIndent,
+ WhitespaceManager &Whitespaces,
+ encoding::Encoding Encoding,
+ bool BinPackInconclusiveFunctions)
+ : Style(Style), SourceMgr(SourceMgr), Line(Line), FirstIndent(FirstIndent),
+ Whitespaces(Whitespaces), Encoding(Encoding),
+ BinPackInconclusiveFunctions(BinPackInconclusiveFunctions) {}
+
+LineState ContinuationIndenter::getInitialState() {
+ // Initialize state dependent on indent.
+ LineState State;
+ State.Column = FirstIndent;
+ State.NextToken = Line.First;
+ State.Stack.push_back(ParenState(FirstIndent, FirstIndent,
+ /*AvoidBinPacking=*/false,
+ /*NoLineBreak=*/false));
+ State.LineContainsContinuedForLoopSection = false;
+ State.ParenLevel = 0;
+ State.StartOfStringLiteral = 0;
+ State.StartOfLineLevel = State.ParenLevel;
+ State.LowestLevelOnLine = State.ParenLevel;
+ State.IgnoreStackForComparison = false;
+
+ // The first token has already been indented and thus consumed.
+ moveStateToNextToken(State, /*DryRun=*/false,
+ /*Newline=*/false);
+ return State;
+}
+
+bool ContinuationIndenter::canBreak(const LineState &State) {
+ const FormatToken &Current = *State.NextToken;
+ const FormatToken &Previous = *Current.Previous;
+ assert(&Previous == Current.Previous);
+ if (!Current.CanBreakBefore &&
+ !(Current.is(tok::r_brace) && State.Stack.back().BreakBeforeClosingBrace))
+ return false;
+ // The opening "{" of a braced list has to be on the same line as the first
+ // element if it is nested in another braced init list or function call.
+ if (!Current.MustBreakBefore && Previous.is(tok::l_brace) &&
+ Previous.Previous &&
+ Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma))
+ return false;
+ // This prevents breaks like:
+ // ...
+ // SomeParameter, OtherParameter).DoSomething(
+ // ...
+ // As they hide "DoSomething" and are generally bad for readability.
+ if (Previous.opensScope() && State.LowestLevelOnLine < State.StartOfLineLevel)
+ return false;
+ return !State.Stack.back().NoLineBreak;
+}
+
+bool ContinuationIndenter::mustBreak(const LineState &State) {
+ const FormatToken &Current = *State.NextToken;
+ const FormatToken &Previous = *Current.Previous;
+ if (Current.MustBreakBefore || Current.Type == TT_InlineASMColon)
+ return true;
+ if (!Style.Cpp11BracedListStyle && Current.is(tok::r_brace) &&
+ State.Stack.back().BreakBeforeClosingBrace)
+ return true;
+ if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection)
+ return true;
+ if (Style.BreakConstructorInitializersBeforeComma) {
+ if (Previous.Type == TT_CtorInitializerComma)
+ return false;
+ if (Current.Type == TT_CtorInitializerComma)
+ return true;
+ }
+ if ((Previous.isOneOf(tok::comma, tok::semi) || Current.is(tok::question) ||
+ (Current.Type == TT_ConditionalExpr &&
+ !(Current.is(tok::colon) && Previous.is(tok::question)))) &&
+ State.Stack.back().BreakBeforeParameter && !Current.isTrailingComment() &&
+ !Current.isOneOf(tok::r_paren, tok::r_brace))
+ return true;
+ if (Style.AlwaysBreakBeforeMultilineStrings &&
+ State.Column > State.Stack.back().Indent &&
+ Current.is(tok::string_literal) && Previous.isNot(tok::lessless) &&
+ Previous.Type != TT_InlineASMColon &&
+ ((Current.getNextNonComment() &&
+ Current.getNextNonComment()->is(tok::string_literal)) ||
+ (Current.TokenText.find("\\\n") != StringRef::npos)))
+ return true;
+
+ if (!Style.BreakBeforeBinaryOperators) {
+ // If we need to break somewhere inside the LHS of a binary expression, we
+ // should also break after the operator. Otherwise, the formatting would
+ // hide the operator precedence, e.g. in:
+ // if (aaaaaaaaaaaaaa ==
+ // bbbbbbbbbbbbbb && c) {..
+ // For comparisons, we only apply this rule, if the LHS is a binary
+ // expression itself as otherwise, the line breaks seem superfluous.
+ // We need special cases for ">>" which we have split into two ">" while
+ // lexing in order to make template parsing easier.
+ //
+ // FIXME: We'll need something similar for styles that break before binary
+ // operators.
+ bool IsComparison = (Previous.getPrecedence() == prec::Relational ||
+ Previous.getPrecedence() == prec::Equality) &&
+ Previous.Previous &&
+ Previous.Previous->Type != TT_BinaryOperator; // For >>.
+ bool LHSIsBinaryExpr =
+ Previous.Previous && Previous.Previous->FakeRParens > 0;
+ if (Previous.Type == TT_BinaryOperator &&
+ (!IsComparison || LHSIsBinaryExpr) &&
+ Current.Type != TT_BinaryOperator && // For >>.
+ !Current.isTrailingComment() &&
+ !Previous.isOneOf(tok::lessless, tok::question) &&
+ Previous.getPrecedence() != prec::Assignment &&
+ State.Stack.back().BreakBeforeParameter)
+ return true;
+ }
+
+ // Same as above, but for the first "<<" operator.
+ if (Current.is(tok::lessless) && State.Stack.back().BreakBeforeParameter &&
+ State.Stack.back().FirstLessLess == 0)
+ return true;
+
+ // FIXME: Comparing LongestObjCSelectorName to 0 is a hacky way of finding
+ // out whether it is the first parameter. Clean this up.
+ if (Current.Type == TT_ObjCSelectorName &&
+ Current.LongestObjCSelectorName == 0 &&
+ State.Stack.back().BreakBeforeParameter)
+ return true;
+ if ((Current.Type == TT_CtorInitializerColon ||
+ (Previous.ClosesTemplateDeclaration && State.ParenLevel == 0)))
+ return true;
+
+ if ((Current.Type == TT_StartOfName || Current.is(tok::kw_operator)) &&
+ Line.MightBeFunctionDecl && State.Stack.back().BreakBeforeParameter &&
+ State.ParenLevel == 0)
+ return true;
+ return false;
+}
+
+unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
+ bool DryRun) {
+ const FormatToken &Current = *State.NextToken;
+ const FormatToken &Previous = *State.NextToken->Previous;
+
+ // Extra penalty that needs to be added because of the way certain line
+ // breaks are chosen.
+ unsigned ExtraPenalty = 0;
+
+ if (State.Stack.size() == 0 || Current.Type == TT_ImplicitStringLiteral) {
+ // FIXME: Is this correct?
+ int WhitespaceLength = SourceMgr.getSpellingColumnNumber(
+ State.NextToken->WhitespaceRange.getEnd()) -
+ SourceMgr.getSpellingColumnNumber(
+ State.NextToken->WhitespaceRange.getBegin());
+ State.Column += WhitespaceLength + State.NextToken->CodePointCount;
+ State.NextToken = State.NextToken->Next;
+ return 0;
+ }
+
+ // If we are continuing an expression, we want to indent an extra 4 spaces.
+ unsigned ContinuationIndent =
+ std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + 4;
+ if (Newline) {
+ // Breaking before the first "<<" is generally not desirable if the LHS is
+ // short.
+ if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0 &&
+ State.Column <= Style.ColumnLimit / 2)
+ ExtraPenalty += Style.PenaltyBreakFirstLessLess;
+
+ State.Stack.back().ContainsLineBreak = true;
+ if (Current.is(tok::r_brace)) {
+ if (Current.BlockKind == BK_BracedInit)
+ State.Column = State.Stack[State.Stack.size() - 2].LastSpace;
+ else
+ State.Column = FirstIndent;
+ } else if (Current.is(tok::string_literal) &&
+ State.StartOfStringLiteral != 0) {
+ State.Column = State.StartOfStringLiteral;
+ State.Stack.back().BreakBeforeParameter = true;
+ } else if (Current.is(tok::lessless) &&
+ State.Stack.back().FirstLessLess != 0) {
+ State.Column = State.Stack.back().FirstLessLess;
+ } else if (Current.isOneOf(tok::period, tok::arrow) &&
+ Current.Type != TT_DesignatedInitializerPeriod) {
+ if (State.Stack.back().CallContinuation == 0) {
+ State.Column = ContinuationIndent;
+ State.Stack.back().CallContinuation = State.Column;
+ } else {
+ State.Column = State.Stack.back().CallContinuation;
+ }
+ } else if (Current.Type == TT_ConditionalExpr) {
+ State.Column = State.Stack.back().QuestionColumn;
+ } else if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0) {
+ State.Column = State.Stack.back().VariablePos;
+ } else if (Previous.ClosesTemplateDeclaration ||
+ ((Current.Type == TT_StartOfName ||
+ Current.is(tok::kw_operator)) &&
+ State.ParenLevel == 0 &&
+ (!Style.IndentFunctionDeclarationAfterType ||
+ Line.StartsDefinition))) {
+ State.Column = State.Stack.back().Indent;
+ } else if (Current.Type == TT_ObjCSelectorName) {
+ if (State.Stack.back().ColonPos > Current.CodePointCount) {
+ State.Column = State.Stack.back().ColonPos - Current.CodePointCount;
+ } else {
+ State.Column = State.Stack.back().Indent;
+ State.Stack.back().ColonPos = State.Column + Current.CodePointCount;
+ }
+ } else if (Current.is(tok::l_square) && Current.Type != TT_ObjCMethodExpr) {
+ if (State.Stack.back().StartOfArraySubscripts != 0)
+ State.Column = State.Stack.back().StartOfArraySubscripts;
+ else
+ State.Column = ContinuationIndent;
+ } else if (Current.Type == TT_StartOfName ||
+ Previous.isOneOf(tok::coloncolon, tok::equal) ||
+ Previous.Type == TT_ObjCMethodExpr) {
+ State.Column = ContinuationIndent;
+ } else if (Current.Type == TT_CtorInitializerColon) {
+ State.Column = FirstIndent + Style.ConstructorInitializerIndentWidth;
+ } else if (Current.Type == TT_CtorInitializerComma) {
+ State.Column = State.Stack.back().Indent;
+ } else {
+ State.Column = State.Stack.back().Indent;
+ // Ensure that we fall back to indenting 4 spaces instead of just
+ // flushing continuations left.
+ if (State.Column == FirstIndent)
+ State.Column += 4;
+ }
+
+ if (Current.is(tok::question))
+ State.Stack.back().BreakBeforeParameter = true;
+ if ((Previous.isOneOf(tok::comma, tok::semi) &&
+ !State.Stack.back().AvoidBinPacking) ||
+ Previous.Type == TT_BinaryOperator)
+ State.Stack.back().BreakBeforeParameter = false;
+ if (Previous.Type == TT_TemplateCloser && State.ParenLevel == 0)
+ State.Stack.back().BreakBeforeParameter = false;
+
+ if (!DryRun) {
+ unsigned NewLines = 1;
+ if (Current.is(tok::comment))
+ NewLines = std::max(NewLines, std::min(Current.NewlinesBefore,
+ Style.MaxEmptyLinesToKeep + 1));
+ Whitespaces.replaceWhitespace(Current, NewLines, State.Column,
+ State.Column, Line.InPPDirective);
+ }
+
+ if (!Current.isTrailingComment())
+ State.Stack.back().LastSpace = State.Column;
+ if (Current.isOneOf(tok::arrow, tok::period) &&
+ Current.Type != TT_DesignatedInitializerPeriod)
+ State.Stack.back().LastSpace += Current.CodePointCount;
+ State.StartOfLineLevel = State.ParenLevel;
+ State.LowestLevelOnLine = State.ParenLevel;
+
+ // Any break on this level means that the parent level has been broken
+ // and we need to avoid bin packing there.
+ for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
+ State.Stack[i].BreakBeforeParameter = true;
+ }
+ const FormatToken *TokenBefore = Current.getPreviousNonComment();
+ if (TokenBefore && !TokenBefore->isOneOf(tok::comma, tok::semi) &&
+ TokenBefore->Type != TT_TemplateCloser &&
+ TokenBefore->Type != TT_BinaryOperator && !TokenBefore->opensScope())
+ State.Stack.back().BreakBeforeParameter = true;
+
+ // If we break after {, we should also break before the corresponding }.
+ if (Previous.is(tok::l_brace))
+ State.Stack.back().BreakBeforeClosingBrace = true;
+
+ if (State.Stack.back().AvoidBinPacking) {
+ // If we are breaking after '(', '{', '<', this is not bin packing
+ // unless AllowAllParametersOfDeclarationOnNextLine is false.
+ if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) ||
+ Previous.Type == TT_BinaryOperator) ||
+ (!Style.AllowAllParametersOfDeclarationOnNextLine &&
+ Line.MustBeDeclaration))
+ State.Stack.back().BreakBeforeParameter = true;
+ }
+
+ } else {
+ if (Current.is(tok::equal) &&
+ (Line.First->is(tok::kw_for) || State.ParenLevel == 0) &&
+ State.Stack.back().VariablePos == 0) {
+ State.Stack.back().VariablePos = State.Column;
+ // Move over * and & if they are bound to the variable name.
+ const FormatToken *Tok = &Previous;
+ while (Tok && State.Stack.back().VariablePos >= Tok->CodePointCount) {
+ State.Stack.back().VariablePos -= Tok->CodePointCount;
+ if (Tok->SpacesRequiredBefore != 0)
+ break;
+ Tok = Tok->Previous;
+ }
+ if (Previous.PartOfMultiVariableDeclStmt)
+ State.Stack.back().LastSpace = State.Stack.back().VariablePos;
+ }
+
+ unsigned Spaces = State.NextToken->SpacesRequiredBefore;
+
+ if (!DryRun)
+ Whitespaces.replaceWhitespace(Current, 0, Spaces, State.Column + Spaces);
+
+ if (Current.Type == TT_ObjCSelectorName &&
+ State.Stack.back().ColonPos == 0) {
+ if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
+ State.Column + Spaces + Current.CodePointCount)
+ State.Stack.back().ColonPos =
+ State.Stack.back().Indent + Current.LongestObjCSelectorName;
+ else
+ State.Stack.back().ColonPos =
+ State.Column + Spaces + Current.CodePointCount;
+ }
+
+ if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr &&
+ Current.Type != TT_LineComment)
+ State.Stack.back().Indent = State.Column + Spaces;
+ if (Previous.is(tok::comma) && !Current.isTrailingComment() &&
+ State.Stack.back().AvoidBinPacking)
+ State.Stack.back().NoLineBreak = true;
+
+ State.Column += Spaces;
+ if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for))
+ // Treat the condition inside an if as if it was a second function
+ // parameter, i.e. let nested calls have an indent of 4.
+ State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(".
+ else if (Previous.is(tok::comma))
+ State.Stack.back().LastSpace = State.Column;
+ else if ((Previous.Type == TT_BinaryOperator ||
+ Previous.Type == TT_ConditionalExpr ||
+ Previous.Type == TT_CtorInitializerColon) &&
+ !(Previous.getPrecedence() == prec::Assignment &&
+ Current.FakeLParens.empty()))
+ // Always indent relative to the RHS of the expression unless this is a
+ // simple assignment without binary expression on the RHS.
+ State.Stack.back().LastSpace = State.Column;
+ else if (Previous.Type == TT_InheritanceColon)
+ State.Stack.back().Indent = State.Column;
+ else if (Previous.opensScope()) {
+ // If a function has multiple parameters (including a single parameter
+ // that is a binary expression) or a trailing call, indent all
+ // parameters from the opening parenthesis. This avoids confusing
+ // indents like:
+ // OuterFunction(InnerFunctionCall(
+ // ParameterToInnerFunction),
+ // SecondParameterToOuterFunction);
+ bool HasMultipleParameters = !Current.FakeLParens.empty();
+ bool HasTrailingCall = false;
+ if (Previous.MatchingParen) {
+ const FormatToken *Next = Previous.MatchingParen->getNextNonComment();
+ if (Next && Next->isOneOf(tok::period, tok::arrow))
+ HasTrailingCall = true;
+ }
+ if (HasMultipleParameters || HasTrailingCall)
+ State.Stack.back().LastSpace = State.Column;
+ }
+ }
+
+ return moveStateToNextToken(State, DryRun, Newline) + ExtraPenalty;
+}
+
+unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
+ bool DryRun, bool Newline) {
+ const FormatToken &Current = *State.NextToken;
+ assert(State.Stack.size());
+
+ if (Current.Type == TT_InheritanceColon)
+ State.Stack.back().AvoidBinPacking = true;
+ if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0)
+ State.Stack.back().FirstLessLess = State.Column;
+ if (Current.is(tok::l_square) &&
+ State.Stack.back().StartOfArraySubscripts == 0)
+ State.Stack.back().StartOfArraySubscripts = State.Column;
+ if (Current.is(tok::question))
+ State.Stack.back().QuestionColumn = State.Column;
+ if (!Current.opensScope() && !Current.closesScope())
+ State.LowestLevelOnLine =
+ std::min(State.LowestLevelOnLine, State.ParenLevel);
+ if (Current.isOneOf(tok::period, tok::arrow) &&
+ Line.Type == LT_BuilderTypeCall && State.ParenLevel == 0)
+ State.Stack.back().StartOfFunctionCall =
+ Current.LastInChainOfCalls ? 0 : State.Column + Current.CodePointCount;
+ if (Current.Type == TT_CtorInitializerColon) {
+ // Indent 2 from the column, so:
+ // SomeClass::SomeClass()
+ // : First(...), ...
+ // Next(...)
+ // ^ line up here.
+ State.Stack.back().Indent =
+ State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2);
+ if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
+ State.Stack.back().AvoidBinPacking = true;
+ State.Stack.back().BreakBeforeParameter = false;
+ }
+
+ // If return returns a binary expression, align after it.
+ if (Current.is(tok::kw_return) && !Current.FakeLParens.empty())
+ State.Stack.back().LastSpace = State.Column + 7;
+
+ // In ObjC method declaration we align on the ":" of parameters, but we need
+ // to ensure that we indent parameters on subsequent lines by at least 4.
+ if (Current.Type == TT_ObjCMethodSpecifier)
+ State.Stack.back().Indent += 4;
+
+ // Insert scopes created by fake parenthesis.
+ const FormatToken *Previous = Current.getPreviousNonComment();
+ // Don't add extra indentation for the first fake parenthesis after
+ // 'return', assignements or opening <({[. The indentation for these cases
+ // is special cased.
+ bool SkipFirstExtraIndent =
+ Current.is(tok::kw_return) ||
+ (Previous && (Previous->opensScope() ||
+ Previous->getPrecedence() == prec::Assignment));
+ for (SmallVectorImpl<prec::Level>::const_reverse_iterator
+ I = Current.FakeLParens.rbegin(),
+ E = Current.FakeLParens.rend();
+ I != E; ++I) {
+ ParenState NewParenState = State.Stack.back();
+ NewParenState.ContainsLineBreak = false;
+ NewParenState.Indent =
+ std::max(std::max(State.Column, NewParenState.Indent),
+ State.Stack.back().LastSpace);
+
+ // Always indent conditional expressions. Never indent expression where
+ // the 'operator' is ',', ';' or an assignment (i.e. *I <=
+ // prec::Assignment) as those have different indentation rules. Indent
+ // other expression, unless the indentation needs to be skipped.
+ if (*I == prec::Conditional ||
+ (!SkipFirstExtraIndent && *I > prec::Assignment &&
+ !Style.BreakBeforeBinaryOperators))
+ NewParenState.Indent += 4;
+ if (Previous && !Previous->opensScope())
+ NewParenState.BreakBeforeParameter = false;
+ State.Stack.push_back(NewParenState);
+ SkipFirstExtraIndent = false;
+ }
+
+ // If we encounter an opening (, [, { or <, we add a level to our stacks to
+ // prepare for the following tokens.
+ if (Current.opensScope()) {
+ unsigned NewIndent;
+ unsigned LastSpace = State.Stack.back().LastSpace;
+ bool AvoidBinPacking;
+ if (Current.is(tok::l_brace)) {
+ NewIndent =
+ LastSpace + (Style.Cpp11BracedListStyle ? 4 : Style.IndentWidth);
+ const FormatToken *NextNoComment = Current.getNextNonComment();
+ AvoidBinPacking = NextNoComment &&
+ NextNoComment->Type == TT_DesignatedInitializerPeriod;
+ } else {
+ NewIndent =
+ 4 + std::max(LastSpace, State.Stack.back().StartOfFunctionCall);
+ AvoidBinPacking = !Style.BinPackParameters ||
+ (Style.ExperimentalAutoDetectBinPacking &&
+ (Current.PackingKind == PPK_OnePerLine ||
+ (!BinPackInconclusiveFunctions &&
+ Current.PackingKind == PPK_Inconclusive)));
+ }
+
+ State.Stack.push_back(ParenState(NewIndent, LastSpace, AvoidBinPacking,
+ State.Stack.back().NoLineBreak));
+ ++State.ParenLevel;
+ }
+
+ // If this '[' opens an ObjC call, determine whether all parameters fit into
+ // one line and put one per line if they don't.
+ if (Current.is(tok::l_square) && Current.Type == TT_ObjCMethodExpr &&
+ Current.MatchingParen != NULL) {
+ if (getLengthToMatchingParen(Current) + State.Column > getColumnLimit())
+ State.Stack.back().BreakBeforeParameter = true;
+ }
+
+ // If we encounter a closing ), ], } or >, we can remove a level from our
+ // stacks.
+ if (Current.isOneOf(tok::r_paren, tok::r_square) ||
+ (Current.is(tok::r_brace) && State.NextToken != Line.First) ||
+ State.NextToken->Type == TT_TemplateCloser) {
+ State.Stack.pop_back();
+ --State.ParenLevel;
+ }
+ if (Current.is(tok::r_square)) {
+ // If this ends the array subscript expr, reset the corresponding value.
+ const FormatToken *NextNonComment = Current.getNextNonComment();
+ if (NextNonComment && NextNonComment->isNot(tok::l_square))
+ State.Stack.back().StartOfArraySubscripts = 0;
+ }
+
+ // Remove scopes created by fake parenthesis.
+ for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
+ unsigned VariablePos = State.Stack.back().VariablePos;
+ State.Stack.pop_back();
+ State.Stack.back().VariablePos = VariablePos;
+ }
+
+ if (Current.is(tok::string_literal) && State.StartOfStringLiteral == 0) {
+ State.StartOfStringLiteral = State.Column;
+ } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash,
+ tok::string_literal)) {
+ State.StartOfStringLiteral = 0;
+ }
+
+ State.Column += Current.CodePointCount;
+
+ State.NextToken = State.NextToken->Next;
+
+ if (!Newline && Style.AlwaysBreakBeforeMultilineStrings &&
+ Current.is(tok::string_literal) && Current.CanBreakBefore)
+ return 0;
+
+ return breakProtrudingToken(Current, State, DryRun);
+}
+
+unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
+ LineState &State,
+ bool DryRun) {
+ llvm::OwningPtr<BreakableToken> Token;
+ unsigned StartColumn = State.Column - Current.CodePointCount;
+ unsigned OriginalStartColumn =
+ SourceMgr.getSpellingColumnNumber(Current.getStartOfNonWhitespace()) - 1;
+
+ if (Current.is(tok::string_literal) &&
+ Current.Type != TT_ImplicitStringLiteral) {
+ // Only break up default narrow strings.
+ if (!Current.TokenText.startswith("\""))
+ return 0;
+ // Don't break string literals with escaped newlines. As clang-format must
+ // not change the string's content, it is unlikely that we'll end up with
+ // a better format.
+ if (Current.TokenText.find("\\\n") != StringRef::npos)
+ return 0;
+ // Exempts unterminated string literals from line breaking. The user will
+ // likely want to terminate the string before any line breaking is done.
+ if (Current.IsUnterminatedLiteral)
+ return 0;
+
+ Token.reset(new BreakableStringLiteral(Current, StartColumn,
+ Line.InPPDirective, Encoding));
+ } else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) {
+ Token.reset(new BreakableBlockComment(
+ Style, Current, StartColumn, OriginalStartColumn, !Current.Previous,
+ Line.InPPDirective, Encoding));
+ } else if (Current.Type == TT_LineComment &&
+ (Current.Previous == NULL ||
+ Current.Previous->Type != TT_ImplicitStringLiteral)) {
+ // Don't break line comments with escaped newlines. These look like
+ // separate line comments, but in fact contain a single line comment with
+ // multiple lines including leading whitespace and the '//' markers.
+ //
+ // FIXME: If we want to handle them correctly, we'll need to adjust
+ // leading whitespace in consecutive lines when changing indentation of
+ // the first line similar to what we do with block comments.
+ StringRef::size_type EscapedNewlinePos = Current.TokenText.find("\\\n");
+ if (EscapedNewlinePos != StringRef::npos) {
+ State.Column =
+ StartColumn +
+ encoding::getCodePointCount(
+ Current.TokenText.substr(0, EscapedNewlinePos), Encoding) +
+ 1;
+ return 0;
+ }
+
+ Token.reset(new BreakableLineComment(Current, StartColumn,
+ Line.InPPDirective, Encoding));
+ } else {
+ return 0;
+ }
+ if (Current.UnbreakableTailLength >= getColumnLimit())
+ return 0;
+
+ unsigned RemainingSpace = getColumnLimit() - Current.UnbreakableTailLength;
+ bool BreakInserted = false;
+ unsigned Penalty = 0;
+ unsigned RemainingTokenColumns = 0;
+ for (unsigned LineIndex = 0, EndIndex = Token->getLineCount();
+ LineIndex != EndIndex; ++LineIndex) {
+ if (!DryRun)
+ Token->replaceWhitespaceBefore(LineIndex, Whitespaces);
+ unsigned TailOffset = 0;
+ RemainingTokenColumns =
+ Token->getLineLengthAfterSplit(LineIndex, TailOffset, StringRef::npos);
+ while (RemainingTokenColumns > RemainingSpace) {
+ BreakableToken::Split Split =
+ Token->getSplit(LineIndex, TailOffset, getColumnLimit());
+ if (Split.first == StringRef::npos) {
+ // The last line's penalty is handled in addNextStateToQueue().
+ if (LineIndex < EndIndex - 1)
+ Penalty += Style.PenaltyExcessCharacter *
+ (RemainingTokenColumns - RemainingSpace);
+ break;
+ }
+ assert(Split.first != 0);
+ unsigned NewRemainingTokenColumns = Token->getLineLengthAfterSplit(
+ LineIndex, TailOffset + Split.first + Split.second, StringRef::npos);
+ assert(NewRemainingTokenColumns < RemainingTokenColumns);
+ if (!DryRun)
+ Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces);
+ Penalty += Current.is(tok::string_literal) ? Style.PenaltyBreakString
+ : Style.PenaltyBreakComment;
+ unsigned ColumnsUsed =
+ Token->getLineLengthAfterSplit(LineIndex, TailOffset, Split.first);
+ if (ColumnsUsed > getColumnLimit()) {
+ Penalty +=
+ Style.PenaltyExcessCharacter * (ColumnsUsed - getColumnLimit());
+ }
+ TailOffset += Split.first + Split.second;
+ RemainingTokenColumns = NewRemainingTokenColumns;
+ BreakInserted = true;
+ }
+ }
+
+ State.Column = RemainingTokenColumns;
+
+ if (BreakInserted) {
+ // If we break the token inside a parameter list, we need to break before
+ // the next parameter on all levels, so that the next parameter is clearly
+ // visible. Line comments already introduce a break.
+ if (Current.Type != TT_LineComment) {
+ for (unsigned i = 0, e = State.Stack.size(); i != e; ++i)
+ State.Stack[i].BreakBeforeParameter = true;
+ }
+
+ State.Stack.back().LastSpace = StartColumn;
+ }
+ return Penalty;
+}
+
+unsigned ContinuationIndenter::getColumnLimit() const {
+ // In preprocessor directives reserve two chars for trailing " \"
+ return Style.ColumnLimit - (Line.InPPDirective ? 2 : 0);
+}
+
+} // namespace format
+} // namespace clang
Added: cfe/trunk/lib/Format/ContinuationIndenter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.h?rev=188543&view=auto
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.h (added)
+++ cfe/trunk/lib/Format/ContinuationIndenter.h Fri Aug 16 06:20:30 2013
@@ -0,0 +1,277 @@
+//===--- ContinuationIndenter.h - Format C++ code ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements an indenter that manages the indentation of
+/// continuations.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H
+#define LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H
+
+#include "Encoding.h"
+#include "clang/Format/Format.h"
+
+namespace clang {
+class SourceManager;
+
+namespace format {
+
+class AnnotatedLine;
+struct FormatToken;
+struct LineState;
+struct ParenState;
+class WhitespaceManager;
+
+class ContinuationIndenter {
+public:
+ /// \brief Constructs a \c ContinuationIndenter to format \p Line starting in
+ /// column \p FirstIndent.
+ ContinuationIndenter(const FormatStyle &Style, SourceManager &SourceMgr,
+ const AnnotatedLine &Line, unsigned FirstIndent,
+ WhitespaceManager &Whitespaces,
+ encoding::Encoding Encoding,
+ bool BinPackInconclusiveFunctions);
+
+ /// \brief Get the initial state, i.e. the state after placing the line's
+ /// first token.
+ LineState getInitialState();
+
+ // FIXME: canBreak and mustBreak aren't strictly indentation-related. Find a
+ // better home.
+ /// \brief Returns \c true, if a line break after \p State is allowed.
+ bool canBreak(const LineState &State);
+
+ /// \brief Returns \c true, if a line break after \p State is mandatory.
+ bool mustBreak(const LineState &State);
+
+ /// \brief Appends the next token to \p State and updates information
+ /// necessary for indentation.
+ ///
+ /// Puts the token on the current line if \p Newline is \c false and adds a
+ /// line break and necessary indentation otherwise.
+ ///
+ /// If \p DryRun is \c false, also creates and stores the required
+ /// \c Replacement.
+ unsigned addTokenToState(LineState &State, bool Newline, bool DryRun);
+
+ /// \brief Get the column limit for this line. This is the style's column
+ /// limit, potentially reduced for preprocessor definitions.
+ unsigned getColumnLimit() const;
+
+private:
+ /// \brief Mark the next token as consumed in \p State and modify its stacks
+ /// accordingly.
+ unsigned moveStateToNextToken(LineState &State, bool DryRun, bool Newline);
+
+ /// \brief If the current token sticks out over the end of the line, break
+ /// it if possible.
+ ///
+ /// \returns An extra penalty if a token was broken, otherwise 0.
+ ///
+ /// The returned penalty will cover the cost of the additional line breaks and
+ /// column limit violation in all lines except for the last one. The penalty
+ /// for the column limit violation in the last line (and in single line
+ /// tokens) is handled in \c addNextStateToQueue.
+ unsigned breakProtrudingToken(const FormatToken &Current, LineState &State,
+ bool DryRun);
+
+ FormatStyle Style;
+ SourceManager &SourceMgr;
+ const AnnotatedLine &Line;
+ const unsigned FirstIndent;
+ WhitespaceManager &Whitespaces;
+ encoding::Encoding Encoding;
+ bool BinPackInconclusiveFunctions;
+};
+
+struct ParenState {
+ ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking,
+ bool NoLineBreak)
+ : Indent(Indent), LastSpace(LastSpace), FirstLessLess(0),
+ BreakBeforeClosingBrace(false), QuestionColumn(0),
+ AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
+ NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
+ StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0),
+ CallContinuation(0), VariablePos(0), ContainsLineBreak(false) {}
+
+ /// \brief The position to which a specific parenthesis level needs to be
+ /// indented.
+ unsigned Indent;
+
+ /// \brief The position of the last space on each level.
+ ///
+ /// Used e.g. to break like:
+ /// functionCall(Parameter, otherCall(
+ /// OtherParameter));
+ unsigned LastSpace;
+
+ /// \brief The position the first "<<" operator encountered on each level.
+ ///
+ /// Used to align "<<" operators. 0 if no such operator has been encountered
+ /// on a level.
+ unsigned FirstLessLess;
+
+ /// \brief Whether a newline needs to be inserted before the block's closing
+ /// brace.
+ ///
+ /// We only want to insert a newline before the closing brace if there also
+ /// was a newline after the beginning left brace.
+ bool BreakBeforeClosingBrace;
+
+ /// \brief The column of a \c ? in a conditional expression;
+ unsigned QuestionColumn;
+
+ /// \brief Avoid bin packing, i.e. multiple parameters/elements on multiple
+ /// lines, in this context.
+ bool AvoidBinPacking;
+
+ /// \brief Break after the next comma (or all the commas in this context if
+ /// \c AvoidBinPacking is \c true).
+ bool BreakBeforeParameter;
+
+ /// \brief Line breaking in this context would break a formatting rule.
+ bool NoLineBreak;
+
+ /// \brief The position of the colon in an ObjC method declaration/call.
+ unsigned ColonPos;
+
+ /// \brief The start of the most recent function in a builder-type call.
+ unsigned StartOfFunctionCall;
+
+ /// \brief Contains the start of array subscript expressions, so that they
+ /// can be aligned.
+ unsigned StartOfArraySubscripts;
+
+ /// \brief If a nested name specifier was broken over multiple lines, this
+ /// contains the start column of the second line. Otherwise 0.
+ unsigned NestedNameSpecifierContinuation;
+
+ /// \brief If a call expression was broken over multiple lines, this
+ /// contains the start column of the second line. Otherwise 0.
+ unsigned CallContinuation;
+
+ /// \brief The column of the first variable name in a variable declaration.
+ ///
+ /// Used to align further variables if necessary.
+ unsigned VariablePos;
+
+ /// \brief \c true if this \c ParenState already contains a line-break.
+ ///
+ /// The first line break in a certain \c ParenState causes extra penalty so
+ /// that clang-format prefers similar breaks, i.e. breaks in the same
+ /// parenthesis.
+ bool ContainsLineBreak;
+
+ bool operator<(const ParenState &Other) const {
+ if (Indent != Other.Indent)
+ return Indent < Other.Indent;
+ if (LastSpace != Other.LastSpace)
+ return LastSpace < Other.LastSpace;
+ if (FirstLessLess != Other.FirstLessLess)
+ return FirstLessLess < Other.FirstLessLess;
+ if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace)
+ return BreakBeforeClosingBrace;
+ if (QuestionColumn != Other.QuestionColumn)
+ return QuestionColumn < Other.QuestionColumn;
+ if (AvoidBinPacking != Other.AvoidBinPacking)
+ return AvoidBinPacking;
+ if (BreakBeforeParameter != Other.BreakBeforeParameter)
+ return BreakBeforeParameter;
+ if (NoLineBreak != Other.NoLineBreak)
+ return NoLineBreak;
+ if (ColonPos != Other.ColonPos)
+ return ColonPos < Other.ColonPos;
+ if (StartOfFunctionCall != Other.StartOfFunctionCall)
+ return StartOfFunctionCall < Other.StartOfFunctionCall;
+ if (StartOfArraySubscripts != Other.StartOfArraySubscripts)
+ return StartOfArraySubscripts < Other.StartOfArraySubscripts;
+ if (CallContinuation != Other.CallContinuation)
+ return CallContinuation < Other.CallContinuation;
+ if (VariablePos != Other.VariablePos)
+ return VariablePos < Other.VariablePos;
+ if (ContainsLineBreak != Other.ContainsLineBreak)
+ return ContainsLineBreak < Other.ContainsLineBreak;
+ return false;
+ }
+};
+
+/// \brief The current state when indenting a unwrapped line.
+///
+/// As the indenting tries different combinations this is copied by value.
+struct LineState {
+ /// \brief The number of used columns in the current line.
+ unsigned Column;
+
+ /// \brief The token that needs to be next formatted.
+ const FormatToken *NextToken;
+
+ /// \brief \c true if this line contains a continued for-loop section.
+ bool LineContainsContinuedForLoopSection;
+
+ /// \brief The level of nesting inside (), [], <> and {}.
+ unsigned ParenLevel;
+
+ /// \brief The \c ParenLevel at the start of this line.
+ unsigned StartOfLineLevel;
+
+ /// \brief The lowest \c ParenLevel on the current line.
+ unsigned LowestLevelOnLine;
+
+ /// \brief The start column of the string literal, if we're in a string
+ /// literal sequence, 0 otherwise.
+ unsigned StartOfStringLiteral;
+
+ /// \brief A stack keeping track of properties applying to parenthesis
+ /// levels.
+ std::vector<ParenState> Stack;
+
+ /// \brief Ignore the stack of \c ParenStates for state comparison.
+ ///
+ /// In long and deeply nested unwrapped lines, the current algorithm can
+ /// be insufficient for finding the best formatting with a reasonable amount
+ /// of time and memory. Setting this flag will effectively lead to the
+ /// algorithm not analyzing some combinations. However, these combinations
+ /// rarely contain the optimal solution: In short, accepting a higher
+ /// penalty early would need to lead to different values in the \c
+ /// ParenState stack (in an otherwise identical state) and these different
+ /// values would need to lead to a significant amount of avoided penalty
+ /// later.
+ ///
+ /// FIXME: Come up with a better algorithm instead.
+ bool IgnoreStackForComparison;
+
+ /// \brief Comparison operator to be able to used \c LineState in \c map.
+ bool operator<(const LineState &Other) const {
+ if (NextToken != Other.NextToken)
+ return NextToken < Other.NextToken;
+ if (Column != Other.Column)
+ return Column < Other.Column;
+ if (LineContainsContinuedForLoopSection !=
+ Other.LineContainsContinuedForLoopSection)
+ return LineContainsContinuedForLoopSection;
+ if (ParenLevel != Other.ParenLevel)
+ return ParenLevel < Other.ParenLevel;
+ if (StartOfLineLevel != Other.StartOfLineLevel)
+ return StartOfLineLevel < Other.StartOfLineLevel;
+ if (LowestLevelOnLine != Other.LowestLevelOnLine)
+ return LowestLevelOnLine < Other.LowestLevelOnLine;
+ if (StartOfStringLiteral != Other.StartOfStringLiteral)
+ return StartOfStringLiteral < Other.StartOfStringLiteral;
+ if (IgnoreStackForComparison || Other.IgnoreStackForComparison)
+ return false;
+ return Stack < Other.Stack;
+ }
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif // LLVM_CLANG_FORMAT_CONTINUATION_INDENTER_H
Modified: cfe/trunk/lib/Format/Format.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=188543&r1=188542&r2=188543&view=diff
==============================================================================
--- cfe/trunk/lib/Format/Format.cpp (original)
+++ cfe/trunk/lib/Format/Format.cpp Fri Aug 16 06:20:30 2013
@@ -15,12 +15,11 @@
#define DEBUG_TYPE "format-formatter"
-#include "BreakableToken.h"
+#include "ContinuationIndenter.h"
#include "TokenAnnotator.h"
#include "UnwrappedLineParser.h"
#include "WhitespaceManager.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
@@ -300,67 +299,37 @@ std::string configurationAsText(const Fo
return Stream.str();
}
-// Returns the length of everything up to the first possible line break after
-// the ), ], } or > matching \c Tok.
-static unsigned getLengthToMatchingParen(const FormatToken &Tok) {
- if (Tok.MatchingParen == NULL)
- return 0;
- FormatToken *End = Tok.MatchingParen;
- while (End->Next && !End->Next->CanBreakBefore) {
- End = End->Next;
- }
- return End->TotalLength - Tok.TotalLength + 1;
-}
-
namespace {
-class UnwrappedLineFormatter {
+class NoColumnLimitFormatter {
public:
- UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
- const AnnotatedLine &Line, unsigned FirstIndent,
- const FormatToken *RootToken,
- WhitespaceManager &Whitespaces,
- encoding::Encoding Encoding,
- bool BinPackInconclusiveFunctions)
- : Style(Style), SourceMgr(SourceMgr), Line(Line),
- FirstIndent(FirstIndent), RootToken(RootToken),
- Whitespaces(Whitespaces), Count(0), Encoding(Encoding),
- BinPackInconclusiveFunctions(BinPackInconclusiveFunctions) {}
-
- /// \brief Formats an \c UnwrappedLine.
- void format(const AnnotatedLine *NextLine) {
- // Initialize state dependent on indent.
- LineState State;
- State.Column = FirstIndent;
- State.NextToken = RootToken;
- State.Stack.push_back(ParenState(FirstIndent, FirstIndent,
- /*AvoidBinPacking=*/false,
- /*NoLineBreak=*/false));
- State.LineContainsContinuedForLoopSection = false;
- State.ParenLevel = 0;
- State.StartOfStringLiteral = 0;
- State.StartOfLineLevel = State.ParenLevel;
- State.LowestLevelOnLine = State.ParenLevel;
- State.IgnoreStackForComparison = false;
-
- // The first token has already been indented and thus consumed.
- moveStateToNextToken(State, /*DryRun=*/false, /*Newline=*/false);
+ NoColumnLimitFormatter(ContinuationIndenter *Indenter)
+ : Indenter(Indenter) {}
- if (Style.ColumnLimit == 0) {
- formatWithoutColumnLimit(State);
- return;
+ /// \brief Formats the line starting at \p State, simply keeping all of the
+ /// input's line breaking decisions.
+ void format() {
+ LineState State = Indenter->getInitialState();
+ while (State.NextToken != NULL) {
+ bool Newline =
+ Indenter->mustBreak(State) ||
+ (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
+ Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
}
+ }
+private:
+ ContinuationIndenter *Indenter;
+};
- // If everything fits on a single line, just put it there.
- unsigned ColumnLimit = Style.ColumnLimit;
- if (NextLine && NextLine->InPPDirective &&
- !NextLine->First->HasUnescapedNewline)
- ColumnLimit = getColumnLimit();
- if (Line.Last->TotalLength <= ColumnLimit - FirstIndent) {
- while (State.NextToken != NULL) {
- addTokenToState(false, false, State);
- }
- }
+class UnwrappedLineFormatter {
+public:
+ UnwrappedLineFormatter(ContinuationIndenter *Indenter,
+ const FormatStyle &Style, const AnnotatedLine &Line)
+ : Indenter(Indenter), Style(Style), Line(Line), Count(0) {}
+
+ /// \brief Formats an \c UnwrappedLine.
+ void format() {
+ LineState State = Indenter->getInitialState();
// If the ObjC method declaration does not fit on a line, we should format
// it with one arg per line.
@@ -372,717 +341,6 @@ public:
}
private:
- void DebugTokenState(const FormatToken &FormatTok) {
- const Token &Tok = FormatTok.Tok;
- llvm::dbgs() << StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
- Tok.getLength());
- llvm::dbgs();
- }
-
- struct ParenState {
- ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking,
- bool NoLineBreak)
- : Indent(Indent), LastSpace(LastSpace), FirstLessLess(0),
- BreakBeforeClosingBrace(false), QuestionColumn(0),
- AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
- NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
- StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0),
- CallContinuation(0), VariablePos(0), ContainsLineBreak(false) {}
-
- /// \brief The position to which a specific parenthesis level needs to be
- /// indented.
- unsigned Indent;
-
- /// \brief The position of the last space on each level.
- ///
- /// Used e.g. to break like:
- /// functionCall(Parameter, otherCall(
- /// OtherParameter));
- unsigned LastSpace;
-
- /// \brief The position the first "<<" operator encountered on each level.
- ///
- /// Used to align "<<" operators. 0 if no such operator has been encountered
- /// on a level.
- unsigned FirstLessLess;
-
- /// \brief Whether a newline needs to be inserted before the block's closing
- /// brace.
- ///
- /// We only want to insert a newline before the closing brace if there also
- /// was a newline after the beginning left brace.
- bool BreakBeforeClosingBrace;
-
- /// \brief The column of a \c ? in a conditional expression;
- unsigned QuestionColumn;
-
- /// \brief Avoid bin packing, i.e. multiple parameters/elements on multiple
- /// lines, in this context.
- bool AvoidBinPacking;
-
- /// \brief Break after the next comma (or all the commas in this context if
- /// \c AvoidBinPacking is \c true).
- bool BreakBeforeParameter;
-
- /// \brief Line breaking in this context would break a formatting rule.
- bool NoLineBreak;
-
- /// \brief The position of the colon in an ObjC method declaration/call.
- unsigned ColonPos;
-
- /// \brief The start of the most recent function in a builder-type call.
- unsigned StartOfFunctionCall;
-
- /// \brief Contains the start of array subscript expressions, so that they
- /// can be aligned.
- unsigned StartOfArraySubscripts;
-
- /// \brief If a nested name specifier was broken over multiple lines, this
- /// contains the start column of the second line. Otherwise 0.
- unsigned NestedNameSpecifierContinuation;
-
- /// \brief If a call expression was broken over multiple lines, this
- /// contains the start column of the second line. Otherwise 0.
- unsigned CallContinuation;
-
- /// \brief The column of the first variable name in a variable declaration.
- ///
- /// Used to align further variables if necessary.
- unsigned VariablePos;
-
- /// \brief \c true if this \c ParenState already contains a line-break.
- ///
- /// The first line break in a certain \c ParenState causes extra penalty so
- /// that clang-format prefers similar breaks, i.e. breaks in the same
- /// parenthesis.
- bool ContainsLineBreak;
-
- bool operator<(const ParenState &Other) const {
- if (Indent != Other.Indent)
- return Indent < Other.Indent;
- if (LastSpace != Other.LastSpace)
- return LastSpace < Other.LastSpace;
- if (FirstLessLess != Other.FirstLessLess)
- return FirstLessLess < Other.FirstLessLess;
- if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace)
- return BreakBeforeClosingBrace;
- if (QuestionColumn != Other.QuestionColumn)
- return QuestionColumn < Other.QuestionColumn;
- if (AvoidBinPacking != Other.AvoidBinPacking)
- return AvoidBinPacking;
- if (BreakBeforeParameter != Other.BreakBeforeParameter)
- return BreakBeforeParameter;
- if (NoLineBreak != Other.NoLineBreak)
- return NoLineBreak;
- if (ColonPos != Other.ColonPos)
- return ColonPos < Other.ColonPos;
- if (StartOfFunctionCall != Other.StartOfFunctionCall)
- return StartOfFunctionCall < Other.StartOfFunctionCall;
- if (StartOfArraySubscripts != Other.StartOfArraySubscripts)
- return StartOfArraySubscripts < Other.StartOfArraySubscripts;
- if (CallContinuation != Other.CallContinuation)
- return CallContinuation < Other.CallContinuation;
- if (VariablePos != Other.VariablePos)
- return VariablePos < Other.VariablePos;
- if (ContainsLineBreak != Other.ContainsLineBreak)
- return ContainsLineBreak < Other.ContainsLineBreak;
- return false;
- }
- };
-
- /// \brief The current state when indenting a unwrapped line.
- ///
- /// As the indenting tries different combinations this is copied by value.
- struct LineState {
- /// \brief The number of used columns in the current line.
- unsigned Column;
-
- /// \brief The token that needs to be next formatted.
- const FormatToken *NextToken;
-
- /// \brief \c true if this line contains a continued for-loop section.
- bool LineContainsContinuedForLoopSection;
-
- /// \brief The level of nesting inside (), [], <> and {}.
- unsigned ParenLevel;
-
- /// \brief The \c ParenLevel at the start of this line.
- unsigned StartOfLineLevel;
-
- /// \brief The lowest \c ParenLevel on the current line.
- unsigned LowestLevelOnLine;
-
- /// \brief The start column of the string literal, if we're in a string
- /// literal sequence, 0 otherwise.
- unsigned StartOfStringLiteral;
-
- /// \brief A stack keeping track of properties applying to parenthesis
- /// levels.
- std::vector<ParenState> Stack;
-
- /// \brief Ignore the stack of \c ParenStates for state comparison.
- ///
- /// In long and deeply nested unwrapped lines, the current algorithm can
- /// be insufficient for finding the best formatting with a reasonable amount
- /// of time and memory. Setting this flag will effectively lead to the
- /// algorithm not analyzing some combinations. However, these combinations
- /// rarely contain the optimal solution: In short, accepting a higher
- /// penalty early would need to lead to different values in the \c
- /// ParenState stack (in an otherwise identical state) and these different
- /// values would need to lead to a significant amount of avoided penalty
- /// later.
- ///
- /// FIXME: Come up with a better algorithm instead.
- bool IgnoreStackForComparison;
-
- /// \brief Comparison operator to be able to used \c LineState in \c map.
- bool operator<(const LineState &Other) const {
- if (NextToken != Other.NextToken)
- return NextToken < Other.NextToken;
- if (Column != Other.Column)
- return Column < Other.Column;
- if (LineContainsContinuedForLoopSection !=
- Other.LineContainsContinuedForLoopSection)
- return LineContainsContinuedForLoopSection;
- if (ParenLevel != Other.ParenLevel)
- return ParenLevel < Other.ParenLevel;
- if (StartOfLineLevel != Other.StartOfLineLevel)
- return StartOfLineLevel < Other.StartOfLineLevel;
- if (LowestLevelOnLine != Other.LowestLevelOnLine)
- return LowestLevelOnLine < Other.LowestLevelOnLine;
- if (StartOfStringLiteral != Other.StartOfStringLiteral)
- return StartOfStringLiteral < Other.StartOfStringLiteral;
- if (IgnoreStackForComparison || Other.IgnoreStackForComparison)
- return false;
- return Stack < Other.Stack;
- }
- };
-
- /// \brief Formats the line starting at \p State, simply keeping all of the
- /// input's line breaking decisions.
- void formatWithoutColumnLimit(LineState &State) {
- while (State.NextToken != NULL) {
- bool Newline = mustBreak(State) ||
- (canBreak(State) && State.NextToken->NewlinesBefore > 0);
- addTokenToState(Newline, /*DryRun=*/false, State);
- }
- }
-
- /// \brief Appends the next token to \p State and updates information
- /// necessary for indentation.
- ///
- /// Puts the token on the current line if \p Newline is \c false and adds a
- /// line break and necessary indentation otherwise.
- ///
- /// If \p DryRun is \c false, also creates and stores the required
- /// \c Replacement.
- unsigned addTokenToState(bool Newline, bool DryRun, LineState &State) {
- const FormatToken &Current = *State.NextToken;
- const FormatToken &Previous = *State.NextToken->Previous;
-
- // Extra penalty that needs to be added because of the way certain line
- // breaks are chosen.
- unsigned ExtraPenalty = 0;
-
- if (State.Stack.size() == 0 || Current.Type == TT_ImplicitStringLiteral) {
- // FIXME: Is this correct?
- int WhitespaceLength = SourceMgr.getSpellingColumnNumber(
- State.NextToken->WhitespaceRange.getEnd()) -
- SourceMgr.getSpellingColumnNumber(
- State.NextToken->WhitespaceRange.getBegin());
- State.Column += WhitespaceLength + State.NextToken->CodePointCount;
- State.NextToken = State.NextToken->Next;
- return 0;
- }
-
- // If we are continuing an expression, we want to indent an extra 4 spaces.
- unsigned ContinuationIndent =
- std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + 4;
- if (Newline) {
- // Breaking before the first "<<" is generally not desirable if the LHS is
- // short.
- if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0 &&
- State.Column <= Style.ColumnLimit / 2)
- ExtraPenalty += Style.PenaltyBreakFirstLessLess;
-
- State.Stack.back().ContainsLineBreak = true;
- if (Current.is(tok::r_brace)) {
- if (Current.BlockKind == BK_BracedInit)
- State.Column = State.Stack[State.Stack.size() - 2].LastSpace;
- else
- State.Column = FirstIndent;
- } else if (Current.is(tok::string_literal) &&
- State.StartOfStringLiteral != 0) {
- State.Column = State.StartOfStringLiteral;
- State.Stack.back().BreakBeforeParameter = true;
- } else if (Current.is(tok::lessless) &&
- State.Stack.back().FirstLessLess != 0) {
- State.Column = State.Stack.back().FirstLessLess;
- } else if (Current.isOneOf(tok::period, tok::arrow) &&
- Current.Type != TT_DesignatedInitializerPeriod) {
- if (State.Stack.back().CallContinuation == 0) {
- State.Column = ContinuationIndent;
- State.Stack.back().CallContinuation = State.Column;
- } else {
- State.Column = State.Stack.back().CallContinuation;
- }
- } else if (Current.Type == TT_ConditionalExpr) {
- State.Column = State.Stack.back().QuestionColumn;
- } else if (Previous.is(tok::comma) &&
- State.Stack.back().VariablePos != 0) {
- State.Column = State.Stack.back().VariablePos;
- } else if (Previous.ClosesTemplateDeclaration ||
- ((Current.Type == TT_StartOfName ||
- Current.is(tok::kw_operator)) &&
- State.ParenLevel == 0 &&
- (!Style.IndentFunctionDeclarationAfterType ||
- Line.StartsDefinition))) {
- State.Column = State.Stack.back().Indent;
- } else if (Current.Type == TT_ObjCSelectorName) {
- if (State.Stack.back().ColonPos > Current.CodePointCount) {
- State.Column = State.Stack.back().ColonPos - Current.CodePointCount;
- } else {
- State.Column = State.Stack.back().Indent;
- State.Stack.back().ColonPos = State.Column + Current.CodePointCount;
- }
- } else if (Current.is(tok::l_square) &&
- Current.Type != TT_ObjCMethodExpr) {
- if (State.Stack.back().StartOfArraySubscripts != 0)
- State.Column = State.Stack.back().StartOfArraySubscripts;
- else
- State.Column = ContinuationIndent;
- } else if (Current.Type == TT_StartOfName ||
- Previous.isOneOf(tok::coloncolon, tok::equal) ||
- Previous.Type == TT_ObjCMethodExpr) {
- State.Column = ContinuationIndent;
- } else if (Current.Type == TT_CtorInitializerColon) {
- State.Column = FirstIndent + Style.ConstructorInitializerIndentWidth;
- } else if (Current.Type == TT_CtorInitializerComma) {
- State.Column = State.Stack.back().Indent;
- } else {
- State.Column = State.Stack.back().Indent;
- // Ensure that we fall back to indenting 4 spaces instead of just
- // flushing continuations left.
- if (State.Column == FirstIndent)
- State.Column += 4;
- }
-
- if (Current.is(tok::question))
- State.Stack.back().BreakBeforeParameter = true;
- if ((Previous.isOneOf(tok::comma, tok::semi) &&
- !State.Stack.back().AvoidBinPacking) ||
- Previous.Type == TT_BinaryOperator)
- State.Stack.back().BreakBeforeParameter = false;
- if (Previous.Type == TT_TemplateCloser && State.ParenLevel == 0)
- State.Stack.back().BreakBeforeParameter = false;
-
- if (!DryRun) {
- unsigned NewLines = 1;
- if (Current.is(tok::comment))
- NewLines = std::max(
- NewLines,
- std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1));
- Whitespaces.replaceWhitespace(Current, NewLines, State.Column,
- State.Column, Line.InPPDirective);
- }
-
- if (!Current.isTrailingComment())
- State.Stack.back().LastSpace = State.Column;
- if (Current.isOneOf(tok::arrow, tok::period) &&
- Current.Type != TT_DesignatedInitializerPeriod)
- State.Stack.back().LastSpace += Current.CodePointCount;
- State.StartOfLineLevel = State.ParenLevel;
- State.LowestLevelOnLine = State.ParenLevel;
-
- // Any break on this level means that the parent level has been broken
- // and we need to avoid bin packing there.
- for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
- State.Stack[i].BreakBeforeParameter = true;
- }
- const FormatToken *TokenBefore = Current.getPreviousNonComment();
- if (TokenBefore && !TokenBefore->isOneOf(tok::comma, tok::semi) &&
- TokenBefore->Type != TT_TemplateCloser &&
- TokenBefore->Type != TT_BinaryOperator && !TokenBefore->opensScope())
- State.Stack.back().BreakBeforeParameter = true;
-
- // If we break after {, we should also break before the corresponding }.
- if (Previous.is(tok::l_brace))
- State.Stack.back().BreakBeforeClosingBrace = true;
-
- if (State.Stack.back().AvoidBinPacking) {
- // If we are breaking after '(', '{', '<', this is not bin packing
- // unless AllowAllParametersOfDeclarationOnNextLine is false.
- if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) ||
- Previous.Type == TT_BinaryOperator) ||
- (!Style.AllowAllParametersOfDeclarationOnNextLine &&
- Line.MustBeDeclaration))
- State.Stack.back().BreakBeforeParameter = true;
- }
-
- } else {
- if (Current.is(tok::equal) &&
- (RootToken->is(tok::kw_for) || State.ParenLevel == 0) &&
- State.Stack.back().VariablePos == 0) {
- State.Stack.back().VariablePos = State.Column;
- // Move over * and & if they are bound to the variable name.
- const FormatToken *Tok = &Previous;
- while (Tok && State.Stack.back().VariablePos >= Tok->CodePointCount) {
- State.Stack.back().VariablePos -= Tok->CodePointCount;
- if (Tok->SpacesRequiredBefore != 0)
- break;
- Tok = Tok->Previous;
- }
- if (Previous.PartOfMultiVariableDeclStmt)
- State.Stack.back().LastSpace = State.Stack.back().VariablePos;
- }
-
- unsigned Spaces = State.NextToken->SpacesRequiredBefore;
-
- if (!DryRun)
- Whitespaces.replaceWhitespace(Current, 0, Spaces,
- State.Column + Spaces);
-
- if (Current.Type == TT_ObjCSelectorName &&
- State.Stack.back().ColonPos == 0) {
- if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
- State.Column + Spaces + Current.CodePointCount)
- State.Stack.back().ColonPos =
- State.Stack.back().Indent + Current.LongestObjCSelectorName;
- else
- State.Stack.back().ColonPos =
- State.Column + Spaces + Current.CodePointCount;
- }
-
- if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr &&
- Current.Type != TT_LineComment)
- State.Stack.back().Indent = State.Column + Spaces;
- if (Previous.is(tok::comma) && !Current.isTrailingComment() &&
- State.Stack.back().AvoidBinPacking)
- State.Stack.back().NoLineBreak = true;
-
- State.Column += Spaces;
- if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for))
- // Treat the condition inside an if as if it was a second function
- // parameter, i.e. let nested calls have an indent of 4.
- State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(".
- else if (Previous.is(tok::comma))
- State.Stack.back().LastSpace = State.Column;
- else if ((Previous.Type == TT_BinaryOperator ||
- Previous.Type == TT_ConditionalExpr ||
- Previous.Type == TT_CtorInitializerColon) &&
- !(Previous.getPrecedence() == prec::Assignment &&
- Current.FakeLParens.empty()))
- // Always indent relative to the RHS of the expression unless this is a
- // simple assignment without binary expression on the RHS.
- State.Stack.back().LastSpace = State.Column;
- else if (Previous.Type == TT_InheritanceColon)
- State.Stack.back().Indent = State.Column;
- else if (Previous.opensScope()) {
- // If a function has multiple parameters (including a single parameter
- // that is a binary expression) or a trailing call, indent all
- // parameters from the opening parenthesis. This avoids confusing
- // indents like:
- // OuterFunction(InnerFunctionCall(
- // ParameterToInnerFunction),
- // SecondParameterToOuterFunction);
- bool HasMultipleParameters = !Current.FakeLParens.empty();
- bool HasTrailingCall = false;
- if (Previous.MatchingParen) {
- const FormatToken *Next = Previous.MatchingParen->getNextNonComment();
- if (Next && Next->isOneOf(tok::period, tok::arrow))
- HasTrailingCall = true;
- }
- if (HasMultipleParameters || HasTrailingCall)
- State.Stack.back().LastSpace = State.Column;
- }
- }
-
- return moveStateToNextToken(State, DryRun, Newline) + ExtraPenalty;
- }
-
- /// \brief Mark the next token as consumed in \p State and modify its stacks
- /// accordingly.
- unsigned moveStateToNextToken(LineState &State, bool DryRun, bool Newline) {
- const FormatToken &Current = *State.NextToken;
- assert(State.Stack.size());
-
- if (Current.Type == TT_InheritanceColon)
- State.Stack.back().AvoidBinPacking = true;
- if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0)
- State.Stack.back().FirstLessLess = State.Column;
- if (Current.is(tok::l_square) &&
- State.Stack.back().StartOfArraySubscripts == 0)
- State.Stack.back().StartOfArraySubscripts = State.Column;
- if (Current.is(tok::question))
- State.Stack.back().QuestionColumn = State.Column;
- if (!Current.opensScope() && !Current.closesScope())
- State.LowestLevelOnLine =
- std::min(State.LowestLevelOnLine, State.ParenLevel);
- if (Current.isOneOf(tok::period, tok::arrow) &&
- Line.Type == LT_BuilderTypeCall && State.ParenLevel == 0)
- State.Stack.back().StartOfFunctionCall =
- Current.LastInChainOfCalls ? 0
- : State.Column + Current.CodePointCount;
- if (Current.Type == TT_CtorInitializerColon) {
- // Indent 2 from the column, so:
- // SomeClass::SomeClass()
- // : First(...), ...
- // Next(...)
- // ^ line up here.
- State.Stack.back().Indent =
- State.Column +
- (Style.BreakConstructorInitializersBeforeComma ? 0 : 2);
- if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
- State.Stack.back().AvoidBinPacking = true;
- State.Stack.back().BreakBeforeParameter = false;
- }
-
- // If return returns a binary expression, align after it.
- if (Current.is(tok::kw_return) && !Current.FakeLParens.empty())
- State.Stack.back().LastSpace = State.Column + 7;
-
- // In ObjC method declaration we align on the ":" of parameters, but we need
- // to ensure that we indent parameters on subsequent lines by at least 4.
- if (Current.Type == TT_ObjCMethodSpecifier)
- State.Stack.back().Indent += 4;
-
- // Insert scopes created by fake parenthesis.
- const FormatToken *Previous = Current.getPreviousNonComment();
- // Don't add extra indentation for the first fake parenthesis after
- // 'return', assignements or opening <({[. The indentation for these cases
- // is special cased.
- bool SkipFirstExtraIndent =
- Current.is(tok::kw_return) ||
- (Previous && (Previous->opensScope() ||
- Previous->getPrecedence() == prec::Assignment));
- for (SmallVectorImpl<prec::Level>::const_reverse_iterator
- I = Current.FakeLParens.rbegin(),
- E = Current.FakeLParens.rend();
- I != E; ++I) {
- ParenState NewParenState = State.Stack.back();
- NewParenState.ContainsLineBreak = false;
- NewParenState.Indent =
- std::max(std::max(State.Column, NewParenState.Indent),
- State.Stack.back().LastSpace);
-
- // Always indent conditional expressions. Never indent expression where
- // the 'operator' is ',', ';' or an assignment (i.e. *I <=
- // prec::Assignment) as those have different indentation rules. Indent
- // other expression, unless the indentation needs to be skipped.
- if (*I == prec::Conditional ||
- (!SkipFirstExtraIndent && *I > prec::Assignment &&
- !Style.BreakBeforeBinaryOperators))
- NewParenState.Indent += 4;
- if (Previous && !Previous->opensScope())
- NewParenState.BreakBeforeParameter = false;
- State.Stack.push_back(NewParenState);
- SkipFirstExtraIndent = false;
- }
-
- // If we encounter an opening (, [, { or <, we add a level to our stacks to
- // prepare for the following tokens.
- if (Current.opensScope()) {
- unsigned NewIndent;
- unsigned LastSpace = State.Stack.back().LastSpace;
- bool AvoidBinPacking;
- if (Current.is(tok::l_brace)) {
- NewIndent =
- LastSpace + (Style.Cpp11BracedListStyle ? 4 : Style.IndentWidth);
- const FormatToken *NextNoComment = Current.getNextNonComment();
- AvoidBinPacking = NextNoComment &&
- NextNoComment->Type == TT_DesignatedInitializerPeriod;
- } else {
- NewIndent =
- 4 + std::max(LastSpace, State.Stack.back().StartOfFunctionCall);
- AvoidBinPacking = !Style.BinPackParameters ||
- (Style.ExperimentalAutoDetectBinPacking &&
- (Current.PackingKind == PPK_OnePerLine ||
- (!BinPackInconclusiveFunctions &&
- Current.PackingKind == PPK_Inconclusive)));
- }
-
- State.Stack.push_back(ParenState(NewIndent, LastSpace, AvoidBinPacking,
- State.Stack.back().NoLineBreak));
- ++State.ParenLevel;
- }
-
- // If this '[' opens an ObjC call, determine whether all parameters fit into
- // one line and put one per line if they don't.
- if (Current.is(tok::l_square) && Current.Type == TT_ObjCMethodExpr &&
- Current.MatchingParen != NULL) {
- if (getLengthToMatchingParen(Current) + State.Column > getColumnLimit())
- State.Stack.back().BreakBeforeParameter = true;
- }
-
- // If we encounter a closing ), ], } or >, we can remove a level from our
- // stacks.
- if (Current.isOneOf(tok::r_paren, tok::r_square) ||
- (Current.is(tok::r_brace) && State.NextToken != RootToken) ||
- State.NextToken->Type == TT_TemplateCloser) {
- State.Stack.pop_back();
- --State.ParenLevel;
- }
- if (Current.is(tok::r_square)) {
- // If this ends the array subscript expr, reset the corresponding value.
- const FormatToken *NextNonComment = Current.getNextNonComment();
- if (NextNonComment && NextNonComment->isNot(tok::l_square))
- State.Stack.back().StartOfArraySubscripts = 0;
- }
-
- // Remove scopes created by fake parenthesis.
- for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
- unsigned VariablePos = State.Stack.back().VariablePos;
- State.Stack.pop_back();
- State.Stack.back().VariablePos = VariablePos;
- }
-
- if (Current.is(tok::string_literal) && State.StartOfStringLiteral == 0) {
- State.StartOfStringLiteral = State.Column;
- } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash,
- tok::string_literal)) {
- State.StartOfStringLiteral = 0;
- }
-
- State.Column += Current.CodePointCount;
-
- State.NextToken = State.NextToken->Next;
-
- if (!Newline && Style.AlwaysBreakBeforeMultilineStrings &&
- Current.is(tok::string_literal) && Current.CanBreakBefore)
- return 0;
-
- return breakProtrudingToken(Current, State, DryRun);
- }
-
- /// \brief If the current token sticks out over the end of the line, break
- /// it if possible.
- ///
- /// \returns An extra penalty if a token was broken, otherwise 0.
- ///
- /// The returned penalty will cover the cost of the additional line breaks and
- /// column limit violation in all lines except for the last one. The penalty
- /// for the column limit violation in the last line (and in single line
- /// tokens) is handled in \c addNextStateToQueue.
- unsigned breakProtrudingToken(const FormatToken &Current, LineState &State,
- bool DryRun) {
- llvm::OwningPtr<BreakableToken> Token;
- unsigned StartColumn = State.Column - Current.CodePointCount;
- unsigned OriginalStartColumn =
- SourceMgr.getSpellingColumnNumber(Current.getStartOfNonWhitespace()) -
- 1;
-
- if (Current.is(tok::string_literal) &&
- Current.Type != TT_ImplicitStringLiteral) {
- // Only break up default narrow strings.
- if (!Current.TokenText.startswith("\""))
- return 0;
- // Don't break string literals with escaped newlines. As clang-format must
- // not change the string's content, it is unlikely that we'll end up with
- // a better format.
- if (Current.TokenText.find("\\\n") != StringRef::npos)
- return 0;
- // Exempts unterminated string literals from line breaking. The user will
- // likely want to terminate the string before any line breaking is done.
- if (Current.IsUnterminatedLiteral)
- return 0;
-
- Token.reset(new BreakableStringLiteral(Current, StartColumn,
- Line.InPPDirective, Encoding));
- } else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) {
- Token.reset(new BreakableBlockComment(
- Style, Current, StartColumn, OriginalStartColumn, !Current.Previous,
- Line.InPPDirective, Encoding));
- } else if (Current.Type == TT_LineComment &&
- (Current.Previous == NULL ||
- Current.Previous->Type != TT_ImplicitStringLiteral)) {
- // Don't break line comments with escaped newlines. These look like
- // separate line comments, but in fact contain a single line comment with
- // multiple lines including leading whitespace and the '//' markers.
- //
- // FIXME: If we want to handle them correctly, we'll need to adjust
- // leading whitespace in consecutive lines when changing indentation of
- // the first line similar to what we do with block comments.
- StringRef::size_type EscapedNewlinePos = Current.TokenText.find("\\\n");
- if (EscapedNewlinePos != StringRef::npos) {
- State.Column =
- StartColumn +
- encoding::getCodePointCount(
- Current.TokenText.substr(0, EscapedNewlinePos), Encoding) +
- 1;
- return 0;
- }
-
- Token.reset(new BreakableLineComment(Current, StartColumn,
- Line.InPPDirective, Encoding));
- } else {
- return 0;
- }
- if (Current.UnbreakableTailLength >= getColumnLimit())
- return 0;
-
- unsigned RemainingSpace = getColumnLimit() - Current.UnbreakableTailLength;
- bool BreakInserted = false;
- unsigned Penalty = 0;
- unsigned RemainingTokenColumns = 0;
- for (unsigned LineIndex = 0, EndIndex = Token->getLineCount();
- LineIndex != EndIndex; ++LineIndex) {
- if (!DryRun)
- Token->replaceWhitespaceBefore(LineIndex, Whitespaces);
- unsigned TailOffset = 0;
- RemainingTokenColumns = Token->getLineLengthAfterSplit(
- LineIndex, TailOffset, StringRef::npos);
- while (RemainingTokenColumns > RemainingSpace) {
- BreakableToken::Split Split =
- Token->getSplit(LineIndex, TailOffset, getColumnLimit());
- if (Split.first == StringRef::npos) {
- // The last line's penalty is handled in addNextStateToQueue().
- if (LineIndex < EndIndex - 1)
- Penalty += Style.PenaltyExcessCharacter *
- (RemainingTokenColumns - RemainingSpace);
- break;
- }
- assert(Split.first != 0);
- unsigned NewRemainingTokenColumns = Token->getLineLengthAfterSplit(
- LineIndex, TailOffset + Split.first + Split.second,
- StringRef::npos);
- assert(NewRemainingTokenColumns < RemainingTokenColumns);
- if (!DryRun)
- Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces);
- Penalty += Current.is(tok::string_literal) ? Style.PenaltyBreakString
- : Style.PenaltyBreakComment;
- unsigned ColumnsUsed =
- Token->getLineLengthAfterSplit(LineIndex, TailOffset, Split.first);
- if (ColumnsUsed > getColumnLimit()) {
- Penalty +=
- Style.PenaltyExcessCharacter * (ColumnsUsed - getColumnLimit());
- }
- TailOffset += Split.first + Split.second;
- RemainingTokenColumns = NewRemainingTokenColumns;
- BreakInserted = true;
- }
- }
-
- State.Column = RemainingTokenColumns;
-
- if (BreakInserted) {
- // If we break the token inside a parameter list, we need to break before
- // the next parameter on all levels, so that the next parameter is clearly
- // visible. Line comments already introduce a break.
- if (Current.Type != TT_LineComment) {
- for (unsigned i = 0, e = State.Stack.size(); i != e; ++i)
- State.Stack[i].BreakBeforeParameter = true;
- }
-
- State.Stack.back().LastSpace = StartColumn;
- }
- return Penalty;
- }
-
- unsigned getColumnLimit() {
- // In preprocessor directives reserve two chars for trailing " \"
- return Style.ColumnLimit - (Line.InPPDirective ? 2 : 0);
- }
-
/// \brief An edge in the solution space from \c Previous->State to \c State,
/// inserting a newline dependent on the \c NewLine.
struct StateNode {
@@ -1173,7 +431,7 @@ private:
<< (*I)->Previous->State.NextToken->SplitPenalty << "\n";
}
});
- addTokenToState((*I)->NewLine, false, State);
+ Indenter->addTokenToState(State, (*I)->NewLine, false);
}
}
@@ -1183,9 +441,9 @@ private:
/// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
bool NewLine) {
- if (NewLine && !canBreak(PreviousNode->State))
+ if (NewLine && !Indenter->canBreak(PreviousNode->State))
return;
- if (!NewLine && mustBreak(PreviousNode->State))
+ if (!NewLine && Indenter->mustBreak(PreviousNode->State))
return;
if (NewLine) {
if (!PreviousNode->State.Stack.back().ContainsLineBreak)
@@ -1195,9 +453,10 @@ private:
StateNode *Node = new (Allocator.Allocate())
StateNode(PreviousNode->State, NewLine, PreviousNode);
- Penalty += addTokenToState(NewLine, true, Node->State);
- if (Node->State.Column > getColumnLimit()) {
- unsigned ExcessCharacters = Node->State.Column - getColumnLimit();
+ Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
+ if (Node->State.Column > Indenter->getColumnLimit()) {
+ unsigned ExcessCharacters =
+ Node->State.Column - Indenter->getColumnLimit();
Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
}
@@ -1205,137 +464,15 @@ private:
++Count;
}
- /// \brief Returns \c true, if a line break after \p State is allowed.
- bool canBreak(const LineState &State) {
- const FormatToken &Current = *State.NextToken;
- const FormatToken &Previous = *Current.Previous;
- assert(&Previous == Current.Previous);
- if (!Current.CanBreakBefore &&
- !(Current.is(tok::r_brace) &&
- State.Stack.back().BreakBeforeClosingBrace))
- return false;
- // The opening "{" of a braced list has to be on the same line as the first
- // element if it is nested in another braced init list or function call.
- if (!Current.MustBreakBefore && Previous.is(tok::l_brace) &&
- Previous.Previous &&
- Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma))
- return false;
- // This prevents breaks like:
- // ...
- // SomeParameter, OtherParameter).DoSomething(
- // ...
- // As they hide "DoSomething" and are generally bad for readability.
- if (Previous.opensScope() &&
- State.LowestLevelOnLine < State.StartOfLineLevel)
- return false;
- return !State.Stack.back().NoLineBreak;
- }
-
- /// \brief Returns \c true, if a line break after \p State is mandatory.
- bool mustBreak(const LineState &State) {
- const FormatToken &Current = *State.NextToken;
- const FormatToken &Previous = *Current.Previous;
- if (Current.MustBreakBefore || Current.Type == TT_InlineASMColon)
- return true;
- if (!Style.Cpp11BracedListStyle && Current.is(tok::r_brace) &&
- State.Stack.back().BreakBeforeClosingBrace)
- return true;
- if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection)
- return true;
- if (Style.BreakConstructorInitializersBeforeComma) {
- if (Previous.Type == TT_CtorInitializerComma)
- return false;
- if (Current.Type == TT_CtorInitializerComma)
- return true;
- }
- if ((Previous.isOneOf(tok::comma, tok::semi) || Current.is(tok::question) ||
- (Current.Type == TT_ConditionalExpr &&
- !(Current.is(tok::colon) && Previous.is(tok::question)))) &&
- State.Stack.back().BreakBeforeParameter &&
- !Current.isTrailingComment() &&
- !Current.isOneOf(tok::r_paren, tok::r_brace))
- return true;
- if (Style.AlwaysBreakBeforeMultilineStrings &&
- State.Column > State.Stack.back().Indent &&
- Current.is(tok::string_literal) && Previous.isNot(tok::lessless) &&
- Previous.Type != TT_InlineASMColon &&
- ((Current.getNextNonComment() &&
- Current.getNextNonComment()->is(tok::string_literal)) ||
- (Current.TokenText.find("\\\n") != StringRef::npos)))
- return true;
-
- if (!Style.BreakBeforeBinaryOperators) {
- // If we need to break somewhere inside the LHS of a binary expression, we
- // should also break after the operator. Otherwise, the formatting would
- // hide the operator precedence, e.g. in:
- // if (aaaaaaaaaaaaaa ==
- // bbbbbbbbbbbbbb && c) {..
- // For comparisons, we only apply this rule, if the LHS is a binary
- // expression itself as otherwise, the line breaks seem superfluous.
- // We need special cases for ">>" which we have split into two ">" while
- // lexing in order to make template parsing easier.
- //
- // FIXME: We'll need something similar for styles that break before binary
- // operators.
- bool IsComparison = (Previous.getPrecedence() == prec::Relational ||
- Previous.getPrecedence() == prec::Equality) &&
- Previous.Previous && Previous.Previous->Type !=
- TT_BinaryOperator; // For >>.
- bool LHSIsBinaryExpr =
- Previous.Previous && Previous.Previous->FakeRParens > 0;
- if (Previous.Type == TT_BinaryOperator &&
- (!IsComparison || LHSIsBinaryExpr) &&
- Current.Type != TT_BinaryOperator && // For >>.
- !Current.isTrailingComment() &&
- !Previous.isOneOf(tok::lessless, tok::question) &&
- Previous.getPrecedence() != prec::Assignment &&
- State.Stack.back().BreakBeforeParameter)
- return true;
- }
-
- // Same as above, but for the first "<<" operator.
- if (Current.is(tok::lessless) && State.Stack.back().BreakBeforeParameter &&
- State.Stack.back().FirstLessLess == 0)
- return true;
-
- // FIXME: Comparing LongestObjCSelectorName to 0 is a hacky way of finding
- // out whether it is the first parameter. Clean this up.
- if (Current.Type == TT_ObjCSelectorName &&
- Current.LongestObjCSelectorName == 0 &&
- State.Stack.back().BreakBeforeParameter)
- return true;
- if ((Current.Type == TT_CtorInitializerColon ||
- (Previous.ClosesTemplateDeclaration && State.ParenLevel == 0)))
- return true;
-
- if ((Current.Type == TT_StartOfName || Current.is(tok::kw_operator)) &&
- Line.MightBeFunctionDecl && State.Stack.back().BreakBeforeParameter &&
- State.ParenLevel == 0)
- return true;
- return false;
- }
-
- // Returns the total number of columns required for the remaining tokens.
- unsigned getRemainingLength(const LineState &State) {
- if (State.NextToken && State.NextToken->Previous)
- return Line.Last->TotalLength - State.NextToken->Previous->TotalLength;
- return 0;
- }
-
+ ContinuationIndenter *Indenter;
FormatStyle Style;
- SourceManager &SourceMgr;
const AnnotatedLine &Line;
- const unsigned FirstIndent;
- const FormatToken *RootToken;
- WhitespaceManager &Whitespaces;
llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
QueueType Queue;
// Increasing count of \c StateNode items we have created. This is used
// to create a deterministic order independent of the container.
unsigned Count;
- encoding::Encoding Encoding;
- bool BinPackInconclusiveFunctions;
};
class FormatTokenLexer {
@@ -1549,10 +686,28 @@ public:
SourceMgr.getSpellingColumnNumber(FirstTok->Tok.getLocation()) -
1;
}
- UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent,
- TheLine.First, Whitespaces, Encoding,
- BinPackInconclusiveFunctions);
- Formatter.format(I + 1 != E ? &*(I + 1) : NULL);
+ ContinuationIndenter Indenter(Style, SourceMgr, TheLine, Indent,
+ Whitespaces, Encoding,
+ BinPackInconclusiveFunctions);
+
+ // If everything fits on a single line, just put it there.
+ unsigned ColumnLimit = Style.ColumnLimit;
+ if ((I + 1) != E && (I + 1)->InPPDirective &&
+ !(I + 1)->First->HasUnescapedNewline)
+ ColumnLimit = Indenter.getColumnLimit();
+
+ if (I->Last->TotalLength + Indent <= ColumnLimit) {
+ LineState State = Indenter.getInitialState();
+ while (State.NextToken != NULL)
+ Indenter.addTokenToState(State, false, false);
+ } else if (Style.ColumnLimit == 0) {
+ NoColumnLimitFormatter Formatter(&Indenter);
+ Formatter.format();
+ } else {
+ UnwrappedLineFormatter Formatter(&Indenter, Style, TheLine);
+ Formatter.format();
+ }
+
IndentForLevel[TheLine.Level] = LevelIndent;
PreviousLineWasTouched = true;
} else {
More information about the cfe-commits
mailing list