summaryrefslogtreecommitdiff
path: root/lib/Format/TokenAnnotator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Format/TokenAnnotator.cpp')
-rw-r--r--lib/Format/TokenAnnotator.cpp70
1 files changed, 63 insertions, 7 deletions
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 3a19215e18037..24c2f998c388a 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -366,7 +366,8 @@ private:
// specifier parameter, although this is technically valid:
// [[foo(:)]]
if (AttrTok->is(tok::colon) ||
- AttrTok->startsSequence(tok::identifier, tok::identifier))
+ AttrTok->startsSequence(tok::identifier, tok::identifier) ||
+ AttrTok->startsSequence(tok::r_paren, tok::identifier))
return false;
if (AttrTok->is(tok::ellipsis))
return true;
@@ -398,9 +399,11 @@ private:
bool IsCpp11AttributeSpecifier = isCpp11AttributeSpecifier(*Left) ||
Contexts.back().InCpp11AttributeSpecifier;
+ bool InsideInlineASM = Line.startsWith(tok::kw_asm);
bool StartsObjCMethodExpr =
- !CppArrayTemplates && Style.isCpp() && !IsCpp11AttributeSpecifier &&
- Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
+ !InsideInlineASM && !CppArrayTemplates && Style.isCpp() &&
+ !IsCpp11AttributeSpecifier && 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,
@@ -1120,6 +1123,7 @@ private:
(Tok.Next->Next->TokenText == "module" ||
Tok.Next->Next->TokenText == "provide" ||
Tok.Next->Next->TokenText == "require" ||
+ Tok.Next->Next->TokenText == "requireType" ||
Tok.Next->Next->TokenText == "forwardDeclare") &&
Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren);
}
@@ -2517,7 +2521,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Right.MatchingParen->BlockKind != BK_Block))
return !Style.Cpp11BracedListStyle;
if (Left.is(TT_BlockComment))
- return !Left.TokenText.endswith("=*/");
+ // No whitespace in x(/*foo=*/1), except for JavaScript.
+ return Style.Language == FormatStyle::LK_JavaScript ||
+ !Left.TokenText.endswith("=*/");
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)))
@@ -2553,8 +2559,11 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return false;
if (Left.is(TT_TemplateCloser) && Left.MatchingParen &&
Left.MatchingParen->Previous &&
- Left.MatchingParen->Previous->is(tok::period))
+ (Left.MatchingParen->Previous->is(tok::period) ||
+ Left.MatchingParen->Previous->is(tok::coloncolon)))
+ // Java call to generic function with explicit type:
// A.<B<C<...>>>DoSomething();
+ // A::<B<C<...>>>DoSomething(); // With a Java 8 method reference.
return false;
if (Left.is(TT_TemplateCloser) && Right.is(tok::l_square))
return false;
@@ -2774,6 +2783,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (!Style.SpaceBeforeAssignmentOperators &&
Right.getPrecedence() == prec::Assignment)
return false;
+ if (Style.Language == FormatStyle::LK_Java && Right.is(tok::coloncolon) &&
+ (Left.is(tok::identifier) || Left.is(tok::kw_this)))
+ return false;
if (Right.is(tok::coloncolon) && Left.is(tok::identifier))
// Generally don't remove existing spaces between an identifier and "::".
// The identifier might actually be a macro name such as ALWAYS_INLINE. If
@@ -2866,6 +2878,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
} else if (Style.Language == FormatStyle::LK_Cpp ||
Style.Language == FormatStyle::LK_ObjC ||
Style.Language == FormatStyle::LK_Proto ||
+ Style.Language == FormatStyle::LK_TableGen ||
Style.Language == FormatStyle::LK_TextProto) {
if (Left.isStringLiteral() && Right.isStringLiteral())
return true;
@@ -3041,6 +3054,30 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return true;
}
+ // Deal with lambda arguments in C++ - we want consistent line breaks whether
+ // they happen to be at arg0, arg1 or argN. The selection is a bit nuanced
+ // as aggressive line breaks are placed when the lambda is not the last arg.
+ if ((Style.Language == FormatStyle::LK_Cpp ||
+ Style.Language == FormatStyle::LK_ObjC) &&
+ Left.is(tok::l_paren) && Left.BlockParameterCount > 0 &&
+ !Right.isOneOf(tok::l_paren, TT_LambdaLSquare)) {
+ // Multiple lambdas in the same function call force line breaks.
+ if (Left.BlockParameterCount > 1)
+ return true;
+
+ // A lambda followed by another arg forces a line break.
+ if (!Left.Role)
+ return false;
+ auto Comma = Left.Role->lastComma();
+ if (!Comma)
+ return false;
+ auto Next = Comma->getNextNonComment();
+ if (!Next)
+ return false;
+ if (!Next->isOneOf(TT_LambdaLSquare, tok::l_brace, tok::caret))
+ return true;
+ }
+
return false;
}
@@ -3078,14 +3115,33 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
// Don't wrap between ":" and "!" of a strict prop init ("field!: type;").
if (Left.is(tok::exclaim) && Right.is(tok::colon))
return false;
- if (Right.is(Keywords.kw_is))
- return false;
+ // Look for is type annotations like:
+ // function f(): a is B { ... }
+ // Do not break before is in these cases.
+ if (Right.is(Keywords.kw_is)) {
+ const FormatToken* Next = Right.getNextNonComment();
+ // If `is` is followed by a colon, it's likely that it's a dict key, so
+ // ignore it for this check.
+ // For example this is common in Polymer:
+ // Polymer({
+ // is: 'name',
+ // ...
+ // });
+ if (!Next || !Next->is(tok::colon))
+ return false;
+ }
if (Left.is(Keywords.kw_in))
return Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None;
if (Right.is(Keywords.kw_in))
return Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None;
if (Right.is(Keywords.kw_as))
return false; // must not break before as in 'x as type' casts
+ if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_infer)) {
+ // extends and infer can appear as keywords in conditional types:
+ // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types
+ // do not break before them, as the expressions are subject to ASI.
+ return false;
+ }
if (Left.is(Keywords.kw_as))
return true;
if (Left.is(TT_JsNonNullAssertion))