diff options
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); |