return;
if (tryMergeLessLess())
return;
- if (tryMergeGreaterGreater())
- return;
if (tryMergeForEach())
return;
if (Style.isCpp() && tryTransformTryUsageForC())
return false;
auto X = Tokens.size() > 3 ? First[-1] : nullptr;
- if (X && X->is(tok::less))
+ auto Y = First[2];
+ if ((X && X->is(tok::less)) || Y->is(tok::less))
return false;
- auto Y = First[2];
- if ((!X || X->isNot(tok::kw_operator)) && Y->is(tok::less))
+ // Do not remove a whitespace between the two "<" e.g. "operator< <>".
+ if (X && X->is(tok::kw_operator) && Y->is(tok::greater))
return false;
First[0]->Tok.setKind(tok::lessless);
return true;
}
-bool FormatTokenLexer::tryMergeGreaterGreater() {
- // Merge kw_operator,greater,greater into kw_operator,greatergreater.
- if (Tokens.size() < 2)
- return false;
-
- auto First = Tokens.end() - 2;
- if (First[0]->isNot(tok::greater) || First[1]->isNot(tok::greater))
- return false;
-
- // Only merge if there currently is no whitespace between the first two ">".
- if (First[1]->hasWhitespaceBefore())
- return false;
-
- auto Tok = Tokens.size() > 2 ? First[-1] : nullptr;
- if (Tok && Tok->isNot(tok::kw_operator))
- return false;
-
- First[0]->Tok.setKind(tok::greatergreater);
- First[0]->TokenText = ">>";
- First[0]->ColumnWidth += 1;
- Tokens.erase(Tokens.end() - 1);
- return true;
-}
-
bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds,
TokenType NewType) {
if (Tokens.size() < Kinds.size())
void tryMergePreviousTokens();
bool tryMergeLessLess();
- bool tryMergeGreaterGreater();
bool tryMergeNSStringLiteral();
bool tryMergeJSPrivateIdentifier();
bool tryMergeCSharpStringLiteral();
!CurrentToken->isOneOf(tok::l_paren, tok::semi, tok::r_paren)) {
if (CurrentToken->isOneOf(tok::star, tok::amp))
CurrentToken->setType(TT_PointerOrReference);
- auto Next = CurrentToken->getNextNonComment();
- if (!Next)
- break;
- if (Next->is(tok::less))
- next();
- else
- consumeToken();
- assert(CurrentToken);
- auto Previous = CurrentToken->getPreviousNonComment();
- assert(Previous);
- if (CurrentToken->is(tok::comma) && Previous->isNot(tok::kw_operator))
+ consumeToken();
+ if (!CurrentToken)
+ continue;
+ if (CurrentToken->is(tok::comma) &&
+ CurrentToken->Previous->isNot(tok::kw_operator)) {
break;
- if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator, tok::comma,
- tok::star, tok::arrow, tok::amp, tok::ampamp) ||
+ }
+ if (CurrentToken->Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator,
+ tok::comma, tok::star, tok::arrow,
+ tok::amp, tok::ampamp) ||
// User defined literal.
- Previous->TokenText.startswith("\"\"")) {
- Previous->setType(TT_OverloadedOperator);
- if (CurrentToken->isOneOf(tok::less, tok::greater))
- break;
+ CurrentToken->Previous->TokenText.startswith("\"\"")) {
+ CurrentToken->Previous->setType(TT_OverloadedOperator);
}
}
if (CurrentToken && CurrentToken->is(tok::l_paren))
return true;
if (Style.isCpp()) {
- if (Left.is(TT_OverloadedOperator) &&
- Right.isOneOf(TT_TemplateOpener, TT_TemplateCloser)) {
- return true;
- }
// Space between UDL and dot: auto b = 4s .count();
if (Right.is(tok::period) && Left.is(tok::numeric_constant))
return true;
verifyFormat("foo() { ::operator new(n * sizeof(foo)); }");
}
-TEST_F(FormatTest, SpaceBeforeTemplateCloser) {
- verifyFormat("C<&operator- > minus;");
- verifyFormat("C<&operator> > gt;");
- verifyFormat("C<&operator>= > ge;");
- verifyFormat("C<&operator<= > le;");
- verifyFormat("C<&operator< <X>> lt;");
-}
-
TEST_F(FormatTest, UnderstandsFunctionRefQualification) {
verifyFormat("void A::b() && {}");
verifyFormat("void A::b() && noexcept {}");
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_OverloadedOperatorLParen);
}
-TEST_F(TokenAnnotatorTest, OverloadedOperatorInTemplate) {
- struct {
- const char *Text;
- tok::TokenKind Kind;
- } Operators[] = {{"+", tok::plus},
- {"-", tok::minus},
- // FIXME:
- // {"*", tok::star},
- {"/", tok::slash},
- {"%", tok::percent},
- {"^", tok::caret},
- // FIXME:
- // {"&", tok::amp},
- {"|", tok::pipe},
- {"~", tok::tilde},
- {"!", tok::exclaim},
- {"=", tok::equal},
- // FIXME:
- // {"<", tok::less},
- {">", tok::greater},
- {"+=", tok::plusequal},
- {"-=", tok::minusequal},
- {"*=", tok::starequal},
- {"/=", tok::slashequal},
- {"%=", tok::percentequal},
- {"^=", tok::caretequal},
- {"&=", tok::ampequal},
- {"|=", tok::pipeequal},
- {"<<", tok::lessless},
- {">>", tok::greatergreater},
- {">>=", tok::greatergreaterequal},
- {"<<=", tok::lesslessequal},
- {"==", tok::equalequal},
- {"!=", tok::exclaimequal},
- {"<=", tok::lessequal},
- {">=", tok::greaterequal},
- {"<=>", tok::spaceship},
- {"&&", tok::ampamp},
- {"||", tok::pipepipe},
- {"++", tok::plusplus},
- {"--", tok::minusminus},
- {",", tok::comma},
- {"->*", tok::arrowstar},
- {"->", tok::arrow}};
-
- for (const auto &Operator : Operators) {
- std::string Input("C<&operator");
- Input += Operator.Text;
- Input += " > a;";
- auto Tokens = annotate(std::string(Input));
- ASSERT_EQ(Tokens.size(), 9u) << Tokens;
- EXPECT_TOKEN(Tokens[1], tok::less, TT_TemplateOpener);
- EXPECT_TOKEN(Tokens[4], Operator.Kind, TT_OverloadedOperator);
- EXPECT_TOKEN(Tokens[5], tok::greater, TT_TemplateCloser);
- }
-
- auto Tokens = annotate("C<&operator< <X>> lt;");
- ASSERT_EQ(Tokens.size(), 12u) << Tokens;
- EXPECT_TOKEN(Tokens[1], tok::less, TT_TemplateOpener);
- EXPECT_TOKEN(Tokens[4], tok::less, TT_OverloadedOperator);
- EXPECT_TOKEN(Tokens[5], tok::less, TT_TemplateOpener);
- EXPECT_TOKEN(Tokens[7], tok::greater, TT_TemplateCloser);
- EXPECT_TOKEN(Tokens[8], tok::greater, TT_TemplateCloser);
-}
-
TEST_F(TokenAnnotatorTest, UnderstandsRequiresClausesAndConcepts) {
auto Tokens = annotate("template <typename T>\n"
"concept C = (Foo && Bar) && (Bar && Baz);");