Update aosp/master clang for rebase to r230699.
Change-Id: I6a546ab3d4ae37119eebb735e102cca4f80ab520
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index 1bea0e5..c84d9af 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/lib/Format/BreakableToken.cpp
@@ -106,7 +106,7 @@
Text.substr(0, Advance), UsedColumns + Chars, TabWidth, Encoding);
}
- if (Chars > MaxSplit || Text.size() == Advance)
+ if (Chars > MaxSplit || Text.size() <= Advance)
break;
if (IsBlank(Text[0]))
@@ -303,7 +303,8 @@
StartOfLineColumn[i] += Decoration.size();
Lines[i] = Lines[i].substr(Decoration.size());
LeadingWhitespace[i] += Decoration.size();
- IndentAtLineBreak = std::min<int>(IndentAtLineBreak, StartOfLineColumn[i]);
+ IndentAtLineBreak =
+ std::min<int>(IndentAtLineBreak, std::max(0, StartOfLineColumn[i]));
}
IndentAtLineBreak = std::max<unsigned>(IndentAtLineBreak, Decoration.size());
DEBUG({
diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h
index 6f49ed2..eb1f9fd 100644
--- a/lib/Format/BreakableToken.h
+++ b/lib/Format/BreakableToken.h
@@ -212,6 +212,11 @@
// StartOfLineColumn[i] is the target column at which Line[i] should be.
// Note that this excludes a leading "* " or "*" in case all lines have
// a "*" prefix.
+ // The first line's target column is always positive. The remaining lines'
+ // target columns are relative to the first line to allow correct indentation
+ // of comments in \c WhitespaceManager. Thus they can be negative as well (in
+ // case the first line needs to be unindented more than there's actual
+ // whitespace in another line).
SmallVector<int, 16> StartOfLineColumn;
// The column at which the text of a broken line should start.
diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt
index 3f08d9d..2ce3834 100644
--- a/lib/Format/CMakeLists.txt
+++ b/lib/Format/CMakeLists.txt
@@ -6,6 +6,7 @@
Format.cpp
FormatToken.cpp
TokenAnnotator.cpp
+ UnwrappedLineFormatter.cpp
UnwrappedLineParser.cpp
WhitespaceManager.cpp
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 40b50dd..7c2d916 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -48,11 +48,11 @@
static bool startsNextParameter(const FormatToken &Current,
const FormatStyle &Style) {
const FormatToken &Previous = *Current.Previous;
- if (Current.Type == TT_CtorInitializerComma &&
+ if (Current.is(TT_CtorInitializerComma) &&
Style.BreakConstructorInitializersBeforeComma)
return true;
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
- (Previous.Type != TT_CtorInitializerComma ||
+ (Previous.isNot(TT_CtorInitializerComma) ||
!Style.BreakConstructorInitializersBeforeComma);
}
@@ -93,13 +93,14 @@
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *Current.Previous;
assert(&Previous == Current.Previous);
- if (!Current.CanBreakBefore && !(State.Stack.back().BreakBeforeClosingBrace &&
- Current.closesBlockTypeList(Style)))
+ if (!Current.CanBreakBefore &&
+ !(State.Stack.back().BreakBeforeClosingBrace &&
+ Current.closesBlockTypeList(Style)))
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.Type != TT_DictLiteral && Previous.BlockKind == BK_BracedInit &&
+ Previous.isNot(TT_DictLiteral) && Previous.BlockKind == BK_BracedInit &&
Previous.Previous &&
Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma))
return false;
@@ -117,15 +118,14 @@
// Don't create a 'hanging' indent if there are multiple blocks in a single
// statement.
- if (Style.Language == FormatStyle::LK_JavaScript &&
- Previous.is(tok::l_brace) && State.Stack.size() > 1 &&
- State.Stack[State.Stack.size() - 2].JSFunctionInlined &&
+ if (Previous.is(tok::l_brace) && State.Stack.size() > 1 &&
+ State.Stack[State.Stack.size() - 2].NestedBlockInlined &&
State.Stack[State.Stack.size() - 2].HasMultipleNestedBlocks)
return false;
// Don't break after very short return types (e.g. "void") as that is often
// unexpected.
- if (Current.Type == TT_FunctionDeclarationName &&
+ if (Current.is(TT_FunctionDeclarationName) &&
!Style.AlwaysBreakAfterDefinitionReturnType && State.Column < 6)
return false;
@@ -135,7 +135,7 @@
bool ContinuationIndenter::mustBreak(const LineState &State) {
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *Current.Previous;
- if (Current.MustBreakBefore || Current.Type == TT_InlineASMColon)
+ if (Current.MustBreakBefore || Current.is(TT_InlineASMColon))
return true;
if (State.Stack.back().BreakBeforeClosingBrace &&
Current.closesBlockTypeList(Style))
@@ -144,32 +144,32 @@
return true;
if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) ||
(Style.BreakBeforeTernaryOperators &&
- (Current.is(tok::question) || (Current.Type == TT_ConditionalExpr &&
- Previous.isNot(tok::question)))) ||
+ (Current.is(tok::question) ||
+ (Current.is(TT_ConditionalExpr) && Previous.isNot(tok::question)))) ||
(!Style.BreakBeforeTernaryOperators &&
- (Previous.is(tok::question) || Previous.Type == TT_ConditionalExpr))) &&
+ (Previous.is(tok::question) || Previous.is(TT_ConditionalExpr)))) &&
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 && // Breaking saves columns.
!Previous.isOneOf(tok::kw_return, tok::lessless, tok::at) &&
- Previous.Type != TT_InlineASMColon &&
- Previous.Type != TT_ConditionalExpr && nextIsMultilineString(State))
+ !Previous.isOneOf(TT_InlineASMColon, TT_ConditionalExpr) &&
+ nextIsMultilineString(State))
return true;
- if (((Previous.Type == TT_DictLiteral && Previous.is(tok::l_brace)) ||
- Previous.Type == TT_ArrayInitializerLSquare) &&
+ if (((Previous.is(TT_DictLiteral) && Previous.is(tok::l_brace)) ||
+ Previous.is(TT_ArrayInitializerLSquare)) &&
Style.ColumnLimit > 0 &&
getLengthToMatchingParen(Previous) + State.Column > getColumnLimit(State))
return true;
- if (Current.Type == TT_CtorInitializerColon &&
+ if (Current.is(TT_CtorInitializerColon) &&
((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) ||
Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0))
return true;
if (State.Column < getNewLineColumn(State))
return false;
- if (!Style.BreakBeforeBinaryOperators) {
+ if (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None) {
// 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:
@@ -179,41 +179,43 @@
// 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 >>.
+ Previous.Previous->isNot(TT_BinaryOperator); // For >>.
bool LHSIsBinaryExpr =
Previous.Previous && Previous.Previous->EndsBinaryExpression;
- if (Previous.Type == TT_BinaryOperator &&
- (!IsComparison || LHSIsBinaryExpr) &&
- Current.Type != TT_BinaryOperator && // For >>.
+ if (Previous.is(TT_BinaryOperator) && (!IsComparison || LHSIsBinaryExpr) &&
+ Current.isNot(TT_BinaryOperator) && // For >>.
!Current.isTrailingComment() && !Previous.is(tok::lessless) &&
Previous.getPrecedence() != prec::Assignment &&
State.Stack.back().BreakBeforeParameter)
return true;
+ } else {
+ if (Current.is(TT_BinaryOperator) && Previous.EndsBinaryExpression &&
+ State.Stack.back().BreakBeforeParameter)
+ return true;
}
// Same as above, but for the first "<<" operator.
- if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator &&
+ if (Current.is(tok::lessless) && Current.isNot(TT_OverloadedOperator) &&
State.Stack.back().BreakBeforeParameter &&
State.Stack.back().FirstLessLess == 0)
return true;
- if (Current.Type == TT_SelectorName &&
- State.Stack.back().ObjCSelectorNameFound &&
+ if (Current.is(TT_SelectorName) && State.Stack.back().ObjCSelectorNameFound &&
State.Stack.back().BreakBeforeParameter)
return true;
- if (Previous.ClosesTemplateDeclaration && Current.NestingLevel == 0 &&
- !Current.isTrailingComment())
- return true;
+ if (Current.NestingLevel == 0 && !Current.isTrailingComment()) {
+ if (Previous.ClosesTemplateDeclaration)
+ return true;
+ if (Previous.is(TT_LeadingJavaAnnotation) && Current.isNot(tok::l_paren) &&
+ Current.isNot(TT_LeadingJavaAnnotation))
+ return true;
+ }
// If the return type spans multiple lines, wrap before the function name.
- if ((Current.Type == TT_FunctionDeclarationName ||
- Current.is(tok::kw_operator)) &&
+ if (Current.isOneOf(TT_FunctionDeclarationName, tok::kw_operator) &&
State.Stack.back().BreakBeforeParameter)
return true;
@@ -230,6 +232,10 @@
Previous.is(tok::l_brace) && !Current.isOneOf(tok::r_brace, tok::comment))
return true;
+ if (Current.is(tok::lessless) && Previous.is(tok::identifier) &&
+ Previous.TokenText == "endl")
+ return true;
+
return false;
}
@@ -239,16 +245,22 @@
const FormatToken &Current = *State.NextToken;
assert(!State.Stack.empty());
- if ((Current.Type == TT_ImplicitStringLiteral &&
+ if ((Current.is(TT_ImplicitStringLiteral) &&
(Current.Previous->Tok.getIdentifierInfo() == nullptr ||
Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp_not_keyword))) {
- // FIXME: Is this correct?
- int WhitespaceLength = SourceMgr.getSpellingColumnNumber(
- State.NextToken->WhitespaceRange.getEnd()) -
- SourceMgr.getSpellingColumnNumber(
- State.NextToken->WhitespaceRange.getBegin());
- State.Column += WhitespaceLength;
+ unsigned EndColumn =
+ SourceMgr.getSpellingColumnNumber(Current.WhitespaceRange.getEnd());
+ if (Current.LastNewlineOffset != 0) {
+ // If there is a newline within this token, the final column will solely
+ // determined by the current end column.
+ State.Column = EndColumn;
+ } else {
+ unsigned StartColumn =
+ SourceMgr.getSpellingColumnNumber(Current.WhitespaceRange.getBegin());
+ assert(EndColumn >= StartColumn);
+ State.Column += EndColumn - StartColumn;
+ }
moveStateToNextToken(State, DryRun, /*Newline=*/false);
return 0;
}
@@ -288,7 +300,7 @@
Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0,
Spaces, State.Column + Spaces);
- if (Current.Type == TT_SelectorName &&
+ if (Current.is(TT_SelectorName) &&
!State.Stack.back().ObjCSelectorNameFound) {
if (Current.LongestObjCSelectorName == 0)
State.Stack.back().AlignColons = false;
@@ -300,9 +312,9 @@
State.Stack.back().ColonPos = State.Column + Spaces + Current.ColumnWidth;
}
- if (Style.AlignAfterOpenBracket &&
- Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr &&
- (Current.Type != TT_LineComment || Previous.BlockKind == BK_BracedInit))
+ if (Style.AlignAfterOpenBracket && Previous.opensScope() &&
+ Previous.isNot(TT_ObjCMethodExpr) &&
+ (Current.isNot(TT_LineComment) || Previous.BlockKind == BK_BracedInit))
State.Stack.back().Indent = State.Column + Spaces;
if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style))
State.Stack.back().NoLineBreak = true;
@@ -323,26 +335,27 @@
State.Column += Spaces;
if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) &&
- Previous.Previous && Previous.Previous->isOneOf(tok::kw_if, tok::kw_for))
+ Previous.Previous &&
+ Previous.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 a continuation indent.
State.Stack.back().LastSpace = State.Column;
- else if (!Current.isOneOf(tok::comment, tok::caret) &&
- (Previous.is(tok::comma) ||
- (Previous.is(tok::colon) && Previous.Type == TT_ObjCMethodExpr)))
+ State.Stack.back().NestedBlockIndent = State.Column;
+ } else if (!Current.isOneOf(tok::comment, tok::caret) &&
+ (Previous.is(tok::comma) ||
+ (Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) {
State.Stack.back().LastSpace = State.Column;
- else if ((Previous.Type == TT_BinaryOperator ||
- Previous.Type == TT_ConditionalExpr ||
- Previous.Type == TT_CtorInitializerColon) &&
- ((Previous.getPrecedence() != prec::Assignment &&
- (Previous.isNot(tok::lessless) || Previous.OperatorIndex != 0 ||
- !Previous.LastOperator)) ||
- Current.StartsBinaryExpression))
+ } else if ((Previous.isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
+ TT_CtorInitializerColon)) &&
+ ((Previous.getPrecedence() != prec::Assignment &&
+ (Previous.isNot(tok::lessless) || Previous.OperatorIndex != 0 ||
+ !Previous.LastOperator)) ||
+ 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) {
+ } else if (Previous.is(TT_InheritanceColon)) {
State.Stack.back().Indent = State.Column;
State.Stack.back().LastSpace = State.Column;
} else if (Previous.opensScope()) {
@@ -356,7 +369,7 @@
const FormatToken *Next = Previous.MatchingParen->getNextNonComment();
HasTrailingCall = Next && Next->isMemberAccess();
}
- if (HasTrailingCall &&
+ if (HasTrailingCall && State.Stack.size() > 1 &&
State.Stack[State.Stack.size() - 2].CallContinuation == 0)
State.Stack.back().LastSpace = State.Column;
}
@@ -393,10 +406,11 @@
Penalty += Style.PenaltyBreakFirstLessLess;
State.Column = getNewLineColumn(State);
+ State.Stack.back().NestedBlockIndent = State.Column;
if (NextNonComment->isMemberAccess()) {
if (State.Stack.back().CallContinuation == 0)
State.Stack.back().CallContinuation = State.Column;
- } else if (NextNonComment->Type == TT_SelectorName) {
+ } else if (NextNonComment->is(TT_SelectorName)) {
if (!State.Stack.back().ObjCSelectorNameFound) {
if (NextNonComment->LongestObjCSelectorName == 0) {
State.Stack.back().AlignColons = false;
@@ -409,8 +423,7 @@
State.Stack.back().ColonPos = State.Column + NextNonComment->ColumnWidth;
}
} else if (PreviousNonComment && PreviousNonComment->is(tok::colon) &&
- (PreviousNonComment->Type == TT_ObjCMethodExpr ||
- PreviousNonComment->Type == TT_DictLiteral)) {
+ PreviousNonComment->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral)) {
// FIXME: This is hacky, find a better way. The problem is that in an ObjC
// method expression, the block should be aligned to the line starting it,
// e.g.:
@@ -428,10 +441,9 @@
if ((Previous.isOneOf(tok::comma, tok::semi) &&
!State.Stack.back().AvoidBinPacking) ||
- Previous.Type == TT_BinaryOperator)
+ Previous.is(TT_BinaryOperator))
State.Stack.back().BreakBeforeParameter = false;
- if ((Previous.Type == TT_TemplateCloser ||
- Previous.Type == TT_JavaAnnotation) &&
+ if (Previous.isOneOf(TT_TemplateCloser, TT_JavaAnnotation) &&
Current.NestingLevel == 0)
State.Stack.back().BreakBeforeParameter = false;
if (NextNonComment->is(tok::question) ||
@@ -453,11 +465,10 @@
// Any break on this level means that the parent level has been broken
// and we need to avoid bin packing there.
- bool JavaScriptFormat = Style.Language == FormatStyle::LK_JavaScript &&
- Current.is(tok::r_brace) &&
- State.Stack.size() > 1 &&
- State.Stack[State.Stack.size() - 2].JSFunctionInlined;
- if (!JavaScriptFormat) {
+ bool NestedBlockSpecialCase =
+ Current.is(tok::r_brace) && State.Stack.size() > 1 &&
+ State.Stack[State.Stack.size() - 2].NestedBlockInlined;
+ if (!NestedBlockSpecialCase) {
for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
State.Stack[i].BreakBeforeParameter = true;
}
@@ -465,30 +476,27 @@
if (PreviousNonComment &&
!PreviousNonComment->isOneOf(tok::comma, tok::semi) &&
- (PreviousNonComment->Type != TT_TemplateCloser ||
+ (PreviousNonComment->isNot(TT_TemplateCloser) ||
Current.NestingLevel != 0) &&
- PreviousNonComment->Type != TT_BinaryOperator &&
- PreviousNonComment->Type != TT_JavaAnnotation &&
- PreviousNonComment->Type != TT_LeadingJavaAnnotation &&
- Current.Type != TT_BinaryOperator && !PreviousNonComment->opensScope())
+ !PreviousNonComment->isOneOf(TT_BinaryOperator, TT_JavaAnnotation,
+ TT_LeadingJavaAnnotation) &&
+ Current.isNot(TT_BinaryOperator) && !PreviousNonComment->opensScope())
State.Stack.back().BreakBeforeParameter = true;
// If we break after { or the [ of an array initializer, we should also break
// before the corresponding } or ].
if (PreviousNonComment &&
- (PreviousNonComment->is(tok::l_brace) ||
- PreviousNonComment->Type == TT_ArrayInitializerLSquare))
+ (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)))
State.Stack.back().BreakBeforeClosingBrace = true;
if (State.Stack.back().AvoidBinPacking) {
// If we are breaking after '(', '{', '<', this is not bin packing
// unless AllowAllParametersOfDeclarationOnNextLine is false or this is a
// dict/object literal.
- if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) ||
- Previous.Type == TT_BinaryOperator) ||
+ if (!Previous.isOneOf(tok::l_paren, tok::l_brace, TT_BinaryOperator) ||
(!Style.AllowAllParametersOfDeclarationOnNextLine &&
State.Line->MustBeDeclaration) ||
- Previous.Type == TT_DictLiteral)
+ Previous.is(TT_DictLiteral))
State.Stack.back().BreakBeforeParameter = true;
}
@@ -518,19 +526,16 @@
if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block)
return Current.NestingLevel == 0 ? State.FirstIndent
: State.Stack.back().Indent;
- if (Current.isOneOf(tok::r_brace, tok::r_square)) {
- if (State.Stack.size() > 1 &&
- State.Stack[State.Stack.size() - 2].JSFunctionInlined)
- return State.FirstIndent;
- if (Current.closesBlockTypeList(Style) ||
- (Current.MatchingParen &&
- Current.MatchingParen->BlockKind == BK_BracedInit))
+ if (Current.isOneOf(tok::r_brace, tok::r_square) && State.Stack.size() > 1) {
+ if (Current.closesBlockTypeList(Style))
+ return State.Stack[State.Stack.size() - 2].NestedBlockIndent;
+ if (Current.MatchingParen &&
+ Current.MatchingParen->BlockKind == BK_BracedInit)
return State.Stack[State.Stack.size() - 2].LastSpace;
- else
- return State.FirstIndent;
+ return State.FirstIndent;
}
if (Current.is(tok::identifier) && Current.Next &&
- Current.Next->Type == TT_DictLiteral)
+ Current.Next->is(TT_DictLiteral))
return State.Stack.back().Indent;
if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0)
return State.StartOfStringLiteral;
@@ -538,62 +543,53 @@
State.Stack.back().FirstLessLess != 0)
return State.Stack.back().FirstLessLess;
if (NextNonComment->isMemberAccess()) {
- if (State.Stack.back().CallContinuation == 0) {
+ if (State.Stack.back().CallContinuation == 0)
return ContinuationIndent;
- } else {
- return State.Stack.back().CallContinuation;
- }
+ return State.Stack.back().CallContinuation;
}
if (State.Stack.back().QuestionColumn != 0 &&
((NextNonComment->is(tok::colon) &&
- NextNonComment->Type == TT_ConditionalExpr) ||
- Previous.Type == TT_ConditionalExpr))
+ NextNonComment->is(TT_ConditionalExpr)) ||
+ Previous.is(TT_ConditionalExpr)))
return State.Stack.back().QuestionColumn;
if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0)
return State.Stack.back().VariablePos;
if ((PreviousNonComment &&
(PreviousNonComment->ClosesTemplateDeclaration ||
- PreviousNonComment->Type == TT_AttributeParen ||
- PreviousNonComment->Type == TT_JavaAnnotation ||
- PreviousNonComment->Type == TT_LeadingJavaAnnotation)) ||
+ PreviousNonComment->isOneOf(TT_AttributeParen, TT_JavaAnnotation,
+ TT_LeadingJavaAnnotation))) ||
(!Style.IndentWrappedFunctionNames &&
- (NextNonComment->is(tok::kw_operator) ||
- NextNonComment->Type == TT_FunctionDeclarationName)))
+ NextNonComment->isOneOf(tok::kw_operator, TT_FunctionDeclarationName)))
return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent);
- if (NextNonComment->Type == TT_SelectorName) {
+ if (NextNonComment->is(TT_SelectorName)) {
if (!State.Stack.back().ObjCSelectorNameFound) {
- if (NextNonComment->LongestObjCSelectorName == 0) {
+ if (NextNonComment->LongestObjCSelectorName == 0)
return State.Stack.back().Indent;
- } else {
- return State.Stack.back().Indent +
- NextNonComment->LongestObjCSelectorName -
- NextNonComment->ColumnWidth;
- }
- } else if (!State.Stack.back().AlignColons) {
- return State.Stack.back().Indent;
- } else if (State.Stack.back().ColonPos > NextNonComment->ColumnWidth) {
- return State.Stack.back().ColonPos - NextNonComment->ColumnWidth;
- } else {
- return State.Stack.back().Indent;
+ return State.Stack.back().Indent +
+ NextNonComment->LongestObjCSelectorName -
+ NextNonComment->ColumnWidth;
}
+ if (!State.Stack.back().AlignColons)
+ return State.Stack.back().Indent;
+ if (State.Stack.back().ColonPos > NextNonComment->ColumnWidth)
+ return State.Stack.back().ColonPos - NextNonComment->ColumnWidth;
+ return State.Stack.back().Indent;
}
- if (NextNonComment->Type == TT_ArraySubscriptLSquare) {
+ if (NextNonComment->is(TT_ArraySubscriptLSquare)) {
if (State.Stack.back().StartOfArraySubscripts != 0)
return State.Stack.back().StartOfArraySubscripts;
- else
- return ContinuationIndent;
+ return ContinuationIndent;
}
- if (NextNonComment->Type == TT_StartOfName ||
+ if (NextNonComment->is(TT_StartOfName) ||
Previous.isOneOf(tok::coloncolon, tok::equal)) {
return ContinuationIndent;
}
if (PreviousNonComment && PreviousNonComment->is(tok::colon) &&
- (PreviousNonComment->Type == TT_ObjCMethodExpr ||
- PreviousNonComment->Type == TT_DictLiteral))
+ PreviousNonComment->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral))
return ContinuationIndent;
- if (NextNonComment->Type == TT_CtorInitializerColon)
+ if (NextNonComment->is(TT_CtorInitializerColon))
return State.FirstIndent + Style.ConstructorInitializerIndentWidth;
- if (NextNonComment->Type == TT_CtorInitializerComma)
+ if (NextNonComment->is(TT_CtorInitializerComma))
return State.Stack.back().Indent;
if (Previous.is(tok::r_paren) && !Current.isBinaryOperator() &&
!Current.isOneOf(tok::colon, tok::comment))
@@ -611,18 +607,18 @@
assert(State.Stack.size());
const FormatToken &Current = *State.NextToken;
- if (Current.Type == TT_InheritanceColon)
+ if (Current.is(TT_InheritanceColon))
State.Stack.back().AvoidBinPacking = true;
- if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator) {
+ if (Current.is(tok::lessless) && Current.isNot(TT_OverloadedOperator)) {
if (State.Stack.back().FirstLessLess == 0)
State.Stack.back().FirstLessLess = State.Column;
else
State.Stack.back().LastOperatorWrapped = Newline;
}
- if ((Current.Type == TT_BinaryOperator && Current.isNot(tok::lessless)) ||
- Current.Type == TT_ConditionalExpr)
+ if ((Current.is(TT_BinaryOperator) && Current.isNot(tok::lessless)) ||
+ Current.is(TT_ConditionalExpr))
State.Stack.back().LastOperatorWrapped = Newline;
- if (Current.Type == TT_ArraySubscriptLSquare &&
+ if (Current.is(TT_ArraySubscriptLSquare) &&
State.Stack.back().StartOfArraySubscripts == 0)
State.Stack.back().StartOfArraySubscripts = State.Column;
if ((Current.is(tok::question) && Style.BreakBeforeTernaryOperators) ||
@@ -636,9 +632,9 @@
if (Current.isMemberAccess())
State.Stack.back().StartOfFunctionCall =
Current.LastOperator ? 0 : State.Column + Current.ColumnWidth;
- if (Current.Type == TT_SelectorName)
+ if (Current.is(TT_SelectorName))
State.Stack.back().ObjCSelectorNameFound = true;
- if (Current.Type == TT_CtorInitializerColon) {
+ if (Current.is(TT_CtorInitializerColon)) {
// Indent 2 from the column, so:
// SomeClass::SomeClass()
// : First(...), ...
@@ -646,6 +642,7 @@
// ^ line up here.
State.Stack.back().Indent =
State.Column + (Style.BreakConstructorInitializersBeforeComma ? 0 : 2);
+ State.Stack.back().NestedBlockIndent = State.Stack.back().Indent;
if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
State.Stack.back().AvoidBinPacking = true;
State.Stack.back().BreakBeforeParameter = false;
@@ -654,7 +651,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 our
// continuation indent width.
- if (Current.Type == TT_ObjCMethodSpecifier)
+ if (Current.is(TT_ObjCMethodSpecifier))
State.Stack.back().Indent += Style.ContinuationIndentWidth;
// Insert scopes created by fake parenthesis.
@@ -666,22 +663,21 @@
// foo();
// bar();
// }, a, b, c);
- if (Style.Language == FormatStyle::LK_JavaScript) {
- if (Current.isNot(tok::comment) && Previous && Previous->is(tok::l_brace) &&
- State.Stack.size() > 1) {
- if (State.Stack[State.Stack.size() - 2].JSFunctionInlined && Newline) {
- for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
- State.Stack[i].NoLineBreak = true;
- }
+ if (Current.isNot(tok::comment) && Previous && Previous->is(tok::l_brace) &&
+ State.Stack.size() > 1) {
+ if (State.Stack[State.Stack.size() - 2].NestedBlockInlined && Newline) {
+ for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
+ State.Stack[i].NoLineBreak = true;
}
- State.Stack[State.Stack.size() - 2].JSFunctionInlined = false;
}
- if (Current.is(Keywords.kw_function))
- State.Stack.back().JSFunctionInlined =
- !Newline && Previous && Previous->Type != TT_DictLiteral &&
- // If the unnamed function is the only parameter to another function,
- // we can likely inline it and come up with a good format.
- (Previous->isNot(tok::l_paren) || Previous->ParameterCount > 1);
+ State.Stack[State.Stack.size() - 2].NestedBlockInlined = false;
+ }
+ if (Previous && (Previous->isOneOf(tok::l_paren, tok::comma, tok::colon) ||
+ Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr)) &&
+ !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) {
+ State.Stack.back().NestedBlockInlined =
+ !Newline &&
+ (Previous->isNot(tok::l_paren) || Previous->ParameterCount > 1);
}
moveStatePastFakeLParens(State, Newline);
@@ -727,8 +723,9 @@
// is special cased.
bool SkipFirstExtraIndent =
(Previous && (Previous->opensScope() || Previous->is(tok::kw_return) ||
- Previous->getPrecedence() == prec::Assignment ||
- Previous->Type == TT_ObjCMethodExpr));
+ (Previous->getPrecedence() == prec::Assignment &&
+ Style.AlignOperands) ||
+ Previous->is(TT_ObjCMethodExpr)));
for (SmallVectorImpl<prec::Level>::const_reverse_iterator
I = Current.FakeLParens.rbegin(),
E = Current.FakeLParens.rend();
@@ -740,6 +737,7 @@
// a builder type call after 'return' or, if the alignment after opening
// brackets is disabled.
if (!Current.isTrailingComment() &&
+ (Style.AlignOperands || *I < prec::Assignment) &&
(!Previous || Previous->isNot(tok::kw_return) ||
(Style.Language != FormatStyle::LK_Java && *I > 0)) &&
(Style.AlignAfterOpenBracket || *I != prec::Comma ||
@@ -753,14 +751,14 @@
// Exclude relational operators, as there, it is always more desirable to
// have the LHS 'left' of the RHS.
if (Previous && Previous->getPrecedence() > prec::Assignment &&
- (Previous->Type == TT_BinaryOperator ||
- Previous->Type == TT_ConditionalExpr) &&
+ Previous->isOneOf(TT_BinaryOperator, TT_ConditionalExpr) &&
Previous->getPrecedence() != prec::Relational) {
- bool BreakBeforeOperator = Previous->is(tok::lessless) ||
- (Previous->Type == TT_BinaryOperator &&
- Style.BreakBeforeBinaryOperators) ||
- (Previous->Type == TT_ConditionalExpr &&
- Style.BreakBeforeTernaryOperators);
+ bool BreakBeforeOperator =
+ Previous->is(tok::lessless) ||
+ (Previous->is(TT_BinaryOperator) &&
+ Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None) ||
+ (Previous->is(TT_ConditionalExpr) &&
+ Style.BreakBeforeTernaryOperators);
if ((!Newline && !BreakBeforeOperator) ||
(!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator))
NewParenState.NoLineBreak = true;
@@ -774,7 +772,8 @@
// ParameterToInnerFunction));
if (*I > prec::Unknown)
NewParenState.LastSpace = std::max(NewParenState.LastSpace, State.Column);
- NewParenState.StartOfFunctionCall = State.Column;
+ if (*I != prec::Conditional)
+ NewParenState.StartOfFunctionCall = State.Column;
// Always indent conditional expressions. Never indent expression where
// the 'operator' is ',', ';' or an assignment (i.e. *I <=
@@ -782,7 +781,7 @@
// other expression, unless the indentation needs to be skipped.
if (*I == prec::Conditional ||
(!SkipFirstExtraIndent && *I > prec::Assignment &&
- !Current.isTrailingComment() && !Style.BreakBeforeBinaryOperators))
+ !Current.isTrailingComment()))
NewParenState.Indent += Style.ContinuationIndentWidth;
if ((Previous && !Previous->opensScope()) || *I > prec::Comma)
NewParenState.BreakBeforeParameter = false;
@@ -791,11 +790,9 @@
}
}
-// Remove the fake r_parens after 'Tok'.
-static void consumeRParens(LineState& State, const FormatToken &Tok) {
- for (unsigned i = 0, e = Tok.FakeRParens; i != e; ++i) {
+void ContinuationIndenter::moveStatePastFakeRParens(LineState &State) {
+ for (unsigned i = 0, e = State.NextToken->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;
@@ -805,46 +802,6 @@
}
}
-// Returns whether 'Tok' opens or closes a scope requiring special handling
-// of the subsequent fake r_parens.
-//
-// For example, 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. This formats:
-//
-// SomeFunction(a, [] {
-// f(); // break
-// });
-//
-// instead of:
-// SomeFunction(a, [] {
-// f(); // break
-// });
-static bool fakeRParenSpecialCase(const LineState &State) {
- const FormatToken &Tok = *State.NextToken;
- if (!Tok.MatchingParen)
- return false;
- const FormatToken *Left = &Tok;
- if (Tok.isOneOf(tok::r_brace, tok::r_square))
- Left = Tok.MatchingParen;
- return !State.Stack.back().HasMultipleNestedBlocks &&
- Left->isOneOf(tok::l_brace, tok::l_square) &&
- (Left->BlockKind == BK_Block ||
- Left->Type == TT_ArrayInitializerLSquare ||
- Left->Type == TT_DictLiteral);
-}
-
-void ContinuationIndenter::moveStatePastFakeRParens(LineState &State) {
- // Don't remove FakeRParens attached to r_braces that surround nested blocks
- // as they will have been removed early (see above).
- if (fakeRParenSpecialCase(State))
- return;
-
- consumeRParens(State, *State.NextToken);
-}
-
void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
bool Newline) {
const FormatToken &Current = *State.NextToken;
@@ -860,26 +817,19 @@
unsigned NewIndentLevel = State.Stack.back().IndentLevel;
bool AvoidBinPacking;
bool BreakBeforeParameter = false;
- if (Current.is(tok::l_brace) || Current.Type == TT_ArrayInitializerLSquare) {
- if (fakeRParenSpecialCase(State))
- consumeRParens(State, *Current.MatchingParen);
-
- NewIndent = State.Stack.back().LastSpace;
+ if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) {
if (Current.opensBlockTypeList(Style)) {
- NewIndent += Style.IndentWidth;
+ NewIndent = State.Stack.back().NestedBlockIndent + Style.IndentWidth;
NewIndent = std::min(State.Column + 2, NewIndent);
++NewIndentLevel;
} else {
- NewIndent += Style.ContinuationIndentWidth;
- NewIndent = std::min(State.Column + 1, NewIndent);
+ NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth;
}
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);
+ AvoidBinPacking =
+ Current.isOneOf(TT_ArrayInitializerLSquare, TT_DictLiteral) ||
+ Style.Language == FormatStyle::LK_Proto || !Style.BinPackParameters ||
+ (NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod));
} else {
NewIndent = Style.ContinuationIndentWidth +
std::max(State.Stack.back().LastSpace,
@@ -893,17 +843,19 @@
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 &&
+ if (Current.is(TT_ObjCMethodExpr) && Style.ColumnLimit != 0 &&
getLengthToMatchingParen(Current) + State.Column >
getColumnLimit(State))
BreakBeforeParameter = true;
}
bool NoLineBreak = State.Stack.back().NoLineBreak ||
- (Current.Type == TT_TemplateOpener &&
+ (Current.is(TT_TemplateOpener) &&
State.Stack.back().ContainsUnwrappedBuilder);
+ unsigned NestedBlockIndent = State.Stack.back().NestedBlockIndent;
State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
State.Stack.back().LastSpace,
AvoidBinPacking, NoLineBreak));
+ State.Stack.back().NestedBlockIndent = NestedBlockIndent;
State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
State.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1;
}
@@ -918,7 +870,7 @@
if (State.Stack.size() > 1 &&
(Current.isOneOf(tok::r_paren, tok::r_square) ||
(Current.is(tok::r_brace) && State.NextToken != State.Line->First) ||
- State.NextToken->Type == TT_TemplateCloser))
+ State.NextToken->is(TT_TemplateCloser)))
State.Stack.pop_back();
if (Current.is(tok::r_square)) {
@@ -930,20 +882,17 @@
}
void ContinuationIndenter::moveStateToNewBlock(LineState &State) {
- // 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 (fakeRParenSpecialCase(State))
- consumeRParens(State, *State.NextToken->MatchingParen);
-
+ unsigned NestedBlockIndent = State.Stack.back().NestedBlockIndent;
// ObjC block sometimes follow special indentation rules.
- unsigned NewIndent = State.Stack.back().LastSpace +
- (State.NextToken->Type == TT_ObjCBlockLBrace
- ? Style.ObjCBlockIndentWidth
- : Style.IndentWidth);
+ unsigned NewIndent =
+ NestedBlockIndent + (State.NextToken->is(TT_ObjCBlockLBrace)
+ ? Style.ObjCBlockIndentWidth
+ : 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().NestedBlockIndent = NestedBlockIndent;
State.Stack.back().BreakBeforeParameter = true;
}
@@ -963,34 +912,17 @@
return 0;
}
-static bool getRawStringLiteralPrefixPostfix(StringRef Text, StringRef &Prefix,
- StringRef &Postfix) {
- if (Text.startswith(Prefix = "R\"") || Text.startswith(Prefix = "uR\"") ||
- Text.startswith(Prefix = "UR\"") || Text.startswith(Prefix = "u8R\"") ||
- Text.startswith(Prefix = "LR\"")) {
- size_t ParenPos = Text.find('(');
- if (ParenPos != StringRef::npos) {
- StringRef Delimiter =
- Text.substr(Prefix.size(), ParenPos - Prefix.size());
- Prefix = Text.substr(0, ParenPos + 1);
- Postfix = Text.substr(Text.size() - 2 - Delimiter.size());
- return Postfix.front() == ')' && Postfix.back() == '"' &&
- Postfix.substr(1).startswith(Delimiter);
- }
- }
- return false;
-}
-
unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
LineState &State,
bool DryRun) {
// Don't break multi-line tokens other than block comments. Instead, just
// update the state.
- if (Current.Type != TT_BlockComment && Current.IsMultiline)
+ if (Current.isNot(TT_BlockComment) && Current.IsMultiline)
return addMultilineToken(Current, State);
- // Don't break implicit string literals.
- if (Current.Type == TT_ImplicitStringLiteral)
+ // Don't break implicit string literals or import statements.
+ if (Current.is(TT_ImplicitStringLiteral) ||
+ State.Line->Type == LT_ImportStatement)
return 0;
if (!Current.isStringLiteral() && !Current.is(tok::comment))
@@ -1001,6 +933,12 @@
unsigned ColumnLimit = getColumnLimit(State);
if (Current.isStringLiteral()) {
+ // FIXME: String literal breaking is currently disabled for Java and JS, as
+ // it requires strings to be merged using "+" which we don't support.
+ if (Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript)
+ return 0;
+
// Don't break string literals inside preprocessor directives (except for
// #define directives, as their contents are stored in separate lines and
// are not affected by this check).
@@ -1031,23 +969,22 @@
Text.startswith(Prefix = "u\"") || Text.startswith(Prefix = "U\"") ||
Text.startswith(Prefix = "u8\"") ||
Text.startswith(Prefix = "L\""))) ||
- (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")")) ||
- getRawStringLiteralPrefixPostfix(Text, Prefix, Postfix)) {
+ (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")"))) {
Token.reset(new BreakableStringLiteral(
Current, State.Line->Level, StartColumn, Prefix, Postfix,
State.Line->InPPDirective, Encoding, Style));
} else {
return 0;
}
- } else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) {
+ } else if (Current.is(TT_BlockComment) && Current.isTrailingComment()) {
if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
return 0;
Token.reset(new BreakableBlockComment(
Current, State.Line->Level, StartColumn, Current.OriginalColumn,
!Current.Previous, State.Line->InPPDirective, Encoding, Style));
- } else if (Current.Type == TT_LineComment &&
+ } else if (Current.is(TT_LineComment) &&
(Current.Previous == nullptr ||
- Current.Previous->Type != TT_ImplicitStringLiteral)) {
+ Current.Previous->isNot(TT_ImplicitStringLiteral))) {
if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
return 0;
Token.reset(new BreakableLineComment(Current, State.Line->Level,
@@ -1121,7 +1058,7 @@
// 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) {
+ if (Current.isNot(TT_LineComment)) {
for (unsigned i = 0, e = State.Stack.size(); i != e; ++i)
State.Stack[i].BreakBeforeParameter = true;
}
@@ -1141,7 +1078,7 @@
bool ContinuationIndenter::nextIsMultilineString(const LineState &State) {
const FormatToken &Current = *State.NextToken;
- if (!Current.isStringLiteral() || Current.Type == TT_ImplicitStringLiteral)
+ if (!Current.isStringLiteral() || Current.is(TT_ImplicitStringLiteral))
return false;
// We never consider raw string literals "multiline" for the purpose of
// AlwaysBreakBeforeMultilineStrings implementation as they are special-cased
@@ -1153,8 +1090,9 @@
if (Current.getNextNonComment() &&
Current.getNextNonComment()->isStringLiteral())
return true; // Implicit concatenation.
- if (State.Column + Current.ColumnWidth + Current.UnbreakableTailLength >
- Style.ColumnLimit)
+ if (Style.ColumnLimit != 0 &&
+ State.Column + Current.ColumnWidth + Current.UnbreakableTailLength >
+ Style.ColumnLimit)
return true; // String will be split.
return false;
}
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
index 5abbe7e..36691d9 100644
--- a/lib/Format/ContinuationIndenter.h
+++ b/lib/Format/ContinuationIndenter.h
@@ -148,14 +148,15 @@
ParenState(unsigned Indent, unsigned IndentLevel, unsigned LastSpace,
bool AvoidBinPacking, bool NoLineBreak)
: Indent(Indent), IndentLevel(IndentLevel), LastSpace(LastSpace),
- FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0),
+ NestedBlockIndent(Indent), FirstLessLess(0),
+ BreakBeforeClosingBrace(false), QuestionColumn(0),
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
NoLineBreak(NoLineBreak), LastOperatorWrapped(true), ColonPos(0),
StartOfFunctionCall(0), StartOfArraySubscripts(0),
NestedNameSpecifierContinuation(0), CallContinuation(0), VariablePos(0),
ContainsLineBreak(false), ContainsUnwrappedBuilder(0),
AlignColons(true), ObjCSelectorNameFound(false),
- HasMultipleNestedBlocks(false), JSFunctionInlined(false) {}
+ HasMultipleNestedBlocks(false), NestedBlockInlined(false) {}
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
@@ -171,6 +172,10 @@
/// OtherParameter));
unsigned LastSpace;
+ /// \brief If a block relative to this parenthesis level gets wrapped, indent
+ /// it this much.
+ unsigned NestedBlockIndent;
+
/// \brief The position the first "<<" operator encountered on each level.
///
/// Used to align "<<" operators. 0 if no such operator has been encountered
@@ -256,15 +261,17 @@
/// the same token.
bool HasMultipleNestedBlocks;
- // \brief The previous JavaScript 'function' keyword is not wrapped to a new
- // line.
- bool JSFunctionInlined;
+ // \brief The start of a nested block (e.g. lambda introducer in C++ or
+ // "function" in JavaScript) is not wrapped to a new line.
+ bool NestedBlockInlined;
bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
if (LastSpace != Other.LastSpace)
return LastSpace < Other.LastSpace;
+ if (NestedBlockIndent != Other.NestedBlockIndent)
+ return NestedBlockIndent < Other.NestedBlockIndent;
if (FirstLessLess != Other.FirstLessLess)
return FirstLessLess < Other.FirstLessLess;
if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace)
@@ -293,8 +300,8 @@
return ContainsLineBreak < Other.ContainsLineBreak;
if (ContainsUnwrappedBuilder != Other.ContainsUnwrappedBuilder)
return ContainsUnwrappedBuilder < Other.ContainsUnwrappedBuilder;
- if (JSFunctionInlined != Other.JSFunctionInlined)
- return JSFunctionInlined < Other.JSFunctionInlined;
+ if (NestedBlockInlined != Other.NestedBlockInlined)
+ return NestedBlockInlined < Other.NestedBlockInlined;
return false;
}
};
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 729ca97..035dc73 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -15,6 +15,7 @@
#include "ContinuationIndenter.h"
#include "TokenAnnotator.h"
+#include "UnwrappedLineFormatter.h"
#include "UnwrappedLineParser.h"
#include "WhitespaceManager.h"
#include "clang/Basic/Diagnostic.h"
@@ -74,6 +75,7 @@
IO.enumCase(Value, "All", FormatStyle::SFS_All);
IO.enumCase(Value, "true", FormatStyle::SFS_All);
IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
+ IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
}
};
@@ -107,10 +109,8 @@
}
};
-template <>
-struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
- static void enumeration(IO &IO,
- FormatStyle::PointerAlignmentStyle &Value) {
+template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
+ static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
IO.enumCase(Value, "Left", FormatStyle::PAS_Left);
IO.enumCase(Value, "Right", FormatStyle::PAS_Right);
@@ -142,8 +142,8 @@
IO.mapOptional("Language", Style.Language);
if (IO.outputting()) {
- StringRef StylesArray[] = { "LLVM", "Google", "Chromium",
- "Mozilla", "WebKit", "GNU" };
+ StringRef StylesArray[] = {"LLVM", "Google", "Chromium",
+ "Mozilla", "WebKit", "GNU"};
ArrayRef<StringRef> Styles(StylesArray);
for (size_t i = 0, e = Styles.size(); i < e; ++i) {
StringRef StyleName(Styles[i]);
@@ -172,6 +172,7 @@
IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlinesLeft);
+ IO.mapOptional("AlignOperands", Style.AlignOperands);
IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
Style.AllowAllParametersOfDeclarationOnNextLine);
@@ -270,7 +271,7 @@
// will be used to get default values for missing keys.
// If the first element has no Language specified, it will be treated as the
// default one for the following elements.
-template <> struct DocumentListTraits<std::vector<FormatStyle> > {
+template <> struct DocumentListTraits<std::vector<FormatStyle>> {
static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
return Seq.size();
}
@@ -326,6 +327,7 @@
LLVMStyle.AccessModifierOffset = -2;
LLVMStyle.AlignEscapedNewlinesLeft = false;
LLVMStyle.AlignAfterOpenBracket = true;
+ LLVMStyle.AlignOperands = true;
LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
@@ -414,7 +416,11 @@
if (Language == FormatStyle::LK_Java) {
GoogleStyle.AlignAfterOpenBracket = false;
- GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
+ GoogleStyle.AlignOperands = false;
+ GoogleStyle.AlignTrailingComments = false;
+ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
+ GoogleStyle.AllowShortIfStatementsOnASingleLine = false;
+ GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
GoogleStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
GoogleStyle.ColumnLimit = 100;
GoogleStyle.SpaceAfterCStyleCast = true;
@@ -424,6 +430,7 @@
GoogleStyle.MaxEmptyLinesToKeep = 3;
GoogleStyle.SpacesInContainerLiterals = false;
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
+ GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
} else if (Language == FormatStyle::LK_Proto) {
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
GoogleStyle.SpacesInContainerLiterals = false;
@@ -434,12 +441,18 @@
FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
FormatStyle ChromiumStyle = getGoogleStyle(Language);
- ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
- ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
- ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
- ChromiumStyle.AllowShortLoopsOnASingleLine = false;
- ChromiumStyle.BinPackParameters = false;
- ChromiumStyle.DerivePointerAlignment = false;
+ if (Language == FormatStyle::LK_Java) {
+ ChromiumStyle.AllowShortIfStatementsOnASingleLine = true;
+ ChromiumStyle.IndentWidth = 4;
+ ChromiumStyle.ContinuationIndentWidth = 8;
+ } else {
+ ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
+ ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
+ ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
+ ChromiumStyle.AllowShortLoopsOnASingleLine = false;
+ ChromiumStyle.BinPackParameters = false;
+ ChromiumStyle.DerivePointerAlignment = false;
+ }
return ChromiumStyle;
}
@@ -462,6 +475,7 @@
FormatStyle Style = getLLVMStyle();
Style.AccessModifierOffset = -4;
Style.AlignAfterOpenBracket = false;
+ Style.AlignOperands = false;
Style.AlignTrailingComments = false;
Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
@@ -579,779 +593,15 @@
namespace {
-bool startsExternCBlock(const AnnotatedLine &Line) {
- const FormatToken *Next = Line.First->getNextNonComment();
- const FormatToken *NextNext = Next ? Next->getNextNonComment() : nullptr;
- return Line.First->is(tok::kw_extern) && Next && Next->isStringLiteral() &&
- NextNext && NextNext->is(tok::l_brace);
-}
-
-class NoColumnLimitFormatter {
-public:
- NoColumnLimitFormatter(ContinuationIndenter *Indenter) : Indenter(Indenter) {}
-
- /// \brief Formats the line starting at \p State, simply keeping all of the
- /// input's line breaking decisions.
- void format(unsigned FirstIndent, const AnnotatedLine *Line) {
- LineState State =
- Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);
- while (State.NextToken) {
- bool Newline =
- Indenter->mustBreak(State) ||
- (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
- Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
- }
- }
-
-private:
- ContinuationIndenter *Indenter;
-};
-
-class LineJoiner {
-public:
- LineJoiner(const FormatStyle &Style) : Style(Style) {}
-
- /// \brief Calculates how many lines can be merged into 1 starting at \p I.
- unsigned
- tryFitMultipleLinesInOne(unsigned Indent,
- SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
- // We can never merge stuff if there are trailing line comments.
- const AnnotatedLine *TheLine = *I;
- if (TheLine->Last->Type == TT_LineComment)
- return 0;
-
- if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
- return 0;
-
- unsigned Limit =
- Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;
- // If we already exceed the column limit, we set 'Limit' to 0. The different
- // tryMerge..() functions can then decide whether to still do merging.
- Limit = TheLine->Last->TotalLength > Limit
- ? 0
- : Limit - TheLine->Last->TotalLength;
-
- if (I + 1 == E || I[1]->Type == LT_Invalid || I[1]->First->MustBreakBefore)
- return 0;
-
- // FIXME: TheLine->Level != 0 might or might not be the right check to do.
- // If necessary, change to something smarter.
- bool MergeShortFunctions =
- Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
- (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
- TheLine->Level != 0);
-
- if (TheLine->Last->Type == TT_FunctionLBrace &&
- TheLine->First != TheLine->Last) {
- return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
- }
- if (TheLine->Last->is(tok::l_brace)) {
- return Style.BreakBeforeBraces == FormatStyle::BS_Attach
- ? tryMergeSimpleBlock(I, E, Limit)
- : 0;
- }
- if (I[1]->First->Type == TT_FunctionLBrace &&
- Style.BreakBeforeBraces != FormatStyle::BS_Attach) {
- // Check for Limit <= 2 to account for the " {".
- if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))
- return 0;
- Limit -= 2;
-
- unsigned MergedLines = 0;
- if (MergeShortFunctions) {
- MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
- // If we managed to merge the block, count the function header, which is
- // on a separate line.
- if (MergedLines > 0)
- ++MergedLines;
- }
- return MergedLines;
- }
- if (TheLine->First->is(tok::kw_if)) {
- return Style.AllowShortIfStatementsOnASingleLine
- ? tryMergeSimpleControlStatement(I, E, Limit)
- : 0;
- }
- if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
- return Style.AllowShortLoopsOnASingleLine
- ? tryMergeSimpleControlStatement(I, E, Limit)
- : 0;
- }
- if (TheLine->First->isOneOf(tok::kw_case, tok::kw_default)) {
- return Style.AllowShortCaseLabelsOnASingleLine
- ? tryMergeShortCaseLabels(I, E, Limit)
- : 0;
- }
- if (TheLine->InPPDirective &&
- (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {
- return tryMergeSimplePPDirective(I, E, Limit);
- }
- return 0;
- }
-
-private:
- unsigned
- tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,
- unsigned Limit) {
- if (Limit == 0)
- return 0;
- if (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline)
- return 0;
- if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)
- return 0;
- if (1 + I[1]->Last->TotalLength > Limit)
- return 0;
- return 1;
- }
-
- unsigned tryMergeSimpleControlStatement(
- SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
- if (Limit == 0)
- return 0;
- if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
- Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&
- (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))
- return 0;
- if (I[1]->InPPDirective != (*I)->InPPDirective ||
- (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
- return 0;
- Limit = limitConsideringMacros(I + 1, E, Limit);
- AnnotatedLine &Line = **I;
- if (Line.Last->isNot(tok::r_paren))
- return 0;
- if (1 + I[1]->Last->TotalLength > Limit)
- return 0;
- if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,
- tok::kw_while) ||
- I[1]->First->Type == TT_LineComment)
- return 0;
- // Only inline simple if's (no nested if or else).
- if (I + 2 != E && Line.First->is(tok::kw_if) &&
- I[2]->First->is(tok::kw_else))
- return 0;
- return 1;
- }
-
- unsigned tryMergeShortCaseLabels(
- SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
- if (Limit == 0 || I + 1 == E ||
- I[1]->First->isOneOf(tok::kw_case, tok::kw_default))
- return 0;
- unsigned NumStmts = 0;
- unsigned Length = 0;
- for (; NumStmts < 3; ++NumStmts) {
- if (I + 1 + NumStmts == E)
- break;
- const AnnotatedLine *Line = I[1 + NumStmts];
- if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
- break;
- if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
- tok::kw_while))
- return 0;
- Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the space.
- }
- if (NumStmts == 0 || NumStmts == 3 || Length > Limit)
- return 0;
- return NumStmts;
- }
-
- unsigned
- tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,
- unsigned Limit) {
- AnnotatedLine &Line = **I;
-
- // Don't merge ObjC @ keywords and methods.
- if (Line.First->isOneOf(tok::at, tok::minus, tok::plus))
- return 0;
-
- // Check that the current line allows merging. This depends on whether we
- // are in a control flow statements as well as several style flags.
- if (Line.First->isOneOf(tok::kw_else, tok::kw_case))
- return 0;
- if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,
- tok::kw_catch, tok::kw_for, tok::r_brace)) {
- if (!Style.AllowShortBlocksOnASingleLine)
- return 0;
- if (!Style.AllowShortIfStatementsOnASingleLine &&
- Line.First->is(tok::kw_if))
- return 0;
- if (!Style.AllowShortLoopsOnASingleLine &&
- Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))
- return 0;
- // FIXME: Consider an option to allow short exception handling clauses on
- // a single line.
- if (Line.First->isOneOf(tok::kw_try, tok::kw_catch))
- return 0;
- }
-
- FormatToken *Tok = I[1]->First;
- if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
- (Tok->getNextNonComment() == nullptr ||
- Tok->getNextNonComment()->is(tok::semi))) {
- // We merge empty blocks even if the line exceeds the column limit.
- Tok->SpacesRequiredBefore = 0;
- Tok->CanBreakBefore = true;
- return 1;
- } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace) &&
- !startsExternCBlock(Line)) {
- // We don't merge short records.
- if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct))
- return 0;
-
- // Check that we still have three lines and they fit into the limit.
- if (I + 2 == E || I[2]->Type == LT_Invalid)
- return 0;
- Limit = limitConsideringMacros(I + 2, E, Limit);
-
- if (!nextTwoLinesFitInto(I, Limit))
- return 0;
-
- // Second, check that the next line does not contain any braces - if it
- // does, readability declines when putting it into a single line.
- if (I[1]->Last->Type == TT_LineComment)
- return 0;
- do {
- if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
- return 0;
- Tok = Tok->Next;
- } while (Tok);
-
- // Last, check that the third line starts with a closing brace.
- Tok = I[2]->First;
- if (Tok->isNot(tok::r_brace))
- return 0;
-
- return 2;
- }
- return 0;
- }
-
- /// Returns the modified column limit for \p I if it is inside a macro and
- /// needs a trailing '\'.
- unsigned
- limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E,
- unsigned Limit) {
- if (I[0]->InPPDirective && I + 1 != E &&
- !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {
- return Limit < 2 ? 0 : Limit - 2;
- }
- return Limit;
- }
-
- bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- unsigned Limit) {
- if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
- return false;
- return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
- }
-
- bool containsMustBreak(const AnnotatedLine *Line) {
- for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
- if (Tok->MustBreakBefore)
- return true;
- }
- return false;
- }
-
- const FormatStyle &Style;
-};
-
-class UnwrappedLineFormatter {
-public:
- UnwrappedLineFormatter(ContinuationIndenter *Indenter,
- WhitespaceManager *Whitespaces,
- const FormatStyle &Style)
- : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
- Joiner(Style) {}
-
- unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
- int AdditionalIndent = 0, bool FixBadIndentation = false) {
- // Try to look up already computed penalty in DryRun-mode.
- std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
- &Lines, AdditionalIndent);
- auto CacheIt = PenaltyCache.find(CacheKey);
- if (DryRun && CacheIt != PenaltyCache.end())
- return CacheIt->second;
-
- assert(!Lines.empty());
- unsigned Penalty = 0;
- std::vector<int> IndentForLevel;
- for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)
- IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
- const AnnotatedLine *PreviousLine = nullptr;
- for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),
- E = Lines.end();
- I != E; ++I) {
- const AnnotatedLine &TheLine = **I;
- const FormatToken *FirstTok = TheLine.First;
- int Offset = getIndentOffset(*FirstTok);
-
- // Determine indent and try to merge multiple unwrapped lines.
- unsigned Indent;
- if (TheLine.InPPDirective) {
- Indent = TheLine.Level * Style.IndentWidth;
- } else {
- while (IndentForLevel.size() <= TheLine.Level)
- IndentForLevel.push_back(-1);
- IndentForLevel.resize(TheLine.Level + 1);
- Indent = getIndent(IndentForLevel, TheLine.Level);
- }
- unsigned LevelIndent = Indent;
- if (static_cast<int>(Indent) + Offset >= 0)
- Indent += Offset;
-
- // Merge multiple lines if possible.
- unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E);
- if (MergedLines > 0 && Style.ColumnLimit == 0) {
- // Disallow line merging if there is a break at the start of one of the
- // input lines.
- for (unsigned i = 0; i < MergedLines; ++i) {
- if (I[i + 1]->First->NewlinesBefore > 0)
- MergedLines = 0;
- }
- }
- if (!DryRun) {
- for (unsigned i = 0; i < MergedLines; ++i) {
- join(*I[i], *I[i + 1]);
- }
- }
- I += MergedLines;
-
- bool FixIndentation =
- FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);
- if (TheLine.First->is(tok::eof)) {
- if (PreviousLine && PreviousLine->Affected && !DryRun) {
- // Remove the file's trailing whitespace.
- unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);
- Whitespaces->replaceWhitespace(*TheLine.First, Newlines,
- /*IndentLevel=*/0, /*Spaces=*/0,
- /*TargetColumn=*/0);
- }
- } else if (TheLine.Type != LT_Invalid &&
- (TheLine.Affected || FixIndentation)) {
- if (FirstTok->WhitespaceRange.isValid()) {
- if (!DryRun)
- formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level,
- Indent, TheLine.InPPDirective);
- } else {
- Indent = LevelIndent = FirstTok->OriginalColumn;
- }
-
- // If everything fits on a single line, just put it there.
- unsigned ColumnLimit = Style.ColumnLimit;
- if (I + 1 != E) {
- AnnotatedLine *NextLine = I[1];
- if (NextLine->InPPDirective && !NextLine->First->HasUnescapedNewline)
- ColumnLimit = getColumnLimit(TheLine.InPPDirective);
- }
-
- if (TheLine.Last->TotalLength + Indent <= ColumnLimit) {
- LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun);
- while (State.NextToken) {
- formatChildren(State, /*Newline=*/false, /*DryRun=*/false, Penalty);
- Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
- }
- } else if (Style.ColumnLimit == 0) {
- // FIXME: Implement nested blocks for ColumnLimit = 0.
- NoColumnLimitFormatter Formatter(Indenter);
- if (!DryRun)
- Formatter.format(Indent, &TheLine);
- } else {
- Penalty += format(TheLine, Indent, DryRun);
- }
-
- if (!TheLine.InPPDirective)
- IndentForLevel[TheLine.Level] = LevelIndent;
- } else if (TheLine.ChildrenAffected) {
- format(TheLine.Children, DryRun);
- } else {
- // Format the first token if necessary, and notify the WhitespaceManager
- // about the unchanged whitespace.
- for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
- if (Tok == TheLine.First &&
- (Tok->NewlinesBefore > 0 || Tok->IsFirst)) {
- unsigned LevelIndent = Tok->OriginalColumn;
- if (!DryRun) {
- // Remove trailing whitespace of the previous line.
- if ((PreviousLine && PreviousLine->Affected) ||
- TheLine.LeadingEmptyLinesAffected) {
- formatFirstToken(*Tok, PreviousLine, TheLine.Level, LevelIndent,
- TheLine.InPPDirective);
- } else {
- Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
- }
- }
-
- if (static_cast<int>(LevelIndent) - Offset >= 0)
- LevelIndent -= Offset;
- if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)
- IndentForLevel[TheLine.Level] = LevelIndent;
- } else if (!DryRun) {
- Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
- }
- }
- }
- if (!DryRun) {
- for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
- Tok->Finalized = true;
- }
- }
- PreviousLine = *I;
- }
- PenaltyCache[CacheKey] = Penalty;
- return Penalty;
- }
-
-private:
- /// \brief Formats an \c AnnotatedLine and returns the penalty.
- ///
- /// If \p DryRun is \c false, directly applies the changes.
- unsigned format(const AnnotatedLine &Line, unsigned FirstIndent,
- bool DryRun) {
- LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
-
- // If the ObjC method declaration does not fit on a line, we should format
- // it with one arg per line.
- if (State.Line->Type == LT_ObjCMethodDecl)
- State.Stack.back().BreakBeforeParameter = true;
-
- // Find best solution in solution space.
- return analyzeSolutionSpace(State, DryRun);
- }
-
- /// \brief An edge in the solution space from \c Previous->State to \c State,
- /// inserting a newline dependent on the \c NewLine.
- struct StateNode {
- StateNode(const LineState &State, bool NewLine, StateNode *Previous)
- : State(State), NewLine(NewLine), Previous(Previous) {}
- LineState State;
- bool NewLine;
- StateNode *Previous;
- };
-
- /// \brief A pair of <penalty, count> that is used to prioritize the BFS on.
- ///
- /// In case of equal penalties, we want to prefer states that were inserted
- /// first. During state generation we make sure that we insert states first
- /// that break the line as late as possible.
- typedef std::pair<unsigned, unsigned> OrderedPenalty;
-
- /// \brief An item in the prioritized BFS search queue. The \c StateNode's
- /// \c State has the given \c OrderedPenalty.
- typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
-
- /// \brief The BFS queue type.
- typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
- std::greater<QueueItem> > QueueType;
-
- /// \brief Get the offset of the line relatively to the level.
- ///
- /// For example, 'public:' labels in classes are offset by 1 or 2
- /// characters to the left from their level.
- int getIndentOffset(const FormatToken &RootToken) {
- if (Style.Language == FormatStyle::LK_Java)
- return 0;
- if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())
- return Style.AccessModifierOffset;
- return 0;
- }
-
- /// \brief Add a new line and the required indent before the first Token
- /// of the \c UnwrappedLine if there was no structural parsing error.
- void formatFirstToken(FormatToken &RootToken,
- const AnnotatedLine *PreviousLine, unsigned IndentLevel,
- unsigned Indent, bool InPPDirective) {
- unsigned Newlines =
- std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
- // Remove empty lines before "}" where applicable.
- if (RootToken.is(tok::r_brace) &&
- (!RootToken.Next ||
- (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))
- Newlines = std::min(Newlines, 1u);
- if (Newlines == 0 && !RootToken.IsFirst)
- Newlines = 1;
- if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
- Newlines = 0;
-
- // Remove empty lines after "{".
- if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
- PreviousLine->Last->is(tok::l_brace) &&
- PreviousLine->First->isNot(tok::kw_namespace) &&
- !startsExternCBlock(*PreviousLine))
- Newlines = 1;
-
- // Insert extra new line before access specifiers.
- if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&
- RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)
- ++Newlines;
-
- // Remove empty lines after access specifiers.
- if (PreviousLine && PreviousLine->First->isAccessSpecifier())
- Newlines = std::min(1u, Newlines);
-
- Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
- Indent, InPPDirective &&
- !RootToken.HasUnescapedNewline);
- }
-
- /// \brief Get the indent of \p Level from \p IndentForLevel.
- ///
- /// \p IndentForLevel must contain the indent for the level \c l
- /// at \p IndentForLevel[l], or a value < 0 if the indent for
- /// that level is unknown.
- unsigned getIndent(ArrayRef<int> IndentForLevel, unsigned Level) {
- if (IndentForLevel[Level] != -1)
- return IndentForLevel[Level];
- if (Level == 0)
- return 0;
- return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;
- }
-
- void join(AnnotatedLine &A, const AnnotatedLine &B) {
- assert(!A.Last->Next);
- assert(!B.First->Previous);
- if (B.Affected)
- A.Affected = true;
- A.Last->Next = B.First;
- B.First->Previous = A.Last;
- B.First->CanBreakBefore = true;
- unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;
- for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {
- Tok->TotalLength += LengthA;
- A.Last = Tok;
- }
- }
-
- unsigned getColumnLimit(bool InPPDirective) const {
- // In preprocessor directives reserve two chars for trailing " \"
- return Style.ColumnLimit - (InPPDirective ? 2 : 0);
- }
-
- struct CompareLineStatePointers {
- bool operator()(LineState *obj1, LineState *obj2) const {
- return *obj1 < *obj2;
- }
- };
-
- /// \brief Analyze the entire solution space starting from \p InitialState.
- ///
- /// This implements a variant of Dijkstra's algorithm on the graph that spans
- /// the solution space (\c LineStates are the nodes). The algorithm tries to
- /// find the shortest path (the one with lowest penalty) from \p InitialState
- /// to a state where all tokens are placed. Returns the penalty.
- ///
- /// If \p DryRun is \c false, directly applies the changes.
- unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false) {
- std::set<LineState *, CompareLineStatePointers> Seen;
-
- // Increasing count of \c StateNode items we have created. This is used to
- // create a deterministic order independent of the container.
- unsigned Count = 0;
- QueueType Queue;
-
- // Insert start element into queue.
- StateNode *Node =
- new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);
- Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
- ++Count;
-
- unsigned Penalty = 0;
-
- // While not empty, take first element and follow edges.
- while (!Queue.empty()) {
- Penalty = Queue.top().first.first;
- StateNode *Node = Queue.top().second;
- if (!Node->State.NextToken) {
- DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");
- break;
- }
- Queue.pop();
-
- // Cut off the analysis of certain solutions if the analysis gets too
- // complex. See description of IgnoreStackForComparison.
- if (Count > 10000)
- Node->State.IgnoreStackForComparison = true;
-
- if (!Seen.insert(&Node->State).second)
- // State already examined with lower penalty.
- continue;
-
- FormatDecision LastFormat = Node->State.NextToken->Decision;
- if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
- addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue);
- if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
- addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue);
- }
-
- if (Queue.empty()) {
- // We were unable to find a solution, do nothing.
- // FIXME: Add diagnostic?
- DEBUG(llvm::dbgs() << "Could not find a solution.\n");
- return 0;
- }
-
- // Reconstruct the solution.
- if (!DryRun)
- reconstructPath(InitialState, Queue.top().second);
-
- DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count << "\n");
- DEBUG(llvm::dbgs() << "---\n");
-
- return Penalty;
- }
-
- void reconstructPath(LineState &State, StateNode *Current) {
- std::deque<StateNode *> Path;
- // We do not need a break before the initial token.
- while (Current->Previous) {
- Path.push_front(Current);
- Current = Current->Previous;
- }
- for (std::deque<StateNode *>::iterator I = Path.begin(), E = Path.end();
- I != E; ++I) {
- unsigned Penalty = 0;
- formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);
- Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);
-
- DEBUG({
- if ((*I)->NewLine) {
- llvm::dbgs() << "Penalty for placing "
- << (*I)->Previous->State.NextToken->Tok.getName() << ": "
- << Penalty << "\n";
- }
- });
- }
- }
-
- /// \brief Add the following state to the analysis queue \c Queue.
- ///
- /// Assume the current state is \p PreviousNode and has been reached with a
- /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
- void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
- bool NewLine, unsigned *Count, QueueType *Queue) {
- if (NewLine && !Indenter->canBreak(PreviousNode->State))
- return;
- if (!NewLine && Indenter->mustBreak(PreviousNode->State))
- return;
-
- StateNode *Node = new (Allocator.Allocate())
- StateNode(PreviousNode->State, NewLine, PreviousNode);
- if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))
- return;
-
- Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
-
- Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
- ++(*Count);
- }
-
- /// \brief If the \p State's next token is an r_brace closing a nested block,
- /// format the nested block before it.
- ///
- /// Returns \c true if all children could be placed successfully and adapts
- /// \p Penalty as well as \p State. If \p DryRun is false, also directly
- /// creates changes using \c Whitespaces.
- ///
- /// The crucial idea here is that children always get formatted upon
- /// encountering the closing brace right after the nested block. Now, if we
- /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is
- /// \c false), the entire block has to be kept on the same line (which is only
- /// possible if it fits on the line, only contains a single statement, etc.
- ///
- /// If \p NewLine is true, we format the nested block on separate lines, i.e.
- /// break after the "{", format all lines with correct indentation and the put
- /// the closing "}" on yet another new line.
- ///
- /// This enables us to keep the simple structure of the
- /// \c UnwrappedLineFormatter, where we only have two options for each token:
- /// break or don't break.
- bool formatChildren(LineState &State, bool NewLine, bool DryRun,
- unsigned &Penalty) {
- FormatToken &Previous = *State.NextToken->Previous;
- const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
- if (!LBrace || LBrace->isNot(tok::l_brace) ||
- LBrace->BlockKind != BK_Block || Previous.Children.size() == 0)
- // The previous token does not open a block. Nothing to do. We don't
- // assert so that we can simply call this function for all tokens.
- return true;
-
- if (NewLine) {
- int AdditionalIndent =
- State.FirstIndent - State.Line->Level * Style.IndentWidth;
- if (State.Stack.size() < 2 ||
- !State.Stack[State.Stack.size() - 2].JSFunctionInlined) {
- AdditionalIndent = State.Stack.back().Indent -
- Previous.Children[0]->Level * Style.IndentWidth;
- }
-
- Penalty += format(Previous.Children, DryRun, AdditionalIndent,
- /*FixBadIndentation=*/true);
- return true;
- }
-
- if (Previous.Children[0]->First->MustBreakBefore)
- 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.
- if (Previous.is(tok::comment))
- return false;
-
- // We can't put the closing "}" on a line with a trailing comment.
- if (Previous.Children[0]->Last->isTrailingComment())
- return false;
-
- // If the child line exceeds the column limit, we wouldn't want to merge it.
- // We add +2 for the trailing " }".
- if (Style.ColumnLimit > 0 &&
- Previous.Children[0]->Last->TotalLength + State.Column + 2 >
- Style.ColumnLimit)
- return false;
-
- if (!DryRun) {
- Whitespaces->replaceWhitespace(
- *Previous.Children[0]->First,
- /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,
- /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
- }
- Penalty += format(*Previous.Children[0], State.Column + 1, DryRun);
-
- State.Column += 1 + Previous.Children[0]->Last->TotalLength;
- return true;
- }
-
- ContinuationIndenter *Indenter;
- WhitespaceManager *Whitespaces;
- FormatStyle Style;
- LineJoiner Joiner;
-
- llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
-
- // Cache to store the penalty of formatting a vector of AnnotatedLines
- // starting from a specific additional offset. Improves performance if there
- // are many nested blocks.
- std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
- unsigned> PenaltyCache;
-};
-
class FormatTokenLexer {
public:
FormatTokenLexer(SourceManager &SourceMgr, FileID ID, FormatStyle &Style,
encoding::Encoding Encoding)
: FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false),
- Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID),
- Style(Style), IdentTable(getFormattingLangOpts(Style)),
- Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0),
- FormattingDisabled(false) {
+ LessStashed(false), Column(0), TrailingWhitespace(0),
+ SourceMgr(SourceMgr), ID(ID), Style(Style),
+ IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable),
+ Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false) {
Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr,
getFormattingLangOpts(Style)));
Lex->SetKeepWhitespaceMode(true);
@@ -1367,7 +617,7 @@
do {
Tokens.push_back(getNextToken());
tryMergePreviousTokens();
- if (Tokens.back()->NewlinesBefore > 0)
+ if (Tokens.back()->NewlinesBefore > 0 || Tokens.back()->IsMultiline)
FirstInLineIndex = Tokens.size() - 1;
} while (Tokens.back()->Tok.isNot(tok::eof));
return Tokens;
@@ -1381,18 +631,22 @@
return;
if (tryMergeConflictMarkers())
return;
+ if (tryMergeLessLess())
+ return;
if (Style.Language == FormatStyle::LK_JavaScript) {
if (tryMergeJSRegexLiteral())
return;
if (tryMergeEscapeSequence())
return;
+ if (tryMergeTemplateString())
+ return;
- static tok::TokenKind JSIdentity[] = { tok::equalequal, tok::equal };
- static tok::TokenKind JSNotIdentity[] = { tok::exclaimequal, tok::equal };
- static tok::TokenKind JSShiftEqual[] = { tok::greater, tok::greater,
- tok::greaterequal };
- static tok::TokenKind JSRightArrow[] = { tok::equal, tok::greater };
+ static tok::TokenKind JSIdentity[] = {tok::equalequal, tok::equal};
+ static tok::TokenKind JSNotIdentity[] = {tok::exclaimequal, tok::equal};
+ static tok::TokenKind JSShiftEqual[] = {tok::greater, tok::greater,
+ tok::greaterequal};
+ static tok::TokenKind JSRightArrow[] = {tok::equal, tok::greater};
// FIXME: We probably need to change token type to mimic operator with the
// correct priority.
if (tryMergeTokens(JSIdentity))
@@ -1406,6 +660,32 @@
}
}
+ bool tryMergeLessLess() {
+ // Merge X,less,less,Y into X,lessless,Y unless X or Y is less.
+ if (Tokens.size() < 3)
+ return false;
+
+ bool FourthTokenIsLess = false;
+ if (Tokens.size() > 3)
+ FourthTokenIsLess = (Tokens.end() - 4)[0]->is(tok::less);
+
+ auto First = Tokens.end() - 3;
+ if (First[2]->is(tok::less) || First[1]->isNot(tok::less) ||
+ First[0]->isNot(tok::less) || FourthTokenIsLess)
+ return false;
+
+ // Only merge if there currently is no whitespace between the two "<".
+ if (First[1]->WhitespaceRange.getBegin() !=
+ First[1]->WhitespaceRange.getEnd())
+ return false;
+
+ First[0]->Tok.setKind(tok::lessless);
+ First[0]->TokenText = "<<";
+ First[0]->ColumnWidth += 1;
+ Tokens.erase(Tokens.end() - 2);
+ return true;
+ }
+
bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds) {
if (Tokens.size() < Kinds.size())
return false;
@@ -1416,8 +696,9 @@
return false;
unsigned AddLength = 0;
for (unsigned i = 1; i < Kinds.size(); ++i) {
- if (!First[i]->is(Kinds[i]) || First[i]->WhitespaceRange.getBegin() !=
- First[i]->WhitespaceRange.getEnd())
+ if (!First[i]->is(Kinds[i]) ||
+ First[i]->WhitespaceRange.getBegin() !=
+ First[i]->WhitespaceRange.getEnd())
return false;
AddLength += First[i]->TokenText.size();
}
@@ -1493,6 +774,66 @@
return false;
}
+ bool tryMergeTemplateString() {
+ if (Tokens.size() < 2)
+ return false;
+
+ FormatToken *EndBacktick = Tokens.back();
+ if (!(EndBacktick->is(tok::unknown) && EndBacktick->TokenText == "`"))
+ return false;
+
+ unsigned TokenCount = 0;
+ bool IsMultiline = false;
+ unsigned EndColumnInFirstLine = 0;
+ for (auto I = Tokens.rbegin() + 1, E = Tokens.rend(); I != E; I++) {
+ ++TokenCount;
+ if (I[0]->NewlinesBefore > 0 || I[0]->IsMultiline)
+ IsMultiline = true;
+
+ // If there was a preceding template string, this must be the start of a
+ // template string, not the end.
+ if (I[0]->is(TT_TemplateString))
+ return false;
+
+ if (I[0]->isNot(tok::unknown) || I[0]->TokenText != "`") {
+ // Keep track of the rhs offset of the last token to wrap across lines -
+ // its the rhs offset of the first line of the template string, used to
+ // determine its width.
+ if (I[0]->IsMultiline)
+ EndColumnInFirstLine = I[0]->OriginalColumn + I[0]->ColumnWidth;
+ // If the token has newlines, the token before it (if it exists) is the
+ // rhs end of the previous line.
+ if (I[0]->NewlinesBefore > 0 && (I + 1 != E))
+ EndColumnInFirstLine = I[1]->OriginalColumn + I[1]->ColumnWidth;
+
+ continue;
+ }
+
+ Tokens.resize(Tokens.size() - TokenCount);
+ Tokens.back()->Type = TT_TemplateString;
+ const char *EndOffset = EndBacktick->TokenText.data() + 1;
+ Tokens.back()->TokenText =
+ StringRef(Tokens.back()->TokenText.data(),
+ EndOffset - Tokens.back()->TokenText.data());
+ if (IsMultiline) {
+ // ColumnWidth is from backtick to last token in line.
+ // LastLineColumnWidth is 0 to backtick.
+ // x = `some content
+ // until here`;
+ Tokens.back()->ColumnWidth =
+ EndColumnInFirstLine - Tokens.back()->OriginalColumn;
+ Tokens.back()->LastLineColumnWidth = EndBacktick->OriginalColumn;
+ Tokens.back()->IsMultiline = true;
+ } else {
+ // Token simply spans from start to end, +1 for the ` itself.
+ Tokens.back()->ColumnWidth =
+ EndBacktick->OriginalColumn - Tokens.back()->OriginalColumn + 1;
+ }
+ return true;
+ }
+ return false;
+ }
+
bool tryMerge_TMacro() {
if (Tokens.size() < 4)
return false;
@@ -1590,21 +931,33 @@
return false;
}
+ FormatToken *getStashedToken() {
+ // Create a synthesized second '>' or '<' token.
+ Token Tok = FormatTok->Tok;
+ StringRef TokenText = FormatTok->TokenText;
+
+ unsigned OriginalColumn = FormatTok->OriginalColumn;
+ FormatTok = new (Allocator.Allocate()) FormatToken;
+ FormatTok->Tok = Tok;
+ SourceLocation TokLocation =
+ FormatTok->Tok.getLocation().getLocWithOffset(Tok.getLength() - 1);
+ FormatTok->Tok.setLocation(TokLocation);
+ FormatTok->WhitespaceRange = SourceRange(TokLocation, TokLocation);
+ FormatTok->TokenText = TokenText;
+ FormatTok->ColumnWidth = 1;
+ FormatTok->OriginalColumn = OriginalColumn + 1;
+
+ return FormatTok;
+ }
+
FormatToken *getNextToken() {
if (GreaterStashed) {
- // Create a synthesized second '>' token.
- // FIXME: Increment Column and set OriginalColumn.
- Token Greater = FormatTok->Tok;
- FormatTok = new (Allocator.Allocate()) FormatToken;
- FormatTok->Tok = Greater;
- SourceLocation GreaterLocation =
- FormatTok->Tok.getLocation().getLocWithOffset(1);
- FormatTok->WhitespaceRange =
- SourceRange(GreaterLocation, GreaterLocation);
- FormatTok->TokenText = ">";
- FormatTok->ColumnWidth = 1;
GreaterStashed = false;
- return FormatTok;
+ return getStashedToken();
+ }
+ if (LessStashed) {
+ LessStashed = false;
+ return getStashedToken();
}
FormatTok = new (Allocator.Allocate()) FormatToken;
@@ -1617,6 +970,8 @@
// Consume and record whitespace until we find a significant token.
unsigned WhitespaceLength = TrailingWhitespace;
while (FormatTok->Tok.is(tok::unknown)) {
+ // FIXME: This miscounts tok:unknown tokens that are not just
+ // whitespace, e.g. a '`' character.
for (int i = 0, e = FormatTok->TokenText.size(); i != e; ++i) {
switch (FormatTok->TokenText[i]) {
case '\n':
@@ -1631,6 +986,9 @@
Column = 0;
break;
case '\r':
+ FormatTok->LastNewlineOffset = WhitespaceLength + i + 1;
+ Column = 0;
+ break;
case '\f':
case '\v':
Column = 0;
@@ -1642,7 +1000,6 @@
Column += Style.TabWidth - Column % Style.TabWidth;
break;
case '\\':
- ++Column;
if (i + 1 == e || (FormatTok->TokenText[i + 1] != '\r' &&
FormatTok->TokenText[i + 1] != '\n'))
FormatTok->Type = TT_ImplicitStringLiteral;
@@ -1654,7 +1011,7 @@
}
}
- if (FormatTok->Type == TT_ImplicitStringLiteral)
+ if (FormatTok->is(TT_ImplicitStringLiteral))
break;
WhitespaceLength += FormatTok->Tok.getLength();
@@ -1697,6 +1054,10 @@
FormatTok->Tok.setKind(tok::greater);
FormatTok->TokenText = FormatTok->TokenText.substr(0, 1);
GreaterStashed = true;
+ } else if (FormatTok->Tok.is(tok::lessless)) {
+ FormatTok->Tok.setKind(tok::less);
+ FormatTok->TokenText = FormatTok->TokenText.substr(0, 1);
+ LessStashed = true;
}
// Now FormatTok is the next non-whitespace token.
@@ -1733,7 +1094,7 @@
FormatToken *FormatTok;
bool IsFirstToken;
- bool GreaterStashed;
+ bool GreaterStashed, LessStashed;
unsigned Column;
unsigned TrailingWhitespace;
std::unique_ptr<Lexer> Lex;
@@ -1871,7 +1232,8 @@
ContinuationIndenter Indenter(Style, Tokens.getKeywords(), SourceMgr,
Whitespaces, Encoding,
BinPackInconclusiveFunctions);
- UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style);
+ UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style,
+ Tokens.getKeywords());
Formatter.format(AnnotatedLines, /*DryRun=*/false);
return Whitespaces.generateReplacements();
}
@@ -2026,7 +1388,7 @@
continue;
FormatToken *Tok = AnnotatedLines[i]->First->Next;
while (Tok->Next) {
- if (Tok->Type == TT_PointerOrReference) {
+ if (Tok->is(TT_PointerOrReference)) {
bool SpacesBefore =
Tok->WhitespaceRange.getBegin() != Tok->WhitespaceRange.getEnd();
bool SpacesAfter = Tok->Next->WhitespaceRange.getBegin() !=
@@ -2038,11 +1400,10 @@
}
if (Tok->WhitespaceRange.getBegin() == Tok->WhitespaceRange.getEnd()) {
- if (Tok->is(tok::coloncolon) &&
- Tok->Previous->Type == TT_TemplateOpener)
+ if (Tok->is(tok::coloncolon) && Tok->Previous->is(TT_TemplateOpener))
HasCpp03IncompatibleFormat = true;
- if (Tok->Type == TT_TemplateCloser &&
- Tok->Previous->Type == TT_TemplateCloser)
+ if (Tok->is(TT_TemplateCloser) &&
+ Tok->Previous->is(TT_TemplateCloser))
HasCpp03IncompatibleFormat = true;
}
@@ -2148,6 +1509,7 @@
LangOpts.Bool = 1;
LangOpts.ObjC1 = 1;
LangOpts.ObjC2 = 1;
+ LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
return LangOpts;
}
diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp
index 677f1a0..0addbfe 100644
--- a/lib/Format/FormatToken.cpp
+++ b/lib/Format/FormatToken.cpp
@@ -59,7 +59,8 @@
unsigned CommaSeparatedList::formatAfterToken(LineState &State,
ContinuationIndenter *Indenter,
bool DryRun) {
- if (!State.NextToken->Previous || !State.NextToken->Previous->Previous)
+ if (State.NextToken == nullptr || !State.NextToken->Previous ||
+ !State.NextToken->Previous->Previous)
return 0;
// Ensure that we start on the opening brace.
@@ -138,6 +139,10 @@
Commas.size() < 19)
return;
+ // Column format doesn't really make sense if we don't align after brackets.
+ if (!Style.AlignAfterOpenBracket)
+ return;
+
FormatToken *ItemBegin = Token->Next;
SmallVector<bool, 8> MustBreakBeforeItem;
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index 0ef563b..14f45a4 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -48,6 +48,8 @@
TT_InheritanceColon,
TT_InlineASMColon,
TT_JavaAnnotation,
+ TT_JsTypeColon,
+ TT_LambdaArrow,
TT_LambdaLSquare,
TT_LeadingJavaAnnotation,
TT_LineComment,
@@ -68,6 +70,7 @@
TT_StartOfName,
TT_TemplateCloser,
TT_TemplateOpener,
+ TT_TemplateString,
TT_TrailingAnnotation,
TT_TrailingReturnArrow,
TT_TrailingUnaryOperator,
@@ -270,36 +273,18 @@
bool IsForEachMacro;
bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
-
+ bool is(TokenType TT) const { return Type == TT; }
bool is(const IdentifierInfo *II) const {
return II && II == Tok.getIdentifierInfo();
}
-
- template <typename T>
- bool isOneOf(T K1, T K2) const {
+ template <typename A, typename B> bool isOneOf(A K1, B K2) const {
return is(K1) || is(K2);
}
-
- template <typename T>
- bool isOneOf(T K1, T K2, T K3) const {
- return is(K1) || is(K2) || is(K3);
+ template <typename A, typename B, typename... Ts>
+ bool isOneOf(A K1, B K2, Ts... Ks) const {
+ return is(K1) || isOneOf(K2, Ks...);
}
-
- template <typename T>
- bool isOneOf(T K1, T K2, T K3, T K4, T K5 = tok::NUM_TOKENS,
- T K6 = tok::NUM_TOKENS, T K7 = tok::NUM_TOKENS,
- T K8 = tok::NUM_TOKENS, T K9 = tok::NUM_TOKENS,
- T K10 = tok::NUM_TOKENS, T K11 = tok::NUM_TOKENS,
- T K12 = tok::NUM_TOKENS) const {
- return is(K1) || is(K2) || is(K3) || is(K4) || is(K5) || is(K6) || is(K7) ||
- is(K8) || is(K9) || is(K10) || is(K11) || is(K12);
- }
-
- template <typename T>
- bool isNot(T Kind) const {
- return Tok.isNot(Kind);
- }
- bool isNot(IdentifierInfo *II) const { return II != Tok.getIdentifierInfo(); }
+ template <typename T> bool isNot(T Kind) const { return !is(Kind); }
bool isStringLiteral() const { return tok::isStringLiteral(Tok.getKind()); }
@@ -324,20 +309,19 @@
/// \brief Returns whether \p Tok is ([{ or a template opening <.
bool opensScope() const {
- return isOneOf(tok::l_paren, tok::l_brace, tok::l_square) ||
- Type == TT_TemplateOpener;
+ return isOneOf(tok::l_paren, tok::l_brace, tok::l_square,
+ TT_TemplateOpener);
}
/// \brief Returns whether \p Tok is )]} or a template closing >.
bool closesScope() const {
- return isOneOf(tok::r_paren, tok::r_brace, tok::r_square) ||
- Type == TT_TemplateCloser;
+ return isOneOf(tok::r_paren, tok::r_brace, tok::r_square,
+ TT_TemplateCloser);
}
/// \brief Returns \c true if this is a "." or "->" accessing a member.
bool isMemberAccess() const {
return isOneOf(tok::arrow, tok::period, tok::arrowstar) &&
- Type != TT_DesignatedInitializerPeriod &&
- Type != TT_TrailingReturnArrow;
+ !isOneOf(TT_DesignatedInitializerPeriod, TT_TrailingReturnArrow);
}
bool isUnaryOperator() const {
@@ -363,7 +347,7 @@
bool isTrailingComment() const {
return is(tok::comment) &&
- (Type == TT_LineComment || !Next || Next->NewlinesBefore > 0);
+ (is(TT_LineComment) || !Next || Next->NewlinesBefore > 0);
}
/// \brief Returns \c true if this is a keyword that can be used
@@ -409,10 +393,10 @@
/// \brief Returns \c true if this tokens starts a block-type list, i.e. a
/// list that should be indented with a block indent.
bool opensBlockTypeList(const FormatStyle &Style) const {
- return Type == TT_ArrayInitializerLSquare ||
+ return is(TT_ArrayInitializerLSquare) ||
(is(tok::l_brace) &&
- (BlockKind == BK_Block || Type == TT_DictLiteral ||
- !Style.Cpp11BracedListStyle));
+ (BlockKind == BK_Block || is(TT_DictLiteral) ||
+ (!Style.Cpp11BracedListStyle && NestingLevel == 0)));
}
/// \brief Same as opensBlockTypeList, but for the closing token.
@@ -437,8 +421,8 @@
private:
// Disallow copying.
- FormatToken(const FormatToken &) LLVM_DELETED_FUNCTION;
- void operator=(const FormatToken &) LLVM_DELETED_FUNCTION;
+ FormatToken(const FormatToken &) = delete;
+ void operator=(const FormatToken &) = delete;
};
class ContinuationIndenter;
@@ -537,17 +521,27 @@
struct AdditionalKeywords {
AdditionalKeywords(IdentifierTable &IdentTable) {
kw_in = &IdentTable.get("in");
+ kw_CF_ENUM = &IdentTable.get("CF_ENUM");
+ kw_CF_OPTIONS = &IdentTable.get("CF_OPTIONS");
kw_NS_ENUM = &IdentTable.get("NS_ENUM");
+ kw_NS_OPTIONS = &IdentTable.get("NS_OPTIONS");
kw_finally = &IdentTable.get("finally");
kw_function = &IdentTable.get("function");
+ kw_import = &IdentTable.get("import");
kw_var = &IdentTable.get("var");
+ kw_abstract = &IdentTable.get("abstract");
kw_extends = &IdentTable.get("extends");
+ kw_final = &IdentTable.get("final");
kw_implements = &IdentTable.get("implements");
+ kw_instanceof = &IdentTable.get("instanceof");
kw_interface = &IdentTable.get("interface");
+ kw_native = &IdentTable.get("native");
+ kw_package = &IdentTable.get("package");
kw_synchronized = &IdentTable.get("synchronized");
kw_throws = &IdentTable.get("throws");
+ kw___except = &IdentTable.get("__except");
kw_option = &IdentTable.get("option");
kw_optional = &IdentTable.get("optional");
@@ -556,19 +550,29 @@
kw_returns = &IdentTable.get("returns");
}
- // ObjC context sensitive keywords.
+ // Context sensitive keywords.
IdentifierInfo *kw_in;
+ IdentifierInfo *kw_CF_ENUM;
+ IdentifierInfo *kw_CF_OPTIONS;
IdentifierInfo *kw_NS_ENUM;
+ IdentifierInfo *kw_NS_OPTIONS;
+ IdentifierInfo *kw___except;
// JavaScript keywords.
IdentifierInfo *kw_finally;
IdentifierInfo *kw_function;
+ IdentifierInfo *kw_import;
IdentifierInfo *kw_var;
// Java keywords.
+ IdentifierInfo *kw_abstract;
IdentifierInfo *kw_extends;
+ IdentifierInfo *kw_final;
IdentifierInfo *kw_implements;
+ IdentifierInfo *kw_instanceof;
IdentifierInfo *kw_interface;
+ IdentifierInfo *kw_native;
+ IdentifierInfo *kw_package;
IdentifierInfo *kw_synchronized;
IdentifierInfo *kw_throws;
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 1afdb19..fa086a9 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -33,8 +33,8 @@
public:
AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line,
const AdditionalKeywords &Keywords)
- : Style(Style), Line(Line), CurrentToken(Line.First),
- KeywordVirtualFound(false), AutoFound(false), Keywords(Keywords) {
+ : Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
+ Keywords(Keywords) {
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
resetTokenMetadata(CurrentToken);
}
@@ -78,7 +78,7 @@
// parameters.
// FIXME: This is getting out of hand, write a decent parser.
if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) &&
- CurrentToken->Previous->Type == TT_BinaryOperator &&
+ CurrentToken->Previous->is(TT_BinaryOperator) &&
Contexts[Contexts.size() - 2].IsExpression &&
Line.First->isNot(tok::kw_template))
return false;
@@ -114,17 +114,17 @@
if (Left->Previous &&
(Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_if,
tok::kw_while, tok::l_paren, tok::comma) ||
- Left->Previous->Type == TT_BinaryOperator)) {
+ Left->Previous->is(TT_BinaryOperator))) {
// static_assert, if and while usually contain expressions.
Contexts.back().IsExpression = true;
} else if (Line.InPPDirective &&
(!Left->Previous ||
- (Left->Previous->isNot(tok::identifier) &&
- Left->Previous->Type != TT_OverloadedOperator))) {
+ !Left->Previous->isOneOf(tok::identifier,
+ TT_OverloadedOperator))) {
Contexts.back().IsExpression = true;
} else if (Left->Previous && Left->Previous->is(tok::r_square) &&
Left->Previous->MatchingParen &&
- Left->Previous->MatchingParen->Type == TT_LambdaLSquare) {
+ Left->Previous->MatchingParen->is(TT_LambdaLSquare)) {
// This is a parameter list of a lambda expression.
Contexts.back().IsExpression = false;
} else if (Contexts[Contexts.size() - 2].CaretFound) {
@@ -137,7 +137,7 @@
Contexts.back().IsForEachMacro = true;
Contexts.back().IsExpression = false;
} else if (Left->Previous && Left->Previous->MatchingParen &&
- Left->Previous->MatchingParen->Type == TT_ObjCBlockLParen) {
+ Left->Previous->MatchingParen->is(TT_ObjCBlockLParen)) {
Contexts.back().IsExpression = false;
}
@@ -168,11 +168,11 @@
}
}
- if (CurrentToken->Previous->Type == TT_PointerOrReference &&
+ if (CurrentToken->Previous->is(TT_PointerOrReference) &&
CurrentToken->Previous->Previous->isOneOf(tok::l_paren,
tok::coloncolon))
MightBeFunctionType = true;
- if (CurrentToken->Previous->Type == TT_BinaryOperator)
+ if (CurrentToken->Previous->is(TT_BinaryOperator))
Contexts.back().IsExpression = true;
if (CurrentToken->is(tok::r_paren)) {
if (MightBeFunctionType && CurrentToken->Next &&
@@ -191,11 +191,11 @@
}
}
- if (Left->Type == TT_AttributeParen)
+ if (Left->is(TT_AttributeParen))
CurrentToken->Type = TT_AttributeParen;
- if (Left->Previous && Left->Previous->Type == TT_JavaAnnotation)
+ if (Left->Previous && Left->Previous->is(TT_JavaAnnotation))
CurrentToken->Type = TT_JavaAnnotation;
- if (Left->Previous && Left->Previous->Type == TT_LeadingJavaAnnotation)
+ if (Left->Previous && Left->Previous->is(TT_LeadingJavaAnnotation))
CurrentToken->Type = TT_LeadingJavaAnnotation;
if (!HasMultipleLines)
@@ -239,12 +239,13 @@
FormatToken *Left = CurrentToken->Previous;
FormatToken *Parent = Left->getPreviousNonComment();
bool StartsObjCMethodExpr =
- Contexts.back().CanBeExpression && Left->Type != TT_LambdaLSquare &&
+ Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
CurrentToken->isNot(tok::l_brace) &&
- (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
- tok::kw_return, tok::kw_throw) ||
- Parent->isUnaryOperator() || Parent->Type == TT_ObjCForIn ||
- Parent->Type == TT_CastRParen ||
+ (!Parent ||
+ Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
+ tok::kw_return, tok::kw_throw) ||
+ Parent->isUnaryOperator() ||
+ Parent->isOneOf(TT_ObjCForIn, TT_CastRParen) ||
getBinOpPrecedence(Parent->Tok.getKind(), true, true) > prec::Unknown);
ScopedContextCreator ContextCreator(*this, tok::l_square, 10);
Contexts.back().IsExpression = true;
@@ -255,14 +256,14 @@
Left->Type = TT_ObjCMethodExpr;
} else if (Parent && Parent->is(tok::at)) {
Left->Type = TT_ArrayInitializerLSquare;
- } else if (Left->Type == TT_Unknown) {
+ } else if (Left->is(TT_Unknown)) {
Left->Type = TT_ArraySubscriptLSquare;
}
while (CurrentToken) {
if (CurrentToken->is(tok::r_square)) {
if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) &&
- Left->Type == TT_ObjCMethodExpr) {
+ Left->is(TT_ObjCMethodExpr)) {
// An ObjC method call is rarely followed by an open parenthesis.
// FIXME: Do we incorrectly label ":" with this?
StartsObjCMethodExpr = false;
@@ -273,7 +274,7 @@
// determineStarAmpUsage() thinks that '*' '[' is allocating an
// array of pointers, but if '[' starts a selector then '*' is a
// binary operator.
- if (Parent && Parent->Type == TT_PointerOrReference)
+ if (Parent && Parent->is(TT_PointerOrReference))
Parent->Type = TT_BinaryOperator;
}
Left->MatchingParen = CurrentToken;
@@ -290,7 +291,7 @@
if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace))
return false;
if (CurrentToken->is(tok::colon)) {
- if (Left->Type == TT_ArraySubscriptLSquare) {
+ if (Left->is(TT_ArraySubscriptLSquare)) {
Left->Type = TT_ObjCMethodExpr;
StartsObjCMethodExpr = true;
Contexts.back().ColonIsObjCMethodExpr = true;
@@ -301,10 +302,10 @@
}
if (CurrentToken->is(tok::comma) &&
Style.Language != FormatStyle::LK_Proto &&
- (Left->Type == TT_ArraySubscriptLSquare ||
- (Left->Type == TT_ObjCMethodExpr && !ColonFound)))
+ (Left->is(TT_ArraySubscriptLSquare) ||
+ (Left->is(TT_ObjCMethodExpr) && !ColonFound)))
Left->Type = TT_ArrayInitializerLSquare;
- FormatToken* Tok = CurrentToken;
+ FormatToken *Tok = CurrentToken;
if (!consumeToken())
return false;
updateParameterCount(Left, Tok);
@@ -352,8 +353,8 @@
}
void updateParameterCount(FormatToken *Left, FormatToken *Current) {
- if (Current->Type == TT_LambdaLSquare ||
- (Current->is(tok::caret) && Current->Type == TT_UnaryOperator) ||
+ if (Current->is(TT_LambdaLSquare) ||
+ (Current->is(tok::caret) && Current->is(TT_UnaryOperator)) ||
(Style.Language == FormatStyle::LK_JavaScript &&
Current->is(Keywords.kw_function))) {
++Left->BlockParameterCount;
@@ -407,13 +408,10 @@
if (!Tok->Previous)
return false;
// Colons from ?: are handled in parseConditional().
- if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1 &&
- Line.First->isNot(tok::kw_case)) {
- Tok->Type = TT_CtorInitializerColon;
- } else if (Contexts.back().ColonIsDictLiteral) {
+ if (Contexts.back().ColonIsDictLiteral) {
Tok->Type = TT_DictLiteral;
} else if (Contexts.back().ColonIsObjCMethodExpr ||
- Line.First->Type == TT_ObjCMethodSpecifier) {
+ Line.First->is(TT_ObjCMethodSpecifier)) {
Tok->Type = TT_ObjCMethodExpr;
Tok->Previous->Type = TT_SelectorName;
if (Tok->Previous->ColumnWidth >
@@ -423,19 +421,28 @@
if (!Contexts.back().FirstObjCSelectorName)
Contexts.back().FirstObjCSelectorName = Tok->Previous;
} else if (Contexts.back().ColonIsForRangeExpr) {
- Tok->Type = TT_RangeBasedForLoopColon;
+ Tok->Type = Style.Language == FormatStyle::LK_JavaScript
+ ? TT_JsTypeColon
+ : TT_RangeBasedForLoopColon;
} else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) {
Tok->Type = TT_BitFieldColon;
} else if (Contexts.size() == 1 &&
!Line.First->isOneOf(tok::kw_enum, tok::kw_case)) {
- Tok->Type = TT_InheritanceColon;
+ if (Style.Language == FormatStyle::LK_JavaScript)
+ Tok->Type = TT_JsTypeColon;
+ else if (Tok->Previous->is(tok::r_paren))
+ Tok->Type = TT_CtorInitializerColon;
+ else
+ Tok->Type = TT_InheritanceColon;
} else if (Tok->Previous->is(tok::identifier) && Tok->Next &&
Tok->Next->isOneOf(tok::r_paren, tok::comma)) {
// This handles a special macro in ObjC code where selectors including
// the colon are passed as macro arguments.
Tok->Type = TT_ObjCMethodExpr;
} else if (Contexts.back().ContextKind == tok::l_paren) {
- Tok->Type = TT_InlineASMColon;
+ Tok->Type = Style.Language == FormatStyle::LK_JavaScript
+ ? TT_JsTypeColon
+ : TT_InlineASMColon;
}
break;
case tok::kw_if:
@@ -456,9 +463,9 @@
if (!parseParens())
return false;
if (Line.MustBeDeclaration && Contexts.size() == 1 &&
- !Contexts.back().IsExpression &&
- Line.First->Type != TT_ObjCProperty &&
- (!Tok->Previous || Tok->Previous->isNot(tok::kw_decltype)))
+ !Contexts.back().IsExpression && Line.First->isNot(TT_ObjCProperty) &&
+ (!Tok->Previous ||
+ !Tok->Previous->isOneOf(tok::kw_decltype, TT_LeadingJavaAnnotation)))
Line.MightBeFunctionDecl = true;
break;
case tok::l_square:
@@ -470,9 +477,12 @@
return false;
break;
case tok::less:
- if ((!Tok->Previous || !Tok->Previous->Tok.isLiteral()) && parseAngle())
+ if ((!Tok->Previous ||
+ (!Tok->Previous->Tok.isLiteral() &&
+ !(Tok->Previous->is(tok::r_paren) && Contexts.size() > 1))) &&
+ parseAngle()) {
Tok->Type = TT_TemplateOpener;
- else {
+ } else {
Tok->Type = TT_BinaryOperator;
CurrentToken = Tok;
next();
@@ -495,12 +505,12 @@
if (CurrentToken->isOneOf(tok::star, tok::amp))
CurrentToken->Type = TT_PointerOrReference;
consumeToken();
- if (CurrentToken && CurrentToken->Previous->Type == TT_BinaryOperator)
+ if (CurrentToken && CurrentToken->Previous->is(TT_BinaryOperator))
CurrentToken->Previous->Type = TT_OverloadedOperator;
}
if (CurrentToken) {
CurrentToken->Type = TT_OverloadedOperatorLParen;
- if (CurrentToken->Previous->Type == TT_BinaryOperator)
+ if (CurrentToken->Previous->is(TT_BinaryOperator))
CurrentToken->Previous->Type = TT_OverloadedOperator;
}
break;
@@ -511,7 +521,8 @@
parseTemplateDeclaration();
break;
case tok::identifier:
- if (Line.First->is(tok::kw_for) && Tok->is(Keywords.kw_in))
+ if (Line.First->is(tok::kw_for) && Tok->is(Keywords.kw_in) &&
+ Tok->Previous->isNot(tok::colon))
Tok->Type = TT_ObjCForIn;
break;
case tok::comma:
@@ -536,14 +547,6 @@
CurrentToken->Type = TT_ImplicitStringLiteral;
next();
}
- } else {
- while (CurrentToken) {
- if (CurrentToken->isNot(tok::comment))
- // Mark these tokens as "implicit" string literals, so that
- // they are not split or line-wrapped.
- CurrentToken->Type = TT_ImplicitStringLiteral;
- next();
- }
}
}
@@ -570,23 +573,25 @@
}
}
- void parsePreprocessorDirective() {
+ LineType parsePreprocessorDirective() {
+ LineType Type = LT_PreprocessorDirective;
next();
if (!CurrentToken)
- return;
+ return Type;
if (CurrentToken->Tok.is(tok::numeric_constant)) {
CurrentToken->SpacesRequiredBefore = 1;
- return;
+ return Type;
}
// Hashes in the middle of a line can lead to any strange token
// sequence.
if (!CurrentToken->Tok.getIdentifierInfo())
- return;
+ return Type;
switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
case tok::pp_import:
next();
parseIncludeDirective();
+ Type = LT_ImportStatement;
break;
case tok::pp_error:
case tok::pp_warning:
@@ -605,43 +610,53 @@
}
while (CurrentToken)
next();
+ return Type;
}
public:
LineType parseLine() {
if (CurrentToken->is(tok::hash)) {
- parsePreprocessorDirective();
- return LT_PreprocessorDirective;
+ return parsePreprocessorDirective();
}
// Directly allow to 'import <string-literal>' to support protocol buffer
// definitions (code.google.com/p/protobuf) or missing "#" (either way we
// should not break the line).
IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo();
- if (Info && Info->getPPKeywordID() == tok::pp_import &&
- CurrentToken->Next) {
+ if ((Style.Language == FormatStyle::LK_Java &&
+ CurrentToken->is(Keywords.kw_package)) ||
+ (Info && Info->getPPKeywordID() == tok::pp_import &&
+ CurrentToken->Next &&
+ CurrentToken->Next->isOneOf(tok::string_literal, tok::identifier,
+ tok::kw_static))) {
next();
parseIncludeDirective();
- return LT_Other;
+ return LT_ImportStatement;
}
// If this line starts and ends in '<' and '>', respectively, it is likely
// part of "#define <a/b.h>".
if (CurrentToken->is(tok::less) && Line.Last->is(tok::greater)) {
parseIncludeDirective();
- return LT_Other;
+ return LT_ImportStatement;
}
+ bool KeywordVirtualFound = false;
+ bool ImportStatement = false;
while (CurrentToken) {
if (CurrentToken->is(tok::kw_virtual))
KeywordVirtualFound = true;
+ if (IsImportStatement(*CurrentToken))
+ ImportStatement = true;
if (!consumeToken())
return LT_Invalid;
}
if (KeywordVirtualFound)
return LT_VirtualFunctionDecl;
+ if (ImportStatement)
+ return LT_ImportStatement;
- if (Line.First->Type == TT_ObjCMethodSpecifier) {
+ if (Line.First->is(TT_ObjCMethodSpecifier)) {
if (Contexts.back().FirstObjCSelectorName)
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
@@ -652,19 +667,29 @@
}
private:
+ bool IsImportStatement(const FormatToken &Tok) {
+ // FIXME: Closure-library specific stuff should not be hard-coded but be
+ // configurable.
+ return Style.Language == FormatStyle::LK_JavaScript &&
+ Tok.TokenText == "goog" && Tok.Next && Tok.Next->is(tok::period) &&
+ Tok.Next->Next && (Tok.Next->Next->TokenText == "module" ||
+ Tok.Next->Next->TokenText == "require" ||
+ Tok.Next->Next->TokenText == "provide") &&
+ Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren);
+ }
+
void resetTokenMetadata(FormatToken *Token) {
if (!Token)
return;
// Reset token type in case we have already looked at it and then
// recovered from an error (e.g. failure to find the matching >).
- if (CurrentToken->Type != TT_LambdaLSquare &&
- CurrentToken->Type != TT_FunctionLBrace &&
- CurrentToken->Type != TT_ImplicitStringLiteral &&
- CurrentToken->Type != TT_RegexLiteral &&
- CurrentToken->Type != TT_TrailingReturnArrow)
+ if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_FunctionLBrace,
+ TT_ImplicitStringLiteral, TT_RegexLiteral,
+ TT_TrailingReturnArrow))
CurrentToken->Type = TT_Unknown;
CurrentToken->Role.reset();
+ CurrentToken->MatchingParen = nullptr;
CurrentToken->FakeLParens.clear();
CurrentToken->FakeRParens = 0;
}
@@ -673,6 +698,7 @@
if (CurrentToken) {
CurrentToken->NestingLevel = Contexts.size() - 1;
CurrentToken->BindingStrength = Contexts.back().BindingStrength;
+ modifyContext(*CurrentToken);
determineTokenType(*CurrentToken);
CurrentToken = CurrentToken->Next;
}
@@ -725,28 +751,30 @@
~ScopedContextCreator() { P.Contexts.pop_back(); }
};
- void determineTokenType(FormatToken &Current) {
+ void modifyContext(const FormatToken &Current) {
if (Current.getPrecedence() == prec::Assignment &&
!Line.First->isOneOf(tok::kw_template, tok::kw_using) &&
(!Current.Previous || Current.Previous->isNot(tok::kw_operator))) {
Contexts.back().IsExpression = true;
- for (FormatToken *Previous = Current.Previous;
- Previous && !Previous->isOneOf(tok::comma, tok::semi);
- Previous = Previous->Previous) {
- if (Previous->isOneOf(tok::r_square, tok::r_paren)) {
- Previous = Previous->MatchingParen;
- if (!Previous)
- break;
- }
- if ((Previous->Type == TT_BinaryOperator ||
- Previous->Type == TT_UnaryOperator) &&
- Previous->isOneOf(tok::star, tok::amp) && Previous->Previous &&
- Previous->Previous->isNot(tok::equal)) {
- Previous->Type = TT_PointerOrReference;
+ if (!Line.First->is(TT_UnaryOperator)) {
+ for (FormatToken *Previous = Current.Previous;
+ Previous && !Previous->isOneOf(tok::comma, tok::semi);
+ Previous = Previous->Previous) {
+ if (Previous->isOneOf(tok::r_square, tok::r_paren)) {
+ Previous = Previous->MatchingParen;
+ if (!Previous)
+ break;
+ }
+ if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator) &&
+ Previous->isOneOf(tok::star, tok::amp, tok::ampamp) &&
+ Previous->Previous && Previous->Previous->isNot(tok::equal))
+ Previous->Type = TT_PointerOrReference;
}
}
} else if (Current.isOneOf(tok::kw_return, tok::kw_throw)) {
Contexts.back().IsExpression = true;
+ } else if (Current.is(TT_TrailingReturnArrow)) {
+ Contexts.back().IsExpression = false;
} else if (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
!Line.InPPDirective &&
(!Current.Previous ||
@@ -754,7 +782,7 @@
bool ParametersOfFunctionType =
Current.Previous && Current.Previous->is(tok::r_paren) &&
Current.Previous->MatchingParen &&
- Current.Previous->MatchingParen->Type == TT_FunctionTypeLParen;
+ Current.Previous->MatchingParen->is(TT_FunctionTypeLParen);
bool IsForOrCatch = Current.Previous &&
Current.Previous->isOneOf(tok::kw_for, tok::kw_catch);
Contexts.back().IsExpression = !ParametersOfFunctionType && !IsForOrCatch;
@@ -766,7 +794,7 @@
if (Line.MustBeDeclaration)
Contexts.back().IsExpression = Contexts.front().InCtorInitializer;
} else if (Current.Previous &&
- Current.Previous->Type == TT_CtorInitializerColon) {
+ Current.Previous->is(TT_CtorInitializerColon)) {
Contexts.back().IsExpression = true;
Contexts.back().InCtorInitializer = true;
} else if (Current.is(tok::kw_new)) {
@@ -775,81 +803,99 @@
// This should be the condition or increment in a for-loop.
Contexts.back().IsExpression = true;
}
+ }
- if (Current.Type == TT_Unknown) {
+ void determineTokenType(FormatToken &Current) {
+ if (!Current.is(TT_Unknown))
+ // The token type is already known.
+ return;
+
+ // Line.MightBeFunctionDecl can only be true after the parentheses of a
+ // function declaration have been found. In this case, 'Current' is a
+ // trailing token of this declaration and thus cannot be a name.
+ if (Current.is(Keywords.kw_instanceof)) {
+ Current.Type = TT_BinaryOperator;
+ } else if (isStartOfName(Current) &&
+ (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) {
+ Contexts.back().FirstStartOfName = &Current;
+ Current.Type = TT_StartOfName;
+ } else if (Current.is(tok::kw_auto)) {
+ AutoFound = true;
+ } else if (Current.is(tok::arrow) &&
+ Style.Language == FormatStyle::LK_Java) {
+ Current.Type = TT_LambdaArrow;
+ } else if (Current.is(tok::arrow) && AutoFound && Line.MustBeDeclaration &&
+ Current.NestingLevel == 0) {
+ Current.Type = TT_TrailingReturnArrow;
+ } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
+ Current.Type =
+ determineStarAmpUsage(Current, Contexts.back().CanBeExpression &&
+ Contexts.back().IsExpression,
+ Contexts.back().InTemplateArgument);
+ } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
+ Current.Type = determinePlusMinusCaretUsage(Current);
+ if (Current.is(TT_UnaryOperator) && Current.is(tok::caret))
+ Contexts.back().CaretFound = true;
+ } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
+ Current.Type = determineIncrementUsage(Current);
+ } else if (Current.isOneOf(tok::exclaim, tok::tilde)) {
+ Current.Type = TT_UnaryOperator;
+ } else if (Current.is(tok::question)) {
+ Current.Type = TT_ConditionalExpr;
+ } else if (Current.isBinaryOperator() &&
+ (!Current.Previous || Current.Previous->isNot(tok::l_square))) {
+ Current.Type = TT_BinaryOperator;
+ } else if (Current.is(tok::comment)) {
+ Current.Type =
+ Current.TokenText.startswith("/*") ? TT_BlockComment : TT_LineComment;
+ } else if (Current.is(tok::r_paren)) {
+ if (rParenEndsCast(Current))
+ Current.Type = TT_CastRParen;
+ } else if (Current.is(tok::at) && Current.Next) {
+ switch (Current.Next->Tok.getObjCKeywordID()) {
+ case tok::objc_interface:
+ case tok::objc_implementation:
+ case tok::objc_protocol:
+ Current.Type = TT_ObjCDecl;
+ break;
+ case tok::objc_property:
+ Current.Type = TT_ObjCProperty;
+ break;
+ default:
+ break;
+ }
+ } else if (Current.is(tok::period)) {
+ FormatToken *PreviousNoComment = Current.getPreviousNonComment();
+ if (PreviousNoComment &&
+ PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
+ Current.Type = TT_DesignatedInitializerPeriod;
+ else if (Style.Language == FormatStyle::LK_Java && Current.Previous &&
+ Current.Previous->isOneOf(TT_JavaAnnotation,
+ TT_LeadingJavaAnnotation)) {
+ Current.Type = Current.Previous->Type;
+ }
+ } else if (Current.isOneOf(tok::identifier, tok::kw_const) &&
+ Current.Previous &&
+ !Current.Previous->isOneOf(tok::equal, tok::at) &&
+ Line.MightBeFunctionDecl && Contexts.size() == 1) {
// Line.MightBeFunctionDecl can only be true after the parentheses of a
- // function declaration have been found. In this case, 'Current' is a
- // trailing token of this declaration and thus cannot be a name.
- if (isStartOfName(Current) &&
- (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) {
- Contexts.back().FirstStartOfName = &Current;
- Current.Type = TT_StartOfName;
- } else if (Current.is(tok::kw_auto)) {
- AutoFound = true;
- } else if (Current.is(tok::arrow) && AutoFound &&
- Line.MustBeDeclaration && Current.NestingLevel == 0) {
- Current.Type = TT_TrailingReturnArrow;
- } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
- Current.Type =
- determineStarAmpUsage(Current, Contexts.back().CanBeExpression &&
- Contexts.back().IsExpression,
- Contexts.back().InTemplateArgument);
- } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
- Current.Type = determinePlusMinusCaretUsage(Current);
- if (Current.Type == TT_UnaryOperator && Current.is(tok::caret))
- Contexts.back().CaretFound = true;
- } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
- Current.Type = determineIncrementUsage(Current);
- } else if (Current.isOneOf(tok::exclaim, tok::tilde)) {
- Current.Type = TT_UnaryOperator;
- } else if (Current.is(tok::question)) {
- Current.Type = TT_ConditionalExpr;
- } else if (Current.isBinaryOperator() &&
- (!Current.Previous ||
- Current.Previous->isNot(tok::l_square))) {
- Current.Type = TT_BinaryOperator;
- } else if (Current.is(tok::comment)) {
- if (Current.TokenText.startswith("//"))
- Current.Type = TT_LineComment;
- else
- Current.Type = TT_BlockComment;
- } else if (Current.is(tok::r_paren)) {
- if (rParenEndsCast(Current))
- Current.Type = TT_CastRParen;
- } else if (Current.is(tok::at) && Current.Next) {
- switch (Current.Next->Tok.getObjCKeywordID()) {
- case tok::objc_interface:
- case tok::objc_implementation:
- case tok::objc_protocol:
- Current.Type = TT_ObjCDecl;
- break;
- case tok::objc_property:
- Current.Type = TT_ObjCProperty;
- break;
- default:
- break;
- }
- } else if (Current.is(tok::period)) {
- FormatToken *PreviousNoComment = Current.getPreviousNonComment();
- if (PreviousNoComment &&
- PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
- Current.Type = TT_DesignatedInitializerPeriod;
- } else if (Current.isOneOf(tok::identifier, tok::kw_const) &&
- Current.Previous &&
- !Current.Previous->isOneOf(tok::equal, tok::at) &&
- Line.MightBeFunctionDecl && Contexts.size() == 1) {
- // Line.MightBeFunctionDecl can only be true after the parentheses of a
- // function declaration have been found.
- Current.Type = TT_TrailingAnnotation;
- } else if (Style.Language == FormatStyle::LK_Java && Current.Previous &&
- Current.Previous->is(tok::at) &&
- Current.isNot(Keywords.kw_interface)) {
- const FormatToken& AtToken = *Current.Previous;
- if (!AtToken.Previous ||
- AtToken.Previous->Type == TT_LeadingJavaAnnotation)
+ // function declaration have been found.
+ Current.Type = TT_TrailingAnnotation;
+ } else if ((Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript) &&
+ Current.Previous) {
+ if (Current.Previous->is(tok::at) &&
+ Current.isNot(Keywords.kw_interface)) {
+ const FormatToken &AtToken = *Current.Previous;
+ const FormatToken *Previous = AtToken.getPreviousNonComment();
+ if (!Previous || Previous->is(TT_LeadingJavaAnnotation))
Current.Type = TT_LeadingJavaAnnotation;
else
Current.Type = TT_JavaAnnotation;
+ } else if (Current.Previous->is(tok::period) &&
+ Current.Previous->isOneOf(TT_JavaAnnotation,
+ TT_LeadingJavaAnnotation)) {
+ Current.Type = Current.Previous->Type;
}
}
}
@@ -863,6 +909,9 @@
if (Tok.isNot(tok::identifier) || !Tok.Previous)
return false;
+ if (Tok.Previous->is(TT_LeadingJavaAnnotation))
+ return false;
+
// Skip "const" as it does not have an influence on whether this is a name.
FormatToken *PreviousNotConst = Tok.Previous;
while (PreviousNotConst && PreviousNotConst->is(tok::kw_const))
@@ -875,7 +924,7 @@
PreviousNotConst->Previous &&
PreviousNotConst->Previous->is(tok::hash);
- if (PreviousNotConst->Type == TT_TemplateCloser)
+ if (PreviousNotConst->is(TT_TemplateCloser))
return PreviousNotConst && PreviousNotConst->MatchingParen &&
PreviousNotConst->MatchingParen->Previous &&
PreviousNotConst->MatchingParen->Previous->isNot(tok::period) &&
@@ -887,7 +936,7 @@
return true;
return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) ||
- PreviousNotConst->Type == TT_PointerOrReference ||
+ PreviousNotConst->is(TT_PointerOrReference) ||
PreviousNotConst->isSimpleTypeSpecifier();
}
@@ -901,24 +950,29 @@
LeftOfParens = LeftOfParens->MatchingParen->Previous;
if (LeftOfParens && LeftOfParens->is(tok::r_square) &&
LeftOfParens->MatchingParen &&
- LeftOfParens->MatchingParen->Type == TT_LambdaLSquare)
+ LeftOfParens->MatchingParen->is(TT_LambdaLSquare))
return false;
+ if (Tok.Next) {
+ if (Tok.Next->is(tok::question))
+ return false;
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ Tok.Next->is(Keywords.kw_in))
+ return false;
+ if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren))
+ return true;
+ }
bool IsCast = false;
bool ParensAreEmpty = Tok.Previous == Tok.MatchingParen;
- bool ParensAreType = !Tok.Previous ||
- Tok.Previous->Type == TT_PointerOrReference ||
- Tok.Previous->Type == TT_TemplateCloser ||
- Tok.Previous->isSimpleTypeSpecifier();
- if (Style.Language == FormatStyle::LK_JavaScript && Tok.Next &&
- Tok.Next->is(Keywords.kw_in))
- return false;
+ bool ParensAreType =
+ !Tok.Previous ||
+ Tok.Previous->isOneOf(TT_PointerOrReference, TT_TemplateCloser) ||
+ Tok.Previous->isSimpleTypeSpecifier();
bool ParensCouldEndDecl =
Tok.Next && Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace);
bool IsSizeOfOrAlignOf =
LeftOfParens && LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof);
if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
- ((Contexts.size() > 1 && Contexts[Contexts.size() - 2].IsExpression) ||
- (Tok.Next && Tok.Next->isBinaryOperator())))
+ (Contexts.size() > 1 && Contexts[Contexts.size() - 2].IsExpression))
IsCast = true;
else if (Tok.Next && Tok.Next->isNot(tok::string_literal) &&
(Tok.Next->Tok.isLiteral() ||
@@ -926,12 +980,11 @@
IsCast = true;
// If there is an identifier after the (), it is likely a cast, unless
// there is also an identifier before the ().
- else if (LeftOfParens &&
+ else if (LeftOfParens && Tok.Next &&
(LeftOfParens->Tok.getIdentifierInfo() == nullptr ||
LeftOfParens->is(tok::kw_return)) &&
- LeftOfParens->Type != TT_OverloadedOperator &&
- LeftOfParens->isNot(tok::at) &&
- LeftOfParens->Type != TT_TemplateCloser && Tok.Next) {
+ !LeftOfParens->isOneOf(TT_OverloadedOperator, tok::at,
+ TT_TemplateCloser)) {
if (Tok.Next->isOneOf(tok::identifier, tok::numeric_constant)) {
IsCast = true;
} else {
@@ -970,7 +1023,8 @@
return TT_UnaryOperator;
const FormatToken *NextToken = Tok.getNextNonComment();
- if (!NextToken || NextToken->is(tok::l_brace))
+ if (!NextToken ||
+ (NextToken->is(tok::l_brace) && !NextToken->getNextNonComment()))
return TT_Unknown;
if (PrevToken->is(tok::coloncolon))
@@ -979,14 +1033,13 @@
if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace,
tok::comma, tok::semi, tok::kw_return, tok::colon,
tok::equal, tok::kw_delete, tok::kw_sizeof) ||
- PrevToken->Type == TT_BinaryOperator ||
- PrevToken->Type == TT_ConditionalExpr ||
- PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
+ PrevToken->isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
+ TT_UnaryOperator, TT_CastRParen))
return TT_UnaryOperator;
- if (NextToken->is(tok::l_square) && NextToken->Type != TT_LambdaLSquare)
+ if (NextToken->is(tok::l_square) && NextToken->isNot(TT_LambdaLSquare))
return TT_PointerOrReference;
- if (NextToken->isOneOf(tok::kw_operator, tok::comma))
+ if (NextToken->isOneOf(tok::kw_operator, tok::comma, tok::semi))
return TT_PointerOrReference;
if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen &&
@@ -1019,7 +1072,7 @@
// It is very unlikely that we are going to find a pointer or reference type
// definition on the RHS of an assignment.
- if (IsExpression)
+ if (IsExpression && !Contexts.back().CaretFound)
return TT_BinaryOperator;
return TT_PointerOrReference;
@@ -1027,7 +1080,7 @@
TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
- if (!PrevToken || PrevToken->Type == TT_CastRParen)
+ if (!PrevToken || PrevToken->is(TT_CastRParen))
return TT_UnaryOperator;
// Use heuristics to recognize unary operators.
@@ -1037,7 +1090,7 @@
return TT_UnaryOperator;
// There can't be two consecutive binary operators.
- if (PrevToken->Type == TT_BinaryOperator)
+ if (PrevToken->is(TT_BinaryOperator))
return TT_UnaryOperator;
// Fall back to marking the token as binary operator.
@@ -1047,7 +1100,7 @@
/// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
TokenType determineIncrementUsage(const FormatToken &Tok) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
- if (!PrevToken || PrevToken->Type == TT_CastRParen)
+ if (!PrevToken || PrevToken->is(TT_CastRParen))
return TT_UnaryOperator;
if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier))
return TT_TrailingUnaryOperator;
@@ -1060,7 +1113,6 @@
const FormatStyle &Style;
AnnotatedLine &Line;
FormatToken *CurrentToken;
- bool KeywordVirtualFound;
bool AutoFound;
const AdditionalKeywords &Keywords;
};
@@ -1080,10 +1132,9 @@
void parse(int Precedence = 0) {
// Skip 'return' and ObjC selector colons as they are not part of a binary
// expression.
- while (Current &&
- (Current->is(tok::kw_return) ||
- (Current->is(tok::colon) && (Current->Type == TT_ObjCMethodExpr ||
- Current->Type == TT_DictLiteral))))
+ while (Current && (Current->is(tok::kw_return) ||
+ (Current->is(tok::colon) &&
+ Current->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral))))
next();
if (!Current || Precedence > PrecedenceArrowAndPeriod)
@@ -1112,7 +1163,7 @@
int CurrentPrecedence = getCurrentPrecedence();
- if (Current && Current->Type == TT_SelectorName &&
+ if (Current && Current->is(TT_SelectorName) &&
Precedence == CurrentPrecedence) {
if (LatestOperator)
addFakeParenthesis(Start, prec::Level(Precedence));
@@ -1125,16 +1176,7 @@
(CurrentPrecedence != -1 && CurrentPrecedence < Precedence) ||
(CurrentPrecedence == prec::Conditional &&
Precedence == prec::Assignment && Current->is(tok::colon))) {
- if (LatestOperator) {
- LatestOperator->LastOperator = true;
- if (Precedence == PrecedenceArrowAndPeriod) {
- // Call expressions don't have a binary operator precedence.
- addFakeParenthesis(Start, prec::Unknown);
- } else {
- addFakeParenthesis(Start, prec::Level(Precedence));
- }
- }
- return;
+ break;
}
// Consume scopes: (), [], <> and {}
@@ -1154,6 +1196,16 @@
next(/*SkipPastLeadingComments=*/Precedence > 0);
}
}
+
+ if (LatestOperator && (Current || Precedence > 0)) {
+ LatestOperator->LastOperator = true;
+ if (Precedence == PrecedenceArrowAndPeriod) {
+ // Call expressions don't have a binary operator precedence.
+ addFakeParenthesis(Start, prec::Unknown);
+ } else {
+ addFakeParenthesis(Start, prec::Level(Precedence));
+ }
+ }
}
private:
@@ -1162,24 +1214,27 @@
int getCurrentPrecedence() {
if (Current) {
const FormatToken *NextNonComment = Current->getNextNonComment();
- if (Current->Type == TT_ConditionalExpr)
+ if (Current->is(TT_ConditionalExpr))
return prec::Conditional;
else if (NextNonComment && NextNonComment->is(tok::colon) &&
- NextNonComment->Type == TT_DictLiteral)
+ NextNonComment->is(TT_DictLiteral))
return prec::Comma;
- else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon ||
- Current->Type == TT_SelectorName ||
+ else if (Current->is(TT_LambdaArrow))
+ return prec::Comma;
+ else if (Current->isOneOf(tok::semi, TT_InlineASMColon,
+ TT_SelectorName) ||
(Current->is(tok::comment) && NextNonComment &&
- NextNonComment->Type == TT_SelectorName))
+ NextNonComment->is(TT_SelectorName)))
return 0;
- else if (Current->Type == TT_RangeBasedForLoopColon)
+ else if (Current->is(TT_RangeBasedForLoopColon))
return prec::Comma;
- else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma))
+ else if (Current->is(TT_BinaryOperator) || Current->is(tok::comma))
return Current->getPrecedence();
else if (Current->isOneOf(tok::period, tok::arrow))
return PrecedenceArrowAndPeriod;
else if (Style.Language == FormatStyle::LK_Java &&
- Current->isOneOf(Keywords.kw_extends, Keywords.kw_implements))
+ Current->isOneOf(Keywords.kw_extends, Keywords.kw_implements,
+ Keywords.kw_throws))
return 0;
}
return -1;
@@ -1191,7 +1246,7 @@
Start->StartsBinaryExpression = true;
if (Current) {
FormatToken *Previous = Current->Previous;
- if (Previous->is(tok::comment) && Previous->Previous)
+ while (Previous->is(tok::comment) && Previous->Previous)
Previous = Previous->Previous;
++Previous->FakeRParens;
if (Precedence > prec::Unknown)
@@ -1202,7 +1257,7 @@
/// \brief Parse unary operator expressions and surround them with fake
/// parentheses if appropriate.
void parseUnaryOperator() {
- if (!Current || Current->Type != TT_UnaryOperator) {
+ if (!Current || Current->isNot(TT_UnaryOperator)) {
parse(PrecedenceArrowAndPeriod);
return;
}
@@ -1225,7 +1280,7 @@
return;
next();
parse(prec::Assignment);
- if (!Current || Current->Type != TT_ConditionalExpr)
+ if (!Current || Current->isNot(TT_ConditionalExpr))
return;
next();
parse(prec::Assignment);
@@ -1248,8 +1303,8 @@
} // end anonymous namespace
-void
-TokenAnnotator::setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) {
+void TokenAnnotator::setCommentLineLevels(
+ SmallVectorImpl<AnnotatedLine *> &Lines) {
const AnnotatedLine *NextNonCommentLine = nullptr;
for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(),
E = Lines.rend();
@@ -1278,11 +1333,11 @@
ExpressionParser ExprParser(Style, Keywords, Line);
ExprParser.parse();
- if (Line.First->Type == TT_ObjCMethodSpecifier)
+ if (Line.First->is(TT_ObjCMethodSpecifier))
Line.Type = LT_ObjCMethodDecl;
- else if (Line.First->Type == TT_ObjCDecl)
+ else if (Line.First->is(TT_ObjCDecl))
Line.Type = LT_ObjCDecl;
- else if (Line.First->Type == TT_ObjCProperty)
+ else if (Line.First->is(TT_ObjCProperty))
Line.Type = LT_ObjCProperty;
Line.First->SpacesRequiredBefore = 1;
@@ -1292,12 +1347,11 @@
// This function heuristically determines whether 'Current' starts the name of a
// function declaration.
static bool isFunctionDeclarationName(const FormatToken &Current) {
- if (Current.Type != TT_StartOfName ||
- Current.NestingLevel != 0)
+ if (!Current.is(TT_StartOfName) || Current.NestingLevel != 0)
return false;
const FormatToken *Next = Current.Next;
for (; Next; Next = Next->Next) {
- if (Next->Type == TT_TemplateOpener) {
+ if (Next->is(TT_TemplateOpener)) {
Next = Next->MatchingParen;
} else if (Next->is(tok::coloncolon)) {
Next = Next->Next;
@@ -1314,10 +1368,10 @@
assert(Next->is(tok::l_paren));
if (Next->Next == Next->MatchingParen)
return true;
- for (const FormatToken *Tok = Next->Next; Tok != Next->MatchingParen;
+ for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen;
Tok = Tok->Next) {
if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() ||
- Tok->Type == TT_PointerOrReference || Tok->Type == TT_StartOfName)
+ Tok->isOneOf(TT_PointerOrReference, TT_StartOfName))
return true;
if (Tok->isOneOf(tok::l_brace, tok::string_literal) || Tok->Tok.isLiteral())
return false;
@@ -1341,7 +1395,7 @@
while (Current) {
if (isFunctionDeclarationName(*Current))
Current->Type = TT_FunctionDeclarationName;
- if (Current->Type == TT_LineComment) {
+ if (Current->is(TT_LineComment)) {
if (Current->Previous->BlockKind == BK_BracedInit &&
Current->Previous->opensScope())
Current->SpacesRequiredBefore = Style.Cpp11BracedListStyle ? 0 : 1;
@@ -1361,7 +1415,7 @@
if (Parameter->isOneOf(tok::comment, tok::r_brace))
break;
if (Parameter->Previous && Parameter->Previous->is(tok::comma)) {
- if (Parameter->Previous->Type != TT_CtorInitializerComma &&
+ if (!Parameter->Previous->is(TT_CtorInitializerComma) &&
Parameter->HasUnescapedNewline)
Parameter->MustBreakBefore = true;
break;
@@ -1376,9 +1430,9 @@
Current->MustBreakBefore =
Current->MustBreakBefore || mustBreakBefore(Line, *Current);
- if (Style.AlwaysBreakAfterDefinitionReturnType &&
- InFunctionDecl && Current->Type == TT_FunctionDeclarationName &&
- !Line.Last->isOneOf(tok::semi, tok::comment)) // Only for definitions.
+ if (Style.AlwaysBreakAfterDefinitionReturnType && InFunctionDecl &&
+ Current->is(TT_FunctionDeclarationName) &&
+ !Line.Last->isOneOf(tok::semi, tok::comment)) // Only for definitions.
// FIXME: Line.Last points to other characters than tok::semi
// and tok::lbrace.
Current->MustBreakBefore = true;
@@ -1391,7 +1445,7 @@
ChildSize = LastOfChild.isTrailingComment() ? Style.ColumnLimit
: LastOfChild.TotalLength + 1;
}
- const FormatToken *Prev= Current->Previous;
+ const FormatToken *Prev = Current->Previous;
if (Current->MustBreakBefore || Prev->Children.size() > 1 ||
(Prev->Children.size() == 1 &&
Prev->Children[0]->First->MustBreakBefore) ||
@@ -1401,7 +1455,7 @@
Current->TotalLength = Prev->TotalLength + Current->ColumnWidth +
ChildSize + Current->SpacesRequiredBefore;
- if (Current->Type == TT_CtorInitializerColon)
+ if (Current->is(TT_CtorInitializerColon))
InFunctionDecl = false;
// FIXME: Only calculate this if CanBreakBefore is true once static
@@ -1448,31 +1502,32 @@
return 0;
if (Style.Language == FormatStyle::LK_Java) {
- if (Left.Type == TT_LeadingJavaAnnotation)
- return 1;
- if (Right.is(Keywords.kw_extends))
+ if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_throws))
return 1;
if (Right.is(Keywords.kw_implements))
return 2;
if (Left.is(tok::comma) && Left.NestingLevel == 0)
return 3;
+ } else if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Right.is(Keywords.kw_function))
+ return 100;
}
if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next &&
- Right.Next->Type == TT_DictLiteral))
+ Right.Next->is(TT_DictLiteral)))
return 1;
if (Right.is(tok::l_square)) {
if (Style.Language == FormatStyle::LK_Proto)
return 1;
- if (Right.Type != TT_ObjCMethodExpr && Right.Type != TT_LambdaLSquare)
+ if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare))
return 500;
}
- if (Right.Type == TT_StartOfName ||
- Right.Type == TT_FunctionDeclarationName || Right.is(tok::kw_operator)) {
+ if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
+ Right.is(tok::kw_operator)) {
if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
return 3;
- if (Left.Type == TT_StartOfName)
+ if (Left.is(TT_StartOfName))
return 20;
if (InFunctionDecl && Right.NestingLevel == 0)
return Style.PenaltyReturnTypeOnItsOwnLine;
@@ -1480,7 +1535,7 @@
}
if (Left.is(tok::equal) && Right.is(tok::l_brace))
return 150;
- if (Left.Type == TT_CastRParen)
+ if (Left.is(TT_CastRParen))
return 100;
if (Left.is(tok::coloncolon) ||
(Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto))
@@ -1488,8 +1543,7 @@
if (Left.isOneOf(tok::kw_class, tok::kw_struct))
return 5000;
- if (Left.Type == TT_RangeBasedForLoopColon ||
- Left.Type == TT_InheritanceColon)
+ if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon))
return 2;
if (Right.isMemberAccess()) {
@@ -1499,11 +1553,11 @@
return 150;
}
- if (Right.Type == TT_TrailingAnnotation &&
+ if (Right.is(TT_TrailingAnnotation) &&
(!Right.Next || Right.Next->isNot(tok::l_paren))) {
// Moving trailing annotations to the next line is fine for ObjC method
// declarations.
- if (Line.First->Type == TT_ObjCMethodSpecifier)
+ if (Line.First->is(TT_ObjCMethodSpecifier))
return 10;
// Generally, breaking before a trailing annotation is bad unless it is
@@ -1521,18 +1575,20 @@
// In Objective-C method expressions, prefer breaking before "param:" over
// breaking after it.
- if (Right.Type == TT_SelectorName)
+ if (Right.is(TT_SelectorName))
return 0;
- if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
+ if (Left.is(tok::colon) && Left.is(TT_ObjCMethodExpr))
return Line.MightBeFunctionDecl ? 50 : 500;
if (Left.is(tok::l_paren) && InFunctionDecl && Style.AlignAfterOpenBracket)
return 100;
+ if (Left.is(tok::l_paren) && Left.Previous && Left.Previous->is(tok::kw_if))
+ return 1000;
if (Left.is(tok::equal) && InFunctionDecl)
return 110;
if (Right.is(tok::r_brace))
return 1;
- if (Left.Type == TT_TemplateOpener)
+ if (Left.is(TT_TemplateOpener))
return 100;
if (Left.opensScope()) {
if (!Style.AlignAfterOpenBracket)
@@ -1540,6 +1596,8 @@
return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter
: 19;
}
+ if (Left.is(TT_JavaAnnotation))
+ return 50;
if (Right.is(tok::lessless)) {
if (Left.is(tok::string_literal)) {
@@ -1555,7 +1613,7 @@
}
return 1; // Breaking at a << is really cheap.
}
- if (Left.Type == TT_ConditionalExpr)
+ if (Left.is(TT_ConditionalExpr))
return prec::Conditional;
prec::Level Level = Left.getPrecedence();
@@ -1580,8 +1638,8 @@
if (Left.is(tok::l_paren) && Right.is(tok::r_paren))
return Style.SpaceInEmptyParentheses;
if (Left.is(tok::l_paren) || Right.is(tok::r_paren))
- return (Right.Type == TT_CastRParen ||
- (Left.MatchingParen && Left.MatchingParen->Type == TT_CastRParen))
+ return (Right.is(TT_CastRParen) ||
+ (Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen)))
? Style.SpacesInCStyleCastParentheses
: Style.SpacesInParentheses;
if (Right.isOneOf(tok::semi, tok::comma))
@@ -1605,56 +1663,60 @@
return Left.Tok.isLiteral();
if (Left.is(tok::l_square) && Right.is(tok::amp))
return false;
- if (Right.Type == TT_PointerOrReference)
- return Left.Tok.isLiteral() ||
- ((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) &&
- Style.PointerAlignment != FormatStyle::PAS_Left);
- if (Right.Type == TT_FunctionTypeLParen && Left.isNot(tok::l_paren) &&
- (Left.Type != TT_PointerOrReference ||
+ if (Right.is(TT_PointerOrReference))
+ return !(Left.is(tok::r_paren) && Left.MatchingParen &&
+ (Left.MatchingParen->is(TT_OverloadedOperatorLParen) ||
+ (Left.MatchingParen->Previous &&
+ Left.MatchingParen->Previous->is(
+ TT_FunctionDeclarationName)))) &&
+ (Left.Tok.isLiteral() ||
+ (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) &&
+ Style.PointerAlignment != FormatStyle::PAS_Left));
+ if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) &&
+ (!Left.is(TT_PointerOrReference) ||
Style.PointerAlignment != FormatStyle::PAS_Right))
return true;
- if (Left.Type == TT_PointerOrReference)
- return Right.Tok.isLiteral() || Right.Type == TT_BlockComment ||
- ((Right.Type != TT_PointerOrReference) &&
- Right.isNot(tok::l_paren) &&
+ if (Left.is(TT_PointerOrReference))
+ return Right.Tok.isLiteral() || Right.is(TT_BlockComment) ||
+ (!Right.isOneOf(TT_PointerOrReference, tok::l_paren) &&
Style.PointerAlignment != FormatStyle::PAS_Right && Left.Previous &&
!Left.Previous->isOneOf(tok::l_paren, tok::coloncolon));
if (Right.is(tok::star) && Left.is(tok::l_paren))
return false;
if (Left.is(tok::l_square))
- return (Left.Type == TT_ArrayInitializerLSquare &&
+ return (Left.is(TT_ArrayInitializerLSquare) &&
Style.SpacesInContainerLiterals && Right.isNot(tok::r_square)) ||
- (Left.Type == TT_ArraySubscriptLSquare &&
- Style.SpacesInSquareBrackets && Right.isNot(tok::r_square));
+ (Left.is(TT_ArraySubscriptLSquare) && Style.SpacesInSquareBrackets &&
+ Right.isNot(tok::r_square));
if (Right.is(tok::r_square))
return Right.MatchingParen &&
((Style.SpacesInContainerLiterals &&
- Right.MatchingParen->Type == TT_ArrayInitializerLSquare) ||
+ Right.MatchingParen->is(TT_ArrayInitializerLSquare)) ||
(Style.SpacesInSquareBrackets &&
- Right.MatchingParen->Type == TT_ArraySubscriptLSquare));
- if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr &&
- Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant) &&
- Left.Type != TT_DictLiteral)
+ Right.MatchingParen->is(TT_ArraySubscriptLSquare)));
+ if (Right.is(tok::l_square) &&
+ !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare) &&
+ !Left.isOneOf(tok::numeric_constant, TT_DictLiteral))
return false;
if (Left.is(tok::colon))
- return Left.Type != TT_ObjCMethodExpr;
+ return !Left.is(TT_ObjCMethodExpr);
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
return !Left.Children.empty(); // No spaces in "{}".
if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) ||
(Right.is(tok::r_brace) && Right.MatchingParen &&
Right.MatchingParen->BlockKind != BK_Block))
return !Style.Cpp11BracedListStyle;
- if (Left.Type == TT_BlockComment)
+ if (Left.is(TT_BlockComment))
return !Left.TokenText.endswith("=*/");
if (Right.is(tok::l_paren)) {
- if (Left.is(tok::r_paren) && Left.Type == TT_AttributeParen)
+ if (Left.is(tok::r_paren) && Left.is(TT_AttributeParen))
return true;
- return Line.Type == LT_ObjCDecl ||
- Left.isOneOf(tok::kw_new, tok::kw_delete, tok::semi) ||
+ return Line.Type == LT_ObjCDecl || Left.is(tok::semi) ||
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
(Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while,
tok::kw_switch, tok::kw_case) ||
- (Left.is(tok::kw_catch) &&
+ (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch,
+ tok::kw_new, tok::kw_delete) &&
(!Left.Previous || Left.Previous->isNot(tok::period))) ||
Left.IsForEachMacro)) ||
(Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&
@@ -1663,9 +1725,9 @@
}
if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword)
return false;
- if (Right.Type == TT_UnaryOperator)
+ if (Right.is(TT_UnaryOperator))
return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) &&
- (Left.isNot(tok::colon) || Left.Type != TT_ObjCMethodExpr);
+ (Left.isNot(tok::colon) || Left.isNot(TT_ObjCMethodExpr));
if ((Left.isOneOf(tok::identifier, tok::greater, tok::r_square,
tok::r_paren) ||
Left.isSimpleTypeSpecifier()) &&
@@ -1676,12 +1738,12 @@
return false;
if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L")
return false;
- if (Left.Type == TT_TemplateCloser && Left.MatchingParen &&
+ if (Left.is(TT_TemplateCloser) && Left.MatchingParen &&
Left.MatchingParen->Previous &&
Left.MatchingParen->Previous->is(tok::period))
// A.<B>DoSomething();
return false;
- if (Left.Type == TT_TemplateCloser && Right.is(tok::l_square))
+ if (Left.is(TT_TemplateCloser) && Right.is(tok::l_square))
return false;
return true;
}
@@ -1700,20 +1762,31 @@
} else if (Style.Language == FormatStyle::LK_JavaScript) {
if (Left.is(Keywords.kw_var))
return true;
+ if (Right.is(TT_JsTypeColon))
+ return false;
+ if ((Left.is(tok::l_brace) || Right.is(tok::r_brace)) &&
+ Line.First->isOneOf(Keywords.kw_import, tok::kw_export))
+ return false;
} else if (Style.Language == FormatStyle::LK_Java) {
+ if (Left.is(tok::r_square) && Right.is(tok::l_brace))
+ return true;
+ if (Left.is(TT_LambdaArrow) || Right.is(TT_LambdaArrow))
+ return true;
if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren))
return Style.SpaceBeforeParens != FormatStyle::SBPO_Never;
- if (Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private,
- tok::kw_protected) &&
- Right.Type == TT_TemplateOpener)
+ if ((Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private,
+ tok::kw_protected) ||
+ Left.isOneOf(Keywords.kw_final, Keywords.kw_abstract,
+ Keywords.kw_native)) &&
+ Right.is(TT_TemplateOpener))
return true;
}
if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo())
return true; // Never ever merge two identifiers.
- if (Left.Type == TT_ImplicitStringLiteral)
+ if (Left.is(TT_ImplicitStringLiteral))
return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
if (Line.Type == LT_ObjCMethodDecl) {
- if (Left.Type == TT_ObjCMethodSpecifier)
+ if (Left.is(TT_ObjCMethodSpecifier))
return true;
if (Left.is(tok::r_paren) && Right.is(tok::identifier))
// Don't space between ')' and <id>
@@ -1723,31 +1796,30 @@
(Right.is(tok::equal) || Left.is(tok::equal)))
return false;
- if (Right.Type == TT_TrailingReturnArrow ||
- Left.Type == TT_TrailingReturnArrow)
+ if (Right.is(TT_TrailingReturnArrow) || Left.is(TT_TrailingReturnArrow))
return true;
if (Left.is(tok::comma))
return true;
if (Right.is(tok::comma))
return false;
- if (Right.Type == TT_CtorInitializerColon || Right.Type == TT_ObjCBlockLParen)
+ if (Right.isOneOf(TT_CtorInitializerColon, TT_ObjCBlockLParen))
return true;
if (Left.is(tok::kw_operator))
return Right.is(tok::coloncolon);
- if (Right.Type == TT_OverloadedOperatorLParen)
+ if (Right.is(TT_OverloadedOperatorLParen))
return false;
if (Right.is(tok::colon))
return !Line.First->isOneOf(tok::kw_case, tok::kw_default) &&
- Right.getNextNonComment() && Right.Type != TT_ObjCMethodExpr &&
+ Right.getNextNonComment() && Right.isNot(TT_ObjCMethodExpr) &&
!Left.is(tok::question) &&
- !(Right.Type == TT_InlineASMColon && Left.is(tok::coloncolon)) &&
- (Right.Type != TT_DictLiteral || Style.SpacesInContainerLiterals);
- if (Left.Type == TT_UnaryOperator)
- return Right.Type == TT_BinaryOperator;
- if (Left.Type == TT_CastRParen)
- return Style.SpaceAfterCStyleCast || Right.Type == TT_BinaryOperator;
+ !(Right.is(TT_InlineASMColon) && Left.is(tok::coloncolon)) &&
+ (Right.isNot(TT_DictLiteral) || Style.SpacesInContainerLiterals);
+ if (Left.is(TT_UnaryOperator))
+ return Right.is(TT_BinaryOperator);
+ if (Left.is(TT_CastRParen))
+ return Style.SpaceAfterCStyleCast || Right.is(TT_BinaryOperator);
if (Left.is(tok::greater) && Right.is(tok::greater)) {
- return Right.Type == TT_TemplateCloser && Left.Type == TT_TemplateCloser &&
+ return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) &&
(Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles);
}
if (Right.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
@@ -1757,27 +1829,27 @@
Right.getPrecedence() == prec::Assignment)
return false;
if (Right.is(tok::coloncolon) && Left.isNot(tok::l_brace))
- return (Left.Type == TT_TemplateOpener &&
+ return (Left.is(TT_TemplateOpener) &&
Style.Standard == FormatStyle::LS_Cpp03) ||
!(Left.isOneOf(tok::identifier, tok::l_paren, tok::r_paren) ||
- Left.Type == TT_TemplateCloser || Left.Type == TT_TemplateOpener);
- if ((Left.Type == TT_TemplateOpener) != (Right.Type == TT_TemplateCloser))
+ Left.isOneOf(TT_TemplateCloser, TT_TemplateOpener));
+ if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser)))
return Style.SpacesInAngles;
- if ((Right.Type == TT_BinaryOperator && !Left.is(tok::l_paren)) ||
- Left.Type == TT_BinaryOperator || Left.Type == TT_ConditionalExpr)
+ if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) ||
+ Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr))
return true;
- if (Left.Type == TT_TemplateCloser && Right.is(tok::l_paren))
+ if (Left.is(TT_TemplateCloser) && Right.is(tok::l_paren) &&
+ Right.isNot(TT_FunctionTypeLParen))
return Style.SpaceBeforeParens == FormatStyle::SBPO_Always;
- if (Right.Type == TT_TemplateOpener && Left.is(tok::r_paren) &&
- Left.MatchingParen &&
- Left.MatchingParen->Type == TT_OverloadedOperatorLParen)
+ if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) &&
+ Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen))
return false;
if (Right.is(tok::less) && Left.isNot(tok::l_paren) &&
Line.First->is(tok::hash))
return true;
- if (Right.Type == TT_TrailingUnaryOperator)
+ if (Right.is(TT_TrailingUnaryOperator))
return false;
- if (Left.Type == TT_RegexLiteral)
+ if (Left.is(TT_RegexLiteral))
return false;
return spaceRequiredBetween(Line, Left, Right);
}
@@ -1785,7 +1857,7 @@
// Returns 'true' if 'Tok' is a brace we'd want to break before in Allman style.
static bool isAllmanBrace(const FormatToken &Tok) {
return Tok.is(tok::l_brace) && Tok.BlockKind == BK_Block &&
- Tok.Type != TT_ObjCBlockLBrace && Tok.Type != TT_DictLiteral;
+ !Tok.isOneOf(TT_ObjCBlockLBrace, TT_DictLiteral);
}
bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
@@ -1806,66 +1878,68 @@
BeforeClosingBrace->isTrailingComment()))
return true;
- if (Right.is(tok::comment)) {
+ if (Right.is(tok::comment))
return Left.BlockKind != BK_BracedInit &&
- Left.Type != TT_CtorInitializerColon &&
+ Left.isNot(TT_CtorInitializerColon) &&
(Right.NewlinesBefore > 0 && Right.HasUnescapedNewline);
- } else if (Right.Previous->isTrailingComment() ||
- (Right.isStringLiteral() && Right.Previous->isStringLiteral())) {
+ if (Right.Previous->isTrailingComment() ||
+ (Right.isStringLiteral() && Right.Previous->isStringLiteral()))
return true;
- } else if (Right.Previous->IsUnterminatedLiteral) {
+ if (Right.Previous->IsUnterminatedLiteral)
return true;
- } else if (Right.is(tok::lessless) && Right.Next &&
- Right.Previous->is(tok::string_literal) &&
- Right.Next->is(tok::string_literal)) {
+ if (Right.is(tok::lessless) && Right.Next &&
+ Right.Previous->is(tok::string_literal) &&
+ Right.Next->is(tok::string_literal))
return true;
- } else if (Right.Previous->ClosesTemplateDeclaration &&
- Right.Previous->MatchingParen &&
- Right.Previous->MatchingParen->NestingLevel == 0 &&
- Style.AlwaysBreakTemplateDeclarations) {
+ if (Right.Previous->ClosesTemplateDeclaration &&
+ Right.Previous->MatchingParen &&
+ Right.Previous->MatchingParen->NestingLevel == 0 &&
+ Style.AlwaysBreakTemplateDeclarations)
return true;
- } else if ((Right.Type == TT_CtorInitializerComma ||
- Right.Type == TT_CtorInitializerColon) &&
- Style.BreakConstructorInitializersBeforeComma &&
- !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) {
+ if ((Right.isOneOf(TT_CtorInitializerComma, TT_CtorInitializerColon)) &&
+ Style.BreakConstructorInitializersBeforeComma &&
+ !Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
return true;
- } else if (Right.is(tok::string_literal) &&
- Right.TokenText.startswith("R\"")) {
+ if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\""))
// Raw string literals are special wrt. line breaks. The author has made a
// deliberate choice and might have aligned the contents of the string
// literal accordingly. Thus, we try keep existing line breaks.
return Right.NewlinesBefore > 0;
- } else if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
- Style.Language == FormatStyle::LK_Proto) {
+ if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
+ Style.Language == FormatStyle::LK_Proto)
// Don't put enums onto single lines in protocol buffers.
return true;
- } else if (Style.Language == FormatStyle::LK_JavaScript &&
- Right.is(tok::r_brace) && Left.is(tok::l_brace) &&
- !Left.Children.empty()) {
+ if (Style.Language == FormatStyle::LK_JavaScript && Right.is(tok::r_brace) &&
+ Left.is(tok::l_brace) && !Left.Children.empty())
// Support AllowShortFunctionsOnASingleLine for JavaScript.
return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None ||
(Left.NestingLevel == 0 && Line.Level == 0 &&
Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline);
- } else if (isAllmanBrace(Left) || isAllmanBrace(Right)) {
+ if (isAllmanBrace(Left) || isAllmanBrace(Right))
return Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
Style.BreakBeforeBraces == FormatStyle::BS_GNU;
- } else if (Style.Language == FormatStyle::LK_Proto &&
- Left.isNot(tok::l_brace) && Right.Type == TT_SelectorName) {
+ if (Style.Language == FormatStyle::LK_Proto && Left.isNot(tok::l_brace) &&
+ Right.is(TT_SelectorName))
return true;
- } else if (Left.Type == TT_ObjCBlockLBrace &&
- !Style.AllowShortBlocksOnASingleLine) {
+ if (Left.is(TT_ObjCBlockLBrace) && !Style.AllowShortBlocksOnASingleLine)
return true;
- }
+
+ if ((Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript) &&
+ Left.is(TT_LeadingJavaAnnotation) &&
+ Right.isNot(TT_LeadingJavaAnnotation) && Right.isNot(tok::l_paren) &&
+ Line.Last->is(tok::l_brace))
+ return true;
if (Style.Language == FormatStyle::LK_JavaScript) {
// FIXME: This might apply to other languages and token kinds.
if (Right.is(tok::char_constant) && Left.is(tok::plus) && Left.Previous &&
Left.Previous->is(tok::char_constant))
return true;
- } else if (Style.Language == FormatStyle::LK_Java) {
- if (Left.Type == TT_LeadingJavaAnnotation && Right.isNot(tok::l_paren) &&
- Line.Last->is(tok::l_brace))
+ if (Left.is(TT_DictLiteral) && Left.is(tok::l_brace) &&
+ Left.NestingLevel == 0)
return true;
+ } else if (Style.Language == FormatStyle::LK_Java) {
if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next &&
Right.Next->is(tok::string_literal))
return true;
@@ -1891,10 +1965,10 @@
return false;
if (Left.Tok.getObjCKeywordID() == tok::objc_interface)
return false;
- if (Left.Type == TT_JavaAnnotation || Left.Type == TT_LeadingJavaAnnotation)
- return true;
- if (Right.Type == TT_StartOfName ||
- Right.Type == TT_FunctionDeclarationName || Right.is(tok::kw_operator))
+ if (Left.isOneOf(TT_JavaAnnotation, TT_LeadingJavaAnnotation))
+ return !Right.is(tok::l_paren);
+ if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
+ Right.is(tok::kw_operator))
return true;
if (Right.isTrailingComment())
// We rely on MustBreakBefore being set correctly here as we should not
@@ -1905,47 +1979,45 @@
return Left.BlockKind == BK_BracedInit;
if (Left.is(tok::question) && Right.is(tok::colon))
return false;
- if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
+ if (Right.is(TT_ConditionalExpr) || Right.is(tok::question))
return Style.BreakBeforeTernaryOperators;
- if (Left.Type == TT_ConditionalExpr || Left.is(tok::question))
+ if (Left.is(TT_ConditionalExpr) || Left.is(tok::question))
return !Style.BreakBeforeTernaryOperators;
- if (Right.Type == TT_InheritanceColon)
+ if (Right.is(TT_InheritanceColon))
return true;
- if (Right.is(tok::colon) && (Right.Type != TT_CtorInitializerColon &&
- Right.Type != TT_InlineASMColon))
+ if (Right.is(tok::colon) &&
+ !Right.isOneOf(TT_CtorInitializerColon, TT_InlineASMColon))
return false;
- if (Left.is(tok::colon) &&
- (Left.Type == TT_DictLiteral || Left.Type == TT_ObjCMethodExpr))
+ if (Left.is(tok::colon) && (Left.isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)))
return true;
- if (Right.Type == TT_SelectorName)
+ if (Right.is(TT_SelectorName))
return true;
if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty)
return true;
if (Left.ClosesTemplateDeclaration)
return true;
- if (Right.Type == TT_RangeBasedForLoopColon ||
- Right.Type == TT_OverloadedOperatorLParen ||
- Right.Type == TT_OverloadedOperator)
+ if (Right.isOneOf(TT_RangeBasedForLoopColon, TT_OverloadedOperatorLParen,
+ TT_OverloadedOperator))
return false;
- if (Left.Type == TT_RangeBasedForLoopColon)
+ if (Left.is(TT_RangeBasedForLoopColon))
return true;
- if (Right.Type == TT_RangeBasedForLoopColon)
+ if (Right.is(TT_RangeBasedForLoopColon))
return false;
- if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
- Left.Type == TT_UnaryOperator || Left.is(tok::kw_operator))
+ if (Left.isOneOf(TT_PointerOrReference, TT_TemplateCloser,
+ TT_UnaryOperator) ||
+ Left.is(tok::kw_operator))
return false;
if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
return false;
- if (Left.is(tok::l_paren) && Left.Type == TT_AttributeParen)
+ if (Left.is(tok::l_paren) && Left.is(TT_AttributeParen))
return false;
if (Left.is(tok::l_paren) && Left.Previous &&
- (Left.Previous->Type == TT_BinaryOperator ||
- Left.Previous->Type == TT_CastRParen || Left.Previous->is(tok::kw_if)))
+ (Left.Previous->isOneOf(TT_BinaryOperator, TT_CastRParen)))
return false;
- if (Right.Type == TT_ImplicitStringLiteral)
+ if (Right.is(TT_ImplicitStringLiteral))
return false;
- if (Right.is(tok::r_paren) || Right.Type == TT_TemplateCloser)
+ if (Right.is(tok::r_paren) || Right.is(TT_TemplateCloser))
return false;
// We only break before r_brace if there was a corresponding break before
@@ -1955,7 +2027,7 @@
// Allow breaking after a trailing annotation, e.g. after a method
// declaration.
- if (Left.Type == TT_TrailingAnnotation)
+ if (Left.is(TT_TrailingAnnotation))
return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal, tok::l_paren,
tok::less, tok::coloncolon);
@@ -1965,25 +2037,24 @@
if (Left.is(tok::identifier) && Right.is(tok::string_literal))
return true;
- if (Right.is(tok::identifier) && Right.Next &&
- Right.Next->Type == TT_DictLiteral)
+ if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
return true;
- if (Left.Type == TT_CtorInitializerComma &&
+ if (Left.is(TT_CtorInitializerComma) &&
Style.BreakConstructorInitializersBeforeComma)
return false;
- if (Right.Type == TT_CtorInitializerComma &&
+ if (Right.is(TT_CtorInitializerComma) &&
Style.BreakConstructorInitializersBeforeComma)
return true;
- if (Left.is(tok::greater) && Right.is(tok::greater) &&
- Left.Type != TT_TemplateCloser)
+ if ((Left.is(tok::greater) && Right.is(tok::greater)) ||
+ (Left.is(tok::less) && Right.is(tok::less)))
return false;
- if (Right.Type == TT_BinaryOperator &&
+ if (Right.is(TT_BinaryOperator) &&
Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None &&
(Style.BreakBeforeBinaryOperators == FormatStyle::BOS_All ||
Right.getPrecedence() != prec::Assignment))
return true;
- if (Left.Type == TT_ArrayInitializerLSquare)
+ if (Left.is(TT_ArrayInitializerLSquare))
return true;
if (Right.is(tok::kw_typename) && Left.isNot(tok::kw_const))
return true;
@@ -1994,7 +2065,7 @@
return true;
return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
tok::kw_class, tok::kw_struct) ||
- Right.isMemberAccess() || Right.Type == TT_TrailingReturnArrow ||
+ Right.isMemberAccess() || Right.is(TT_TrailingReturnArrow) ||
Right.isOneOf(tok::lessless, tok::colon, tok::l_square, tok::at) ||
(Left.is(tok::r_paren) &&
Right.isOneOf(tok::identifier, tok::kw_const)) ||
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index fc4d1d6..94ed1d1 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -27,12 +27,13 @@
enum LineType {
LT_Invalid,
- LT_Other,
- LT_PreprocessorDirective,
- LT_VirtualFunctionDecl,
+ LT_ImportStatement,
LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
LT_ObjCMethodDecl,
- LT_ObjCProperty // An @property line.
+ LT_ObjCProperty, // An @property line.
+ LT_Other,
+ LT_PreprocessorDirective,
+ LT_VirtualFunctionDecl
};
class AnnotatedLine {
@@ -58,11 +59,8 @@
I->Tok->Previous = Current;
Current = Current->Next;
Current->Children.clear();
- for (SmallVectorImpl<UnwrappedLine>::const_iterator
- I = Node.Children.begin(),
- E = Node.Children.end();
- I != E; ++I) {
- Children.push_back(new AnnotatedLine(*I));
+ for (const auto& Child : Node.Children) {
+ Children.push_back(new AnnotatedLine(Child));
Current->Children.push_back(Children.back());
}
}
@@ -74,6 +72,12 @@
for (unsigned i = 0, e = Children.size(); i != e; ++i) {
delete Children[i];
}
+ FormatToken *Current = First;
+ while (Current) {
+ Current->Children.clear();
+ Current->Role.reset();
+ Current = Current->Next;
+ }
}
FormatToken *First;
@@ -100,8 +104,8 @@
private:
// Disallow copying.
- AnnotatedLine(const AnnotatedLine &) LLVM_DELETED_FUNCTION;
- void operator=(const AnnotatedLine &) LLVM_DELETED_FUNCTION;
+ AnnotatedLine(const AnnotatedLine &) = delete;
+ void operator=(const AnnotatedLine &) = delete;
};
/// \brief Determines extra information about the tokens comprising an
diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
new file mode 100644
index 0000000..8e6809f
--- /dev/null
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -0,0 +1,722 @@
+//===--- UnwrappedLineFormatter.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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnwrappedLineFormatter.h"
+#include "WhitespaceManager.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "format-formatter"
+
+namespace clang {
+namespace format {
+
+namespace {
+
+bool startsExternCBlock(const AnnotatedLine &Line) {
+ const FormatToken *Next = Line.First->getNextNonComment();
+ const FormatToken *NextNext = Next ? Next->getNextNonComment() : nullptr;
+ return Line.First->is(tok::kw_extern) && Next && Next->isStringLiteral() &&
+ NextNext && NextNext->is(tok::l_brace);
+}
+
+class LineJoiner {
+public:
+ LineJoiner(const FormatStyle &Style, const AdditionalKeywords &Keywords)
+ : Style(Style), Keywords(Keywords) {}
+
+ /// \brief Calculates how many lines can be merged into 1 starting at \p I.
+ unsigned
+ tryFitMultipleLinesInOne(unsigned Indent,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
+ // We can never merge stuff if there are trailing line comments.
+ const AnnotatedLine *TheLine = *I;
+ if (TheLine->Last->is(TT_LineComment))
+ return 0;
+
+ if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
+ return 0;
+
+ unsigned Limit =
+ Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent;
+ // If we already exceed the column limit, we set 'Limit' to 0. The different
+ // tryMerge..() functions can then decide whether to still do merging.
+ Limit = TheLine->Last->TotalLength > Limit
+ ? 0
+ : Limit - TheLine->Last->TotalLength;
+
+ if (I + 1 == E || I[1]->Type == LT_Invalid || I[1]->First->MustBreakBefore)
+ return 0;
+
+ // FIXME: TheLine->Level != 0 might or might not be the right check to do.
+ // If necessary, change to something smarter.
+ bool MergeShortFunctions =
+ Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
+ (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty &&
+ I[1]->First->is(tok::r_brace)) ||
+ (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
+ TheLine->Level != 0);
+
+ if (TheLine->Last->is(TT_FunctionLBrace) &&
+ TheLine->First != TheLine->Last) {
+ return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
+ }
+ if (TheLine->Last->is(tok::l_brace)) {
+ return Style.BreakBeforeBraces == FormatStyle::BS_Attach
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+ }
+ if (I[1]->First->is(TT_FunctionLBrace) &&
+ Style.BreakBeforeBraces != FormatStyle::BS_Attach) {
+ if (I[1]->Last->is(TT_LineComment))
+ return 0;
+
+ // Check for Limit <= 2 to account for the " {".
+ if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))
+ return 0;
+ Limit -= 2;
+
+ unsigned MergedLines = 0;
+ if (MergeShortFunctions) {
+ MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
+ // If we managed to merge the block, count the function header, which is
+ // on a separate line.
+ if (MergedLines > 0)
+ ++MergedLines;
+ }
+ return MergedLines;
+ }
+ if (TheLine->First->is(tok::kw_if)) {
+ return Style.AllowShortIfStatementsOnASingleLine
+ ? tryMergeSimpleControlStatement(I, E, Limit)
+ : 0;
+ }
+ if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
+ return Style.AllowShortLoopsOnASingleLine
+ ? tryMergeSimpleControlStatement(I, E, Limit)
+ : 0;
+ }
+ if (TheLine->First->isOneOf(tok::kw_case, tok::kw_default)) {
+ return Style.AllowShortCaseLabelsOnASingleLine
+ ? tryMergeShortCaseLabels(I, E, Limit)
+ : 0;
+ }
+ if (TheLine->InPPDirective &&
+ (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {
+ return tryMergeSimplePPDirective(I, E, Limit);
+ }
+ return 0;
+ }
+
+private:
+ unsigned
+ tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ if (Limit == 0)
+ return 0;
+ if (!I[1]->InPPDirective || I[1]->First->HasUnescapedNewline)
+ return 0;
+ if (I + 2 != E && I[2]->InPPDirective && !I[2]->First->HasUnescapedNewline)
+ return 0;
+ if (1 + I[1]->Last->TotalLength > Limit)
+ return 0;
+ return 1;
+ }
+
+ unsigned tryMergeSimpleControlStatement(
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
+ if (Limit == 0)
+ return 0;
+ if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&
+ (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))
+ return 0;
+ if (I[1]->InPPDirective != (*I)->InPPDirective ||
+ (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
+ return 0;
+ Limit = limitConsideringMacros(I + 1, E, Limit);
+ AnnotatedLine &Line = **I;
+ if (Line.Last->isNot(tok::r_paren))
+ return 0;
+ if (1 + I[1]->Last->TotalLength > Limit)
+ return 0;
+ if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,
+ tok::kw_while, TT_LineComment))
+ return 0;
+ // Only inline simple if's (no nested if or else).
+ if (I + 2 != E && Line.First->is(tok::kw_if) &&
+ I[2]->First->is(tok::kw_else))
+ return 0;
+ return 1;
+ }
+
+ unsigned tryMergeShortCaseLabels(
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
+ if (Limit == 0 || I + 1 == E ||
+ I[1]->First->isOneOf(tok::kw_case, tok::kw_default))
+ return 0;
+ unsigned NumStmts = 0;
+ unsigned Length = 0;
+ bool InPPDirective = I[0]->InPPDirective;
+ for (; NumStmts < 3; ++NumStmts) {
+ if (I + 1 + NumStmts == E)
+ break;
+ const AnnotatedLine *Line = I[1 + NumStmts];
+ if (Line->InPPDirective != InPPDirective)
+ break;
+ if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
+ break;
+ if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
+ tok::kw_while, tok::comment))
+ return 0;
+ Length += I[1 + NumStmts]->Last->TotalLength + 1; // 1 for the space.
+ }
+ if (NumStmts == 0 || NumStmts == 3 || Length > Limit)
+ return 0;
+ return NumStmts;
+ }
+
+ unsigned
+ tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ AnnotatedLine &Line = **I;
+
+ // Don't merge ObjC @ keywords and methods.
+ // FIXME: If an option to allow short exception handling clauses on a single
+ // line is added, change this to not return for @try and friends.
+ if (Style.Language != FormatStyle::LK_Java &&
+ Line.First->isOneOf(tok::at, tok::minus, tok::plus))
+ return 0;
+
+ // Check that the current line allows merging. This depends on whether we
+ // are in a control flow statements as well as several style flags.
+ if (Line.First->isOneOf(tok::kw_else, tok::kw_case))
+ return 0;
+ if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,
+ tok::kw___try, tok::kw_catch, tok::kw___finally,
+ tok::kw_for, tok::r_brace) ||
+ Line.First->is(Keywords.kw___except)) {
+ if (!Style.AllowShortBlocksOnASingleLine)
+ return 0;
+ if (!Style.AllowShortIfStatementsOnASingleLine &&
+ Line.First->is(tok::kw_if))
+ return 0;
+ if (!Style.AllowShortLoopsOnASingleLine &&
+ Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for))
+ return 0;
+ // FIXME: Consider an option to allow short exception handling clauses on
+ // a single line.
+ // FIXME: This isn't covered by tests.
+ // FIXME: For catch, __except, __finally the first token on the line
+ // is '}', so this isn't correct here.
+ if (Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch,
+ Keywords.kw___except, tok::kw___finally))
+ return 0;
+ }
+
+ FormatToken *Tok = I[1]->First;
+ if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
+ (Tok->getNextNonComment() == nullptr ||
+ Tok->getNextNonComment()->is(tok::semi))) {
+ // We merge empty blocks even if the line exceeds the column limit.
+ Tok->SpacesRequiredBefore = 0;
+ Tok->CanBreakBefore = true;
+ return 1;
+ } else if (Limit != 0 && Line.First->isNot(tok::kw_namespace) &&
+ !startsExternCBlock(Line)) {
+ // We don't merge short records.
+ if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct))
+ return 0;
+
+ // Check that we still have three lines and they fit into the limit.
+ if (I + 2 == E || I[2]->Type == LT_Invalid)
+ return 0;
+ Limit = limitConsideringMacros(I + 2, E, Limit);
+
+ if (!nextTwoLinesFitInto(I, Limit))
+ return 0;
+
+ // Second, check that the next line does not contain any braces - if it
+ // does, readability declines when putting it into a single line.
+ if (I[1]->Last->is(TT_LineComment))
+ return 0;
+ do {
+ if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
+ return 0;
+ Tok = Tok->Next;
+ } while (Tok);
+
+ // Last, check that the third line starts with a closing brace.
+ Tok = I[2]->First;
+ if (Tok->isNot(tok::r_brace))
+ return 0;
+
+ return 2;
+ }
+ return 0;
+ }
+
+ /// Returns the modified column limit for \p I if it is inside a macro and
+ /// needs a trailing '\'.
+ unsigned
+ limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ if (I[0]->InPPDirective && I + 1 != E &&
+ !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {
+ return Limit < 2 ? 0 : Limit - 2;
+ }
+ return Limit;
+ }
+
+ bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ unsigned Limit) {
+ if (I[1]->First->MustBreakBefore || I[2]->First->MustBreakBefore)
+ return false;
+ return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
+ }
+
+ bool containsMustBreak(const AnnotatedLine *Line) {
+ for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
+ if (Tok->MustBreakBefore)
+ return true;
+ }
+ return false;
+ }
+
+ const FormatStyle &Style;
+ const AdditionalKeywords &Keywords;
+};
+
+class NoColumnLimitFormatter {
+public:
+ NoColumnLimitFormatter(ContinuationIndenter *Indenter) : Indenter(Indenter) {}
+
+ /// \brief Formats the line starting at \p State, simply keeping all of the
+ /// input's line breaking decisions.
+ void format(unsigned FirstIndent, const AnnotatedLine *Line) {
+ LineState State =
+ Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);
+ while (State.NextToken) {
+ bool Newline =
+ Indenter->mustBreak(State) ||
+ (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
+ Indenter->addTokenToState(State, Newline, /*DryRun=*/false);
+ }
+ }
+
+private:
+ ContinuationIndenter *Indenter;
+};
+
+
+static void markFinalized(FormatToken *Tok) {
+ for (; Tok; Tok = Tok->Next) {
+ Tok->Finalized = true;
+ for (AnnotatedLine *Child : Tok->Children)
+ markFinalized(Child->First);
+ }
+}
+
+} // namespace
+
+unsigned
+UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
+ bool DryRun, int AdditionalIndent,
+ bool FixBadIndentation) {
+ LineJoiner Joiner(Style, Keywords);
+
+ // Try to look up already computed penalty in DryRun-mode.
+ std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
+ &Lines, AdditionalIndent);
+ auto CacheIt = PenaltyCache.find(CacheKey);
+ if (DryRun && CacheIt != PenaltyCache.end())
+ return CacheIt->second;
+
+ assert(!Lines.empty());
+ unsigned Penalty = 0;
+ std::vector<int> IndentForLevel;
+ for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)
+ IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
+ const AnnotatedLine *PreviousLine = nullptr;
+ for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),
+ E = Lines.end();
+ I != E; ++I) {
+ const AnnotatedLine &TheLine = **I;
+ const FormatToken *FirstTok = TheLine.First;
+ int Offset = getIndentOffset(*FirstTok);
+
+ // Determine indent and try to merge multiple unwrapped lines.
+ unsigned Indent;
+ if (TheLine.InPPDirective) {
+ Indent = TheLine.Level * Style.IndentWidth;
+ } else {
+ while (IndentForLevel.size() <= TheLine.Level)
+ IndentForLevel.push_back(-1);
+ IndentForLevel.resize(TheLine.Level + 1);
+ Indent = getIndent(IndentForLevel, TheLine.Level);
+ }
+ unsigned LevelIndent = Indent;
+ if (static_cast<int>(Indent) + Offset >= 0)
+ Indent += Offset;
+
+ // Merge multiple lines if possible.
+ unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E);
+ if (MergedLines > 0 && Style.ColumnLimit == 0) {
+ // Disallow line merging if there is a break at the start of one of the
+ // input lines.
+ for (unsigned i = 0; i < MergedLines; ++i) {
+ if (I[i + 1]->First->NewlinesBefore > 0)
+ MergedLines = 0;
+ }
+ }
+ if (!DryRun) {
+ for (unsigned i = 0; i < MergedLines; ++i) {
+ join(*I[i], *I[i + 1]);
+ }
+ }
+ I += MergedLines;
+
+ bool FixIndentation =
+ FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);
+ if (TheLine.First->is(tok::eof)) {
+ if (PreviousLine && PreviousLine->Affected && !DryRun) {
+ // Remove the file's trailing whitespace.
+ unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);
+ Whitespaces->replaceWhitespace(*TheLine.First, Newlines,
+ /*IndentLevel=*/0, /*Spaces=*/0,
+ /*TargetColumn=*/0);
+ }
+ } else if (TheLine.Type != LT_Invalid &&
+ (TheLine.Affected || FixIndentation)) {
+ if (FirstTok->WhitespaceRange.isValid()) {
+ if (!DryRun)
+ formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level, Indent,
+ TheLine.InPPDirective);
+ } else {
+ Indent = LevelIndent = FirstTok->OriginalColumn;
+ }
+
+ // If everything fits on a single line, just put it there.
+ unsigned ColumnLimit = Style.ColumnLimit;
+ if (I + 1 != E) {
+ AnnotatedLine *NextLine = I[1];
+ if (NextLine->InPPDirective && !NextLine->First->HasUnescapedNewline)
+ ColumnLimit = getColumnLimit(TheLine.InPPDirective);
+ }
+
+ if (TheLine.Last->TotalLength + Indent <= ColumnLimit ||
+ TheLine.Type == LT_ImportStatement) {
+ LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun);
+ while (State.NextToken) {
+ formatChildren(State, /*Newline=*/false, DryRun, Penalty);
+ Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
+ }
+ } else if (Style.ColumnLimit == 0) {
+ // FIXME: Implement nested blocks for ColumnLimit = 0.
+ NoColumnLimitFormatter Formatter(Indenter);
+ if (!DryRun)
+ Formatter.format(Indent, &TheLine);
+ } else {
+ Penalty += format(TheLine, Indent, DryRun);
+ }
+
+ if (!TheLine.InPPDirective)
+ IndentForLevel[TheLine.Level] = LevelIndent;
+ } else if (TheLine.ChildrenAffected) {
+ format(TheLine.Children, DryRun);
+ } else {
+ // Format the first token if necessary, and notify the WhitespaceManager
+ // about the unchanged whitespace.
+ for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
+ if (Tok == TheLine.First && (Tok->NewlinesBefore > 0 || Tok->IsFirst)) {
+ unsigned LevelIndent = Tok->OriginalColumn;
+ if (!DryRun) {
+ // Remove trailing whitespace of the previous line.
+ if ((PreviousLine && PreviousLine->Affected) ||
+ TheLine.LeadingEmptyLinesAffected) {
+ formatFirstToken(*Tok, PreviousLine, TheLine.Level, LevelIndent,
+ TheLine.InPPDirective);
+ } else {
+ Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
+ }
+ }
+
+ if (static_cast<int>(LevelIndent) - Offset >= 0)
+ LevelIndent -= Offset;
+ if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)
+ IndentForLevel[TheLine.Level] = LevelIndent;
+ } else if (!DryRun) {
+ Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
+ }
+ }
+ }
+ if (!DryRun)
+ markFinalized(TheLine.First);
+ PreviousLine = *I;
+ }
+ PenaltyCache[CacheKey] = Penalty;
+ return Penalty;
+}
+
+unsigned UnwrappedLineFormatter::format(const AnnotatedLine &Line,
+ unsigned FirstIndent, bool DryRun) {
+ LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
+
+ // If the ObjC method declaration does not fit on a line, we should format
+ // it with one arg per line.
+ if (State.Line->Type == LT_ObjCMethodDecl)
+ State.Stack.back().BreakBeforeParameter = true;
+
+ // Find best solution in solution space.
+ return analyzeSolutionSpace(State, DryRun);
+}
+
+void UnwrappedLineFormatter::formatFirstToken(FormatToken &RootToken,
+ const AnnotatedLine *PreviousLine,
+ unsigned IndentLevel,
+ unsigned Indent,
+ bool InPPDirective) {
+ unsigned Newlines =
+ std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
+ // Remove empty lines before "}" where applicable.
+ if (RootToken.is(tok::r_brace) &&
+ (!RootToken.Next ||
+ (RootToken.Next->is(tok::semi) && !RootToken.Next->Next)))
+ Newlines = std::min(Newlines, 1u);
+ if (Newlines == 0 && !RootToken.IsFirst)
+ Newlines = 1;
+ if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
+ Newlines = 0;
+
+ // Remove empty lines after "{".
+ if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
+ PreviousLine->Last->is(tok::l_brace) &&
+ PreviousLine->First->isNot(tok::kw_namespace) &&
+ !startsExternCBlock(*PreviousLine))
+ Newlines = 1;
+
+ // Insert extra new line before access specifiers.
+ if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&
+ RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)
+ ++Newlines;
+
+ // Remove empty lines after access specifiers.
+ if (PreviousLine && PreviousLine->First->isAccessSpecifier())
+ Newlines = std::min(1u, Newlines);
+
+ Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
+ Indent, InPPDirective &&
+ !RootToken.HasUnescapedNewline);
+}
+
+/// \brief Get the indent of \p Level from \p IndentForLevel.
+///
+/// \p IndentForLevel must contain the indent for the level \c l
+/// at \p IndentForLevel[l], or a value < 0 if the indent for
+/// that level is unknown.
+unsigned UnwrappedLineFormatter::getIndent(ArrayRef<int> IndentForLevel,
+ unsigned Level) {
+ if (IndentForLevel[Level] != -1)
+ return IndentForLevel[Level];
+ if (Level == 0)
+ return 0;
+ return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth;
+}
+
+void UnwrappedLineFormatter::join(AnnotatedLine &A, const AnnotatedLine &B) {
+ assert(!A.Last->Next);
+ assert(!B.First->Previous);
+ if (B.Affected)
+ A.Affected = true;
+ A.Last->Next = B.First;
+ B.First->Previous = A.Last;
+ B.First->CanBreakBefore = true;
+ unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore;
+ for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) {
+ Tok->TotalLength += LengthA;
+ A.Last = Tok;
+ }
+}
+
+unsigned UnwrappedLineFormatter::analyzeSolutionSpace(LineState &InitialState,
+ bool DryRun) {
+ std::set<LineState *, CompareLineStatePointers> Seen;
+
+ // Increasing count of \c StateNode items we have created. This is used to
+ // create a deterministic order independent of the container.
+ unsigned Count = 0;
+ QueueType Queue;
+
+ // Insert start element into queue.
+ StateNode *Node =
+ new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);
+ Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
+ ++Count;
+
+ unsigned Penalty = 0;
+
+ // While not empty, take first element and follow edges.
+ while (!Queue.empty()) {
+ Penalty = Queue.top().first.first;
+ StateNode *Node = Queue.top().second;
+ if (!Node->State.NextToken) {
+ DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");
+ break;
+ }
+ Queue.pop();
+
+ // Cut off the analysis of certain solutions if the analysis gets too
+ // complex. See description of IgnoreStackForComparison.
+ if (Count > 10000)
+ Node->State.IgnoreStackForComparison = true;
+
+ if (!Seen.insert(&Node->State).second)
+ // State already examined with lower penalty.
+ continue;
+
+ FormatDecision LastFormat = Node->State.NextToken->Decision;
+ if (LastFormat == FD_Unformatted || LastFormat == FD_Continue)
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue);
+ if (LastFormat == FD_Unformatted || LastFormat == FD_Break)
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/true, &Count, &Queue);
+ }
+
+ if (Queue.empty()) {
+ // We were unable to find a solution, do nothing.
+ // FIXME: Add diagnostic?
+ DEBUG(llvm::dbgs() << "Could not find a solution.\n");
+ return 0;
+ }
+
+ // Reconstruct the solution.
+ if (!DryRun)
+ reconstructPath(InitialState, Queue.top().second);
+
+ DEBUG(llvm::dbgs() << "Total number of analyzed states: " << Count << "\n");
+ DEBUG(llvm::dbgs() << "---\n");
+
+ return Penalty;
+}
+
+#ifndef NDEBUG
+static void printLineState(const LineState &State) {
+ llvm::dbgs() << "State: ";
+ for (const ParenState &P : State.Stack) {
+ llvm::dbgs() << P.Indent << "|" << P.LastSpace << "|" << P.NestedBlockIndent
+ << " ";
+ }
+ llvm::dbgs() << State.NextToken->TokenText << "\n";
+}
+#endif
+
+void UnwrappedLineFormatter::reconstructPath(LineState &State,
+ StateNode *Current) {
+ std::deque<StateNode *> Path;
+ // We do not need a break before the initial token.
+ while (Current->Previous) {
+ Path.push_front(Current);
+ Current = Current->Previous;
+ }
+ for (std::deque<StateNode *>::iterator I = Path.begin(), E = Path.end();
+ I != E; ++I) {
+ unsigned Penalty = 0;
+ formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);
+ Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);
+
+ DEBUG({
+ printLineState((*I)->Previous->State);
+ if ((*I)->NewLine) {
+ llvm::dbgs() << "Penalty for placing "
+ << (*I)->Previous->State.NextToken->Tok.getName() << ": "
+ << Penalty << "\n";
+ }
+ });
+ }
+}
+
+void UnwrappedLineFormatter::addNextStateToQueue(unsigned Penalty,
+ StateNode *PreviousNode,
+ bool NewLine, unsigned *Count,
+ QueueType *Queue) {
+ if (NewLine && !Indenter->canBreak(PreviousNode->State))
+ return;
+ if (!NewLine && Indenter->mustBreak(PreviousNode->State))
+ return;
+
+ StateNode *Node = new (Allocator.Allocate())
+ StateNode(PreviousNode->State, NewLine, PreviousNode);
+ if (!formatChildren(Node->State, NewLine, /*DryRun=*/true, Penalty))
+ return;
+
+ Penalty += Indenter->addTokenToState(Node->State, NewLine, true);
+
+ Queue->push(QueueItem(OrderedPenalty(Penalty, *Count), Node));
+ ++(*Count);
+}
+
+bool UnwrappedLineFormatter::formatChildren(LineState &State, bool NewLine,
+ bool DryRun, unsigned &Penalty) {
+ const FormatToken *LBrace = State.NextToken->getPreviousNonComment();
+ FormatToken &Previous = *State.NextToken->Previous;
+ if (!LBrace || LBrace->isNot(tok::l_brace) || LBrace->BlockKind != BK_Block ||
+ Previous.Children.size() == 0)
+ // The previous token does not open a block. Nothing to do. We don't
+ // assert so that we can simply call this function for all tokens.
+ return true;
+
+ if (NewLine) {
+ int AdditionalIndent = State.Stack.back().Indent -
+ Previous.Children[0]->Level * Style.IndentWidth;
+
+ Penalty += format(Previous.Children, DryRun, AdditionalIndent,
+ /*FixBadIndentation=*/true);
+ return true;
+ }
+
+ if (Previous.Children[0]->First->MustBreakBefore)
+ 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.
+ if (Previous.is(tok::comment))
+ return false;
+
+ // We can't put the closing "}" on a line with a trailing comment.
+ if (Previous.Children[0]->Last->isTrailingComment())
+ return false;
+
+ // If the child line exceeds the column limit, we wouldn't want to merge it.
+ // We add +2 for the trailing " }".
+ if (Style.ColumnLimit > 0 &&
+ Previous.Children[0]->Last->TotalLength + State.Column + 2 >
+ Style.ColumnLimit)
+ return false;
+
+ if (!DryRun) {
+ Whitespaces->replaceWhitespace(
+ *Previous.Children[0]->First,
+ /*Newlines=*/0, /*IndentLevel=*/0, /*Spaces=*/1,
+ /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
+ }
+ Penalty += format(*Previous.Children[0], State.Column + 1, DryRun);
+
+ State.Column += 1 + Previous.Children[0]->Last->TotalLength;
+ return true;
+}
+
+} // namespace format
+} // namespace clang
diff --git a/lib/Format/UnwrappedLineFormatter.h b/lib/Format/UnwrappedLineFormatter.h
new file mode 100644
index 0000000..9b83b27
--- /dev/null
+++ b/lib/Format/UnwrappedLineFormatter.h
@@ -0,0 +1,172 @@
+//===--- UnwrappedLineFormatter.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 Implements a combinartorial exploration of all the different
+/// linebreaks unwrapped lines can be formatted in.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
+#define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
+
+#include "ContinuationIndenter.h"
+#include "clang/Format/Format.h"
+#include <map>
+#include <queue>
+#include <string>
+
+namespace clang {
+namespace format {
+
+class ContinuationIndenter;
+class WhitespaceManager;
+
+class UnwrappedLineFormatter {
+public:
+ UnwrappedLineFormatter(ContinuationIndenter *Indenter,
+ WhitespaceManager *Whitespaces,
+ const FormatStyle &Style,
+ const AdditionalKeywords &Keywords)
+ : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
+ Keywords(Keywords) {}
+
+ unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
+ int AdditionalIndent = 0, bool FixBadIndentation = false);
+
+private:
+ /// \brief Formats an \c AnnotatedLine and returns the penalty.
+ ///
+ /// If \p DryRun is \c false, directly applies the changes.
+ unsigned format(const AnnotatedLine &Line, unsigned FirstIndent,
+ bool DryRun);
+
+ /// \brief An edge in the solution space from \c Previous->State to \c State,
+ /// inserting a newline dependent on the \c NewLine.
+ struct StateNode {
+ StateNode(const LineState &State, bool NewLine, StateNode *Previous)
+ : State(State), NewLine(NewLine), Previous(Previous) {}
+ LineState State;
+ bool NewLine;
+ StateNode *Previous;
+ };
+
+ /// \brief A pair of <penalty, count> that is used to prioritize the BFS on.
+ ///
+ /// In case of equal penalties, we want to prefer states that were inserted
+ /// first. During state generation we make sure that we insert states first
+ /// that break the line as late as possible.
+ typedef std::pair<unsigned, unsigned> OrderedPenalty;
+
+ /// \brief An item in the prioritized BFS search queue. The \c StateNode's
+ /// \c State has the given \c OrderedPenalty.
+ typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
+
+ /// \brief The BFS queue type.
+ typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
+ std::greater<QueueItem> > QueueType;
+
+ /// \brief Get the offset of the line relatively to the level.
+ ///
+ /// For example, 'public:' labels in classes are offset by 1 or 2
+ /// characters to the left from their level.
+ int getIndentOffset(const FormatToken &RootToken) {
+ if (Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript)
+ return 0;
+ if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())
+ return Style.AccessModifierOffset;
+ return 0;
+ }
+
+ /// \brief Add a new line and the required indent before the first Token
+ /// of the \c UnwrappedLine if there was no structural parsing error.
+ void formatFirstToken(FormatToken &RootToken,
+ const AnnotatedLine *PreviousLine, unsigned IndentLevel,
+ unsigned Indent, bool InPPDirective);
+
+ /// \brief Get the indent of \p Level from \p IndentForLevel.
+ ///
+ /// \p IndentForLevel must contain the indent for the level \c l
+ /// at \p IndentForLevel[l], or a value < 0 if the indent for
+ /// that level is unknown.
+ unsigned getIndent(ArrayRef<int> IndentForLevel, unsigned Level);
+
+ void join(AnnotatedLine &A, const AnnotatedLine &B);
+
+ unsigned getColumnLimit(bool InPPDirective) const {
+ // In preprocessor directives reserve two chars for trailing " \"
+ return Style.ColumnLimit - (InPPDirective ? 2 : 0);
+ }
+
+ struct CompareLineStatePointers {
+ bool operator()(LineState *obj1, LineState *obj2) const {
+ return *obj1 < *obj2;
+ }
+ };
+
+ /// \brief Analyze the entire solution space starting from \p InitialState.
+ ///
+ /// This implements a variant of Dijkstra's algorithm on the graph that spans
+ /// the solution space (\c LineStates are the nodes). The algorithm tries to
+ /// find the shortest path (the one with lowest penalty) from \p InitialState
+ /// to a state where all tokens are placed. Returns the penalty.
+ ///
+ /// If \p DryRun is \c false, directly applies the changes.
+ unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false);
+
+ void reconstructPath(LineState &State, StateNode *Current);
+
+ /// \brief Add the following state to the analysis queue \c Queue.
+ ///
+ /// Assume the current state is \p PreviousNode and has been reached with a
+ /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
+ void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
+ bool NewLine, unsigned *Count, QueueType *Queue);
+
+ /// \brief If the \p State's next token is an r_brace closing a nested block,
+ /// format the nested block before it.
+ ///
+ /// Returns \c true if all children could be placed successfully and adapts
+ /// \p Penalty as well as \p State. If \p DryRun is false, also directly
+ /// creates changes using \c Whitespaces.
+ ///
+ /// The crucial idea here is that children always get formatted upon
+ /// encountering the closing brace right after the nested block. Now, if we
+ /// are currently trying to keep the "}" on the same line (i.e. \p NewLine is
+ /// \c false), the entire block has to be kept on the same line (which is only
+ /// possible if it fits on the line, only contains a single statement, etc.
+ ///
+ /// If \p NewLine is true, we format the nested block on separate lines, i.e.
+ /// break after the "{", format all lines with correct indentation and the put
+ /// the closing "}" on yet another new line.
+ ///
+ /// This enables us to keep the simple structure of the
+ /// \c UnwrappedLineFormatter, where we only have two options for each token:
+ /// break or don't break.
+ bool formatChildren(LineState &State, bool NewLine, bool DryRun,
+ unsigned &Penalty);
+
+ ContinuationIndenter *Indenter;
+ WhitespaceManager *Whitespaces;
+ FormatStyle Style;
+ const AdditionalKeywords &Keywords;
+
+ llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
+
+ // Cache to store the penalty of formatting a vector of AnnotatedLines
+ // starting from a specific additional offset. Improves performance if there
+ // are many nested blocks.
+ std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
+ unsigned> PenaltyCache;
+};
+} // end namespace format
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index af1e94c..7bab55c 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -262,7 +262,7 @@
void UnwrappedLineParser::parseFile() {
ScopedDeclarationState DeclarationState(
*Line, DeclarationScopeStack,
- /*MustBeDeclaration=*/ !Line->InPPDirective);
+ /*MustBeDeclaration=*/!Line->InPPDirective);
parseLevel(/*HasOpeningBrace=*/false);
// Make sure to format the remaining tokens.
flushComments(true);
@@ -374,6 +374,7 @@
case tok::kw_for:
case tok::kw_switch:
case tok::kw_try:
+ case tok::kw___try:
if (!LBraceStack.empty())
LBraceStack.back()->BlockKind = BK_Block;
break;
@@ -418,6 +419,8 @@
}
static bool IsGoogScope(const UnwrappedLine &Line) {
+ // FIXME: Closure-library specific stuff should not be hard-coded but be
+ // configurable.
if (Line.Tokens.size() < 4)
return false;
auto I = Line.Tokens.begin();
@@ -547,6 +550,7 @@
void UnwrappedLineParser::parsePPIf(bool IfDef) {
nextToken();
bool IsLiteralFalse = (FormatTok->Tok.isLiteral() &&
+ FormatTok->Tok.getLiteralData() != nullptr &&
StringRef(FormatTok->Tok.getLiteralData(),
FormatTok->Tok.getLength()) == "0") ||
FormatTok->Tok.is(tok::kw_false);
@@ -653,20 +657,25 @@
nextToken();
addUnwrappedLine();
return;
+ case tok::objc_try:
+ // This branch isn't strictly necessary (the kw_try case below would
+ // do this too after the tok::at is parsed above). But be explicit.
+ parseTryCatch();
+ return;
default:
break;
}
break;
case tok::kw_asm:
- FormatTok->Finalized = true;
nextToken();
if (FormatTok->is(tok::l_brace)) {
+ nextToken();
while (FormatTok && FormatTok->isNot(tok::eof)) {
- FormatTok->Finalized = true;
if (FormatTok->is(tok::r_brace)) {
nextToken();
break;
}
+ FormatTok->Finalized = true;
nextToken();
}
}
@@ -684,7 +693,8 @@
case tok::kw_public:
case tok::kw_protected:
case tok::kw_private:
- if (Style.Language == FormatStyle::LK_Java)
+ if (Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript)
nextToken();
else
parseAccessSpecifier();
@@ -710,6 +720,7 @@
parseCaseLabel();
return;
case tok::kw_try:
+ case tok::kw___try:
parseTryCatch();
return;
case tok::kw_extern:
@@ -723,11 +734,22 @@
}
}
break;
+ case tok::kw_export:
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ parseJavaScriptEs6ImportExport();
+ return;
+ }
+ break;
case tok::identifier:
if (FormatTok->IsForEachMacro) {
parseForOrWhileLoop();
return;
}
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->is(Keywords.kw_import)) {
+ parseJavaScriptEs6ImportExport();
+ return;
+ }
// In all other cases, parse the declaration.
break;
default:
@@ -745,7 +767,8 @@
break;
case tok::kw_typedef:
nextToken();
- if (FormatTok->is(Keywords.kw_NS_ENUM))
+ if (FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
+ Keywords.kw_CF_ENUM, Keywords.kw_CF_OPTIONS))
parseEnum();
break;
case tok::kw_struct:
@@ -755,6 +778,13 @@
// A record declaration or definition is always the start of a structural
// element.
break;
+ case tok::period:
+ nextToken();
+ // In Java, classes have an implicit static member "class".
+ if (Style.Language == FormatStyle::LK_Java && FormatTok &&
+ FormatTok->is(tok::kw_class))
+ nextToken();
+ break;
case tok::semi:
nextToken();
addUnwrappedLine();
@@ -805,13 +835,17 @@
break;
}
nextToken();
- if (Line->Tokens.size() == 1) {
+ if (Line->Tokens.size() == 1 &&
+ // JS doesn't have macros, and within classes colons indicate fields,
+ // not labels.
+ (Style.Language != FormatStyle::LK_JavaScript ||
+ !Line->MustBeDeclaration)) {
if (FormatTok->Tok.is(tok::colon)) {
parseLabel();
return;
}
// Recognize function-like macro usages without trailing semicolon as
- // well as free-standing macrose like Q_OBJECT.
+ // well as free-standing macros like Q_OBJECT.
bool FunctionLike = FormatTok->is(tok::l_paren);
if (FunctionLike)
parseParens();
@@ -867,6 +901,10 @@
case tok::l_paren:
parseParens();
break;
+ case tok::amp:
+ case tok::star:
+ case tok::kw_const:
+ case tok::comma:
case tok::less:
case tok::greater:
case tok::identifier:
@@ -938,7 +976,7 @@
// Consume function name.
if (FormatTok->is(tok::identifier))
- nextToken();
+ nextToken();
if (FormatTok->isNot(tok::l_paren))
return;
@@ -1019,6 +1057,8 @@
switch (FormatTok->Tok.getKind()) {
case tok::l_paren:
parseParens();
+ if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_brace))
+ parseChildBlock();
break;
case tok::r_paren:
nextToken();
@@ -1029,12 +1069,11 @@
case tok::l_square:
tryToParseLambda();
break;
- case tok::l_brace: {
+ case tok::l_brace:
if (!tryToParseBracedList()) {
parseChildBlock();
}
break;
- }
case tok::at:
nextToken();
if (FormatTok->Tok.is(tok::l_brace))
@@ -1133,7 +1172,7 @@
}
void UnwrappedLineParser::parseTryCatch() {
- assert(FormatTok->is(tok::kw_try) && "'try' expected");
+ assert(FormatTok->isOneOf(tok::kw_try, tok::kw___try) && "'try' expected");
nextToken();
bool NeedsUnwrappedLine = false;
if (FormatTok->is(tok::colon)) {
@@ -1149,6 +1188,10 @@
nextToken();
}
}
+ // Parse try with resource.
+ if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren)) {
+ parseParens();
+ }
if (FormatTok->is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
@@ -1169,17 +1212,24 @@
parseStructuralElement();
--Line->Level;
}
- while (FormatTok->is(tok::kw_catch) ||
- ((Style.Language == FormatStyle::LK_Java ||
- Style.Language == FormatStyle::LK_JavaScript) &&
- FormatTok->is(Keywords.kw_finally))) {
+ while (1) {
+ if (FormatTok->is(tok::at))
+ nextToken();
+ if (!(FormatTok->isOneOf(tok::kw_catch, Keywords.kw___except,
+ tok::kw___finally) ||
+ ((Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript) &&
+ FormatTok->is(Keywords.kw_finally)) ||
+ (FormatTok->Tok.isObjCAtKeyword(tok::objc_catch) ||
+ FormatTok->Tok.isObjCAtKeyword(tok::objc_finally))))
+ break;
nextToken();
while (FormatTok->isNot(tok::l_brace)) {
if (FormatTok->is(tok::l_paren)) {
parseParens();
continue;
}
- if (FormatTok->isOneOf(tok::semi, tok::r_brace))
+ if (FormatTok->isOneOf(tok::semi, tok::r_brace, tok::eof))
return;
nextToken();
}
@@ -1480,7 +1530,8 @@
// class A {} n, m;
// will end up in one unwrapped line.
// This does not apply for Java.
- if (Style.Language == FormatStyle::LK_Java)
+ if (Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript)
addUnwrappedLine();
}
@@ -1559,6 +1610,30 @@
parseObjCUntilAtEnd();
}
+void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
+ assert(FormatTok->isOneOf(Keywords.kw_import, tok::kw_export));
+ nextToken();
+
+ if (FormatTok->isOneOf(tok::kw_const, tok::kw_class, Keywords.kw_function,
+ Keywords.kw_var))
+ return; // Fall through to parsing the corresponding structure.
+
+ if (FormatTok->is(tok::kw_default)) {
+ nextToken(); // export default ..., fall through after eating 'default'.
+ return;
+ }
+
+ if (FormatTok->is(tok::l_brace)) {
+ FormatTok->BlockKind = BK_Block;
+ parseBracedList();
+ }
+
+ while (!eof() && FormatTok->isNot(tok::semi) &&
+ FormatTok->isNot(tok::l_brace)) {
+ nextToken();
+ }
+}
+
LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
StringRef Prefix = "") {
llvm::dbgs() << Prefix << "Line(" << Line.Level << ")"
@@ -1643,8 +1718,7 @@
(FormatTok->HasUnescapedNewline || FormatTok->IsFirst)) {
// If there is an unfinished unwrapped line, we flush the preprocessor
// directives only after that unwrapped line was finished later.
- bool SwitchToPreprocessorLines =
- !Line->Tokens.empty() && CurrentLines == &Lines;
+ bool SwitchToPreprocessorLines = !Line->Tokens.empty();
ScopedLineState BlockState(*this, SwitchToPreprocessorLines);
// Comments stored before the preprocessor directive need to be output
// before the preprocessor directive, at the same level as the
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 3218afe..4b953ea 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -103,6 +103,7 @@
void parseObjCUntilAtEnd();
void parseObjCInterfaceOrImplementation();
void parseObjCProtocol();
+ void parseJavaScriptEs6ImportExport();
bool tryToParseLambda();
bool tryToParseLambdaIntroducer();
void tryToParseJSFunction();
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 47b94de..44e5f69 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -81,7 +81,7 @@
// FIXME: We still need to take this change in account to properly
// calculate the new length of the comment and to calculate the changes
// for which to do the alignment when aligning comments.
- Tok.Type == TT_LineComment && Newlines > 0 ? tok::comment : tok::unknown,
+ Tok.is(TT_LineComment) && Newlines > 0 ? tok::comment : tok::unknown,
InPPDirective && !Tok.IsFirst));
}
@@ -163,15 +163,17 @@
Changes[i - 1].StartOfTokenColumn == 0;
bool WasAlignedWithStartOfNextLine = false;
if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
+ unsigned CommentColumn = SourceMgr.getSpellingColumnNumber(
+ Changes[i].OriginalWhitespaceRange.getEnd());
for (unsigned j = i + 1; j != e; ++j) {
if (Changes[j].Kind != tok::comment) { // Skip over comments.
+ unsigned NextColumn = SourceMgr.getSpellingColumnNumber(
+ Changes[j].OriginalWhitespaceRange.getEnd());
// The start of the next token was previously aligned with the
// start of this comment.
WasAlignedWithStartOfNextLine =
- (SourceMgr.getSpellingColumnNumber(
- Changes[i].OriginalWhitespaceRange.getEnd()) ==
- SourceMgr.getSpellingColumnNumber(
- Changes[j].OriginalWhitespaceRange.getEnd()));
+ CommentColumn == NextColumn ||
+ CommentColumn == NextColumn + Style.IndentWidth;
break;
}
}
@@ -262,6 +264,11 @@
void WhitespaceManager::generateChanges() {
for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
const Change &C = Changes[i];
+ if (i > 0) {
+ assert(Changes[i - 1].OriginalWhitespaceRange.getBegin() !=
+ C.OriginalWhitespaceRange.getBegin() &&
+ "Generating two replacements for the same location");
+ }
if (C.CreateReplacement) {
std::string ReplacementText = C.PreviousLinePostfix;
if (C.ContinuesPPDirective)