[clang-format] Fix bug in parsing `operator<` with template

Fixes https://github.com/llvm/llvm-project/issues/44601.

This patch handles a bug when parsing a below example code :

```
template <class> class S;

template <class T> bool operator<(S<T> const &x, S<T> const &y) {
  return x.i < y.i;
}

template <class T> class S {
  int i = 42;
  friend bool operator< <>(S const &, S const &);
};

int main() { return S<int>{} < S<int>{}; }
```
which parse `< <>` as `<< >`, not `< <>` in terms of tokens as discussed in discord.

1. Add a condition in `tryMergeLessLess()` considering `operator` keyword and `>`
2. Force to leave a whitespace between `tok::less` and a template opener
3. Add unit test

Reviewed By: MyDeveloperDay, curdeius

Differential Revision: https://reviews.llvm.org/D117398
This commit is contained in:
Jino Park 2022-01-20 08:42:19 +01:00 committed by Marek Kurdej
parent 8eae99dfe5
commit 560eb2277b
3 changed files with 18 additions and 4 deletions

View File

@ -429,11 +429,18 @@ bool FormatTokenLexer::tryMergeLessLess() {
if (Tokens.size() < 3)
return false;
bool FourthTokenIsLess = false;
if (Tokens.size() > 3)
FourthTokenIsLess = (Tokens.end() - 4)[0]->is(tok::less);
auto First = Tokens.end() - 3;
bool FourthTokenIsLess = false;
if (Tokens.size() > 3) {
auto Fourth = (Tokens.end() - 4)[0];
FourthTokenIsLess = Fourth->is(tok::less);
// Do not remove a whitespace between the two "<" e.g. "operator< <>".
if (First[2]->is(tok::greater) && Fourth->is(tok::kw_operator))
return false;
}
if (First[2]->is(tok::less) || First[1]->isNot(tok::less) ||
First[0]->isNot(tok::less) || FourthTokenIsLess)
return false;

View File

@ -3346,6 +3346,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) &&
!Left.opensScope() && Style.SpaceBeforeCpp11BracedList)
return true;
if (Left.is(tok::less) && Left.is(TT_OverloadedOperator) &&
Right.is(TT_TemplateOpener))
return true;
} else if (Style.Language == FormatStyle::LK_Proto ||
Style.Language == FormatStyle::LK_TextProto) {
if (Right.is(tok::period) &&

View File

@ -9463,6 +9463,10 @@ TEST_F(FormatTest, UnderstandsOverloadedOperators) {
verifyFormat("operator SomeType<int>();");
verifyFormat("operator SomeType<int, int>();");
verifyFormat("operator SomeType<SomeType<int>>();");
verifyFormat("operator< <>();");
verifyFormat("operator<< <>();");
verifyFormat("< <>");
verifyFormat("void *operator new(std::size_t size);");
verifyFormat("void *operator new[](std::size_t size);");
verifyFormat("void operator delete(void *ptr);");