Commit bb0b5a8c authored by Milian Wolff's avatar Milian Wolff
Browse files

Add support for operator<=> to the ParamIterator

This means we won't parse C++17 operator<= when it comes directly
before the closing '>' of another template parameter list. But
that's probably fine as clang would warn about such identifiers
anyways, now that C++20 has the spaceship operator.
parent 2df95e20
......@@ -85,14 +85,23 @@ bool endsWithWordBoundary(QStringView str)
bool isOperator(const QString& str, int pos)
{
const auto op = QLatin1String("operator");
if (pos < op.size()) {
return false;
}
const auto c = str[pos];
Q_ASSERT(c == QLatin1Char('<') || c == QLatin1Char('>'));
--pos;
// handle `operator<<` and `operator>>`
if (pos > 0 && str[pos] == c) {
// note: due to the `pos < op.size()` check above, the below conditionals don't need to check boundaries
if (str[pos] == c) {
// handle `operator<<` and `operator>>`
--pos;
} else if (c == QLatin1Char('>') && str[pos] == QLatin1Char('=') && str[pos - 1] == QLatin1Char('<')) {
// handle `operator<=>`
pos -= 2;
}
// skip spaces, e.g. `operator <`
......@@ -101,7 +110,6 @@ bool isOperator(const QString& str, int pos)
}
auto prefix = QStringView(str).left(pos + 1);
const auto op = QLatin1String("operator");
if (!prefix.endsWith(op)) {
return false;
}
......
......@@ -158,12 +158,18 @@ void TestStringHelpers::testParamIterator_data()
addTest("A<\">\\\">\">", {"\">\\\">\""});
addTest("A<'>'>", {"'>'"});
addTest("myoperator<anoperator<anotheroperator>, my_operator>", {"anoperator<anotheroperator>", "my_operator"});
// c++17 operator<=
addTest("Y<decltype(&X::operator<=), &X::operator<=>", {"decltype(&X::operator<=)", "&X::operator<="});
// c++20 operator<=>
addTest("Y<decltype(&X::operator<=>), &X::operator<=>>", {"decltype(&X::operator<=>)", "&X::operator<=>"});
addTest("Y<decltype(&X::operator->), &X::operator->>", {"decltype(&X::operator->)", "&X::operator->"});
addTest("Y<decltype(&X::operator->), Z<&X::operator->>>", {"decltype(&X::operator->)", "Z<&X::operator->>"});
addTest("Y<decltype(&X::operator--), &X::operator-->", {"decltype(&X::operator--)", "&X::operator--"});
addTest("Y<decltype(&X::operator--), Z<&X::operator-->>", {"decltype(&X::operator--)", "Z<&X::operator-->"});
// c++17 operator<=
addTest("Y<decltype(&X::operator<=), Z<&X::operator<=>>", {"decltype(&X::operator<=)", "Z<&X::operator<=>"});
// c++20 operator<=>
addTest("Y<decltype(&X::operator<=>), Z<&X::operator<=>>>", {"decltype(&X::operator<=>)", "Z<&X::operator<=>>"});
// NOTE: this identifier here is invalid but we shouldn't trigger UB either, so the test is just that we get _something_ (even if it's wrong)
addTest("bogus<_Tp, _Up, invalid<decltype(<=(std::declval<_Tp>(), std::declval<_Up>()))>>", {"_Tp", "_Up", "invalid<decltype(<=(std::declval<_Tp>(), std::declval<_Up>()))>>"});
addTest("hardToParse<A<B>", {"A<B"});
......@@ -180,10 +186,18 @@ void TestStringHelpers::testParamIterator()
auto it = KDevelop::ParamIterator(parens, source);
QEXPECT_FAIL("hardToParse<A<B>", "quasi impossible to parse without semantic knowledge of the types", Abort);
int i = 0;
while (!params.isEmpty()) {
QVERIFY(it);
if (i == 1) {
QEXPECT_FAIL("Y<decltype(&X::operator<=), &X::operator<=>", "clang triggers warning for this C++17 code, due to C++20 spaceship op", Continue);
QEXPECT_FAIL("Y<decltype(&X::operator<=), Z<&X::operator<=>>",
"clang triggers warning for this C++17 code, due to C++20 spaceship op", Continue);
}
QCOMPARE(*it, params.takeFirst());
++it;
++i;
}
QVERIFY(!it);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment