Update Clang for 3.5 rebase (r209713).
Change-Id: I8c9133b0f8f776dc915f270b60f94962e771bc83
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index d43a774..1bea0e5 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/lib/Format/BreakableToken.cpp
@@ -13,8 +13,6 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-token-breaker"
-
#include "BreakableToken.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Format/Format.h"
@@ -22,6 +20,8 @@
#include "llvm/Support/Debug.h"
#include <algorithm>
+#define DEBUG_TYPE "format-token-breaker"
+
namespace clang {
namespace format {
@@ -82,11 +82,9 @@
return BreakableToken::Split(StringRef::npos, 0);
}
-static BreakableToken::Split getStringSplit(StringRef Text,
- unsigned UsedColumns,
- unsigned ColumnLimit,
- unsigned TabWidth,
- encoding::Encoding Encoding) {
+static BreakableToken::Split
+getStringSplit(StringRef Text, unsigned UsedColumns, unsigned ColumnLimit,
+ unsigned TabWidth, encoding::Encoding Encoding) {
// FIXME: Reduce unit test case.
if (Text.empty())
return BreakableToken::Split(StringRef::npos, 0);
@@ -350,10 +348,9 @@
Lines[LineIndex].begin() - Lines[LineIndex - 1].end();
// Adjust the start column uniformly across all lines.
- StartOfLineColumn[LineIndex] = std::max<int>(
- 0,
+ StartOfLineColumn[LineIndex] =
encoding::columnWidthWithTabs(Whitespace, 0, Style.TabWidth, Encoding) +
- IndentDelta);
+ IndentDelta;
}
unsigned BreakableBlockComment::getLineCount() const { return Lines.size(); }
@@ -437,7 +434,6 @@
unsigned WhitespaceOffsetInToken = Lines[LineIndex].data() -
Tok.TokenText.data() -
LeadingWhitespace[LineIndex];
- assert(StartOfLineColumn[LineIndex] >= Prefix.size());
Whitespaces.replaceWhitespaceInToken(
Tok, WhitespaceOffsetInToken, LeadingWhitespace[LineIndex], "", Prefix,
InPPDirective, 1, IndentLevel,
@@ -450,7 +446,7 @@
// If we break, we always break at the predefined indent.
if (TailOffset != 0)
return IndentAtLineBreak;
- return StartOfLineColumn[LineIndex];
+ return std::max(0, StartOfLineColumn[LineIndex]);
}
} // namespace format
diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h
index e294a50..72bb1e4 100644
--- a/lib/Format/BreakableToken.h
+++ b/lib/Format/BreakableToken.h
@@ -212,7 +212,7 @@
// 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.
- SmallVector<unsigned, 16> StartOfLineColumn;
+ SmallVector<int, 16> StartOfLineColumn;
// The column at which the text of a broken line should start.
// Note that an optional decoration would go before that column.
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 5a3dee6..7485e0d 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -12,8 +12,6 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-formatter"
-
#include "BreakableToken.h"
#include "ContinuationIndenter.h"
#include "WhitespaceManager.h"
@@ -23,13 +21,15 @@
#include "llvm/Support/Debug.h"
#include <string>
+#define DEBUG_TYPE "format-formatter"
+
namespace clang {
namespace format {
// Returns the length of everything up to the first possible line break after
// the ), ], } or > matching \c Tok.
static unsigned getLengthToMatchingParen(const FormatToken &Tok) {
- if (Tok.MatchingParen == NULL)
+ if (!Tok.MatchingParen)
return 0;
FormatToken *End = Tok.MatchingParen;
while (End->Next && !End->Next->CanBreakBefore) {
@@ -78,10 +78,9 @@
/*AvoidBinPacking=*/false,
/*NoLineBreak=*/false));
State.LineContainsContinuedForLoopSection = false;
- State.ParenLevel = 0;
State.StartOfStringLiteral = 0;
- State.StartOfLineLevel = State.ParenLevel;
- State.LowestLevelOnLine = State.ParenLevel;
+ State.StartOfLineLevel = 0;
+ State.LowestLevelOnLine = 0;
State.IgnoreStackForComparison = false;
// The first token has already been indented and thus consumed.
@@ -99,8 +98,8 @@
// 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.Previous &&
+ Previous.Type != TT_DictLiteral && Previous.BlockKind == BK_BracedInit &&
+ Previous.Previous &&
Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma))
return false;
// This prevents breaks like:
@@ -142,10 +141,11 @@
return true;
if (((Previous.Type == TT_DictLiteral && Previous.is(tok::l_brace)) ||
Previous.Type == TT_ArrayInitializerLSquare) &&
+ Style.ColumnLimit > 0 &&
getLengthToMatchingParen(Previous) + State.Column > getColumnLimit(State))
return true;
if (Current.Type == TT_CtorInitializerColon &&
- (!Style.AllowShortFunctionsOnASingleLine ||
+ ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) ||
Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0))
return true;
@@ -173,8 +173,7 @@
if (Previous.Type == TT_BinaryOperator &&
(!IsComparison || LHSIsBinaryExpr) &&
Current.Type != TT_BinaryOperator && // For >>.
- !Current.isTrailingComment() &&
- !Previous.isOneOf(tok::lessless, tok::question) &&
+ !Current.isTrailingComment() && !Previous.is(tok::lessless) &&
Previous.getPrecedence() != prec::Assignment &&
State.Stack.back().BreakBeforeParameter)
return true;
@@ -190,13 +189,13 @@
State.Stack.back().ObjCSelectorNameFound &&
State.Stack.back().BreakBeforeParameter)
return true;
- if (Previous.ClosesTemplateDeclaration && State.ParenLevel == 0 &&
+ if (Previous.ClosesTemplateDeclaration && Current.NestingLevel == 0 &&
!Current.isTrailingComment())
return true;
if ((Current.Type == TT_StartOfName || Current.is(tok::kw_operator)) &&
State.Line->MightBeFunctionDecl &&
- State.Stack.back().BreakBeforeParameter && State.ParenLevel == 0)
+ State.Stack.back().BreakBeforeParameter && Current.NestingLevel == 0)
return true;
if (startsSegmentOfBuilderTypeCall(Current) &&
(State.Stack.back().CallContinuation != 0 ||
@@ -207,8 +206,8 @@
// The following could be precomputed as they do not depend on the state.
// However, as they should take effect only if the UnwrappedLine does not fit
// into the ColumnLimit, they are checked here in the ContinuationIndenter.
- if (Previous.BlockKind == BK_Block && Previous.is(tok::l_brace) &&
- !Current.isOneOf(tok::r_brace, tok::comment))
+ if (Style.ColumnLimit != 0 && Previous.BlockKind == BK_Block &&
+ Previous.is(tok::l_brace) && !Current.isOneOf(tok::r_brace, tok::comment))
return true;
return false;
@@ -221,7 +220,7 @@
assert(!State.Stack.empty());
if ((Current.Type == TT_ImplicitStringLiteral &&
- (Current.Previous->Tok.getIdentifierInfo() == NULL ||
+ (Current.Previous->Tok.getIdentifierInfo() == nullptr ||
Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp_not_keyword))) {
// FIXME: Is this correct?
@@ -248,7 +247,7 @@
FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *State.NextToken->Previous;
if (Current.is(tok::equal) &&
- (State.Line->First->is(tok::kw_for) || State.ParenLevel == 0) &&
+ (State.Line->First->is(tok::kw_for) || Current.NestingLevel == 0) &&
State.Stack.back().VariablePos == 0) {
State.Stack.back().VariablePos = State.Column;
// Move over * and & if they are bound to the variable name.
@@ -290,10 +289,11 @@
State.Stack.back().ContainsUnwrappedBuilder = true;
State.Column += Spaces;
- if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for))
+ if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) &&
+ 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 + 1; // 1 is length of "(".
+ State.Stack.back().LastSpace = State.Column;
else if (Current.isNot(tok::comment) &&
(Previous.is(tok::comma) ||
(Previous.is(tok::colon) && Previous.Type == TT_ObjCMethodExpr)))
@@ -301,7 +301,9 @@
else if ((Previous.Type == TT_BinaryOperator ||
Previous.Type == TT_ConditionalExpr ||
Previous.Type == TT_CtorInitializerColon) &&
- (Previous.getPrecedence() != prec::Assignment ||
+ ((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
@@ -340,7 +342,7 @@
const FormatToken *NextNonComment = Previous.getNextNonComment();
if (!NextNonComment)
NextNonComment = &Current;
- // The first line break on any ParenLevel causes an extra penalty in order
+ // The first line break on any NestingLevel causes an extra penalty in order
// prefer similar line breaks.
if (!State.Stack.back().ContainsLineBreak)
Penalty += 15;
@@ -383,7 +385,7 @@
// ^(int *i) {
// // ...
// }];
- // Thus, we set LastSpace of the next higher ParenLevel, to which we move
+ // Thus, we set LastSpace of the next higher NestingLevel, to which we move
// when we consume all of the "}"'s FakeRParens at the "{".
if (State.Stack.size() > 1)
State.Stack[State.Stack.size() - 2].LastSpace =
@@ -395,7 +397,7 @@
!State.Stack.back().AvoidBinPacking) ||
Previous.Type == TT_BinaryOperator)
State.Stack.back().BreakBeforeParameter = false;
- if (Previous.Type == TT_TemplateCloser && State.ParenLevel == 0)
+ if (Previous.Type == TT_TemplateCloser && Current.NestingLevel == 0)
State.Stack.back().BreakBeforeParameter = false;
if (NextNonComment->is(tok::question) ||
(PreviousNonComment && PreviousNonComment->is(tok::question)))
@@ -413,20 +415,26 @@
if (!Current.isTrailingComment())
State.Stack.back().LastSpace = State.Column;
- State.StartOfLineLevel = State.ParenLevel;
- State.LowestLevelOnLine = State.ParenLevel;
+ State.StartOfLineLevel = Current.NestingLevel;
+ State.LowestLevelOnLine = Current.NestingLevel;
// Any break on this level means that the parent level has been broken
// and we need to avoid bin packing there.
- for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
- State.Stack[i].BreakBeforeParameter = true;
+ 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) {
+ for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
+ State.Stack[i].BreakBeforeParameter = true;
+ }
}
+
if (PreviousNonComment &&
!PreviousNonComment->isOneOf(tok::comma, tok::semi) &&
PreviousNonComment->Type != TT_TemplateCloser &&
PreviousNonComment->Type != TT_BinaryOperator &&
- Current.Type != TT_BinaryOperator &&
- !PreviousNonComment->opensScope())
+ Current.Type != TT_BinaryOperator && !PreviousNonComment->opensScope())
State.Stack.back().BreakBeforeParameter = true;
// If we break after { or the [ of an array initializer, we should also break
@@ -436,11 +444,13 @@
if (State.Stack.back().AvoidBinPacking) {
// If we are breaking after '(', '{', '<', this is not bin packing
- // unless AllowAllParametersOfDeclarationOnNextLine is false.
+ // unless AllowAllParametersOfDeclarationOnNextLine is false or this is a
+ // dict/object literal.
if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) ||
Previous.Type == TT_BinaryOperator) ||
(!Style.AllowAllParametersOfDeclarationOnNextLine &&
- State.Line->MustBeDeclaration))
+ State.Line->MustBeDeclaration) ||
+ Previous.Type == TT_DictLiteral)
State.Stack.back().BreakBeforeParameter = true;
}
@@ -460,11 +470,13 @@
const FormatToken *NextNonComment = Previous.getNextNonComment();
if (!NextNonComment)
NextNonComment = &Current;
- if (NextNonComment->is(tok::l_brace) &&
- NextNonComment->BlockKind == BK_Block)
- return State.ParenLevel == 0 ? State.FirstIndent
- : State.Stack.back().Indent;
+ 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))
@@ -472,6 +484,9 @@
else
return State.FirstIndent;
}
+ if (Current.is(tok::identifier) && Current.Next &&
+ Current.Next->Type == TT_DictLiteral)
+ return State.Stack.back().Indent;
if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0)
return State.StartOfStringLiteral;
if (NextNonComment->is(tok::lessless) &&
@@ -485,7 +500,8 @@
}
}
if (State.Stack.back().QuestionColumn != 0 &&
- (NextNonComment->Type == TT_ConditionalExpr ||
+ ((NextNonComment->is(tok::colon) &&
+ NextNonComment->Type == TT_ConditionalExpr) ||
Previous.Type == TT_ConditionalExpr))
return State.Stack.back().QuestionColumn;
if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0)
@@ -494,8 +510,9 @@
PreviousNonComment->Type == TT_AttributeParen)) ||
((NextNonComment->Type == TT_StartOfName ||
NextNonComment->is(tok::kw_operator)) &&
- State.ParenLevel == 0 && (!Style.IndentFunctionDeclarationAfterType ||
- State.Line->StartsDefinition)))
+ Current.NestingLevel == 0 &&
+ (!Style.IndentFunctionDeclarationAfterType ||
+ State.Line->StartsDefinition)))
return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent);
if (NextNonComment->Type == TT_ObjCSelectorName) {
if (!State.Stack.back().ObjCSelectorNameFound) {
@@ -542,14 +559,20 @@
unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
bool DryRun, bool Newline) {
- const FormatToken &Current = *State.NextToken;
assert(State.Stack.size());
+ const FormatToken &Current = *State.NextToken;
if (Current.Type == TT_InheritanceColon)
State.Stack.back().AvoidBinPacking = true;
- if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator &&
- State.Stack.back().FirstLessLess == 0)
- State.Stack.back().FirstLessLess = State.Column;
+ if (Current.is(tok::lessless) && Current.Type != 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)
+ State.Stack.back().LastOperatorWrapped = Newline;
if (Current.Type == TT_ArraySubscriptLSquare &&
State.Stack.back().StartOfArraySubscripts == 0)
State.Stack.back().StartOfArraySubscripts = State.Column;
@@ -560,12 +583,14 @@
State.Stack.back().QuestionColumn = State.Column;
if (!Current.opensScope() && !Current.closesScope())
State.LowestLevelOnLine =
- std::min(State.LowestLevelOnLine, State.ParenLevel);
+ std::min(State.LowestLevelOnLine, Current.NestingLevel);
if (Current.isMemberAccess())
State.Stack.back().StartOfFunctionCall =
- Current.LastInChainOfCalls ? 0 : State.Column + Current.ColumnWidth;
+ Current.LastOperator ? 0 : State.Column + Current.ColumnWidth;
if (Current.Type == TT_ObjCSelectorName)
State.Stack.back().ObjCSelectorNameFound = true;
+ if (Current.Type == TT_LambdaLSquare)
+ ++State.Stack.back().LambdasFound;
if (Current.Type == TT_CtorInitializerColon) {
// Indent 2 from the column, so:
// SomeClass::SomeClass()
@@ -587,180 +612,31 @@
// Insert scopes created by fake parenthesis.
const FormatToken *Previous = Current.getPreviousNonComment();
- // Don't add extra indentation for the first fake parenthesis after
- // 'return', assignements or opening <({[. The indentation for these cases
- // is special cased.
- bool SkipFirstExtraIndent =
- (Previous && (Previous->opensScope() || Previous->is(tok::kw_return) ||
- Previous->getPrecedence() == prec::Assignment ||
- Previous->Type == TT_ObjCMethodExpr));
- for (SmallVectorImpl<prec::Level>::const_reverse_iterator
- I = Current.FakeLParens.rbegin(),
- E = Current.FakeLParens.rend();
- I != E; ++I) {
- ParenState NewParenState = State.Stack.back();
- NewParenState.ContainsLineBreak = false;
- // Indent from 'LastSpace' unless this the fake parentheses encapsulating a
- // builder type call after 'return'. If such a call is line-wrapped, we
- // commonly just want to indent from the start of the line.
- if (!Previous || Previous->isNot(tok::kw_return) || *I > 0)
- NewParenState.Indent =
- std::max(std::max(State.Column, NewParenState.Indent),
- State.Stack.back().LastSpace);
-
- // Don't allow the RHS of an operator to be split over multiple lines unless
- // there is a line-break right after the operator.
- // Exclude relational operators, as there, it is always more desirable to
- // have the LHS 'left' of the RHS.
- // FIXME: Implement this for '<<' and BreakBeforeBinaryOperators.
- if (!Newline && Previous && Previous->Type == TT_BinaryOperator &&
- !Previous->isOneOf(tok::lessless, tok::question, tok::colon) &&
- Previous->getPrecedence() > prec::Assignment &&
- Previous->getPrecedence() != prec::Relational &&
- !Style.BreakBeforeBinaryOperators)
- NewParenState.NoLineBreak = true;
-
- // Do not indent relative to the fake parentheses inserted for "." or "->".
- // This is a special case to make the following to statements consistent:
- // OuterFunction(InnerFunctionCall( // break
- // ParameterToInnerFunction));
- // OuterFunction(SomeObject.InnerFunctionCall( // break
- // ParameterToInnerFunction));
- if (*I > prec::Unknown)
- NewParenState.LastSpace = std::max(NewParenState.LastSpace, State.Column);
- NewParenState.StartOfFunctionCall = State.Column;
-
- // Always indent conditional expressions. Never indent expression where
- // the 'operator' is ',', ';' or an assignment (i.e. *I <=
- // prec::Assignment) as those have different indentation rules. Indent
- // other expression, unless the indentation needs to be skipped.
- if (*I == prec::Conditional ||
- (!SkipFirstExtraIndent && *I > prec::Assignment &&
- !Style.BreakBeforeBinaryOperators))
- NewParenState.Indent += Style.ContinuationIndentWidth;
- if ((Previous && !Previous->opensScope()) || *I > prec::Comma)
- NewParenState.BreakBeforeParameter = false;
- State.Stack.push_back(NewParenState);
- SkipFirstExtraIndent = false;
- }
-
- // If we encounter an opening (, [, { or <, we add a level to our stacks to
- // prepare for the following tokens.
- if (Current.opensScope()) {
- unsigned NewIndent;
- unsigned NewIndentLevel = State.Stack.back().IndentLevel;
- bool AvoidBinPacking;
- bool BreakBeforeParameter = false;
- if (Current.is(tok::l_brace) ||
- Current.Type == TT_ArrayInitializerLSquare) {
- if (Current.MatchingParen && Current.BlockKind == BK_Block) {
- // If this is an l_brace starting a nested block, we pretend (wrt. to
- // indentation) that we already consumed the corresponding r_brace.
- // Thus, we remove all ParenStates caused by fake parentheses that end
- // at the r_brace. The net effect of this is that we don't indent
- // relative to the l_brace, if the nested block is the last parameter of
- // a function. For example, this formats:
- //
- // SomeFunction(a, [] {
- // f(); // break
- // });
- //
- // instead of:
- // SomeFunction(a, [] {
- // f(); // break
- // });
- for (unsigned i = 0; i != Current.MatchingParen->FakeRParens; ++i) {
- assert(State.Stack.size() > 1);
- if (State.Stack.size() == 1) {
- // Do not pop the last element.
- break;
- }
- State.Stack.pop_back();
- }
- // For some reason, ObjC blocks are indented like continuations.
- NewIndent =
- State.Stack.back().LastSpace + (Current.Type == TT_ObjCBlockLBrace
- ? Style.ContinuationIndentWidth
- : Style.IndentWidth);
- ++NewIndentLevel;
- BreakBeforeParameter = true;
- } else {
- NewIndent = State.Stack.back().LastSpace;
- if (Current.opensBlockTypeList(Style)) {
- NewIndent += Style.IndentWidth;
- NewIndent = std::min(State.Column + 2, NewIndent);
- ++NewIndentLevel;
- } else {
- NewIndent += Style.ContinuationIndentWidth;
- NewIndent = std::min(State.Column + 1, NewIndent);
+ // Add special behavior to support a format commonly used for JavaScript
+ // closures:
+ // SomeFunction(function() {
+ // 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;
}
}
- const FormatToken *NextNoComment = Current.getNextNonComment();
- AvoidBinPacking = Current.BlockKind == BK_Block ||
- Current.Type == TT_ArrayInitializerLSquare ||
- Current.Type == TT_DictLiteral ||
- (NextNoComment &&
- NextNoComment->Type == TT_DesignatedInitializerPeriod);
- } else {
- NewIndent = Style.ContinuationIndentWidth +
- std::max(State.Stack.back().LastSpace,
- State.Stack.back().StartOfFunctionCall);
- AvoidBinPacking = !Style.BinPackParameters ||
- (Style.ExperimentalAutoDetectBinPacking &&
- (Current.PackingKind == PPK_OnePerLine ||
- (!BinPackInconclusiveFunctions &&
- Current.PackingKind == PPK_Inconclusive)));
- // If this '[' opens an ObjC call, determine whether all parameters fit
- // into one line and put one per line if they don't.
- if (Current.Type == TT_ObjCMethodExpr &&
- getLengthToMatchingParen(Current) + State.Column >
- getColumnLimit(State))
- BreakBeforeParameter = true;
+ State.Stack[State.Stack.size() - 2].JSFunctionInlined = false;
}
-
- bool NoLineBreak = State.Stack.back().NoLineBreak ||
- (Current.Type == TT_TemplateOpener &&
- State.Stack.back().ContainsUnwrappedBuilder);
- State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
- State.Stack.back().LastSpace,
- AvoidBinPacking, NoLineBreak));
- State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
- ++State.ParenLevel;
+ if (Current.TokenText == "function")
+ State.Stack.back().JSFunctionInlined = !Newline;
}
- // If we encounter a closing ), ], } or >, we can remove a level from our
- // stacks.
- 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.Stack.pop_back();
- --State.ParenLevel;
- }
- if (Current.is(tok::r_square)) {
- // If this ends the array subscript expr, reset the corresponding value.
- const FormatToken *NextNonComment = Current.getNextNonComment();
- if (NextNonComment && NextNonComment->isNot(tok::l_square))
- State.Stack.back().StartOfArraySubscripts = 0;
- }
-
- // Remove scopes created by fake parenthesis.
- if (Current.isNot(tok::r_brace) ||
- (Current.MatchingParen && Current.MatchingParen->BlockKind != BK_Block)) {
- // Don't remove FakeRParens attached to r_braces that surround nested blocks
- // as they will have been removed early (see above).
- for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
- unsigned VariablePos = State.Stack.back().VariablePos;
- assert(State.Stack.size() > 1);
- if (State.Stack.size() == 1) {
- // Do not pop the last element.
- break;
- }
- State.Stack.pop_back();
- State.Stack.back().VariablePos = VariablePos;
- }
- }
+ moveStatePastFakeLParens(State, Newline);
+ moveStatePastScopeOpener(State, Newline);
+ moveStatePastScopeCloser(State);
+ moveStatePastFakeRParens(State);
if (Current.isStringLiteral() && State.StartOfStringLiteral == 0) {
State.StartOfStringLiteral = State.Column;
@@ -790,6 +666,218 @@
return Penalty;
}
+void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
+ bool Newline) {
+ const FormatToken &Current = *State.NextToken;
+ const FormatToken *Previous = Current.getPreviousNonComment();
+
+ // Don't add extra indentation for the first fake parenthesis after
+ // 'return', assignments or opening <({[. The indentation for these cases
+ // is special cased.
+ bool SkipFirstExtraIndent =
+ (Previous && (Previous->opensScope() || Previous->is(tok::kw_return) ||
+ Previous->getPrecedence() == prec::Assignment ||
+ Previous->Type == TT_ObjCMethodExpr));
+ for (SmallVectorImpl<prec::Level>::const_reverse_iterator
+ I = Current.FakeLParens.rbegin(),
+ E = Current.FakeLParens.rend();
+ I != E; ++I) {
+ ParenState NewParenState = State.Stack.back();
+ NewParenState.ContainsLineBreak = false;
+
+ // Indent from 'LastSpace' unless this the fake parentheses encapsulating a
+ // builder type call after 'return'. If such a call is line-wrapped, we
+ // commonly just want to indent from the start of the line.
+ if (!Previous || Previous->isNot(tok::kw_return) || *I > 0)
+ NewParenState.Indent =
+ std::max(std::max(State.Column, NewParenState.Indent),
+ State.Stack.back().LastSpace);
+
+ // Don't allow the RHS of an operator to be split over multiple lines unless
+ // there is a line-break right after the operator.
+ // 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->getPrecedence() != prec::Relational) {
+ bool BreakBeforeOperator = Previous->is(tok::lessless) ||
+ (Previous->Type == TT_BinaryOperator &&
+ Style.BreakBeforeBinaryOperators) ||
+ (Previous->Type == TT_ConditionalExpr &&
+ Style.BreakBeforeTernaryOperators);
+ if ((!Newline && !BreakBeforeOperator) ||
+ (!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator))
+ NewParenState.NoLineBreak = true;
+ }
+
+ // Do not indent relative to the fake parentheses inserted for "." or "->".
+ // This is a special case to make the following to statements consistent:
+ // OuterFunction(InnerFunctionCall( // break
+ // ParameterToInnerFunction));
+ // OuterFunction(SomeObject.InnerFunctionCall( // break
+ // ParameterToInnerFunction));
+ if (*I > prec::Unknown)
+ NewParenState.LastSpace = std::max(NewParenState.LastSpace, State.Column);
+ NewParenState.StartOfFunctionCall = State.Column;
+
+ // Always indent conditional expressions. Never indent expression where
+ // the 'operator' is ',', ';' or an assignment (i.e. *I <=
+ // prec::Assignment) as those have different indentation rules. Indent
+ // other expression, unless the indentation needs to be skipped.
+ if (*I == prec::Conditional ||
+ (!SkipFirstExtraIndent && *I > prec::Assignment &&
+ !Style.BreakBeforeBinaryOperators))
+ NewParenState.Indent += Style.ContinuationIndentWidth;
+ if ((Previous && !Previous->opensScope()) || *I > prec::Comma)
+ NewParenState.BreakBeforeParameter = false;
+ State.Stack.push_back(NewParenState);
+ SkipFirstExtraIndent = false;
+ }
+}
+
+void ContinuationIndenter::moveStatePastFakeRParens(LineState &State) {
+ const FormatToken &Current = *State.NextToken;
+
+ // Remove scopes created by fake parenthesis.
+ if (Current.isNot(tok::r_brace) ||
+ (Current.MatchingParen && Current.MatchingParen->BlockKind != BK_Block)) {
+ // Don't remove FakeRParens attached to r_braces that surround nested blocks
+ // as they will have been removed early (see above).
+ for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
+ unsigned VariablePos = State.Stack.back().VariablePos;
+ assert(State.Stack.size() > 1);
+ if (State.Stack.size() == 1) {
+ // Do not pop the last element.
+ break;
+ }
+ State.Stack.pop_back();
+ State.Stack.back().VariablePos = VariablePos;
+ }
+ }
+}
+
+void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
+ bool Newline) {
+ const FormatToken &Current = *State.NextToken;
+ if (!Current.opensScope())
+ return;
+
+ if (Current.MatchingParen && Current.BlockKind == BK_Block) {
+ moveStateToNewBlock(State);
+ return;
+ }
+
+ unsigned NewIndent;
+ unsigned NewIndentLevel = State.Stack.back().IndentLevel;
+ bool AvoidBinPacking;
+ bool BreakBeforeParameter = false;
+ if (Current.is(tok::l_brace) || Current.Type == TT_ArrayInitializerLSquare) {
+ NewIndent = State.Stack.back().LastSpace;
+ if (Current.opensBlockTypeList(Style)) {
+ NewIndent += Style.IndentWidth;
+ NewIndent = std::min(State.Column + 2, NewIndent);
+ ++NewIndentLevel;
+ } else {
+ NewIndent += Style.ContinuationIndentWidth;
+ NewIndent = std::min(State.Column + 1, NewIndent);
+ }
+ const FormatToken *NextNoComment = Current.getNextNonComment();
+ AvoidBinPacking = Current.Type == TT_ArrayInitializerLSquare ||
+ Current.Type == TT_DictLiteral ||
+ Style.Language == FormatStyle::LK_Proto ||
+ !Style.BinPackParameters ||
+ (NextNoComment &&
+ NextNoComment->Type == TT_DesignatedInitializerPeriod);
+ } else {
+ NewIndent = Style.ContinuationIndentWidth +
+ std::max(State.Stack.back().LastSpace,
+ State.Stack.back().StartOfFunctionCall);
+ AvoidBinPacking = !Style.BinPackParameters ||
+ (Style.ExperimentalAutoDetectBinPacking &&
+ (Current.PackingKind == PPK_OnePerLine ||
+ (!BinPackInconclusiveFunctions &&
+ Current.PackingKind == PPK_Inconclusive)));
+ // If this '[' opens an ObjC call, determine whether all parameters fit
+ // into one line and put one per line if they don't.
+ if (Current.Type == TT_ObjCMethodExpr && Style.ColumnLimit != 0 &&
+ getLengthToMatchingParen(Current) + State.Column >
+ getColumnLimit(State))
+ BreakBeforeParameter = true;
+ }
+ bool NoLineBreak = State.Stack.back().NoLineBreak ||
+ (Current.Type == TT_TemplateOpener &&
+ State.Stack.back().ContainsUnwrappedBuilder);
+ State.Stack.push_back(ParenState(NewIndent, NewIndentLevel,
+ State.Stack.back().LastSpace,
+ AvoidBinPacking, NoLineBreak));
+ State.Stack.back().BreakBeforeParameter = BreakBeforeParameter;
+}
+
+void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) {
+ const FormatToken &Current = *State.NextToken;
+ if (!Current.closesScope())
+ return;
+
+ // If we encounter a closing ), ], } or >, we can remove a level from our
+ // stacks.
+ if (State.Stack.size() > 1 &&
+ (Current.isOneOf(tok::r_paren, tok::r_square) ||
+ (Current.is(tok::r_brace) && State.NextToken != State.Line->First) ||
+ State.NextToken->Type == TT_TemplateCloser)) {
+ State.Stack.pop_back();
+ }
+ if (Current.is(tok::r_square)) {
+ // If this ends the array subscript expr, reset the corresponding value.
+ const FormatToken *NextNonComment = Current.getNextNonComment();
+ if (NextNonComment && NextNonComment->isNot(tok::l_square))
+ State.Stack.back().StartOfArraySubscripts = 0;
+ }
+}
+
+void ContinuationIndenter::moveStateToNewBlock(LineState &State) {
+ // If this is an l_brace starting a nested block, we pretend (wrt. to
+ // indentation) that we already consumed the corresponding r_brace. Thus, we
+ // remove all ParenStates caused by fake parentheses that end at the r_brace.
+ // The net effect of this is that we don't indent relative to the l_brace, if
+ // the nested block is the last parameter of a function. For example, this
+ // formats:
+ //
+ // SomeFunction(a, [] {
+ // f(); // break
+ // });
+ //
+ // instead of:
+ // SomeFunction(a, [] {
+ // f(); // break
+ // });
+ //
+ // If we have already found more than one lambda introducers on this level, we
+ // opt out of this because similarity between the lambdas is more important.
+ if (State.Stack.back().LambdasFound <= 1) {
+ for (unsigned i = 0; i != State.NextToken->MatchingParen->FakeRParens;
+ ++i) {
+ assert(State.Stack.size() > 1);
+ if (State.Stack.size() == 1) {
+ // Do not pop the last element.
+ break;
+ }
+ State.Stack.pop_back();
+ }
+ }
+
+ // For some reason, ObjC blocks are indented like continuations.
+ unsigned NewIndent = State.Stack.back().LastSpace +
+ (State.NextToken->Type == TT_ObjCBlockLBrace
+ ? Style.ContinuationIndentWidth
+ : Style.IndentWidth);
+ State.Stack.push_back(ParenState(
+ NewIndent, /*NewIndentLevel=*/State.Stack.back().IndentLevel + 1,
+ State.Stack.back().LastSpace, /*AvoidBinPacking=*/true,
+ State.Stack.back().NoLineBreak));
+ State.Stack.back().BreakBeforeParameter = true;
+}
+
unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
LineState &State) {
// Break before further function parameters on all levels.
@@ -806,8 +894,7 @@
return 0;
}
-static bool getRawStringLiteralPrefixPostfix(StringRef Text,
- StringRef &Prefix,
+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\"") ||
@@ -890,7 +977,7 @@
Current, State.Line->Level, StartColumn, Current.OriginalColumn,
!Current.Previous, State.Line->InPPDirective, Encoding, Style));
} else if (Current.Type == TT_LineComment &&
- (Current.Previous == NULL ||
+ (Current.Previous == nullptr ||
Current.Previous->Type != TT_ImplicitStringLiteral)) {
if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
return 0;
@@ -938,6 +1025,12 @@
break;
}
+ // When breaking before a tab character, it may be moved by a few columns,
+ // but will still be expanded to the next tab stop, so we don't save any
+ // columns.
+ if (NewRemainingTokenColumns == RemainingTokenColumns)
+ break;
+
assert(NewRemainingTokenColumns < RemainingTokenColumns);
if (!DryRun)
Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces);
@@ -979,7 +1072,7 @@
bool ContinuationIndenter::nextIsMultilineString(const LineState &State) {
const FormatToken &Current = *State.NextToken;
- if (!Current.isStringLiteral())
+ if (!Current.isStringLiteral() || Current.Type == TT_ImplicitStringLiteral)
return false;
// We never consider raw string literals "multiline" for the purpose of
// AlwaysBreakBeforeMultilineStrings implementation as they are special-cased
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
index 9a3c118..4733bda 100644
--- a/lib/Format/ContinuationIndenter.h
+++ b/lib/Format/ContinuationIndenter.h
@@ -73,6 +73,18 @@
/// accordingly.
unsigned moveStateToNextToken(LineState &State, bool DryRun, bool Newline);
+ /// \brief Update 'State' according to the next token's fake left parentheses.
+ void moveStatePastFakeLParens(LineState &State, bool Newline);
+ /// \brief Update 'State' according to the next token's fake r_parens.
+ void moveStatePastFakeRParens(LineState &State);
+
+ /// \brief Update 'State' according to the next token being one of "(<{[".
+ void moveStatePastScopeOpener(LineState &State, bool Newline);
+ /// \brief Update 'State' according to the next token being one of ")>}]".
+ void moveStatePastScopeCloser(LineState &State);
+ /// \brief Update 'State' with the next token opening a nested block.
+ void moveStateToNewBlock(LineState &State);
+
/// \brief If the current token sticks out over the end of the line, break
/// it if possible.
///
@@ -135,11 +147,12 @@
: Indent(Indent), IndentLevel(IndentLevel), LastSpace(LastSpace),
FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0),
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
- NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
- StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0),
- CallContinuation(0), VariablePos(0), ContainsLineBreak(false),
- ContainsUnwrappedBuilder(0), AlignColons(true),
- ObjCSelectorNameFound(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), LambdasFound(0),
+ JSFunctionInlined(false) {}
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
@@ -182,6 +195,10 @@
/// \brief Line breaking in this context would break a formatting rule.
bool NoLineBreak;
+ /// \brief True if the last binary operator on this level was wrapped to the
+ /// next line.
+ bool LastOperatorWrapped;
+
/// \brief The position of the colon in an ObjC method declaration/call.
unsigned ColonPos;
@@ -230,6 +247,16 @@
/// the same token.
bool ObjCSelectorNameFound;
+ /// \brief Counts the number of lambda introducers found on this level.
+ ///
+ /// Not considered for memoization as it will always have the same value at
+ /// the same token.
+ unsigned LambdasFound;
+
+ // \brief The previous JavaScript 'function' keyword is not wrapped to a new
+ // line.
+ bool JSFunctionInlined;
+
bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
@@ -247,6 +274,8 @@
return BreakBeforeParameter;
if (NoLineBreak != Other.NoLineBreak)
return NoLineBreak;
+ if (LastOperatorWrapped != Other.LastOperatorWrapped)
+ return LastOperatorWrapped;
if (ColonPos != Other.ColonPos)
return ColonPos < Other.ColonPos;
if (StartOfFunctionCall != Other.StartOfFunctionCall)
@@ -261,6 +290,8 @@
return ContainsLineBreak < Other.ContainsLineBreak;
if (ContainsUnwrappedBuilder != Other.ContainsUnwrappedBuilder)
return ContainsUnwrappedBuilder < Other.ContainsUnwrappedBuilder;
+ if (JSFunctionInlined != Other.JSFunctionInlined)
+ return JSFunctionInlined < Other.JSFunctionInlined;
return false;
}
};
@@ -278,13 +309,10 @@
/// \brief \c true if this line contains a continued for-loop section.
bool LineContainsContinuedForLoopSection;
- /// \brief The level of nesting inside (), [], <> and {}.
- unsigned ParenLevel;
-
- /// \brief The \c ParenLevel at the start of this line.
+ /// \brief The \c NestingLevel at the start of this line.
unsigned StartOfLineLevel;
- /// \brief The lowest \c ParenLevel on the current line.
+ /// \brief The lowest \c NestingLevel on the current line.
unsigned LowestLevelOnLine;
/// \brief The start column of the string literal, if we're in a string
@@ -327,8 +355,6 @@
if (LineContainsContinuedForLoopSection !=
Other.LineContainsContinuedForLoopSection)
return LineContainsContinuedForLoopSection;
- if (ParenLevel != Other.ParenLevel)
- return ParenLevel < Other.ParenLevel;
if (StartOfLineLevel != Other.StartOfLineLevel)
return StartOfLineLevel < Other.StartOfLineLevel;
if (LowestLevelOnLine != Other.LowestLevelOnLine)
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index cb07cb5..7d0e102 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -13,13 +13,12 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-formatter"
-
#include "ContinuationIndenter.h"
#include "TokenAnnotator.h"
#include "UnwrappedLineParser.h"
#include "WhitespaceManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
@@ -31,6 +30,8 @@
#include <queue>
#include <string>
+#define DEBUG_TYPE "format-formatter"
+
using clang::format::FormatStyle;
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
@@ -65,6 +66,16 @@
}
};
+template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
+ static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
+ IO.enumCase(Value, "None", FormatStyle::SFS_None);
+ IO.enumCase(Value, "false", FormatStyle::SFS_None);
+ IO.enumCase(Value, "All", FormatStyle::SFS_All);
+ IO.enumCase(Value, "true", FormatStyle::SFS_All);
+ IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
+ }
+};
+
template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) {
IO.enumCase(Value, "Attach", FormatStyle::BS_Attach);
@@ -140,6 +151,8 @@
IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
Style.AllowAllParametersOfDeclarationOnNextLine);
+ IO.mapOptional("AllowShortBlocksOnASingleLine",
+ Style.AllowShortBlocksOnASingleLine);
IO.mapOptional("AllowShortIfStatementsOnASingleLine",
Style.AllowShortIfStatementsOnASingleLine);
IO.mapOptional("AllowShortLoopsOnASingleLine",
@@ -202,7 +215,7 @@
Style.SpaceBeforeAssignmentOperators);
IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
IO.mapOptional("CommentPragmas", Style.CommentPragmas);
- IO.mapOptional("ForEachMacros", Style.ForEachMacros);
+ IO.mapOptional("ForEachMacros", Style.ForEachMacros);
// For backward compatibility.
if (!IO.outputting()) {
@@ -210,6 +223,7 @@
Style.SpaceBeforeParens);
}
IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
+ IO.mapOptional("DisableFormat", Style.DisableFormat);
}
};
@@ -230,7 +244,7 @@
if (Seq.size() > 0 && Seq[0].Language == FormatStyle::LK_None) {
Template = Seq[0];
} else {
- Template = *((const FormatStyle*)IO.getContext());
+ Template = *((const FormatStyle *)IO.getContext());
Template.Language = FormatStyle::LK_None;
}
Seq.resize(Index + 1, Template);
@@ -251,7 +265,8 @@
LLVMStyle.AlignEscapedNewlinesLeft = false;
LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
- LLVMStyle.AllowShortFunctionsOnASingleLine = true;
+ LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
+ LLVMStyle.AllowShortBlocksOnASingleLine = false;
LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
LLVMStyle.AllowShortLoopsOnASingleLine = false;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
@@ -300,6 +315,8 @@
LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
+ LLVMStyle.DisableFormat = false;
+
return LLVMStyle;
}
@@ -329,10 +346,11 @@
if (Language == FormatStyle::LK_JavaScript) {
GoogleStyle.BreakBeforeTernaryOperators = false;
- GoogleStyle.MaxEmptyLinesToKeep = 2;
+ GoogleStyle.MaxEmptyLinesToKeep = 3;
GoogleStyle.SpacesInContainerLiterals = false;
} else if (Language == FormatStyle::LK_Proto) {
- GoogleStyle.AllowShortFunctionsOnASingleLine = false;
+ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
+ GoogleStyle.SpacesInContainerLiterals = false;
}
return GoogleStyle;
@@ -341,6 +359,7 @@
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;
@@ -393,6 +412,12 @@
return Style;
}
+FormatStyle getNoStyle() {
+ FormatStyle NoStyle = getLLVMStyle();
+ NoStyle.DisableFormat = true;
+ return NoStyle;
+}
+
bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
FormatStyle *Style) {
if (Name.equals_lower("llvm")) {
@@ -407,6 +432,8 @@
*Style = getWebKitStyle();
} else if (Name.equals_lower("gnu")) {
*Style = getGNUStyle();
+ } else if (Name.equals_lower("none")) {
+ *Style = getNoStyle();
} else {
return false;
}
@@ -455,7 +482,7 @@
Styles[i].Language == FormatStyle::LK_None) {
*Style = Styles[i];
Style->Language = Language;
- return llvm::make_error_code(llvm::errc::success);
+ return llvm::error_code::success();
}
}
return llvm::make_error_code(llvm::errc::not_supported);
@@ -483,7 +510,7 @@
void format(unsigned FirstIndent, const AnnotatedLine *Line) {
LineState State =
Indenter->getInitialState(FirstIndent, Line, /*DryRun=*/false);
- while (State.NextToken != NULL) {
+ while (State.NextToken) {
bool Newline =
Indenter->mustBreak(State) ||
(Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0);
@@ -520,14 +547,19 @@
? 0
: Limit - TheLine->Last->TotalLength;
- if (I + 1 == E || I[1]->Type == LT_Invalid)
+ 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 Style.AllowShortFunctionsOnASingleLine
- ? tryMergeSimpleBlock(I, E, Limit)
- : 0;
+ return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
}
if (TheLine->Last->is(tok::l_brace)) {
return Style.BreakBeforeBraces == FormatStyle::BS_Attach
@@ -542,7 +574,7 @@
Limit -= 2;
unsigned MergedLines = 0;
- if (Style.AllowShortFunctionsOnASingleLine) {
+ 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.
@@ -591,7 +623,7 @@
return 0;
if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&
- I[1]->First->is(tok::l_brace))
+ (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))
return 0;
if (I[1]->InPPDirective != (*I)->InPPDirective ||
(I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
@@ -617,26 +649,45 @@
tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
unsigned Limit) {
- // First, check that the current line allows merging. This is the case if
- // we're not in a control flow statement and the last token is an opening
- // brace.
AnnotatedLine &Line = **I;
- if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace,
- tok::kw_else, tok::kw_try, tok::kw_catch,
- tok::kw_for,
- // This gets rid of all ObjC @ keywords and methods.
- tok::at, tok::minus, tok::plus))
+
+ // 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() == NULL ||
+ (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)) {
+ // 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;
@@ -647,18 +698,17 @@
// 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 || Tok->MustBreakBefore)
+ if (I[1]->Last->Type == TT_LineComment)
return 0;
do {
- if (Tok->isOneOf(tok::l_brace, tok::r_brace))
+ if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
return 0;
Tok = Tok->Next;
- } while (Tok != NULL);
+ } while (Tok);
- // Last, check that the third line contains a single closing brace.
+ // Last, check that the third line starts with a closing brace.
Tok = I[2]->First;
- if (Tok->getNextNonComment() != NULL || Tok->isNot(tok::r_brace) ||
- Tok->MustBreakBefore)
+ if (Tok->isNot(tok::r_brace))
return 0;
return 2;
@@ -681,6 +731,8 @@
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;
}
@@ -705,12 +757,19 @@
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 = NULL;
+ const AnnotatedLine *PreviousLine = nullptr;
for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),
E = Lines.end();
I != E; ++I) {
@@ -779,8 +838,10 @@
if (TheLine.Last->TotalLength + Indent <= ColumnLimit) {
LineState State = Indenter->getInitialState(Indent, &TheLine, DryRun);
- while (State.NextToken != NULL)
+ 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);
@@ -797,7 +858,7 @@
} else {
// Format the first token if necessary, and notify the WhitespaceManager
// about the unchanged whitespace.
- for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) {
+ for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
if (Tok == TheLine.First &&
(Tok->NewlinesBefore > 0 || Tok->IsFirst)) {
unsigned LevelIndent = Tok->OriginalColumn;
@@ -822,12 +883,13 @@
}
}
if (!DryRun) {
- for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) {
+ for (FormatToken *Tok = TheLine.First; Tok; Tok = Tok->Next) {
Tok->Finalized = true;
}
}
PreviousLine = *I;
}
+ PenaltyCache[CacheKey] = Penalty;
return Penalty;
}
@@ -897,6 +959,8 @@
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 &&
@@ -951,6 +1015,12 @@
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
@@ -960,7 +1030,7 @@
///
/// If \p DryRun is \c false, directly applies the changes.
unsigned analyzeSolutionSpace(LineState &InitialState, bool DryRun = false) {
- std::set<LineState> Seen;
+ 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.
@@ -969,7 +1039,7 @@
// Insert start element into queue.
StateNode *Node =
- new (Allocator.Allocate()) StateNode(InitialState, false, NULL);
+ new (Allocator.Allocate()) StateNode(InitialState, false, nullptr);
Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
++Count;
@@ -979,7 +1049,7 @@
while (!Queue.empty()) {
Penalty = Queue.top().first.first;
StateNode *Node = Queue.top().second;
- if (Node->State.NextToken == NULL) {
+ if (!Node->State.NextToken) {
DEBUG(llvm::dbgs() << "\n---\nPenalty for line: " << Penalty << "\n");
break;
}
@@ -990,7 +1060,7 @@
if (Count > 10000)
Node->State.IgnoreStackForComparison = true;
- if (!Seen.insert(Node->State).second)
+ if (!Seen.insert(&Node->State).second)
// State already examined with lower penalty.
continue;
@@ -1094,8 +1164,13 @@
return true;
if (NewLine) {
- int AdditionalIndent = State.Stack.back().Indent -
- Previous.Children[0]->Level * Style.IndentWidth;
+ int AdditionalIndent = 0;
+ 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;
@@ -1105,10 +1180,21 @@
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,
@@ -1127,27 +1213,37 @@
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(Lexer &Lex, SourceManager &SourceMgr, FormatStyle &Style,
encoding::Encoding Encoding)
- : FormatTok(NULL), IsFirstToken(true), GreaterStashed(false), Column(0),
- TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), Style(Style),
- IdentTable(getFormattingLangOpts()), Encoding(Encoding) {
+ : FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false),
+ Column(0), TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr),
+ Style(Style), IdentTable(getFormattingLangOpts()), Encoding(Encoding),
+ FirstInLineIndex(0) {
Lex.SetKeepWhitespaceMode(true);
- for (const std::string& ForEachMacro : Style.ForEachMacros)
+ for (const std::string &ForEachMacro : Style.ForEachMacros)
ForEachMacros.push_back(&IdentTable.get(ForEachMacro));
std::sort(ForEachMacros.begin(), ForEachMacros.end());
}
ArrayRef<FormatToken *> lex() {
assert(Tokens.empty());
+ assert(FirstInLineIndex == 0);
do {
Tokens.push_back(getNextToken());
tryMergePreviousTokens();
+ if (Tokens.back()->NewlinesBefore > 0)
+ FirstInLineIndex = Tokens.size() - 1;
} while (Tokens.back()->Tok.isNot(tok::eof));
return Tokens;
}
@@ -1158,12 +1254,20 @@
void tryMergePreviousTokens() {
if (tryMerge_TMacro())
return;
+ if (tryMergeConflictMarkers())
+ return;
if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (tryMergeEscapeSequence())
+ return;
+ if (tryMergeJSRegexLiteral())
+ 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 };
// FIXME: We probably need to change token type to mimic operator with the
// correct priority.
if (tryMergeTokens(JSIdentity))
@@ -1172,6 +1276,8 @@
return;
if (tryMergeTokens(JSShiftEqual))
return;
+ if (tryMergeTokens(JSRightArrow))
+ return;
}
}
@@ -1197,6 +1303,56 @@
return true;
}
+ // Tries to merge an escape sequence, i.e. a "\\" and the following
+ // character. Use e.g. inside JavaScript regex literals.
+ bool tryMergeEscapeSequence() {
+ if (Tokens.size() < 2)
+ return false;
+ FormatToken *Previous = Tokens[Tokens.size() - 2];
+ if (Previous->isNot(tok::unknown) || Previous->TokenText != "\\" ||
+ Tokens.back()->NewlinesBefore != 0)
+ return false;
+ Previous->ColumnWidth += Tokens.back()->ColumnWidth;
+ StringRef Text = Previous->TokenText;
+ Previous->TokenText =
+ StringRef(Text.data(), Text.size() + Tokens.back()->TokenText.size());
+ Tokens.resize(Tokens.size() - 1);
+ return true;
+ }
+
+ // Try to determine whether the current token ends a JavaScript regex literal.
+ // We heuristically assume that this is a regex literal if we find two
+ // unescaped slashes on a line and the token before the first slash is one of
+ // "(;,{}![:?", a binary operator or 'return', as those cannot be followed by
+ // a division.
+ bool tryMergeJSRegexLiteral() {
+ if (Tokens.size() < 2 || Tokens.back()->isNot(tok::slash) ||
+ (Tokens[Tokens.size() - 2]->is(tok::unknown) &&
+ Tokens[Tokens.size() - 2]->TokenText == "\\"))
+ return false;
+ unsigned TokenCount = 0;
+ unsigned LastColumn = Tokens.back()->OriginalColumn;
+ for (auto I = Tokens.rbegin() + 1, E = Tokens.rend(); I != E; ++I) {
+ ++TokenCount;
+ if (I[0]->is(tok::slash) && I + 1 != E &&
+ (I[1]->isOneOf(tok::l_paren, tok::semi, tok::l_brace, tok::r_brace,
+ tok::exclaim, tok::l_square, tok::colon, tok::comma,
+ tok::question, tok::kw_return) ||
+ I[1]->isBinaryOperator())) {
+ Tokens.resize(Tokens.size() - TokenCount);
+ Tokens.back()->Tok.setKind(tok::unknown);
+ Tokens.back()->Type = TT_RegexLiteral;
+ Tokens.back()->ColumnWidth += LastColumn - I[0]->OriginalColumn;
+ return true;
+ }
+
+ // There can't be a newline inside a regex literal.
+ if (I[0]->NewlinesBefore > 0)
+ return false;
+ }
+ return false;
+ }
+
bool tryMerge_TMacro() {
if (Tokens.size() < 4)
return false;
@@ -1232,6 +1388,68 @@
return true;
}
+ bool tryMergeConflictMarkers() {
+ if (Tokens.back()->NewlinesBefore == 0 && Tokens.back()->isNot(tok::eof))
+ return false;
+
+ // Conflict lines look like:
+ // <marker> <text from the vcs>
+ // For example:
+ // >>>>>>> /file/in/file/system at revision 1234
+ //
+ // We merge all tokens in a line that starts with a conflict marker
+ // into a single token with a special token type that the unwrapped line
+ // parser will use to correctly rebuild the underlying code.
+
+ FileID ID;
+ // Get the position of the first token in the line.
+ unsigned FirstInLineOffset;
+ std::tie(ID, FirstInLineOffset) = SourceMgr.getDecomposedLoc(
+ Tokens[FirstInLineIndex]->getStartOfNonWhitespace());
+ StringRef Buffer = SourceMgr.getBuffer(ID)->getBuffer();
+ // Calculate the offset of the start of the current line.
+ auto LineOffset = Buffer.rfind('\n', FirstInLineOffset);
+ if (LineOffset == StringRef::npos) {
+ LineOffset = 0;
+ } else {
+ ++LineOffset;
+ }
+
+ auto FirstSpace = Buffer.find_first_of(" \n", LineOffset);
+ StringRef LineStart;
+ if (FirstSpace == StringRef::npos) {
+ LineStart = Buffer.substr(LineOffset);
+ } else {
+ LineStart = Buffer.substr(LineOffset, FirstSpace - LineOffset);
+ }
+
+ TokenType Type = TT_Unknown;
+ if (LineStart == "<<<<<<<" || LineStart == ">>>>") {
+ Type = TT_ConflictStart;
+ } else if (LineStart == "|||||||" || LineStart == "=======" ||
+ LineStart == "====") {
+ Type = TT_ConflictAlternative;
+ } else if (LineStart == ">>>>>>>" || LineStart == "<<<<") {
+ Type = TT_ConflictEnd;
+ }
+
+ if (Type != TT_Unknown) {
+ FormatToken *Next = Tokens.back();
+
+ Tokens.resize(FirstInLineIndex + 1);
+ // We do not need to build a complete token here, as we will skip it
+ // during parsing anyway (as we must not touch whitespace around conflict
+ // markers).
+ Tokens.back()->Type = Type;
+ Tokens.back()->Tok.setKind(tok::kw___unknown_anytype);
+
+ Tokens.push_back(Next);
+ return true;
+ }
+
+ return false;
+ }
+
FormatToken *getNextToken() {
if (GreaterStashed) {
// Create a synthesized second '>' token.
@@ -1309,7 +1527,7 @@
// FIXME: Add a more explicit test.
while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\' &&
FormatTok->TokenText[1] == '\n') {
- // FIXME: ++FormatTok->NewlinesBefore is missing...
+ ++FormatTok->NewlinesBefore;
WhitespaceLength += 2;
Column = 0;
FormatTok->TokenText = FormatTok->TokenText.substr(2);
@@ -1379,8 +1597,10 @@
IdentifierTable IdentTable;
encoding::Encoding Encoding;
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
+ // Index (in 'Tokens') of the last token that starts a new line.
+ unsigned FirstInLineIndex;
SmallVector<FormatToken *, 16> Tokens;
- SmallVector<IdentifierInfo*, 8> ForEachMacros;
+ SmallVector<IdentifierInfo *, 8> ForEachMacros;
void readRawToken(FormatToken &Tok) {
Lex.LexFromRawLexer(Tok.Tok);
@@ -1489,7 +1709,7 @@
bool computeAffectedLines(SmallVectorImpl<AnnotatedLine *>::iterator I,
SmallVectorImpl<AnnotatedLine *>::iterator E) {
bool SomeLineAffected = false;
- const AnnotatedLine *PreviousLine = NULL;
+ const AnnotatedLine *PreviousLine = nullptr;
while (I != E) {
AnnotatedLine *Line = *I;
Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
@@ -1559,11 +1779,10 @@
bool LineMoved = PreviousLine && PreviousLine->Affected &&
Line->First->NewlinesBefore == 0;
- bool IsContinuedComment = Line->First->is(tok::comment) &&
- Line->First->Next == NULL &&
- Line->First->NewlinesBefore < 2 && PreviousLine &&
- PreviousLine->Affected &&
- PreviousLine->Last->is(tok::comment);
+ bool IsContinuedComment =
+ Line->First->is(tok::comment) && Line->First->Next == nullptr &&
+ Line->First->NewlinesBefore < 2 && PreviousLine &&
+ PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
IsContinuedComment) {
@@ -1701,6 +1920,11 @@
tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
SourceManager &SourceMgr,
std::vector<CharSourceRange> Ranges) {
+ if (Style.DisableFormat) {
+ tooling::Replacements EmptyResult;
+ return EmptyResult;
+ }
+
Formatter formatter(Style, Lex, SourceMgr, Ranges);
return formatter.format();
}
@@ -1735,7 +1959,9 @@
LangOptions LangOpts;
LangOpts.CPlusPlus = 1;
LangOpts.CPlusPlus11 = Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
+ LangOpts.CPlusPlus1y = Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.LineComment = 1;
+ LangOpts.CXXOperatorNames = 1;
LangOpts.Bool = 1;
LangOpts.ObjC1 = 1;
LangOpts.ObjC2 = 1;
diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp
index c147dbb..c91d25f 100644
--- a/lib/Format/FormatToken.cpp
+++ b/lib/Format/FormatToken.cpp
@@ -64,16 +64,15 @@
// Ensure that we start on the opening brace.
const FormatToken *LBrace = State.NextToken->Previous->Previous;
- if (LBrace->isNot(tok::l_brace) ||
- LBrace->BlockKind == BK_Block ||
+ if (LBrace->isNot(tok::l_brace) || LBrace->BlockKind == BK_Block ||
LBrace->Type == TT_DictLiteral ||
LBrace->Next->Type == TT_DesignatedInitializerPeriod)
return 0;
// Calculate the number of code points we have to format this list. As the
// first token is already placed, we have to subtract it.
- unsigned RemainingCodePoints = Style.ColumnLimit - State.Column +
- State.NextToken->Previous->ColumnWidth;
+ unsigned RemainingCodePoints =
+ Style.ColumnLimit - State.Column + State.NextToken->Previous->ColumnWidth;
// Find the best ColumnFormat, i.e. the best number of columns to use.
const ColumnFormat *Format = getColumnFormat(RemainingCodePoints);
@@ -132,6 +131,11 @@
if (!Token->MatchingParen || Token->isNot(tok::l_brace))
return;
+ // In C++11 braced list style, we should not format in columns unless we allow
+ // bin-packing of function parameters.
+ if (Style.Cpp11BracedListStyle && !Style.BinPackParameters)
+ return;
+
FormatToken *ItemBegin = Token->Next;
SmallVector<bool, 8> MustBreakBeforeItem;
@@ -147,7 +151,7 @@
MustBreakBeforeItem.push_back(ItemBegin->MustBreakBefore);
if (ItemBegin->is(tok::l_brace))
HasNestedBracedList = true;
- const FormatToken *ItemEnd = NULL;
+ const FormatToken *ItemEnd = nullptr;
if (i == Commas.size()) {
ItemEnd = Token->MatchingParen;
const FormatToken *NonCommentEnd = ItemEnd->getPreviousNonComment();
@@ -181,8 +185,7 @@
// If this doesn't have a nested list, we require at least 6 elements in order
// create a column layout. If it has a nested list, column layout ensures one
// list element per line.
- if (HasNestedBracedList || Commas.size() < 5 ||
- Token->NestingLevel != 0)
+ if (HasNestedBracedList || Commas.size() < 5 || Token->NestingLevel != 0)
return;
// We can never place more than ColumnLimit / 3 items in a row (because of the
@@ -204,8 +207,7 @@
HasRowWithSufficientColumns = true;
unsigned length =
(Column == Columns - 1) ? EndOfLineItemLength[i] : ItemLengths[i];
- Format.ColumnSizes[Column] =
- std::max(Format.ColumnSizes[Column], length);
+ Format.ColumnSizes[Column] = std::max(Format.ColumnSizes[Column], length);
++Column;
}
// If all rows are terminated early (e.g. by trailing comments), we don't
@@ -227,7 +229,7 @@
const CommaSeparatedList::ColumnFormat *
CommaSeparatedList::getColumnFormat(unsigned RemainingCharacters) const {
- const ColumnFormat *BestFormat = NULL;
+ const ColumnFormat *BestFormat = nullptr;
for (SmallVector<ColumnFormat, 4>::const_reverse_iterator
I = Formats.rbegin(),
E = Formats.rend();
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index a5aaa6f..f2bba32 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -33,19 +33,22 @@
TT_BlockComment,
TT_CastRParen,
TT_ConditionalExpr,
+ TT_ConflictAlternative,
+ TT_ConflictEnd,
+ TT_ConflictStart,
TT_CtorInitializerColon,
TT_CtorInitializerComma,
TT_DesignatedInitializerPeriod,
TT_DictLiteral,
- TT_ImplicitStringLiteral,
- TT_InlineASMColon,
- TT_InheritanceColon,
TT_FunctionLBrace,
TT_FunctionTypeLParen,
+ TT_ImplicitStringLiteral,
+ TT_InheritanceColon,
+ TT_InlineASMColon,
TT_LambdaLSquare,
TT_LineComment,
- TT_ObjCBlockLParen,
TT_ObjCBlockLBrace,
+ TT_ObjCBlockLParen,
TT_ObjCDecl,
TT_ObjCForIn,
TT_ObjCMethodExpr,
@@ -57,6 +60,7 @@
TT_PointerOrReference,
TT_PureVirtualSpecifier,
TT_RangeBasedForLoopColon,
+ TT_RegexLiteral,
TT_StartOfName,
TT_TemplateCloser,
TT_TemplateOpener,
@@ -103,8 +107,9 @@
UnbreakableTailLength(0), BindingStrength(0), NestingLevel(0),
SplitPenalty(0), LongestObjCSelectorName(0), FakeRParens(0),
StartsBinaryExpression(false), EndsBinaryExpression(false),
- LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false),
- IsForEachMacro(false), MatchingParen(NULL), Previous(NULL), Next(NULL),
+ OperatorIndex(0), LastOperator(false),
+ PartOfMultiVariableDeclStmt(false), IsForEachMacro(false),
+ MatchingParen(nullptr), Previous(nullptr), Next(nullptr),
Decision(FD_Unformatted), Finalized(false) {}
/// \brief The \c Token.
@@ -239,8 +244,13 @@
/// \brief \c true if this token ends a binary expression.
bool EndsBinaryExpression;
- /// \brief Is this the last "." or "->" in a builder-type call?
- bool LastInChainOfCalls;
+ /// \brief Is this is an operator (or "."/"->") in a sequence of operators
+ /// with the same precedence, contains the 0-based operator index.
+ unsigned OperatorIndex;
+
+ /// \brief Is this the last operator (or "."/"->") in a sequence of operators
+ /// with the same precedence?
+ bool LastOperator;
/// \brief Is this token part of a \c DeclStmt defining multiple variables?
///
@@ -344,7 +354,7 @@
/// \brief Returns the previous token ignoring comments.
FormatToken *getPreviousNonComment() const {
FormatToken *Tok = Previous;
- while (Tok != NULL && Tok->is(tok::comment))
+ while (Tok && Tok->is(tok::comment))
Tok = Tok->Previous;
return Tok;
}
@@ -352,7 +362,7 @@
/// \brief Returns the next token ignoring comments.
const FormatToken *getNextNonComment() const {
const FormatToken *Tok = Next;
- while (Tok != NULL && Tok->is(tok::comment))
+ while (Tok && Tok->is(tok::comment))
Tok = Tok->Next;
return Tok;
}
@@ -445,7 +455,9 @@
bool DryRun) override;
/// \brief Adds \p Token as the next comma to the \c CommaSeparated list.
- void CommaFound(const FormatToken *Token) override { Commas.push_back(Token);}
+ void CommaFound(const FormatToken *Token) override {
+ Commas.push_back(Token);
+ }
private:
/// \brief A struct that holds information on how to format a given list with
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 0034235..3fea52b 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -17,6 +17,8 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "format-token-annotator"
+
namespace clang {
namespace format {
@@ -39,7 +41,7 @@
private:
bool parseAngle() {
- if (CurrentToken == NULL)
+ if (!CurrentToken)
return false;
ScopedContextCreator ContextCreator(*this, tok::less, 10);
FormatToken *Left = CurrentToken->Previous;
@@ -47,9 +49,9 @@
// If there's a template keyword before the opening angle bracket, this is a
// template parameter, not an argument.
Contexts.back().InTemplateArgument =
- Left->Previous != NULL && Left->Previous->Tok.isNot(tok::kw_template);
+ Left->Previous && Left->Previous->Tok.isNot(tok::kw_template);
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->is(tok::greater)) {
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
@@ -83,7 +85,7 @@
}
bool parseParens(bool LookForDecls = false) {
- if (CurrentToken == NULL)
+ if (!CurrentToken)
return false;
ScopedContextCreator ContextCreator(*this, tok::l_paren, 1);
@@ -110,6 +112,11 @@
Left->Previous->Type == 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))) {
+ Contexts.back().IsExpression = true;
} else if (Left->Previous && Left->Previous->is(tok::r_square) &&
Left->Previous->MatchingParen &&
Left->Previous->MatchingParen->Type == TT_LambdaLSquare) {
@@ -134,7 +141,7 @@
bool MightBeFunctionType = CurrentToken->is(tok::star);
bool HasMultipleLines = false;
bool HasMultipleParametersOnALine = false;
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
// LookForDecls is set when "if (" has been seen. Check for
// 'identifier' '*' 'identifier' followed by not '=' -- this
// '*' has to be a binary operator but determineStarAmpUsage() will
@@ -168,7 +175,7 @@
if (StartsObjCMethodExpr) {
CurrentToken->Type = TT_ObjCMethodExpr;
- if (Contexts.back().FirstObjCSelectorName != NULL) {
+ if (Contexts.back().FirstObjCSelectorName) {
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
}
@@ -218,6 +225,7 @@
FormatToken *Parent = Left->getPreviousNonComment();
bool StartsObjCMethodExpr =
Contexts.back().CanBeExpression && Left->Type != 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 ||
@@ -236,7 +244,7 @@
Left->Type = TT_ArraySubscriptLSquare;
}
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->is(tok::r_square)) {
if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) &&
Left->Type == TT_ObjCMethodExpr) {
@@ -245,17 +253,17 @@
StartsObjCMethodExpr = false;
Left->Type = TT_Unknown;
}
- if (StartsObjCMethodExpr) {
+ if (StartsObjCMethodExpr && CurrentToken->Previous != Left) {
CurrentToken->Type = TT_ObjCMethodExpr;
// determineStarAmpUsage() thinks that '*' '[' is allocating an
// array of pointers, but if '[' starts a selector then '*' is a
// binary operator.
- if (Parent != NULL && Parent->Type == TT_PointerOrReference)
+ if (Parent && Parent->Type == TT_PointerOrReference)
Parent->Type = TT_BinaryOperator;
}
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
- if (Contexts.back().FirstObjCSelectorName != NULL) {
+ if (Contexts.back().FirstObjCSelectorName) {
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
if (Contexts.back().NumBlockParameters > 1)
@@ -281,7 +289,7 @@
}
bool parseBrace() {
- if (CurrentToken != NULL) {
+ if (CurrentToken) {
FormatToken *Left = CurrentToken->Previous;
if (Contexts.back().CaretFound)
@@ -290,8 +298,10 @@
ScopedContextCreator ContextCreator(*this, tok::l_brace, 1);
Contexts.back().ColonIsDictLiteral = true;
+ if (Left->BlockKind == BK_BracedInit)
+ Contexts.back().IsExpression = true;
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->is(tok::r_brace)) {
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
@@ -325,7 +335,7 @@
}
bool parseConditional() {
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->is(tok::colon)) {
CurrentToken->Type = TT_ConditionalExpr;
next();
@@ -338,12 +348,12 @@
}
bool parseTemplateDeclaration() {
- if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
+ if (CurrentToken && CurrentToken->is(tok::less)) {
CurrentToken->Type = TT_TemplateOpener;
next();
if (!parseAngle())
return false;
- if (CurrentToken != NULL)
+ if (CurrentToken)
CurrentToken->Previous->ClosesTemplateDeclaration = true;
return true;
}
@@ -356,14 +366,15 @@
switch (Tok->Tok.getKind()) {
case tok::plus:
case tok::minus:
- if (Tok->Previous == NULL && Line.MustBeDeclaration)
+ if (!Tok->Previous && Line.MustBeDeclaration)
Tok->Type = TT_ObjCMethodSpecifier;
break;
case tok::colon:
- if (Tok->Previous == NULL)
+ if (!Tok->Previous)
return false;
// Colons from ?: are handled in parseConditional().
- if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1) {
+ 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) {
Tok->Type = TT_DictLiteral;
@@ -375,12 +386,11 @@
Contexts.back().LongestObjCSelectorName) {
Contexts.back().LongestObjCSelectorName = Tok->Previous->ColumnWidth;
}
- if (Contexts.back().FirstObjCSelectorName == NULL)
+ if (!Contexts.back().FirstObjCSelectorName)
Contexts.back().FirstObjCSelectorName = Tok->Previous;
} else if (Contexts.back().ColonIsForRangeExpr) {
Tok->Type = TT_RangeBasedForLoopColon;
- } else if (CurrentToken != NULL &&
- CurrentToken->is(tok::numeric_constant)) {
+ } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) {
Tok->Type = TT_BitFieldColon;
} else if (Contexts.size() == 1 && Line.First->isNot(tok::kw_enum)) {
Tok->Type = TT_InheritanceColon;
@@ -390,7 +400,7 @@
break;
case tok::kw_if:
case tok::kw_while:
- if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
+ if (CurrentToken && CurrentToken->is(tok::l_paren)) {
next();
if (!parseParens(/*LookForDecls=*/true))
return false;
@@ -406,7 +416,9 @@
if (!parseParens())
return false;
if (Line.MustBeDeclaration && Contexts.size() == 1 &&
- !Contexts.back().IsExpression && Line.First->Type != TT_ObjCProperty)
+ !Contexts.back().IsExpression &&
+ Line.First->Type != TT_ObjCProperty &&
+ (!Tok->Previous || Tok->Previous->isNot(tok::kw_decltype)))
Line.MightBeFunctionDecl = true;
break;
case tok::l_square:
@@ -431,7 +443,7 @@
return false;
case tok::r_brace:
// Lines can start with '}'.
- if (Tok->Previous != NULL)
+ if (Tok->Previous)
return false;
break;
case tok::greater:
@@ -479,15 +491,15 @@
void parseIncludeDirective() {
next();
- if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
+ if (CurrentToken && CurrentToken->is(tok::less)) {
next();
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->isNot(tok::comment) || CurrentToken->Next)
CurrentToken->Type = TT_ImplicitStringLiteral;
next();
}
} else {
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->is(tok::string_literal))
// Mark these string literals as "implicit" literals, too, so that
// they are not split or line-wrapped.
@@ -502,7 +514,7 @@
// We still want to format the whitespace left of the first token of the
// warning or error.
next();
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
CurrentToken->Type = TT_ImplicitStringLiteral;
next();
}
@@ -513,7 +525,7 @@
if (CurrentToken && CurrentToken->TokenText == "mark") {
next(); // Consume "mark".
next(); // Consume first token (so we fix leading whitespace).
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
CurrentToken->Type = TT_ImplicitStringLiteral;
next();
}
@@ -522,7 +534,7 @@
void parsePreprocessorDirective() {
next();
- if (CurrentToken == NULL)
+ if (!CurrentToken)
return;
if (CurrentToken->Tok.is(tok::numeric_constant)) {
CurrentToken->SpacesRequiredBefore = 1;
@@ -530,7 +542,7 @@
}
// Hashes in the middle of a line can lead to any strange token
// sequence.
- if (CurrentToken->Tok.getIdentifierInfo() == NULL)
+ if (!CurrentToken->Tok.getIdentifierInfo())
return;
switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
@@ -552,7 +564,7 @@
default:
break;
}
- while (CurrentToken != NULL)
+ while (CurrentToken)
next();
}
@@ -571,7 +583,7 @@
CurrentToken->Next && CurrentToken->Next->is(tok::string_literal))
parseIncludeDirective();
- while (CurrentToken != NULL) {
+ while (CurrentToken) {
if (CurrentToken->is(tok::kw_virtual))
KeywordVirtualFound = true;
if (!consumeToken())
@@ -581,7 +593,7 @@
return LT_VirtualFunctionDecl;
if (Line.First->Type == TT_ObjCMethodSpecifier) {
- if (Contexts.back().FirstObjCSelectorName != NULL)
+ if (Contexts.back().FirstObjCSelectorName)
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
return LT_ObjCMethodDecl;
@@ -592,30 +604,30 @@
private:
void resetTokenMetadata(FormatToken *Token) {
- if (Token == nullptr) return;
+ 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)
CurrentToken->Type = TT_Unknown;
if (CurrentToken->Role)
- CurrentToken->Role.reset(NULL);
+ CurrentToken->Role.reset(nullptr);
CurrentToken->FakeLParens.clear();
CurrentToken->FakeRParens = 0;
}
void next() {
- if (CurrentToken != NULL) {
+ if (CurrentToken) {
determineTokenType(*CurrentToken);
CurrentToken->BindingStrength = Contexts.back().BindingStrength;
CurrentToken->NestingLevel = Contexts.size() - 1;
- }
-
- if (CurrentToken != NULL)
CurrentToken = CurrentToken->Next;
+ }
resetTokenMetadata(CurrentToken);
}
@@ -628,8 +640,8 @@
: ContextKind(ContextKind), BindingStrength(BindingStrength),
LongestObjCSelectorName(0), NumBlockParameters(0),
ColonIsForRangeExpr(false), ColonIsDictLiteral(false),
- ColonIsObjCMethodExpr(false), FirstObjCSelectorName(NULL),
- FirstStartOfName(NULL), IsExpression(IsExpression),
+ ColonIsObjCMethodExpr(false), FirstObjCSelectorName(nullptr),
+ FirstStartOfName(nullptr), IsExpression(IsExpression),
CanBeExpression(true), InTemplateArgument(false),
InCtorInitializer(false), CaretFound(false), IsForEachMacro(false) {}
@@ -674,7 +686,7 @@
for (FormatToken *Previous = Current.Previous;
Previous && !Previous->isOneOf(tok::comma, tok::semi);
Previous = Previous->Previous) {
- if (Previous->is(tok::r_square))
+ if (Previous->isOneOf(tok::r_square, tok::r_paren))
Previous = Previous->MatchingParen;
if (Previous->Type == TT_BinaryOperator &&
Previous->isOneOf(tok::star, tok::amp)) {
@@ -684,7 +696,9 @@
} else if (Current.isOneOf(tok::kw_return, tok::kw_throw)) {
Contexts.back().IsExpression = true;
} else if (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
- !Line.InPPDirective) {
+ !Line.InPPDirective &&
+ (!Current.Previous ||
+ Current.Previous->isNot(tok::kw_decltype))) {
bool ParametersOfFunctionType =
Current.Previous && Current.Previous->is(tok::r_paren) &&
Current.Previous->MatchingParen &&
@@ -727,15 +741,16 @@
Contexts.back().InTemplateArgument);
} else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
Current.Type = determinePlusMinusCaretUsage(Current);
- if (Current.Type == TT_UnaryOperator) {
+ if (Current.Type == TT_UnaryOperator && Current.is(tok::caret)) {
++Contexts.back().NumBlockParameters;
- if (Current.is(tok::caret))
- Contexts.back().CaretFound = true;
+ Contexts.back().CaretFound = true;
}
} else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
Current.Type = determineIncrementUsage(Current);
} else if (Current.is(tok::exclaim)) {
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))) {
@@ -746,40 +761,7 @@
else
Current.Type = TT_BlockComment;
} else if (Current.is(tok::r_paren)) {
- FormatToken *LeftOfParens = NULL;
- if (Current.MatchingParen)
- LeftOfParens = Current.MatchingParen->getPreviousNonComment();
- bool IsCast = false;
- bool ParensAreEmpty = Current.Previous == Current.MatchingParen;
- bool ParensAreType = !Current.Previous ||
- Current.Previous->Type == TT_PointerOrReference ||
- Current.Previous->Type == TT_TemplateCloser ||
- Current.Previous->isSimpleTypeSpecifier();
- bool ParensCouldEndDecl =
- Current.Next &&
- Current.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) ||
- (Current.Next && Current.Next->isBinaryOperator())))
- IsCast = true;
- if (Current.Next && Current.Next->isNot(tok::string_literal) &&
- (Current.Next->Tok.isLiteral() ||
- Current.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof)))
- IsCast = true;
- // If there is an identifier after the (), it is likely a cast, unless
- // there is also an identifier before the ().
- if (LeftOfParens && (LeftOfParens->Tok.getIdentifierInfo() == NULL ||
- LeftOfParens->is(tok::kw_return)) &&
- LeftOfParens->Type != TT_OverloadedOperator &&
- LeftOfParens->isNot(tok::at) &&
- LeftOfParens->Type != TT_TemplateCloser && Current.Next &&
- Current.Next->is(tok::identifier))
- IsCast = true;
- if (IsCast && !ParensAreEmpty)
+ if (rParenEndsCast(Current))
Current.Type = TT_CastRParen;
} else if (Current.is(tok::at) && Current.Next) {
switch (Current.Next->Tok.getObjCKeywordID()) {
@@ -800,6 +782,7 @@
PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
Current.Type = TT_DesignatedInitializerPeriod;
} else if (Current.isOneOf(tok::identifier, tok::kw_const) &&
+ Current.Previous && Current.Previous->isNot(tok::equal) &&
Line.MightBeFunctionDecl && Contexts.size() == 1) {
// Line.MightBeFunctionDecl can only be true after the parentheses of a
// function declaration have been found.
@@ -814,15 +797,15 @@
/// This is a heuristic based on whether \p Tok is an identifier following
/// something that is likely a type.
bool isStartOfName(const FormatToken &Tok) {
- if (Tok.isNot(tok::identifier) || Tok.Previous == NULL)
+ if (Tok.isNot(tok::identifier) || !Tok.Previous)
return false;
// Skip "const" as it does not have an influence on whether this is a name.
FormatToken *PreviousNotConst = Tok.Previous;
- while (PreviousNotConst != NULL && PreviousNotConst->is(tok::kw_const))
+ while (PreviousNotConst && PreviousNotConst->is(tok::kw_const))
PreviousNotConst = PreviousNotConst->Previous;
- if (PreviousNotConst == NULL)
+ if (!PreviousNotConst)
return false;
bool IsPPKeyword = PreviousNotConst->is(tok::identifier) &&
@@ -834,20 +817,81 @@
PreviousNotConst->MatchingParen->Previous &&
PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template);
+ if (PreviousNotConst->is(tok::r_paren) && PreviousNotConst->MatchingParen &&
+ PreviousNotConst->MatchingParen->Previous &&
+ PreviousNotConst->MatchingParen->Previous->is(tok::kw_decltype))
+ return true;
+
return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) ||
PreviousNotConst->Type == TT_PointerOrReference ||
PreviousNotConst->isSimpleTypeSpecifier();
}
+ /// \brief Determine whether ')' is ending a cast.
+ bool rParenEndsCast(const FormatToken &Tok) {
+ FormatToken *LeftOfParens = NULL;
+ if (Tok.MatchingParen)
+ LeftOfParens = Tok.MatchingParen->getPreviousNonComment();
+ 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();
+ 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())))
+ IsCast = true;
+ else if (Tok.Next && Tok.Next->isNot(tok::string_literal) &&
+ (Tok.Next->Tok.isLiteral() ||
+ Tok.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof)))
+ 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 && (LeftOfParens->Tok.getIdentifierInfo() == NULL ||
+ LeftOfParens->is(tok::kw_return)) &&
+ LeftOfParens->Type != TT_OverloadedOperator &&
+ LeftOfParens->isNot(tok::at) &&
+ LeftOfParens->Type != TT_TemplateCloser && Tok.Next) {
+ if (Tok.Next->isOneOf(tok::identifier, tok::numeric_constant)) {
+ IsCast = true;
+ } else {
+ // Use heuristics to recognize c style casting.
+ FormatToken *Prev = Tok.Previous;
+ if (Prev && Prev->isOneOf(tok::amp, tok::star))
+ Prev = Prev->Previous;
+
+ if (Prev && Tok.Next && Tok.Next->Next) {
+ bool NextIsUnary = Tok.Next->isUnaryOperator() ||
+ Tok.Next->isOneOf(tok::amp, tok::star);
+ IsCast = NextIsUnary && Tok.Next->Next->isOneOf(
+ tok::identifier, tok::numeric_constant);
+ }
+
+ for (; Prev != Tok.MatchingParen; Prev = Prev->Previous) {
+ if (!Prev || !Prev->isOneOf(tok::kw_const, tok::identifier)) {
+ IsCast = false;
+ break;
+ }
+ }
+ }
+ }
+ return IsCast && !ParensAreEmpty;
+ }
+
/// \brief Return the type of the given token assuming it is * or &.
TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression,
bool InTemplateArgument) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
- if (PrevToken == NULL)
+ if (!PrevToken)
return TT_UnaryOperator;
const FormatToken *NextToken = Tok.getNextNonComment();
- if (NextToken == NULL)
+ if (!NextToken)
return TT_Unknown;
if (PrevToken->is(tok::coloncolon) ||
@@ -858,10 +902,11 @@
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)
return TT_UnaryOperator;
- if (NextToken->is(tok::l_square))
+ if (NextToken->is(tok::l_square) && NextToken->Type != TT_LambdaLSquare)
return TT_PointerOrReference;
if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen &&
@@ -891,7 +936,7 @@
TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
- if (PrevToken == NULL || PrevToken->Type == TT_CastRParen)
+ if (!PrevToken || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
// Use heuristics to recognize unary operators.
@@ -911,7 +956,7 @@
/// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
TokenType determineIncrementUsage(const FormatToken &Tok) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
- if (PrevToken == NULL || PrevToken->Type == TT_CastRParen)
+ if (!PrevToken || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier))
return TT_TrailingUnaryOperator;
@@ -919,7 +964,6 @@
return TT_UnaryOperator;
}
-
SmallVector<Context, 8> Contexts;
const FormatStyle &Style;
@@ -952,7 +996,7 @@
(Current->is(tok::colon) && Current->Type == TT_ObjCMethodExpr)))
next();
- if (Current == NULL || Precedence > PrecedenceArrowAndPeriod)
+ if (!Current || Precedence > PrecedenceArrowAndPeriod)
return;
// Conditional expressions need to be parsed separately for proper nesting.
@@ -969,7 +1013,8 @@
}
FormatToken *Start = Current;
- FormatToken *LatestOperator = NULL;
+ FormatToken *LatestOperator = nullptr;
+ unsigned OperatorIndex = 0;
while (Current) {
// Consume operators with higher precedence.
@@ -986,11 +1031,11 @@
// At the end of the line or when an operator with higher precedence is
// found, insert fake parenthesis and return.
- if (Current == NULL || Current->closesScope() ||
+ if (!Current || Current->closesScope() ||
(CurrentPrecedence != -1 && CurrentPrecedence < Precedence)) {
if (LatestOperator) {
+ LatestOperator->LastOperator = true;
if (Precedence == PrecedenceArrowAndPeriod) {
- LatestOperator->LastInChainOfCalls = true;
// Call expressions don't have a binary operator precedence.
addFakeParenthesis(Start, prec::Unknown);
} else {
@@ -1009,8 +1054,11 @@
next();
} else {
// Operator found.
- if (CurrentPrecedence == Precedence)
+ if (CurrentPrecedence == Precedence) {
LatestOperator = Current;
+ Current->OperatorIndex = OperatorIndex;
+ ++OperatorIndex;
+ }
next();
}
@@ -1051,7 +1099,7 @@
/// \brief Parse unary operator expressions and surround them with fake
/// parentheses if appropriate.
void parseUnaryOperator() {
- if (Current == NULL || Current->Type != TT_UnaryOperator) {
+ if (!Current || Current->Type != TT_UnaryOperator) {
parse(PrecedenceArrowAndPeriod);
return;
}
@@ -1092,15 +1140,15 @@
void
TokenAnnotator::setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) {
- const AnnotatedLine *NextNonCommentLine = NULL;
+ const AnnotatedLine *NextNonCommentLine = nullptr;
for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(),
E = Lines.rend();
I != E; ++I) {
if (NextNonCommentLine && (*I)->First->is(tok::comment) &&
- (*I)->First->Next == NULL)
+ (*I)->First->Next == nullptr)
(*I)->Level = NextNonCommentLine->Level;
else
- NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : NULL;
+ NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr;
setCommentLineLevels((*I)->Children);
}
@@ -1132,13 +1180,19 @@
}
void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
+ for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
+ E = Line.Children.end();
+ I != E; ++I) {
+ calculateFormattingInformation(**I);
+ }
+
Line.First->TotalLength =
Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth;
if (!Line.First->Next)
return;
FormatToken *Current = Line.First->Next;
bool InFunctionDecl = Line.MightBeFunctionDecl;
- while (Current != NULL) {
+ while (Current) {
if (Current->Type == TT_LineComment) {
if (Current->Previous->BlockKind == BK_BracedInit &&
Current->Previous->opensScope())
@@ -1167,7 +1221,7 @@
}
}
} else if (Current->SpacesRequiredBefore == 0 &&
- spaceRequiredBefore(Line, *Current)) {
+ spaceRequiredBefore(Line, *Current)) {
Current->SpacesRequiredBefore = 1;
}
@@ -1176,12 +1230,18 @@
Current->CanBreakBefore =
Current->MustBreakBefore || canBreakBefore(Line, *Current);
- if (Current->MustBreakBefore || !Current->Children.empty() ||
+ unsigned ChildSize = 0;
+ if (Current->Previous->Children.size() == 1) {
+ FormatToken &LastOfChild = *Current->Previous->Children[0]->Last;
+ ChildSize = LastOfChild.isTrailingComment() ? Style.ColumnLimit
+ : LastOfChild.TotalLength + 1;
+ }
+ if (Current->MustBreakBefore || Current->Previous->Children.size() > 1 ||
Current->IsMultiline)
Current->TotalLength = Current->Previous->TotalLength + Style.ColumnLimit;
else
Current->TotalLength = Current->Previous->TotalLength +
- Current->ColumnWidth +
+ Current->ColumnWidth + ChildSize +
Current->SpacesRequiredBefore;
if (Current->Type == TT_CtorInitializerColon)
@@ -1197,24 +1257,18 @@
}
calculateUnbreakableTailLengths(Line);
- for (Current = Line.First; Current != NULL; Current = Current->Next) {
+ for (Current = Line.First; Current != nullptr; Current = Current->Next) {
if (Current->Role)
Current->Role->precomputeFormattingInfos(Current);
}
DEBUG({ printDebugInfo(Line); });
-
- for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
- E = Line.Children.end();
- I != E; ++I) {
- calculateFormattingInformation(**I);
- }
}
void TokenAnnotator::calculateUnbreakableTailLengths(AnnotatedLine &Line) {
unsigned UnbreakableTailLength = 0;
FormatToken *Current = Line.Last;
- while (Current != NULL) {
+ while (Current) {
Current->UnbreakableTailLength = UnbreakableTailLength;
if (Current->CanBreakBefore ||
Current->isOneOf(tok::comment, tok::string_literal)) {
@@ -1235,7 +1289,8 @@
if (Left.is(tok::semi))
return 0;
- if (Left.is(tok::comma))
+ if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next &&
+ Right.Next->Type == TT_DictLiteral))
return 1;
if (Right.is(tok::l_square)) {
if (Style.Language == FormatStyle::LK_Proto)
@@ -1280,11 +1335,8 @@
// annotations (i.e. "const", "final" and "override") on the same line.
// Use a slightly higher penalty after ")" so that annotations like
// "const override" are kept together.
- bool is_standard_annotation = Right.is(tok::kw_const) ||
- Right.TokenText == "override" ||
- Right.TokenText == "final";
- return (Left.is(tok::r_paren) ? 100 : 120) +
- (is_standard_annotation ? 50 : 0);
+ bool is_short_annotation = Right.TokenText.size() < 10;
+ return (Left.is(tok::r_paren) ? 100 : 120) + (is_short_annotation ? 50 : 0);
}
// In for-loops, prefer breaking at ',' and ';'.
@@ -1337,7 +1389,12 @@
if (Right.is(tok::l_paren) &&
(Left.TokenText == "returns" || Left.TokenText == "option"))
return true;
+ } else if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Left.TokenText == "var")
+ return true;
}
+ if (Left.is(tok::kw_return) && Right.isNot(tok::semi))
+ return true;
if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty &&
Left.Tok.getObjCKeywordID() == tok::objc_property)
return true;
@@ -1404,19 +1461,21 @@
return Right.MatchingParen && Style.SpacesInContainerLiterals &&
Right.MatchingParen->Type == TT_ArrayInitializerLSquare;
if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr &&
- Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant))
+ Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant) &&
+ Left.Type != TT_DictLiteral)
return false;
if (Left.is(tok::colon))
return Left.Type != TT_ObjCMethodExpr;
+ if (Left.Type == TT_BlockComment)
+ return !Left.TokenText.endswith("=*/");
if (Right.is(tok::l_paren)) {
if (Left.is(tok::r_paren) && Left.Type == TT_AttributeParen)
return true;
return Line.Type == LT_ObjCDecl ||
- Left.isOneOf(tok::kw_return, tok::kw_new, tok::kw_delete,
- tok::semi) ||
+ Left.isOneOf(tok::kw_new, tok::kw_delete, tok::semi) ||
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
(Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while,
- tok::kw_switch, tok::kw_catch) ||
+ tok::kw_switch, tok::kw_catch, tok::kw_case) ||
Left.IsForEachMacro)) ||
(Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&
Left.isOneOf(tok::identifier, tok::kw___attribute) &&
@@ -1430,12 +1489,11 @@
(Right.is(tok::r_brace) && Right.MatchingParen &&
Right.MatchingParen->BlockKind != BK_Block))
return !Style.Cpp11BracedListStyle;
- if (Left.Type == TT_BlockComment && Left.TokenText.endswith("=*/"))
- return false;
if (Right.Type == TT_UnaryOperator)
return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) &&
(Left.isNot(tok::colon) || Left.Type != TT_ObjCMethodExpr);
- if (Left.isOneOf(tok::identifier, tok::greater, tok::r_square) &&
+ if ((Left.isOneOf(tok::identifier, tok::greater, tok::r_square) ||
+ Left.isSimpleTypeSpecifier()) &&
Right.is(tok::l_brace) && Right.getNextNonComment() &&
Right.BlockKind != BK_Block)
return false;
@@ -1478,7 +1536,7 @@
return false;
if (Tok.is(tok::colon))
return !Line.First->isOneOf(tok::kw_case, tok::kw_default) &&
- Tok.getNextNonComment() != NULL && Tok.Type != TT_ObjCMethodExpr &&
+ Tok.getNextNonComment() && Tok.Type != TT_ObjCMethodExpr &&
!Tok.Previous->is(tok::question) &&
(Tok.Type != TT_DictLiteral || Style.SpacesInContainerLiterals);
if (Tok.Previous->Type == TT_UnaryOperator ||
@@ -1496,7 +1554,8 @@
Tok.getPrecedence() == prec::Assignment)
return false;
if ((Tok.Type == TT_BinaryOperator && !Tok.Previous->is(tok::l_paren)) ||
- Tok.Previous->Type == TT_BinaryOperator)
+ Tok.Previous->Type == TT_BinaryOperator ||
+ Tok.Previous->Type == TT_ConditionalExpr)
return true;
if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
return false;
@@ -1505,6 +1564,8 @@
return true;
if (Tok.Type == TT_TrailingUnaryOperator)
return false;
+ if (Tok.Previous->Type == TT_RegexLiteral)
+ return false;
return spaceRequiredBetween(Line, *Tok.Previous, Tok);
}
@@ -1514,7 +1575,7 @@
if (Right.is(tok::comment)) {
return Right.Previous->BlockKind != BK_BracedInit &&
Right.Previous->Type != TT_CtorInitializerColon &&
- Right.NewlinesBefore > 0;
+ (Right.NewlinesBefore > 0 && Right.HasUnescapedNewline);
} else if (Right.Previous->isTrailingComment() ||
(Right.isStringLiteral() && Right.Previous->isStringLiteral())) {
return true;
@@ -1534,7 +1595,8 @@
Style.BreakConstructorInitializersBeforeComma &&
!Style.ConstructorInitializerAllOnOneLineOrOnePerLine) {
return true;
- } else if (Right.is(tok::l_brace) && (Right.BlockKind == BK_Block)) {
+ } else if (Right.is(tok::l_brace) && Right.BlockKind == BK_Block &&
+ Right.Type != TT_ObjCBlockLBrace && Right.Type != TT_DictLiteral) {
return Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
Style.BreakBeforeBraces == FormatStyle::BS_GNU;
} else if (Right.is(tok::string_literal) &&
@@ -1547,14 +1609,27 @@
Style.Language == FormatStyle::LK_Proto) {
// Don't enums onto single lines in protocol buffers.
return true;
- } else if ((Left.is(tok::l_brace) && Left.MatchingParen &&
- Left.MatchingParen->Previous &&
- Left.MatchingParen->Previous->is(tok::comma)) ||
- (Right.is(tok::r_brace) && Left.is(tok::comma))) {
- // If the last token before a '}' is a comma, the intention is to insert a
- // line break after it in order to make shuffling around entries easier.
- return true;
}
+
+ // If the last token before a '}' is a comma or a comment, the intention is to
+ // insert a line break after it in order to make shuffling around entries
+ // easier.
+ const FormatToken *BeforeClosingBrace = nullptr;
+ if (Left.is(tok::l_brace) && Left.MatchingParen)
+ BeforeClosingBrace = Left.MatchingParen->Previous;
+ else if (Right.is(tok::r_brace))
+ BeforeClosingBrace = Right.Previous;
+ if (BeforeClosingBrace &&
+ BeforeClosingBrace->isOneOf(tok::comma, tok::comment))
+ 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;
+ }
+
return false;
}
@@ -1563,6 +1638,8 @@
const FormatToken &Left = *Right.Previous;
if (Left.is(tok::at))
return false;
+ if (Left.Tok.getObjCKeywordID() == tok::objc_interface)
+ return false;
if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator))
return true;
if (Right.isTrailingComment())
@@ -1609,7 +1686,7 @@
return false;
if (Left.is(tok::l_paren) && Left.Previous &&
(Left.Previous->Type == TT_BinaryOperator ||
- Left.Previous->Type == TT_CastRParen))
+ Left.Previous->Type == TT_CastRParen || Left.Previous->is(tok::kw_if)))
return false;
if (Right.Type == TT_ImplicitStringLiteral)
return false;
@@ -1622,11 +1699,11 @@
if (Right.is(tok::r_brace))
return Right.MatchingParen && Right.MatchingParen->BlockKind == BK_Block;
- // Allow breaking after a trailing 'const', e.g. after a method declaration,
- // unless it is follow by ';', '{' or '='.
- if (Left.is(tok::kw_const) && Left.Previous != NULL &&
- Left.Previous->is(tok::r_paren))
- return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal);
+ // Allow breaking after a trailing annotation, e.g. after a method
+ // declaration.
+ if (Left.Type == TT_TrailingAnnotation)
+ return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal, tok::l_paren,
+ tok::less, tok::coloncolon);
if (Right.is(tok::kw___attribute))
return true;
@@ -1634,17 +1711,21 @@
if (Left.is(tok::identifier) && Right.is(tok::string_literal))
return true;
+ if (Right.is(tok::identifier) && Right.Next &&
+ Right.Next->Type == TT_DictLiteral)
+ return true;
+
if (Left.Type == TT_CtorInitializerComma &&
Style.BreakConstructorInitializersBeforeComma)
return false;
if (Right.Type == TT_CtorInitializerComma &&
Style.BreakConstructorInitializersBeforeComma)
return true;
- if (Right.Type == TT_BinaryOperator && Style.BreakBeforeBinaryOperators)
- return true;
if (Left.is(tok::greater) && Right.is(tok::greater) &&
Left.Type != TT_TemplateCloser)
return false;
+ if (Right.Type == TT_BinaryOperator && Style.BreakBeforeBinaryOperators)
+ return true;
if (Left.Type == TT_ArrayInitializerLSquare)
return true;
return (Left.isBinaryOperator() && Left.isNot(tok::lessless) &&
@@ -1671,7 +1752,7 @@
for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i)
llvm::errs() << Tok->FakeLParens[i] << "/";
llvm::errs() << " FakeRParens=" << Tok->FakeRParens << "\n";
- if (Tok->Next == NULL)
+ if (!Tok->Next)
assert(Tok == Line.Last);
Tok = Tok->Next;
}
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index bd91980..0df70a0 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -48,7 +48,7 @@
// Calculate Next and Previous for all tokens. Note that we must overwrite
// Next and Previous for every token, as previous formatting runs might have
// left them in a different state.
- First->Previous = NULL;
+ First->Previous = nullptr;
FormatToken *Current = First;
for (std::list<UnwrappedLineNode>::const_iterator I = ++Line.Tokens.begin(),
E = Line.Tokens.end();
@@ -67,7 +67,7 @@
}
}
Last = Current;
- Last->Next = NULL;
+ Last->Next = nullptr;
}
~AnnotatedLine() {
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 96d8155..d0750af 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -13,11 +13,11 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-parser"
-
#include "UnwrappedLineParser.h"
#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "format-parser"
+
namespace clang {
namespace format {
@@ -60,7 +60,7 @@
: Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource),
StructuralError(StructuralError),
- PreviousStructuralError(StructuralError), Token(NULL) {
+ PreviousStructuralError(StructuralError), Token(nullptr) {
TokenSource = this;
Line.Level = 0;
Line.InPPDirective = true;
@@ -164,9 +164,7 @@
++LineLevel;
}
}
- ~CompoundStatementIndenter() {
- LineLevel = OldLineLevel;
- }
+ ~CompoundStatementIndenter() { LineLevel = OldLineLevel; }
private:
unsigned &LineLevel;
@@ -208,14 +206,15 @@
ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
- CurrentLines(&Lines), StructuralError(false), Style(Style), Tokens(NULL),
- Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1) {}
+ CurrentLines(&Lines), StructuralError(false), Style(Style),
+ Tokens(nullptr), Callback(Callback), AllTokens(Tokens),
+ PPBranchLevel(-1) {}
void UnwrappedLineParser::reset() {
PPBranchLevel = -1;
Line.reset(new UnwrappedLine);
CommentsBeforeNextToken.clear();
- FormatTok = NULL;
+ FormatTok = nullptr;
MustBreakBeforeNextToken = false;
PreprocessorDirectives.clear();
CurrentLines = &Lines;
@@ -335,18 +334,30 @@
case tok::r_brace:
if (!LBraceStack.empty()) {
if (LBraceStack.back()->BlockKind == BK_Unknown) {
- // If there is a comma, semicolon or right paren after the closing
- // brace, we assume this is a braced initializer list. Note that
- // regardless how we mark inner braces here, we will overwrite the
- // BlockKind later if we parse a braced list (where all blocks inside
- // are by default braced lists), or when we explicitly detect blocks
- // (for example while parsing lambdas).
- //
- // We exclude + and - as they can be ObjC visibility modifiers.
- if (NextTok->isOneOf(tok::comma, tok::semi, tok::r_paren, tok::period,
- tok::r_square, tok::l_brace, tok::colon) ||
- (NextTok->isBinaryOperator() &&
- !NextTok->isOneOf(tok::plus, tok::minus))) {
+ bool ProbablyBracedList = false;
+ if (Style.Language == FormatStyle::LK_Proto) {
+ ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
+ } else {
+ // Using OriginalColumn to distinguish between ObjC methods and
+ // binary operators is a bit hacky.
+ bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
+ NextTok->OriginalColumn == 0;
+
+ // If there is a comma, semicolon or right paren after the closing
+ // brace, we assume this is a braced initializer list. Note that
+ // regardless how we mark inner braces here, we will overwrite the
+ // BlockKind later if we parse a braced list (where all blocks
+ // inside are by default braced lists), or when we explicitly detect
+ // blocks (for example while parsing lambdas).
+ //
+ // We exclude + and - as they can be ObjC visibility modifiers.
+ ProbablyBracedList =
+ NextTok->isOneOf(tok::comma, tok::semi, tok::period, tok::colon,
+ tok::r_paren, tok::r_square, tok::l_brace,
+ tok::l_paren) ||
+ (NextTok->isBinaryOperator() && !NextIsObjCMethod);
+ }
+ if (ProbablyBracedList) {
Tok->BlockKind = BK_BracedInit;
LBraceStack.back()->BlockKind = BK_BracedInit;
} else {
@@ -408,16 +419,34 @@
Line->Level = InitialLevel;
}
+static bool IsGoogScope(const UnwrappedLine &Line) {
+ if (Line.Tokens.size() < 4)
+ return false;
+ auto I = Line.Tokens.begin();
+ if (I->Tok->TokenText != "goog")
+ return false;
+ ++I;
+ if (I->Tok->isNot(tok::period))
+ return false;
+ ++I;
+ if (I->Tok->TokenText != "scope")
+ return false;
+ ++I;
+ return I->Tok->is(tok::l_paren);
+}
+
void UnwrappedLineParser::parseChildBlock() {
FormatTok->BlockKind = BK_Block;
nextToken();
{
+ bool GoogScope =
+ Style.Language == FormatStyle::LK_JavaScript && IsGoogScope(*Line);
ScopedLineState LineState(*this);
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
/*MustBeDeclaration=*/false);
- Line->Level += 1;
+ Line->Level += GoogScope ? 0 : 1;
parseLevel(/*HasOpeningBrace=*/true);
- Line->Level -= 1;
+ Line->Level -= GoogScope ? 0 : 1;
}
nextToken();
}
@@ -427,7 +456,7 @@
ScopedMacroState MacroState(*Line, Tokens, FormatTok, StructuralError);
nextToken();
- if (FormatTok->Tok.getIdentifierInfo() == NULL) {
+ if (!FormatTok->Tok.getIdentifierInfo()) {
parsePPUnknown();
return;
}
@@ -458,14 +487,14 @@
}
}
-void UnwrappedLineParser::pushPPConditional() {
- if (!PPStack.empty() && PPStack.back() == PP_Unreachable)
+void UnwrappedLineParser::conditionalCompilationCondition(bool Unreachable) {
+ if (Unreachable || (!PPStack.empty() && PPStack.back() == PP_Unreachable))
PPStack.push_back(PP_Unreachable);
else
PPStack.push_back(PP_Conditional);
}
-void UnwrappedLineParser::parsePPIf(bool IfDef) {
+void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) {
++PPBranchLevel;
assert(PPBranchLevel >= 0 && PPBranchLevel <= (int)PPLevelBranchIndex.size());
if (PPBranchLevel == (int)PPLevelBranchIndex.size()) {
@@ -473,37 +502,22 @@
PPLevelBranchCount.push_back(0);
}
PPChainBranchIndex.push(0);
- nextToken();
- bool IsLiteralFalse = (FormatTok->Tok.isLiteral() &&
- StringRef(FormatTok->Tok.getLiteralData(),
- FormatTok->Tok.getLength()) == "0") ||
- FormatTok->Tok.is(tok::kw_false);
- if ((!IfDef && IsLiteralFalse) || PPLevelBranchIndex[PPBranchLevel] > 0) {
- PPStack.push_back(PP_Unreachable);
- } else {
- pushPPConditional();
- }
- parsePPUnknown();
+ bool Skip = PPLevelBranchIndex[PPBranchLevel] > 0;
+ conditionalCompilationCondition(Unreachable || Skip);
}
-void UnwrappedLineParser::parsePPElse() {
+void UnwrappedLineParser::conditionalCompilationAlternative() {
if (!PPStack.empty())
PPStack.pop_back();
assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
if (!PPChainBranchIndex.empty())
++PPChainBranchIndex.top();
- if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty() &&
- PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top()) {
- PPStack.push_back(PP_Unreachable);
- } else {
- pushPPConditional();
- }
- parsePPUnknown();
+ conditionalCompilationCondition(
+ PPBranchLevel >= 0 && !PPChainBranchIndex.empty() &&
+ PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top());
}
-void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
-
-void UnwrappedLineParser::parsePPEndIf() {
+void UnwrappedLineParser::conditionalCompilationEnd() {
assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty()) {
if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel]) {
@@ -517,6 +531,27 @@
PPChainBranchIndex.pop();
if (!PPStack.empty())
PPStack.pop_back();
+}
+
+void UnwrappedLineParser::parsePPIf(bool IfDef) {
+ nextToken();
+ bool IsLiteralFalse = (FormatTok->Tok.isLiteral() &&
+ StringRef(FormatTok->Tok.getLiteralData(),
+ FormatTok->Tok.getLength()) == "0") ||
+ FormatTok->Tok.is(tok::kw_false);
+ conditionalCompilationStart(!IfDef && IsLiteralFalse);
+ parsePPUnknown();
+}
+
+void UnwrappedLineParser::parsePPElse() {
+ conditionalCompilationAlternative();
+ parsePPUnknown();
+}
+
+void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
+
+void UnwrappedLineParser::parsePPEndIf() {
+ conditionalCompilationEnd();
parsePPUnknown();
}
@@ -575,7 +610,9 @@
// Colon is used in labels, base class lists, initializer lists,
// range-based for loops, ternary operator, but should never be the
// first token in an unwrapped line.
- Tok.isNot(tok::colon);
+ Tok.isNot(tok::colon) &&
+ // 'noexcept' is a trailing annotation.
+ Tok.isNot(tok::kw_noexcept);
}
void UnwrappedLineParser::parseStructuralElement() {
@@ -644,6 +681,9 @@
case tok::kw_case:
parseCaseLabel();
return;
+ case tok::kw_try:
+ parseTryCatch();
+ return;
case tok::kw_extern:
nextToken();
if (FormatTok->Tok.is(tok::string_literal)) {
@@ -724,8 +764,16 @@
// Otherwise this was a braced init list, and the structural
// element continues.
break;
+ case tok::kw_try:
+ // We arrive here when parsing function-try blocks.
+ parseTryCatch();
+ return;
case tok::identifier: {
StringRef Text = FormatTok->TokenText;
+ if (Style.Language == FormatStyle::LK_JavaScript && Text == "function") {
+ tryToParseJSFunction();
+ break;
+ }
nextToken();
if (Line->Tokens.size() == 1) {
if (FormatTok->Tok.is(tok::colon)) {
@@ -855,6 +903,22 @@
return false;
}
+void UnwrappedLineParser::tryToParseJSFunction() {
+ nextToken();
+ if (FormatTok->isNot(tok::l_paren))
+ return;
+ nextToken();
+ while (FormatTok->isNot(tok::l_brace)) {
+ // Err on the side of caution in order to avoid consuming the full file in
+ // case of incomplete code.
+ if (!FormatTok->isOneOf(tok::identifier, tok::comma, tok::r_paren,
+ tok::comment))
+ return;
+ nextToken();
+ }
+ parseChildBlock();
+}
+
bool UnwrappedLineParser::tryToParseBracedList() {
if (FormatTok->BlockKind == BK_Unknown)
calculateBraceTypes();
@@ -872,9 +936,11 @@
// FIXME: Once we have an expression parser in the UnwrappedLineParser,
// replace this by using parseAssigmentExpression() inside.
do {
- // FIXME: When we start to support lambdas, we'll want to parse them away
- // here, otherwise our bail-out scenarios below break. The better solution
- // might be to just implement a more or less complete expression parser.
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->TokenText == "function") {
+ tryToParseJSFunction();
+ continue;
+ }
switch (FormatTok->Tok.getKind()) {
case tok::caret:
nextToken();
@@ -1022,6 +1088,72 @@
}
}
+void UnwrappedLineParser::parseTryCatch() {
+ assert(FormatTok->is(tok::kw_try) && "'try' expected");
+ nextToken();
+ bool NeedsUnwrappedLine = false;
+ if (FormatTok->is(tok::colon)) {
+ // We are in a function try block, what comes is an initializer list.
+ nextToken();
+ while (FormatTok->is(tok::identifier)) {
+ nextToken();
+ if (FormatTok->is(tok::l_paren))
+ parseParens();
+ else
+ StructuralError = true;
+ if (FormatTok->is(tok::comma))
+ nextToken();
+ }
+ }
+ if (FormatTok->is(tok::l_brace)) {
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
+ parseBlock(/*MustBeDeclaration=*/false);
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU ||
+ Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) {
+ addUnwrappedLine();
+ } else {
+ NeedsUnwrappedLine = true;
+ }
+ } else if (!FormatTok->is(tok::kw_catch)) {
+ // The C++ standard requires a compound-statement after a try.
+ // If there's none, we try to assume there's a structuralElement
+ // and try to continue.
+ StructuralError = true;
+ addUnwrappedLine();
+ ++Line->Level;
+ parseStructuralElement();
+ --Line->Level;
+ }
+ while (FormatTok->is(tok::kw_catch) ||
+ (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->TokenText == "finally")) {
+ nextToken();
+ while (FormatTok->isNot(tok::l_brace)) {
+ if (FormatTok->is(tok::l_paren)) {
+ parseParens();
+ continue;
+ }
+ if (FormatTok->isOneOf(tok::semi, tok::r_brace))
+ return;
+ nextToken();
+ }
+ NeedsUnwrappedLine = false;
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
+ parseBlock(/*MustBeDeclaration=*/false);
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU ||
+ Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) {
+ addUnwrappedLine();
+ } else {
+ NeedsUnwrappedLine = true;
+ }
+ }
+ if (NeedsUnwrappedLine) {
+ addUnwrappedLine();
+ }
+}
+
void UnwrappedLineParser::parseNamespace() {
assert(FormatTok->Tok.is(tok::kw_namespace) && "'namespace' expected");
nextToken();
@@ -1157,9 +1289,8 @@
nextToken();
}
// Eat up enum class ...
- if (FormatTok->Tok.is(tok::kw_class) ||
- FormatTok->Tok.is(tok::kw_struct))
- nextToken();
+ if (FormatTok->Tok.is(tok::kw_class) || FormatTok->Tok.is(tok::kw_struct))
+ nextToken();
while (FormatTok->Tok.getIdentifierInfo() ||
FormatTok->isOneOf(tok::colon, tok::coloncolon)) {
nextToken();
@@ -1278,9 +1409,12 @@
if (FormatTok->Tok.is(tok::less))
parseObjCProtocolList();
- // If instance variables are present, keep the '{' on the first line too.
- if (FormatTok->Tok.is(tok::l_brace))
+ if (FormatTok->Tok.is(tok::l_brace)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU)
+ addUnwrappedLine();
parseBlock(/*MustBeDeclaration=*/true);
+ }
// With instance variables, this puts '}' on its own line. Without instance
// variables, this ends the @interface line.
@@ -1351,13 +1485,18 @@
bool UnwrappedLineParser::eof() const { return FormatTok->Tok.is(tok::eof); }
+bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) {
+ return (Line->InPPDirective || FormatTok.HasUnescapedNewline) &&
+ FormatTok.NewlinesBefore > 0;
+}
+
void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
bool JustComments = Line->Tokens.empty();
for (SmallVectorImpl<FormatToken *>::const_iterator
I = CommentsBeforeNextToken.begin(),
E = CommentsBeforeNextToken.end();
I != E; ++I) {
- if ((*I)->NewlinesBefore && JustComments) {
+ if (isOnNewLine(**I) && JustComments) {
addUnwrappedLine();
}
pushToken(*I);
@@ -1371,7 +1510,7 @@
void UnwrappedLineParser::nextToken() {
if (eof())
return;
- flushComments(FormatTok->NewlinesBefore > 0);
+ flushComments(isOnNewLine(*FormatTok));
pushToken(FormatTok);
readToken();
}
@@ -1391,9 +1530,22 @@
// Comments stored before the preprocessor directive need to be output
// before the preprocessor directive, at the same level as the
// preprocessor directive, as we consider them to apply to the directive.
- flushComments(FormatTok->NewlinesBefore > 0);
+ flushComments(isOnNewLine(*FormatTok));
parsePPDirective();
}
+ while (FormatTok->Type == TT_ConflictStart ||
+ FormatTok->Type == TT_ConflictEnd ||
+ FormatTok->Type == TT_ConflictAlternative) {
+ if (FormatTok->Type == TT_ConflictStart) {
+ conditionalCompilationStart(/*Unreachable=*/false);
+ } else if (FormatTok->Type == TT_ConflictAlternative) {
+ conditionalCompilationAlternative();
+ } else if (FormatTok->Type == TT_ConflictEnd) {
+ conditionalCompilationEnd();
+ }
+ FormatTok = Tokens->getNextToken();
+ FormatTok->MustBreakBefore = true;
+ }
if (!PPStack.empty() && (PPStack.back() == PP_Unreachable) &&
!Line->InPPDirective) {
@@ -1402,7 +1554,7 @@
if (!FormatTok->Tok.is(tok::comment))
return;
- if (FormatTok->NewlinesBefore > 0 || FormatTok->IsFirst) {
+ if (isOnNewLine(*FormatTok) || FormatTok->IsFirst) {
CommentsInCurrentLine = false;
}
if (CommentsInCurrentLine) {
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 62e0b58..c9182e9 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -85,6 +85,7 @@
void parseParens();
void parseSquare();
void parseIfThenElse();
+ void parseTryCatch();
void parseForOrWhileLoop();
void parseDoWhile();
void parseLabel();
@@ -100,6 +101,7 @@
void parseObjCProtocol();
bool tryToParseLambda();
bool tryToParseLambdaIntroducer();
+ void tryToParseJSFunction();
void addUnwrappedLine();
bool eof() const;
void nextToken();
@@ -107,7 +109,17 @@
void flushComments(bool NewlineBeforeNext);
void pushToken(FormatToken *Tok);
void calculateBraceTypes();
- void pushPPConditional();
+
+ // Marks a conditional compilation edge (for example, an '#if', '#ifdef',
+ // '#else' or merge conflict marker). If 'Unreachable' is true, assumes
+ // this branch either cannot be taken (for example '#if false'), or should
+ // not be taken in this round.
+ void conditionalCompilationCondition(bool Unreachable);
+ void conditionalCompilationStart(bool Unreachable);
+ void conditionalCompilationAlternative();
+ void conditionalCompilationEnd();
+
+ bool isOnNewLine(const FormatToken &FormatTok);
// FIXME: We are constantly running into bugs where Line.Level is incorrectly
// subtracted from beyond 0. Introduce a method to subtract from Line.Level
@@ -189,7 +201,7 @@
};
struct UnwrappedLineNode {
- UnwrappedLineNode() : Tok(NULL) {}
+ UnwrappedLineNode() : Tok(nullptr) {}
UnwrappedLineNode(FormatToken *Tok) : Tok(Tok) {}
FormatToken *Tok;
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 4c393ed..47b94de 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -18,9 +18,8 @@
namespace clang {
namespace format {
-bool
-WhitespaceManager::Change::IsBeforeInFile::operator()(const Change &C1,
- const Change &C2) const {
+bool WhitespaceManager::Change::IsBeforeInFile::
+operator()(const Change &C1, const Change &C2) const {
return SourceMgr.isBeforeInTranslationUnit(
C1.OriginalWhitespaceRange.getBegin(),
C2.OriginalWhitespaceRange.getBegin());
@@ -28,7 +27,7 @@
WhitespaceManager::Change::Change(
bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
- unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn,
+ unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore, StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective)
: CreateReplacement(CreateReplacement),
@@ -69,14 +68,14 @@
void WhitespaceManager::replaceWhitespaceInToken(
const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
- unsigned Newlines, unsigned IndentLevel, unsigned Spaces) {
+ unsigned Newlines, unsigned IndentLevel, int Spaces) {
if (Tok.Finalized)
return;
+ SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
Changes.push_back(Change(
- true, SourceRange(Tok.getStartOfNonWhitespace().getLocWithOffset(Offset),
- Tok.getStartOfNonWhitespace().getLocWithOffset(
- Offset + ReplaceChars)),
- IndentLevel, Spaces, Spaces, Newlines, PreviousPostfix, CurrentPrefix,
+ true, SourceRange(Start, Start.getLocWithOffset(ReplaceChars)),
+ IndentLevel, Spaces, std::max(0, Spaces), Newlines, PreviousPostfix,
+ CurrentPrefix,
// If we don't add a newline this change doesn't start a comment. Thus,
// when we align line comments, we don't need to treat this change as one.
// FIXME: We still need to take this change in account to properly
@@ -122,6 +121,22 @@
// cases, setting TokenLength of the last token to 0 is wrong.
Changes.back().TokenLength = 0;
Changes.back().IsTrailingComment = Changes.back().Kind == tok::comment;
+
+ const WhitespaceManager::Change *LastBlockComment = nullptr;
+ for (auto &Change : Changes) {
+ Change.StartOfBlockComment = nullptr;
+ Change.IndentationOffset = 0;
+ if (Change.Kind == tok::comment) {
+ LastBlockComment = &Change;
+ } else if (Change.Kind == tok::unknown) {
+ if ((Change.StartOfBlockComment = LastBlockComment))
+ Change.IndentationOffset =
+ Change.StartOfTokenColumn -
+ Change.StartOfBlockComment->StartOfTokenColumn;
+ } else {
+ LastBlockComment = nullptr;
+ }
+ }
}
void WhitespaceManager::alignTrailingComments() {
@@ -131,58 +146,62 @@
bool BreakBeforeNext = false;
unsigned Newlines = 0;
for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
- unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
- // FIXME: Correctly handle ChangeMaxColumn in PP directives.
- unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
+ if (Changes[i].StartOfBlockComment)
+ continue;
Newlines += Changes[i].NewlinesBefore;
- if (Changes[i].IsTrailingComment) {
- // If this comment follows an } in column 0, it probably documents the
- // closing of a namespace and we don't want to align it.
- bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
- Changes[i - 1].Kind == tok::r_brace &&
- Changes[i - 1].StartOfTokenColumn == 0;
- bool WasAlignedWithStartOfNextLine = false;
- if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
- for (unsigned j = i + 1; j != e; ++j) {
- if (Changes[j].Kind != tok::comment) { // Skip over comments.
- // 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()));
- break;
- }
+ if (!Changes[i].IsTrailingComment)
+ continue;
+
+ unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
+ unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
+ if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
+ ChangeMaxColumn -= 2;
+ // If this comment follows an } in column 0, it probably documents the
+ // closing of a namespace and we don't want to align it.
+ bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
+ Changes[i - 1].Kind == tok::r_brace &&
+ Changes[i - 1].StartOfTokenColumn == 0;
+ bool WasAlignedWithStartOfNextLine = false;
+ if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
+ for (unsigned j = i + 1; j != e; ++j) {
+ if (Changes[j].Kind != tok::comment) { // Skip over comments.
+ // 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()));
+ break;
}
}
- if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
- alignTrailingComments(StartOfSequence, i, MinColumn);
- MinColumn = ChangeMinColumn;
- MaxColumn = ChangeMinColumn;
- StartOfSequence = i;
- } else if (BreakBeforeNext || Newlines > 1 ||
- (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
- // Break the comment sequence if the previous line did not end
- // in a trailing comment.
- (Changes[i].NewlinesBefore == 1 && i > 0 &&
- !Changes[i - 1].IsTrailingComment) ||
- WasAlignedWithStartOfNextLine) {
- alignTrailingComments(StartOfSequence, i, MinColumn);
- MinColumn = ChangeMinColumn;
- MaxColumn = ChangeMaxColumn;
- StartOfSequence = i;
- } else {
- MinColumn = std::max(MinColumn, ChangeMinColumn);
- MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
- }
- BreakBeforeNext =
- (i == 0) || (Changes[i].NewlinesBefore > 1) ||
- // Never start a sequence with a comment at the beginning of
- // the line.
- (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
- Newlines = 0;
}
+ if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
+ alignTrailingComments(StartOfSequence, i, MinColumn);
+ MinColumn = ChangeMinColumn;
+ MaxColumn = ChangeMinColumn;
+ StartOfSequence = i;
+ } else if (BreakBeforeNext || Newlines > 1 ||
+ (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
+ // Break the comment sequence if the previous line did not end
+ // in a trailing comment.
+ (Changes[i].NewlinesBefore == 1 && i > 0 &&
+ !Changes[i - 1].IsTrailingComment) ||
+ WasAlignedWithStartOfNextLine) {
+ alignTrailingComments(StartOfSequence, i, MinColumn);
+ MinColumn = ChangeMinColumn;
+ MaxColumn = ChangeMaxColumn;
+ StartOfSequence = i;
+ } else {
+ MinColumn = std::max(MinColumn, ChangeMinColumn);
+ MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
+ }
+ BreakBeforeNext =
+ (i == 0) || (Changes[i].NewlinesBefore > 1) ||
+ // Never start a sequence with a comment at the beginning of
+ // the line.
+ (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
+ Newlines = 0;
}
alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
}
@@ -190,15 +209,20 @@
void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
unsigned Column) {
for (unsigned i = Start; i != End; ++i) {
+ int Shift = 0;
if (Changes[i].IsTrailingComment) {
- assert(Column >= Changes[i].StartOfTokenColumn);
- Changes[i].Spaces += Column - Changes[i].StartOfTokenColumn;
- if (i + 1 != End) {
- Changes[i + 1].PreviousEndOfTokenColumn +=
- Column - Changes[i].StartOfTokenColumn;
- }
- Changes[i].StartOfTokenColumn = Column;
+ Shift = Column - Changes[i].StartOfTokenColumn;
}
+ if (Changes[i].StartOfBlockComment) {
+ Shift = Changes[i].IndentationOffset +
+ Changes[i].StartOfBlockComment->StartOfTokenColumn -
+ Changes[i].StartOfTokenColumn;
+ }
+ assert(Shift >= 0);
+ Changes[i].Spaces += Shift;
+ if (i + 1 != End)
+ Changes[i + 1].PreviousEndOfTokenColumn += Shift;
+ Changes[i].StartOfTokenColumn += Shift;
}
}
@@ -245,8 +269,8 @@
C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
else
appendNewlineText(ReplacementText, C.NewlinesBefore);
- appendIndentText(ReplacementText, C.IndentLevel, C.Spaces,
- C.StartOfTokenColumn - C.Spaces);
+ appendIndentText(ReplacementText, C.IndentLevel, std::max(0, C.Spaces),
+ C.StartOfTokenColumn - std::max(0, C.Spaces));
ReplacementText.append(C.CurrentLinePrefix);
storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
}
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index f94464f..189b1ae 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -63,6 +63,12 @@
/// (in this order) at \p Offset inside \p Tok, replacing \p ReplaceChars
/// characters.
///
+ /// Note: \p Spaces can be negative to retain information about initial
+ /// relative column offset between a line of a block comment and the start of
+ /// the comment. This negative offset may be compensated by trailing comment
+ /// alignment here. In all other cases negative \p Spaces will be truncated to
+ /// 0.
+ ///
/// When \p InPPDirective is true, escaped newlines are inserted. \p Spaces is
/// used to align backslashes correctly.
void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset,
@@ -70,7 +76,7 @@
StringRef PreviousPostfix,
StringRef CurrentPrefix, bool InPPDirective,
unsigned Newlines, unsigned IndentLevel,
- unsigned Spaces);
+ int Spaces);
/// \brief Returns all the \c Replacements created during formatting.
const tooling::Replacements &generateReplacements();
@@ -101,7 +107,7 @@
/// \p StartOfTokenColumn and \p InPPDirective will be used to lay out
/// trailing comments and escaped newlines.
Change(bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
- unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn,
+ unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore, StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix, tok::TokenKind Kind,
bool ContinuesPPDirective);
@@ -128,7 +134,10 @@
// The number of spaces in front of the token or broken part of the token.
// This will be adapted when aligning tokens.
- unsigned Spaces;
+ // Can be negative to retain information about the initial relative offset
+ // of the lines in a block comment. This is used when aligning trailing
+ // comments. Uncompensated negative offset is truncated to 0.
+ int Spaces;
// \c IsTrailingComment, \c TokenLength, \c PreviousEndOfTokenColumn and
// \c EscapedNewlineColumn will be calculated in
@@ -137,6 +146,17 @@
unsigned TokenLength;
unsigned PreviousEndOfTokenColumn;
unsigned EscapedNewlineColumn;
+
+ // These fields are used to retain correct relative line indentation in a
+ // block comment when aligning trailing comments.
+ //
+ // If this Change represents a continuation of a block comment,
+ // \c StartOfBlockComment is pointer to the first Change in the block
+ // comment. \c IndentationOffset is a relative column offset to this
+ // change, so that the correct column can be reconstructed at the end of
+ // the alignment process.
+ const Change *StartOfBlockComment;
+ int IndentationOffset;
};
/// \brief Calculate \c IsTrailingComment, \c TokenLength for the last tokens