aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/shiboken6/ApiExtractor/CMakeLists.txt1
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp20
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.h8
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp200
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h10
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testenum.cpp155
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testenum.h2
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.cpp137
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.h3
9 files changed, 386 insertions, 150 deletions
diff --git a/sources/shiboken6/ApiExtractor/CMakeLists.txt b/sources/shiboken6/ApiExtractor/CMakeLists.txt
index 8d2d194ab..37f929531 100644
--- a/sources/shiboken6/ApiExtractor/CMakeLists.txt
+++ b/sources/shiboken6/ApiExtractor/CMakeLists.txt
@@ -10,6 +10,7 @@ apiextractor.cpp
apiextractorresult.cpp
abstractmetaargument.cpp
abstractmetabuilder.cpp
+abstractmetabuilder_helpers.cpp
abstractmetaenum.cpp
abstractmetafield.cpp
abstractmetafunction.cpp
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
index aa2b01a34..b6c072b9b 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
@@ -2532,10 +2532,16 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV
return 0;
}
+QString AbstractMetaBuilder::fixEnumDefault(const AbstractMetaType &type,
+ const QString &expr) const
+{
+ return d->fixEnumDefault(type, expr);
+}
+
QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &item,
const AbstractMetaType &type,
const AbstractMetaClass *implementingClass,
- int /* argumentIndex */)
+ int /* argumentIndex */) const
{
QString expr = item->defaultValueExpression();
if (expr.isEmpty() || expr == u"{}")
@@ -2559,17 +2565,7 @@ QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &ite
// processed. This is done in figureOutEnumValues()
}
} else if (type.isFlags() || type.isEnum()) {
- bool isNumber;
- expr.toInt(&isNumber);
- if (!isNumber && expr.indexOf(colonColon()) < 0) {
- // Add the enum/flag scope to default value, making it usable
- // from other contexts beside its owner class hierarchy
- static const QRegularExpression typeRegEx(QStringLiteral("[^<]*[<]([^:]*::).*"));
- Q_ASSERT(typeRegEx.isValid());
- const QRegularExpressionMatch match = typeRegEx.match(type.minimalSignature());
- if (match.hasMatch())
- expr.prepend(match.captured(1));
- }
+ expr = fixEnumDefault(type, expr);
} else if (type.isContainer() && expr.contains(QLatin1Char('<'))) {
static const QRegularExpression typeRegEx(QStringLiteral("[^<]*<(.*)>"));
Q_ASSERT(typeRegEx.isValid());
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder.h
index 97c324f51..022c29cdd 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.h
@@ -107,6 +107,14 @@ public:
static QStringList definitionNames(const QString &name,
TypeSystem::SnakeCase snakeCase);
+ static QString resolveScopePrefix(const AbstractMetaClass *scope,
+ QStringView value);
+ static QString searchForEnumScope(const AbstractMetaClass *metaClass,
+ QStringView value);
+
+ // For testing purposes
+ QString fixEnumDefault(const AbstractMetaType &type, const QString &expr) const;
+
#ifndef QT_NO_DEBUG_STREAM
void formatDebug(QDebug &d) const;
#endif
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp
new file mode 100644
index 000000000..068c67241
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "abstractmetabuilder.h"
+#include "abstractmetabuilder_p.h"
+#include "abstractmetaenum.h"
+#include "abstractmetalang.h"
+#include "typesystem.h"
+
+using QStringViewList = QList<QStringView>;
+
+// Return a prefix to fully qualify value, eg:
+// resolveScopePrefix("Class::NestedClass::Enum::Value1", "Enum::Value1")
+// -> "Class::NestedClass::")
+static QString resolveScopePrefixHelper(const QStringViewList &scopeList,
+ QStringView value)
+{
+ QString name;
+ for (qsizetype i = scopeList.size() - 1 ; i >= 0; --i) {
+ const QString prefix = scopeList.at(i).toString() + u"::"_qs;
+ if (value.startsWith(prefix))
+ name.clear();
+ else
+ name.prepend(prefix);
+ }
+ return name;
+}
+
+QString AbstractMetaBuilder::resolveScopePrefix(const AbstractMetaClass *scope,
+ QStringView value)
+{
+ if (!scope)
+ return {};
+ const QString &qualifiedCppName = scope->qualifiedCppName();
+ const QStringViewList scopeList =
+ QStringView{qualifiedCppName}.split(u"::"_qs, Qt::SkipEmptyParts);
+ return resolveScopePrefixHelper(scopeList, value);
+}
+
+// Return the scope for fully qualifying the enumeration value
+static QString resolveEnumValueScopePrefix(const AbstractMetaEnum &metaEnum,
+ QStringView value)
+{
+ const AbstractMetaClass *scope = metaEnum.enclosingClass();
+ if (!scope)
+ return {}; // global enum, value should work as is
+ const QString &qualifiedCppName = scope->qualifiedCppName();
+ const QString &enumName = metaEnum.name();
+ QStringViewList parts =
+ QStringView{qualifiedCppName}.split(u"::"_qs, Qt::SkipEmptyParts);
+ // Append the type (as required for enum classes) unless it is an anonymous enum.
+ if (!metaEnum.isAnonymous())
+ parts.append(QStringView{enumName});
+ return resolveScopePrefixHelper(parts, value);
+}
+
+// Return the scope for fully qualifying an enumeration value from
+// an unknown enum in the class scope including trailing "::".
+QString AbstractMetaBuilder::searchForEnumScope(const AbstractMetaClass *metaClass,
+ QStringView value)
+{
+ if (!metaClass)
+ return QString();
+ for (const AbstractMetaEnum &metaEnum : metaClass->enums()) {
+ auto v = metaEnum.findEnumValue(value);
+ if (v.has_value())
+ return resolveEnumValueScopePrefix(metaEnum, value);
+ }
+ // PYSIDE-331: We need to also search the base classes.
+ QString ret = searchForEnumScope(metaClass->enclosingClass(), value);
+ if (ret.isEmpty())
+ ret = searchForEnumScope(metaClass->baseClass(), value);
+ return ret;
+}
+
+static bool isQualifiedCppIdentifier(QStringView e)
+{
+ return !e.isEmpty() && e.at(0).isLetter()
+ && std::all_of(e.cbegin() + 1, e.cend(),
+ [](QChar c) { return c.isLetterOrNumber() || c == u'_' || c == u':'; });
+}
+
+static bool isNumericConstant(const QStringView expr)
+{
+ bool isNumber;
+ auto n = expr.toInt(&isNumber, /* guess base: 0x or decimal */ 0);
+ Q_UNUSED(n);
+ return isNumber;
+}
+
+// Fix an enum default value: Add the enum/flag scope or fully qualified name
+// to the default value, making it usable from Python wrapper code outside the
+// owner class hierarchy. See TestEnum::testEnumDefaultValues().
+QString AbstractMetaBuilderPrivate::fixEnumDefault(const AbstractMetaType &type,
+ const QString &expr) const
+{
+ // QFlags construct from integers, do not fix that
+ if (isNumericConstant(expr))
+ return expr;
+
+ const auto *typeEntry = type.typeEntry();
+ const EnumTypeEntry *enumTypeEntry = nullptr;
+ const FlagsTypeEntry *flagsTypeEntry = nullptr;
+ if (typeEntry->isFlags()) {
+ flagsTypeEntry = static_cast<const FlagsTypeEntry *>(typeEntry);
+ enumTypeEntry = flagsTypeEntry->originator();
+ } else {
+ Q_ASSERT(typeEntry->isEnum());
+ enumTypeEntry = static_cast<const EnumTypeEntry *>(typeEntry);
+ }
+ // Use the enum's qualified name (would otherwise be "QFlags<Enum>")
+ if (!enumTypeEntry->qualifiedCppName().contains(u"::"))
+ return expr; // Global enum, nothing to fix here
+
+ // This is a somehow scoped enum
+ AbstractMetaEnum metaEnum = m_enums.value(enumTypeEntry);
+
+ if (isQualifiedCppIdentifier(expr)) // A single enum value
+ return resolveEnumValueScopePrefix(metaEnum, expr) + expr;
+
+ QString result;
+ // Is this a cast from integer or other type ("Enum(-1)" or "Options(0x10|0x20)"?
+ // Prepend the scope (assuming enum and flags are in the same scope).
+ auto parenPos = expr.indexOf(u'(');
+ const bool typeCast = parenPos != -1 && expr.endsWith(u')')
+ && isQualifiedCppIdentifier(QStringView{expr}.left(parenPos));
+ if (typeCast) {
+ const QString prefix =
+ AbstractMetaBuilder::resolveScopePrefix(metaEnum.enclosingClass(), expr);
+ result += prefix;
+ parenPos += prefix.size();
+ }
+ result += expr;
+
+ // Extract "Option1 | Option2" from "Options(Option1 | Option2)"
+ QStringView innerExpression = typeCast
+ ? QStringView{result}.mid(parenPos + 1, result.size() - parenPos - 2)
+ : QStringView{result};
+
+ // Quick check for number "Options(0x4)"
+ if (isNumericConstant(innerExpression))
+ return result;
+
+ // Quick check for single enum value "Options(Option1)"
+ if (isQualifiedCppIdentifier(innerExpression)) {
+ const QString prefix = resolveEnumValueScopePrefix(metaEnum, innerExpression);
+ result.insert(parenPos + 1, prefix);
+ return result;
+ }
+
+ // Tokenize simple "A | B" expressions and qualify the enum values therein.
+ // Anything more complicated is left as is ATM.
+ if (!innerExpression.contains(u'|') || innerExpression.contains(u'&')
+ || innerExpression.contains(u'^') || innerExpression.contains(u'(')
+ || innerExpression.contains(u'~')) {
+ return result;
+ }
+
+ const QList<QStringView> tokens = innerExpression.split(u'|', Qt::SkipEmptyParts);
+ QStringList qualifiedTokens;
+ qualifiedTokens.reserve(tokens.size());
+ for (const auto &tokenIn : tokens) {
+ const auto token = tokenIn.trimmed();
+ QString qualified = token.toString();
+ if (!isNumericConstant(token) && isQualifiedCppIdentifier(token))
+ qualified.prepend(resolveEnumValueScopePrefix(metaEnum, token));
+ qualifiedTokens.append(qualified);
+ }
+ const QString qualifiedExpression = qualifiedTokens.join(u" | "_qs);
+ if (!typeCast)
+ return qualifiedExpression;
+
+ result.replace(parenPos + 1, innerExpression.size(), qualifiedExpression);
+ return result;
+}
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
index ac4e5adec..a52b4bf9d 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
@@ -149,10 +149,12 @@ public:
static void setupFunctionDefaults(AbstractMetaFunction *metaFunction,
AbstractMetaClass *metaClass);
- static QString fixDefaultValue(const ArgumentModelItem &item,
- const AbstractMetaType &type,
- const AbstractMetaClass *,
- int argumentIndex);
+ QString fixDefaultValue(const ArgumentModelItem &item,
+ const AbstractMetaType &type,
+ const AbstractMetaClass *,
+ int argumentIndex) const;
+ QString fixEnumDefault(const AbstractMetaType &type, const QString &expr) const;
+
std::optional<AbstractMetaType>
translateType(const TypeInfo &type, const AbstractMetaClass *currentClass,
TranslateTypeFlags flags = {}, QString *errorMessage = nullptr);
diff --git a/sources/shiboken6/ApiExtractor/tests/testenum.cpp b/sources/shiboken6/ApiExtractor/tests/testenum.cpp
index df744e994..c1d552786 100644
--- a/sources/shiboken6/ApiExtractor/tests/testenum.cpp
+++ b/sources/shiboken6/ApiExtractor/tests/testenum.cpp
@@ -32,6 +32,7 @@
#include <abstractmetaenum.h>
#include <abstractmetafunction.h>
#include <abstractmetalang.h>
+#include <abstractmetabuilder_p.h>
#include <typesystem.h>
#include <parser/enumvalue.h>
@@ -437,4 +438,158 @@ void TestEnum::testTypedefEnum()
QCOMPARE(enumValueA1.stringValue(), QString());
}
+// Helper classes and functions for testing enum default value fixing.
+// Put the AbstractMetaBuilder into test fixture struct to avoid having
+// to re-parse for each data row.
+
+struct EnumDefaultValuesFixture
+{
+ QSharedPointer<AbstractMetaBuilder> builder;
+
+ AbstractMetaType globalEnum;
+ AbstractMetaType testEnum;
+ AbstractMetaType testOptions;
+};
+
+Q_DECLARE_METATYPE(EnumDefaultValuesFixture)
+Q_DECLARE_METATYPE(AbstractMetaType)
+
+static int populateDefaultValuesFixture(EnumDefaultValuesFixture *fixture)
+{
+ static const char cppCode[] =R"(
+enum GlobalEnum { GE1, GE2 };
+namespace Test1
+{
+namespace Test2
+{
+ enum Enum1 { E1, E2 };
+ enum Option { O1, O2 };
+} // namespace Test2
+} // namespace Test1
+)";
+ static const char xmlCode[] = R"(
+<typesystem package="Foo">
+ <enum-type name='GlobalEnum'/>
+ <namespace-type name='Test1'>
+ <namespace-type name='Test2'>
+ <enum-type name='Enum1'/>
+ <enum-type name='Option' flags='Options'/>
+ </namespace-type>
+ </namespace-type>
+</typesystem>
+)";
+
+ fixture->builder.reset(TestUtil::parse(cppCode, xmlCode, false));
+ if (fixture->builder.isNull())
+ return -1;
+
+ const auto globalEnums = fixture->builder->globalEnums();
+ if (globalEnums.count() != 1)
+ return -2;
+
+ fixture->globalEnum = AbstractMetaType(globalEnums.constFirst().typeEntry());
+ fixture->globalEnum.decideUsagePattern();
+
+ const AbstractMetaClass *testNamespace = nullptr;
+ for (auto *c : fixture->builder->classes()) {
+ if (c->name() == u"Test2") {
+ testNamespace = c;
+ break;
+ }
+ }
+ if (!testNamespace)
+ return -3;
+
+ const auto namespaceEnums = testNamespace->enums();
+ if (namespaceEnums.count() != 2)
+ return -4;
+ QList<const EnumTypeEntry *> enumTypeEntries{
+ static_cast<const EnumTypeEntry *>(namespaceEnums.at(0).typeEntry()),
+ static_cast<const EnumTypeEntry *>(namespaceEnums.at(1).typeEntry())};
+ if (enumTypeEntries.constFirst()->flags())
+ std::swap(enumTypeEntries[0], enumTypeEntries[1]);
+ fixture->testEnum = AbstractMetaType(enumTypeEntries.at(0));
+ fixture->testEnum.decideUsagePattern();
+ fixture->testOptions = AbstractMetaType(enumTypeEntries.at(1)->flags());
+ fixture->testOptions.decideUsagePattern();
+ return 0;
+}
+
+void TestEnum::testEnumDefaultValues_data()
+{
+ EnumDefaultValuesFixture fixture;
+ const int setupOk = populateDefaultValuesFixture(&fixture);
+
+ QTest::addColumn<EnumDefaultValuesFixture>("fixture");
+ QTest::addColumn<int>("setupOk"); // To verify setup
+ QTest::addColumn<AbstractMetaType>("metaType"); // Type and parameters for fixup
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("expected");
+
+ // Global should just remain unmodified
+ QTest::newRow("global") << fixture << setupOk
+ << fixture.globalEnum << "GE1" << "GE1";
+ QTest::newRow("global-int") << fixture << setupOk
+ << fixture.globalEnum << "42" << "42";
+ QTest::newRow("global-hex-int") << fixture << setupOk
+ << fixture.globalEnum << "0x10" << "0x10";
+ QTest::newRow("global-int-cast") << fixture << setupOk
+ << fixture.globalEnum << "GlobalEnum(-1)" << "GlobalEnum(-1)";
+
+ // Namespaced enum as number should remain unmodified
+ QTest::newRow("namespace-enum-int") << fixture << setupOk
+ << fixture.testEnum << "42" << "42";
+ QTest::newRow("namespace-enum-hex-int") << fixture << setupOk
+ << fixture.testEnum << "0x10" << "0x10";
+ // Partial qualification of namespaced enum
+ QTest::newRow("namespace-enum-qualified") << fixture << setupOk
+ << fixture.testEnum << "Enum1::E1" << "Test1::Test2::Enum1::E1";
+ // Unqualified namespaced enums
+ QTest::newRow("namespace-enum-unqualified") << fixture << setupOk
+ << fixture.testEnum << "E1" << "Test1::Test2::Enum1::E1";
+ // Namespaced enums cast from int should be qualified by scope
+ QTest::newRow("namespace-enum-int-cast") << fixture << setupOk
+ << fixture.testEnum << "Enum1(-1)" << "Test1::Test2::Enum1(-1)";
+
+ // Namespaced option as number should remain unmodified
+ QTest::newRow("namespace-option-int") << fixture << setupOk
+ << fixture.testOptions << "0x10" << "0x10";
+ QTest::newRow("namespace-option-expression") << fixture << setupOk
+ << fixture.testOptions << "0x10 | 0x20" << "0x10 | 0x20";
+ QTest::newRow("namespace-option-expression1") << fixture << setupOk
+ << fixture.testOptions << "0x10 | Test1::Test2::Option::O1"
+ << "0x10 | Test1::Test2::Option::O1";
+ QTest::newRow("namespace-option-expression2") << fixture << setupOk
+ << fixture.testOptions << "0x10 | O1" << "0x10 | Test1::Test2::Option::O1";
+ // Complicated expressions - should remain unmodified
+ QTest::newRow("namespace-option-expression-paren") << fixture << setupOk
+ << fixture.testOptions << "0x10 | (0x20 | 0x40 | O1)"
+ << "0x10 | (0x20 | 0x40 | O1)";
+
+ // Option: Cast Enum from int should be qualified
+ QTest::newRow("namespace-option-int-cast") << fixture << setupOk
+ << fixture.testOptions << "Option(0x10)" << "Test1::Test2::Option(0x10)";
+ // Option: Cast Flags from int should be qualified
+ QTest::newRow("namespace-options-int-cast") << fixture << setupOk
+ << fixture.testOptions << "Options(0x10 | 0x20)" << "Test1::Test2::Options(0x10 | 0x20)";
+ QTest::newRow("namespace-option-cast-expression1") << fixture << setupOk
+ << fixture.testOptions << "Test1::Test2::Options(0x10 | Test1::Test2::Option::O1)"
+ << "Test1::Test2::Options(0x10 | Test1::Test2::Option::O1)";
+ QTest::newRow("namespace-option-cast-expression2") << fixture << setupOk
+ << fixture.testOptions << "Options(0x10 | O1)"
+ << "Test1::Test2::Options(0x10 | Test1::Test2::Option::O1)";
+}
+
+void TestEnum::testEnumDefaultValues()
+{
+ QFETCH(EnumDefaultValuesFixture, fixture);
+ QFETCH(int, setupOk);
+ QFETCH(AbstractMetaType, metaType);
+ QFETCH(QString, input);
+ QFETCH(QString, expected);
+ QCOMPARE(setupOk, 0);
+ const QString actual = fixture.builder->fixEnumDefault(metaType, input);
+ QCOMPARE(actual, expected);
+}
+
QTEST_APPLESS_MAIN(TestEnum)
diff --git a/sources/shiboken6/ApiExtractor/tests/testenum.h b/sources/shiboken6/ApiExtractor/tests/testenum.h
index 312551763..20dbac79f 100644
--- a/sources/shiboken6/ApiExtractor/tests/testenum.h
+++ b/sources/shiboken6/ApiExtractor/tests/testenum.h
@@ -42,6 +42,8 @@ private slots:
void testEnumValueFromExpression();
void testPrivateEnum();
void testTypedefEnum();
+ void testEnumDefaultValues_data();
+ void testEnumDefaultValues();
};
#endif
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
index 5063faa88..6d5d20dcd 100644
--- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
@@ -29,6 +29,7 @@
#include "shibokengenerator.h"
#include "apiextractorresult.h"
#include "ctypenames.h"
+#include <abstractmetabuilder.h>
#include <abstractmetaenum.h>
#include <abstractmetafield.h>
#include <abstractmetafunction.h>
@@ -79,58 +80,6 @@ const char *BEGIN_ALLOW_THREADS =
"PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS";
const char *END_ALLOW_THREADS = "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS";
-// Return a prefix to fully qualify value, eg:
-// resolveScopePrefix("Class::NestedClass::Enum::Value1", "Enum::Value1")
-// -> "Class::NestedClass::")
-static QString resolveScopePrefix(const QStringList &scopeList, const QString &value)
-{
- QString name;
- for (int i = scopeList.size() - 1 ; i >= 0; --i) {
- const QString prefix = scopeList.at(i) + QLatin1String("::");
- if (value.startsWith(prefix))
- name.clear();
- else
- name.prepend(prefix);
- }
- return name;
-}
-
-static inline QStringList splitClassScope(const AbstractMetaClass *scope)
-{
- return scope->qualifiedCppName().split(QLatin1String("::"), Qt::SkipEmptyParts);
-}
-
-static QString resolveScopePrefix(const AbstractMetaClass *scope, const QString &value)
-{
- return scope
- ? resolveScopePrefix(splitClassScope(scope), value)
- : QString();
-}
-
-// Check whether the value is a cast from int for an enum "Enum(-1)"
-static bool isEnumCastFromInt(const AbstractMetaEnum &metaEnum,
- const QString &value)
-{
- const auto parenPos = value.indexOf(u'(');
- if (parenPos < 0)
- return false;
- const auto prefix = QStringView{value}.left(parenPos);
- return prefix.endsWith(metaEnum.name());
-}
-
-static QString resolveScopePrefix(const AbstractMetaEnum &metaEnum,
- const QString &value)
-{
- QStringList parts;
- if (const AbstractMetaClass *scope = metaEnum.enclosingClass())
- parts.append(splitClassScope(scope));
- // Fully qualify the value which is required for C++ 11 enum classes
- // unless it is a cast from int "Enum(-)" which already has the type name.
- if (!metaEnum.isAnonymous() && !isEnumCastFromInt(metaEnum, value))
- parts.append(metaEnum.name());
- return resolveScopePrefix(parts, value);
-}
-
struct GeneratorClassInfoCacheEntry
{
ShibokenGenerator::FunctionGroups functionGroups;
@@ -415,76 +364,6 @@ static QString cpythonEnumFlagsName(const QString &moduleName,
return result;
}
-// Return the scope for fully qualifying the enumeration including trailing "::".
-static QString searchForEnumScope(const AbstractMetaClass *metaClass, const QString &value)
-{
- if (!metaClass)
- return QString();
- for (const AbstractMetaEnum &metaEnum : metaClass->enums()) {
- auto v = metaEnum.findEnumValue(value);
- if (v.has_value())
- return resolveScopePrefix(metaEnum, value);
- }
- // PYSIDE-331: We need to also search the base classes.
- QString ret = searchForEnumScope(metaClass->enclosingClass(), value);
- if (ret.isEmpty())
- ret = searchForEnumScope(metaClass->baseClass(), value);
- return ret;
-}
-
-// Handle QFlags<> for guessScopeForDefaultValue()
-QString ShibokenGenerator::guessScopeForDefaultFlagsValue(const AbstractMetaFunctionCPtr &func,
- const AbstractMetaArgument &arg,
- const QString &value) const
-{
- // Numeric values -> "Options(42)"
- static const QRegularExpression numberRegEx(QStringLiteral("^\\d+$")); // Numbers to flags
- Q_ASSERT(numberRegEx.isValid());
- if (numberRegEx.match(value).hasMatch()) {
- QString typeName = translateTypeForWrapperMethod(arg.type(), func->implementingClass());
- if (arg.type().isConstant())
- typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
- switch (arg.type().referenceType()) {
- case NoReference:
- break;
- case LValueReference:
- typeName.chop(1);
- break;
- case RValueReference:
- typeName.chop(2);
- break;
- }
- return typeName + QLatin1Char('(') + value + QLatin1Char(')');
- }
-
- // "Options(Option1 | Option2)" -> "Options(Class::Enum::Option1 | Class::Enum::Option2)"
- static const QRegularExpression enumCombinationRegEx(QStringLiteral("^([A-Za-z_][\\w:]*)\\(([^,\\(\\)]*)\\)$")); // FlagName(EnumItem|EnumItem|...)
- Q_ASSERT(enumCombinationRegEx.isValid());
- const QRegularExpressionMatch match = enumCombinationRegEx.match(value);
- if (match.hasMatch()) {
- const QString expression = match.captured(2).trimmed();
- if (expression.isEmpty())
- return value;
- const QStringList enumItems = expression.split(QLatin1Char('|'));
- const QString scope = searchForEnumScope(func->implementingClass(),
- enumItems.constFirst().trimmed());
- if (scope.isEmpty())
- return value;
- QString result;
- QTextStream str(&result);
- str << match.captured(1) << '('; // Flag name
- for (int i = 0, size = enumItems.size(); i < size; ++i) {
- if (i)
- str << '|';
- str << scope << enumItems.at(i).trimmed();
- }
- str << ')';
- return result;
- }
- // A single flag "Option1" -> "Class::Enum::Option1"
- return searchForEnumScope(func->implementingClass(), value) + value;
-}
-
/*
* This function uses some heuristics to find out the scope for a given
* argument default value since they must be fully qualified when used outside the class:
@@ -518,20 +397,16 @@ QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunctionC
return value;
QString prefix;
- if (arg.type().isEnum()) {
- auto metaEnum = api().findAbstractMetaEnum(arg.type().typeEntry());
- if (metaEnum.has_value())
- prefix = resolveScopePrefix(metaEnum.value(), value);
- } else if (arg.type().isFlags()) {
- value = guessScopeForDefaultFlagsValue(func, arg, value);
+ if (arg.type().isEnum() || arg.type().isFlags()) {
+ // handled by AbstractMetaBuilder::fixEnumDefault()
} else if (arg.type().typeEntry()->isValue()) {
auto metaClass = AbstractMetaClass::findClass(api().classes(),
arg.type().typeEntry());
if (enumValueRegEx.match(value).hasMatch() && value != QLatin1String("NULL"))
- prefix = resolveScopePrefix(metaClass, value);
+ prefix = AbstractMetaBuilder::resolveScopePrefix(metaClass, value);
} else if (arg.type().isPrimitive() && arg.type().name() == intT()) {
if (enumValueRegEx.match(value).hasMatch() && func->implementingClass())
- prefix = resolveScopePrefix(func->implementingClass(), value);
+ prefix = AbstractMetaBuilder::resolveScopePrefix(func->implementingClass(), value);
} else if (arg.type().isPrimitive()) {
static const QRegularExpression unknowArgumentRegEx(QStringLiteral("^(?:[A-Za-z_][\\w:]*\\()?([A-Za-z_]\\w*)(?:\\))?$")); // [PrimitiveType(] DESIREDNAME [)]
Q_ASSERT(unknowArgumentRegEx.isValid());
@@ -541,7 +416,7 @@ QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunctionC
if (match.captured(1).trimmed() == field.name()) {
QString fieldName = field.name();
if (field.isStatic()) {
- prefix = resolveScopePrefix(func->implementingClass(), value);
+ prefix = AbstractMetaBuilder::resolveScopePrefix(func->implementingClass(), value);
fieldName.prepend(prefix);
prefix.clear();
} else {
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.h b/sources/shiboken6/generator/shiboken/shibokengenerator.h
index 7e8d0b290..bf71bb0a3 100644
--- a/sources/shiboken6/generator/shiboken/shibokengenerator.h
+++ b/sources/shiboken6/generator/shiboken/shibokengenerator.h
@@ -270,9 +270,6 @@ protected:
/// Guesses the scope to where belongs an argument's default value.
QString guessScopeForDefaultValue(const AbstractMetaFunctionCPtr &func,
const AbstractMetaArgument &arg) const;
- QString guessScopeForDefaultFlagsValue(const AbstractMetaFunctionCPtr &func,
- const AbstractMetaArgument &arg,
- const QString &value) const;
static QString cpythonEnumName(const EnumTypeEntry *enumEntry);
static QString cpythonEnumName(const AbstractMetaEnum &metaEnum);