aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2022-02-14 10:45:54 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2022-06-21 21:14:58 +0200
commitd189efa29969ce9731a2954c398c8c7eeb5f5dc2 (patch)
treee556c1051bacfa41240d0414ee9114a685eca425
parent85fc651460f0e408548c13d7056e7e30a148a946 (diff)
shiboken6: Implement the spaceship comparison operator of C++ 20
Synthesize all comparison operators if one is found in the code model. Task-number: QTBUG-103757 Change-Id: I78fbcd93bc4cd172266f9dd0dbb2ebcf3a8bb7f2 Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp8
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang.cpp40
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang.h2
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel.cpp9
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel.h1
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp31
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testreverseoperators.h1
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testutil.h7
-rw-r--r--sources/shiboken6/tests/libsample/oddbool.cpp4
-rw-r--r--sources/shiboken6/tests/libsample/oddbool.h21
-rw-r--r--sources/shiboken6/tests/samplebinding/CMakeLists.txt1
-rw-r--r--sources/shiboken6/tests/samplebinding/oddbool_test.py15
-rw-r--r--sources/shiboken6/tests/samplebinding/typesystem_sample.xml3
13 files changed, 137 insertions, 6 deletions
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
index 824f6fc9e..1391a7b0a 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
@@ -282,6 +282,11 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte
if (baseoperandClass == nullptr)
return;
+ if (item->isSpaceshipOperator() && !item->isDeleted()) {
+ baseoperandClass->addSynthesizedComparisonOperators();
+ return;
+ }
+
AbstractMetaFunction *metaFunction = traverseFunction(item, baseoperandClass);
if (metaFunction == nullptr)
return;
@@ -1304,6 +1309,9 @@ AbstractMetaFunctionRawPtrList
for (const FunctionModelItem &function : scopeFunctionList) {
if (isNamespace && function->isOperator()) {
traverseOperatorFunction(function, currentClass);
+ } else if (function->isSpaceshipOperator() && !function->isDeleted()) {
+ if (currentClass)
+ currentClass->addSynthesizedComparisonOperators();
} else if (auto *metaFunction = traverseFunction(function, currentClass)) {
result.append(metaFunction);
} else if (function->functionType() == CodeModel::Constructor) {
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang.cpp b/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
index 21b1ba1f2..33ed659c0 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
@@ -17,10 +17,14 @@
#include "namespacetypeentry.h"
#include "usingmember.h"
+#include "qtcompat.h"
+
#include <QtCore/QDebug>
#include <algorithm>
+using namespace Qt::StringLiterals;
+
bool function_sorter(const AbstractMetaFunctionCPtr &a, const AbstractMetaFunctionCPtr &b)
{
return a->signature() < b->signature();
@@ -819,6 +823,42 @@ AbstractMetaFunction *
return f;
}
+static AbstractMetaType boolType()
+{
+ auto *boolType = TypeDatabase::instance()->findType(u"bool"_s);
+ Q_ASSERT(boolType);
+ AbstractMetaType result(boolType);
+ result.decideUsagePattern();
+ return result;
+}
+
+// Helper to synthesize comparison operators from a spaceship operator. Since
+// shiboken also generates code for comparing to different types, this fits
+// better than of handling it in the generator code.
+void AbstractMetaClass::addSynthesizedComparisonOperators()
+{
+ static const auto returnType = boolType();
+
+ AbstractMetaType selfType(typeEntry());
+ selfType.setConstant(true);
+ selfType.setReferenceType(LValueReference);
+ selfType.decideUsagePattern();
+ AbstractMetaArgument selfArgument;
+ selfArgument.setType(selfType);
+ selfArgument.setName(u"rhs"_qs);
+ AbstractMetaArgumentList arguments(1, selfArgument);
+
+ static const char *operators[]
+ = {"operator==", "operator!=", "operator<", "operator<=", "operator>", "operator>="};
+ for (auto *op : operators) {
+ auto *f = AbstractMetaClassPrivate::createFunction(QLatin1StringView(op),
+ AbstractMetaFunction::ComparisonOperator,
+ Access::Public, arguments,
+ returnType, this);
+ d->addFunction(AbstractMetaFunctionCPtr(f));
+ }
+}
+
bool AbstractMetaClass::hasNonPrivateConstructor() const
{
return d->m_hasNonPrivateConstructor;
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang.h b/sources/shiboken6/ApiExtractor/abstractmetalang.h
index d17bc5c80..10543381a 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang.h
@@ -117,6 +117,8 @@ public:
const TypeEntry *parentManagementEntry() const;
bool hasParentManagement() const { return parentManagementEntry() != nullptr; }
+ void addSynthesizedComparisonOperators();
+
bool generateExceptionHandling() const;
CppWrapper cppWrapper() const;
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
index 77f6d911e..4099caa2c 100644
--- a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
@@ -908,7 +908,13 @@ void _FunctionModelItem::setVariadics(bool isVariadics)
bool _FunctionModelItem::isDefaultConstructor() const
{
return m_functionType == CodeModel::Constructor
- && (m_arguments.isEmpty() || m_arguments.constFirst()->defaultValue());
+ && (m_arguments.isEmpty() || m_arguments.constFirst()->defaultValue());
+}
+
+bool _FunctionModelItem::isSpaceshipOperator() const
+{
+ return m_functionType == CodeModel::ComparisonOperator
+ && name() == u"operator<=>";
}
bool _FunctionModelItem::isNoExcept() const
@@ -1101,6 +1107,7 @@ static const NameFunctionTypeHash &nameToOperatorFunction()
{u"operator>=", CodeModel::ComparisonOperator},
{u"operator==", CodeModel::ComparisonOperator},
{u"operator!=", CodeModel::ComparisonOperator},
+ {u"operator<=>", CodeModel::ComparisonOperator},
{u"operator!", CodeModel::LogicalOperator},
{u"operator&&", CodeModel::LogicalOperator},
{u"operator||", CodeModel::LogicalOperator},
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.h b/sources/shiboken6/ApiExtractor/parser/codemodel.h
index 3b468c55b..58c7a9d2c 100644
--- a/sources/shiboken6/ApiExtractor/parser/codemodel.h
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel.h
@@ -514,6 +514,7 @@ public:
void setVariadics(bool isVariadics);
bool isDefaultConstructor() const;
+ bool isSpaceshipOperator() const;
bool isSimilar(const FunctionModelItem &other) const;
diff --git a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp
index 7401d64f5..90c613f96 100644
--- a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp
+++ b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp
@@ -7,6 +7,9 @@
#include <abstractmetafunction.h>
#include <abstractmetalang.h>
#include <typesystem.h>
+#include <clangparser/compilersupport.h>
+
+#include <algorithm>
void TestReverseOperators::testReverseSum()
{
@@ -93,7 +96,33 @@ void TestReverseOperators::testReverseSumWithAmbiguity()
QCOMPARE(reverseOp->minimalSignature(), u"operator+(A,B)");
}
-
+void TestReverseOperators::testSpaceshipOperator()
+{
+ const char cppCode[] = R"(
+ class Test {
+ public:
+ explicit Test(int v);
+ int operator<=>(const Test &rhs) const = default;
+ };)";
+ const char xmlCode[] = R"(
+ <typesystem package="Foo">
+ <value-type name='Test'/>
+ </typesystem>)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false,
+ {}, {}, LanguageLevel::Cpp20));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const AbstractMetaClass *testClass = AbstractMetaClass::findClass(classes, u"Test");
+ QVERIFY(testClass);
+ const auto &functions = testClass->functions();
+ // 6 operators should be synthesized
+ const auto count = std::count_if(functions.cbegin(), functions.cend(),
+ [](const AbstractMetaFunctionCPtr &f) {
+ return f->isComparisonOperator();
+ });
+ QCOMPARE(count, 6);
+}
QTEST_APPLESS_MAIN(TestReverseOperators)
diff --git a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h
index 7cf2cf13d..fb8d97c97 100644
--- a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h
+++ b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h
@@ -11,6 +11,7 @@ class TestReverseOperators : public QObject
private slots:
void testReverseSum();
void testReverseSumWithAmbiguity();
+ void testSpaceshipOperator();
};
#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testutil.h b/sources/shiboken6/ApiExtractor/tests/testutil.h
index 9b4ecf653..7fbc7e906 100644
--- a/sources/shiboken6/ApiExtractor/tests/testutil.h
+++ b/sources/shiboken6/ApiExtractor/tests/testutil.h
@@ -18,8 +18,9 @@ namespace TestUtil
{
static AbstractMetaBuilder *parse(const char *cppCode, const char *xmlCode,
bool silent = true,
- const QString &apiVersion = QString(),
- const QStringList &dropTypeEntries = QStringList())
+ const QString &apiVersion = {},
+ const QStringList &dropTypeEntries = {},
+ LanguageLevel languageLevel = LanguageLevel::Default)
{
ReportHandler::setSilent(silent);
ReportHandler::startTimer();
@@ -51,7 +52,7 @@ namespace TestUtil
auto builder = std::make_unique<AbstractMetaBuilder>();
try {
- if (!builder->build(arguments))
+ if (!builder->build(arguments, {}, true, languageLevel))
return nullptr;
} catch (const std::exception &e) {
qWarning("%s", e.what());
diff --git a/sources/shiboken6/tests/libsample/oddbool.cpp b/sources/shiboken6/tests/libsample/oddbool.cpp
index 4b21fbd80..06a61f1c2 100644
--- a/sources/shiboken6/tests/libsample/oddbool.cpp
+++ b/sources/shiboken6/tests/libsample/oddbool.cpp
@@ -21,3 +21,7 @@ int ComparisonTester::compare(const ComparisonTester &rhs) const
return 1;
return 0;
}
+
+SpaceshipComparisonTester::SpaceshipComparisonTester(int v) : m_value(v)
+{
+}
diff --git a/sources/shiboken6/tests/libsample/oddbool.h b/sources/shiboken6/tests/libsample/oddbool.h
index 6394119db..a64a05eb3 100644
--- a/sources/shiboken6/tests/libsample/oddbool.h
+++ b/sources/shiboken6/tests/libsample/oddbool.h
@@ -8,6 +8,10 @@
#include <type_traits>
+#if __cplusplus >= 202002 || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002)
+# include <compare>
+#endif
+
class OddBool
{
@@ -80,4 +84,21 @@ inline std::enable_if<std::is_assignable<ComparisonTester, int>::value, bool>::t
operator!=(const ComparisonTester &c1, const ComparisonTester &c2)
{ return c1.compare(c2) != 0; }
+class LIBSAMPLE_API SpaceshipComparisonTester
+{
+public:
+ explicit SpaceshipComparisonTester(int v);
+
+#if __cplusplus >= 202002 || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002)
+ auto operator<=>(const SpaceshipComparisonTester &rhs) const = default;
+
+ enum Enabled { HasSpaceshipOperator = 1 };
+#else
+ enum Enabled { HasSpaceshipOperator = 0 };
+#endif // C++ 20
+
+private:
+ int m_value;
+};
+
#endif // ODDBOOL_H
diff --git a/sources/shiboken6/tests/samplebinding/CMakeLists.txt b/sources/shiboken6/tests/samplebinding/CMakeLists.txt
index 65a790627..7576f6734 100644
--- a/sources/shiboken6/tests/samplebinding/CMakeLists.txt
+++ b/sources/shiboken6/tests/samplebinding/CMakeLists.txt
@@ -117,6 +117,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/sizef_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/snakecasetest_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/snakecasederivedtest_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/sonofmderived1_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/spaceshipcomparisontester_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/str_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/strlist_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/time_wrapper.cpp
diff --git a/sources/shiboken6/tests/samplebinding/oddbool_test.py b/sources/shiboken6/tests/samplebinding/oddbool_test.py
index de264614f..466ddba82 100644
--- a/sources/shiboken6/tests/samplebinding/oddbool_test.py
+++ b/sources/shiboken6/tests/samplebinding/oddbool_test.py
@@ -13,7 +13,7 @@ sys.path.append(os.fspath(Path(__file__).resolve().parents[1]))
from shiboken_paths import init_paths
init_paths()
-from sample import OddBoolUser, ComparisonTester
+from sample import OddBoolUser, ComparisonTester, SpaceshipComparisonTester
class DerivedOddBoolUser (OddBoolUser):
def returnMyselfVirtual(self):
@@ -59,6 +59,19 @@ class OddBoolTest(unittest.TestCase):
t2 = ComparisonTester(42)
self.assertEqual(t1, t2)
+ def testSpaceshipOperator(self):
+ if not SpaceshipComparisonTester.HasSpaceshipOperator:
+ print("Skipping Spaceship Operator test")
+ return
+ t1 = SpaceshipComparisonTester(42)
+ t2 = SpaceshipComparisonTester(42)
+ self.assertEqual(t1, t2)
+ self.assertTrue(t1 <= t2)
+ self.assertTrue(t1 >= t2)
+ t2 = SpaceshipComparisonTester(43)
+ self.assertTrue(t1 < t2)
+ self.assertFalse(t1 > t2)
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
index 706485459..7583a900a 100644
--- a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
+++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
@@ -152,6 +152,9 @@
<add-function signature="operator==(const ComparisonTester&amp;)" return-type="bool"/>
<add-function signature="operator!=(const ComparisonTester&amp;)" return-type="bool"/>
</value-type>
+ <value-type name="SpaceshipComparisonTester">
+ <enum-type name="Enabled"/>
+ </value-type>
<primitive-type name="PStr">
<include file-name="str.h" location="global"/>