diff options
4 files changed, 114 insertions, 23 deletions
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder.h index 022c29cdd..82503ae44 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.h +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.h @@ -109,8 +109,6 @@ public: 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; diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp index 068c67241..f153d0594 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp @@ -79,25 +79,6 @@ static QString resolveEnumValueScopePrefix(const AbstractMetaEnum &metaEnum, 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() diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp index d1f3e552b..ac7445c13 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp +++ b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp @@ -700,6 +700,90 @@ EnumModelItem _ScopeModelItem::findEnum(const QString &name) const return findModelItem(m_enums, name); } +_ScopeModelItem::FindEnumByValueReturn + _ScopeModelItem::findEnumByValueHelper(QStringView fullValue, + QStringView enumValue) const +{ + const bool unqualified = fullValue.size() == enumValue.size(); + QString scopePrefix = scope().join(u"::"); + if (!scopePrefix.isEmpty()) + scopePrefix += u"::"_qs; + scopePrefix += name() + u"::"_qs; + + for (const auto &e : m_enums) { + const auto index = e->indexOfValue(enumValue); + if (index != -1) { + QString fullyQualifiedName = scopePrefix; + if (e->enumKind() != AnonymousEnum) + fullyQualifiedName += e->name() + u"::"_qs; + fullyQualifiedName += e->enumerators().at(index)->name(); + if (unqualified || fullyQualifiedName.endsWith(fullValue)) + return {e, fullyQualifiedName}; + // For standard enums, check the name without enum name + if (e->enumKind() == CEnum) { + const QString qualifiedName = + scopePrefix + e->enumerators().at(index)->name(); + if (qualifiedName.endsWith(fullValue)) + return {e, fullyQualifiedName}; + } + } + } + + return {}; +} + +// Helper to recursively find the scope of an enum value +_ScopeModelItem::FindEnumByValueReturn + _ScopeModelItem::findEnumByValueRecursion(const _ScopeModelItem *scope, + QStringView fullValue, + QStringView enumValue, + bool searchSiblingNamespaces) +{ + if (const auto e = scope->findEnumByValueHelper(fullValue, enumValue)) + return e; + + if (auto *enclosingScope = scope->enclosingScope()) { + // The enclosing scope may have several sibling namespaces of that name. + if (searchSiblingNamespaces && scope->kind() == Kind_Namespace) { + if (auto *enclosingNamespace = dynamic_cast<const _NamespaceModelItem *>(enclosingScope)) { + for (const auto &sibling : enclosingNamespace->namespaces()) { + if (sibling.data() != scope && sibling->name() == scope->name()) { + if (const auto e = findEnumByValueRecursion(sibling.data(), + fullValue, enumValue, false)) { + return e; + } + } + } + } + } + + if (const auto e = findEnumByValueRecursion(enclosingScope, fullValue, enumValue)) + return e; + } + + // PYSIDE-331: We need to also search the base classes. + if (auto *classItem = dynamic_cast<const _ClassModelItem *>(scope)) { + for (const auto &base : classItem->baseClasses()) { + if (!base.klass.isNull()) { + auto *c = base.klass.data(); + if (const auto e = findEnumByValueRecursion(c, fullValue, enumValue)) + return e; + } + } + } + + return {}; +} + +_ScopeModelItem::FindEnumByValueReturn + _ScopeModelItem::findEnumByValue(QStringView value) const +{ + const auto lastQualifier = value.lastIndexOf(u"::"); + const auto enumValue = lastQualifier == -1 + ? value : value.mid(lastQualifier + 2); + return findEnumByValueRecursion(this, value, enumValue); +} + FunctionList _ScopeModelItem::findFunctions(const QString &name) const { FunctionList result; @@ -1185,6 +1269,15 @@ void _EnumModelItem::addEnumerator(const EnumeratorModelItem &item) m_enumerators.append(item); } +qsizetype _EnumModelItem::indexOfValue(QStringView value) const +{ + for (qsizetype i = 0, size = m_enumerators.size(); i < size; ++i) { + if (m_enumerators.at(i)->name() == value) + return i; + } + return -1; +} + bool _EnumModelItem::isSigned() const { return m_signed; diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.h b/sources/shiboken6/ApiExtractor/parser/codemodel.h index db3675d17..38652aa7e 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel.h +++ b/sources/shiboken6/ApiExtractor/parser/codemodel.h @@ -205,7 +205,7 @@ public: ~_ScopeModelItem(); ClassList classes() const { return m_classes; } - EnumList enums() const { return m_enums; } + const EnumList &enums() const { return m_enums; } inline const FunctionList &functions() const { return m_functions; } TypeDefList typeDefs() const { return m_typeDefs; } TemplateTypeAliasList templateTypeAliases() const { return m_templateTypeAliases; } @@ -220,6 +220,16 @@ public: ClassModelItem findClass(const QString &name) const; EnumModelItem findEnum(const QString &name) const; + + struct FindEnumByValueReturn + { + operator bool() const { return !item.isNull(); } + + EnumModelItem item; + QString qualifiedName; + }; + FindEnumByValueReturn findEnumByValue(QStringView value) const; + FunctionList findFunctions(const QString &name) const; TypeDefModelItem findTypeDef(const QString &name) const; TemplateTypeAliasModelItem findTemplateTypeAlias(const QString &name) const; @@ -252,6 +262,13 @@ protected: private: qsizetype indexOfEnum(const QString &name) const; + FindEnumByValueReturn findEnumByValueHelper(QStringView fullValue, + QStringView value) const; + static FindEnumByValueReturn + findEnumByValueRecursion(const _ScopeModelItem *scope, + QStringView fullValue, QStringView value, + bool searchSiblingNamespaces = true); + ClassList m_classes; EnumList m_enums; TypeDefList m_typeDefs; @@ -288,7 +305,7 @@ public: : _ScopeModelItem(model, name, kind), m_classType(CodeModel::Class) {} ~_ClassModelItem(); - QList<BaseClass> baseClasses() const { return m_baseClasses; } + const QList<BaseClass> &baseClasses() const { return m_baseClasses; } const QList<UsingMember> &usingMembers() const; void addUsingMember(const QString &className, const QString &memberName, @@ -636,6 +653,8 @@ public: EnumKind enumKind() const { return m_enumKind; } void setEnumKind(EnumKind kind) { m_enumKind = kind; } + qsizetype indexOfValue(QStringView value) const; + #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; #endif |