aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Format/TokenAnnotator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Format/TokenAnnotator.cpp')
-rw-r--r--[-rwxr-xr-x]clang/lib/Format/TokenAnnotator.cpp453
1 files changed, 308 insertions, 145 deletions
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 34c291ecc492..54e6c7d38e7d 100755..100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -116,10 +116,17 @@ private:
while (CurrentToken) {
if (CurrentToken->is(tok::greater)) {
// Try to do a better job at looking for ">>" within the condition of
- // a statement.
+ // a statement. Conservatively insert spaces between consecutive ">"
+ // tokens to prevent splitting right bitshift operators and potentially
+ // altering program semantics. This check is overly conservative and
+ // will prevent spaces from being inserted in select nested template
+ // parameter cases, but should not alter program semantics.
if (CurrentToken->Next && CurrentToken->Next->is(tok::greater) &&
Left->ParentBracket != tok::less &&
- isKeywordWithCondition(*Line.First))
+ (isKeywordWithCondition(*Line.First) ||
+ CurrentToken->getStartOfNonWhitespace() ==
+ CurrentToken->Next->getStartOfNonWhitespace().getLocWithOffset(
+ -1)))
return false;
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
@@ -222,7 +229,19 @@ private:
}
if (Left->is(TT_OverloadedOperatorLParen)) {
- Contexts.back().IsExpression = false;
+ // Find the previous kw_operator token.
+ FormatToken *Prev = Left;
+ while (!Prev->is(tok::kw_operator)) {
+ Prev = Prev->Previous;
+ assert(Prev && "Expect a kw_operator prior to the OperatorLParen!");
+ }
+
+ // If faced with "a.operator*(argument)" or "a->operator*(argument)",
+ // i.e. the operator is called as a member function,
+ // then the argument must be an expression.
+ bool OperatorCalledAsMemberFunction =
+ Prev->Previous && Prev->Previous->isOneOf(tok::period, tok::arrow);
+ Contexts.back().IsExpression = OperatorCalledAsMemberFunction;
} else if (Style.Language == FormatStyle::LK_JavaScript &&
(Line.startsWith(Keywords.kw_type, tok::identifier) ||
Line.startsWith(tok::kw_export, Keywords.kw_type,
@@ -344,7 +363,7 @@ private:
Left->Previous && Left->Previous->is(tok::l_paren)) {
// Detect the case where macros are used to generate lambdas or
// function bodies, e.g.:
- // auto my_lambda = MARCO((Type *type, int i) { .. body .. });
+ // auto my_lambda = MACRO((Type *type, int i) { .. body .. });
for (FormatToken *Tok = Left; Tok != CurrentToken; Tok = Tok->Next) {
if (Tok->is(TT_BinaryOperator) &&
Tok->isOneOf(tok::star, tok::amp, tok::ampamp))
@@ -390,9 +409,13 @@ private:
!CurrentToken->Next->HasUnescapedNewline &&
!CurrentToken->Next->isTrailingComment())
HasMultipleParametersOnALine = true;
+ bool ProbablyFunctionTypeLParen =
+ (CurrentToken->is(tok::l_paren) && CurrentToken->Next &&
+ CurrentToken->Next->isOneOf(tok::star, tok::amp, tok::caret));
if ((CurrentToken->Previous->isOneOf(tok::kw_const, tok::kw_auto) ||
CurrentToken->Previous->isSimpleTypeSpecifier()) &&
- !CurrentToken->is(tok::l_brace))
+ !(CurrentToken->is(tok::l_brace) ||
+ (CurrentToken->is(tok::l_paren) && !ProbablyFunctionTypeLParen)))
Contexts.back().IsExpression = false;
if (CurrentToken->isOneOf(tok::semi, tok::colon)) {
MightBeObjCForRangeLoop = false;
@@ -722,6 +745,21 @@ private:
return false;
}
+ bool couldBeInStructArrayInitializer() const {
+ if (Contexts.size() < 2)
+ return false;
+ // We want to back up no more then 2 context levels i.e.
+ // . { { <-
+ const auto End = std::next(Contexts.rbegin(), 2);
+ auto Last = Contexts.rbegin();
+ unsigned Depth = 0;
+ for (; Last != End; ++Last) {
+ if (Last->ContextKind == tok::l_brace)
+ ++Depth;
+ }
+ return Depth == 2 && Last->ContextKind != tok::l_brace;
+ }
+
bool parseBrace() {
if (CurrentToken) {
FormatToken *Left = CurrentToken->Previous;
@@ -739,10 +777,17 @@ private:
Left->Previous->is(TT_JsTypeColon))
Contexts.back().IsExpression = false;
+ unsigned CommaCount = 0;
while (CurrentToken) {
if (CurrentToken->is(tok::r_brace)) {
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
+ if (Style.AlignArrayOfStructures != FormatStyle::AIAS_None) {
+ if (Left->ParentBracket == tok::l_brace &&
+ couldBeInStructArrayInitializer() && CommaCount > 0) {
+ Contexts.back().InStructArrayInitializer = true;
+ }
+ }
next();
return true;
}
@@ -766,9 +811,11 @@ private:
Style.Language == FormatStyle::LK_JavaScript)
Left->setType(TT_DictLiteral);
}
- if (CurrentToken->is(tok::comma) &&
- Style.Language == FormatStyle::LK_JavaScript)
- Left->setType(TT_DictLiteral);
+ if (CurrentToken->is(tok::comma)) {
+ if (Style.Language == FormatStyle::LK_JavaScript)
+ Left->setType(TT_DictLiteral);
+ ++CommaCount;
+ }
if (!consumeToken())
return false;
}
@@ -1048,13 +1095,6 @@ private:
CurrentToken->Previous->setType(TT_OverloadedOperator);
break;
case tok::question:
- if (Tok->is(TT_CSharpNullConditionalLSquare)) {
- if (!parseSquare())
- return false;
- break;
- }
- if (Tok->isOneOf(TT_CSharpNullConditional, TT_CSharpNullCoalescing))
- break;
if (Style.Language == FormatStyle::LK_JavaScript && Tok->Next &&
Tok->Next->isOneOf(tok::semi, tok::comma, tok::colon, tok::r_paren,
tok::r_brace)) {
@@ -1339,6 +1379,12 @@ public:
return LT_ObjCMethodDecl;
}
+ for (const auto &ctx : Contexts) {
+ if (ctx.InStructArrayInitializer) {
+ return LT_ArrayOfStructInitializer;
+ }
+ }
+
return LT_Other;
}
@@ -1363,9 +1409,9 @@ private:
// 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->isOneOf(
- TT_LambdaLSquare, TT_LambdaLBrace, TT_AttributeMacro,
+ TT_LambdaLSquare, TT_LambdaLBrace, TT_AttributeMacro, TT_IfMacro,
TT_ForEachMacro, TT_TypenameMacro, TT_FunctionLBrace,
- TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_JsFatArrow,
+ TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_FatArrow,
TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator,
TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral,
TT_UntouchableMacroFunc, TT_ConstraintJunctions,
@@ -1414,6 +1460,7 @@ private:
bool IsForEachMacro = false;
bool InCpp11AttributeSpecifier = false;
bool InCSharpAttributeSpecifier = false;
+ bool InStructArrayInitializer = false;
};
/// Puts a new \c Context onto the stack \c Contexts for the lifetime
@@ -1429,7 +1476,16 @@ private:
P.Contexts.back().IsExpression));
}
- ~ScopedContextCreator() { P.Contexts.pop_back(); }
+ ~ScopedContextCreator() {
+ if (P.Style.AlignArrayOfStructures != FormatStyle::AIAS_None) {
+ if (P.Contexts.back().InStructArrayInitializer) {
+ P.Contexts.pop_back();
+ P.Contexts.back().InStructArrayInitializer = true;
+ return;
+ }
+ }
+ P.Contexts.pop_back();
+ }
};
void modifyContext(const FormatToken &Current) {
@@ -1564,39 +1620,29 @@ private:
// The token type is already known.
return;
- if (Style.isCSharp() && CurrentToken->is(tok::question)) {
- if (CurrentToken->TokenText == "??") {
- Current.setType(TT_CSharpNullCoalescing);
- return;
- }
- if (CurrentToken->TokenText == "?.") {
- Current.setType(TT_CSharpNullConditional);
- return;
- }
- if (CurrentToken->TokenText == "?[") {
- Current.setType(TT_CSharpNullConditionalLSquare);
- return;
- }
- }
-
- if (Style.Language == FormatStyle::LK_JavaScript) {
- if (Current.is(tok::exclaim)) {
- if (Current.Previous &&
- (Keywords.IsJavaScriptIdentifier(
- *Current.Previous, /* AcceptIdentifierName= */ true) ||
- Current.Previous->isOneOf(
- tok::kw_namespace, tok::r_paren, tok::r_square, tok::r_brace,
- Keywords.kw_type, Keywords.kw_get, Keywords.kw_set) ||
- Current.Previous->Tok.isLiteral())) {
- Current.setType(TT_JsNonNullAssertion);
- return;
- }
- if (Current.Next &&
- Current.Next->isOneOf(TT_BinaryOperator, Keywords.kw_as)) {
- Current.setType(TT_JsNonNullAssertion);
+ if ((Style.Language == FormatStyle::LK_JavaScript || Style.isCSharp()) &&
+ Current.is(tok::exclaim)) {
+ if (Current.Previous) {
+ bool IsIdentifier =
+ Style.Language == FormatStyle::LK_JavaScript
+ ? Keywords.IsJavaScriptIdentifier(
+ *Current.Previous, /* AcceptIdentifierName= */ true)
+ : Current.Previous->is(tok::identifier);
+ if (IsIdentifier ||
+ Current.Previous->isOneOf(
+ tok::kw_namespace, tok::r_paren, tok::r_square, tok::r_brace,
+ tok::kw_false, tok::kw_true, Keywords.kw_type, Keywords.kw_get,
+ Keywords.kw_set) ||
+ Current.Previous->Tok.isLiteral()) {
+ Current.setType(TT_NonNullAssertion);
return;
}
}
+ if (Current.Next &&
+ Current.Next->isOneOf(TT_BinaryOperator, Keywords.kw_as)) {
+ Current.setType(TT_NonNullAssertion);
+ return;
+ }
}
// Line.MightBeFunctionDecl can only be true after the parentheses of a
@@ -1917,12 +1963,12 @@ private:
if (Tok.Next->isOneOf(tok::identifier, tok::kw_this))
return true;
- if (Tok.Next->is(tok::l_paren) &&
- !(Tok.Previous && Tok.Previous->is(tok::identifier) &&
- Tok.Previous->Previous &&
- Tok.Previous->Previous->isOneOf(tok::arrowstar, tok::arrow,
- tok::star)))
- return true;
+ // Look for a cast `( x ) (`.
+ if (Tok.Next->is(tok::l_paren) && Tok.Previous && Tok.Previous->Previous) {
+ if (Tok.Previous->is(tok::identifier) &&
+ Tok.Previous->Previous->is(tok::l_paren))
+ return true;
+ }
if (!Tok.Next->Next)
return false;
@@ -2184,7 +2230,7 @@ private:
return prec::Assignment;
if (Current->is(TT_LambdaArrow))
return prec::Comma;
- if (Current->is(TT_JsFatArrow))
+ if (Current->is(TT_FatArrow))
return prec::Assignment;
if (Current->isOneOf(tok::semi, TT_InlineASMColon, TT_SelectorName) ||
(Current->is(tok::comment) && NextNonComment &&
@@ -2430,6 +2476,14 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
if (Next->MatchingParen->Next &&
Next->MatchingParen->Next->is(TT_PointerOrReference))
return true;
+ // Check for K&R C function definitions, e.g.:
+ // int f(i)
+ // {
+ // return i + 1;
+ // }
+ if (Next->Next && Next->Next->is(tok::identifier) &&
+ !(Next->MatchingParen->Next && Next->MatchingParen->Next->is(tok::semi)))
+ return true;
for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen;
Tok = Tok->Next) {
if (Tok->is(TT_TypeDeclarationParen))
@@ -2483,6 +2537,12 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
: Line.FirstStartColumn + Line.First->ColumnWidth;
FormatToken *Current = Line.First->Next;
bool InFunctionDecl = Line.MightBeFunctionDecl;
+ bool AlignArrayOfStructures =
+ (Style.AlignArrayOfStructures != FormatStyle::AIAS_None &&
+ Line.Type == LT_ArrayOfStructInitializer);
+ if (AlignArrayOfStructures)
+ calculateArrayInitializerColumnList(Line);
+
while (Current) {
if (isFunctionDeclarationName(*Current, Line))
Current->setType(TT_FunctionDeclarationName);
@@ -2602,6 +2662,45 @@ void TokenAnnotator::calculateUnbreakableTailLengths(AnnotatedLine &Line) {
}
}
+void TokenAnnotator::calculateArrayInitializerColumnList(AnnotatedLine &Line) {
+ if (Line.First == Line.Last) {
+ return;
+ }
+ auto *CurrentToken = Line.First;
+ CurrentToken->ArrayInitializerLineStart = true;
+ unsigned Depth = 0;
+ while (CurrentToken != nullptr && CurrentToken != Line.Last) {
+ if (CurrentToken->is(tok::l_brace)) {
+ CurrentToken->IsArrayInitializer = true;
+ if (CurrentToken->Next != nullptr)
+ CurrentToken->Next->MustBreakBefore = true;
+ CurrentToken =
+ calculateInitializerColumnList(Line, CurrentToken->Next, Depth + 1);
+ } else {
+ CurrentToken = CurrentToken->Next;
+ }
+ }
+}
+
+FormatToken *TokenAnnotator::calculateInitializerColumnList(
+ AnnotatedLine &Line, FormatToken *CurrentToken, unsigned Depth) {
+ while (CurrentToken != nullptr && CurrentToken != Line.Last) {
+ if (CurrentToken->is(tok::l_brace))
+ ++Depth;
+ else if (CurrentToken->is(tok::r_brace))
+ --Depth;
+ if (Depth == 2 && CurrentToken->isOneOf(tok::l_brace, tok::comma)) {
+ CurrentToken = CurrentToken->Next;
+ if (CurrentToken == nullptr)
+ break;
+ CurrentToken->StartsColumn = true;
+ CurrentToken = CurrentToken->Previous;
+ }
+ CurrentToken = CurrentToken->Next;
+ }
+ return CurrentToken;
+}
+
unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
const FormatToken &Tok,
bool InFunctionDecl) {
@@ -2809,6 +2908,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
const FormatToken &Right) {
if (Left.is(tok::kw_return) && Right.isNot(tok::semi))
return true;
+ if (Style.isJson() && Left.is(tok::string_literal) && Right.is(tok::colon))
+ return false;
if (Left.is(Keywords.kw_assert) && Style.Language == FormatStyle::LK_Java)
return true;
if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty &&
@@ -2897,16 +2998,17 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Both) &&
(Left.is(TT_AttributeParen) || Left.canBePointerOrReferenceQualifier()))
return true;
- return (Left.Tok.isLiteral() ||
- (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) &&
- (Style.PointerAlignment != FormatStyle::PAS_Left ||
- (Line.IsMultiVariableDeclStmt &&
- (Left.NestingLevel == 0 ||
- (Left.NestingLevel == 1 && Line.First->is(tok::kw_for)))))));
+ return (
+ Left.Tok.isLiteral() ||
+ (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) &&
+ (getTokenPointerOrReferenceAlignment(Right) != FormatStyle::PAS_Left ||
+ (Line.IsMultiVariableDeclStmt &&
+ (Left.NestingLevel == 0 ||
+ (Left.NestingLevel == 1 && Line.First->is(tok::kw_for)))))));
}
if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) &&
(!Left.is(TT_PointerOrReference) ||
- (Style.PointerAlignment != FormatStyle::PAS_Right &&
+ (getTokenPointerOrReferenceAlignment(Left) != FormatStyle::PAS_Right &&
!Line.IsMultiVariableDeclStmt)))
return true;
if (Left.is(TT_PointerOrReference)) {
@@ -2922,7 +3024,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
(Right.is(tok::l_brace) && Right.is(BK_Block)) ||
(!Right.isOneOf(TT_PointerOrReference, TT_ArraySubscriptLSquare,
tok::l_paren) &&
- (Style.PointerAlignment != FormatStyle::PAS_Right &&
+ (getTokenPointerOrReferenceAlignment(Left) !=
+ FormatStyle::PAS_Right &&
!Line.IsMultiVariableDeclStmt) &&
Left.Previous &&
!Left.Previous->isOneOf(tok::l_paren, tok::coloncolon,
@@ -2957,6 +3060,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
// Space between the type and the * in:
// operator void*()
// operator char*()
+ // operator void const*()
+ // operator void volatile*()
// operator /*comment*/ const char*()
// operator volatile /*comment*/ char*()
// operator Foo*()
@@ -2964,11 +3069,15 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
// operator std::Foo*()
// operator C<T>::D<U>*()
// dependent on PointerAlignment style.
- if (Previous &&
- (Previous->endsSequence(tok::kw_operator) ||
- Previous->endsSequence(tok::kw_const, tok::kw_operator) ||
- Previous->endsSequence(tok::kw_volatile, tok::kw_operator)))
- return (Style.PointerAlignment != FormatStyle::PAS_Left);
+ if (Previous) {
+ if (Previous->endsSequence(tok::kw_operator))
+ return (Style.PointerAlignment != FormatStyle::PAS_Left);
+ if (Previous->is(tok::kw_const) || Previous->is(tok::kw_volatile))
+ return (Style.PointerAlignment != FormatStyle::PAS_Left) ||
+ (Style.SpaceAroundPointerQualifiers ==
+ FormatStyle::SAPQ_After) ||
+ (Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Both);
+ }
}
const auto SpaceRequiredForArrayInitializerLSquare =
[](const FormatToken &LSquareTok, const FormatStyle &Style) {
@@ -3023,9 +3132,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
(Left.is(tok::r_square) && Left.is(TT_AttributeSquare)))
return true;
if (Style.SpaceBeforeParens ==
- FormatStyle::SBPO_ControlStatementsExceptForEachMacros &&
+ FormatStyle::SBPO_ControlStatementsExceptControlMacros &&
Left.is(TT_ForEachMacro))
return false;
+ if (Style.SpaceBeforeParens ==
+ FormatStyle::SBPO_ControlStatementsExceptControlMacros &&
+ Left.is(TT_IfMacro))
+ return false;
return Line.Type == LT_ObjCDecl || Left.is(tok::semi) ||
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
(Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while,
@@ -3081,13 +3194,16 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
// Match const and volatile ref-qualifiers without any additional
// qualifiers such as
// void Fn() const &;
- return Style.PointerAlignment != FormatStyle::PAS_Left;
+ return getTokenReferenceAlignment(Right) != FormatStyle::PAS_Left;
return true;
}
bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
const FormatToken &Right) {
const FormatToken &Left = *Right.Previous;
+ auto HasExistingWhitespace = [&Right]() {
+ return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
+ };
if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo())
return true; // Never ever merge two identifiers.
if (Style.isCpp()) {
@@ -3120,7 +3236,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// Preserve the existence of a space before a percent for cases like 0x%04x
// and "%d %d"
if (Left.is(tok::numeric_constant) && Right.is(tok::percent))
- return Right.WhitespaceRange.getEnd() != Right.WhitespaceRange.getBegin();
+ return HasExistingWhitespace();
+ } else if (Style.isJson()) {
+ if (Right.is(tok::colon))
+ return false;
} else if (Style.isCSharp()) {
// Require spaces around '{' and before '}' unless they appear in
// interpolated strings. Interpolated strings are merged into a single token
@@ -3146,7 +3265,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return true;
// Spaces around '=>'.
- if (Left.is(TT_JsFatArrow) || Right.is(TT_JsFatArrow))
+ if (Left.is(TT_FatArrow) || Right.is(TT_FatArrow))
return true;
// No spaces around attribute target colons
@@ -3165,30 +3284,14 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Right.is(TT_CSharpNullable))
return false;
- // Require space after ? in nullable types except in generics and casts.
- if (Left.is(TT_CSharpNullable))
- return !Right.isOneOf(TT_TemplateCloser, tok::r_paren);
-
- // No space before or after '?.'.
- if (Left.is(TT_CSharpNullConditional) || Right.is(TT_CSharpNullConditional))
- return false;
-
- // Space before and after '??'.
- if (Left.is(TT_CSharpNullCoalescing) || Right.is(TT_CSharpNullCoalescing))
- return true;
-
- // No space before '?['.
- if (Right.is(TT_CSharpNullConditionalLSquare))
+ // No space before null forgiving '!'.
+ if (Right.is(TT_NonNullAssertion))
return false;
// No space between consecutive commas '[,,]'.
if (Left.is(tok::comma) && Right.is(tok::comma))
return false;
- // Possible space inside `?[ 0 ]`.
- if (Left.is(TT_CSharpNullConditionalLSquare))
- return Style.SpacesInSquareBrackets;
-
// space after var in `var (key, value)`
if (Left.is(Keywords.kw_var) && Right.is(tok::l_paren))
return true;
@@ -3210,7 +3313,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
Right.is(tok::l_paren))
return true;
} else if (Style.Language == FormatStyle::LK_JavaScript) {
- if (Left.is(TT_JsFatArrow))
+ if (Left.is(TT_FatArrow))
return true;
// for await ( ...
if (Right.is(tok::l_paren) && Left.is(Keywords.kw_await) && Left.Previous &&
@@ -3221,7 +3324,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
const FormatToken *Next = Right.MatchingParen->getNextNonComment();
// An async arrow function, for example: `x = async () => foo();`,
// as opposed to calling a function called async: `x = async();`
- if (Next && Next->is(TT_JsFatArrow))
+ if (Next && Next->is(TT_FatArrow))
return true;
}
if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) ||
@@ -3295,9 +3398,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// locations that should have whitespace following are identified by the
// above set of follower tokens.
return false;
- if (Right.is(TT_JsNonNullAssertion))
+ if (Right.is(TT_NonNullAssertion))
return false;
- if (Left.is(TT_JsNonNullAssertion) &&
+ if (Left.is(TT_NonNullAssertion) &&
Right.isOneOf(Keywords.kw_as, Keywords.kw_in))
return true; // "x! as string", "x! in y"
} else if (Style.Language == FormatStyle::LK_Java) {
@@ -3313,7 +3416,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return true;
}
if (Left.is(TT_ImplicitStringLiteral))
- return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
+ return HasExistingWhitespace();
if (Line.Type == LT_ObjCMethodDecl) {
if (Left.is(TT_ObjCMethodSpecifier))
return true;
@@ -3370,6 +3473,12 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
Style.BitFieldColonSpacing == FormatStyle::BFCS_Before;
return true;
}
+ // Do not merge "- -" into "--".
+ if ((Left.isOneOf(tok::minus, tok::minusminus) &&
+ Right.isOneOf(tok::minus, tok::minusminus)) ||
+ (Left.isOneOf(tok::plus, tok::plusplus) &&
+ Right.isOneOf(tok::plus, tok::plusplus)))
+ return true;
if (Left.is(TT_UnaryOperator)) {
if (!Right.is(tok::l_paren)) {
// The alternative operators for ~ and ! are "compl" and "not".
@@ -3394,12 +3503,21 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return Style.SpaceAfterCStyleCast ||
Right.isOneOf(TT_BinaryOperator, TT_SelectorName);
+ auto ShouldAddSpacesInAngles = [this, &HasExistingWhitespace]() {
+ if (this->Style.SpacesInAngles == FormatStyle::SIAS_Always)
+ return true;
+ if (this->Style.SpacesInAngles == FormatStyle::SIAS_Leave)
+ return HasExistingWhitespace();
+ return false;
+ };
+
if (Left.is(tok::greater) && Right.is(tok::greater)) {
if (Style.Language == FormatStyle::LK_TextProto ||
(Style.Language == FormatStyle::LK_Proto && Left.is(TT_DictLiteral)))
return !Style.Cpp11BracedListStyle;
return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) &&
- (Style.Standard < FormatStyle::LS_Cpp11 || Style.SpacesInAngles);
+ ((Style.Standard < FormatStyle::LS_Cpp11) ||
+ ShouldAddSpacesInAngles());
}
if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) ||
Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
@@ -3415,26 +3533,27 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// Generally don't remove existing spaces between an identifier and "::".
// The identifier might actually be a macro name such as ALWAYS_INLINE. If
// this turns out to be too lenient, add analysis of the identifier itself.
- return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
+ return HasExistingWhitespace();
if (Right.is(tok::coloncolon) &&
!Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren))
// Put a space between < and :: in vector< ::std::string >
return (Left.is(TT_TemplateOpener) &&
- (Style.Standard < FormatStyle::LS_Cpp11 || Style.SpacesInAngles)) ||
+ ((Style.Standard < FormatStyle::LS_Cpp11) ||
+ ShouldAddSpacesInAngles())) ||
!(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
tok::kw___super, TT_TemplateOpener,
TT_TemplateCloser)) ||
(Left.is(tok::l_paren) && Style.SpacesInParentheses);
if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser)))
- return Style.SpacesInAngles;
+ return ShouldAddSpacesInAngles();
// Space before TT_StructuredBindingLSquare.
if (Right.is(TT_StructuredBindingLSquare))
return !Left.isOneOf(tok::amp, tok::ampamp) ||
- Style.PointerAlignment != FormatStyle::PAS_Right;
+ getTokenReferenceAlignment(Left) != FormatStyle::PAS_Right;
// Space before & or && following a TT_StructuredBindingLSquare.
if (Right.Next && Right.Next->is(TT_StructuredBindingLSquare) &&
Right.isOneOf(tok::amp, tok::ampamp))
- return Style.PointerAlignment != FormatStyle::PAS_Left;
+ return getTokenReferenceAlignment(Right) != FormatStyle::PAS_Left;
if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) ||
(Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) &&
!Right.is(tok::r_paren)))
@@ -3473,42 +3592,11 @@ isItAnEmptyLambdaAllowed(const FormatToken &Tok,
return Tok.Children.empty() && ShortLambdaOption != FormatStyle::SLS_None;
}
-static bool
-isItAInlineLambdaAllowed(const FormatToken &Tok,
- FormatStyle::ShortLambdaStyle ShortLambdaOption) {
- return (ShortLambdaOption == FormatStyle::SLS_Inline &&
- IsFunctionArgument(Tok)) ||
- (ShortLambdaOption == FormatStyle::SLS_All);
-}
-
-static bool isOneChildWithoutMustBreakBefore(const FormatToken &Tok) {
- if (Tok.Children.size() != 1)
- return false;
- FormatToken *curElt = Tok.Children[0]->First;
- while (curElt) {
- if (curElt->MustBreakBefore)
- return false;
- curElt = curElt->Next;
- }
- return true;
-}
static bool isAllmanLambdaBrace(const FormatToken &Tok) {
return (Tok.is(tok::l_brace) && Tok.is(BK_Block) &&
!Tok.isOneOf(TT_ObjCBlockLBrace, TT_DictLiteral));
}
-static bool isAllmanBraceIncludedBreakableLambda(
- const FormatToken &Tok, FormatStyle::ShortLambdaStyle ShortLambdaOption) {
- if (!isAllmanLambdaBrace(Tok))
- return false;
-
- if (isItAnEmptyLambdaAllowed(Tok, ShortLambdaOption))
- return false;
-
- return !isItAInlineLambdaAllowed(Tok, ShortLambdaOption) ||
- !isOneChildWithoutMustBreakBefore(Tok);
-}
-
bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
const FormatToken &Right) {
const FormatToken &Left = *Right.Previous;
@@ -3521,6 +3609,17 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return false;
if (Right.is(TT_CSharpGenericTypeConstraint))
return true;
+
+ // Break after C# [...] and before public/protected/private/internal.
+ if (Left.is(TT_AttributeSquare) && Left.is(tok::r_square) &&
+ (Right.isAccessSpecifier(/*ColonRequired=*/false) ||
+ Right.is(Keywords.kw_internal)))
+ return true;
+ // Break between ] and [ but only when there are really 2 attributes.
+ if (Left.is(TT_AttributeSquare) && Right.is(TT_AttributeSquare) &&
+ Left.is(tok::r_square) && Right.is(tok::l_square))
+ return true;
+
} else if (Style.Language == FormatStyle::LK_JavaScript) {
// FIXME: This might apply to other languages and token kinds.
if (Right.is(tok::string_literal) && Left.is(tok::plus) && Left.Previous &&
@@ -3545,7 +3644,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
// instead of bin-packing.
return true;
if (Right.is(tok::r_brace) && Left.is(tok::l_brace) && Left.Previous &&
- Left.Previous->is(TT_JsFatArrow)) {
+ Left.Previous->is(TT_FatArrow)) {
// JS arrow function (=> {...}).
switch (Style.AllowShortLambdasOnASingleLine) {
case FormatStyle::SLS_All:
@@ -3584,6 +3683,26 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return true;
}
+ // Basic JSON newline processing.
+ if (Style.isJson()) {
+ // Always break after a JSON record opener.
+ // {
+ // }
+ if (Left.is(TT_DictLiteral) && Left.is(tok::l_brace))
+ return true;
+ // Always break after a JSON array opener.
+ // [
+ // ]
+ if (Left.is(TT_ArrayInitializerLSquare) && Left.is(tok::l_square) &&
+ !Right.is(tok::r_square))
+ return true;
+ // Always break afer successive entries.
+ // 1,
+ // 2
+ if (Left.is(tok::comma))
+ return true;
+ }
+
// If the last token before a '}', ']', or ')' is a comma or a trailing
// comment, the intention is to insert a line break after it in order to make
// shuffling around entries easier. Import statements, especially in
@@ -3640,6 +3759,9 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
if (Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma &&
Right.is(TT_InheritanceComma))
return true;
+ if (Style.BreakInheritanceList == FormatStyle::BILS_AfterComma &&
+ Left.is(TT_InheritanceComma))
+ return true;
if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\""))
// Multiline raw string literals are special wrt. line breaks. The author
// has made a deliberate choice and might have aligned the contents of the
@@ -3656,13 +3778,6 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
if (Right.is(TT_InlineASMBrace))
return Right.HasUnescapedNewline;
- auto ShortLambdaOption = Style.AllowShortLambdasOnASingleLine;
- if (Style.BraceWrapping.BeforeLambdaBody &&
- (isAllmanBraceIncludedBreakableLambda(Left, ShortLambdaOption) ||
- isAllmanBraceIncludedBreakableLambda(Right, ShortLambdaOption))) {
- return true;
- }
-
if (isAllmanBrace(Left) || isAllmanBrace(Right))
return (Line.startsWith(tok::kw_enum) && Style.BraceWrapping.AfterEnum) ||
(Line.startsWith(tok::kw_typedef, tok::kw_enum) &&
@@ -3685,6 +3800,11 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return true;
}
+ if (Style.BraceWrapping.BeforeLambdaBody && Right.is(TT_LambdaLBrace) &&
+ Left.isOneOf(tok::star, tok::amp, tok::ampamp, TT_TemplateCloser)) {
+ return true;
+ }
+
// Put multiple Java annotation on a new line.
if ((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
@@ -3819,6 +3939,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
// Only break after commas for generic type constraints.
if (Line.First->is(TT_CSharpGenericTypeConstraint))
return Left.is(TT_CSharpGenericTypeConstraintComma);
+ // Keep nullable operators attached to their identifiers.
+ if (Right.is(TT_CSharpNullable)) {
+ return false;
+ }
} else if (Style.Language == FormatStyle::LK_Java) {
if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
Keywords.kw_implements))
@@ -3841,7 +3965,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
Left.isOneOf(tok::r_square, tok::r_paren)) &&
Right.isOneOf(tok::l_square, tok::l_paren))
return false; // Otherwise automatic semicolon insertion would trigger.
- if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace))
+ if (NonComment && NonComment->is(tok::identifier) &&
+ NonComment->TokenText == "asserts")
+ return false;
+ if (Left.is(TT_FatArrow) && Right.is(tok::l_brace))
return false;
if (Left.is(TT_JsTypeColon))
return true;
@@ -3877,7 +4004,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
}
if (Left.is(Keywords.kw_as))
return true;
- if (Left.is(TT_JsNonNullAssertion))
+ if (Left.is(TT_NonNullAssertion))
return true;
if (Left.is(Keywords.kw_declare) &&
Right.isOneOf(Keywords.kw_module, tok::kw_namespace,
@@ -3909,7 +4036,8 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return !Right.is(tok::l_paren);
if (Right.is(TT_PointerOrReference))
return Line.IsMultiVariableDeclStmt ||
- (Style.PointerAlignment == FormatStyle::PAS_Right &&
+ (getTokenPointerOrReferenceAlignment(Right) ==
+ FormatStyle::PAS_Right &&
(!Right.Next || Right.Next->isNot(TT_FunctionDeclarationName)));
if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
Right.is(tok::kw_operator))
@@ -4081,7 +4209,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return false;
auto ShortLambdaOption = Style.AllowShortLambdasOnASingleLine;
- if (Style.BraceWrapping.BeforeLambdaBody) {
+ if (Style.BraceWrapping.BeforeLambdaBody && Right.is(TT_LambdaLBrace)) {
if (isAllmanLambdaBrace(Left))
return !isItAnEmptyLambdaAllowed(Left, ShortLambdaOption);
if (isAllmanLambdaBrace(Right))
@@ -4093,7 +4221,6 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
Right.isMemberAccess() ||
Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow, tok::lessless,
tok::colon, tok::l_square, tok::at) ||
- (Style.BraceWrapping.BeforeLambdaBody && Right.is(TT_LambdaLBrace)) ||
(Left.is(tok::r_paren) &&
Right.isOneOf(tok::identifier, tok::kw_const)) ||
(Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
@@ -4124,5 +4251,41 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {
llvm::errs() << "----\n";
}
+FormatStyle::PointerAlignmentStyle
+TokenAnnotator::getTokenReferenceAlignment(const FormatToken &Reference) {
+ assert(Reference.isOneOf(tok::amp, tok::ampamp));
+ switch (Style.ReferenceAlignment) {
+ case FormatStyle::RAS_Pointer:
+ return Style.PointerAlignment;
+ case FormatStyle::RAS_Left:
+ return FormatStyle::PAS_Left;
+ case FormatStyle::RAS_Right:
+ return FormatStyle::PAS_Right;
+ case FormatStyle::RAS_Middle:
+ return FormatStyle::PAS_Middle;
+ }
+ assert(0); //"Unhandled value of ReferenceAlignment"
+ return Style.PointerAlignment;
+}
+
+FormatStyle::PointerAlignmentStyle
+TokenAnnotator::getTokenPointerOrReferenceAlignment(
+ const FormatToken &PointerOrReference) {
+ if (PointerOrReference.isOneOf(tok::amp, tok::ampamp)) {
+ switch (Style.ReferenceAlignment) {
+ case FormatStyle::RAS_Pointer:
+ return Style.PointerAlignment;
+ case FormatStyle::RAS_Left:
+ return FormatStyle::PAS_Left;
+ case FormatStyle::RAS_Right:
+ return FormatStyle::PAS_Right;
+ case FormatStyle::RAS_Middle:
+ return FormatStyle::PAS_Middle;
+ }
+ }
+ assert(PointerOrReference.is(tok::star));
+ return Style.PointerAlignment;
+}
+
} // namespace format
} // namespace clang