aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2021-10-29 09:33:16 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-11-05 15:28:57 +0000
commitfb7b64aff910d777428948400bc9c375ec6af4e0 (patch)
treeeecfc91eb8a30c580d6e7fdf0cf63b3764a647eb
parent7bb93691123f392d1db6e5d6f326d788970073b4 (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>
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.h2
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp19
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel.cpp93
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel.h23
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