diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-11-03 15:22:50 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-11-05 15:09:24 +0000 |
commit | 3019e2079a55d0eea252495954ee784652bca46b (patch) | |
tree | 90b33ff666d12f59b0fe82135c17d27f3a96a52e | |
parent | ce954a1cec8e7cd44cdad09bcda8f9f6d9aaa83d (diff) |
shiboken6: Split out class TypeInfo
This is the first step towards using it in AddedFunction
as well, replacing AddedFunction::TypeInfo.
Change list accessors to return const-ref on this occasion.
Change-Id: I78a7be0b3cb738b859519b7fbff8ed024fb46106
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
-rw-r--r-- | sources/shiboken6/ApiExtractor/CMakeLists.txt | 1 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp | 3 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/parser/codemodel.cpp | 391 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/parser/codemodel.h | 152 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/parser/typeinfo.cpp | 413 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/parser/typeinfo.h | 168 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/typeparser.cpp | 2 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/typeparser.h | 1 |
8 files changed, 598 insertions, 533 deletions
diff --git a/sources/shiboken6/ApiExtractor/CMakeLists.txt b/sources/shiboken6/ApiExtractor/CMakeLists.txt index e1b1f64e4..ec9c55364 100644 --- a/sources/shiboken6/ApiExtractor/CMakeLists.txt +++ b/sources/shiboken6/ApiExtractor/CMakeLists.txt @@ -30,6 +30,7 @@ clangparser/clangbuilder.cpp clangparser/clangdebugutils.cpp clangparser/clangutils.cpp # Old parser +parser/typeinfo.cpp parser/codemodel.cpp parser/enumvalue.cpp xmlutils.cpp diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp index 3bcc35048..122ea374f 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp @@ -2670,10 +2670,9 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, const AbstractMetaClass *templateClass, const TypeInfo &info) { - QVector<TypeInfo> targs = info.instantiations(); AbstractMetaTypeList templateTypes; - for (const TypeInfo &i : qAsConst(targs)) { + for (const TypeInfo &i : info.instantiations()) { QString typeName = i.qualifiedName().join(colonColon()); TypeDatabase *typeDb = TypeDatabase::instance(); TypeEntry *t = nullptr; diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp index 76ce333ed..8e1cb9710 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp +++ b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp @@ -31,14 +31,13 @@ #include "codemodel.h" #include <sourcelocation.h> -#include <clangparser/clangutils.h> + +#include <QtCore/QDebug> +#include <QtCore/QDir> #include <algorithm> #include <functional> #include <iostream> -#include <QDebug> -#include <QDir> -#include <QtCore/QStack> // Predicate to find an item by name in a list of QSharedPointer<Item> template <class T> class ModelItemNamePredicate @@ -134,380 +133,6 @@ QDebug operator<<(QDebug d, const CodeModel *m) #endif // !QT_NO_DEBUG_STREAM // --------------------------------------------------------------------------- -TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs) -{ - TypeInfo __result = __lhs; - - __result.setConstant(__result.isConstant() || __rhs.isConstant()); - __result.setVolatile(__result.isVolatile() || __rhs.isVolatile()); - if (__rhs.referenceType() > __result.referenceType()) - __result.setReferenceType(__rhs.referenceType()); - __result.m_indirections.append(__rhs.m_indirections); - __result.setArrayElements(__result.arrayElements() + __rhs.arrayElements()); - __result.m_instantiations.append(__rhs.m_instantiations); - - return __result; -} - -bool TypeInfo::isVoid() const -{ - return m_indirections.isEmpty() && m_referenceType == NoReference - && m_arguments.isEmpty() && m_arrayElements.isEmpty() - && m_instantiations.isEmpty() - && m_qualifiedName.size() == 1 - && m_qualifiedName.constFirst() == QLatin1String("void"); -} - -TypeInfo TypeInfo::resolveType(TypeInfo const &__type, const ScopeModelItem &__scope) -{ - CodeModel *__model = __scope->model(); - Q_ASSERT(__model != nullptr); - - return TypeInfo::resolveType(__model->findItem(__type.qualifiedName(), __scope), __type, __scope); -} - -TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, const ScopeModelItem &__scope) -{ - // Copy the type and replace with the proper qualified name. This - // only makes sence to do if we're actually getting a resolved - // type with a namespace. We only get this if the returned type - // has more than 2 entries in the qualified name... This test - // could be improved by returning if the type was found or not. - TypeInfo otherType(__type); - if (__item && __item->qualifiedName().size() > 1) { - otherType.setQualifiedName(__item->qualifiedName()); - } - - if (TypeDefModelItem __typedef = qSharedPointerDynamicCast<_TypeDefModelItem>(__item)) { - const TypeInfo combined = TypeInfo::combine(__typedef->type(), otherType); - const CodeModelItem nextItem = __scope->model()->findItem(combined.qualifiedName(), __scope); - if (!nextItem) - return combined; - // PYSIDE-362, prevent recursion on opaque structs like - // typedef struct xcb_connection_t xcb_connection_t; - if (nextItem.data() ==__item.data()) { - std::cerr << "** WARNING Bailing out recursion of " << __FUNCTION__ - << "() on " << qPrintable(__type.qualifiedName().join(QLatin1String("::"))) - << std::endl; - return otherType; - } - return resolveType(nextItem, combined, __scope); - } - - if (TemplateTypeAliasModelItem templateTypeAlias = qSharedPointerDynamicCast<_TemplateTypeAliasModelItem>(__item)) { - - TypeInfo combined = TypeInfo::combine(templateTypeAlias->type(), otherType); - // For the alias "template<typename T> using QList = QVector<T>" with - // other="QList<int>", replace the instantiations to obtain "QVector<int>". - auto aliasInstantiations = templateTypeAlias->type().instantiations(); - auto concreteInstantiations = otherType.instantiations(); - const int count = qMin(aliasInstantiations.size(), concreteInstantiations.size()); - for (int i = 0; i < count; ++i) - aliasInstantiations[i] = concreteInstantiations[i]; - combined.setInstantiations(aliasInstantiations); - const CodeModelItem nextItem = __scope->model()->findItem(combined.qualifiedName(), __scope); - if (!nextItem) - return combined; - return resolveType(nextItem, combined, __scope); - } - - return otherType; -} - -// Handler for clang::parseTemplateArgumentList() that populates -// TypeInfo::m_instantiations -class TypeInfoTemplateArgumentHandler -{ -public: - explicit TypeInfoTemplateArgumentHandler(TypeInfo *t) - { - m_parseStack.append(t); - } - - void operator()(int level, QStringView name) - { - if (level > m_parseStack.size()) { - Q_ASSERT(!top()->m_instantiations.isEmpty()); - m_parseStack.push(&top()->m_instantiations.back()); - } - while (level < m_parseStack.size()) - m_parseStack.pop(); - TypeInfo instantiation; - instantiation.setQualifiedName(qualifiedName(name)); - top()->addInstantiation(instantiation); - } - -private: - TypeInfo *top() const { return m_parseStack.back(); } - - static QStringList qualifiedName(QStringView name) - { - QStringList result; - const auto nameParts = name.split(u"::"); - result.reserve(nameParts.size()); - for (const auto &p : nameParts) - result.append(p.toString()); - return result; - } - - QStack<TypeInfo *> m_parseStack; -}; - -QPair<int, int> TypeInfo::parseTemplateArgumentList(const QString &l, int from) -{ - return clang::parseTemplateArgumentList(l, clang::TemplateArgumentHandler(TypeInfoTemplateArgumentHandler(this)), from); -} - -QString TypeInfo::toString() const -{ - QString tmp; - if (isConstant()) - tmp += QLatin1String("const "); - - if (isVolatile()) - tmp += QLatin1String("volatile "); - - tmp += m_qualifiedName.join(QLatin1String("::")); - - if (const int instantiationCount = m_instantiations.size()) { - tmp += QLatin1Char('<'); - for (int i = 0; i < instantiationCount; ++i) { - if (i) - tmp += QLatin1String(", "); - tmp += m_instantiations.at(i).toString(); - } - if (tmp.endsWith(QLatin1Char('>'))) - tmp += QLatin1Char(' '); - tmp += QLatin1Char('>'); - } - - for (Indirection i : m_indirections) - tmp.append(indirectionKeyword(i)); - - switch (referenceType()) { - case NoReference: - break; - case LValueReference: - tmp += QLatin1Char('&'); - break; - case RValueReference: - tmp += QLatin1String("&&"); - break; - } - - if (isFunctionPointer()) { - tmp += QLatin1String(" (*)("); - for (int i = 0; i < m_arguments.count(); ++i) { - if (i != 0) - tmp += QLatin1String(", "); - - tmp += m_arguments.at(i).toString(); - } - tmp += QLatin1Char(')'); - } - - for (const QString &elt : m_arrayElements) { - tmp += QLatin1Char('['); - tmp += elt; - tmp += QLatin1Char(']'); - } - - return tmp; -} - -bool TypeInfo::operator==(const TypeInfo &other) const -{ - if (arrayElements().count() != other.arrayElements().count()) - return false; - -#if defined (RXX_CHECK_ARRAY_ELEMENTS) // ### it'll break - for (int i = 0; i < arrayElements().count(); ++i) { - QString elt1 = arrayElements().at(i).trimmed(); - QString elt2 = other.arrayElements().at(i).trimmed(); - - if (elt1 != elt2) - return false; - } -#endif - - return flags == other.flags - && m_qualifiedName == other.m_qualifiedName - && (!m_functionPointer || m_arguments == other.m_arguments) - && m_instantiations == other.m_instantiations; -} - -QString TypeInfo::indirectionKeyword(Indirection i) -{ - return i == Indirection::Pointer - ? QStringLiteral("*") : QStringLiteral("*const"); -} - -static inline QString constQualifier() { return QStringLiteral("const"); } -static inline QString volatileQualifier() { return QStringLiteral("volatile"); } - -bool TypeInfo::stripLeadingConst(QString *s) -{ - return stripLeadingQualifier(constQualifier(), s); -} - -bool TypeInfo::stripLeadingVolatile(QString *s) -{ - return stripLeadingQualifier(volatileQualifier(), s); -} - -bool TypeInfo::stripLeadingQualifier(const QString &qualifier, QString *s) -{ - // "const int x" - const int qualifierSize = qualifier.size(); - if (s->size() < qualifierSize + 1 || !s->startsWith(qualifier) - || !s->at(qualifierSize).isSpace()) { - return false; - } - s->remove(0, qualifierSize + 1); - while (!s->isEmpty() && s->at(0).isSpace()) - s->remove(0, 1); - return true; -} - -// Strip all const/volatile/*/& -void TypeInfo::stripQualifiers(QString *s) -{ - stripLeadingConst(s); - stripLeadingVolatile(s); - while (s->endsWith(QLatin1Char('&')) || s->endsWith(QLatin1Char('*')) - || s->endsWith(QLatin1Char(' '))) { - s->chop(1); - } -} - -// Helper functionality to simplify a raw standard type as returned by -// clang_getCanonicalType() for g++ standard containers from -// "std::__cxx11::list<int, std::allocator<int> >" or -// "std::__1::list<int, std::allocator<int> >" -> "std::list<int>". - -bool TypeInfo::isStdType() const -{ - return m_qualifiedName.size() > 1 - && m_qualifiedName.constFirst() == QLatin1String("std"); -} - -static inline bool discardStdType(const QString &name) -{ - return name == QLatin1String("allocator") || name == QLatin1String("less"); -} - -void TypeInfo::simplifyStdType() -{ - if (isStdType()) { - if (m_qualifiedName.at(1).startsWith(QLatin1String("__"))) - m_qualifiedName.removeAt(1); - for (int t = m_instantiations.size() - 1; t >= 0; --t) { - if (m_instantiations.at(t).isStdType()) { - if (discardStdType(m_instantiations.at(t).m_qualifiedName.constLast())) - m_instantiations.removeAt(t); - else - m_instantiations[t].simplifyStdType(); - } - } - } -} - -void TypeInfo::formatTypeSystemSignature(QTextStream &str) const -{ - if (m_constant) - str << "const "; - str << m_qualifiedName.join(QLatin1String("::")); - switch (m_referenceType) { - case NoReference: - break; - case LValueReference: - str << '&'; - break; - case RValueReference: - str << "&&"; - break; - } - for (auto i : m_indirections) { - switch (i) { - case Indirection::Pointer: - str << '*'; - break; - case Indirection::ConstPointer: - str << "* const"; - break; - } - } -} - -#ifndef QT_NO_DEBUG_STREAM -template <class It> -void formatSequence(QDebug &d, It i1, It i2, const char *separator=", ") -{ - for (It i = i1; i != i2; ++i) { - if (i != i1) - d << separator; - d << *i; - } -} - -void TypeInfo::formatDebug(QDebug &d) const -{ - d << '"'; - formatSequence(d, m_qualifiedName.begin(), m_qualifiedName.end(), "\", \""); - d << '"'; - if (m_constant) - d << ", [const]"; - if (m_volatile) - d << ", [volatile]"; - if (!m_indirections.isEmpty()) { - d << ", indirections="; - for (auto i : m_indirections) - d << ' ' << TypeInfo::indirectionKeyword(i); - } - switch (m_referenceType) { - case NoReference: - break; - case LValueReference: - d << ", [ref]"; - break; - case RValueReference: - d << ", [rvalref]"; - break; - } - if (!m_instantiations.isEmpty()) { - d << ", template<"; - formatSequence(d, m_instantiations.begin(), m_instantiations.end()); - d << '>'; - } - if (m_functionPointer) { - d << ", function ptr("; - formatSequence(d, m_arguments.begin(), m_arguments.end()); - d << ')'; - } - if (!m_arrayElements.isEmpty()) { - d << ", array[" << m_arrayElements.size() << "]["; - formatSequence(d, m_arrayElements.begin(), m_arrayElements.end()); - d << ']'; - } -} - -QDebug operator<<(QDebug d, const TypeInfo &t) -{ - QDebugStateSaver s(d); - const int verbosity = d.verbosity(); - d.noquote(); - d.nospace(); - d << "TypeInfo("; - if (verbosity > 2) - t.formatDebug(d); - else - d << t.toString(); - d << ')'; - return d; -} -#endif // !QT_NO_DEBUG_STREAM - -// --------------------------------------------------------------------------- _CodeModelItem::_CodeModelItem(CodeModel *model, int kind) : m_model(model), m_kind(kind), @@ -612,6 +237,16 @@ SourceLocation _CodeModelItem::sourceLocation() const #ifndef QT_NO_DEBUG_STREAM template <class It> +void formatSequence(QDebug &d, It i1, It i2, const char *separator=", ") +{ + for (It i = i1; i != i2; ++i) { + if (i != i1) + d << separator; + d << *i; + } +} + +template <class It> static void formatPtrSequence(QDebug &d, It i1, It i2, const char *separator=", ") { for (It i = i1; i != i2; ++i) { diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.h b/sources/shiboken6/ApiExtractor/parser/codemodel.h index 13bc7cf36..e3ff4cf70 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel.h +++ b/sources/shiboken6/ApiExtractor/parser/codemodel.h @@ -34,6 +34,7 @@ #include "codemodel_fwd.h" #include "codemodel_enums.h" #include "enumvalue.h" +#include "typeinfo.h" #include <QtCore/QHash> #include <QtCore/QPair> @@ -97,157 +98,6 @@ private: QDebug operator<<(QDebug d, const CodeModel *m); #endif -class TypeInfo -{ - friend class TypeParser; -public: - using Indirections = QVector<Indirection>; - - TypeInfo() : flags(0), m_referenceType(NoReference) {} - - QStringList qualifiedName() const - { - return m_qualifiedName; - } - - void setQualifiedName(const QStringList &qualified_name) - { - m_qualifiedName = qualified_name; - } - - bool isVoid() const; - - bool isConstant() const - { - return m_constant; - } - - void setConstant(bool is) - { - m_constant = is; - } - - bool isVolatile() const - { - return m_volatile; - } - - void setVolatile(bool is) - { - m_volatile = is; - } - - ReferenceType referenceType() const { return m_referenceType; } - void setReferenceType(ReferenceType r) { m_referenceType = r; } - - Indirections indirectionsV() const { return m_indirections; } - void setIndirectionsV(const Indirections &i) { m_indirections = i; } - void addIndirection(Indirection i) { m_indirections.append(i); } - - // "Legacy", rename? - int indirections() const { return m_indirections.size(); } - - void setIndirections(int indirections) - { - m_indirections = Indirections(indirections, Indirection::Pointer); - } - - bool isFunctionPointer() const - { - return m_functionPointer; - } - void setFunctionPointer(bool is) - { - m_functionPointer = is; - } - - QStringList arrayElements() const - { - return m_arrayElements; - } - void setArrayElements(const QStringList &arrayElements) - { - m_arrayElements = arrayElements; - } - - void addArrayElement(const QString &a) { m_arrayElements.append(a); } - - QVector<TypeInfo> arguments() const { return m_arguments; } - - void setArguments(const QVector<TypeInfo> &arguments); - - void addArgument(const TypeInfo &arg) - { - m_arguments.append(arg); - } - - QVector<TypeInfo> instantiations() const { return m_instantiations; } - void setInstantiations(const QVector<TypeInfo> &i) { m_instantiations = i; } - void addInstantiation(const TypeInfo &i) { m_instantiations.append(i); } - void clearInstantiations() { m_instantiations.clear(); } - - bool isStdType() const; - - QPair<int, int> parseTemplateArgumentList(const QString &l, int from = 0); - - bool operator==(const TypeInfo &other) const; - - bool operator!=(const TypeInfo &other) const - { - return !(*this == other); - } - - // ### arrays and templates?? - - QString toString() const; - - static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs); - static TypeInfo resolveType(TypeInfo const &__type, const ScopeModelItem &__scope); - - void formatTypeSystemSignature(QTextStream &str) const; - -#ifndef QT_NO_DEBUG_STREAM - void formatDebug(QDebug &d) const; -#endif - - static QString indirectionKeyword(Indirection i); - - static bool stripLeadingConst(QString *s); - static bool stripLeadingVolatile(QString *s); - static bool stripLeadingQualifier(const QString &qualifier, QString *s); - static void stripQualifiers(QString *s); - - void simplifyStdType(); - -private: - friend class TypeInfoTemplateArgumentHandler; - - static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, const ScopeModelItem &__scope); - - QStringList m_qualifiedName; - QStringList m_arrayElements; - QVector<TypeInfo> m_arguments; - QVector<TypeInfo> m_instantiations; - Indirections m_indirections; - - union { - uint flags; - - struct { - uint m_constant: 1; - uint m_volatile: 1; - uint m_functionPointer: 1; - uint m_padding: 29; - }; - }; - - ReferenceType m_referenceType; -}; - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const TypeInfo &t); -#endif - class _CodeModelItem { Q_DISABLE_COPY(_CodeModelItem) diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp new file mode 100644 index 000000000..0765e9c9e --- /dev/null +++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp @@ -0,0 +1,413 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org> +** 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 "typeinfo.h" +#include "codemodel.h" + +#include <clangparser/clangutils.h> + +#include <QtCore/QDebug> +#include <QtCore/QStack> +#include <QtCore/QTextStream> + +#include <iostream> + +TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs) +{ + TypeInfo __result = __lhs; + + __result.setConstant(__result.isConstant() || __rhs.isConstant()); + __result.setVolatile(__result.isVolatile() || __rhs.isVolatile()); + if (__rhs.referenceType() > __result.referenceType()) + __result.setReferenceType(__rhs.referenceType()); + __result.m_indirections.append(__rhs.m_indirections); + __result.setArrayElements(__result.arrayElements() + __rhs.arrayElements()); + __result.m_instantiations.append(__rhs.m_instantiations); + + return __result; +} + +bool TypeInfo::isVoid() const +{ + return m_indirections.isEmpty() && m_referenceType == NoReference + && m_arguments.isEmpty() && m_arrayElements.isEmpty() + && m_instantiations.isEmpty() + && m_qualifiedName.size() == 1 + && m_qualifiedName.constFirst() == QLatin1String("void"); +} + +TypeInfo TypeInfo::resolveType(TypeInfo const &__type, const ScopeModelItem &__scope) +{ + CodeModel *__model = __scope->model(); + Q_ASSERT(__model != nullptr); + + return TypeInfo::resolveType(__model->findItem(__type.qualifiedName(), __scope), __type, __scope); +} + +TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, const ScopeModelItem &__scope) +{ + // Copy the type and replace with the proper qualified name. This + // only makes sence to do if we're actually getting a resolved + // type with a namespace. We only get this if the returned type + // has more than 2 entries in the qualified name... This test + // could be improved by returning if the type was found or not. + TypeInfo otherType(__type); + if (__item && __item->qualifiedName().size() > 1) { + otherType.setQualifiedName(__item->qualifiedName()); + } + + if (TypeDefModelItem __typedef = qSharedPointerDynamicCast<_TypeDefModelItem>(__item)) { + const TypeInfo combined = TypeInfo::combine(__typedef->type(), otherType); + const CodeModelItem nextItem = __scope->model()->findItem(combined.qualifiedName(), __scope); + if (!nextItem) + return combined; + // PYSIDE-362, prevent recursion on opaque structs like + // typedef struct xcb_connection_t xcb_connection_t; + if (nextItem.data() ==__item.data()) { + std::cerr << "** WARNING Bailing out recursion of " << __FUNCTION__ + << "() on " << qPrintable(__type.qualifiedName().join(QLatin1String("::"))) + << std::endl; + return otherType; + } + return resolveType(nextItem, combined, __scope); + } + + if (TemplateTypeAliasModelItem templateTypeAlias = qSharedPointerDynamicCast<_TemplateTypeAliasModelItem>(__item)) { + + TypeInfo combined = TypeInfo::combine(templateTypeAlias->type(), otherType); + // For the alias "template<typename T> using QList = QVector<T>" with + // other="QList<int>", replace the instantiations to obtain "QVector<int>". + auto aliasInstantiations = templateTypeAlias->type().instantiations(); + const auto &concreteInstantiations = otherType.instantiations(); + const int count = qMin(aliasInstantiations.size(), concreteInstantiations.size()); + for (int i = 0; i < count; ++i) + aliasInstantiations[i] = concreteInstantiations[i]; + combined.setInstantiations(aliasInstantiations); + const CodeModelItem nextItem = __scope->model()->findItem(combined.qualifiedName(), __scope); + if (!nextItem) + return combined; + return resolveType(nextItem, combined, __scope); + } + + return otherType; +} + +// Handler for clang::parseTemplateArgumentList() that populates +// TypeInfo::m_instantiations +class TypeInfoTemplateArgumentHandler +{ +public: + explicit TypeInfoTemplateArgumentHandler(TypeInfo *t) + { + m_parseStack.append(t); + } + + void operator()(int level, QStringView name) + { + if (level > m_parseStack.size()) { + Q_ASSERT(!top()->m_instantiations.isEmpty()); + m_parseStack.push(&top()->m_instantiations.back()); + } + while (level < m_parseStack.size()) + m_parseStack.pop(); + TypeInfo instantiation; + instantiation.setQualifiedName(qualifiedName(name)); + top()->addInstantiation(instantiation); + } + +private: + TypeInfo *top() const { return m_parseStack.back(); } + + static QStringList qualifiedName(QStringView name) + { + QStringList result; + const auto nameParts = name.split(u"::"); + result.reserve(nameParts.size()); + for (const auto &p : nameParts) + result.append(p.toString()); + return result; + } + + QStack<TypeInfo *> m_parseStack; +}; + +QPair<int, int> TypeInfo::parseTemplateArgumentList(const QString &l, int from) +{ + return clang::parseTemplateArgumentList(l, clang::TemplateArgumentHandler(TypeInfoTemplateArgumentHandler(this)), from); +} + +QString TypeInfo::toString() const +{ + QString tmp; + if (isConstant()) + tmp += QLatin1String("const "); + + if (isVolatile()) + tmp += QLatin1String("volatile "); + + tmp += m_qualifiedName.join(QLatin1String("::")); + + if (const int instantiationCount = m_instantiations.size()) { + tmp += QLatin1Char('<'); + for (int i = 0; i < instantiationCount; ++i) { + if (i) + tmp += QLatin1String(", "); + tmp += m_instantiations.at(i).toString(); + } + if (tmp.endsWith(QLatin1Char('>'))) + tmp += QLatin1Char(' '); + tmp += QLatin1Char('>'); + } + + for (Indirection i : m_indirections) + tmp.append(indirectionKeyword(i)); + + switch (referenceType()) { + case NoReference: + break; + case LValueReference: + tmp += QLatin1Char('&'); + break; + case RValueReference: + tmp += QLatin1String("&&"); + break; + } + + if (isFunctionPointer()) { + tmp += QLatin1String(" (*)("); + for (int i = 0; i < m_arguments.count(); ++i) { + if (i != 0) + tmp += QLatin1String(", "); + + tmp += m_arguments.at(i).toString(); + } + tmp += QLatin1Char(')'); + } + + for (const QString &elt : m_arrayElements) { + tmp += QLatin1Char('['); + tmp += elt; + tmp += QLatin1Char(']'); + } + + return tmp; +} + +bool TypeInfo::equals(const TypeInfo &other) const +{ + if (arrayElements().count() != other.arrayElements().count()) + return false; + +#if defined (RXX_CHECK_ARRAY_ELEMENTS) // ### it'll break + for (int i = 0; i < arrayElements().count(); ++i) { + QString elt1 = arrayElements().at(i).trimmed(); + QString elt2 = other.arrayElements().at(i).trimmed(); + + if (elt1 != elt2) + return false; + } +#endif + + return flags == other.flags + && m_qualifiedName == other.m_qualifiedName + && (!m_functionPointer || m_arguments == other.m_arguments) + && m_instantiations == other.m_instantiations; +} + +QString TypeInfo::indirectionKeyword(Indirection i) +{ + return i == Indirection::Pointer + ? QStringLiteral("*") : QStringLiteral("*const"); +} + +static inline QString constQualifier() { return QStringLiteral("const"); } +static inline QString volatileQualifier() { return QStringLiteral("volatile"); } + +bool TypeInfo::stripLeadingConst(QString *s) +{ + return stripLeadingQualifier(constQualifier(), s); +} + +bool TypeInfo::stripLeadingVolatile(QString *s) +{ + return stripLeadingQualifier(volatileQualifier(), s); +} + +bool TypeInfo::stripLeadingQualifier(const QString &qualifier, QString *s) +{ + // "const int x" + const int qualifierSize = qualifier.size(); + if (s->size() < qualifierSize + 1 || !s->startsWith(qualifier) + || !s->at(qualifierSize).isSpace()) { + return false; + } + s->remove(0, qualifierSize + 1); + while (!s->isEmpty() && s->at(0).isSpace()) + s->remove(0, 1); + return true; +} + +// Strip all const/volatile/*/& +void TypeInfo::stripQualifiers(QString *s) +{ + stripLeadingConst(s); + stripLeadingVolatile(s); + while (s->endsWith(QLatin1Char('&')) || s->endsWith(QLatin1Char('*')) + || s->endsWith(QLatin1Char(' '))) { + s->chop(1); + } +} + +// Helper functionality to simplify a raw standard type as returned by +// clang_getCanonicalType() for g++ standard containers from +// "std::__cxx11::list<int, std::allocator<int> >" or +// "std::__1::list<int, std::allocator<int> >" -> "std::list<int>". + +bool TypeInfo::isStdType() const +{ + return m_qualifiedName.size() > 1 + && m_qualifiedName.constFirst() == QLatin1String("std"); +} + +static inline bool discardStdType(const QString &name) +{ + return name == QLatin1String("allocator") || name == QLatin1String("less"); +} + +void TypeInfo::simplifyStdType() +{ + if (isStdType()) { + if (m_qualifiedName.at(1).startsWith(QLatin1String("__"))) + m_qualifiedName.removeAt(1); + for (int t = m_instantiations.size() - 1; t >= 0; --t) { + if (m_instantiations.at(t).isStdType()) { + if (discardStdType(m_instantiations.at(t).m_qualifiedName.constLast())) + m_instantiations.removeAt(t); + else + m_instantiations[t].simplifyStdType(); + } + } + } +} + +void TypeInfo::formatTypeSystemSignature(QTextStream &str) const +{ + if (m_constant) + str << "const "; + str << m_qualifiedName.join(QLatin1String("::")); + switch (m_referenceType) { + case NoReference: + break; + case LValueReference: + str << '&'; + break; + case RValueReference: + str << "&&"; + break; + } + for (auto i : m_indirections) { + switch (i) { + case Indirection::Pointer: + str << '*'; + break; + case Indirection::ConstPointer: + str << "* const"; + break; + } + } +} + +#ifndef QT_NO_DEBUG_STREAM +template <class It> +void formatSequence(QDebug &d, It i1, It i2, const char *separator=", ") +{ + for (It i = i1; i != i2; ++i) { + if (i != i1) + d << separator; + d << *i; + } +} + +void TypeInfo::formatDebug(QDebug &d) const +{ + d << '"'; + formatSequence(d, m_qualifiedName.begin(), m_qualifiedName.end(), "\", \""); + d << '"'; + if (m_constant) + d << ", [const]"; + if (m_volatile) + d << ", [volatile]"; + if (!m_indirections.isEmpty()) { + d << ", indirections="; + for (auto i : m_indirections) + d << ' ' << TypeInfo::indirectionKeyword(i); + } + switch (m_referenceType) { + case NoReference: + break; + case LValueReference: + d << ", [ref]"; + break; + case RValueReference: + d << ", [rvalref]"; + break; + } + if (!m_instantiations.isEmpty()) { + d << ", template<"; + formatSequence(d, m_instantiations.begin(), m_instantiations.end()); + d << '>'; + } + if (m_functionPointer) { + d << ", function ptr("; + formatSequence(d, m_arguments.begin(), m_arguments.end()); + d << ')'; + } + if (!m_arrayElements.isEmpty()) { + d << ", array[" << m_arrayElements.size() << "]["; + formatSequence(d, m_arrayElements.begin(), m_arrayElements.end()); + d << ']'; + } +} + +QDebug operator<<(QDebug d, const TypeInfo &t) +{ + QDebugStateSaver s(d); + const int verbosity = d.verbosity(); + d.noquote(); + d.nospace(); + d << "TypeInfo("; + if (verbosity > 2) + t.formatDebug(d); + else + d << t.toString(); + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.h b/sources/shiboken6/ApiExtractor/parser/typeinfo.h new file mode 100644 index 000000000..74987493d --- /dev/null +++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org> +** 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$ +** +****************************************************************************/ + +#ifndef TYPEINFO_H +#define TYPEINFO_H + +#include "codemodel_enums.h" +#include "codemodel_fwd.h" + +#include <QtCore/QString> +#include <QtCore/QStringList> + +QT_FORWARD_DECLARE_CLASS(QDebug) +QT_FORWARD_DECLARE_CLASS(QTextStream) + +class TypeInfo +{ + friend class TypeParser; +public: + using Indirections = QList<Indirection>; + using TypeInfoList = QList<TypeInfo>; + + TypeInfo() : flags(0), m_referenceType(NoReference) {} + + QStringList qualifiedName() const { return m_qualifiedName; } + void setQualifiedName(const QStringList &qualified_name) + { + m_qualifiedName = qualified_name; + } + + bool isVoid() const; + + bool isConstant() const { return m_constant; } + void setConstant(bool is) { m_constant = is; } + + bool isVolatile() const { return m_volatile; } + + void setVolatile(bool is) { m_volatile = is; } + + ReferenceType referenceType() const { return m_referenceType; } + void setReferenceType(ReferenceType r) { m_referenceType = r; } + + const Indirections &indirectionsV() const { return m_indirections; } + void setIndirectionsV(const Indirections &i) { m_indirections = i; } + void addIndirection(Indirection i) { m_indirections.append(i); } + + // "Legacy", rename? + int indirections() const { return m_indirections.size(); } + + void setIndirections(int indirections) + { + m_indirections = Indirections(indirections, Indirection::Pointer); + } + + bool isFunctionPointer() const { return m_functionPointer; } + void setFunctionPointer(bool is) { m_functionPointer = is; } + + const QStringList &arrayElements() const { return m_arrayElements; } + void setArrayElements(const QStringList &arrayElements) + { + m_arrayElements = arrayElements; + } + + void addArrayElement(const QString &a) { m_arrayElements.append(a); } + + const TypeInfoList &arguments() const { return m_arguments; } + void setArguments(const TypeInfoList &arguments); + + void addArgument(const TypeInfo &arg) + { + m_arguments.append(arg); + } + + const TypeInfoList &instantiations() const { return m_instantiations; } + void setInstantiations(const TypeInfoList &i) { m_instantiations = i; } + void addInstantiation(const TypeInfo &i) { m_instantiations.append(i); } + void clearInstantiations() { m_instantiations.clear(); } + + bool isStdType() const; + + QPair<int, int> parseTemplateArgumentList(const QString &l, int from = 0); + + bool equals(const TypeInfo &other) const; + + // ### arrays and templates?? + + QString toString() const; + + static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs); + static TypeInfo resolveType(TypeInfo const &__type, const ScopeModelItem &__scope); + + void formatTypeSystemSignature(QTextStream &str) const; + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const; +#endif + + static QString indirectionKeyword(Indirection i); + + static bool stripLeadingConst(QString *s); + static bool stripLeadingVolatile(QString *s); + static bool stripLeadingQualifier(const QString &qualifier, QString *s); + static void stripQualifiers(QString *s); + + void simplifyStdType(); + +private: + friend class TypeInfoTemplateArgumentHandler; + + static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, const ScopeModelItem &__scope); + + QStringList m_qualifiedName; + QStringList m_arrayElements; + QList<TypeInfo> m_arguments; + QList<TypeInfo> m_instantiations; + Indirections m_indirections; + + union { + uint flags; + + struct { + uint m_constant: 1; + uint m_volatile: 1; + uint m_functionPointer: 1; + uint m_padding: 29; + }; + }; + + ReferenceType m_referenceType; +}; + +inline bool operator==(const TypeInfo &t1, const TypeInfo &t2) +{ return t1.equals(t2); } + +inline bool operator!=(const TypeInfo &t1, const TypeInfo &t2) +{ return !t1.equals(t2); } + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const TypeInfo &t); +#endif + +#endif // TYPEINFO_H diff --git a/sources/shiboken6/ApiExtractor/typeparser.cpp b/sources/shiboken6/ApiExtractor/typeparser.cpp index c440fb66d..08063af48 100644 --- a/sources/shiboken6/ApiExtractor/typeparser.cpp +++ b/sources/shiboken6/ApiExtractor/typeparser.cpp @@ -27,7 +27,7 @@ ****************************************************************************/ #include "typeparser.h" -#include <codemodel.h> +#include <typeinfo.h> #include <QtCore/QDebug> #include <QtCore/QStack> diff --git a/sources/shiboken6/ApiExtractor/typeparser.h b/sources/shiboken6/ApiExtractor/typeparser.h index 3b538017a..2359da7b2 100644 --- a/sources/shiboken6/ApiExtractor/typeparser.h +++ b/sources/shiboken6/ApiExtractor/typeparser.h @@ -32,7 +32,6 @@ #include "parser/codemodel_enums.h" #include <QtCore/QString> -#include <QtCore/QVector> class TypeInfo; |