Refactoring: split addTokenToState into two methods.

Summary: Pure refactoring, should be no semantic changes.

Reviewers: djasper

Reviewed By: djasper

CC: cfe-commits, klimek

Differential Revision: http://llvm-reviews.chandlerc.com/D1796

llvm-svn: 191772
This commit is contained in:
Alexander Kornienko 2013-10-01 14:41:18 +00:00
parent a77b7b8427
commit 1f80396d03
2 changed files with 237 additions and 207 deletions

View File

@ -191,13 +191,6 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
bool DryRun,
unsigned ExtraSpaces) {
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *State.NextToken->Previous;
const FormatToken *PreviousNonComment =
State.NextToken->getPreviousNonComment();
// Extra penalty that needs to be added because of the way certain line
// breaks are chosen.
unsigned Penalty = 0;
if (State.Stack.size() == 0 || Current.Type == TT_ImplicitStringLiteral) {
// FIXME: Is this correct?
@ -210,220 +203,238 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
return 0;
}
unsigned Penalty = 0;
if (Newline)
Penalty = addTokenOnNewLine(State, DryRun);
else
addTokenOnCurrentLine(State, DryRun, ExtraSpaces);
return moveStateToNextToken(State, DryRun, Newline) + Penalty;
}
void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
unsigned ExtraSpaces) {
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *State.NextToken->Previous;
if (Current.is(tok::equal) &&
(State.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->ColumnWidth) {
State.Stack.back().VariablePos -= Tok->ColumnWidth;
if (Tok->SpacesRequiredBefore != 0)
break;
Tok = Tok->Previous;
}
if (Previous.PartOfMultiVariableDeclStmt)
State.Stack.back().LastSpace = State.Stack.back().VariablePos;
}
unsigned Spaces = Current.SpacesRequiredBefore + ExtraSpaces;
if (!DryRun)
Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/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.ColumnWidth)
State.Stack.back().ColonPos =
State.Stack.back().Indent + Current.LongestObjCSelectorName;
else
State.Stack.back().ColonPos = State.Column + Spaces + Current.ColumnWidth;
}
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;
if (startsSegmentOfBuilderTypeCall(Current))
State.Stack.back().ContainsUnwrappedBuilder = 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_UnaryOperator ||
Previous.Type == TT_CtorInitializerColon) &&
(Previous.getPrecedence() != prec::Assignment ||
Current.StartsBinaryExpression))
// Always indent relative to the RHS of the expression unless this is a
// simple assignment without binary expression on the RHS. Also indent
// relative to unary operators and the colons of constructor initializers.
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 a trailing call, indent all parameters from the
// opening parenthesis. This avoids confusing indents like:
// OuterFunction(InnerFunctionCall( // break
// ParameterToInnerFunction)) // break
// .SecondInnerFunctionCall();
bool HasTrailingCall = false;
if (Previous.MatchingParen) {
const FormatToken *Next = Previous.MatchingParen->getNextNonComment();
HasTrailingCall = Next && Next->isMemberAccess();
}
if (HasTrailingCall &&
State.Stack[State.Stack.size() - 2].CallContinuation == 0)
State.Stack.back().LastSpace = State.Column;
}
}
unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
bool DryRun) {
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *State.NextToken->Previous;
// 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) {
// The first line break on any ParenLevel causes an extra penalty in order
// prefer similar line breaks.
if (!State.Stack.back().ContainsLineBreak)
Penalty += 15;
State.Stack.back().ContainsLineBreak = true;
// Extra penalty that needs to be added because of the way certain line
// breaks are chosen.
unsigned Penalty = 0;
Penalty += State.NextToken->SplitPenalty;
const FormatToken *PreviousNonComment =
State.NextToken->getPreviousNonComment();
// The first line break on any ParenLevel causes an extra penalty in order
// prefer similar line breaks.
if (!State.Stack.back().ContainsLineBreak)
Penalty += 15;
State.Stack.back().ContainsLineBreak = true;
// 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)
Penalty += Style.PenaltyBreakFirstLessLess;
Penalty += State.NextToken->SplitPenalty;
if (Current.is(tok::l_brace) && Current.BlockKind == BK_Block) {
// 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)
Penalty += Style.PenaltyBreakFirstLessLess;
if (Current.is(tok::l_brace) && Current.BlockKind == BK_Block) {
State.Column = State.FirstIndent;
} else if (Current.is(tok::r_brace)) {
if (Current.MatchingParen &&
(Current.MatchingParen->BlockKind == BK_BracedInit ||
!Current.MatchingParen->Children.empty()))
State.Column = State.Stack[State.Stack.size() - 2].LastSpace;
else
State.Column = State.FirstIndent;
} else if (Current.is(tok::r_brace)) {
if (Current.MatchingParen &&
(Current.MatchingParen->BlockKind == BK_BracedInit ||
!Current.MatchingParen->Children.empty()))
State.Column = State.Stack[State.Stack.size() - 2].LastSpace;
else
State.Column = State.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.isMemberAccess()) {
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 ((PreviousNonComment &&
PreviousNonComment->ClosesTemplateDeclaration) ||
((Current.Type == TT_StartOfName ||
Current.is(tok::kw_operator)) &&
State.ParenLevel == 0 &&
(!Style.IndentFunctionDeclarationAfterType ||
State.Line->StartsDefinition))) {
State.Column = State.Stack.back().Indent;
} else if (Current.Type == TT_ObjCSelectorName) {
if (State.Stack.back().ColonPos > Current.ColumnWidth) {
State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
} else {
State.Column = State.Stack.back().Indent;
State.Stack.back().ColonPos = State.Column + Current.ColumnWidth;
}
} else if (Current.is(tok::l_square) && Current.Type != TT_ObjCMethodExpr &&
Current.Type != TT_LambdaLSquare) {
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) {
} 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.isMemberAccess()) {
if (State.Stack.back().CallContinuation == 0) {
State.Column = ContinuationIndent;
} else if (Current.Type == TT_CtorInitializerColon) {
State.Column =
State.FirstIndent + Style.ConstructorInitializerIndentWidth;
} else if (Current.Type == TT_CtorInitializerComma) {
State.Column = State.Stack.back().Indent;
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 ((PreviousNonComment &&
PreviousNonComment->ClosesTemplateDeclaration) ||
((Current.Type == TT_StartOfName ||
Current.is(tok::kw_operator)) &&
State.ParenLevel == 0 &&
(!Style.IndentFunctionDeclarationAfterType ||
State.Line->StartsDefinition))) {
State.Column = State.Stack.back().Indent;
} else if (Current.Type == TT_ObjCSelectorName) {
if (State.Stack.back().ColonPos > Current.ColumnWidth) {
State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
} 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 == State.FirstIndent)
State.Column += 4;
State.Stack.back().ColonPos = State.Column + Current.ColumnWidth;
}
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.Line->Level,
State.Column, State.Column,
State.Line->InPPDirective);
}
if (!Current.isTrailingComment())
State.Stack.back().LastSpace = State.Column;
if (Current.isMemberAccess())
State.Stack.back().LastSpace += Current.ColumnWidth;
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 &&
State.Line->MustBeDeclaration))
State.Stack.back().BreakBeforeParameter = true;
}
} else if (Current.is(tok::l_square) && Current.Type != TT_ObjCMethodExpr &&
Current.Type != TT_LambdaLSquare) {
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 = State.FirstIndent + Style.ConstructorInitializerIndentWidth;
} else if (Current.Type == TT_CtorInitializerComma) {
State.Column = State.Stack.back().Indent;
} else {
if (Current.is(tok::equal) &&
(State.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->ColumnWidth) {
State.Stack.back().VariablePos -= Tok->ColumnWidth;
if (Tok->SpacesRequiredBefore != 0)
break;
Tok = Tok->Previous;
}
if (Previous.PartOfMultiVariableDeclStmt)
State.Stack.back().LastSpace = State.Stack.back().VariablePos;
}
unsigned Spaces = State.NextToken->SpacesRequiredBefore + ExtraSpaces;
if (!DryRun)
Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/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.ColumnWidth)
State.Stack.back().ColonPos =
State.Stack.back().Indent + Current.LongestObjCSelectorName;
else
State.Stack.back().ColonPos =
State.Column + Spaces + Current.ColumnWidth;
}
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;
if (startsSegmentOfBuilderTypeCall(Current))
State.Stack.back().ContainsUnwrappedBuilder = 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_UnaryOperator ||
Previous.Type == TT_CtorInitializerColon) &&
(Previous.getPrecedence() != prec::Assignment ||
Current.StartsBinaryExpression))
// Always indent relative to the RHS of the expression unless this is a
// simple assignment without binary expression on the RHS. Also indent
// relative to unary operators and the colons of constructor initializers.
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 a trailing call, indent all parameters from the
// opening parenthesis. This avoids confusing indents like:
// OuterFunction(InnerFunctionCall( // break
// ParameterToInnerFunction)) // break
// .SecondInnerFunctionCall();
bool HasTrailingCall = false;
if (Previous.MatchingParen) {
const FormatToken *Next = Previous.MatchingParen->getNextNonComment();
HasTrailingCall = Next && Next->isMemberAccess();
}
if (HasTrailingCall &&
State.Stack[State.Stack.size() - 2].CallContinuation == 0)
State.Stack.back().LastSpace = State.Column;
}
State.Column = State.Stack.back().Indent;
// Ensure that we fall back to indenting 4 spaces instead of just
// flushing continuations left.
if (State.Column == State.FirstIndent)
State.Column += 4;
}
return moveStateToNextToken(State, DryRun, Newline) + Penalty;
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.Line->Level,
State.Column, State.Column,
State.Line->InPPDirective);
}
if (!Current.isTrailingComment())
State.Stack.back().LastSpace = State.Column;
if (Current.isMemberAccess())
State.Stack.back().LastSpace += Current.ColumnWidth;
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 &&
State.Line->MustBeDeclaration))
State.Stack.back().BreakBeforeParameter = true;
}
return Penalty;
}
unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,

View File

@ -84,6 +84,25 @@ private:
unsigned breakProtrudingToken(const FormatToken &Current, LineState &State,
bool DryRun);
/// \brief Appends the next token to \p State and updates information
/// necessary for indentation.
///
/// Puts the token on the current line.
///
/// If \p DryRun is \c false, also creates and stores the required
/// \c Replacement.
void addTokenOnCurrentLine(LineState &State, bool DryRun,
unsigned ExtraSpaces);
/// \brief Appends the next token to \p State and updates information
/// necessary for indentation.
///
/// Adds a line break and necessary indentation.
///
/// If \p DryRun is \c false, also creates and stores the required
/// \c Replacement.
unsigned addTokenOnNewLine(LineState &State, bool DryRun);
/// \brief Adds a multiline token to the \p State.
///
/// \returns Extra penalty for the first line of the literal: last line is