diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2021-10-29 09:33:16 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-11-05 15:28:57 +0000 |
commit | fb7b64aff910d777428948400bc9c375ec6af4e0 (patch) | |
tree | eecfc91eb8a30c580d6e7fdf0cf63b3764a647eb | |
parent | 7bb93691123f392d1db6e5d6f326d788970073b4 (diff) |
shiboken6: Implement enum search by value in code model
Replace (currently unused) AbstractMetaBuilder::searchForEnumScope()
by _ScopeModelItem::findEnumByValue() returning an enum and the fully
qualified name.
This function is intended for resolving enum values used as default
values for functions taking int where the underlying enum is not
known.
As opposed to old code, all parts of a (partially) qualified name are
checked for a match to ensure no mismatches of equally named values.
Another advantage is that also enum values that are not in the type
system are found.
The function returns the fully qualified name (also including
the enum name for non-class type enums).
Task-number: PYSIDE-1691
Change-Id: I89ebfdf8435470c626cfdee4fc0d0738cc3fc195
Reviewed-by: Christian Tismer <tismer@stackless.com>
(cherry picked from commit 8b414806b80683e162133338c4b3ca0816746aaa)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
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 |