[clang-format] Refactor WhitespaceManager and friends

The main motivation behind this is to cleanup the WhitespaceManager and
make it more extensible for future alignment etc. features.
Specifically, WhitespaceManager has started to copy more and more code
that is already present in FormatToken. Instead, I think it makes more
sense to actually store a reference to each FormatToken for each change.

This has as a consequence led to a change in the calculation of indent
levels. Now, we actually compute them for each Token ahead of time,
which should be more efficient as it removes an unsigned value for the
ParenState, which is used during the combinatorial exploration of the
solution space.

No functional changes intended.

Review: https://reviews.llvm.org/D29300
llvm-svn: 293616
This commit is contained in:
Daniel Jasper 2017-01-31 11:25:01 +00:00
parent 5364cf3b56
commit 7d42f3f746
10 changed files with 182 additions and 211 deletions

View File

@ -181,10 +181,10 @@ unsigned BreakableSingleLineToken::getLineLengthAfterSplit(
} }
BreakableSingleLineToken::BreakableSingleLineToken( BreakableSingleLineToken::BreakableSingleLineToken(
const FormatToken &Tok, unsigned IndentLevel, unsigned StartColumn, const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
StringRef Prefix, StringRef Postfix, bool InPPDirective, StringRef Postfix, bool InPPDirective, encoding::Encoding Encoding,
encoding::Encoding Encoding, const FormatStyle &Style) const FormatStyle &Style)
: BreakableToken(Tok, IndentLevel, InPPDirective, Encoding, Style), : BreakableToken(Tok, InPPDirective, Encoding, Style),
StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix) { StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix) {
assert(Tok.TokenText.endswith(Postfix)); assert(Tok.TokenText.endswith(Postfix));
Line = Tok.TokenText.substr( Line = Tok.TokenText.substr(
@ -192,11 +192,11 @@ BreakableSingleLineToken::BreakableSingleLineToken(
} }
BreakableStringLiteral::BreakableStringLiteral( BreakableStringLiteral::BreakableStringLiteral(
const FormatToken &Tok, unsigned IndentLevel, unsigned StartColumn, const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
StringRef Prefix, StringRef Postfix, bool InPPDirective, StringRef Postfix, bool InPPDirective, encoding::Encoding Encoding,
encoding::Encoding Encoding, const FormatStyle &Style) const FormatStyle &Style)
: BreakableSingleLineToken(Tok, IndentLevel, StartColumn, Prefix, Postfix, : BreakableSingleLineToken(Tok, StartColumn, Prefix, Postfix, InPPDirective,
InPPDirective, Encoding, Style) {} Encoding, Style) {}
BreakableToken::Split BreakableToken::Split
BreakableStringLiteral::getSplit(unsigned LineIndex, unsigned TailOffset, BreakableStringLiteral::getSplit(unsigned LineIndex, unsigned TailOffset,
@ -218,16 +218,16 @@ void BreakableStringLiteral::insertBreak(unsigned LineIndex,
--LeadingSpaces; --LeadingSpaces;
Whitespaces.replaceWhitespaceInToken( Whitespaces.replaceWhitespaceInToken(
Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix, Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
Prefix, InPPDirective, 1, IndentLevel, LeadingSpaces); Prefix, InPPDirective, 1, LeadingSpaces);
} }
BreakableComment::BreakableComment(const FormatToken &Token, BreakableComment::BreakableComment(const FormatToken &Token,
unsigned IndentLevel, unsigned StartColumn, unsigned StartColumn,
unsigned OriginalStartColumn, unsigned OriginalStartColumn,
bool FirstInLine, bool InPPDirective, bool FirstInLine, bool InPPDirective,
encoding::Encoding Encoding, encoding::Encoding Encoding,
const FormatStyle &Style) const FormatStyle &Style)
: BreakableToken(Token, IndentLevel, InPPDirective, Encoding, Style), : BreakableToken(Token, InPPDirective, Encoding, Style),
StartColumn(StartColumn), OriginalStartColumn(OriginalStartColumn), StartColumn(StartColumn), OriginalStartColumn(OriginalStartColumn),
FirstInLine(FirstInLine) {} FirstInLine(FirstInLine) {}
@ -254,8 +254,7 @@ void BreakableComment::compressWhitespace(unsigned LineIndex,
unsigned CharsToRemove = Split.second; unsigned CharsToRemove = Split.second;
Whitespaces.replaceWhitespaceInToken( Whitespaces.replaceWhitespaceInToken(
tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "", "", tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "", "",
/*InPPDirective=*/false, /*InPPDirective=*/false, /*Newlines=*/0, /*Spaces=*/1);
/*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1);
} }
BreakableToken::Split BreakableToken::Split
@ -319,11 +318,11 @@ bool BreakableComment::mayReflow(unsigned LineIndex) const {
} }
BreakableBlockComment::BreakableBlockComment( BreakableBlockComment::BreakableBlockComment(
const FormatToken &Token, unsigned IndentLevel, unsigned StartColumn, const FormatToken &Token, unsigned StartColumn,
unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective, unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style) encoding::Encoding Encoding, const FormatStyle &Style)
: BreakableComment(Token, IndentLevel, StartColumn, OriginalStartColumn, : BreakableComment(Token, StartColumn, OriginalStartColumn, FirstInLine,
FirstInLine, InPPDirective, Encoding, Style) { InPPDirective, Encoding, Style) {
assert(Tok.is(TT_BlockComment) && assert(Tok.is(TT_BlockComment) &&
"block comment section must start with a block comment"); "block comment section must start with a block comment");
@ -484,7 +483,7 @@ void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
assert(LocalIndentAtLineBreak >= Prefix.size()); assert(LocalIndentAtLineBreak >= Prefix.size());
Whitespaces.replaceWhitespaceInToken( Whitespaces.replaceWhitespaceInToken(
tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "", Prefix, tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "", Prefix,
InPPDirective, /*Newlines=*/1, IndentLevel, InPPDirective, /*Newlines=*/1,
/*Spaces=*/LocalIndentAtLineBreak - Prefix.size()); /*Spaces=*/LocalIndentAtLineBreak - Prefix.size());
} }
@ -555,10 +554,9 @@ void BreakableBlockComment::replaceWhitespaceBefore(
WhitespaceOffsetInToken; WhitespaceOffsetInToken;
Whitespaces.replaceWhitespaceInToken( Whitespaces.replaceWhitespaceInToken(
tokenAt(LineIndex), WhitespaceOffsetInToken, tokenAt(LineIndex), WhitespaceOffsetInToken,
/*ReplaceChars=*/WhitespaceLength, /*ReplaceChars=*/WhitespaceLength, /*PreviousPostfix=*/"",
/*PreviousPostfix=*/"", /*CurrentPrefix=*/ReflowPrefix, InPPDirective, /*Newlines=*/0,
/*CurrentPrefix=*/ReflowPrefix, InPPDirective, /*Spaces=*/0);
/*Newlines=*/0, IndentLevel, /*Spaces=*/0);
// Check if we need to also insert a break at the whitespace range. // Check if we need to also insert a break at the whitespace range.
// For this we first adapt the reflow split relative to the beginning of the // For this we first adapt the reflow split relative to the beginning of the
// content. // content.
@ -604,9 +602,8 @@ void BreakableBlockComment::replaceWhitespaceBefore(
tokenAt(LineIndex).TokenText.data() - tokenAt(LineIndex).TokenText.data() -
WhitespaceOffsetInToken; WhitespaceOffsetInToken;
Whitespaces.replaceWhitespaceInToken( Whitespaces.replaceWhitespaceInToken(
tokenAt(LineIndex), WhitespaceOffsetInToken, WhitespaceLength, "", tokenAt(LineIndex), WhitespaceOffsetInToken, WhitespaceLength, "", Prefix,
Prefix, InPPDirective, /*Newlines=*/1, IndentLevel, InPPDirective, /*Newlines=*/1, ContentColumn[LineIndex] - Prefix.size());
ContentColumn[LineIndex] - Prefix.size());
} }
unsigned unsigned
@ -619,11 +616,11 @@ BreakableBlockComment::getContentStartColumn(unsigned LineIndex,
} }
BreakableLineCommentSection::BreakableLineCommentSection( BreakableLineCommentSection::BreakableLineCommentSection(
const FormatToken &Token, unsigned IndentLevel, unsigned StartColumn, const FormatToken &Token, unsigned StartColumn,
unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective, unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style) encoding::Encoding Encoding, const FormatStyle &Style)
: BreakableComment(Token, IndentLevel, StartColumn, OriginalStartColumn, : BreakableComment(Token, StartColumn, OriginalStartColumn, FirstInLine,
FirstInLine, InPPDirective, Encoding, Style) { InPPDirective, Encoding, Style) {
assert(Tok.is(TT_LineComment) && assert(Tok.is(TT_LineComment) &&
"line comment section must start with a line comment"); "line comment section must start with a line comment");
FormatToken *LineTok = nullptr; FormatToken *LineTok = nullptr;
@ -713,7 +710,7 @@ void BreakableLineCommentSection::insertBreak(unsigned LineIndex,
assert(IndentAtLineBreak >= Prefix[LineIndex].size()); assert(IndentAtLineBreak >= Prefix[LineIndex].size());
Whitespaces.replaceWhitespaceInToken( Whitespaces.replaceWhitespaceInToken(
tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "", tokenAt(LineIndex), BreakOffsetInToken, CharsToRemove, "",
Prefix[LineIndex], InPPDirective, /*Newlines=*/1, IndentLevel, Prefix[LineIndex], InPPDirective, /*Newlines=*/1,
/*Spaces=*/IndentAtLineBreak - Prefix[LineIndex].size()); /*Spaces=*/IndentAtLineBreak - Prefix[LineIndex].size());
} }
@ -758,12 +755,9 @@ void BreakableLineCommentSection::replaceWhitespaceBefore(
if (SplitBefore.first != StringRef::npos) { if (SplitBefore.first != StringRef::npos) {
// Reflow happens between tokens. Replace the whitespace between the // Reflow happens between tokens. Replace the whitespace between the
// tokens by the empty string. // tokens by the empty string.
Whitespaces.replaceWhitespace(*Tokens[LineIndex], Whitespaces.replaceWhitespace(
/*Newlines=*/0, *Tokens[LineIndex], /*Newlines=*/0, /*Spaces=*/0,
/*IndentLevel=*/IndentLevel, /*StartOfTokenColumn=*/StartColumn, /*InPPDirective=*/false);
/*Spaces=*/0,
/*StartOfTokenColumn=*/StartColumn,
/*InPPDirective=*/false);
// Replace the indent and prefix of the token with the reflow prefix. // Replace the indent and prefix of the token with the reflow prefix.
unsigned WhitespaceLength = unsigned WhitespaceLength =
Content[LineIndex].data() - tokenAt(LineIndex).TokenText.data(); Content[LineIndex].data() - tokenAt(LineIndex).TokenText.data();
@ -774,7 +768,6 @@ void BreakableLineCommentSection::replaceWhitespaceBefore(
/*CurrentPrefix=*/ReflowPrefix, /*CurrentPrefix=*/ReflowPrefix,
/*InPPDirective=*/false, /*InPPDirective=*/false,
/*Newlines=*/0, /*Newlines=*/0,
/*IndentLevel=*/IndentLevel,
/*Spaces=*/0); /*Spaces=*/0);
} else { } else {
// This is the first line for the current token, but no reflow with the // This is the first line for the current token, but no reflow with the
@ -786,7 +779,6 @@ void BreakableLineCommentSection::replaceWhitespaceBefore(
if (tokenAt(LineIndex).OriginalColumn != LineColumn) { if (tokenAt(LineIndex).OriginalColumn != LineColumn) {
Whitespaces.replaceWhitespace(*Tokens[LineIndex], Whitespaces.replaceWhitespace(*Tokens[LineIndex],
/*Newlines=*/1, /*Newlines=*/1,
/*IndentLevel=*/IndentLevel,
/*Spaces=*/LineColumn, /*Spaces=*/LineColumn,
/*StartOfTokenColumn=*/LineColumn, /*StartOfTokenColumn=*/LineColumn,
/*InPPDirective=*/false); /*InPPDirective=*/false);
@ -806,9 +798,7 @@ void BreakableLineCommentSection::replaceWhitespaceBefore(
"at most a space"); "at most a space");
Whitespaces.replaceWhitespaceInToken( Whitespaces.replaceWhitespaceInToken(
tokenAt(LineIndex), OriginalPrefix[LineIndex].size(), 0, "", "", tokenAt(LineIndex), OriginalPrefix[LineIndex].size(), 0, "", "",
/*InPPDirective=*/false, /*InPPDirective=*/false, /*Newlines=*/0, /*Spaces=*/1);
/*Newlines=*/0, /*IndentLevel=*/0,
/*Spaces=*/1);
} }
// Add a break after a reflow split has been introduced, if necessary. // Add a break after a reflow split has been introduced, if necessary.
// Note that this break doesn't need to be penalized, since it doesn't change // Note that this break doesn't need to be penalized, since it doesn't change

View File

@ -149,14 +149,12 @@ public:
virtual void updateNextToken(LineState &State) const {} virtual void updateNextToken(LineState &State) const {}
protected: protected:
BreakableToken(const FormatToken &Tok, unsigned IndentLevel, BreakableToken(const FormatToken &Tok, bool InPPDirective,
bool InPPDirective, encoding::Encoding Encoding, encoding::Encoding Encoding, const FormatStyle &Style)
const FormatStyle &Style) : Tok(Tok), InPPDirective(InPPDirective), Encoding(Encoding),
: Tok(Tok), IndentLevel(IndentLevel), InPPDirective(InPPDirective), Style(Style) {}
Encoding(Encoding), Style(Style) {}
const FormatToken &Tok; const FormatToken &Tok;
const unsigned IndentLevel;
const bool InPPDirective; const bool InPPDirective;
const encoding::Encoding Encoding; const encoding::Encoding Encoding;
const FormatStyle &Style; const FormatStyle &Style;
@ -172,10 +170,9 @@ public:
StringRef::size_type Length) const override; StringRef::size_type Length) const override;
protected: protected:
BreakableSingleLineToken(const FormatToken &Tok, unsigned IndentLevel, BreakableSingleLineToken(const FormatToken &Tok, unsigned StartColumn,
unsigned StartColumn, StringRef Prefix, StringRef Prefix, StringRef Postfix,
StringRef Postfix, bool InPPDirective, bool InPPDirective, encoding::Encoding Encoding,
encoding::Encoding Encoding,
const FormatStyle &Style); const FormatStyle &Style);
// The column in which the token starts. // The column in which the token starts.
@ -194,10 +191,10 @@ public:
/// ///
/// \p StartColumn specifies the column in which the token will start /// \p StartColumn specifies the column in which the token will start
/// after formatting. /// after formatting.
BreakableStringLiteral(const FormatToken &Tok, unsigned IndentLevel, BreakableStringLiteral(const FormatToken &Tok, unsigned StartColumn,
unsigned StartColumn, StringRef Prefix, StringRef Prefix, StringRef Postfix,
StringRef Postfix, bool InPPDirective, bool InPPDirective, encoding::Encoding Encoding,
encoding::Encoding Encoding, const FormatStyle &Style); const FormatStyle &Style);
Split getSplit(unsigned LineIndex, unsigned TailOffset, Split getSplit(unsigned LineIndex, unsigned TailOffset,
unsigned ColumnLimit) const override; unsigned ColumnLimit) const override;
@ -215,10 +212,10 @@ protected:
/// after formatting, while \p OriginalStartColumn specifies in which /// after formatting, while \p OriginalStartColumn specifies in which
/// column the comment started before formatting. /// column the comment started before formatting.
/// If the comment starts a line after formatting, set \p FirstInLine to true. /// If the comment starts a line after formatting, set \p FirstInLine to true.
BreakableComment(const FormatToken &Token, unsigned IndentLevel, BreakableComment(const FormatToken &Token, unsigned StartColumn,
unsigned StartColumn, unsigned OriginalStartColumn, unsigned OriginalStartColumn, bool FirstInLine,
bool FirstInLine, bool InPPDirective, bool InPPDirective, encoding::Encoding Encoding,
encoding::Encoding Encoding, const FormatStyle &Style); const FormatStyle &Style);
public: public:
unsigned getLineCount() const override; unsigned getLineCount() const override;
@ -299,10 +296,10 @@ protected:
class BreakableBlockComment : public BreakableComment { class BreakableBlockComment : public BreakableComment {
public: public:
BreakableBlockComment(const FormatToken &Token, unsigned IndentLevel, BreakableBlockComment(const FormatToken &Token, unsigned StartColumn,
unsigned StartColumn, unsigned OriginalStartColumn, unsigned OriginalStartColumn, bool FirstInLine,
bool FirstInLine, bool InPPDirective, bool InPPDirective, encoding::Encoding Encoding,
encoding::Encoding Encoding, const FormatStyle &Style); const FormatStyle &Style);
unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned getLineLengthAfterSplit(unsigned LineIndex,
unsigned TailOffset, unsigned TailOffset,
@ -363,8 +360,7 @@ private:
class BreakableLineCommentSection : public BreakableComment { class BreakableLineCommentSection : public BreakableComment {
public: public:
BreakableLineCommentSection(const FormatToken &Token, unsigned IndentLevel, BreakableLineCommentSection(const FormatToken &Token, unsigned StartColumn,
unsigned StartColumn,
unsigned OriginalStartColumn, bool FirstInLine, unsigned OriginalStartColumn, bool FirstInLine,
bool InPPDirective, encoding::Encoding Encoding, bool InPPDirective, encoding::Encoding Encoding,
const FormatStyle &Style); const FormatStyle &Style);

View File

@ -80,7 +80,7 @@ LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
State.Column = FirstIndent; State.Column = FirstIndent;
State.Line = Line; State.Line = Line;
State.NextToken = Line->First; State.NextToken = Line->First;
State.Stack.push_back(ParenState(FirstIndent, Line->Level, FirstIndent, State.Stack.push_back(ParenState(FirstIndent, FirstIndent,
/*AvoidBinPacking=*/false, /*AvoidBinPacking=*/false,
/*NoLineBreak=*/false)); /*NoLineBreak=*/false));
State.LineContainsContinuedForLoopSection = false; State.LineContainsContinuedForLoopSection = false;
@ -347,8 +347,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
unsigned Spaces = Current.SpacesRequiredBefore + ExtraSpaces; unsigned Spaces = Current.SpacesRequiredBefore + ExtraSpaces;
if (!DryRun) if (!DryRun)
Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0, Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, Spaces,
Spaces, State.Column + Spaces); State.Column + Spaces);
if (Current.is(TT_SelectorName) && if (Current.is(TT_SelectorName) &&
!State.Stack.back().ObjCSelectorNameFound) { !State.Stack.back().ObjCSelectorNameFound) {
@ -574,9 +574,8 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
if (!DryRun) { if (!DryRun) {
unsigned Newlines = std::max( unsigned Newlines = std::max(
1u, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1)); 1u, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1));
Whitespaces.replaceWhitespace(Current, Newlines, Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column,
State.Stack.back().IndentLevel, State.Column, State.Line->InPPDirective);
State.Column, State.Line->InPPDirective);
} }
if (!Current.isTrailingComment()) if (!Current.isTrailingComment())
@ -953,7 +952,6 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
} }
unsigned NewIndent; unsigned NewIndent;
unsigned NewIndentLevel = State.Stack.back().IndentLevel;
unsigned LastSpace = State.Stack.back().LastSpace; unsigned LastSpace = State.Stack.back().LastSpace;
bool AvoidBinPacking; bool AvoidBinPacking;
bool BreakBeforeParameter = false; bool BreakBeforeParameter = false;
@ -963,7 +961,6 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
if (Current.opensBlockOrBlockTypeList(Style)) { if (Current.opensBlockOrBlockTypeList(Style)) {
NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth; NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth;
NewIndent = std::min(State.Column + 2, NewIndent); NewIndent = std::min(State.Column + 2, NewIndent);
++NewIndentLevel;
} else { } else {
NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth; NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth;
} }
@ -1032,8 +1029,8 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
State.Stack.back().NoLineBreakInOperand || State.Stack.back().NoLineBreakInOperand ||
(Current.is(TT_TemplateOpener) && (Current.is(TT_TemplateOpener) &&
State.Stack.back().ContainsUnwrappedBuilder)); State.Stack.back().ContainsUnwrappedBuilder));
State.Stack.push_back(ParenState(NewIndent, NewIndentLevel, LastSpace, State.Stack.push_back(
AvoidBinPacking, NoLineBreak)); ParenState(NewIndent, LastSpace, AvoidBinPacking, NoLineBreak));
State.Stack.back().NestedBlockIndent = NestedBlockIndent; State.Stack.back().NestedBlockIndent = NestedBlockIndent;
State.Stack.back().BreakBeforeParameter = BreakBeforeParameter; State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
State.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1; State.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1;
@ -1067,10 +1064,9 @@ void ContinuationIndenter::moveStateToNewBlock(LineState &State) {
NestedBlockIndent + (State.NextToken->is(TT_ObjCBlockLBrace) NestedBlockIndent + (State.NextToken->is(TT_ObjCBlockLBrace)
? Style.ObjCBlockIndentWidth ? Style.ObjCBlockIndentWidth
: Style.IndentWidth); : Style.IndentWidth);
State.Stack.push_back(ParenState( State.Stack.push_back(ParenState(NewIndent, State.Stack.back().LastSpace,
NewIndent, /*NewIndentLevel=*/State.Stack.back().IndentLevel + 1, /*AvoidBinPacking=*/true,
State.Stack.back().LastSpace, /*AvoidBinPacking=*/true, /*NoLineBreak=*/false));
/*NoLineBreak=*/false));
State.Stack.back().NestedBlockIndent = NestedBlockIndent; State.Stack.back().NestedBlockIndent = NestedBlockIndent;
State.Stack.back().BreakBeforeParameter = true; State.Stack.back().BreakBeforeParameter = true;
} }
@ -1153,9 +1149,9 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
Text.startswith(Prefix = "u8\"") || Text.startswith(Prefix = "u8\"") ||
Text.startswith(Prefix = "L\""))) || Text.startswith(Prefix = "L\""))) ||
(Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")"))) { (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")"))) {
Token.reset(new BreakableStringLiteral( Token.reset(new BreakableStringLiteral(Current, StartColumn, Prefix,
Current, State.Line->Level, StartColumn, Prefix, Postfix, Postfix, State.Line->InPPDirective,
State.Line->InPPDirective, Encoding, Style)); Encoding, Style));
} else { } else {
return 0; return 0;
} }
@ -1168,8 +1164,8 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
switchesFormatting(Current)) switchesFormatting(Current))
return addMultilineToken(Current, State); return addMultilineToken(Current, State);
Token.reset(new BreakableBlockComment( Token.reset(new BreakableBlockComment(
Current, State.Line->Level, StartColumn, Current.OriginalColumn, Current, StartColumn, Current.OriginalColumn, !Current.Previous,
!Current.Previous, State.Line->InPPDirective, Encoding, Style)); State.Line->InPPDirective, Encoding, Style));
} else if (Current.is(TT_LineComment) && } else if (Current.is(TT_LineComment) &&
(Current.Previous == nullptr || (Current.Previous == nullptr ||
Current.Previous->isNot(TT_ImplicitStringLiteral))) { Current.Previous->isNot(TT_ImplicitStringLiteral))) {
@ -1178,8 +1174,7 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
switchesFormatting(Current)) switchesFormatting(Current))
return 0; return 0;
Token.reset(new BreakableLineCommentSection( Token.reset(new BreakableLineCommentSection(
Current, State.Line->Level, StartColumn, Current.OriginalColumn, Current, StartColumn, Current.OriginalColumn, !Current.Previous,
!Current.Previous,
/*InPPDirective=*/false, Encoding, Style)); /*InPPDirective=*/false, Encoding, Style));
// We don't insert backslashes when breaking line comments. // We don't insert backslashes when breaking line comments.
ColumnLimit = Style.ColumnLimit; ColumnLimit = Style.ColumnLimit;

View File

@ -146,24 +146,20 @@ private:
}; };
struct ParenState { struct ParenState {
ParenState(unsigned Indent, unsigned IndentLevel, unsigned LastSpace, ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking,
bool AvoidBinPacking, bool NoLineBreak) bool NoLineBreak)
: Indent(Indent), IndentLevel(IndentLevel), LastSpace(LastSpace), : Indent(Indent), LastSpace(LastSpace), NestedBlockIndent(Indent),
NestedBlockIndent(Indent), BreakBeforeClosingBrace(false), BreakBeforeClosingBrace(false), AvoidBinPacking(AvoidBinPacking),
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), BreakBeforeParameter(false), NoLineBreak(NoLineBreak),
NoLineBreak(NoLineBreak), NoLineBreakInOperand(false), NoLineBreakInOperand(false), LastOperatorWrapped(true),
LastOperatorWrapped(true), ContainsLineBreak(false), ContainsLineBreak(false), ContainsUnwrappedBuilder(false),
ContainsUnwrappedBuilder(false), AlignColons(true), AlignColons(true), ObjCSelectorNameFound(false),
ObjCSelectorNameFound(false), HasMultipleNestedBlocks(false), HasMultipleNestedBlocks(false), NestedBlockInlined(false) {}
NestedBlockInlined(false) {}
/// \brief The position to which a specific parenthesis level needs to be /// \brief The position to which a specific parenthesis level needs to be
/// indented. /// indented.
unsigned Indent; unsigned Indent;
/// \brief The number of indentation levels of the block.
unsigned IndentLevel;
/// \brief The position of the last space on each level. /// \brief The position of the last space on each level.
/// ///
/// Used e.g. to break like: /// Used e.g. to break like:

View File

@ -220,6 +220,9 @@ struct FormatToken {
/// [], {} or <>. /// [], {} or <>.
unsigned NestingLevel = 0; unsigned NestingLevel = 0;
/// \brief The indent level of this token. Copied from the surrounding line.
unsigned IndentLevel = 0;
/// \brief Penalty for inserting a line break before this token. /// \brief Penalty for inserting a line break before this token.
unsigned SplitPenalty = 0; unsigned SplitPenalty = 0;

View File

@ -1759,8 +1759,6 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
Line.First->TotalLength = Line.First->TotalLength =
Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth; Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth;
if (!Line.First->Next)
return;
FormatToken *Current = Line.First->Next; FormatToken *Current = Line.First->Next;
bool InFunctionDecl = Line.MightBeFunctionDecl; bool InFunctionDecl = Line.MightBeFunctionDecl;
while (Current) { while (Current) {
@ -1836,9 +1834,18 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
} }
calculateUnbreakableTailLengths(Line); calculateUnbreakableTailLengths(Line);
unsigned IndentLevel = Line.Level;
for (Current = Line.First; Current != nullptr; Current = Current->Next) { for (Current = Line.First; Current != nullptr; Current = Current->Next) {
if (Current->Role) if (Current->Role)
Current->Role->precomputeFormattingInfos(Current); Current->Role->precomputeFormattingInfos(Current);
if (Current->MatchingParen &&
Current->MatchingParen->opensBlockOrBlockTypeList(Style)) {
assert(IndentLevel > 0);
--IndentLevel;
}
Current->IndentLevel = IndentLevel;
if (Current->opensBlockOrBlockTypeList(Style))
++IndentLevel;
} }
DEBUG({ printDebugInfo(Line); }); DEBUG({ printDebugInfo(Line); });

View File

@ -530,34 +530,33 @@ protected:
if (Previous.Children[0]->First->MustBreakBefore) if (Previous.Children[0]->First->MustBreakBefore)
return false; return false;
// Cannot merge multiple statements into a single line.
if (Previous.Children.size() > 1)
return false;
// Cannot merge into one line if this line ends on a comment. // Cannot merge into one line if this line ends on a comment.
if (Previous.is(tok::comment)) if (Previous.is(tok::comment))
return false; return false;
// Cannot merge multiple statements into a single line.
if (Previous.Children.size() > 1)
return false;
const AnnotatedLine *Child = Previous.Children[0];
// We can't put the closing "}" on a line with a trailing comment. // We can't put the closing "}" on a line with a trailing comment.
if (Previous.Children[0]->Last->isTrailingComment()) if (Child->Last->isTrailingComment())
return false; return false;
// If the child line exceeds the column limit, we wouldn't want to merge it. // If the child line exceeds the column limit, we wouldn't want to merge it.
// We add +2 for the trailing " }". // We add +2 for the trailing " }".
if (Style.ColumnLimit > 0 && if (Style.ColumnLimit > 0 &&
Previous.Children[0]->Last->TotalLength + State.Column + 2 > Child->Last->TotalLength + State.Column + 2 > Style.ColumnLimit)
Style.ColumnLimit)
return false; return false;
if (!DryRun) { if (!DryRun) {
Whitespaces->replaceWhitespace( Whitespaces->replaceWhitespace(
*Previous.Children[0]->First, *Child->First, /*Newlines=*/0, /*Spaces=*/1,
/*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,
/*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective); /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
} }
Penalty += formatLine(*Previous.Children[0], State.Column + 1, DryRun); Penalty += formatLine(*Child, State.Column + 1, DryRun);
State.Column += 1 + Previous.Children[0]->Last->TotalLength; State.Column += 1 + Child->Last->TotalLength;
return true; return true;
} }
@ -841,8 +840,7 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
if (ShouldFormat && TheLine.Type != LT_Invalid) { if (ShouldFormat && TheLine.Type != LT_Invalid) {
if (!DryRun) if (!DryRun)
formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level, Indent, formatFirstToken(TheLine, PreviousLine, Indent);
TheLine.InPPDirective);
NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker); NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine); unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine);
@ -882,9 +880,8 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
TheLine.LeadingEmptyLinesAffected); TheLine.LeadingEmptyLinesAffected);
// Format the first token. // Format the first token.
if (ReformatLeadingWhitespace) if (ReformatLeadingWhitespace)
formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level, formatFirstToken(TheLine, PreviousLine,
TheLine.First->OriginalColumn, TheLine.First->OriginalColumn);
TheLine.InPPDirective);
else else
Whitespaces->addUntouchableToken(*TheLine.First, Whitespaces->addUntouchableToken(*TheLine.First,
TheLine.InPPDirective); TheLine.InPPDirective);
@ -904,15 +901,14 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
return Penalty; return Penalty;
} }
void UnwrappedLineFormatter::formatFirstToken(FormatToken &RootToken, void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
const AnnotatedLine *PreviousLine, const AnnotatedLine *PreviousLine,
unsigned IndentLevel, unsigned Indent) {
unsigned Indent, FormatToken& RootToken = *Line.First;
bool InPPDirective) {
if (RootToken.is(tok::eof)) { if (RootToken.is(tok::eof)) {
unsigned Newlines = std::min(RootToken.NewlinesBefore, 1u); unsigned Newlines = std::min(RootToken.NewlinesBefore, 1u);
Whitespaces->replaceWhitespace(RootToken, Newlines, /*IndentLevel=*/0, Whitespaces->replaceWhitespace(RootToken, Newlines, /*Spaces=*/0,
/*Spaces=*/0, /*TargetColumn=*/0); /*TargetColumn=*/0);
return; return;
} }
unsigned Newlines = unsigned Newlines =
@ -944,9 +940,9 @@ void UnwrappedLineFormatter::formatFirstToken(FormatToken &RootToken,
(!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline)) (!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline))
Newlines = std::min(1u, Newlines); Newlines = std::min(1u, Newlines);
Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent, Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent,
Indent, InPPDirective && Line.InPPDirective &&
!RootToken.HasUnescapedNewline); !RootToken.HasUnescapedNewline);
} }
unsigned unsigned

View File

@ -44,9 +44,8 @@ public:
private: private:
/// \brief Add a new line and the required indent before the first Token /// \brief Add a new line and the required indent before the first Token
/// of the \c UnwrappedLine if there was no structural parsing error. /// of the \c UnwrappedLine if there was no structural parsing error.
void formatFirstToken(FormatToken &RootToken, void formatFirstToken(const AnnotatedLine &Line,
const AnnotatedLine *PreviousLine, unsigned IndentLevel, const AnnotatedLine *PreviousLine, unsigned Indent);
unsigned Indent, bool InPPDirective);
/// \brief Returns the column limit for a line, taking into account whether we /// \brief Returns the column limit for a line, taking into account whether we
/// need an escaped newline due to a continued preprocessor directive. /// need an escaped newline due to a continued preprocessor directive.
@ -57,7 +56,8 @@ private:
// starting from a specific additional offset. Improves performance if there // starting from a specific additional offset. Improves performance if there
// are many nested blocks. // are many nested blocks.
std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>, std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
unsigned> PenaltyCache; unsigned>
PenaltyCache;
ContinuationIndenter *Indenter; ContinuationIndenter *Indenter;
WhitespaceManager *Whitespaces; WhitespaceManager *Whitespaces;

View File

@ -25,64 +25,60 @@ operator()(const Change &C1, const Change &C2) const {
C2.OriginalWhitespaceRange.getBegin()); C2.OriginalWhitespaceRange.getBegin());
} }
WhitespaceManager::Change::Change( WhitespaceManager::Change::Change(const FormatToken &Tok,
bool CreateReplacement, SourceRange OriginalWhitespaceRange, bool CreateReplacement,
unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn, SourceRange OriginalWhitespaceRange,
unsigned NewlinesBefore, StringRef PreviousLinePostfix, int Spaces, unsigned StartOfTokenColumn,
StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective, unsigned NewlinesBefore,
bool IsStartOfDeclName, bool IsInsideToken) StringRef PreviousLinePostfix,
: CreateReplacement(CreateReplacement), StringRef CurrentLinePrefix,
bool ContinuesPPDirective, bool IsInsideToken)
: Tok(&Tok), CreateReplacement(CreateReplacement),
OriginalWhitespaceRange(OriginalWhitespaceRange), OriginalWhitespaceRange(OriginalWhitespaceRange),
StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore), StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
PreviousLinePostfix(PreviousLinePostfix), PreviousLinePostfix(PreviousLinePostfix),
CurrentLinePrefix(CurrentLinePrefix), Kind(Kind), CurrentLinePrefix(CurrentLinePrefix),
ContinuesPPDirective(ContinuesPPDirective), ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces),
IsStartOfDeclName(IsStartOfDeclName), IndentLevel(IndentLevel), IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0),
Spaces(Spaces), IsInsideToken(IsInsideToken), IsTrailingComment(false), PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
TokenLength(0), PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
StartOfBlockComment(nullptr), IndentationOffset(0) {} StartOfBlockComment(nullptr), IndentationOffset(0) {}
void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines, void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
unsigned IndentLevel, unsigned Spaces, unsigned Spaces,
unsigned StartOfTokenColumn, unsigned StartOfTokenColumn,
bool InPPDirective) { bool InPPDirective) {
if (Tok.Finalized) if (Tok.Finalized)
return; return;
Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue; Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
Changes.push_back( Changes.push_back(Change(Tok, /*CreateReplacement=*/true,
Change(/*CreateReplacement=*/true, Tok.WhitespaceRange, IndentLevel, Tok.WhitespaceRange, Spaces, StartOfTokenColumn,
Spaces, StartOfTokenColumn, Newlines, "", "", Tok.Tok.getKind(), Newlines, "", "", InPPDirective && !Tok.IsFirst,
InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/false));
Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
/*IsInsideToken=*/false));
} }
void WhitespaceManager::addUntouchableToken(const FormatToken &Tok, void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
bool InPPDirective) { bool InPPDirective) {
if (Tok.Finalized) if (Tok.Finalized)
return; return;
Changes.push_back(Change( Changes.push_back(Change(Tok, /*CreateReplacement=*/false,
/*CreateReplacement=*/false, Tok.WhitespaceRange, /*IndentLevel=*/0, Tok.WhitespaceRange, /*Spaces=*/0,
/*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore, "", "", Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst, InPPDirective && !Tok.IsFirst,
Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName), /*IsInsideToken=*/false));
/*IsInsideToken=*/false));
} }
void WhitespaceManager::replaceWhitespaceInToken( void WhitespaceManager::replaceWhitespaceInToken(
const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
unsigned Newlines, unsigned IndentLevel, int Spaces) { unsigned Newlines, int Spaces) {
if (Tok.Finalized) if (Tok.Finalized)
return; return;
SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset); SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
Changes.push_back(Change( Changes.push_back(
true, SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Change(Tok, /*CreateReplacement=*/true,
IndentLevel, Spaces, std::max(0, Spaces), Newlines, PreviousPostfix, SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces,
CurrentPrefix, Tok.is(TT_LineComment) ? tok::comment : tok::unknown, std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,
InPPDirective && !Tok.IsFirst, InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/true));
Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
/*IsInsideToken=*/Newlines == 0));
} }
const tooling::Replacements &WhitespaceManager::generateReplacements() { const tooling::Replacements &WhitespaceManager::generateReplacements() {
@ -125,9 +121,9 @@ void WhitespaceManager::calculateLineBreakInformation() {
Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength; Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
Changes[i - 1].IsTrailingComment = Changes[i - 1].IsTrailingComment =
(Changes[i].NewlinesBefore > 0 || Changes[i].Kind == tok::eof || (Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof) ||
(Changes[i].IsInsideToken && Changes[i].Kind == tok::comment)) && (Changes[i].IsInsideToken && Changes[i].Tok->is(tok::comment))) &&
Changes[i - 1].Kind == tok::comment && Changes[i - 1].Tok->is(tok::comment) &&
// FIXME: This is a dirty hack. The problem is that // FIXME: This is a dirty hack. The problem is that
// BreakableLineCommentSection does comment reflow changes and here is // BreakableLineCommentSection does comment reflow changes and here is
// the aligning of trailing comments. Consider the case where we reflow // the aligning of trailing comments. Consider the case where we reflow
@ -163,7 +159,7 @@ void WhitespaceManager::calculateLineBreakInformation() {
// FIXME: The last token is currently not always an eof token; in those // FIXME: The last token is currently not always an eof token; in those
// cases, setting TokenLength of the last token to 0 is wrong. // cases, setting TokenLength of the last token to 0 is wrong.
Changes.back().TokenLength = 0; Changes.back().TokenLength = 0;
Changes.back().IsTrailingComment = Changes.back().Kind == tok::comment; Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);
const WhitespaceManager::Change *LastBlockComment = nullptr; const WhitespaceManager::Change *LastBlockComment = nullptr;
for (auto &Change : Changes) { for (auto &Change : Changes) {
@ -173,13 +169,15 @@ void WhitespaceManager::calculateLineBreakInformation() {
Change.IsTrailingComment = false; Change.IsTrailingComment = false;
Change.StartOfBlockComment = nullptr; Change.StartOfBlockComment = nullptr;
Change.IndentationOffset = 0; Change.IndentationOffset = 0;
if (Change.Kind == tok::comment) { if (Change.Tok->is(tok::comment)) {
LastBlockComment = &Change; if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken)
} else if (Change.Kind == tok::unknown) { LastBlockComment = &Change;
if ((Change.StartOfBlockComment = LastBlockComment)) else {
Change.IndentationOffset = if ((Change.StartOfBlockComment = LastBlockComment))
Change.StartOfTokenColumn - Change.IndentationOffset =
Change.StartOfBlockComment->StartOfTokenColumn; Change.StartOfTokenColumn -
Change.StartOfBlockComment->StartOfTokenColumn;
}
} else { } else {
LastBlockComment = nullptr; LastBlockComment = nullptr;
} }
@ -278,15 +276,13 @@ static void AlignTokens(const FormatStyle &Style, F &&Matches,
FoundMatchOnLine = false; FoundMatchOnLine = false;
} }
if (Changes[i].Kind == tok::comma) { if (Changes[i].Tok->is(tok::comma)) {
++CommasBeforeMatch; ++CommasBeforeMatch;
} else if (Changes[i].Kind == tok::r_brace || } else if (Changes[i].Tok->isOneOf(tok::r_brace, tok::r_paren,
Changes[i].Kind == tok::r_paren || tok::r_square)) {
Changes[i].Kind == tok::r_square) {
--NestingLevel; --NestingLevel;
} else if (Changes[i].Kind == tok::l_brace || } else if (Changes[i].Tok->isOneOf(tok::l_brace, tok::l_paren,
Changes[i].Kind == tok::l_paren || tok::l_square)) {
Changes[i].Kind == tok::l_square) {
// We want sequences to skip over child scopes if possible, but not the // We want sequences to skip over child scopes if possible, but not the
// other way around. // other way around.
NestingLevelOfLastMatch = std::min(NestingLevelOfLastMatch, NestingLevel); NestingLevelOfLastMatch = std::min(NestingLevelOfLastMatch, NestingLevel);
@ -345,7 +341,7 @@ void WhitespaceManager::alignConsecutiveAssignments() {
if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0) if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
return false; return false;
return C.Kind == tok::equal; return C.Tok->is(tok::equal);
}, },
Changes); Changes);
} }
@ -361,7 +357,11 @@ void WhitespaceManager::alignConsecutiveDeclarations() {
// float const* v2; // float const* v2;
// SomeVeryLongType const& v3; // SomeVeryLongType const& v3;
AlignTokens(Style, [](Change const &C) { return C.IsStartOfDeclName; }, AlignTokens(Style,
[](Change const &C) {
return C.Tok->isOneOf(TT_StartOfName,
TT_FunctionDeclarationName);
},
Changes); Changes);
} }
@ -391,17 +391,14 @@ void WhitespaceManager::alignTrailingComments() {
// If this comment follows an } in column 0, it probably documents the // If this comment follows an } in column 0, it probably documents the
// closing of a namespace and we don't want to align it. // closing of a namespace and we don't want to align it.
bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 && bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
Changes[i - 1].Kind == tok::r_brace && Changes[i - 1].Tok->is(tok::r_brace) &&
Changes[i - 1].StartOfTokenColumn == 0; Changes[i - 1].StartOfTokenColumn == 0;
bool WasAlignedWithStartOfNextLine = false; bool WasAlignedWithStartOfNextLine = false;
if (Changes[i].NewlinesBefore == 1) { // A comment on its own line. if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
unsigned CommentColumn = SourceMgr.getSpellingColumnNumber( unsigned CommentColumn = SourceMgr.getSpellingColumnNumber(
Changes[i].OriginalWhitespaceRange.getEnd()); Changes[i].OriginalWhitespaceRange.getEnd());
for (unsigned j = i + 1; j != e; ++j) { for (unsigned j = i + 1; j != e; ++j) {
if (Changes[j].Kind == tok::comment || if (Changes[j].Tok->is(tok::comment))
Changes[j].Kind == tok::unknown)
// Skip over comments and unknown tokens. "unknown tokens are used for
// the continuation of multiline comments.
continue; continue;
unsigned NextColumn = SourceMgr.getSpellingColumnNumber( unsigned NextColumn = SourceMgr.getSpellingColumnNumber(
@ -512,7 +509,8 @@ void WhitespaceManager::generateChanges() {
C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn); C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
else else
appendNewlineText(ReplacementText, C.NewlinesBefore); appendNewlineText(ReplacementText, C.NewlinesBefore);
appendIndentText(ReplacementText, C.IndentLevel, std::max(0, C.Spaces), appendIndentText(ReplacementText, C.Tok->IndentLevel,
std::max(0, C.Spaces),
C.StartOfTokenColumn - std::max(0, C.Spaces)); C.StartOfTokenColumn - std::max(0, C.Spaces));
ReplacementText.append(C.CurrentLinePrefix); ReplacementText.append(C.CurrentLinePrefix);
storeReplacement(C.OriginalWhitespaceRange, ReplacementText); storeReplacement(C.OriginalWhitespaceRange, ReplacementText);

View File

@ -43,8 +43,7 @@ public:
/// \brief Replaces the whitespace in front of \p Tok. Only call once for /// \brief Replaces the whitespace in front of \p Tok. Only call once for
/// each \c AnnotatedToken. /// each \c AnnotatedToken.
void replaceWhitespace(FormatToken &Tok, unsigned Newlines, void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces,
unsigned IndentLevel, unsigned Spaces,
unsigned StartOfTokenColumn, unsigned StartOfTokenColumn,
bool InPPDirective = false); bool InPPDirective = false);
@ -72,8 +71,7 @@ public:
unsigned ReplaceChars, unsigned ReplaceChars,
StringRef PreviousPostfix, StringRef PreviousPostfix,
StringRef CurrentPrefix, bool InPPDirective, StringRef CurrentPrefix, bool InPPDirective,
unsigned Newlines, unsigned IndentLevel, unsigned Newlines, int Spaces);
int Spaces);
/// \brief Returns all the \c Replacements created during formatting. /// \brief Returns all the \c Replacements created during formatting.
const tooling::Replacements &generateReplacements(); const tooling::Replacements &generateReplacements();
@ -91,8 +89,6 @@ public:
const SourceManager &SourceMgr; const SourceManager &SourceMgr;
}; };
Change() {}
/// \brief Creates a \c Change. /// \brief Creates a \c Change.
/// ///
/// The generated \c Change will replace the characters at /// The generated \c Change will replace the characters at
@ -102,12 +98,17 @@ public:
/// ///
/// \p StartOfTokenColumn and \p InPPDirective will be used to lay out /// \p StartOfTokenColumn and \p InPPDirective will be used to lay out
/// trailing comments and escaped newlines. /// trailing comments and escaped newlines.
Change(bool CreateReplacement, SourceRange OriginalWhitespaceRange, Change(const FormatToken &Tok, bool CreateReplacement,
unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn, SourceRange OriginalWhitespaceRange, int Spaces,
unsigned NewlinesBefore, StringRef PreviousLinePostfix, unsigned StartOfTokenColumn, unsigned NewlinesBefore,
StringRef CurrentLinePrefix, tok::TokenKind Kind, StringRef PreviousLinePostfix, StringRef CurrentLinePrefix,
bool ContinuesPPDirective, bool IsStartOfDeclName, bool ContinuesPPDirective, bool IsInsideToken);
bool IsInsideToken);
// The kind of the token whose whitespace this change replaces, or in which
// this change inserts whitespace.
// FIXME: Currently this is not set correctly for breaks inside comments, as
// the \c BreakableToken is still doing its own alignment.
const FormatToken *Tok;
bool CreateReplacement; bool CreateReplacement;
// Changes might be in the middle of a token, so we cannot just keep the // Changes might be in the middle of a token, so we cannot just keep the
@ -117,18 +118,7 @@ public:
unsigned NewlinesBefore; unsigned NewlinesBefore;
std::string PreviousLinePostfix; std::string PreviousLinePostfix;
std::string CurrentLinePrefix; std::string CurrentLinePrefix;
// The kind of the token whose whitespace this change replaces, or in which
// this change inserts whitespace.
// FIXME: Currently this is not set correctly for breaks inside comments, as
// the \c BreakableToken is still doing its own alignment.
tok::TokenKind Kind;
bool ContinuesPPDirective; bool ContinuesPPDirective;
bool IsStartOfDeclName;
// The number of nested blocks the token is in. This is used to add tabs
// only for the indentation, and not for alignment, when
// UseTab = US_ForIndentation.
unsigned IndentLevel;
// The number of spaces in front of the token or broken part of the token. // The number of spaces in front of the token or broken part of the token.
// This will be adapted when aligning tokens. // This will be adapted when aligning tokens.