|
@@ -559,8 +559,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
|
|
|
|
|
|
unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
|
|
|
bool DryRun, bool Newline) {
|
|
|
- const FormatToken &Current = *State.NextToken;
|
|
|
assert(State.Stack.size());
|
|
|
+ const FormatToken &Current = *State.NextToken;
|
|
|
|
|
|
if (Current.Type == TT_InheritanceColon)
|
|
|
State.Stack.back().AvoidBinPacking = true;
|
|
@@ -633,6 +633,44 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
|
|
|
State.Stack.back().JSFunctionInlined = !Newline;
|
|
|
}
|
|
|
|
|
|
+ moveStatePastFakeLParens(State, Newline);
|
|
|
+ moveStatePastScopeOpener(State, Newline);
|
|
|
+ moveStatePastScopeCloser(State);
|
|
|
+ moveStatePastFakeRParens(State);
|
|
|
+
|
|
|
+ if (Current.isStringLiteral() && State.StartOfStringLiteral == 0) {
|
|
|
+ State.StartOfStringLiteral = State.Column;
|
|
|
+ } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash) &&
|
|
|
+ !Current.isStringLiteral()) {
|
|
|
+ State.StartOfStringLiteral = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ State.Column += Current.ColumnWidth;
|
|
|
+ State.NextToken = State.NextToken->Next;
|
|
|
+ unsigned Penalty = breakProtrudingToken(Current, State, DryRun);
|
|
|
+ if (State.Column > getColumnLimit(State)) {
|
|
|
+ unsigned ExcessCharacters = State.Column - getColumnLimit(State);
|
|
|
+ Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Current.Role)
|
|
|
+ Current.Role->formatFromToken(State, this, DryRun);
|
|
|
+ // If the previous has a special role, let it consume tokens as appropriate.
|
|
|
+ // It is necessary to start at the previous token for the only implemented
|
|
|
+ // role (comma separated list). That way, the decision whether or not to break
|
|
|
+ // after the "{" is already done and both options are tried and evaluated.
|
|
|
+ // FIXME: This is ugly, find a better way.
|
|
|
+ if (Previous && Previous->Role)
|
|
|
+ Penalty += Previous->Role->formatAfterToken(State, this, DryRun);
|
|
|
+
|
|
|
+ return Penalty;
|
|
|
+}
|
|
|
+
|
|
|
+void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
|
|
|
+ bool Newline) {
|
|
|
+ const FormatToken &Current = *State.NextToken;
|
|
|
+ const FormatToken *Previous = Current.getPreviousNonComment();
|
|
|
+
|
|
|
// Don't add extra indentation for the first fake parenthesis after
|
|
|
// 'return', assignments or opening <({[. The indentation for these cases
|
|
|
// is special cased.
|
|
@@ -696,97 +734,91 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
|
|
|
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 NewIndentLevel = State.Stack.back().IndentLevel;
|
|
|
- bool AvoidBinPacking;
|
|
|
- bool BreakBeforeParameter = false;
|
|
|
- if (Current.is(tok::l_brace) ||
|
|
|
- Current.Type == TT_ArrayInitializerLSquare) {
|
|
|
- if (Current.MatchingParen && Current.BlockKind == BK_Block &&
|
|
|
- State.Stack.back().LambdasFound <= 1) {
|
|
|
- // If this is an l_brace starting a nested block, we pretend (wrt. to
|
|
|
- // indentation) that we already consumed the corresponding r_brace.
|
|
|
- // Thus, we remove all ParenStates caused by fake parentheses that end
|
|
|
- // at the r_brace. The net effect of this is that we don't indent
|
|
|
- // relative to the l_brace, if the nested block is the last parameter of
|
|
|
- // a function. For example, this formats:
|
|
|
- //
|
|
|
- // SomeFunction(a, [] {
|
|
|
- // f(); // break
|
|
|
- // });
|
|
|
- //
|
|
|
- // instead of:
|
|
|
- // SomeFunction(a, [] {
|
|
|
- // f(); // break
|
|
|
- // });
|
|
|
- //
|
|
|
- // If we have already found more than one lambda introducers on this
|
|
|
- // level, we opt out of this because similarity between the lambdas is
|
|
|
- // more important.
|
|
|
- for (unsigned i = 0; i != Current.MatchingParen->FakeRParens; ++i) {
|
|
|
- assert(State.Stack.size() > 1);
|
|
|
- if (State.Stack.size() == 1) {
|
|
|
- // Do not pop the last element.
|
|
|
- break;
|
|
|
- }
|
|
|
- State.Stack.pop_back();
|
|
|
- }
|
|
|
- // For some reason, ObjC blocks are indented like continuations.
|
|
|
- NewIndent =
|
|
|
- State.Stack.back().LastSpace + (Current.Type == TT_ObjCBlockLBrace
|
|
|
- ? Style.ContinuationIndentWidth
|
|
|
- : Style.IndentWidth);
|
|
|
- ++NewIndentLevel;
|
|
|
- BreakBeforeParameter = true;
|
|
|
- } else {
|
|
|
- NewIndent = State.Stack.back().LastSpace;
|
|
|
- if (Current.opensBlockTypeList(Style)) {
|
|
|
- NewIndent += Style.IndentWidth;
|
|
|
- NewIndent = std::min(State.Column + 2, NewIndent);
|
|
|
- ++NewIndentLevel;
|
|
|
- } else {
|
|
|
- NewIndent += Style.ContinuationIndentWidth;
|
|
|
- NewIndent = std::min(State.Column + 1, NewIndent);
|
|
|
- }
|
|
|
+void ContinuationIndenter::moveStatePastFakeRParens(LineState &State) {
|
|
|
+ const FormatToken &Current = *State.NextToken;
|
|
|
+
|
|
|
+ // Remove scopes created by fake parenthesis.
|
|
|
+ if (Current.isNot(tok::r_brace) ||
|
|
|
+ (Current.MatchingParen && Current.MatchingParen->BlockKind != BK_Block)) {
|
|
|
+ // Don't remove FakeRParens attached to r_braces that surround nested blocks
|
|
|
+ // as they will have been removed early (see above).
|
|
|
+ for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
|
|
|
+ unsigned VariablePos = State.Stack.back().VariablePos;
|
|
|
+ assert(State.Stack.size() > 1);
|
|
|
+ if (State.Stack.size() == 1) {
|
|
|
+ // Do not pop the last element.
|
|
|
+ break;
|
|
|
}
|
|
|
- const FormatToken *NextNoComment = Current.getNextNonComment();
|
|
|
- AvoidBinPacking = Current.BlockKind == BK_Block ||
|
|
|
- Current.Type == TT_ArrayInitializerLSquare ||
|
|
|
- Current.Type == TT_DictLiteral ||
|
|
|
- Style.Language == FormatStyle::LK_Proto ||
|
|
|
- !Style.BinPackParameters ||
|
|
|
- (NextNoComment &&
|
|
|
- NextNoComment->Type == TT_DesignatedInitializerPeriod);
|
|
|
- } else {
|
|
|
- NewIndent = Style.ContinuationIndentWidth +
|
|
|
- std::max(State.Stack.back().LastSpace,
|
|
|
- State.Stack.back().StartOfFunctionCall);
|
|
|
- AvoidBinPacking = !Style.BinPackParameters ||
|
|
|
- (Style.ExperimentalAutoDetectBinPacking &&
|
|
|
- (Current.PackingKind == PPK_OnePerLine ||
|
|
|
- (!BinPackInconclusiveFunctions &&
|
|
|
- Current.PackingKind == PPK_Inconclusive)));
|
|
|
- // 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.Type == TT_ObjCMethodExpr && Style.ColumnLimit != 0 &&
|
|
|
- getLengthToMatchingParen(Current) + State.Column >
|
|
|
- getColumnLimit(State))
|
|
|
- BreakBeforeParameter = true;
|
|
|
+ State.Stack.pop_back();
|
|
|
+ State.Stack.back().VariablePos = VariablePos;
|
|
|
}
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
|
|
|
+ bool Newline) {
|
|
|
+ const FormatToken &Current = *State.NextToken;
|
|
|
+ if (!Current.opensScope())
|
|
|
+ return;
|
|
|
|
|
|
- bool NoLineBreak = State.Stack.back().NoLineBreak ||
|
|
|
- (Current.Type == TT_TemplateOpener &&
|
|
|
- State.Stack.back().ContainsUnwrappedBuilder);
|
|
|
- State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
|
|
|
- State.Stack.back().LastSpace,
|
|
|
- AvoidBinPacking, NoLineBreak));
|
|
|
- State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
|
|
|
+ if (Current.MatchingParen && Current.BlockKind == BK_Block) {
|
|
|
+ moveStateToNewBlock(State);
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
+ unsigned NewIndent;
|
|
|
+ unsigned NewIndentLevel = State.Stack.back().IndentLevel;
|
|
|
+ bool AvoidBinPacking;
|
|
|
+ bool BreakBeforeParameter = false;
|
|
|
+ if (Current.is(tok::l_brace) || Current.Type == TT_ArrayInitializerLSquare) {
|
|
|
+ NewIndent = State.Stack.back().LastSpace;
|
|
|
+ if (Current.opensBlockTypeList(Style)) {
|
|
|
+ NewIndent += Style.IndentWidth;
|
|
|
+ NewIndent = std::min(State.Column + 2, NewIndent);
|
|
|
+ ++NewIndentLevel;
|
|
|
+ } else {
|
|
|
+ NewIndent += Style.ContinuationIndentWidth;
|
|
|
+ NewIndent = std::min(State.Column + 1, NewIndent);
|
|
|
+ }
|
|
|
+ const FormatToken *NextNoComment = Current.getNextNonComment();
|
|
|
+ AvoidBinPacking = Current.Type == TT_ArrayInitializerLSquare ||
|
|
|
+ Current.Type == TT_DictLiteral ||
|
|
|
+ Style.Language == FormatStyle::LK_Proto ||
|
|
|
+ !Style.BinPackParameters ||
|
|
|
+ (NextNoComment &&
|
|
|
+ NextNoComment->Type == TT_DesignatedInitializerPeriod);
|
|
|
+ } else {
|
|
|
+ NewIndent = Style.ContinuationIndentWidth +
|
|
|
+ std::max(State.Stack.back().LastSpace,
|
|
|
+ State.Stack.back().StartOfFunctionCall);
|
|
|
+ AvoidBinPacking = !Style.BinPackParameters ||
|
|
|
+ (Style.ExperimentalAutoDetectBinPacking &&
|
|
|
+ (Current.PackingKind == PPK_OnePerLine ||
|
|
|
+ (!BinPackInconclusiveFunctions &&
|
|
|
+ Current.PackingKind == PPK_Inconclusive)));
|
|
|
+ // 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.Type == TT_ObjCMethodExpr && Style.ColumnLimit != 0 &&
|
|
|
+ getLengthToMatchingParen(Current) + State.Column >
|
|
|
+ getColumnLimit(State))
|
|
|
+ BreakBeforeParameter = true;
|
|
|
+ }
|
|
|
+ bool NoLineBreak = State.Stack.back().NoLineBreak ||
|
|
|
+ (Current.Type == TT_TemplateOpener &&
|
|
|
+ State.Stack.back().ContainsUnwrappedBuilder);
|
|
|
+ State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
|
|
|
+ State.Stack.back().LastSpace,
|
|
|
+ AvoidBinPacking, NoLineBreak));
|
|
|
+ State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
|
|
|
+}
|
|
|
+
|
|
|
+void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) {
|
|
|
+ const FormatToken &Current = *State.NextToken;
|
|
|
+ if (!Current.closesScope())
|
|
|
+ return;
|
|
|
+
|
|
|
// If we encounter a closing ), ], } or >, we can remove a level from our
|
|
|
// stacks.
|
|
|
if (State.Stack.size() > 1 &&
|
|
@@ -801,50 +833,49 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
|
|
|
if (NextNonComment && NextNonComment->isNot(tok::l_square))
|
|
|
State.Stack.back().StartOfArraySubscripts = 0;
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- // Remove scopes created by fake parenthesis.
|
|
|
- if (Current.isNot(tok::r_brace) ||
|
|
|
- (Current.MatchingParen && Current.MatchingParen->BlockKind != BK_Block)) {
|
|
|
- // Don't remove FakeRParens attached to r_braces that surround nested blocks
|
|
|
- // as they will have been removed early (see above).
|
|
|
- for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
|
|
|
- unsigned VariablePos = State.Stack.back().VariablePos;
|
|
|
+void ContinuationIndenter::moveStateToNewBlock(LineState &State) {
|
|
|
+ // If this is an l_brace starting a nested block, we pretend (wrt. to
|
|
|
+ // indentation) that we already consumed the corresponding r_brace. Thus, we
|
|
|
+ // remove all ParenStates caused by fake parentheses that end at the r_brace.
|
|
|
+ // The net effect of this is that we don't indent relative to the l_brace, if
|
|
|
+ // the nested block is the last parameter of a function. For example, this
|
|
|
+ // formats:
|
|
|
+ //
|
|
|
+ // SomeFunction(a, [] {
|
|
|
+ // f(); // break
|
|
|
+ // });
|
|
|
+ //
|
|
|
+ // instead of:
|
|
|
+ // SomeFunction(a, [] {
|
|
|
+ // f(); // break
|
|
|
+ // });
|
|
|
+ //
|
|
|
+ // If we have already found more than one lambda introducers on this level, we
|
|
|
+ // opt out of this because similarity between the lambdas is more important.
|
|
|
+ if (State.Stack.back().LambdasFound <= 1) {
|
|
|
+ for (unsigned i = 0; i != State.NextToken->MatchingParen->FakeRParens;
|
|
|
+ ++i) {
|
|
|
assert(State.Stack.size() > 1);
|
|
|
if (State.Stack.size() == 1) {
|
|
|
// Do not pop the last element.
|
|
|
break;
|
|
|
}
|
|
|
State.Stack.pop_back();
|
|
|
- State.Stack.back().VariablePos = VariablePos;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (Current.isStringLiteral() && State.StartOfStringLiteral == 0) {
|
|
|
- State.StartOfStringLiteral = State.Column;
|
|
|
- } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash) &&
|
|
|
- !Current.isStringLiteral()) {
|
|
|
- State.StartOfStringLiteral = 0;
|
|
|
- }
|
|
|
-
|
|
|
- State.Column += Current.ColumnWidth;
|
|
|
- State.NextToken = State.NextToken->Next;
|
|
|
- unsigned Penalty = breakProtrudingToken(Current, State, DryRun);
|
|
|
- if (State.Column > getColumnLimit(State)) {
|
|
|
- unsigned ExcessCharacters = State.Column - getColumnLimit(State);
|
|
|
- Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
|
|
|
- }
|
|
|
-
|
|
|
- if (Current.Role)
|
|
|
- Current.Role->formatFromToken(State, this, DryRun);
|
|
|
- // If the previous has a special role, let it consume tokens as appropriate.
|
|
|
- // It is necessary to start at the previous token for the only implemented
|
|
|
- // role (comma separated list). That way, the decision whether or not to break
|
|
|
- // after the "{" is already done and both options are tried and evaluated.
|
|
|
- // FIXME: This is ugly, find a better way.
|
|
|
- if (Previous && Previous->Role)
|
|
|
- Penalty += Previous->Role->formatAfterToken(State, this, DryRun);
|
|
|
-
|
|
|
- return Penalty;
|
|
|
+ // For some reason, ObjC blocks are indented like continuations.
|
|
|
+ unsigned NewIndent = State.Stack.back().LastSpace +
|
|
|
+ (State.NextToken->Type == TT_ObjCBlockLBrace
|
|
|
+ ? Style.ContinuationIndentWidth
|
|
|
+ : Style.IndentWidth);
|
|
|
+ State.Stack.push_back(ParenState(
|
|
|
+ NewIndent, /*NewIndentLevel=*/State.Stack.back().IndentLevel + 1,
|
|
|
+ State.Stack.back().LastSpace, /*AvoidBinPacking=*/true,
|
|
|
+ State.Stack.back().NoLineBreak));
|
|
|
+ State.Stack.back().BreakBeforeParameter = true;
|
|
|
}
|
|
|
|
|
|
unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
|