summaryrefslogtreecommitdiff
path: root/clang/lib/Format/TokenAnnotator.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
commitcfca06d7963fa0909f90483b42a6d7d194d01e08 (patch)
tree209fb2a2d68f8f277793fc8df46c753d31bc853b /clang/lib/Format/TokenAnnotator.cpp
parent706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff)
Notes
Diffstat (limited to 'clang/lib/Format/TokenAnnotator.cpp')
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp697
1 files changed, 521 insertions, 176 deletions
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index d5d394e61926a..7f8e351265127 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -118,9 +118,9 @@ private:
if (Style.Language == FormatStyle::LK_TextProto ||
(Style.Language == FormatStyle::LK_Proto && Left->Previous &&
Left->Previous->isOneOf(TT_SelectorName, TT_DictLiteral)))
- CurrentToken->Type = TT_DictLiteral;
+ CurrentToken->setType(TT_DictLiteral);
else
- CurrentToken->Type = TT_TemplateCloser;
+ CurrentToken->setType(TT_TemplateCloser);
next();
return true;
}
@@ -131,7 +131,7 @@ private:
}
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
(CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
- Style.Language != FormatStyle::LK_Proto &&
+ !Style.isCSharp() && Style.Language != FormatStyle::LK_Proto &&
Style.Language != FormatStyle::LK_TextProto))
return false;
// If a && or || is found and interpreted as a binary operator, this set
@@ -151,7 +151,7 @@ private:
if (CurrentToken->is(tok::colon) ||
(CurrentToken->isOneOf(tok::l_brace, tok::less) &&
Previous->isNot(tok::colon)))
- Previous->Type = TT_SelectorName;
+ Previous->setType(TT_SelectorName);
}
}
if (!consumeToken())
@@ -160,6 +160,27 @@ private:
return false;
}
+ bool parseUntouchableParens() {
+ while (CurrentToken) {
+ CurrentToken->Finalized = true;
+ switch (CurrentToken->Tok.getKind()) {
+ case tok::l_paren:
+ next();
+ if (!parseUntouchableParens())
+ return false;
+ continue;
+ case tok::r_paren:
+ next();
+ return true;
+ default:
+ // no-op
+ break;
+ }
+ next();
+ }
+ return false;
+ }
+
bool parseParens(bool LookForDecls = false) {
if (!CurrentToken)
return false;
@@ -171,6 +192,11 @@ private:
Contexts.back().ColonIsForRangeExpr =
Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
+ if (Left->Previous && Left->Previous->is(TT_UntouchableMacroFunc)) {
+ Left->Finalized = true;
+ return parseUntouchableParens();
+ }
+
bool StartsObjCMethodExpr = false;
if (FormatToken *MaybeSel = Left->Previous) {
// @selector( starts a selector.
@@ -217,7 +243,7 @@ private:
// This is the parameter list of an ObjC block.
Contexts.back().IsExpression = false;
} else if (Left->Previous && Left->Previous->is(tok::kw___attribute)) {
- Left->Type = TT_AttributeParen;
+ Left->setType(TT_AttributeParen);
} else if (Left->Previous && Left->Previous->is(TT_ForEachMacro)) {
// The first argument to a foreach macro is a declaration.
Contexts.back().IsForEachMacro = true;
@@ -233,7 +259,7 @@ private:
if (StartsObjCMethodExpr) {
Contexts.back().ColonIsObjCMethodExpr = true;
- Left->Type = TT_ObjCMethodExpr;
+ Left->setType(TT_ObjCMethodExpr);
}
// MightBeFunctionType and ProbablyFunctionType are used for
@@ -264,7 +290,7 @@ private:
if (PrevPrev && PrevPrev->is(tok::identifier) &&
Prev->isOneOf(tok::star, tok::amp, tok::ampamp) &&
CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) {
- Prev->Type = TT_BinaryOperator;
+ Prev->setType(TT_BinaryOperator);
LookForDecls = false;
}
}
@@ -282,8 +308,8 @@ private:
if (MightBeFunctionType && ProbablyFunctionType && CurrentToken->Next &&
(CurrentToken->Next->is(tok::l_paren) ||
(CurrentToken->Next->is(tok::l_square) && Line.MustBeDeclaration)))
- Left->Type = Left->Next->is(tok::caret) ? TT_ObjCBlockLParen
- : TT_FunctionTypeLParen;
+ Left->setType(Left->Next->is(tok::caret) ? TT_ObjCBlockLParen
+ : TT_FunctionTypeLParen);
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
@@ -295,12 +321,12 @@ private:
for (FormatToken *Tok = Left; Tok != CurrentToken; Tok = Tok->Next) {
if (Tok->is(TT_BinaryOperator) &&
Tok->isOneOf(tok::star, tok::amp, tok::ampamp))
- Tok->Type = TT_PointerOrReference;
+ Tok->setType(TT_PointerOrReference);
}
}
if (StartsObjCMethodExpr) {
- CurrentToken->Type = TT_ObjCMethodExpr;
+ CurrentToken->setType(TT_ObjCMethodExpr);
if (Contexts.back().FirstObjCSelectorName) {
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
@@ -308,13 +334,13 @@ private:
}
if (Left->is(TT_AttributeParen))
- CurrentToken->Type = TT_AttributeParen;
+ CurrentToken->setType(TT_AttributeParen);
if (Left->Previous && Left->Previous->is(TT_JavaAnnotation))
- CurrentToken->Type = TT_JavaAnnotation;
+ CurrentToken->setType(TT_JavaAnnotation);
if (Left->Previous && Left->Previous->is(TT_LeadingJavaAnnotation))
- CurrentToken->Type = TT_LeadingJavaAnnotation;
+ CurrentToken->setType(TT_LeadingJavaAnnotation);
if (Left->Previous && Left->Previous->is(TT_AttributeSquare))
- CurrentToken->Type = TT_AttributeSquare;
+ CurrentToken->setType(TT_AttributeSquare);
if (!HasMultipleLines)
Left->PackingKind = PPK_Inconclusive;
@@ -330,7 +356,7 @@ private:
return false;
if (CurrentToken->is(tok::l_brace))
- Left->Type = TT_Unknown; // Not TT_ObjCBlockLParen
+ Left->setType(TT_Unknown); // Not TT_ObjCBlockLParen
if (CurrentToken->is(tok::comma) && CurrentToken->Next &&
!CurrentToken->Next->HasUnescapedNewline &&
!CurrentToken->Next->isTrailingComment())
@@ -342,13 +368,13 @@ private:
if (CurrentToken->isOneOf(tok::semi, tok::colon)) {
MightBeObjCForRangeLoop = false;
if (PossibleObjCForInToken) {
- PossibleObjCForInToken->Type = TT_Unknown;
+ PossibleObjCForInToken->setType(TT_Unknown);
PossibleObjCForInToken = nullptr;
}
}
if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in)) {
PossibleObjCForInToken = CurrentToken;
- PossibleObjCForInToken->Type = TT_ObjCForIn;
+ PossibleObjCForInToken->setType(TT_ObjCForIn);
}
// When we discover a 'new', we set CanBeExpression to 'false' in order to
// parse the type correctly. Reset that after a comma.
@@ -369,6 +395,17 @@ private:
if (!Style.isCSharp())
return false;
+ // `identifier[i]` is not an attribute.
+ if (Tok.Previous && Tok.Previous->is(tok::identifier))
+ return false;
+
+ // Chains of [] in `identifier[i][j][k]` are not attributes.
+ if (Tok.Previous && Tok.Previous->is(tok::r_square)) {
+ auto *MatchingParen = Tok.Previous->MatchingParen;
+ if (!MatchingParen || MatchingParen->is(TT_ArraySubscriptLSquare))
+ return false;
+ }
+
const FormatToken *AttrTok = Tok.Next;
if (!AttrTok)
return false;
@@ -385,15 +422,15 @@ private:
if (!AttrTok)
return false;
- // Move past the end of ']'.
+ // Allow an attribute to be the only content of a file.
AttrTok = AttrTok->Next;
if (!AttrTok)
- return false;
+ return true;
// Limit this to being an access modifier that follows.
if (AttrTok->isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected,
- tok::kw_class, tok::kw_static, tok::l_square,
- Keywords.kw_internal)) {
+ tok::comment, tok::kw_class, tok::kw_static,
+ tok::l_square, Keywords.kw_internal)) {
return true;
}
@@ -460,7 +497,7 @@ private:
Contexts.back().InCpp11AttributeSpecifier;
// Treat C# Attributes [STAThread] much like C++ attributes [[...]].
- bool IsCSharp11AttributeSpecifier =
+ bool IsCSharpAttributeSpecifier =
isCSharpAttributeSpecifier(*Left) ||
Contexts.back().InCSharpAttributeSpecifier;
@@ -469,7 +506,8 @@ private:
bool StartsObjCMethodExpr =
!IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates &&
Style.isCpp() && !IsCpp11AttributeSpecifier &&
- Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
+ !IsCSharpAttributeSpecifier && Contexts.back().CanBeExpression &&
+ Left->isNot(TT_LambdaLSquare) &&
!CurrentToken->isOneOf(tok::l_brace, tok::r_square) &&
(!Parent ||
Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
@@ -483,24 +521,26 @@ private:
unsigned BindingIncrease = 1;
if (IsCppStructuredBinding) {
- Left->Type = TT_StructuredBindingLSquare;
+ Left->setType(TT_StructuredBindingLSquare);
} else if (Left->is(TT_Unknown)) {
if (StartsObjCMethodExpr) {
- Left->Type = TT_ObjCMethodExpr;
+ Left->setType(TT_ObjCMethodExpr);
+ } else if (InsideInlineASM) {
+ Left->setType(TT_InlineASMSymbolicNameLSquare);
} else if (IsCpp11AttributeSpecifier) {
- Left->Type = TT_AttributeSquare;
+ Left->setType(TT_AttributeSquare);
} else if (Style.Language == FormatStyle::LK_JavaScript && Parent &&
Contexts.back().ContextKind == tok::l_brace &&
Parent->isOneOf(tok::l_brace, tok::comma)) {
- Left->Type = TT_JsComputedPropertyName;
+ Left->setType(TT_JsComputedPropertyName);
} else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
- Left->Type = TT_DesignatedInitializerLSquare;
- } else if (IsCSharp11AttributeSpecifier) {
- Left->Type = TT_AttributeSquare;
+ Left->setType(TT_DesignatedInitializerLSquare);
+ } else if (IsCSharpAttributeSpecifier) {
+ Left->setType(TT_AttributeSquare);
} else if (CurrentToken->is(tok::r_square) && Parent &&
Parent->is(TT_TemplateCloser)) {
- Left->Type = TT_ArraySubscriptLSquare;
+ Left->setType(TT_ArraySubscriptLSquare);
} else if (Style.Language == FormatStyle::LK_Proto ||
Style.Language == FormatStyle::LK_TextProto) {
// Square braces in LK_Proto can either be message field attributes:
@@ -529,13 +569,13 @@ private:
//
// In the first and the third case we want to spread the contents inside
// the square braces; in the second we want to keep them inline.
- Left->Type = TT_ArrayInitializerLSquare;
+ Left->setType(TT_ArrayInitializerLSquare);
if (!Left->endsSequence(tok::l_square, tok::numeric_constant,
tok::equal) &&
!Left->endsSequence(tok::l_square, tok::numeric_constant,
tok::identifier) &&
!Left->endsSequence(tok::l_square, tok::colon, TT_SelectorName)) {
- Left->Type = TT_ProtoExtensionLSquare;
+ Left->setType(TT_ProtoExtensionLSquare);
BindingIncrease = 10;
}
} else if (!CppArrayTemplates && Parent &&
@@ -544,10 +584,10 @@ private:
tok::question, tok::colon, tok::kw_return,
// Should only be relevant to JavaScript:
tok::kw_default)) {
- Left->Type = TT_ArrayInitializerLSquare;
+ Left->setType(TT_ArrayInitializerLSquare);
} else {
BindingIncrease = 10;
- Left->Type = TT_ArraySubscriptLSquare;
+ Left->setType(TT_ArraySubscriptLSquare);
}
}
@@ -559,14 +599,14 @@ private:
Contexts.back().ColonIsObjCMethodExpr = StartsObjCMethodExpr;
Contexts.back().InCpp11AttributeSpecifier = IsCpp11AttributeSpecifier;
- Contexts.back().InCSharpAttributeSpecifier = IsCSharp11AttributeSpecifier;
+ Contexts.back().InCSharpAttributeSpecifier = IsCSharpAttributeSpecifier;
while (CurrentToken) {
if (CurrentToken->is(tok::r_square)) {
if (IsCpp11AttributeSpecifier)
- CurrentToken->Type = TT_AttributeSquare;
- if (IsCSharp11AttributeSpecifier)
- CurrentToken->Type = TT_AttributeSquare;
+ CurrentToken->setType(TT_AttributeSquare);
+ if (IsCSharpAttributeSpecifier)
+ CurrentToken->setType(TT_AttributeSquare);
else if (((CurrentToken->Next &&
CurrentToken->Next->is(tok::l_paren)) ||
(CurrentToken->Previous &&
@@ -577,26 +617,26 @@ private:
// will be expanded to more tokens.
// FIXME: Do we incorrectly label ":" with this?
StartsObjCMethodExpr = false;
- Left->Type = TT_Unknown;
+ Left->setType(TT_Unknown);
}
if (StartsObjCMethodExpr && CurrentToken->Previous != Left) {
- CurrentToken->Type = TT_ObjCMethodExpr;
+ CurrentToken->setType(TT_ObjCMethodExpr);
// If we haven't seen a colon yet, make sure the last identifier
// before the r_square is tagged as a selector name component.
if (!ColonFound && CurrentToken->Previous &&
CurrentToken->Previous->is(TT_Unknown) &&
canBeObjCSelectorComponent(*CurrentToken->Previous))
- CurrentToken->Previous->Type = TT_SelectorName;
+ CurrentToken->Previous->setType(TT_SelectorName);
// determineStarAmpUsage() thinks that '*' '[' is allocating an
// array of pointers, but if '[' starts a selector then '*' is a
// binary operator.
if (Parent && Parent->is(TT_PointerOrReference))
- Parent->Type = TT_BinaryOperator;
+ Parent->setType(TT_BinaryOperator);
}
// An arrow after an ObjC method expression is not a lambda arrow.
- if (CurrentToken->Type == TT_ObjCMethodExpr && CurrentToken->Next &&
- CurrentToken->Next->is(TT_LambdaArrow))
- CurrentToken->Next->Type = TT_Unknown;
+ if (CurrentToken->getType() == TT_ObjCMethodExpr &&
+ CurrentToken->Next && CurrentToken->Next->is(TT_LambdaArrow))
+ CurrentToken->Next->setType(TT_Unknown);
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
// FirstObjCSelectorName is set when a colon is found. This does
@@ -630,21 +670,21 @@ private:
tok::kw_using)) {
// Remember that this is a [[using ns: foo]] C++ attribute, so we
// don't add a space before the colon (unlike other colons).
- CurrentToken->Type = TT_AttributeColon;
+ CurrentToken->setType(TT_AttributeColon);
} else if (Left->isOneOf(TT_ArraySubscriptLSquare,
TT_DesignatedInitializerLSquare)) {
- Left->Type = TT_ObjCMethodExpr;
+ Left->setType(TT_ObjCMethodExpr);
StartsObjCMethodExpr = true;
Contexts.back().ColonIsObjCMethodExpr = true;
if (Parent && Parent->is(tok::r_paren))
// FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen.
- Parent->Type = TT_CastRParen;
+ Parent->setType(TT_CastRParen);
}
ColonFound = true;
}
if (CurrentToken->is(tok::comma) && Left->is(TT_ObjCMethodExpr) &&
!ColonFound)
- Left->Type = TT_ArrayInitializerLSquare;
+ Left->setType(TT_ArrayInitializerLSquare);
FormatToken *Tok = CurrentToken;
if (!consumeToken())
return false;
@@ -659,7 +699,7 @@ private:
Left->ParentBracket = Contexts.back().ContextKind;
if (Contexts.back().CaretFound)
- Left->Type = TT_ObjCBlockLBrace;
+ Left->setType(TT_ObjCBlockLBrace);
Contexts.back().CaretFound = false;
ScopedContextCreator ContextCreator(*this, tok::l_brace, 1);
@@ -688,18 +728,18 @@ private:
(!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
Style.Language == FormatStyle::LK_Proto ||
Style.Language == FormatStyle::LK_TextProto) {
- Left->Type = TT_DictLiteral;
+ Left->setType(TT_DictLiteral);
if (Previous->Tok.getIdentifierInfo() ||
Previous->is(tok::string_literal))
- Previous->Type = TT_SelectorName;
+ Previous->setType(TT_SelectorName);
}
if (CurrentToken->is(tok::colon) ||
Style.Language == FormatStyle::LK_JavaScript)
- Left->Type = TT_DictLiteral;
+ Left->setType(TT_DictLiteral);
}
if (CurrentToken->is(tok::comma) &&
Style.Language == FormatStyle::LK_JavaScript)
- Left->Type = TT_DictLiteral;
+ Left->setType(TT_DictLiteral);
if (!consumeToken())
return false;
}
@@ -726,7 +766,7 @@ private:
bool parseConditional() {
while (CurrentToken) {
if (CurrentToken->is(tok::colon)) {
- CurrentToken->Type = TT_ConditionalExpr;
+ CurrentToken->setType(TT_ConditionalExpr);
next();
return true;
}
@@ -738,7 +778,7 @@ private:
bool parseTemplateDeclaration() {
if (CurrentToken && CurrentToken->is(tok::less)) {
- CurrentToken->Type = TT_TemplateOpener;
+ CurrentToken->setType(TT_TemplateOpener);
next();
if (!parseAngle())
return false;
@@ -756,7 +796,7 @@ private:
case tok::plus:
case tok::minus:
if (!Tok->Previous && Line.MustBeDeclaration)
- Tok->Type = TT_ObjCMethodSpecifier;
+ Tok->setType(TT_ObjCMethodSpecifier);
break;
case tok::colon:
if (!Tok->Previous)
@@ -773,21 +813,30 @@ private:
(Contexts.size() == 1 &&
Line.MustBeDeclaration)) { // method/property declaration
Contexts.back().IsExpression = false;
- Tok->Type = TT_JsTypeColon;
+ Tok->setType(TT_JsTypeColon);
+ break;
+ }
+ } else if (Style.isCSharp()) {
+ if (Contexts.back().InCSharpAttributeSpecifier) {
+ Tok->setType(TT_AttributeColon);
+ break;
+ }
+ if (Contexts.back().ContextKind == tok::l_paren) {
+ Tok->setType(TT_CSharpNamedArgumentColon);
break;
}
}
if (Contexts.back().ColonIsDictLiteral ||
Style.Language == FormatStyle::LK_Proto ||
Style.Language == FormatStyle::LK_TextProto) {
- Tok->Type = TT_DictLiteral;
+ Tok->setType(TT_DictLiteral);
if (Style.Language == FormatStyle::LK_TextProto) {
if (FormatToken *Previous = Tok->getPreviousNonComment())
- Previous->Type = TT_SelectorName;
+ Previous->setType(TT_SelectorName);
}
} else if (Contexts.back().ColonIsObjCMethodExpr ||
Line.startsWith(TT_ObjCMethodSpecifier)) {
- Tok->Type = TT_ObjCMethodExpr;
+ Tok->setType(TT_ObjCMethodExpr);
const FormatToken *BeforePrevious = Tok->Previous->Previous;
// Ensure we tag all identifiers in method declarations as
// TT_SelectorName.
@@ -802,7 +851,7 @@ private:
BeforePrevious->is(tok::r_square) ||
Contexts.back().LongestObjCSelectorName == 0 ||
UnknownIdentifierInMethodDeclaration) {
- Tok->Previous->Type = TT_SelectorName;
+ Tok->Previous->setType(TT_SelectorName);
if (!Contexts.back().FirstObjCSelectorName)
Contexts.back().FirstObjCSelectorName = Tok->Previous;
else if (Tok->Previous->ColumnWidth >
@@ -814,25 +863,30 @@ private:
++Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts;
}
} else if (Contexts.back().ColonIsForRangeExpr) {
- Tok->Type = TT_RangeBasedForLoopColon;
+ Tok->setType(TT_RangeBasedForLoopColon);
} else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) {
- Tok->Type = TT_BitFieldColon;
+ Tok->setType(TT_BitFieldColon);
} else if (Contexts.size() == 1 &&
!Line.First->isOneOf(tok::kw_enum, tok::kw_case)) {
- if (Tok->getPreviousNonComment()->isOneOf(tok::r_paren,
- tok::kw_noexcept))
- Tok->Type = TT_CtorInitializerColon;
- else
- Tok->Type = TT_InheritanceColon;
+ FormatToken *Prev = Tok->getPreviousNonComment();
+ if (Prev->isOneOf(tok::r_paren, tok::kw_noexcept))
+ Tok->setType(TT_CtorInitializerColon);
+ else if (Prev->is(tok::kw_try)) {
+ // Member initializer list within function try block.
+ FormatToken *PrevPrev = Prev->getPreviousNonComment();
+ if (PrevPrev && PrevPrev->isOneOf(tok::r_paren, tok::kw_noexcept))
+ Tok->setType(TT_CtorInitializerColon);
+ } else
+ Tok->setType(TT_InheritanceColon);
} else if (canBeObjCSelectorComponent(*Tok->Previous) && Tok->Next &&
(Tok->Next->isOneOf(tok::r_paren, tok::comma) ||
(canBeObjCSelectorComponent(*Tok->Next) && Tok->Next->Next &&
Tok->Next->Next->is(tok::colon)))) {
// This handles a special macro in ObjC code where selectors including
// the colon are passed as macro arguments.
- Tok->Type = TT_ObjCMethodExpr;
+ Tok->setType(TT_ObjCMethodExpr);
} else if (Contexts.back().ContextKind == tok::l_paren) {
- Tok->Type = TT_InlineASMColon;
+ Tok->setType(TT_InlineASMColon);
}
break;
case tok::pipe:
@@ -841,7 +895,7 @@ private:
// intersection types, respectively.
if (Style.Language == FormatStyle::LK_JavaScript &&
!Contexts.back().IsExpression)
- Tok->Type = TT_JsTypeOperator;
+ Tok->setType(TT_JsTypeOperator);
break;
case tok::kw_if:
case tok::kw_while:
@@ -877,9 +931,9 @@ private:
if (Tok->Previous && Tok->Previous->is(tok::r_paren) &&
Tok->Previous->MatchingParen &&
Tok->Previous->MatchingParen->is(TT_OverloadedOperatorLParen)) {
- Tok->Previous->Type = TT_OverloadedOperator;
- Tok->Previous->MatchingParen->Type = TT_OverloadedOperator;
- Tok->Type = TT_OverloadedOperatorLParen;
+ Tok->Previous->setType(TT_OverloadedOperator);
+ Tok->Previous->MatchingParen->setType(TT_OverloadedOperator);
+ Tok->setType(TT_OverloadedOperatorLParen);
}
if (!parseParens())
@@ -898,15 +952,15 @@ private:
case tok::l_brace:
if (Style.Language == FormatStyle::LK_TextProto) {
FormatToken *Previous = Tok->getPreviousNonComment();
- if (Previous && Previous->Type != TT_DictLiteral)
- Previous->Type = TT_SelectorName;
+ if (Previous && Previous->getType() != TT_DictLiteral)
+ Previous->setType(TT_SelectorName);
}
if (!parseBrace())
return false;
break;
case tok::less:
if (parseAngle()) {
- Tok->Type = TT_TemplateOpener;
+ Tok->setType(TT_TemplateOpener);
// In TT_Proto, we must distignuish between:
// map<key, value>
// msg < item: data >
@@ -915,13 +969,13 @@ private:
if (Style.Language == FormatStyle::LK_TextProto ||
(Style.Language == FormatStyle::LK_Proto && Tok->Previous &&
Tok->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) {
- Tok->Type = TT_DictLiteral;
+ Tok->setType(TT_DictLiteral);
FormatToken *Previous = Tok->getPreviousNonComment();
- if (Previous && Previous->Type != TT_DictLiteral)
- Previous->Type = TT_SelectorName;
+ if (Previous && Previous->getType() != TT_DictLiteral)
+ Previous->setType(TT_SelectorName);
}
} else {
- Tok->Type = TT_BinaryOperator;
+ Tok->setType(TT_BinaryOperator);
NonTemplateLess.insert(Tok);
CurrentToken = Tok;
next();
@@ -937,7 +991,7 @@ private:
break;
case tok::greater:
if (Style.Language != FormatStyle::LK_TextProto)
- Tok->Type = TT_BinaryOperator;
+ Tok->setType(TT_BinaryOperator);
if (Tok->Previous && Tok->Previous->is(TT_TemplateCloser))
Tok->SpacesRequiredBefore = 1;
break;
@@ -948,20 +1002,29 @@ private:
while (CurrentToken &&
!CurrentToken->isOneOf(tok::l_paren, tok::semi, tok::r_paren)) {
if (CurrentToken->isOneOf(tok::star, tok::amp))
- CurrentToken->Type = TT_PointerOrReference;
+ CurrentToken->setType(TT_PointerOrReference);
consumeToken();
+ if (CurrentToken && CurrentToken->is(tok::comma) &&
+ CurrentToken->Previous->isNot(tok::kw_operator))
+ break;
if (CurrentToken && CurrentToken->Previous->isOneOf(
TT_BinaryOperator, TT_UnaryOperator, tok::comma,
tok::star, tok::arrow, tok::amp, tok::ampamp))
- CurrentToken->Previous->Type = TT_OverloadedOperator;
- }
- if (CurrentToken) {
- CurrentToken->Type = TT_OverloadedOperatorLParen;
- if (CurrentToken->Previous->is(TT_BinaryOperator))
- CurrentToken->Previous->Type = TT_OverloadedOperator;
+ CurrentToken->Previous->setType(TT_OverloadedOperator);
}
+ if (CurrentToken && CurrentToken->is(tok::l_paren))
+ CurrentToken->setType(TT_OverloadedOperatorLParen);
+ if (CurrentToken && CurrentToken->Previous->is(TT_BinaryOperator))
+ 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)) {
@@ -969,7 +1032,7 @@ private:
// types (fields, parameters), e.g.
// function(x?: string, y?) {...}
// class X { y?; }
- Tok->Type = TT_JsTypeOptionalQuestion;
+ Tok->setType(TT_JsTypeOptionalQuestion);
break;
}
// Declarations cannot be conditional expressions, this can only be part
@@ -977,6 +1040,18 @@ private:
if (Line.MustBeDeclaration && !Contexts.back().IsExpression &&
Style.Language == FormatStyle::LK_JavaScript)
break;
+ if (Style.isCSharp()) {
+ // `Type?)`, `Type?>`, `Type? name;` and `Type? name =` can only be
+ // nullable types.
+ // Line.MustBeDeclaration will be true for `Type? name;`.
+ if ((!Contexts.back().IsExpression && Line.MustBeDeclaration) ||
+ (Tok->Next && Tok->Next->isOneOf(tok::r_paren, tok::greater)) ||
+ (Tok->Next && Tok->Next->is(tok::identifier) && Tok->Next->Next &&
+ Tok->Next->Next->is(tok::equal))) {
+ Tok->setType(TT_CSharpNullable);
+ break;
+ }
+ }
parseConditional();
break;
case tok::kw_template:
@@ -984,9 +1059,9 @@ private:
break;
case tok::comma:
if (Contexts.back().InCtorInitializer)
- Tok->Type = TT_CtorInitializerComma;
+ Tok->setType(TT_CtorInitializerComma);
else if (Contexts.back().InInheritanceList)
- Tok->Type = TT_InheritanceComma;
+ Tok->setType(TT_InheritanceComma);
else if (Contexts.back().FirstStartOfName &&
(Contexts.size() == 1 || Line.startsWith(tok::kw_for))) {
Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
@@ -1000,6 +1075,11 @@ private:
Keywords.kw___has_include_next)) {
parseHasInclude();
}
+ if (Style.isCSharp() && Tok->is(Keywords.kw_where) && Tok->Next &&
+ Tok->Next->isNot(tok::l_paren)) {
+ Tok->setType(TT_CSharpGenericTypeConstraint);
+ parseCSharpGenericTypeConstraint();
+ }
break;
default:
break;
@@ -1007,6 +1087,35 @@ private:
return true;
}
+ void parseCSharpGenericTypeConstraint() {
+ int OpenAngleBracketsCount = 0;
+ while (CurrentToken) {
+ if (CurrentToken->is(tok::less)) {
+ // parseAngle is too greedy and will consume the whole line.
+ CurrentToken->setType(TT_TemplateOpener);
+ ++OpenAngleBracketsCount;
+ next();
+ } else if (CurrentToken->is(tok::greater)) {
+ CurrentToken->setType(TT_TemplateCloser);
+ --OpenAngleBracketsCount;
+ next();
+ } else if (CurrentToken->is(tok::comma) && OpenAngleBracketsCount == 0) {
+ // We allow line breaks after GenericTypeConstraintComma's
+ // so do not flag commas in Generics as GenericTypeConstraintComma's.
+ CurrentToken->setType(TT_CSharpGenericTypeConstraintComma);
+ next();
+ } else if (CurrentToken->is(Keywords.kw_where)) {
+ CurrentToken->setType(TT_CSharpGenericTypeConstraint);
+ next();
+ } else if (CurrentToken->is(tok::colon)) {
+ CurrentToken->setType(TT_CSharpGenericTypeConstraintColon);
+ next();
+ } else {
+ next();
+ }
+ }
+ }
+
void parseIncludeDirective() {
if (CurrentToken && CurrentToken->is(tok::less)) {
next();
@@ -1015,7 +1124,7 @@ private:
// literals.
if (CurrentToken->isNot(tok::comment) &&
!CurrentToken->TokenText.startswith("//"))
- CurrentToken->Type = TT_ImplicitStringLiteral;
+ CurrentToken->setType(TT_ImplicitStringLiteral);
next();
}
}
@@ -1027,7 +1136,7 @@ private:
// warning or error.
next();
while (CurrentToken) {
- CurrentToken->Type = TT_ImplicitStringLiteral;
+ CurrentToken->setType(TT_ImplicitStringLiteral);
next();
}
}
@@ -1041,7 +1150,7 @@ private:
next(); // Consume first token (so we fix leading whitespace).
while (CurrentToken) {
if (IsMark || CurrentToken->Previous->is(TT_BinaryOperator))
- CurrentToken->Type = TT_ImplicitStringLiteral;
+ CurrentToken->setType(TT_ImplicitStringLiteral);
next();
}
}
@@ -1068,7 +1177,7 @@ private:
// Treat these like C++ #include directives.
while (CurrentToken) {
// Tokens cannot be comments here.
- CurrentToken->Type = TT_ImplicitStringLiteral;
+ CurrentToken->setType(TT_ImplicitStringLiteral);
next();
}
return LT_ImportStatement;
@@ -1228,8 +1337,8 @@ private:
TT_TypenameMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral,
TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, TT_NamespaceMacro,
TT_OverloadedOperator, TT_RegexLiteral, TT_TemplateString,
- TT_ObjCStringLiteral))
- CurrentToken->Type = TT_Unknown;
+ TT_ObjCStringLiteral, TT_UntouchableMacroFunc))
+ CurrentToken->setType(TT_Unknown);
CurrentToken->Role.reset();
CurrentToken->MatchingParen = nullptr;
CurrentToken->FakeLParens.clear();
@@ -1317,7 +1426,7 @@ private:
if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator) &&
Previous->isOneOf(tok::star, tok::amp, tok::ampamp) &&
Previous->Previous && Previous->Previous->isNot(tok::equal))
- Previous->Type = TT_PointerOrReference;
+ Previous->setType(TT_PointerOrReference);
}
}
} else if (Current.is(tok::lessless) &&
@@ -1339,7 +1448,7 @@ private:
for (FormatToken *Previous = Current.Previous;
Previous && Previous->isOneOf(tok::star, tok::amp);
Previous = Previous->Previous)
- Previous->Type = TT_PointerOrReference;
+ Previous->setType(TT_PointerOrReference);
if (Line.MustBeDeclaration && !Contexts.front().InCtorInitializer)
Contexts.back().IsExpression = false;
} else if (Current.is(tok::kw_new)) {
@@ -1423,19 +1532,36 @@ 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 &&
- (Current.Previous->isOneOf(tok::identifier, tok::kw_namespace,
- tok::r_paren, tok::r_square,
- tok::r_brace) ||
+ (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.Type = TT_JsNonNullAssertion;
+ Current.setType(TT_JsNonNullAssertion);
return;
}
if (Current.Next &&
Current.Next->isOneOf(TT_BinaryOperator, Keywords.kw_as)) {
- Current.Type = TT_JsNonNullAssertion;
+ Current.setType(TT_JsNonNullAssertion);
return;
}
}
@@ -1445,11 +1571,11 @@ private:
// function declaration have been found. In this case, 'Current' is a
// trailing token of this declaration and thus cannot be a name.
if (Current.is(Keywords.kw_instanceof)) {
- Current.Type = TT_BinaryOperator;
+ Current.setType(TT_BinaryOperator);
} else if (isStartOfName(Current) &&
(!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) {
Contexts.back().FirstStartOfName = &Current;
- Current.Type = TT_StartOfName;
+ Current.setType(TT_StartOfName);
} else if (Current.is(tok::semi)) {
// Reset FirstStartOfName after finding a semicolon so that a for loop
// with multiple increment statements is not confused with a for loop
@@ -1459,57 +1585,57 @@ private:
AutoFound = true;
} else if (Current.is(tok::arrow) &&
Style.Language == FormatStyle::LK_Java) {
- Current.Type = TT_LambdaArrow;
+ Current.setType(TT_LambdaArrow);
} else if (Current.is(tok::arrow) && AutoFound && Line.MustBeDeclaration &&
Current.NestingLevel == 0 &&
!Current.Previous->is(tok::kw_operator)) {
// not auto operator->() -> xxx;
- Current.Type = TT_TrailingReturnArrow;
+ Current.setType(TT_TrailingReturnArrow);
} else if (isDeductionGuide(Current)) {
// Deduction guides trailing arrow " A(...) -> A<T>;".
- Current.Type = TT_TrailingReturnArrow;
+ Current.setType(TT_TrailingReturnArrow);
} else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
- Current.Type = determineStarAmpUsage(Current,
- Contexts.back().CanBeExpression &&
- Contexts.back().IsExpression,
- Contexts.back().InTemplateArgument);
+ Current.setType(determineStarAmpUsage(
+ Current,
+ Contexts.back().CanBeExpression && Contexts.back().IsExpression,
+ Contexts.back().InTemplateArgument));
} else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
- Current.Type = determinePlusMinusCaretUsage(Current);
+ Current.setType(determinePlusMinusCaretUsage(Current));
if (Current.is(TT_UnaryOperator) && Current.is(tok::caret))
Contexts.back().CaretFound = true;
} else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
- Current.Type = determineIncrementUsage(Current);
+ Current.setType(determineIncrementUsage(Current));
} else if (Current.isOneOf(tok::exclaim, tok::tilde)) {
- Current.Type = TT_UnaryOperator;
+ Current.setType(TT_UnaryOperator);
} else if (Current.is(tok::question)) {
if (Style.Language == FormatStyle::LK_JavaScript &&
Line.MustBeDeclaration && !Contexts.back().IsExpression) {
// In JavaScript, `interface X { foo?(): bar; }` is an optional method
// on the interface, not a ternary expression.
- Current.Type = TT_JsTypeOptionalQuestion;
+ Current.setType(TT_JsTypeOptionalQuestion);
} else {
- Current.Type = TT_ConditionalExpr;
+ Current.setType(TT_ConditionalExpr);
}
} else if (Current.isBinaryOperator() &&
(!Current.Previous || Current.Previous->isNot(tok::l_square)) &&
(!Current.is(tok::greater) &&
Style.Language != FormatStyle::LK_TextProto)) {
- Current.Type = TT_BinaryOperator;
+ Current.setType(TT_BinaryOperator);
} else if (Current.is(tok::comment)) {
if (Current.TokenText.startswith("/*")) {
if (Current.TokenText.endswith("*/"))
- Current.Type = TT_BlockComment;
+ Current.setType(TT_BlockComment);
else
// The lexer has for some reason determined a comment here. But we
// cannot really handle it, if it isn't properly terminated.
Current.Tok.setKind(tok::unknown);
} else {
- Current.Type = TT_LineComment;
+ Current.setType(TT_LineComment);
}
} else if (Current.is(tok::r_paren)) {
if (rParenEndsCast(Current))
- Current.Type = TT_CastRParen;
+ Current.setType(TT_CastRParen);
if (Current.MatchingParen && Current.Next &&
!Current.Next->isBinaryOperator() &&
!Current.Next->isOneOf(tok::semi, tok::colon, tok::l_brace,
@@ -1524,7 +1650,7 @@ private:
BeforeParen->TokenText == BeforeParen->TokenText.upper() &&
(!BeforeParen->Previous ||
BeforeParen->Previous->ClosesTemplateDeclaration))
- Current.Type = TT_FunctionAnnotationRParen;
+ Current.setType(TT_FunctionAnnotationRParen);
}
}
} else if (Current.is(tok::at) && Current.Next &&
@@ -1536,10 +1662,10 @@ private:
case tok::objc_interface:
case tok::objc_implementation:
case tok::objc_protocol:
- Current.Type = TT_ObjCDecl;
+ Current.setType(TT_ObjCDecl);
break;
case tok::objc_property:
- Current.Type = TT_ObjCProperty;
+ Current.setType(TT_ObjCProperty);
break;
default:
break;
@@ -1548,11 +1674,11 @@ private:
FormatToken *PreviousNoComment = Current.getPreviousNonComment();
if (PreviousNoComment &&
PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
- Current.Type = TT_DesignatedInitializerPeriod;
+ Current.setType(TT_DesignatedInitializerPeriod);
else if (Style.Language == FormatStyle::LK_Java && Current.Previous &&
Current.Previous->isOneOf(TT_JavaAnnotation,
TT_LeadingJavaAnnotation)) {
- Current.Type = Current.Previous->Type;
+ Current.setType(Current.Previous->getType());
}
} else if (canBeObjCSelectorComponent(Current) &&
// FIXME(bug 36976): ObjC return types shouldn't use
@@ -1565,7 +1691,7 @@ private:
// This is the first part of an Objective-C selector name. (If there's no
// colon after this, this is the only place which annotates the identifier
// as a selector.)
- Current.Type = TT_SelectorName;
+ Current.setType(TT_SelectorName);
} else if (Current.isOneOf(tok::identifier, tok::kw_const,
tok::kw_noexcept) &&
Current.Previous &&
@@ -1573,7 +1699,7 @@ private:
Line.MightBeFunctionDecl && Contexts.size() == 1) {
// Line.MightBeFunctionDecl can only be true after the parentheses of a
// function declaration have been found.
- Current.Type = TT_TrailingAnnotation;
+ Current.setType(TT_TrailingAnnotation);
} else if ((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
Current.Previous) {
@@ -1582,13 +1708,13 @@ private:
const FormatToken &AtToken = *Current.Previous;
const FormatToken *Previous = AtToken.getPreviousNonComment();
if (!Previous || Previous->is(TT_LeadingJavaAnnotation))
- Current.Type = TT_LeadingJavaAnnotation;
+ Current.setType(TT_LeadingJavaAnnotation);
else
- Current.Type = TT_JavaAnnotation;
+ Current.setType(TT_JavaAnnotation);
} else if (Current.Previous->is(tok::period) &&
Current.Previous->isOneOf(TT_JavaAnnotation,
TT_LeadingJavaAnnotation)) {
- Current.Type = Current.Previous->Type;
+ Current.setType(Current.Previous->getType());
}
}
}
@@ -1640,8 +1766,9 @@ private:
/// Determine whether ')' is ending a cast.
bool rParenEndsCast(const FormatToken &Tok) {
- // C-style casts are only used in C++ and Java.
- if (!Style.isCpp() && Style.Language != FormatStyle::LK_Java)
+ // C-style casts are only used in C++, C# and Java.
+ if (!Style.isCSharp() && !Style.isCpp() &&
+ Style.Language != FormatStyle::LK_Java)
return false;
// Empty parens aren't casts and there are no casts at the end of the line.
@@ -1676,6 +1803,10 @@ private:
if (Tok.Next->is(tok::question))
return false;
+ // `foreach((A a, B b) in someList)` should not be seen as a cast.
+ if (Tok.Next->is(Keywords.kw_in) && Style.isCSharp())
+ return false;
+
// Functions which end with decorations like volatile, noexcept are unlikely
// to be casts.
if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,
@@ -1749,6 +1880,10 @@ private:
if (Style.Language == FormatStyle::LK_JavaScript)
return TT_BinaryOperator;
+ // && in C# must be a binary operator.
+ if (Style.isCSharp() && Tok.is(tok::ampamp))
+ return TT_BinaryOperator;
+
const FormatToken *PrevToken = Tok.getPreviousNonComment();
if (!PrevToken)
return TT_UnaryOperator;
@@ -1800,14 +1935,16 @@ private:
return TT_BinaryOperator;
// "&&(" is quite unlikely to be two successive unary "&".
- if (Tok.is(tok::ampamp) && NextToken && NextToken->is(tok::l_paren))
+ if (Tok.is(tok::ampamp) && NextToken->is(tok::l_paren))
return TT_BinaryOperator;
// This catches some cases where evaluation order is used as control flow:
// aaa && aaa->f();
- const FormatToken *NextNextToken = NextToken->getNextNonComment();
- if (NextNextToken && NextNextToken->is(tok::arrow))
- return TT_BinaryOperator;
+ if (NextToken->Tok.isAnyIdentifier()) {
+ const FormatToken *NextNextToken = NextToken->getNextNonComment();
+ if (NextNextToken && NextNextToken->is(tok::arrow))
+ return TT_BinaryOperator;
+ }
// It is very unlikely that we are going to find a pointer or reference type
// definition on the RHS of an assignment.
@@ -2176,6 +2313,10 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
Next = Next->Next;
continue;
}
+ if (Next->is(TT_TemplateOpener) && Next->MatchingParen) {
+ Next = Next->MatchingParen;
+ continue;
+ }
break;
}
@@ -2277,7 +2418,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
bool InFunctionDecl = Line.MightBeFunctionDecl;
while (Current) {
if (isFunctionDeclarationName(*Current, Line))
- Current->Type = TT_FunctionDeclarationName;
+ Current->setType(TT_FunctionDeclarationName);
if (Current->is(TT_LineComment)) {
if (Current->Previous->BlockKind == BK_BracedInit &&
Current->Previous->opensScope())
@@ -2596,7 +2737,7 @@ bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const {
/// otherwise.
static bool isKeywordWithCondition(const FormatToken &Tok) {
return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
- tok::kw_constexpr);
+ tok::kw_constexpr, tok::kw_catch);
}
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
@@ -2703,15 +2844,48 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Left.Previous &&
!Left.Previous->isOneOf(tok::l_paren, tok::coloncolon,
tok::l_square));
+ // Ensure right pointer alignement with ellipsis e.g. int *...P
+ if (Left.is(tok::ellipsis) && Left.Previous &&
+ Left.Previous->isOneOf(tok::star, tok::amp, tok::ampamp))
+ return Style.PointerAlignment != FormatStyle::PAS_Right;
+
if (Right.is(tok::star) && Left.is(tok::l_paren))
return false;
- if (Right.isOneOf(tok::star, tok::amp, tok::ampamp) &&
- (Left.is(tok::identifier) || Left.isSimpleTypeSpecifier()) &&
- Left.Previous && Left.Previous->is(tok::kw_operator))
- // Space between the type and the *
- // operator void*(), operator char*(), operator Foo*() dependant
- // on PointerAlignment style.
- return (Style.PointerAlignment != FormatStyle::PAS_Left);
+ if (Left.is(tok::star) && Right.isOneOf(tok::star, tok::amp, tok::ampamp))
+ return false;
+ if (Right.isOneOf(tok::star, tok::amp, tok::ampamp)) {
+ const FormatToken *Previous = &Left;
+ while (Previous && !Previous->is(tok::kw_operator)) {
+ if (Previous->is(tok::identifier) || Previous->isSimpleTypeSpecifier()) {
+ Previous = Previous->getPreviousNonComment();
+ continue;
+ }
+ if (Previous->is(TT_TemplateCloser) && Previous->MatchingParen) {
+ Previous = Previous->MatchingParen->getPreviousNonComment();
+ continue;
+ }
+ if (Previous->is(tok::coloncolon)) {
+ Previous = Previous->getPreviousNonComment();
+ continue;
+ }
+ break;
+ }
+ // Space between the type and the * in:
+ // operator void*()
+ // operator char*()
+ // operator /*comment*/ const char*()
+ // operator volatile /*comment*/ char*()
+ // operator Foo*()
+ // operator C<T>*()
+ // 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);
+ }
const auto SpaceRequiredForArrayInitializerLSquare =
[](const FormatToken &LSquareTok, const FormatStyle &Style) {
return Style.SpacesInContainerLiterals ||
@@ -2755,10 +2929,19 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
// No whitespace in x(/*foo=*/1), except for JavaScript.
return Style.Language == FormatStyle::LK_JavaScript ||
!Left.TokenText.endswith("=*/");
+
+ // Space between template and attribute.
+ // e.g. template <typename T> [[nodiscard]] ...
+ if (Left.is(TT_TemplateCloser) && Right.is(TT_AttributeSquare))
+ return true;
if (Right.is(tok::l_paren)) {
if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) ||
(Left.is(tok::r_square) && Left.is(TT_AttributeSquare)))
return true;
+ if (Style.SpaceBeforeParens ==
+ FormatStyle::SBPO_ControlStatementsExceptForEachMacros &&
+ Left.is(TT_ForEachMacro))
+ 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,
@@ -2807,7 +2990,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Right.MatchingParen->endsSequence(TT_DictLiteral, tok::at))
// Objective-C dictionary literal -> no space before closing brace.
return false;
- if (Right.Type == TT_TrailingAnnotation &&
+ if (Right.getType() == TT_TrailingAnnotation &&
Right.isOneOf(tok::amp, tok::ampamp) &&
Left.isOneOf(tok::kw_const, tok::kw_volatile) &&
(!Right.Next || Right.Next->is(tok::semi)))
@@ -2855,13 +3038,83 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Left.is(tok::numeric_constant) && Right.is(tok::percent))
return Right.WhitespaceRange.getEnd() != Right.WhitespaceRange.getBegin();
} else if (Style.isCSharp()) {
+ // Require spaces around '{' and before '}' unless they appear in
+ // interpolated strings. Interpolated strings are merged into a single token
+ // so cannot have spaces inserted by this function.
+
+ // No space between 'this' and '['
+ if (Left.is(tok::kw_this) && Right.is(tok::l_square))
+ return false;
+
+ // No space between 'new' and '('
+ if (Left.is(tok::kw_new) && Right.is(tok::l_paren))
+ return false;
+
+ // Space before { (including space within '{ {').
+ if (Right.is(tok::l_brace))
+ return true;
+
+ // Spaces inside braces.
+ if (Left.is(tok::l_brace) && Right.isNot(tok::r_brace))
+ return true;
+
+ if (Left.isNot(tok::l_brace) && Right.is(tok::r_brace))
+ return true;
+
+ // Spaces around '=>'.
+ if (Left.is(TT_JsFatArrow) || Right.is(TT_JsFatArrow))
+ return true;
+
+ // No spaces around attribute target colons
+ if (Left.is(TT_AttributeColon) || Right.is(TT_AttributeColon))
+ return false;
+
// space between type and variable e.g. Dictionary<string,string> foo;
if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName))
return true;
+
+ // spaces inside square brackets.
+ if (Left.is(tok::l_square) || Right.is(tok::r_square))
+ return Style.SpacesInSquareBrackets;
+
+ // No space before ? in nullable types.
+ 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))
+ 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;
+
// space between keywords and paren e.g. "using ("
if (Right.is(tok::l_paren))
- if (Left.is(tok::kw_using))
- return spaceRequiredBeforeParens(Left);
+ if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when,
+ Keywords.kw_lock))
+ return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements ||
+ spaceRequiredBeforeParens(Right);
} else if (Style.Language == FormatStyle::LK_JavaScript) {
if (Left.is(TT_JsFatArrow))
return true;
@@ -2881,9 +3134,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
(Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
return false;
// In tagged template literals ("html`bar baz`"), there is no space between
- // the tag identifier and the template string. getIdentifierInfo makes sure
- // that the identifier is not a pseudo keyword like `yield`, either.
- if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) &&
+ // the tag identifier and the template string.
+ if (Keywords.IsJavaScriptIdentifier(Left,
+ /* AcceptIdentifierName= */ false) &&
Right.is(TT_TemplateString))
return false;
if (Right.is(tok::star) &&
@@ -3012,6 +3265,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return Style.SpacesInContainerLiterals;
if (Right.is(TT_AttributeColon))
return false;
+ if (Right.is(TT_CSharpNamedArgumentColon))
+ return false;
return true;
}
if (Left.is(TT_UnaryOperator)) {
@@ -3062,12 +3317,13 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
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.Standard < FormatStyle::LS_Cpp11 || Style.SpacesInAngles)) ||
!(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
- tok::kw___super, TT_TemplateCloser,
- TT_TemplateOpener)) ||
- (Left.is(tok ::l_paren) && Style.SpacesInParentheses);
+ 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;
// Space before TT_StructuredBindingLSquare.
@@ -3104,13 +3360,67 @@ static bool isAllmanBrace(const FormatToken &Tok) {
!Tok.isOneOf(TT_ObjCBlockLBrace, TT_LambdaLBrace, TT_DictLiteral);
}
+// Returns 'true' if 'Tok' is an function argument.
+static bool IsFunctionArgument(const FormatToken &Tok) {
+ return Tok.MatchingParen && Tok.MatchingParen->Next &&
+ Tok.MatchingParen->Next->isOneOf(tok::comma, tok::r_paren);
+}
+
+static bool
+isItAnEmptyLambdaAllowed(const FormatToken &Tok,
+ FormatStyle::ShortLambdaStyle ShortLambdaOption) {
+ 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.BlockKind == 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;
if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0)
return true;
- if (Style.Language == FormatStyle::LK_JavaScript) {
+ if (Style.isCSharp()) {
+ if (Right.is(TT_CSharpNamedArgumentColon) ||
+ Left.is(TT_CSharpNamedArgumentColon))
+ return false;
+ if (Right.is(TT_CSharpGenericTypeConstraint))
+ 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 &&
Left.Previous->is(tok::string_literal))
@@ -3133,6 +3443,25 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
// JavaScript top-level enum key/value pairs are put on separate lines
// instead of bin-packing.
return true;
+ if (Right.is(tok::r_brace) && Left.is(tok::l_brace) && Left.Previous &&
+ Left.Previous->is(TT_JsFatArrow)) {
+ // JS arrow function (=> {...}).
+ switch (Style.AllowShortLambdasOnASingleLine) {
+ case FormatStyle::SLS_All:
+ return false;
+ case FormatStyle::SLS_None:
+ return true;
+ case FormatStyle::SLS_Empty:
+ return !Left.Children.empty();
+ case FormatStyle::SLS_Inline:
+ // allow one-lining inline (e.g. in function call args) and empty arrow
+ // functions.
+ return (Left.NestingLevel == 0 && Line.Level == 0) &&
+ !Left.Children.empty();
+ }
+ llvm_unreachable("Unknown FormatStyle::ShortLambdaStyle enum");
+ }
+
if (Right.is(tok::r_brace) && Left.is(tok::l_brace) &&
!Left.Children.empty())
// Support AllowShortFunctionsOnASingleLine for JavaScript.
@@ -3220,6 +3549,14 @@ 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) &&
@@ -3231,8 +3568,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return true;
if (Left.is(TT_LambdaLBrace)) {
- if (Left.MatchingParen && Left.MatchingParen->Next &&
- Left.MatchingParen->Next->isOneOf(tok::comma, tok::r_paren) &&
+ if (IsFunctionArgument(Left) &&
Style.AllowShortLambdasOnASingleLine == FormatStyle::SLS_Inline)
return false;
@@ -3243,13 +3579,6 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return true;
}
- // Put multiple C# attributes on a new line.
- if (Style.isCSharp() &&
- ((Left.is(TT_AttributeSquare) && Left.is(tok::r_square)) ||
- (Left.is(tok::r_square) && Right.is(TT_AttributeSquare) &&
- Right.is(tok::l_square))))
- return true;
-
// Put multiple Java annotation on a new line.
if ((Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) &&
@@ -3376,9 +3705,15 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
const FormatToken &Right) {
const FormatToken &Left = *Right.Previous;
-
// Language-specific stuff.
- if (Style.Language == FormatStyle::LK_Java) {
+ if (Style.isCSharp()) {
+ if (Left.isOneOf(TT_CSharpNamedArgumentColon, TT_AttributeColon) ||
+ Right.isOneOf(TT_CSharpNamedArgumentColon, TT_AttributeColon))
+ return false;
+ // Only break after commas for generic type constraints.
+ if (Line.First->is(TT_CSharpGenericTypeConstraint))
+ return Left.is(TT_CSharpGenericTypeConstraintComma);
+ } else if (Style.Language == FormatStyle::LK_Java) {
if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends,
Keywords.kw_implements))
return false;
@@ -3592,7 +3927,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Right.is(tok::kw___attribute) ||
(Right.is(tok::l_square) && Right.is(TT_AttributeSquare)))
- return true;
+ return !Left.is(TT_AttributeSquare);
if (Left.is(tok::identifier) && Right.is(tok::string_literal))
return true;
@@ -3637,11 +3972,21 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if ((Left.is(TT_AttributeSquare) && Right.is(tok::l_square)) ||
(Left.is(tok::r_square) && Right.is(TT_AttributeSquare)))
return false;
+
+ auto ShortLambdaOption = Style.AllowShortLambdasOnASingleLine;
+ if (Style.BraceWrapping.BeforeLambdaBody) {
+ if (isAllmanLambdaBrace(Left))
+ return !isItAnEmptyLambdaAllowed(Left, ShortLambdaOption);
+ if (isAllmanLambdaBrace(Right))
+ return !isItAnEmptyLambdaAllowed(Right, ShortLambdaOption);
+ }
+
return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
tok::kw_class, tok::kw_struct, tok::comment) ||
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)) ||
@@ -3654,9 +3999,9 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) {
while (Tok) {
llvm::errs() << " M=" << Tok->MustBreakBefore
<< " C=" << Tok->CanBreakBefore
- << " T=" << getTokenTypeName(Tok->Type)
+ << " T=" << getTokenTypeName(Tok->getType())
<< " S=" << Tok->SpacesRequiredBefore
- << " B=" << Tok->BlockParameterCount
+ << " F=" << Tok->Finalized << " B=" << Tok->BlockParameterCount
<< " BK=" << Tok->BlockKind << " P=" << Tok->SplitPenalty
<< " Name=" << Tok->Tok.getName() << " L=" << Tok->TotalLength
<< " PPK=" << Tok->PackingKind << " FakeLParens=";