diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor')
215 files changed, 16847 insertions, 12250 deletions
diff --git a/sources/shiboken6/ApiExtractor/CMakeLists.txt b/sources/shiboken6/ApiExtractor/CMakeLists.txt index 040d85f54..7aa2fbd11 100644 --- a/sources/shiboken6/ApiExtractor/CMakeLists.txt +++ b/sources/shiboken6/ApiExtractor/CMakeLists.txt @@ -1,50 +1,88 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + project(apiextractor) -cmake_minimum_required(VERSION 3.16) -cmake_policy(VERSION 3.16) +cmake_minimum_required(VERSION 3.18) +cmake_policy(VERSION 3.18) set(CMAKE_AUTOMOC ON) set(apiextractor_SRC -apiextractor.cpp -apiextractorresult.cpp -abstractmetaargument.cpp -abstractmetabuilder.cpp -abstractmetaenum.cpp -abstractmetafield.cpp -abstractmetafunction.cpp -abstractmetatype.cpp -abstractmetalang.cpp -codesniphelpers.cpp -conditionalstreamreader.cpp -documentation.cpp -enclosingclassmixin.cpp -fileout.cpp -messages.cpp -modifications.cpp -propertyspec.cpp -reporthandler.cpp -sourcelocation.cpp -typeparser.cpp -typesystem.cpp -typesystemparser.cpp -include.cpp -typedatabase.cpp -textstream.cpp +abstractmetaargument.cpp abstractmetaargument.h +abstractmetabuilder.cpp abstractmetabuilder.h abstractmetabuilder_p.h +abstractmetabuilder_helpers.cpp +abstractmetaenum.cpp abstractmetaenum.h +abstractmetafield.cpp abstractmetafield.h +abstractmetafunction.cpp abstractmetafunction.h +abstractmetalang.cpp abstractmetalang.h abstractmetalang_helpers.h abstractmetalang_typedefs.h +abstractmetatype.cpp abstractmetatype.h +addedfunction.cpp addedfunction.h addedfunction_p.h +anystringview_helpers.cpp anystringview_helpers.h +apiextractor.cpp apiextractor.h apiextractorflags.h +apiextractorresult.cpp apiextractorresult.h +arraytypeentry.h +classdocumentation.cpp classdocumentation.h +codesnip.cpp codesnip.h +codesniphelpers.cpp codesniphelpers.h +complextypeentry.h +conditionalstreamreader.cpp conditionalstreamreader.h +configurabletypeentry.h +constantvaluetypeentry.h +containertypeentry.h +customconversion.cpp customconversion.h customconversion_typedefs.h +customtypenentry.h +debughelpers_p.h +dependency.h +documentation.cpp documentation.h +dotview.cpp dotview.h +enclosingclassmixin.cpp enclosingclassmixin.h +enumtypeentry.h +enumvaluetypeentry.h +exception.h +fileout.cpp fileout.h +flagstypeentry.h +functiontypeentry.h +graph.h +header_paths.h +include.cpp include.h +messages.cpp messages.h +modifications.cpp modifications.h modifications_typedefs.h +namespacetypeentry.h +objecttypeentry.h +optionsparser.cpp optionsparser.h +predefined_templates.cpp predefined_templates.h +primitivetypeentry.h +propertyspec.cpp propertyspec.h +pymethoddefentry.cpp pymethoddefentry.h +pythontypeentry.h +reporthandler.cpp reporthandler.h +smartpointertypeentry.h +sourcelocation.cpp sourcelocation.h +templateargumententry.h +textstream.cpp textstream.h +typedatabase.cpp typedatabase.h typedatabase_p.h typedatabase_typedefs.h +typedefentry.h +typeparser.cpp typeparser.h +typesystem.cpp typesystem.h typesystem_enums.h typesystem_typedefs.h +typesystemparser.cpp typesystemparser_p.h +usingmember.h +valuetypeentry.h +varargstypeentry.h +voidtypeentry.h +xmlutils.cpp xmlutils.h xmlutils_libxslt.h xmlutils_qt.h # Clang -clangparser/compilersupport.cpp -clangparser/clangparser.cpp -clangparser/clangbuilder.cpp -clangparser/clangdebugutils.cpp -clangparser/clangutils.cpp +clangparser/clangbuilder.cpp clangparser/clangbuilder.h +clangparser/clangdebugutils.cpp clangparser/clangdebugutils.h +clangparser/clangparser.cpp clangparser/clangparser.h +clangparser/clangutils.cpp clangparser/clangutils.h +clangparser/compilersupport.cpp clangparser/compilersupport.h # Old parser -parser/typeinfo.cpp -parser/codemodel.cpp -parser/enumvalue.cpp -xmlutils.cpp +parser/codemodel.cpp parser/codemodel.h parser/codemodel_fwd.h parser/codemodel_enums.h +parser/enumvalue.cpp parser/enumvalue.h +parser/typeinfo.cpp parser/typeinfo.h ) -find_package(Qt${QT_MAJOR_VERSION}Xml 6.0) find_package(LibXml2 2.6.32) find_package(LibXslt 1.1.19) @@ -56,7 +94,7 @@ endif() if(NOT HAS_LIBXSLT) set(DISABLE_DOCSTRINGS TRUE) message(WARNING - "Documentation will not be built due to missing dependency (no Qt5XmlPatterns found).") + "Documentation will not be built due to missing dependency (libxslt not found).") endif() # Export to parent scope so that generator/CMakeLists.txt gets it @@ -67,7 +105,7 @@ target_include_directories(apiextractor PRIVATE ${CLANG_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/parser) -target_link_libraries(apiextractor PUBLIC Qt${QT_MAJOR_VERSION}::Core) +target_link_libraries(apiextractor PUBLIC Qt::Core) target_link_libraries(apiextractor PRIVATE libclang) if (HAS_LIBXSLT) @@ -80,17 +118,20 @@ if (HAS_LIBXSLT) endif() if (NOT DISABLE_DOCSTRINGS) - target_sources(apiextractor PRIVATE docparser.cpp - doxygenparser.cpp - qtdocparser.cpp) + target_sources(apiextractor PRIVATE + docparser.cpp docparser.h + doxygenparser.cpp doxygenparser.h + qtdocparser.cpp qtdocparser.h) endif() -target_compile_definitions(apiextractor PRIVATE CMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}") +target_compile_definitions(apiextractor + PRIVATE CMAKE_CXX_COMPILER="${CMAKE_CXX_COMPILER}" + PRIVATE QT_LEAN_HEADERS=1) set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE) if (BUILD_TESTS) - find_package(Qt${QT_MAJOR_VERSION}Test 6.0 REQUIRED) + find_package(Qt6 REQUIRED COMPONENTS Test) set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/tests) enable_testing() add_subdirectory(tests) diff --git a/sources/shiboken6/ApiExtractor/abstractmetaargument.cpp b/sources/shiboken6/ApiExtractor/abstractmetaargument.cpp index 366fc00a1..05cebe10a 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetaargument.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetaargument.cpp @@ -1,37 +1,17 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "abstractmetaargument.h" +#include "abstractmetatype.h" #include "documentation.h" +#include "qtcompat.h" + #include <QtCore/QDebug> #include <QtCore/QSharedData> +using namespace Qt::StringLiterals; + class AbstractMetaArgumentData : public QSharedData { public: @@ -39,11 +19,13 @@ public: QString m_name; AbstractMetaType m_type; + AbstractMetaType m_modifiedType; bool m_hasName = false; Documentation m_doc; QString m_expression; QString m_originalExpression; int m_argumentIndex = 0; + bool m_modifiedRemoved = false; }; AbstractMetaArgument::AbstractMetaArgument() : d(new AbstractMetaArgumentData) @@ -56,9 +38,9 @@ AbstractMetaArgument::AbstractMetaArgument(const AbstractMetaArgument &) = defau AbstractMetaArgument &AbstractMetaArgument::operator=(const AbstractMetaArgument &) = default; -AbstractMetaArgument::AbstractMetaArgument(AbstractMetaArgument &&) = default; +AbstractMetaArgument::AbstractMetaArgument(AbstractMetaArgument &&) noexcept = default; -AbstractMetaArgument &AbstractMetaArgument::operator=(AbstractMetaArgument &&) = default; +AbstractMetaArgument &AbstractMetaArgument::operator=(AbstractMetaArgument &&) noexcept = default; const AbstractMetaType &AbstractMetaArgument::type() const { @@ -68,7 +50,34 @@ const AbstractMetaType &AbstractMetaArgument::type() const void AbstractMetaArgument::setType(const AbstractMetaType &type) { if (d->m_type != type) - d->m_type = type; + d->m_type = d->m_modifiedType = type; +} + +const AbstractMetaType &AbstractMetaArgument::modifiedType() const +{ + return d->m_modifiedType; +} + +bool AbstractMetaArgument::isTypeModified() const +{ + return modifiedType() != type(); +} + +bool AbstractMetaArgument::isModifiedRemoved() const +{ + return d->m_modifiedRemoved; +} + +void AbstractMetaArgument::setModifiedRemoved(bool v) +{ + if (d->m_modifiedRemoved != v) + d->m_modifiedRemoved = v; +} + +void AbstractMetaArgument::setModifiedType(const AbstractMetaType &type) +{ + if (d->m_modifiedType != type) + d->m_modifiedType = type; } QString AbstractMetaArgument::name() const @@ -144,9 +153,9 @@ bool AbstractMetaArgument::hasModifiedDefaultValueExpression() const QString AbstractMetaArgumentData::toString() const { - QString result = m_type.name() + QLatin1Char(' ') + m_name; + QString result = m_type.name() + u' ' + m_name; if (!m_expression.isEmpty()) - result += QLatin1String(" = ") + m_expression; + result += u" = "_s + m_expression; return result; } @@ -182,7 +191,7 @@ QDebug operator<<(QDebug d, const AbstractMetaArgument *aa) d.noquote(); d.nospace(); d << "AbstractMetaArgument("; - if (aa) + if (aa != nullptr) d << aa->toString(); else d << '0'; diff --git a/sources/shiboken6/ApiExtractor/abstractmetaargument.h b/sources/shiboken6/ApiExtractor/abstractmetaargument.h index b5fe22db7..38402e369 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetaargument.h +++ b/sources/shiboken6/ApiExtractor/abstractmetaargument.h @@ -1,43 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETAARGUMENT_H #define ABSTRACTMETAARGUMENT_H -#include "abstractmetalang_typedefs.h" -#include "abstractmetatype.h" -#include "typesystem_enums.h" -#include "typesystem_typedefs.h" - #include <QtCore/QSharedDataPointer> QT_FORWARD_DECLARE_CLASS(QDebug) +class AbstractMetaType; class AbstractMetaArgumentData; class Documentation; @@ -48,12 +19,17 @@ public: ~AbstractMetaArgument(); AbstractMetaArgument(const AbstractMetaArgument &); AbstractMetaArgument &operator=(const AbstractMetaArgument &); - AbstractMetaArgument(AbstractMetaArgument &&); - AbstractMetaArgument &operator=(AbstractMetaArgument &&); - + AbstractMetaArgument(AbstractMetaArgument &&) noexcept; + AbstractMetaArgument &operator=(AbstractMetaArgument &&) noexcept; const AbstractMetaType &type() const; void setType(const AbstractMetaType &type); + void setModifiedType(const AbstractMetaType &type); + const AbstractMetaType &modifiedType() const; + bool isTypeModified() const; + + bool isModifiedRemoved() const; + void setModifiedRemoved(bool v); QString name() const; void setName(const QString &name, bool realName = true); diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp index cac311626..89d636964 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp @@ -1,43 +1,34 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "abstractmetabuilder_p.h" +#include "abstractmetaargument.h" #include "abstractmetaenum.h" #include "abstractmetafield.h" #include "abstractmetafunction.h" +#include "abstractmetatype.h" +#include "addedfunction.h" #include "graph.h" +#include "debughelpers_p.h" #include "exception.h" #include "messages.h" #include "propertyspec.h" #include "reporthandler.h" #include "sourcelocation.h" #include "typedatabase.h" -#include "typesystem.h" +#include "enumtypeentry.h" +#include "enumvaluetypeentry.h" +#include "arraytypeentry.h" +#include "constantvaluetypeentry.h" +#include "containertypeentry.h" +#include "flagstypeentry.h" +#include "functiontypeentry.h" +#include "namespacetypeentry.h" +#include "primitivetypeentry.h" +#include "smartpointertypeentry.h" +#include "templateargumententry.h" +#include "typedefentry.h" +#include "typesystemtypeentry.h" #include "usingmember.h" #include "parser/codemodel.h" @@ -46,10 +37,13 @@ #include <clangparser/clangutils.h> #include <clangparser/compilersupport.h> +#include "qtcompat.h" + #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFile> #include <QtCore/QFileInfo> +#include <QtCore/QMetaObject> #include <QtCore/QQueue> #include <QtCore/QRegularExpression> #include <QtCore/QTemporaryFile> @@ -59,26 +53,51 @@ #include <algorithm> #include <memory> -static inline QString colonColon() { return QStringLiteral("::"); } +using namespace Qt::StringLiterals; static QString stripTemplateArgs(const QString &name) { - int pos = name.indexOf(QLatin1Char('<')); + const auto pos = name.indexOf(u'<'); return pos < 0 ? name : name.left(pos); } -bool AbstractMetaBuilderPrivate::m_useGlobalHeader = false; +static void fixArgumentIndexes(AbstractMetaArgumentList *list) +{ + for (qsizetype i = 0, size = list->size(); i < size; ++i) + (*list)[i].setArgumentIndex(i); +} -AbstractMetaBuilderPrivate::AbstractMetaBuilderPrivate() : - m_logDirectory(QLatin1String(".") + QDir::separator()) +bool operator<(const RejectEntry &re1, const RejectEntry &re2) +{ + return re1.reason != re2.reason + ? (re1.reason < re2.reason) : (re1.sortkey < re2.sortkey); +} + +QTextStream &operator<<(QTextStream &str, const RejectEntry &re) +{ + str << re.signature; + if (!re.message.isEmpty()) + str << ": " << re.message; + return str; +} + +static void applyCachedFunctionModifications(AbstractMetaFunction *metaFunction, + const FunctionModificationList &functionMods) { + for (const FunctionModification &mod : functionMods) { + if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) + metaFunction->setExceptionHandlingModification(mod.exceptionHandling()); + if (mod.allowThread() != TypeSystem::AllowThread::Unspecified) + metaFunction->setAllowThreadModification(mod.allowThread()); + } } -AbstractMetaBuilderPrivate::~AbstractMetaBuilderPrivate() +bool AbstractMetaBuilderPrivate::m_useGlobalHeader = false; +bool AbstractMetaBuilderPrivate::m_codeModelTestMode = false; + +AbstractMetaBuilderPrivate::AbstractMetaBuilderPrivate() : + m_logDirectory(u"."_s + QDir::separator()) { - qDeleteAll(m_templates); - qDeleteAll(m_smartPointers); - qDeleteAll(m_metaClasses); } AbstractMetaBuilder::AbstractMetaBuilder() : d(new AbstractMetaBuilderPrivate) @@ -96,16 +115,37 @@ const AbstractMetaClassList &AbstractMetaBuilder::classes() const return d->m_metaClasses; } +AbstractMetaClassList AbstractMetaBuilder::takeClasses() +{ + AbstractMetaClassList result; + qSwap(result, d->m_metaClasses); + return result; +} + const AbstractMetaClassList &AbstractMetaBuilder::templates() const { return d->m_templates; } +AbstractMetaClassList AbstractMetaBuilder::takeTemplates() +{ + AbstractMetaClassList result; + qSwap(result, d->m_templates); + return result; +} + const AbstractMetaClassList &AbstractMetaBuilder::smartPointers() const { return d->m_smartPointers; } +AbstractMetaClassList AbstractMetaBuilder::takeSmartPointers() +{ + AbstractMetaClassList result; + qSwap(result, d->m_smartPointers); + return result; +} + const AbstractMetaFunctionCList &AbstractMetaBuilder::globalFunctions() const { return d->m_globalFunctions; @@ -116,36 +156,41 @@ const AbstractMetaEnumList &AbstractMetaBuilder::globalEnums() const return d->m_globalEnums; } -const QHash<const TypeEntry *, AbstractMetaEnum> &AbstractMetaBuilder::typeEntryToEnumsHash() const +const QHash<TypeEntryCPtr, AbstractMetaEnum> &AbstractMetaBuilder::typeEntryToEnumsHash() const { return d->m_enums; } -void AbstractMetaBuilderPrivate::checkFunctionModifications() +const QMultiHash<QString, QString> &AbstractMetaBuilder::typedefTargetToName() const +{ + return d->m_typedefTargetToName; +} + +void AbstractMetaBuilderPrivate::checkFunctionModifications() const { const auto &entries = TypeDatabase::instance()->entries(); for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) { - const TypeEntry *entry = it.value(); + TypeEntryCPtr entry = it.value(); if (!entry) continue; if (!entry->isComplex() || !entry->generateCode()) continue; - auto centry = static_cast<const ComplexTypeEntry *>(entry); + auto centry = std::static_pointer_cast<const ComplexTypeEntry>(entry); if (!centry->generateCode()) continue; FunctionModificationList modifications = centry->functionModifications(); - for (const FunctionModification &modification : qAsConst(modifications)) { + for (const FunctionModification &modification : std::as_const(modifications)) { QString signature = modification.signature(); QString name = signature.trimmed(); - name.truncate(name.indexOf(QLatin1Char('('))); + name.truncate(name.indexOf(u'(')); - AbstractMetaClass *clazz = AbstractMetaClass::findClass(m_metaClasses, centry); + const auto clazz = AbstractMetaClass::findClass(m_metaClasses, centry); if (!clazz) continue; @@ -153,13 +198,14 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() QStringList possibleSignatures; for (const auto &function : clazz->functions()) { if (function->implementingClass() == clazz - && modification.matches(function->minimalSignature())) { + && modification.matches(function->modificationSignatures())) { found = true; break; } if (function->originalName() == name) { - possibleSignatures.append(function->minimalSignature() + QLatin1String(" in ") + const QString signatures = function->modificationSignatures().join(u'/'); + possibleSignatures.append(signatures + u" in "_s + function->implementingClass()->name()); } } @@ -174,14 +220,14 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() } } -AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument, - const AbstractMetaClass *currentClass) +AbstractMetaClassPtr AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument, + const AbstractMetaClassCPtr ¤tClass) { - AbstractMetaClass *returned = nullptr; + AbstractMetaClassPtr returned; auto type = translateType(argument->type(), currentClass); if (!type.has_value()) return returned; - const TypeEntry *entry = type->typeEntry(); + TypeEntryCPtr entry = type->typeEntry(); if (entry && entry->isComplex()) returned = AbstractMetaClass::findClass(m_metaClasses, entry); return returned; @@ -191,18 +237,20 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(const ArgumentMod * Checks the argument of a hash function and flags the type if it is a complex type */ void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &function_item, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { + if (function_item->isDeleted()) + return; ArgumentList arguments = function_item->arguments(); - if (arguments.size() == 1) { - if (AbstractMetaClass *cls = argumentToClass(arguments.at(0), currentClass)) - cls->setHasHashFunction(true); + if (arguments.size() >= 1) { // (Class, Hash seed). + if (AbstractMetaClassPtr cls = argumentToClass(arguments.at(0), currentClass)) + cls->setHashFunction(function_item->name()); } } void AbstractMetaBuilderPrivate::registerToStringCapabilityIn(const NamespaceModelItem &nsItem) { - const FunctionList &streamOps = nsItem->findFunctions(QLatin1String("operator<<")); + const FunctionList &streamOps = nsItem->findFunctions("operator<<"); for (const FunctionModelItem &item : streamOps) registerToStringCapability(item, nullptr); for (const NamespaceModelItem &ni : nsItem->namespaces()) @@ -214,13 +262,13 @@ void AbstractMetaBuilderPrivate::registerToStringCapabilityIn(const NamespaceMod */ void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelItem &function_item, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { ArgumentList arguments = function_item->arguments(); if (arguments.size() == 2) { - if (arguments.at(0)->type().toString() == QLatin1String("QDebug")) { + if (arguments.at(0)->type().toString() == u"QDebug") { const ArgumentModelItem &arg = arguments.at(1); - if (AbstractMetaClass *cls = argumentToClass(arg, currentClass)) { + if (AbstractMetaClassPtr cls = argumentToClass(arg, currentClass)) { if (arg->type().indirections() < 2) cls->setToStringCapability(true, int(arg->type().indirections())); } @@ -229,27 +277,27 @@ void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelI } void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelItem &item, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { if (item->accessPolicy() != Access::Public) return; - ArgumentList arguments = item->arguments(); + const ArgumentList &itemArguments = item->arguments(); bool firstArgumentIsSelf = true; bool unaryOperator = false; - auto baseoperandClass = argumentToClass(arguments.at(0), currentClass); + auto baseoperandClass = argumentToClass(itemArguments.at(0), currentClass); - if (arguments.size() == 1) { + if (itemArguments.size() == 1) { unaryOperator = true; } else if (!baseoperandClass || !baseoperandClass->typeEntry()->generateCode()) { - baseoperandClass = argumentToClass(arguments.at(1), currentClass); + baseoperandClass = argumentToClass(itemArguments.at(1), currentClass); firstArgumentIsSelf = false; } else { auto type = translateType(item->type(), currentClass); - const TypeEntry *retType = type.has_value() ? type->typeEntry() : nullptr; - AbstractMetaClass *otherArgClass = argumentToClass(arguments.at(1), currentClass); + const auto retType = type.has_value() ? type->typeEntry() : TypeEntryCPtr{}; + const auto otherArgClass = argumentToClass(itemArguments.at(1), currentClass); if (otherArgClass && retType && (retType->isValue() || retType->isObject()) && retType != baseoperandClass->typeEntry() @@ -258,42 +306,60 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte firstArgumentIsSelf = false; } } + if (!baseoperandClass) { + rejectFunction(item, currentClass, AbstractMetaBuilder::UnmatchedOperator, + u"base operand class not found."_s); + return; + } - if (baseoperandClass) { - AbstractMetaFunction *metaFunction = traverseFunction(item, baseoperandClass); - if (metaFunction) { - // Strip away first argument, since that is the containing object - AbstractMetaArgumentList arguments = metaFunction->arguments(); - if (firstArgumentIsSelf || unaryOperator) { - AbstractMetaArgument first = arguments.takeFirst(); - if (!unaryOperator && first.type().indirections()) - metaFunction->setPointerOperator(true); - metaFunction->setArguments(arguments); - } else { - // If the operator method is not unary and the first operator is - // not of the same type of its owning class we suppose that it - // must be an reverse operator (e.g. CLASS::operator(TYPE, CLASS)). - // All operator overloads that operate over a class are already - // being added as member functions of that class by the API Extractor. - AbstractMetaArgument last = arguments.takeLast(); - if (last.type().indirections()) - metaFunction->setPointerOperator(true); - - metaFunction->setArguments(arguments); - metaFunction->setReverseOperator(true); - } - metaFunction->setAccess(Access::Public); - setupFunctionDefaults(metaFunction, baseoperandClass); - baseoperandClass->addFunction(AbstractMetaFunctionCPtr(metaFunction)); - Q_ASSERT(!metaFunction->wasPrivate()); - } else { - delete metaFunction; - } + if (item->isSpaceshipOperator() && !item->isDeleted()) { + AbstractMetaClass::addSynthesizedComparisonOperators(baseoperandClass); + return; } + + AbstractMetaFunction *metaFunction = traverseFunction(item, baseoperandClass); + if (metaFunction == nullptr) + return; + + auto flags = metaFunction->flags(); + // Strip away first argument, since that is the containing object + AbstractMetaArgumentList arguments = metaFunction->arguments(); + if (firstArgumentIsSelf || unaryOperator) { + AbstractMetaArgument first = arguments.takeFirst(); + fixArgumentIndexes(&arguments); + if (!unaryOperator && first.type().indirections()) + metaFunction->setPointerOperator(true); + metaFunction->setArguments(arguments); + flags.setFlag(AbstractMetaFunction::Flag::OperatorLeadingClassArgumentRemoved); + if (first.type().passByValue()) + flags.setFlag(AbstractMetaFunction::Flag::OperatorClassArgumentByValue); + } else { + // If the operator method is not unary and the first operator is + // not of the same type of its owning class we suppose that it + // must be an reverse operator (e.g. CLASS::operator(TYPE, CLASS)). + // All operator overloads that operate over a class are already + // being added as member functions of that class by the API Extractor. + AbstractMetaArgument last = arguments.takeLast(); + if (last.type().indirections()) + metaFunction->setPointerOperator(true); + metaFunction->setArguments(arguments); + metaFunction->setReverseOperator(true); + flags.setFlag(AbstractMetaFunction::Flag::OperatorTrailingClassArgumentRemoved); + if (last.type().passByValue()) + flags.setFlag(AbstractMetaFunction::Flag::OperatorClassArgumentByValue); + } + metaFunction->setFlags(flags); + metaFunction->setAccess(Access::Public); + AbstractMetaClass::addFunction(baseoperandClass, AbstractMetaFunctionCPtr(metaFunction)); + if (!metaFunction->arguments().isEmpty()) { + const auto include = metaFunction->arguments().constFirst().type().typeEntry()->include(); + baseoperandClass->typeEntry()->addArgumentInclude(include); + } + Q_ASSERT(!metaFunction->wasPrivate()); } bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem &item, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { ArgumentList itemArguments = item->arguments(); if (itemArguments.size() != 2 || item->accessPolicy() != Access::Public) @@ -310,21 +376,24 @@ bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem return false; // Strip first argument, since that is the containing object - AbstractMetaArgumentList arguments = streamFunction->arguments(); - if (!streamClass->typeEntry()->generateCode()) - arguments.takeLast(); - else - arguments.takeFirst(); + AbstractMetaArgumentList arguments = streamFunction->arguments(); + if (!streamClass->typeEntry()->generateCode()) { + arguments.takeLast(); + } else { + arguments.takeFirst(); + fixArgumentIndexes(&arguments); + } streamFunction->setArguments(arguments); - *streamFunction += AbstractMetaFunction::FinalInTargetLang; streamFunction->setAccess(Access::Public); - AbstractMetaClass *funcClass; + AbstractMetaClassPtr funcClass; if (!streamClass->typeEntry()->generateCode()) { - AbstractMetaArgumentList reverseArgs = reverseList(streamFunction->arguments()); + AbstractMetaArgumentList reverseArgs = streamFunction->arguments(); + std::reverse(reverseArgs.begin(), reverseArgs.end()); + fixArgumentIndexes(&reverseArgs); streamFunction->setArguments(reverseArgs); streamFunction->setReverseOperator(true); funcClass = streamedClass; @@ -332,19 +401,19 @@ bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem funcClass = streamClass; } - setupFunctionDefaults(streamFunction, funcClass); - funcClass->addFunction(AbstractMetaFunctionCPtr(streamFunction)); + AbstractMetaClass::addFunction(funcClass, AbstractMetaFunctionCPtr(streamFunction)); + auto funcTe = funcClass->typeEntry(); if (funcClass == streamClass) - funcClass->typeEntry()->addExtraInclude(streamedClass->typeEntry()->include()); + funcTe->addArgumentInclude(streamedClass->typeEntry()->include()); else - funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include()); + funcTe->addArgumentInclude(streamClass->typeEntry()->include()); return true; } static bool metaEnumLessThan(const AbstractMetaEnum &e1, const AbstractMetaEnum &e2) { return e1.fullName() < e2.fullName(); } -static bool metaClassLessThan(const AbstractMetaClass *c1, const AbstractMetaClass *c2) +static bool metaClassLessThan(const AbstractMetaClassCPtr &c1, const AbstractMetaClassCPtr &c2) { return c1->fullName() < c2->fullName(); } static bool metaFunctionLessThan(const AbstractMetaFunctionCPtr &f1, const AbstractMetaFunctionCPtr &f2) @@ -357,8 +426,8 @@ void AbstractMetaBuilderPrivate::sortLists() // this is a temporary solution before new type revision implementation // We need move QMetaObject register before QObject. Dependencies additionalDependencies; - if (auto qObjectClass = AbstractMetaClass::findClass(m_metaClasses, QStringLiteral("QObject"))) { - if (auto qMetaObjectClass = AbstractMetaClass::findClass(m_metaClasses, QStringLiteral("QMetaObject"))) { + if (auto qObjectClass = AbstractMetaClass::findClass(m_metaClasses, "QObject")) { + if (auto qMetaObjectClass = AbstractMetaClass::findClass(m_metaClasses, "QMetaObject")) { Dependency dependency; dependency.parent = qMetaObjectClass; dependency.child = qObjectClass; @@ -367,7 +436,7 @@ void AbstractMetaBuilderPrivate::sortLists() } m_metaClasses = classesTopologicalSorted(m_metaClasses, additionalDependencies); - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) + for (const auto &cls : std::as_const(m_metaClasses)) cls->sortFunctions(); // Ensure that indexes are in alphabetical order, roughly, except @@ -384,7 +453,7 @@ FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments, unsigned clangFlags) { clang::Builder builder; - builder.setSystemIncludes(TypeDatabase::instance()->systemIncludes()); + builder.setForceProcessSystemIncludes(TypeDatabase::instance()->forceProcessSystemIncludes()); if (addCompilerSupportArguments) { if (level == LanguageLevel::Default) level = clang::emulatedCompilerLanguageLevel(); @@ -395,18 +464,35 @@ FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments, clangFlags, builder) ? builder.dom() : FileModelItem(); const clang::BaseVisitor::Diagnostics &diagnostics = builder.diagnostics(); - if (const int diagnosticsCount = diagnostics.size()) { + if (const auto diagnosticsCount = diagnostics.size()) { QDebug d = qWarning(); d.nospace(); d.noquote(); d << "Clang: " << diagnosticsCount << " diagnostic messages:\n"; - for (int i = 0; i < diagnosticsCount; ++i) + for (qsizetype i = 0; i < diagnosticsCount; ++i) d << " " << diagnostics.at(i) << '\n'; } return result; } -void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) +// List of candidates for a mismatched added global function. +static QStringList functionCandidates(const AbstractMetaFunctionCList &list, + const QString &signature) +{ + QString name = signature; + const auto parenPos = name.indexOf(u'('); + if (parenPos > 0) + name.truncate(parenPos); + QStringList result; + for (const auto &func : list) { + if (name == func->name()) + result += func->minimalSignature(); + } + return result; +} + +void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, + ApiExtractorFlags flags) { const TypeDatabase *types = TypeDatabase::instance(); @@ -415,18 +501,18 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) // Start the generation... const ClassList &typeValues = dom->classes(); - ReportHandler::startProgress("Generating class model (" - + QByteArray::number(typeValues.size()) + ")..."); + ReportHandler::startProgress("Generated class model (" + + QByteArray::number(typeValues.size()) + ")."); for (const ClassModelItem &item : typeValues) { - if (AbstractMetaClass *cls = traverseClass(dom, item, nullptr)) - addAbstractMetaClass(cls, item.data()); + if (const auto cls = traverseClass(dom, item, nullptr)) + addAbstractMetaClass(cls, item.get()); } // We need to know all global enums const EnumList &enums = dom->enums(); - ReportHandler::startProgress("Generating enum model (" - + QByteArray::number(enums.size()) + ")..."); + ReportHandler::startProgress("Generated enum model (" + + QByteArray::number(enums.size()) + ")."); for (const EnumModelItem &item : enums) { auto metaEnum = traverseEnum(item, nullptr, QSet<QString>()); if (metaEnum.has_value()) { @@ -436,19 +522,19 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } const auto &namespaceTypeValues = dom->namespaces(); - ReportHandler::startProgress("Generating namespace model (" - + QByteArray::number(namespaceTypeValues.size()) + ")..."); + ReportHandler::startProgress("Generated namespace model (" + + QByteArray::number(namespaceTypeValues.size()) + ")."); for (const NamespaceModelItem &item : namespaceTypeValues) traverseNamespace(dom, item); // Go through all typedefs to see if we have defined any // specific typedefs to be used as classes. const TypeDefList typeDefs = dom->typeDefs(); - ReportHandler::startProgress("Resolving typedefs (" - + QByteArray::number(typeDefs.size()) + ")..."); + ReportHandler::startProgress("Resolved typedefs (" + + QByteArray::number(typeDefs.size()) + ")."); for (const TypeDefModelItem &typeDef : typeDefs) { - if (AbstractMetaClass *cls = traverseTypeDef(dom, typeDef, nullptr)) - addAbstractMetaClass(cls, typeDef.data()); + if (const auto cls = traverseTypeDef(dom, typeDef, nullptr)) + addAbstractMetaClass(cls, typeDef.get()); } traverseTypesystemTypedefs(); @@ -462,10 +548,10 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) // Global functions const FunctionList &functions = dom->functions(); for (const FunctionModelItem &func : functions) { - if (func->accessPolicy() != Access::Public || func->name().startsWith(QLatin1String("operator"))) + if (func->accessPolicy() != Access::Public || func->name().startsWith(u"operator")) continue; - FunctionTypeEntry *funcEntry = types->findFunctionType(func->name()); + FunctionTypeEntryPtr funcEntry = types->findFunctionType(func->name()); if (!funcEntry || !funcEntry->generateCode()) continue; @@ -479,14 +565,15 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) metaFunc->setTypeEntry(funcEntry); applyFunctionModifications(metaFunc); + metaFunc->applyTypeModifications(); setInclude(funcEntry, func->fileName()); m_globalFunctions << metaFuncPtr; } - ReportHandler::startProgress("Fixing class inheritance..."); - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { + ReportHandler::startProgress("Fixed class inheritance."); + for (const auto &cls : std::as_const(m_metaClasses)) { if (cls->needsInheritanceSetup()) { setupInheritance(cls); traverseUsingMembers(cls); @@ -498,22 +585,28 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } } - ReportHandler::startProgress("Detecting inconsistencies in class model..."); - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { - cls->fixFunctions(); + ReportHandler::startProgress("Checked for inconsistencies in class model."); + for (const auto &cls : std::as_const(m_metaClasses)) { + AbstractMetaClass::fixFunctions(cls); if (cls->canAddDefaultConstructor()) - cls->addDefaultConstructor(); + AbstractMetaClass::addDefaultConstructor(cls); if (cls->canAddDefaultCopyConstructor()) - cls->addDefaultCopyConstructor(); + AbstractMetaClass::addDefaultCopyConstructor(cls); + + const bool avoidProtectedHack = flags.testFlag(ApiExtractorFlag::AvoidProtectedHack); + const bool vco = + AbstractMetaClass::determineValueTypeWithCopyConstructorOnly(cls, avoidProtectedHack); + cls->setValueTypeWithCopyConstructorOnly(vco); + cls->typeEntry()->setValueTypeWithCopyConstructorOnly(vco); } const auto &allEntries = types->entries(); - ReportHandler::startProgress("Detecting inconsistencies in typesystem (" - + QByteArray::number(allEntries.size()) + ")..."); + ReportHandler::startProgress("Checked for inconsistencies in typesystem (" + + QByteArray::number(allEntries.size()) + ")."); for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) { - TypeEntry *entry = it.value(); + const TypeEntryPtr &entry = it.value(); if (!entry->isPrimitive()) { if ((entry->isValue() || entry->isObject()) && !types->shouldDropTypeEntry(entry->qualifiedCppName()) @@ -523,25 +616,27 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) && !AbstractMetaClass::findClass(m_metaClasses, entry)) { qCWarning(lcShiboken, "%s", qPrintable(msgTypeNotDefined(entry))); } else if (entry->generateCode() && entry->type() == TypeEntry::FunctionType) { - auto fte = static_cast<const FunctionTypeEntry *>(entry); + auto fte = std::static_pointer_cast<const FunctionTypeEntry>(entry); const QStringList &signatures = fte->signatures(); for (const QString &signature : signatures) { bool ok = false; - for (const auto &func : qAsConst(m_globalFunctions)) { + for (const auto &func : std::as_const(m_globalFunctions)) { if (signature == func->minimalSignature()) { ok = true; break; } } if (!ok) { + const QStringList candidates = functionCandidates(m_globalFunctions, + signatures.constFirst()); qCWarning(lcShiboken, "%s", - qPrintable(msgGlobalFunctionNotDefined(fte, signature))); + qPrintable(msgGlobalFunctionNotDefined(fte, signature, candidates))); } } } else if (entry->isEnum() && entry->generateCode()) { - auto enumEntry = static_cast<const EnumTypeEntry *>(entry); - AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, - enumEntry->parent()); + const auto enumEntry = std::static_pointer_cast<const EnumTypeEntry>(entry); + const auto cls = AbstractMetaClass::findClass(m_metaClasses, + enumEntry->parent()); const bool enumFound = cls ? cls->findEnum(entry->targetLangEntryName()).has_value() @@ -558,7 +653,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } { - const FunctionList &hashFunctions = dom->findFunctions(QLatin1String("qHash")); + const FunctionList &hashFunctions = dom->findFunctions("qHash"); for (const FunctionModelItem &item : hashFunctions) registerHashFunction(item, nullptr); } @@ -581,16 +676,15 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } } - ReportHandler::startProgress("Checking inconsistencies in function modifications..."); + ReportHandler::startProgress("Checked for inconsistencies in function modifications."); checkFunctionModifications(); - ReportHandler::startProgress("Writing log files..."); + ReportHandler::startProgress("Wrote log files."); - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { + for (const auto &cls : std::as_const(m_metaClasses)) { // setupEquals(cls); // setupComparable(cls); - setupClonable(cls); setupExternalConversion(cls); // sort all inner classes topologically @@ -600,6 +694,8 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) cls->setInnerClasses(classesTopologicalSorted(cls->innerClasses())); } + fixSmartPointers(); + dumpLog(); sortLists(); @@ -612,25 +708,29 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) throw Exception(errorMessage); } - m_itemToClass.clear(); - m_classToItem.clear(); - m_typeSystemTypeDefs.clear(); + if (!m_codeModelTestMode) { + m_itemToClass.clear(); + m_classToItem.clear(); + m_typeSystemTypeDefs.clear(); + m_scopes.clear(); + } ReportHandler::endProgress(); } bool AbstractMetaBuilder::build(const QByteArrayList &arguments, + ApiExtractorFlags apiExtractorFlags, bool addCompilerSupportArguments, LanguageLevel level, unsigned clangFlags) { const FileModelItem dom = d->buildDom(arguments, addCompilerSupportArguments, level, clangFlags); - if (dom.isNull()) + if (!dom) return false; if (ReportHandler::isDebug(ReportHandler::MediumDebug)) - qCDebug(lcShiboken) << dom.data(); - d->traverseDom(dom); + qCDebug(lcShiboken) << dom.get(); + d->traverseDom(dom, apiExtractorFlags); return true; } @@ -642,7 +742,7 @@ void AbstractMetaBuilder::setLogDirectory(const QString &logDir) d->m_logDirectory.append(QDir::separator()); } -void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls, +void AbstractMetaBuilderPrivate::addAbstractMetaClass(const AbstractMetaClassPtr &cls, const _CodeModelItem *item) { m_itemToClass.insert(item, cls); @@ -656,23 +756,27 @@ void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls, } } -AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom, - const NamespaceModelItem &namespaceItem) +AbstractMetaClassPtr + AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom, + const NamespaceModelItem &namespaceItem) { - QString namespaceName = currentScope()->qualifiedName().join(colonColon()); + QString namespaceName = currentScope()->qualifiedName().join(u"::"_s); if (!namespaceName.isEmpty()) - namespaceName.append(colonColon()); + namespaceName.append(u"::"_s); namespaceName.append(namespaceItem->name()); if (TypeDatabase::instance()->isClassRejected(namespaceName)) { - m_rejectedClasses.insert(namespaceName, AbstractMetaBuilder::GenerationDisabled); - return nullptr; + m_rejectedClasses.insert({AbstractMetaBuilder::GenerationDisabled, + namespaceName, namespaceName, QString{}}); + return {}; } auto type = TypeDatabase::instance()->findNamespaceType(namespaceName, namespaceItem->fileName()); if (!type) { - qCWarning(lcShiboken, "%s", - qPrintable(msgNamespaceNoTypeEntry(namespaceItem, namespaceName))); + const QString rejectReason = msgNamespaceNoTypeEntry(namespaceItem, namespaceName); + qCWarning(lcShiboken, "%s", qPrintable(rejectReason)); + m_rejectedClasses.insert({AbstractMetaBuilder::GenerationDisabled, + namespaceName, namespaceName, rejectReason}); return nullptr; } @@ -682,22 +786,22 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel } // Continue populating namespace? - AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, type); + AbstractMetaClassPtr metaClass = AbstractMetaClass::findClass(m_metaClasses, type); if (!metaClass) { - metaClass = new AbstractMetaClass; + metaClass.reset(new AbstractMetaClass); metaClass->setTypeEntry(type); - addAbstractMetaClass(metaClass, namespaceItem.data()); + addAbstractMetaClass(metaClass, namespaceItem.get()); if (auto extendsType = type->extends()) { - AbstractMetaClass *extended = AbstractMetaClass::findClass(m_metaClasses, extendsType); + const auto extended = AbstractMetaClass::findClass(m_metaClasses, extendsType); if (!extended) { qCWarning(lcShiboken, "%s", qPrintable(msgNamespaceToBeExtendedNotFound(extendsType->name(), extendsType->targetLangPackage()))); - return nullptr; + return {}; } metaClass->setExtendedNamespace(extended); } } else { - m_itemToClass.insert(namespaceItem.data(), metaClass); + m_itemToClass.insert(namespaceItem.get(), metaClass); } traverseEnums(namespaceItem, metaClass, namespaceItem->enumsDeclarations()); @@ -706,11 +810,11 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel const ClassList &classes = namespaceItem->classes(); for (const ClassModelItem &cls : classes) { - AbstractMetaClass *mjc = traverseClass(dom, cls, metaClass); + const auto mjc = traverseClass(dom, cls, metaClass); if (mjc) { metaClass->addInnerClass(mjc); mjc->setEnclosingClass(metaClass); - addAbstractMetaClass(mjc, cls.data()); + addAbstractMetaClass(mjc, cls.get()); } } @@ -718,20 +822,22 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel // specific typedefs to be used as classes. const TypeDefList typeDefs = namespaceItem->typeDefs(); for (const TypeDefModelItem &typeDef : typeDefs) { - AbstractMetaClass *cls = traverseTypeDef(dom, typeDef, metaClass); + const auto cls = traverseTypeDef(dom, typeDef, metaClass); if (cls) { metaClass->addInnerClass(cls); cls->setEnclosingClass(metaClass); - addAbstractMetaClass(cls, typeDef.data()); + addAbstractMetaClass(cls, typeDef.get()); } } // Traverse namespaces recursively for (const NamespaceModelItem &ni : namespaceItem->namespaces()) { - AbstractMetaClass *mjc = traverseNamespace(dom, ni); + const auto mjc = traverseNamespace(dom, ni); if (mjc) { metaClass->addInnerClass(mjc); mjc->setEnclosingClass(metaClass); + m_classToItem.insert(mjc, ni.get()); // Add for enum lookup. + m_itemToClass.insert(ni.get(), mjc); } } @@ -745,16 +851,16 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel std::optional<AbstractMetaEnum> AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem &enumItem, - AbstractMetaClass *enclosing, + const AbstractMetaClassPtr &enclosing, const QSet<QString> &enumsDeclarations) { - QString qualifiedName = enumItem->qualifiedName().join(colonColon()); + QString qualifiedName = enumItem->qualifiedName().join(u"::"_s); - TypeEntry *typeEntry = nullptr; - const TypeEntry *enclosingTypeEntry = enclosing ? enclosing->typeEntry() : nullptr; + TypeEntryPtr typeEntry; + const auto enclosingTypeEntry = enclosing ? enclosing->typeEntry() : TypeEntryCPtr{}; if (enumItem->accessPolicy() == Access::Private) { - typeEntry = new EnumTypeEntry(enumItem->qualifiedName().constLast(), - QVersionNumber(0, 0), enclosingTypeEntry); + typeEntry.reset(new EnumTypeEntry(enumItem->qualifiedName().constLast(), + QVersionNumber(0, 0), enclosingTypeEntry)); TypeDatabase::instance()->addType(typeEntry); } else if (enumItem->enumKind() != AnonymousEnum) { typeEntry = TypeDatabase::instance()->findType(qualifiedName); @@ -764,7 +870,7 @@ std::optional<AbstractMetaEnum> for (const EnumeratorModelItem &enumValue : enums) { tmpQualifiedName.removeLast(); tmpQualifiedName << enumValue->name(); - qualifiedName = tmpQualifiedName.join(colonColon()); + qualifiedName = tmpQualifiedName.join(u"::"_s); typeEntry = TypeDatabase::instance()->findType(qualifiedName); if (typeEntry) break; @@ -781,65 +887,75 @@ std::optional<AbstractMetaEnum> if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) { if (typeEntry) typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); - m_rejectedEnums.insert(qualifiedName + rejectReason, AbstractMetaBuilder::GenerationDisabled); + m_rejectedEnums.insert({AbstractMetaBuilder::GenerationDisabled, qualifiedName, + qualifiedName, rejectReason}); return {}; } const bool rejectionWarning = !enclosing || enclosing->typeEntry()->generateCode(); if (!typeEntry) { + const QString rejectReason = msgNoEnumTypeEntry(enumItem, className); if (rejectionWarning) - qCWarning(lcShiboken, "%s", qPrintable(msgNoEnumTypeEntry(enumItem, className))); - m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); + qCWarning(lcShiboken, "%s", qPrintable(rejectReason)); + m_rejectedEnums.insert({AbstractMetaBuilder::NotInTypeSystem, qualifiedName, + qualifiedName, rejectReason}); return {}; } if (!typeEntry->isEnum()) { - if (rejectionWarning) { - qCWarning(lcShiboken, "%s", - qPrintable(msgNoEnumTypeConflict(enumItem, className, typeEntry))); - } - m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); + const QString rejectReason = msgNoEnumTypeConflict(enumItem, className, typeEntry); + if (rejectionWarning) + qCWarning(lcShiboken, "%s", qPrintable(rejectReason)); + m_rejectedEnums.insert({AbstractMetaBuilder::NotInTypeSystem, qualifiedName, + qualifiedName, rejectReason}); return {}; } AbstractMetaEnum metaEnum; metaEnum.setEnumKind(enumItem->enumKind()); + metaEnum.setDeprecated(enumItem->isDeprecated()); + metaEnum.setUnderlyingType(enumItem->underlyingType()); metaEnum.setSigned(enumItem->isSigned()); if (enumsDeclarations.contains(qualifiedName) || enumsDeclarations.contains(enumName)) { metaEnum.setHasQEnumsDeclaration(true); } - auto *enumTypeEntry = static_cast<EnumTypeEntry *>(typeEntry); + auto enumTypeEntry = std::static_pointer_cast<EnumTypeEntry>(typeEntry); metaEnum.setTypeEntry(enumTypeEntry); metaEnum.setAccess(enumItem->accessPolicy()); if (metaEnum.access() == Access::Private) typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); - + // PYSIDE-2088, MSVC signedness issue in Qt + const bool castToUnsigned = enumItem->isSigned() + && enumTypeEntry->cppType().contains(u"unsigned"_s); const EnumeratorList &enums = enumItem->enumerators(); - for (const EnumeratorModelItem &value : enums) { + for (const EnumeratorModelItem &valueItem : enums) { AbstractMetaEnumValue metaEnumValue; - metaEnumValue.setName(value->name()); + metaEnumValue.setName(valueItem->name()); // Deciding the enum value... - metaEnumValue.setStringValue(value->stringValue()); - metaEnumValue.setValue(value->value()); + metaEnumValue.setStringValue(valueItem->stringValue()); + const auto value = valueItem->value(); + metaEnumValue.setValue(castToUnsigned ? value.toUnsigned() : value); + metaEnumValue.setDeprecated(valueItem->isDeprecated()); metaEnum.addEnumValue(metaEnumValue); } - if (!metaEnum.typeEntry()->include().isValid()) - setInclude(metaEnum.typeEntry(), enumItem->fileName()); + if (!metaEnum.typeEntry()->include().isValid()) { + auto te = std::const_pointer_cast<EnumTypeEntry>(metaEnum.typeEntry()); + setInclude(te, enumItem->fileName()); + } // Register all enum values on Type database const bool isScopedEnum = enumItem->enumKind() == EnumClass; const EnumeratorList &enumerators = enumItem->enumerators(); for (const EnumeratorModelItem &e : enumerators) { - auto enumValue = - new EnumValueTypeEntry(e->name(), e->stringValue(), - enumTypeEntry, isScopedEnum, - enumTypeEntry->version()); + auto enumValue = std::make_shared<EnumValueTypeEntry>(e->name(), e->stringValue(), + enumTypeEntry, isScopedEnum, + enumTypeEntry->version()); TypeDatabase::instance()->addType(enumValue); if (e->value().isNullValue()) enumTypeEntry->setNullValue(enumValue); @@ -851,9 +967,31 @@ std::optional<AbstractMetaEnum> return metaEnum; } -AbstractMetaClass *AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &, - const TypeDefModelItem &typeDef, - AbstractMetaClass *currentClass) +AbstractMetaClassPtr + AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &dom, + const TypeDefModelItem &typeDef, + const AbstractMetaClassPtr ¤tClass) +{ + auto result = traverseTypeDefHelper(dom, typeDef, currentClass); + if (!result && typeDef->type().isPlain()) { + const auto &type = typeDef->type(); + QString fullName; + if (currentClass) + fullName += currentClass->qualifiedCppName() + "::"_L1; + fullName += typeDef->name(); + QString targetName = typeDef->type().toString(); + m_typedefTargetToName.insert(targetName, fullName); + const QByteArray normalized = QMetaObject::normalizedType(targetName.toUtf8().constData()); + if (targetName != QLatin1StringView(normalized)) + m_typedefTargetToName.insert(QString::fromUtf8(normalized), fullName); + } + return result; +} + +AbstractMetaClassPtr + AbstractMetaBuilderPrivate::traverseTypeDefHelper(const FileModelItem &, + const TypeDefModelItem &typeDef, + const AbstractMetaClassPtr ¤tClass) { TypeDatabase *types = TypeDatabase::instance(); QString className = stripTemplateArgs(typeDef->name()); @@ -862,26 +1000,39 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelIt // we have an inner class if (currentClass) { fullClassName = stripTemplateArgs(currentClass->typeEntry()->qualifiedCppName()) - + colonColon() + fullClassName; + + u"::"_s + fullClassName; } // If this is the alias for a primitive type // we store the aliased type on the alias // TypeEntry - PrimitiveTypeEntry *ptype = types->findPrimitiveType(className); + const auto ptype = types->findPrimitiveType(className); + const auto &targetNames = typeDef->type().qualifiedName(); + const auto pTarget = targetNames.size() == 1 + ? types->findPrimitiveType(targetNames.constFirst()) : PrimitiveTypeEntryPtr{}; if (ptype) { - QString typeDefName = typeDef->type().qualifiedName()[0]; - ptype->setReferencedTypeEntry(types->findPrimitiveType(typeDefName)); + ptype->setReferencedTypeEntry(pTarget); return nullptr; } + // It is a (nested?) global typedef to a primitive type + // (like size_t = unsigned)? Add it to the type DB. + if (pTarget && isCppPrimitive(basicReferencedNonBuiltinTypeEntry(pTarget)) + && currentClass == nullptr) { + auto pte = std::make_shared<PrimitiveTypeEntry>(className, QVersionNumber{}, + TypeEntryCPtr{}); + pte->setReferencedTypeEntry(pTarget); + pte->setBuiltIn(true); + types->addType(pte); + return nullptr; + } // If we haven't specified anything for the typedef, then we don't care - ComplexTypeEntry *type = types->findComplexType(fullClassName); + auto type = types->findComplexType(fullClassName); if (!type) return nullptr; - auto *metaClass = new AbstractMetaClass; + auto metaClass = std::make_shared<AbstractMetaClass>(); metaClass->setTypeDef(true); metaClass->setTypeEntry(type); metaClass->setBaseClassNames(QStringList(typeDef->type().toString())); @@ -900,8 +1051,8 @@ void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs() { const auto &entries = TypeDatabase::instance()->typedefEntries(); for (auto it = entries.begin(), end = entries.end(); it != end; ++it) { - TypedefEntry *te = it.value(); - auto *metaClass = new AbstractMetaClass; + const TypedefEntryPtr &te = it.value(); + auto metaClass = std::make_shared<AbstractMetaClass>(); metaClass->setTypeDef(true); metaClass->setTypeEntry(te->target()); metaClass->setBaseClassNames(QStringList(te->sourceType())); @@ -927,9 +1078,9 @@ void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs() } } -AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom, +AbstractMetaClassPtr AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom, const ClassModelItem &classItem, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { QString className = stripTemplateArgs(classItem->name()); QString fullClassName = className; @@ -937,20 +1088,24 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem // we have inner an class if (currentClass) { fullClassName = stripTemplateArgs(currentClass->typeEntry()->qualifiedCppName()) - + colonColon() + fullClassName; + + u"::"_s + fullClassName; } - ComplexTypeEntry *type = TypeDatabase::instance()->findComplexType(fullClassName); + const auto type = TypeDatabase::instance()->findComplexType(fullClassName); AbstractMetaBuilder::RejectReason reason = AbstractMetaBuilder::NoReason; if (TypeDatabase::instance()->isClassRejected(fullClassName)) { reason = AbstractMetaBuilder::GenerationDisabled; } else if (!type) { - TypeEntry *te = TypeDatabase::instance()->findType(fullClassName); - if (te && !te->isComplex()) + TypeEntryPtr te = TypeDatabase::instance()->findType(fullClassName); + if (te && !te->isComplex()) { reason = AbstractMetaBuilder::RedefinedToNotClass; - else + // Set the default include file name + if (!te->include().isValid()) + setInclude(te, classItem->fileName()); + } else { reason = AbstractMetaBuilder::NotInTypeSystem; + } } else if (type->codeGeneration() == TypeEntry::GenerateNothing) { reason = AbstractMetaBuilder::GenerationDisabled; } @@ -959,11 +1114,11 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem QTextStream(&fullClassName) << "anonymous struct at " << classItem->fileName() << ':' << classItem->startLine(); } - m_rejectedClasses.insert(fullClassName, reason); + m_rejectedClasses.insert({reason, fullClassName, fullClassName, QString{}}); return nullptr; } - auto *metaClass = new AbstractMetaClass; + auto metaClass = std::make_shared<AbstractMetaClass>(); metaClass->setSourceLocation(classItem->sourceLocation()); metaClass->setTypeEntry(type); if ((type->typeFlags() & ComplexTypeEntry::ForceAbstract) != 0) @@ -972,6 +1127,9 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem if (classItem->isFinal()) *metaClass += AbstractMetaClass::FinalCppClass; + if (classItem->classType() == CodeModel::Struct) + *metaClass += AbstractMetaClass::Struct; + QStringList baseClassNames; const QList<_ClassModelItem::BaseClass> &baseClasses = classItem->baseClasses(); for (const _ClassModelItem::BaseClass &baseClass : baseClasses) { @@ -985,21 +1143,22 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem if (ReportHandler::isDebug(ReportHandler::MediumDebug)) { const QString message = type->isContainer() - ? QStringLiteral("container: '%1'").arg(fullClassName) - : QStringLiteral("class: '%1'").arg(metaClass->fullName()); + ? u"container: '"_s + fullClassName + u'\'' + : u"class: '"_s + metaClass->fullName() + u'\''; qCInfo(lcShiboken, "%s", qPrintable(message)); } TemplateParameterList template_parameters = classItem->templateParameters(); - TypeEntries template_args; + TypeEntryCList template_args; template_args.clear(); - auto argumentParent = metaClass->typeEntry()->typeSystemTypeEntry(); - for (int i = 0; i < template_parameters.size(); ++i) { + auto argumentParent = typeSystemTypeEntry(metaClass->typeEntry()); + for (qsizetype i = 0; i < template_parameters.size(); ++i) { const TemplateParameterModelItem ¶m = template_parameters.at(i); - auto param_type = new TemplateArgumentEntry(param->name(), type->version(), + auto param_type = + std::make_shared<TemplateArgumentEntry>(param->name(), type->version(), argumentParent); param_type->setOrdinal(i); - template_args.append(param_type); + template_args.append(TypeEntryCPtr(param_type)); } metaClass->setTemplateArguments(template_args); @@ -1011,11 +1170,11 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem { const ClassList &innerClasses = classItem->classes(); for (const ClassModelItem &ci : innerClasses) { - AbstractMetaClass *cl = traverseClass(dom, ci, metaClass); + const auto cl = traverseClass(dom, ci, metaClass); if (cl) { cl->setEnclosingClass(metaClass); metaClass->addInnerClass(cl); - addAbstractMetaClass(cl, ci.data()); + addAbstractMetaClass(cl, ci.get()); } } @@ -1025,10 +1184,10 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem // specific typedefs to be used as classes. const TypeDefList typeDefs = classItem->typeDefs(); for (const TypeDefModelItem &typeDef : typeDefs) { - AbstractMetaClass *cls = traverseTypeDef(dom, typeDef, metaClass); + const auto cls = traverseTypeDef(dom, typeDef, metaClass); if (cls) { cls->setEnclosingClass(metaClass); - addAbstractMetaClass(cls, typeDef.data()); + addAbstractMetaClass(cls, typeDef.get()); } } @@ -1040,7 +1199,7 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem } void AbstractMetaBuilderPrivate::traverseScopeMembers(const ScopeModelItem &item, - AbstractMetaClass *metaClass) + const AbstractMetaClassPtr &metaClass) { // Classes/Namespace members traverseFields(item, metaClass); @@ -1054,28 +1213,25 @@ void AbstractMetaBuilderPrivate::traverseScopeMembers(const ScopeModelItem &item void AbstractMetaBuilderPrivate::traverseClassMembers(const ClassModelItem &item) { - AbstractMetaClass *metaClass = m_itemToClass.value(item.data()); - if (!metaClass) - return; - - // Class members - traverseScopeMembers(item, metaClass); + const auto metaClass = m_itemToClass.value(item.get()); + if (metaClass) // Class members + traverseScopeMembers(item, metaClass); } -void AbstractMetaBuilderPrivate::traverseUsingMembers(AbstractMetaClass *metaClass) +void AbstractMetaBuilderPrivate::traverseUsingMembers(const AbstractMetaClassPtr &metaClass) const { const _CodeModelItem *item = m_classToItem.value(metaClass); if (item == nullptr || item->kind() != _CodeModelItem::Kind_Class) return; - auto classItem = static_cast<const _ClassModelItem *>(item); + const auto *classItem = static_cast<const _ClassModelItem *>(item); for (const auto &um : classItem->usingMembers()) { QString className = um.className; - int pos = className.indexOf(u'<'); // strip "QList<value>" + auto pos = className.indexOf(u'<'); // strip "QList<value>" if (pos != -1) className.truncate(pos); - if (auto baseClass = metaClass->AbstractMetaClass::findBaseClass(className)) { + if (auto baseClass = findBaseClass(metaClass, className)) { QString name = um.memberName; - const int lastQualPos = name.lastIndexOf(colonColon()); + const auto lastQualPos = name.lastIndexOf(u"::"_s); if (lastQualPos != -1) name.remove(0, lastQualPos + 2); metaClass->addUsingMember({name, baseClass, um.access}); @@ -1089,7 +1245,7 @@ void AbstractMetaBuilderPrivate::traverseUsingMembers(AbstractMetaClass *metaCla void AbstractMetaBuilderPrivate::traverseNamespaceMembers(const NamespaceModelItem &item) { - AbstractMetaClass *metaClass = m_itemToClass.value(item.data()); + const auto metaClass = m_itemToClass.value(item.get()); if (!metaClass) return; @@ -1104,18 +1260,18 @@ void AbstractMetaBuilderPrivate::traverseNamespaceMembers(const NamespaceModelIt static inline QString fieldSignatureWithType(const VariableModelItem &field) { - return field->name() + QStringLiteral(" -> ") + field->type().toString(); + return field->name() + " -> "_L1 + field->type().toString(); } static inline QString qualifiedFieldSignatureWithType(const QString &className, const VariableModelItem &field) { - return className + colonColon() + fieldSignatureWithType(field); + return className + u"::"_s + fieldSignatureWithType(field); } std::optional<AbstractMetaField> AbstractMetaBuilderPrivate::traverseField(const VariableModelItem &field, - const AbstractMetaClass *cls) + const AbstractMetaClassCPtr &cls) { QString fieldName = field->name(); QString className = cls->typeEntry()->qualifiedCppName(); @@ -1129,8 +1285,9 @@ std::optional<AbstractMetaField> QString rejectReason; if (TypeDatabase::instance()->isFieldRejected(className, fieldName, &rejectReason)) { - m_rejectedFields.insert(qualifiedFieldSignatureWithType(className, field) + rejectReason, - AbstractMetaBuilder::GenerationDisabled); + const QString signature = qualifiedFieldSignatureWithType(className, field); + m_rejectedFields.insert({AbstractMetaBuilder::GenerationDisabled, + signature, signature, rejectReason}); return {}; } @@ -1143,7 +1300,7 @@ std::optional<AbstractMetaField> auto metaType = translateType(fieldType, cls); if (!metaType.has_value()) { - const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(colonColon()); + const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(u"::"_s); if (cls->typeEntry()->generateCode()) { qCWarning(lcShiboken, "%s", qPrintable(msgSkippingField(field, cls->name(), type))); @@ -1178,7 +1335,7 @@ static bool applyFieldModifications(AbstractMetaField *f) } void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item, - AbstractMetaClass *metaClass) + const AbstractMetaClassPtr &metaClass) { const VariableList &variables = scope_item->variables(); for (const VariableModelItem &field : variables) { @@ -1191,37 +1348,22 @@ void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item } } -void AbstractMetaBuilderPrivate::setupFunctionDefaults(AbstractMetaFunction *metaFunction, - AbstractMetaClass *metaClass) -{ - // Set the default value of the declaring class. This may be changed - // in fixFunctions later on - metaFunction->setDeclaringClass(metaClass); - - // Some of the queries below depend on the implementing class being set - // to function properly. Such as function modifications - metaFunction->setImplementingClass(metaClass); - - if (metaFunction->name() == QLatin1String("operator_equal")) - metaClass->setHasEqualsOperator(true); -} - void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction) { if (!metaFunction->isConversionOperator()) return; TypeDatabase *types = TypeDatabase::instance(); - static const QRegularExpression operatorRegExp(QStringLiteral("^operator ")); + static const QRegularExpression operatorRegExp("^operator "_L1); Q_ASSERT(operatorRegExp.isValid()); QString castTo = metaFunction->name().remove(operatorRegExp).trimmed(); - if (castTo.endsWith(QLatin1Char('&'))) + if (castTo.endsWith(u'&')) castTo.chop(1); - if (castTo.startsWith(QLatin1String("const "))) + if (castTo.startsWith(u"const ")) castTo.remove(0, 6); - TypeEntry *retType = types->findType(castTo); + TypeEntryPtr retType = types->findType(castTo); if (!retType) return; @@ -1233,16 +1375,22 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF AbstractMetaFunctionRawPtrList AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem, AbstractMetaClass::Attributes *constructorAttributes, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { *constructorAttributes = {}; AbstractMetaFunctionRawPtrList result; const FunctionList &scopeFunctionList = scopeItem->functions(); result.reserve(scopeFunctionList.size()); + const bool isNamespace = currentClass->isNamespace(); for (const FunctionModelItem &function : scopeFunctionList) { - if (AbstractMetaFunction *metaFunction = traverseFunction(function, currentClass)) { + if (isNamespace && function->isOperator()) { + traverseOperatorFunction(function, currentClass); + } else if (function->isSpaceshipOperator() && !function->isDeleted()) { + if (currentClass) + AbstractMetaClass::addSynthesizedComparisonOperators(currentClass); + } else if (auto *metaFunction = traverseFunction(function, currentClass)) { result.append(metaFunction); - } else if (function->functionType() == CodeModel::Constructor) { + } else if (!function->isDeleted() && function->functionType() == CodeModel::Constructor) { auto arguments = function->arguments(); *constructorAttributes |= AbstractMetaClass::HasRejectedConstructor; if (arguments.isEmpty() || arguments.constFirst()->defaultValue()) @@ -1252,8 +1400,8 @@ AbstractMetaFunctionRawPtrList return result; } -void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, - AbstractMetaClass *metaClass) +void AbstractMetaBuilderPrivate::traverseFunctions(const ScopeModelItem& scopeItem, + const AbstractMetaClassPtr &metaClass) { AbstractMetaClass::Attributes constructorAttributes; const AbstractMetaFunctionRawPtrList functions = @@ -1262,7 +1410,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, for (AbstractMetaFunction *metaFunction : functions) { if (metaClass->isNamespace()) - *metaFunction += AbstractMetaFunction::Static; + metaFunction->setCppAttribute(FunctionAttribute::Static); const auto propertyFunction = metaClass->searchPropertyFunction(metaFunction->name()); if (propertyFunction.index >= 0) { @@ -1295,34 +1443,31 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, metaFunction->setPropertySpecIndex(propertyFunction.index); } break; + case AbstractMetaClass::PropertyFunction::Notify: + if (metaFunction->isSignal()) { + *metaFunction += AbstractMetaFunction::PropertyNotify; + metaFunction->setPropertySpecIndex(propertyFunction.index); + } } } - const bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate(); - const bool isInvalidConstructor = metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction - && metaFunction->isPrivate(); - if (isInvalidConstructor) + if (metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction + && metaFunction->isPrivate()) { metaClass->setHasPrivateConstructor(true); - if ((isInvalidDestructor || isInvalidConstructor) - && !metaClass->hasNonPrivateConstructor()) { - *metaClass += AbstractMetaClass::FinalInTargetLang; - } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) { - *metaClass -= AbstractMetaClass::FinalInTargetLang; - metaClass->setHasNonPrivateConstructor(true); } + if (metaFunction->isConstructor() && !metaFunction->isPrivate()) // Including Copy CT + metaClass->setHasNonPrivateConstructor(true); if (!metaFunction->isDestructor() && !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) { - setupFunctionDefaults(metaFunction, metaClass); - if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction)) qCWarning(lcShiboken, "%s", qPrintable(msgSignalOverloaded(metaClass, metaFunction))); if (metaFunction->isConversionOperator()) fixReturnTypeOfConversionOperator(metaFunction); - metaClass->addFunction(AbstractMetaFunctionCPtr(metaFunction)); + AbstractMetaClass::addFunction(metaClass, AbstractMetaFunctionCPtr(metaFunction)); applyFunctionModifications(metaFunction); } else if (metaFunction->isDestructor()) { metaClass->setHasPrivateDestructor(metaFunction->isPrivate()); @@ -1338,7 +1483,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, fillAddedFunctions(metaClass); } -void AbstractMetaBuilderPrivate::fillAddedFunctions(AbstractMetaClass *metaClass) +void AbstractMetaBuilderPrivate::fillAddedFunctions(const AbstractMetaClassPtr &metaClass) { // Add the functions added by the typesystem QString errorMessage; @@ -1351,12 +1496,12 @@ void AbstractMetaBuilderPrivate::fillAddedFunctions(AbstractMetaClass *metaClass QString AbstractMetaBuilder::getSnakeCaseName(const QString &name) { - const int size = name.size(); + const auto size = name.size(); if (size < 3) return name; QString result; result.reserve(size + 4); - for (int i = 0; i < size; ++i) { + for (qsizetype i = 0; i < size; ++i) { const QChar c = name.at(i); if (c.isUpper()) { if (i > 0) { @@ -1402,26 +1547,17 @@ void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction func->setOriginalName(func->name()); func->setName(mod.renamedToName()); } else if (mod.isAccessModifier()) { - funcRef -= AbstractMetaFunction::Friendly; - if (mod.isPublic()) funcRef.modifyAccess(Access::Public); else if (mod.isProtected()) funcRef.modifyAccess(Access::Protected); else if (mod.isPrivate()) funcRef.modifyAccess(Access::Private); - else if (mod.isFriendly()) - funcRef += AbstractMetaFunction::Friendly; } - - if (mod.isFinal()) - funcRef += AbstractMetaFunction::FinalInTargetLang; - else if (mod.isNonFinal()) - funcRef -= AbstractMetaFunction::FinalInTargetLang; } } -bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) +bool AbstractMetaBuilderPrivate::setupInheritance(const AbstractMetaClassPtr &metaClass) { if (metaClass->inheritanceDone()) return true; @@ -1431,10 +1567,11 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) QStringList baseClasses = metaClass->baseClassNames(); // we only support our own containers and ONLY if there is only one baseclass - if (baseClasses.size() == 1 && baseClasses.constFirst().contains(QLatin1Char('<'))) { + if (baseClasses.size() == 1 && baseClasses.constFirst().contains(u'<')) { TypeInfo info; - ComplexTypeEntry* baseContainerType; - AbstractMetaClass* templ = findTemplateClass(baseClasses.constFirst(), metaClass, &info, &baseContainerType); + ComplexTypeEntryPtr baseContainerType; + const auto templ = findTemplateClass(baseClasses.constFirst(), metaClass, + &info, &baseContainerType); if (templ) { setupInheritance(templ); inheritTemplate(metaClass, templ, info); @@ -1454,15 +1591,15 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) return true; } - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("template baseclass '%1' of '%2' is not known") - .arg(baseClasses.constFirst(), metaClass->name()); + qCWarning(lcShiboken, "template baseclass '%s' of '%s' is not known", + qPrintable(baseClasses.constFirst()), + qPrintable(metaClass->name())); return false; } - TypeDatabase* types = TypeDatabase::instance(); + auto *types = TypeDatabase::instance(); - for (const auto &baseClassName : baseClasses) { + for (const auto &baseClassName : baseClasses) { if (!types->isClassRejected(baseClassName)) { auto typeEntry = types->findType(baseClassName); if (typeEntry == nullptr || !typeEntry->isComplex()) { @@ -1491,7 +1628,7 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) } else { QString message; QTextStream(&message) << "Class \"" << defaultSuperclassName - << "\" specified as \"default-superclass\" of \"" << metaClass->name() + << R"(" specified as "default-superclass" of ")" << metaClass->name() << "\" could not be found in the code model."; qCWarning(lcShiboken, "%s", qPrintable(message)); } @@ -1501,7 +1638,7 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) } void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem, - AbstractMetaClass *metaClass, + const AbstractMetaClassPtr &metaClass, const QStringList &enumsDeclarations) { const EnumList &enums = scopeItem->enums(); @@ -1549,7 +1686,7 @@ bool AbstractMetaBuilderPrivate::traverseAddedGlobalFunction(const AddedFunction AbstractMetaFunction * AbstractMetaBuilderPrivate::traverseAddedFunctionHelper(const AddedFunctionPtr &addedFunc, - AbstractMetaClass *metaClass /* = nullptr */, + const AbstractMetaClassPtr &metaClass /* = {} */, QString *errorMessage) { auto returnType = translateType(addedFunc->returnType(), metaClass, {}, errorMessage); @@ -1561,13 +1698,17 @@ AbstractMetaFunction * return nullptr; } - auto metaFunction = new AbstractMetaFunction(addedFunc); + auto *metaFunction = new AbstractMetaFunction(addedFunc); metaFunction->setType(returnType.value()); metaFunction->setFunctionType(functionTypeFromName(addedFunc->name())); const auto &args = addedFunc->arguments(); - for (int i = 0; i < args.count(); ++i) { + qsizetype argCount = args.size(); + // Check "foo(void)" + if (argCount == 1 && args.constFirst().typeInfo.isVoid()) + argCount = 0; + for (qsizetype i = 0; i < argCount; ++i) { const AddedFunction::Argument &arg = args.at(i); auto type = translateType(arg.typeInfo, metaClass, {}, errorMessage); if (Q_UNLIKELY(!type.has_value())) { @@ -1614,7 +1755,8 @@ AbstractMetaFunction * // Find the correct default values const FunctionModificationList functionMods = metaFunction->modifications(metaClass); - for (int i = 0; i < metaArguments.size(); ++i) { + applyCachedFunctionModifications(metaFunction, functionMods); + for (qsizetype i = 0; i < metaArguments.size(); ++i) { AbstractMetaArgument &metaArg = metaArguments[i]; // use replace-default-expression for set default value @@ -1629,7 +1771,7 @@ AbstractMetaFunction * } bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunctionPtr &addedFunc, - AbstractMetaClass *metaClass, + const AbstractMetaClassPtr &metaClass, QString *errorMessage) { AbstractMetaFunction *metaFunction = @@ -1639,11 +1781,11 @@ bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunction const AbstractMetaArgumentList fargs = metaFunction->arguments(); if (metaClass->isNamespace()) - *metaFunction += AbstractMetaFunction::Static; + metaFunction->setCppAttribute(FunctionAttribute::Static); if (metaFunction->name() == metaClass->name()) { metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction); if (fargs.size() == 1) { - const TypeEntry *te = fargs.constFirst().type().typeEntry(); + const auto te = fargs.constFirst().type().typeEntry(); if (te->isCustom()) metaFunction->setExplicit(true); if (te->name() == metaFunction->name()) @@ -1653,7 +1795,7 @@ bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunction metaFunction->setDeclaringClass(metaClass); metaFunction->setImplementingClass(metaClass); - metaClass->addFunction(AbstractMetaFunctionCPtr(metaFunction)); + AbstractMetaClass::addFunction(metaClass, AbstractMetaFunctionCPtr(metaFunction)); metaClass->setHasNonPrivateConstructor(true); return true; } @@ -1669,9 +1811,9 @@ void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func, co } } - for (int i = 0, size = arguments.size(); i < size; ++i) { + for (qsizetype i = 0, size = arguments.size(); i < size; ++i) { if (arguments.at(i).name().isEmpty()) - arguments[i].setName(QLatin1String("arg__") + QString::number(i + 1), false); + arguments[i].setName(u"arg__"_s + QString::number(i + 1), false); } } @@ -1681,15 +1823,15 @@ static QString functionSignature(const FunctionModelItem &functionItem) const ArgumentList &arguments = functionItem->arguments(); for (const ArgumentModelItem &arg : arguments) args << arg->type().toString(); - return functionItem->name() + QLatin1Char('(') + args.join(QLatin1Char(',')) + QLatin1Char(')'); + return functionItem->name() + u'(' + args.join(u',') + u')'; } static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem &functionItem, const QString &className = QString()) { - QString result = functionItem->type().toString() + QLatin1Char(' '); + QString result = functionItem->type().toString() + u' '; if (!className.isEmpty()) - result += className + colonColon(); + result += className + u"::"_s; result += functionSignature(functionItem); return result; } @@ -1786,7 +1928,7 @@ static bool applyArrayArgumentModifications(const FunctionModificationList &func const int i = argMod.index() - 1; if (i < 0 || i >= func->arguments().size()) { *errorMessage = msgCannotSetArrayUsage(func->minimalSignature(), i, - QLatin1String("Index out of range.")); + u"Index out of range."_s); return false; } auto t = func->arguments().at(i).type(); @@ -1801,9 +1943,48 @@ static bool applyArrayArgumentModifications(const FunctionModificationList &func return true; } +// Create the meta type for a view (std::string_view -> std::string) +static AbstractMetaType createViewOnType(const AbstractMetaType &metaType, + const TypeEntryCPtr &viewOnTypeEntry) +{ + auto result = metaType; + result.setTypeEntry(viewOnTypeEntry); + if (!metaType.isContainer() || !viewOnTypeEntry->isContainer()) + return result; + // For containers, when sth with several template parameters + // (std::span<T, int N>) is mapped onto a std::vector<T>, + // remove the superfluous template parameters and strip 'const'. + const auto vcte = std::static_pointer_cast<const ContainerTypeEntry>(viewOnTypeEntry); + const auto &instantiations = metaType.instantiations(); + AbstractMetaTypeList viewInstantiations; + const auto size = std::min(vcte->templateParameterCount(), instantiations.size()); + for (qsizetype i = 0; i < size; ++i) { + auto ins = instantiations.at(i); + ins.setConstant(false); + viewInstantiations.append(ins); + } + result.setInstantiations(viewInstantiations); + return result; +} + +void AbstractMetaBuilderPrivate::rejectFunction(const FunctionModelItem &functionItem, + const AbstractMetaClassPtr ¤tClass, + AbstractMetaBuilder::RejectReason reason, + const QString &rejectReason) +{ + QString sortKey; + if (currentClass) + sortKey += currentClass->typeEntry()->qualifiedCppName() + u"::"_s; + sortKey += functionSignature(functionItem); // Sort without return type + const QString signatureWithType = functionItem->type().toString() + u' ' + sortKey; + m_rejectedFunctions.insert({reason, signatureWithType, sortKey, rejectReason}); +} + AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { + const auto *tdb = TypeDatabase::instance(); + if (!functionItem->templateParameters().isEmpty()) return nullptr; @@ -1821,34 +2002,40 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio } return nullptr; } - QString functionName = functionItem->name(); - QString className; - if (currentClass) { + const QString &functionName = functionItem->name(); + const QString className = currentClass != nullptr ? + currentClass->typeEntry()->qualifiedCppName() : QString{}; + + if (m_apiExtractorFlags.testFlag(ApiExtractorFlag::UsePySideExtensions)) { + // Skip enum helpers generated by Q_ENUM + if ((currentClass == nullptr || currentClass->isNamespace()) + && (functionName == u"qt_getEnumMetaObject" || functionName == u"qt_getEnumName")) { + return nullptr; + } + // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT // and overridden metaObject(), QGADGET helpers - if (functionName == QLatin1String("qt_check_for_QGADGET_macro") - || functionName.startsWith(QLatin1String("qt_meta"))) { - return nullptr; + if (currentClass != nullptr) { + if (functionName == u"qt_check_for_QGADGET_macro" + || functionName.startsWith(u"qt_meta")) { + return nullptr; + } + if (functionName == u"metaObject" && className != u"QObject") + return nullptr; } - className = currentClass->typeEntry()->qualifiedCppName(); - if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject")) - return nullptr; - } - - // Store original signature with unresolved typedefs for message/log purposes - const QString originalQualifiedSignatureWithReturn = - qualifiedFunctionSignatureWithType(functionItem, className); + } // PySide extensions QString rejectReason; - if (TypeDatabase::instance()->isFunctionRejected(className, functionName, &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); + if (tdb->isFunctionRejected(className, functionName, &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); return nullptr; } - const QString &signature = functionSignature(functionItem); - const bool rejected = - TypeDatabase::instance()->isFunctionRejected(className, signature, &rejectReason); - if (rejected) { + const QString &signature = functionSignature(functionItem); + if (tdb->isFunctionRejected(className, signature, &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); if (ReportHandler::isDebug(ReportHandler::MediumDebug)) { qCInfo(lcShiboken, "%s::%s was rejected by the type database (%s).", qPrintable(className), qPrintable(signature), qPrintable(rejectReason)); @@ -1859,47 +2046,30 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio if (functionItem->isFriend()) return nullptr; - const bool deprecated = functionItem->isDeprecated(); + const auto cppAttributes = functionItem->attributes(); + const bool deprecated = cppAttributes.testFlag(FunctionAttribute::Deprecated); if (deprecated && m_skipDeprecated) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + QLatin1String(" is deprecated."), - AbstractMetaBuilder::GenerationDisabled); + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, u" is deprecated."_s); return nullptr; } - auto *metaFunction = new AbstractMetaFunction; + AbstractMetaFunction::Flags flags; + auto *metaFunction = new AbstractMetaFunction(functionName); + metaFunction->setCppAttributes(cppAttributes); + const QByteArray cSignature = signature.toUtf8(); + const QString unresolvedSignature = + QString::fromUtf8(QMetaObject::normalizedSignature(cSignature.constData())); + metaFunction->setUnresolvedSignature(unresolvedSignature); + if (functionItem->isHiddenFriend()) + flags.setFlag(AbstractMetaFunction::Flag::HiddenFriend); metaFunction->setSourceLocation(functionItem->sourceLocation()); - if (deprecated) - *metaFunction += AbstractMetaFunction::Deprecated; // Additional check for assignment/move assignment down below metaFunction->setFunctionType(functionTypeFromCodeModel(functionItem->functionType())); metaFunction->setConstant(functionItem->isConstant()); metaFunction->setExceptionSpecification(functionItem->exceptionSpecification()); - metaFunction->setName(functionName); - metaFunction->setOriginalName(functionItem->name()); - - if (functionItem->isAbstract()) - *metaFunction += AbstractMetaFunction::Abstract; - - if (functionItem->isVirtual()) { - *metaFunction += AbstractMetaFunction::VirtualCppMethod; - if (functionItem->isOverride()) - *metaFunction += AbstractMetaFunction::OverriddenCppMethod; - if (functionItem->isFinal()) - *metaFunction += AbstractMetaFunction::FinalCppMethod; - } else { - *metaFunction += AbstractMetaFunction::FinalInTargetLang; - } - - if (functionItem->isInvokable()) - *metaFunction += AbstractMetaFunction::Invokable; - - if (functionItem->isStatic()) { - *metaFunction += AbstractMetaFunction::Static; - *metaFunction += AbstractMetaFunction::FinalInTargetLang; - } - // Access rights metaFunction->setAccess(functionItem->accessPolicy()); @@ -1909,25 +2079,30 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio metaFunction->setType(AbstractMetaType::createVoid()); break; case AbstractMetaFunction::ConstructorFunction: - metaFunction->setExplicit(functionItem->isExplicit()); metaFunction->setName(currentClass->name()); metaFunction->setType(AbstractMetaType::createVoid()); break; default: { TypeInfo returnType = functionItem->type(); - if (TypeDatabase::instance()->isReturnTypeRejected(className, returnType.toString(), &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); + if (tdb->isReturnTypeRejected(className, returnType.toString(), &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); delete metaFunction; return nullptr; } - auto type = translateType(returnType, currentClass, {}, &errorMessage); + TranslateTypeFlags flags; + if (functionItem->scopeResolution()) + flags.setFlag(AbstractMetaBuilder::NoClassScopeLookup); + auto type = translateType(returnType, currentClass, flags, &errorMessage); if (!type.has_value()) { const QString reason = msgUnmatchedReturnType(functionItem, errorMessage); + const QString signature = qualifiedFunctionSignatureWithType(functionItem, className); qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); + qPrintable(msgSkippingFunction(functionItem, signature, reason))); + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::UnmatchedReturnType, reason); delete metaFunction; return nullptr; } @@ -1938,41 +2113,56 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio } ArgumentList arguments = functionItem->arguments(); + // Add private signals for documentation purposes + if (!arguments.isEmpty() + && m_apiExtractorFlags.testFlag(ApiExtractorFlag::UsePySideExtensions) + && functionItem->functionType() == CodeModel::Signal + && arguments.constLast()->type().qualifiedName().constLast() == u"QPrivateSignal") { + flags.setFlag(AbstractMetaFunction::Flag::PrivateSignal); + arguments.removeLast(); + } if (arguments.size() == 1) { ArgumentModelItem arg = arguments.at(0); TypeInfo type = arg->type(); - if (type.qualifiedName().constFirst() == QLatin1String("void") && type.indirections() == 0) + if (type.qualifiedName().constFirst() == u"void" && type.indirections() == 0) arguments.pop_front(); } - for (int i = 0; i < arguments.size(); ++i) { + for (qsizetype i = 0; i < arguments.size(); ++i) { const ArgumentModelItem &arg = arguments.at(i); - if (TypeDatabase::instance()->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); + if (tdb->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); delete metaFunction; return nullptr; } - auto metaTypeO = translateType(arg->type(), currentClass, {}, &errorMessage); + TranslateTypeFlags flags; + if (arg->scopeResolution()) + flags.setFlag(AbstractMetaBuilder::NoClassScopeLookup); + auto metaTypeO = translateType(arg->type(), currentClass, flags, &errorMessage); if (!metaTypeO.has_value()) { // If an invalid argument has a default value, simply remove it // unless the function is virtual (since the override in the // wrapper can then not correctly be generated). - if (arg->defaultValue() && !functionItem->isVirtual()) { + if (arg->defaultValue() + && !functionItem->attributes().testFlag(FunctionAttribute::Virtual)) { if (!currentClass || currentClass->typeEntry()->generateCode()) { + const QString signature = qualifiedFunctionSignatureWithType(functionItem, className); qCWarning(lcShiboken, "%s", - qPrintable(msgStrippingArgument(functionItem, i, originalQualifiedSignatureWithReturn, arg))); + qPrintable(msgStrippingArgument(functionItem, i, signature, + arg, errorMessage))); } break; } const QString reason = msgUnmatchedParameterType(arg, i, errorMessage); + const QString signature = qualifiedFunctionSignatureWithType(functionItem, className); qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn - + QLatin1String(": ") + reason; - m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType); + qPrintable(msgSkippingFunction(functionItem, signature, reason))); + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::UnmatchedArgumentType, reason); delete metaFunction; return nullptr; } @@ -1983,10 +2173,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio auto viewOnTypeEntry = metaType.typeEntry()->viewOn(); if (viewOnTypeEntry != nullptr && metaType.indirections() == 0 && metaType.arrayElementType() == nullptr - && !metaType.hasInstantiations()) { - auto viewOn = metaType; - viewOn.setTypeEntry(viewOnTypeEntry); - metaType.setViewOn(viewOn); + && (!metaType.hasInstantiations() || metaType.isContainer())) { + metaType.setViewOn(createViewOnType(metaType, viewOnTypeEntry)); } AbstractMetaArgument metaArgument; @@ -2002,20 +2190,15 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio ? AbstractMetaFunction::findClassModifications(metaFunction, currentClass) : AbstractMetaFunction::findGlobalModifications(metaFunction); - for (const FunctionModification &mod : functionMods) { - if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) - metaFunction->setExceptionHandlingModification(mod.exceptionHandling()); - else if (mod.allowThread() != TypeSystem::AllowThread::Unspecified) - metaFunction->setAllowThreadModification(mod.allowThread()); - } + applyCachedFunctionModifications(metaFunction, functionMods); // Find the correct default values - for (int i = 0, size = metaArguments.size(); i < size; ++i) { + for (qsizetype i = 0, size = metaArguments.size(); i < size; ++i) { const ArgumentModelItem &arg = arguments.at(i); AbstractMetaArgument &metaArg = metaArguments[i]; const QString originalDefaultExpression = - fixDefaultValue(arg, metaArg.type(), currentClass, i); + fixDefaultValue(arg->defaultValueExpression(), metaArg.type(), currentClass); metaArg.setOriginalDefaultValueExpression(originalDefaultExpression); metaArg.setDefaultValueExpression(originalDefaultExpression); @@ -2048,7 +2231,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio if (currentClass && metaFunction->arguments().size() == 1) { const AbstractMetaType &argType = metaFunction->arguments().constFirst().type(); if (argType.typeEntry() == currentClass->typeEntry() && argType.indirections() == 0) { - if (metaFunction->name() == QLatin1String("operator=")) { + if (metaFunction->name() == u"operator=") { switch (argType.referenceType()) { case NoReference: metaFunction->setFunctionType(AbstractMetaFunction::AssignmentOperatorFunction); @@ -2064,35 +2247,39 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio } } } + metaFunction->setFlags(flags); return metaFunction; } -static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName) +static TypeEntryCPtr findTypeEntryUsingContext(const AbstractMetaClassCPtr &metaClass, + const QString& qualifiedName) { - const TypeEntry* type = nullptr; - QStringList context = metaClass->qualifiedCppName().split(colonColon()); + TypeEntryCPtr type; + QStringList context = metaClass->qualifiedCppName().split(u"::"_s); while (!type && !context.isEmpty()) { - type = TypeDatabase::instance()->findType(context.join(colonColon()) + colonColon() + qualifiedName); + type = TypeDatabase::instance()->findType(context.join(u"::"_s) + u"::"_s + qualifiedName); context.removeLast(); } return type; } // Helper for findTypeEntries/translateTypeStatic() -TypeEntries AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString &qualifiedName, - const QString &name, - const AbstractMetaClass *currentClass, - AbstractMetaBuilderPrivate *d) +TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString &qualifiedName, + const QString &name, + TranslateTypeFlags flags, + const AbstractMetaClassCPtr ¤tClass, + AbstractMetaBuilderPrivate *d) { // 5.1 - Try first using the current scope - if (currentClass) { + if (currentClass != nullptr + && !flags.testFlag(AbstractMetaBuilder::NoClassScopeLookup)) { if (auto type = findTypeEntryUsingContext(currentClass, qualifiedName)) return {type}; // 5.1.1 - Try using the class parents' scopes if (d && !currentClass->baseClassNames().isEmpty()) { - const AbstractMetaClassList &baseClasses = d->getBaseClasses(currentClass); - for (const AbstractMetaClass *cls : baseClasses) { + const auto &baseClasses = d->getBaseClasses(currentClass); + for (const auto &cls : baseClasses) { if (auto type = findTypeEntryUsingContext(cls, qualifiedName)) return {type}; } @@ -2116,7 +2303,7 @@ TypeEntries AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString &qua // of the parameters. if (currentClass) { const auto &template_args = currentClass->templateArguments(); - for (const TypeEntry *te : template_args) { + for (const auto &te : template_args) { if (te->name() == qualifiedName) return {te}; } @@ -2126,25 +2313,37 @@ TypeEntries AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString &qua // Helper for translateTypeStatic() that calls findTypeEntriesHelper() // and does some error checking. -TypeEntries AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualifiedName, - const QString &name, - const AbstractMetaClass *currentClass, - AbstractMetaBuilderPrivate *d, - QString *errorMessage) -{ - const TypeEntries types = findTypeEntriesHelper(qualifiedName, name, currentClass, d); +TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualifiedName, + const QString &name, + TranslateTypeFlags flags, + const AbstractMetaClassCPtr ¤tClass, + AbstractMetaBuilderPrivate *d, + QString *errorMessage) +{ + TypeEntryCList types = findTypeEntriesHelper(qualifiedName, name, flags, + currentClass, d); if (types.isEmpty()) { if (errorMessage != nullptr) *errorMessage = msgCannotFindTypeEntry(qualifiedName); return {}; } + // Resolve entries added by metabuilder (for example, "GLenum") to match + // the signatures for modifications. + for (qsizetype i = 0, size = types.size(); i < size; ++i) { + const auto &e = types.at(i); + if (e->isPrimitive()) { + const auto pte = std::static_pointer_cast<const PrimitiveTypeEntry>(e); + types[i] = basicReferencedNonBuiltinTypeEntry(pte); + } + } + if (types.size() == 1) return types; const auto typeEntryType = types.constFirst()->type(); const bool sameType = std::all_of(types.cbegin() + 1, types.cend(), - [typeEntryType](const TypeEntry *e) { + [typeEntryType](const TypeEntryCPtr &e) { return e->type() == typeEntryType; }); @@ -2167,10 +2366,10 @@ TypeEntries AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualified // Reverse lookup of AbstractMetaType representing a template specialization // found during traversing function arguments to its type system typedef'ed // class. -const AbstractMetaClass *AbstractMetaBuilderPrivate::resolveTypeSystemTypeDef(const AbstractMetaType &t) const +AbstractMetaClassCPtr AbstractMetaBuilderPrivate::resolveTypeSystemTypeDef(const AbstractMetaType &t) const { if (t.hasInstantiations()) { - auto pred = [t](const TypeClassEntry &e) { return e.type.equals(t); }; + auto pred = [t](const TypeClassEntry &e) { return e.type == t; }; auto it = std::find_if(m_typeSystemTypeDefs.cbegin(), m_typeSystemTypeDefs.cend(), pred); if (it != m_typeSystemTypeDefs.cend()) return it->klass; @@ -2178,9 +2377,194 @@ const AbstractMetaClass *AbstractMetaBuilderPrivate::resolveTypeSystemTypeDef(co return nullptr; } +// The below helpers and AbstractMetaBuilderPrivate::fixSmartPointers() +// synthesize missing smart pointer functions and classes. For example for +// std::shared_ptr, the full class declaration or base classes from +// internal, compiler-dependent STL implementation headers might not be exposed +// to the parser unless those headers are specified as <system-include>. + +static void synthesizeWarning(const AbstractMetaFunctionCPtr &f) +{ + qCWarning(lcShiboken, "Synthesizing \"%s\"...", + qPrintable(f->classQualifiedSignature())); +} + +static AbstractMetaFunctionPtr + addMethod(const AbstractMetaClassPtr &s, const AbstractMetaType &returnType, + const QString &name, bool isConst = true) +{ + auto function = std::make_shared<AbstractMetaFunction>(name); + function->setType(returnType); + AbstractMetaClass::addFunction(s, function); + function->setConstant(isConst); + synthesizeWarning(function); + return function; +} + +static AbstractMetaFunctionPtr + addMethod(const AbstractMetaClassPtr &s, const QString &returnTypeName, + const QString &name, bool isConst = true) +{ + auto typeEntry = TypeDatabase::instance()->findPrimitiveType(returnTypeName); + Q_ASSERT(typeEntry); + AbstractMetaType returnType(typeEntry); + returnType.decideUsagePattern(); + return addMethod(s, returnType, name, isConst); +} + +// Create the instantiation type of a smart pointer +static AbstractMetaType instantiationType(const AbstractMetaClassCPtr &s, + const SmartPointerTypeEntryCPtr &ste) +{ + AbstractMetaType type(s->templateArguments().constFirst()); + if (ste->smartPointerType() != TypeSystem::SmartPointerType::ValueHandle) + type.addIndirection(); + type.decideUsagePattern(); + return type; +} + +// Create the pointee argument of a smart pointer constructor or reset() +static AbstractMetaArgument pointeeArgument(const AbstractMetaClassCPtr &s, + const SmartPointerTypeEntryCPtr &ste) +{ + AbstractMetaArgument pointee; + pointee.setType(instantiationType(s, ste)); + pointee.setName(u"pointee"_s); + return pointee; +} + +// Add the smart pointer constructors. For MSVC, (when not specifying +// <system-header>), clang only sees the default constructor. +static void fixSmartPointerConstructors(const AbstractMetaClassPtr &s, + const SmartPointerTypeEntryCPtr &ste) +{ + const auto ctors = s->queryFunctions(FunctionQueryOption::Constructors); + bool seenDefaultConstructor = false; + bool seenParameter = false; + for (const auto &ctor : ctors) { + if (ctor->arguments().isEmpty()) + seenDefaultConstructor = true; + else + seenParameter = true; + } + + if (!seenParameter) { + auto constructor = std::make_shared<AbstractMetaFunction>(s->name()); + constructor->setFunctionType(AbstractMetaFunction::ConstructorFunction); + constructor->addArgument(pointeeArgument(s, ste)); + AbstractMetaClass::addFunction(s, constructor); + synthesizeWarning(constructor); + } + + if (!seenDefaultConstructor) { + auto constructor = std::make_shared<AbstractMetaFunction>(s->name()); + constructor->setFunctionType(AbstractMetaFunction::ConstructorFunction); + AbstractMetaClass::addFunction(s, constructor); + synthesizeWarning(constructor); + } +} + +// Similarly, add the smart pointer reset() functions +static void fixSmartPointerReset(const AbstractMetaClassPtr &s, + const SmartPointerTypeEntryCPtr &ste) +{ + const QString resetMethodName = ste->resetMethod(); + const auto functions = s->findFunctions(resetMethodName); + bool seenParameterLess = false; + bool seenParameter = false; + for (const auto &function : functions) { + if (function->arguments().isEmpty()) + seenParameterLess = true; + else + seenParameter = true; + } + + if (!seenParameter) { + auto f = std::make_shared<AbstractMetaFunction>(resetMethodName); + f->addArgument(pointeeArgument(s, ste)); + AbstractMetaClass::addFunction(s, f); + synthesizeWarning(f); + } + + if (!seenParameterLess) { + auto f = std::make_shared<AbstractMetaFunction>(resetMethodName); + AbstractMetaClass::addFunction(s, f); + synthesizeWarning(f); + } +} + +// Add the relevant missing smart pointer functions. +static void fixSmartPointerClass(const AbstractMetaClassPtr &s, + const SmartPointerTypeEntryCPtr &ste) +{ + fixSmartPointerConstructors(s, ste); + + if (!ste->resetMethod().isEmpty()) + fixSmartPointerReset(s, ste); + + const QString getterName = ste->getter(); + if (!s->findFunction(getterName)) + addMethod(s, instantiationType(s, ste), getterName); + + const QString refCountName = ste->refCountMethodName(); + if (!refCountName.isEmpty() && !s->findFunction(refCountName)) + addMethod(s, u"int"_s, refCountName); + + const QString valueCheckMethod = ste->valueCheckMethod(); + if (!valueCheckMethod.isEmpty() && !s->findFunction(valueCheckMethod)) { + auto f = addMethod(s, u"bool"_s, valueCheckMethod); + if (valueCheckMethod == u"operator bool") + f->setFunctionType(AbstractMetaFunction::ConversionOperator); + } + + const QString nullCheckMethod = ste->nullCheckMethod(); + if (!nullCheckMethod.isEmpty() && !s->findFunction(nullCheckMethod)) + addMethod(s, u"bool"_s, nullCheckMethod); +} + +// Create a missing smart pointer class +static AbstractMetaClassPtr createSmartPointerClass(const SmartPointerTypeEntryCPtr &ste, + const AbstractMetaClassList &allClasses) +{ + auto result = std::make_shared<AbstractMetaClass>(); + result->setTypeEntry(std::const_pointer_cast<SmartPointerTypeEntry>(ste)); + auto templateArg = std::make_shared<TemplateArgumentEntry>(u"T"_s, ste->version(), + typeSystemTypeEntry(ste)); + result->setTemplateArguments({templateArg}); + fixSmartPointerClass(result, ste); + auto enclosingTe = ste->parent(); + if (!enclosingTe->isTypeSystem()) { + const auto enclosing = AbstractMetaClass::findClass(allClasses, enclosingTe); + if (!enclosing) + throw Exception(msgEnclosingClassNotFound(ste)); + result->setEnclosingClass(enclosing); + auto inner = enclosing->innerClasses(); + inner.append(std::const_pointer_cast<const AbstractMetaClass>(result)); + enclosing->setInnerClasses(inner); + } + return result; +} + +void AbstractMetaBuilderPrivate::fixSmartPointers() +{ + const auto smartPointerTypes = TypeDatabase::instance()->smartPointerTypes(); + for (const auto &ste : smartPointerTypes) { + const auto smartPointerClass = + AbstractMetaClass::findClass(m_smartPointers, ste); + if (smartPointerClass) { + fixSmartPointerClass(std::const_pointer_cast<AbstractMetaClass>(smartPointerClass), + ste); + } else { + qCWarning(lcShiboken, "Synthesizing smart pointer \"%s\"...", + qPrintable(ste->qualifiedCppName())); + m_smartPointers.append(createSmartPointerClass(ste, m_metaClasses)); + } + } +} + std::optional<AbstractMetaType> AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei, - const AbstractMetaClass *currentClass, + const AbstractMetaClassCPtr ¤tClass, TranslateTypeFlags flags, QString *errorMessage) { @@ -2193,9 +2577,16 @@ static bool isNumber(const QString &s) [](QChar c) { return c.isDigit(); }); } +// A type entry relevant only for non type template "X<5>" +static bool isNonTypeTemplateArgument(const TypeEntryCPtr &te) +{ + const auto type = te->type(); + return type == TypeEntry::EnumValue || type == TypeEntry::ConstantValueType; +} + std::optional<AbstractMetaType> AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei, - const AbstractMetaClass *currentClass, + const AbstractMetaClassCPtr ¤tClass, AbstractMetaBuilderPrivate *d, TranslateTypeFlags flags, QString *errorMessageIn) @@ -2222,10 +2613,10 @@ std::optional<AbstractMetaType> // the global scope when they are referenced from inside a namespace. // This is a work around to fix this bug since fixing it in resolveType // seemed non-trivial - int i = d ? d->m_scopes.size() - 1 : -1; + qsizetype i = d ? d->m_scopes.size() - 1 : -1; while (i >= 0) { typeInfo = TypeInfo::resolveType(_typei, d->m_scopes.at(i--)); - if (typeInfo.qualifiedName().join(colonColon()) != _typei.qualifiedName().join(colonColon())) + if (typeInfo.qualifiedName().join(u"::"_s) != _typei.qualifiedName().join(u"::"_s)) break; } @@ -2233,7 +2624,7 @@ std::optional<AbstractMetaType> if (typeInfo.isFunctionPointer()) { if (errorMessageIn) - *errorMessageIn = msgUnableToTranslateType(_typei, QLatin1String("Unsupported function pointer.")); + *errorMessageIn = msgUnableToTranslateType(_typei, u"Unsupported function pointer."_s); return {}; } @@ -2249,7 +2640,7 @@ std::optional<AbstractMetaType> bool isConstCharStarCase = oneDimensionalArrayOfUnspecifiedSize && typeInfo.qualifiedName().size() == 1 - && typeInfo.qualifiedName().at(0) == QStringLiteral("char") + && typeInfo.qualifiedName().at(0) == "char"_L1 && typeInfo.indirections() == 0 && typeInfo.isConstant() && typeInfo.referenceType() == NoReference @@ -2273,13 +2664,13 @@ std::optional<AbstractMetaType> auto elementType = translateTypeStatic(newInfo, currentClass, d, flags, &errorMessage); if (!elementType.has_value()) { if (errorMessageIn) { - errorMessage.prepend(QLatin1String("Unable to translate array element: ")); + errorMessage.prepend(u"Unable to translate array element: "_s); *errorMessageIn = msgUnableToTranslateType(_typei, errorMessage); } return {}; } - for (int i = typeInfo.arrayElements().size() - 1; i >= 0; --i) { + for (auto i = typeInfo.arrayElements().size() - 1; i >= 0; --i) { AbstractMetaType arrayType; arrayType.setArrayElementType(elementType.value()); const QString &arrayElement = typeInfo.arrayElements().at(i); @@ -2292,8 +2683,9 @@ std::optional<AbstractMetaType> arrayType.setArrayElementCount(int(elems)); } auto elementTypeEntry = elementType->typeEntry(); - arrayType.setTypeEntry(new ArrayTypeEntry(elementTypeEntry, elementTypeEntry->version(), - elementTypeEntry->parent())); + auto at = std::make_shared<ArrayTypeEntry>(elementTypeEntry, elementTypeEntry->version(), + elementTypeEntry->parent()); + arrayType.setTypeEntry(at); arrayType.decideUsagePattern(); elementType = arrayType; @@ -2304,7 +2696,7 @@ std::optional<AbstractMetaType> QStringList qualifierList = typeInfo.qualifiedName(); if (qualifierList.isEmpty()) { - errorMessage = msgUnableToTranslateType(_typei, QLatin1String("horribly broken type")); + errorMessage = msgUnableToTranslateType(_typei, u"horribly broken type"_s); if (errorMessageIn) *errorMessageIn = errorMessage; else @@ -2312,23 +2704,32 @@ std::optional<AbstractMetaType> return {}; } - QString qualifiedName = qualifierList.join(colonColon()); + QString qualifiedName = qualifierList.join(u"::"_s); QString name = qualifierList.takeLast(); // 4. Special case QFlags (include instantiation in name) - if (qualifiedName == QLatin1String("QFlags")) { + if (qualifiedName == u"QFlags") { qualifiedName = typeInfo.toString(); typeInfo.clearInstantiations(); } - const TypeEntries types = findTypeEntries(qualifiedName, name, currentClass, d, errorMessageIn); + TypeEntryCList types = findTypeEntries(qualifiedName, name, flags, + currentClass, d, errorMessageIn); + if (!flags.testFlag(AbstractMetaBuilder::TemplateArgument)) { + // Avoid clashes between QByteArray and enum value QMetaType::QByteArray + // unless we are looking for template arguments. + auto end = std::remove_if(types.begin(), types.end(), + isNonTypeTemplateArgument); + types.erase(end, types.end()); + } + if (types.isEmpty()) { if (errorMessageIn != nullptr) *errorMessageIn = msgUnableToTranslateType(_typei, *errorMessageIn); return {}; } - const TypeEntry *type = types.constFirst(); + TypeEntryCPtr type = types.constFirst(); const TypeEntry::Type typeEntryType = type->type(); AbstractMetaType metaType; @@ -2339,15 +2740,18 @@ std::optional<AbstractMetaType> metaType.setOriginalTypeDescription(_typei.toString()); const auto &templateArguments = typeInfo.instantiations(); - for (int t = 0, size = templateArguments.size(); t < size; ++t) { + for (qsizetype t = 0, size = templateArguments.size(); t < size; ++t) { const TypeInfo &ti = templateArguments.at(t); - auto targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage); + auto targType = translateTypeStatic(ti, currentClass, d, + flags | AbstractMetaBuilder::TemplateArgument, + &errorMessage); // For non-type template parameters, create a dummy type entry on the fly // as is done for classes. if (!targType.has_value()) { - const QString value = ti.qualifiedName().join(colonColon()); + const QString value = ti.qualifiedName().join(u"::"_s); if (isNumber(value)) { - TypeDatabase::instance()->addConstantValueTypeEntry(value, type->typeSystemTypeEntry()); + auto module = typeSystemTypeEntry(type); + TypeDatabase::instance()->addConstantValueTypeEntry(value, module); targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage); } } @@ -2373,8 +2777,8 @@ std::optional<AbstractMetaType> type = instantiationType; } else { auto it = std::find_if(types.cbegin(), types.cend(), - [instantiationType](const TypeEntry *e) { - auto smartPtr = static_cast<const SmartPointerTypeEntry *>(e); + [instantiationType](const TypeEntryCPtr &e) { + auto smartPtr = std::static_pointer_cast<const SmartPointerTypeEntry>(e); return smartPtr->matchesInstantiation(instantiationType); }); if (it == types.cend()) { @@ -2408,7 +2812,7 @@ std::optional<AbstractMetaType> std::optional<AbstractMetaType> AbstractMetaBuilder::translateType(const TypeInfo &_typei, - AbstractMetaClass *currentClass, + const AbstractMetaClassPtr ¤tClass, TranslateTypeFlags flags, QString *errorMessage) { @@ -2419,7 +2823,7 @@ std::optional<AbstractMetaType> std::optional<AbstractMetaType> AbstractMetaBuilder::translateType(const QString &t, - AbstractMetaClass *currentClass, + const AbstractMetaClassPtr ¤tClass, TranslateTypeFlags flags, QString *errorMessageIn) { @@ -2442,14 +2846,14 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV if (ok) return value; - if (stringValue == QLatin1String("true") || stringValue == QLatin1String("false")) { + if (stringValue == u"true" || stringValue == u"false") { ok = true; - return (stringValue == QLatin1String("true")); + return (stringValue == u"true"); } // This is a very lame way to handle expression evaluation, // but it is not critical and will do for the time being. - static const QRegularExpression variableNameRegExp(QStringLiteral("^[a-zA-Z_][a-zA-Z0-9_]*$")); + static const QRegularExpression variableNameRegExp("^[a-zA-Z_][a-zA-Z0-9_]*$"_L1); Q_ASSERT(variableNameRegExp.isValid()); if (!variableNameRegExp.match(stringValue).hasMatch()) { ok = true; @@ -2462,7 +2866,7 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV return enumValue->value().value(); } - for (const AbstractMetaEnum &metaEnum : qAsConst(m_globalEnums)) { + for (const AbstractMetaEnum &metaEnum : std::as_const(m_globalEnums)) { auto ev = metaEnum.findEnumValue(stringValue); if (ev.has_value()) { ok = true; @@ -2474,113 +2878,163 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV return 0; } -QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &item, - const AbstractMetaType &type, - const AbstractMetaClass *implementingClass, - int /* argumentIndex */) +// Return whether candidate is some underqualified specification of qualifiedType +// ("B::C" should be qualified to "A::B::C") +static bool isUnderQualifiedSpec(QStringView qualifiedType, QStringView candidate) +{ + const auto candidateSize = candidate.size(); + const auto qualifiedTypeSize = qualifiedType.size(); + return candidateSize < qualifiedTypeSize + && qualifiedType.endsWith(candidate) + && qualifiedType.at(qualifiedTypeSize - candidateSize - 1) == u':'; +} + +QString AbstractMetaBuilder::fixEnumDefault(const AbstractMetaType &type, + const QString &expr, + const AbstractMetaClassCPtr &klass) const +{ + return d->fixEnumDefault(type, expr, klass); +} + +void AbstractMetaBuilder::setCodeModelTestMode(bool b) +{ + AbstractMetaBuilderPrivate::m_codeModelTestMode = b; +} + +// Helper to fix a simple default value (field or enum reference) in a +// class context. +QString AbstractMetaBuilderPrivate::fixSimpleDefaultValue(QStringView expr, + const AbstractMetaClassCPtr &klass) const +{ + const QString field = qualifyStaticField(klass, expr); + + if (!field.isEmpty()) + return field; + const auto cit = m_classToItem.constFind(klass); + if (cit == m_classToItem.cend()) + return {}; + auto *scope = dynamic_cast<const _ScopeModelItem *>(cit.value()); + if (!scope) + return {}; + if (auto enumValue = scope->findEnumByValue(expr)) + return enumValue.qualifiedName; + return {}; +} + +// see TestResolveType::testFixDefaultArguments() +QString AbstractMetaBuilderPrivate::fixDefaultValue(QString expr, const AbstractMetaType &type, + const AbstractMetaClassCPtr &implementingClass) const { - QString expr = item->defaultValueExpression(); - if (expr.isEmpty() || expr == u"{}") + expr.replace(u'\n', u' '); // breaks signature parser + + if (AbstractMetaBuilder::dontFixDefaultValue(expr)) return expr; - if (type.isPrimitive()) { - if (type.name() == QLatin1String("boolean")) { - if (expr != QLatin1String("false") && expr != QLatin1String("true")) { - bool ok = false; - int number = expr.toInt(&ok); - if (ok && number) - expr = QLatin1String("true"); - else - expr = QLatin1String("false"); - } - } else { - // This can be an enum or flag so I need to delay the - // translation until all namespaces are completely - // 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)); - } - } else if (type.isContainer() && expr.contains(QLatin1Char('<'))) { - static const QRegularExpression typeRegEx(QStringLiteral("[^<]*<(.*)>")); - Q_ASSERT(typeRegEx.isValid()); - const QRegularExpressionMatch typeMatch = typeRegEx.match(type.minimalSignature()); - static const QRegularExpression defaultRegEx(QLatin1String("([^<]*<).*(>[^>]*)")); - Q_ASSERT(defaultRegEx.isValid()); - const QRegularExpressionMatch defaultMatch = defaultRegEx.match(expr); - if (typeMatch.hasMatch() && defaultMatch.hasMatch()) - expr = defaultMatch.captured(1) + typeMatch.captured(1) + defaultMatch.captured(2); + if (type.isFlags() || type.isEnum()) { + expr = fixEnumDefault(type, expr, implementingClass); + } else if (type.isContainer() && expr.contains(u'<')) { + // Expand a container of a nested class, fex + // "QList<FormatRange>()" -> "QList<QTextLayout::FormatRange>()" + if (type.instantiations().size() != 1) + return expr; // Only simple types are handled, not QMap<int, int>. + auto innerTypeEntry = type.instantiations().constFirst().typeEntry(); + if (!innerTypeEntry->isComplex()) + return expr; + const QString &qualifiedInnerTypeName = innerTypeEntry->qualifiedCppName(); + if (!qualifiedInnerTypeName.contains(u"::")) // Nothing to qualify here + return expr; + const auto openPos = expr.indexOf(u'<'); + const auto closingPos = expr.lastIndexOf(u'>'); + if (openPos == -1 || closingPos == -1) + return expr; + const auto innerPos = openPos + 1; + const auto innerLen = closingPos - innerPos; + const auto innerType = QStringView{expr}.mid(innerPos, innerLen).trimmed(); + if (isUnderQualifiedSpec(qualifiedInnerTypeName, innerType)) + expr.replace(innerPos, innerLen, qualifiedInnerTypeName); } else { - // Here the default value is supposed to be a constructor, - // a class field, or a constructor receiving a class field - static const QRegularExpression defaultRegEx(QStringLiteral("([^\\(]*\\(|)([^\\)]*)(\\)|)")); - Q_ASSERT(defaultRegEx.isValid()); - const QRegularExpressionMatch defaultMatch = defaultRegEx.match(expr); - QString defaultValueCtorName = defaultMatch.hasMatch() ? defaultMatch.captured(1) : QString(); - if (defaultValueCtorName.endsWith(QLatin1Char('('))) - defaultValueCtorName.chop(1); - - // Fix the scope for constructor using the already resolved argument - // type as a reference. The following regular expression extracts any - // use of namespaces/scopes from the type string. - static const QRegularExpression - typeRegEx(QLatin1String(R"(^(?:const[\s]+|)([\w:]*::|)([A-Za-z_]\w*)\s*[&\*]?$)")); - Q_ASSERT(typeRegEx.isValid()); - const QRegularExpressionMatch typeMatch = typeRegEx.match(type.minimalSignature()); - - QString typeNamespace = typeMatch.hasMatch() ? typeMatch.captured(1) : QString(); - QString typeCtorName = typeMatch.hasMatch() ? typeMatch.captured(2) : QString(); - if (!typeNamespace.isEmpty() && defaultValueCtorName == typeCtorName) - expr.prepend(typeNamespace); - - // Fix scope if the parameter is a field of the current class - if (implementingClass) { - const AbstractMetaFieldList &fields = implementingClass->fields(); - for (const AbstractMetaField &field : fields) { - if (defaultMatch.hasMatch() && defaultMatch.captured(2) == field.name()) { - expr = defaultMatch.captured(1) + implementingClass->name() - + colonColon() + defaultMatch.captured(2) + defaultMatch.captured(3); - break; - } + // Here the default value is supposed to be a constructor, a class field, + // a constructor receiving a static class field or an enum. Consider + // class QSqlDatabase { ... + // static const char *defaultConnection; + // QSqlDatabase(const QString &connection = QLatin1String(defaultConnection)) + // -> = QLatin1String(QSqlDatabase::defaultConnection) + // static void foo(QSqlDatabase db = QSqlDatabase(defaultConnection)); + // -> = QSqlDatabase(QSqlDatabase::defaultConnection) + // + // Enum values from the class as defaults of int and others types (via + // implicit conversion) are handled here as well: + // class QStyleOption { ... + // enum StyleOptionType { Type = SO_Default }; + // QStyleOption(..., int type = SO_Default); + // -> = QStyleOption::StyleOptionType::SO_Default + + // Is this a single field or an enum? + if (isQualifiedCppIdentifier(expr)) { + const QString fixed = fixSimpleDefaultValue(expr, implementingClass); + return fixed.isEmpty() ? expr : fixed; + } + + // Is this sth like "QLatin1String(field)", "Class(Field)", "Class()"? + const auto parenPos = expr.indexOf(u'('); + if (parenPos == -1 || !expr.endsWith(u')')) + return expr; + // Is the term within parentheses a class field or enum? + const auto innerLength = expr.size() - parenPos - 2; + if (innerLength > 0) { // Not some function call "defaultFunc()" + const auto inner = QStringView{expr}.mid(parenPos + 1, innerLength); + if (isQualifiedCppIdentifier(inner) + && !AbstractMetaBuilder::dontFixDefaultValue(inner)) { + const QString replacement = fixSimpleDefaultValue(inner, implementingClass); + if (!replacement.isEmpty() && replacement != inner) + expr.replace(parenPos + 1, innerLength, replacement); } } + // Is this a class constructor "Class(Field)"? Expand it. + const auto te = type.typeEntry(); + if (!te->isComplex()) + return expr; + const QString &qualifiedTypeName = te->qualifiedCppName(); + if (!qualifiedTypeName.contains(u"::")) // Nothing to qualify here + return expr; + const auto className = QStringView{expr}.left(parenPos); + if (isUnderQualifiedSpec(qualifiedTypeName, className)) + expr.replace(0, className.size(), qualifiedTypeName); } return expr; } +QString AbstractMetaBuilder::fixDefaultValue(const QString &expr, const AbstractMetaType &type, + const AbstractMetaClassCPtr &c) const +{ + return d->fixDefaultValue(expr, type, c); +} + bool AbstractMetaBuilderPrivate::isEnum(const FileModelItem &dom, const QStringList& qualified_name) { CodeModelItem item = dom->model()->findItem(qualified_name, dom); return item && item->kind() == _EnumModelItem::__node_kind; } -AbstractMetaClass* AbstractMetaBuilderPrivate::findTemplateClass(const QString &name, - const AbstractMetaClass *context, - TypeInfo *info, - ComplexTypeEntry **baseContainerType) const +AbstractMetaClassPtr + AbstractMetaBuilderPrivate::findTemplateClass(const QString &name, + const AbstractMetaClassCPtr &context, + TypeInfo *info, + ComplexTypeEntryPtr *baseContainerType) const { if (baseContainerType) - *baseContainerType = nullptr; - TypeDatabase* types = TypeDatabase::instance(); + baseContainerType->reset(); + auto *types = TypeDatabase::instance(); - QStringList scope = context->typeEntry()->qualifiedCppName().split(colonColon()); + QStringList scope = context->typeEntry()->qualifiedCppName().split(u"::"_s); QString errorMessage; scope.removeLast(); - for (int i = scope.size(); i >= 0; --i) { - QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(colonColon()) + colonColon() : QString(); + for (auto i = scope.size(); i >= 0; --i) { + QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(u"::"_s) + u"::"_s : QString(); QString completeName = prefix + name; const TypeInfo parsed = TypeParser::parse(completeName, &errorMessage); - QString qualifiedName = parsed.qualifiedName().join(colonColon()); + QString qualifiedName = parsed.qualifiedName().join(u"::"_s); if (qualifiedName.isEmpty()) { qWarning().noquote().nospace() << "Unable to parse type \"" << completeName << "\" while looking for template \"" << name << "\": " << errorMessage; @@ -2589,8 +3043,8 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::findTemplateClass(const QString & if (info) *info = parsed; - AbstractMetaClass *templ = nullptr; - for (AbstractMetaClass *c : qAsConst(m_templates)) { + AbstractMetaClassPtr templ; + for (const auto &c : std::as_const(m_templates)) { if (c->typeEntry()->name() == qualifiedName) { templ = c; break; @@ -2610,19 +3064,18 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::findTemplateClass(const QString & return nullptr; } -AbstractMetaClassList AbstractMetaBuilderPrivate::getBaseClasses(const AbstractMetaClass *metaClass) const +AbstractMetaClassCList + AbstractMetaBuilderPrivate::getBaseClasses(const AbstractMetaClassCPtr &metaClass) const { // Shortcut if inheritance has already been set up if (metaClass->inheritanceDone() || !metaClass->needsInheritanceSetup()) return metaClass->baseClasses(); - AbstractMetaClassList baseClasses; + AbstractMetaClassCList baseClasses; const QStringList &baseClassNames = metaClass->baseClassNames(); for (const QString& parent : baseClassNames) { - AbstractMetaClass *cls = nullptr; - if (parent.contains(QLatin1Char('<'))) - cls = findTemplateClass(parent, metaClass); - else - cls = AbstractMetaClass::findClass(m_metaClasses, parent); + const auto cls = parent.contains(u'<') + ? findTemplateClass(parent, metaClass) + : AbstractMetaClass::findClass(m_metaClasses, parent); if (cls) baseClasses << cls; @@ -2642,7 +3095,7 @@ std::optional<AbstractMetaType> returned.setOriginalTemplateType(metaType); if (returned.typeEntry()->isTemplateArgument()) { - const auto *tae = static_cast<const TemplateArgumentEntry*>(returned.typeEntry()); + const auto tae = std::static_pointer_cast<const TemplateArgumentEntry>(returned.typeEntry()); // If the template is intantiated with void we special case this as rejecting the functions that use this // parameter from the instantiation. @@ -2660,7 +3113,7 @@ std::optional<AbstractMetaType> if (returned.hasInstantiations()) { AbstractMetaTypeList instantiations = returned.instantiations(); - for (int i = 0; i < instantiations.count(); ++i) { + for (qsizetype i = 0; i < instantiations.size(); ++i) { auto ins = inheritTemplateType(templateTypes, instantiations.at(i)); if (!ins.has_value()) return {}; @@ -2672,16 +3125,34 @@ std::optional<AbstractMetaType> return returned; } -bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, - const AbstractMetaClass *templateClass, +AbstractMetaClassPtr + AbstractMetaBuilder::inheritTemplateClass(const ComplexTypeEntryPtr &te, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaTypeList &templateTypes, + InheritTemplateFlags flags) +{ + auto result = std::make_shared<AbstractMetaClass>(); + result->setTypeDef(true); + + result->setTypeEntry(te); + if (!AbstractMetaBuilderPrivate::inheritTemplate(result, templateClass, + templateTypes, flags)) { + return {}; + } + AbstractMetaBuilderPrivate::inheritTemplateFunctions(result); + return result; +} + +bool AbstractMetaBuilderPrivate::inheritTemplate(const AbstractMetaClassPtr &subclass, + const AbstractMetaClassCPtr &templateClass, const TypeInfo &info) { AbstractMetaTypeList templateTypes; for (const TypeInfo &i : info.instantiations()) { - QString typeName = i.qualifiedName().join(colonColon()); + QString typeName = i.qualifiedName().join(u"::"_s); TypeDatabase *typeDb = TypeDatabase::instance(); - TypeEntry *t = nullptr; + TypeEntryPtr t; // Check for a non-type template integer parameter, that is, for a base // "template <int R, int C> Matrix<R, C>" and subclass // "typedef Matrix<2,3> Matrix2x3;". If so, create dummy entries of @@ -2689,18 +3160,18 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, if (isNumber(typeName)) { t = typeDb->findType(typeName); if (!t) { - auto parent = subclass->typeEntry()->typeSystemTypeEntry(); + auto parent = typeSystemTypeEntry(subclass->typeEntry()); t = TypeDatabase::instance()->addConstantValueTypeEntry(typeName, parent); } } else { QStringList possibleNames; - possibleNames << subclass->qualifiedCppName() + colonColon() + typeName; - possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName; + possibleNames << subclass->qualifiedCppName() + u"::"_s + typeName; + possibleNames << templateClass->qualifiedCppName() + u"::"_s + typeName; if (subclass->enclosingClass()) - possibleNames << subclass->enclosingClass()->qualifiedCppName() + colonColon() + typeName; + possibleNames << subclass->enclosingClass()->qualifiedCppName() + u"::"_s + typeName; possibleNames << typeName; - for (const QString &possibleName : qAsConst(possibleNames)) { + for (const QString &possibleName : std::as_const(possibleNames)) { t = typeDb->findType(possibleName); if (t) break; @@ -2720,36 +3191,147 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, << info.toString() << ". The corresponding type was not found in the typesystem."; } } + return inheritTemplate(subclass, templateClass, templateTypes); +} +bool AbstractMetaBuilderPrivate::inheritTemplate(const AbstractMetaClassPtr &subclass, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaTypeList &templateTypes, + InheritTemplateFlags flags) +{ subclass->setTemplateBaseClass(templateClass); + if (flags.testFlag(InheritTemplateFlag::SetEnclosingClass)) + subclass->setEnclosingClass(templateClass->enclosingClass()); subclass->setTemplateBaseClassInstantiations(templateTypes); subclass->setBaseClass(templateClass->baseClass()); return true; } -static bool inheritTemplateFunction(const AbstractMetaFunctionCPtr &function, - const AbstractMetaFunctionCList &existingSubclassFuncs, - const AbstractMetaClass *subclass, - const AbstractMetaClass *templateBaseClass) +AbstractMetaFunctionPtr + AbstractMetaBuilderPrivate::inheritTemplateFunction(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes) +{ + AbstractMetaFunctionPtr f(function->copy()); + f->setArguments(AbstractMetaArgumentList()); + f->setFlags(f->flags() | AbstractMetaFunction::Flag::InheritedFromTemplate); + + if (!function->isVoid()) { + auto returnType = inheritTemplateType(templateTypes, function->type()); + if (!returnType.has_value()) + return {}; + f->setType(returnType.value()); + } + + const AbstractMetaArgumentList &arguments = function->arguments(); + for (const AbstractMetaArgument &argument : arguments) { + auto argType = inheritTemplateType(templateTypes, argument.type()); + if (!argType.has_value()) + return {}; + AbstractMetaArgument arg = argument; + arg.setType(argType.value()); + f->addArgument(arg); + } + + return f; +} + +AbstractMetaFunctionPtr + AbstractMetaBuilder::inheritTemplateFunction(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes) +{ + return AbstractMetaBuilderPrivate::inheritTemplateFunction(function, templateTypes); +} + +AbstractMetaFunctionPtr + AbstractMetaBuilderPrivate::inheritTemplateMember(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaClassPtr &subclass) +{ + AbstractMetaFunctionPtr f = inheritTemplateFunction(function, templateTypes); + if (!f) + return {}; + + // There is no base class in the target language to inherit from here, so + // the template instantiation is the class that implements the function. + f->setImplementingClass(subclass); + + // We also set it as the declaring class, since the superclass is + // supposed to disappear. This allows us to make certain function modifications + // on the inherited functions. + f->setDeclaringClass(subclass); + + if (f->isConstructor()) { + f->setName(subclass->name()); + f->setOriginalName(subclass->name()); + } + + ComplexTypeEntryPtr te = subclass->typeEntry(); + const FunctionModificationList mods = function->modifications(templateClass); + + for (auto mod : mods) { + mod.setSignature(f->minimalSignature()); + +// If we ever need it... Below is the code to do +// substitution of the template instantation type inside +// injected code.. +#if 0 + if (mod.modifiers & Modification::CodeInjection) { + for (int j = 0; j < template_types.size(); ++j) { + CodeSnip &snip = mod.snips.last(); + QString code = snip.code(); + code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j), + template_types.at(j)->typeEntry()->qualifiedCppName()); + snip.codeList.clear(); + snip.addCode(code); + } + } +#endif + te->addFunctionModification(mod); + } + + QString errorMessage; + if (!applyArrayArgumentModifications(f->modifications(subclass), f.get(), + &errorMessage)) { + qCWarning(lcShiboken, "While specializing %s (%s): %s", + qPrintable(subclass->name()), qPrintable(templateClass->name()), + qPrintable(errorMessage)); + } + return f; +} + +AbstractMetaFunctionPtr + AbstractMetaBuilder::inheritTemplateMember(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaClassPtr &subclass) +{ + return AbstractMetaBuilderPrivate::inheritTemplateMember(function, templateTypes, + templateClass, subclass); +} + +static bool doInheritTemplateFunction(const AbstractMetaFunctionCPtr &function, + const AbstractMetaFunctionCList &existingSubclassFuncs, + const AbstractMetaClassCPtr &templateBaseClass, + const AbstractMetaClassCPtr &subclass) { // If the function is modified or the instantiation has an equally named // function we are shadowing, so we need to skip it (unless the subclass // declares it via "using"). if (function->isModifiedRemoved()) return false; + if (function->isConstructor() && !subclass->isTypeDef()) + return false; return AbstractMetaFunction::find(existingSubclassFuncs, function->name()) == nullptr || subclass->isUsingMember(templateBaseClass, function->name(), Access::Protected); } -void AbstractMetaBuilderPrivate::inheritTemplateFunctions(AbstractMetaClass *subclass) +void AbstractMetaBuilderPrivate::inheritTemplateFunctions(const AbstractMetaClassPtr &subclass) { - QString errorMessage; auto templateClass = subclass->templateBaseClass(); if (subclass->isTypeDef()) { - subclass->setHasCloneOperator(templateClass->hasCloneOperator()); - subclass->setHasEqualsOperator(templateClass->hasEqualsOperator()); - subclass->setHasHashFunction(templateClass->hasHashFunction()); + subclass->setHashFunction(templateClass->hashFunction()); subclass->setHasNonPrivateConstructor(templateClass->hasNonPrivateConstructor()); subclass->setHasPrivateDestructor(templateClass->hasPrivateDestructor()); subclass->setHasProtectedDestructor(templateClass->hasProtectedDestructor()); @@ -2761,82 +3343,13 @@ void AbstractMetaBuilderPrivate::inheritTemplateFunctions(AbstractMetaClass *sub subclass->functions(); // Take copy const auto &templateClassFunctions = templateClass->functions(); for (const auto &function : templateClassFunctions) { - if (!inheritTemplateFunction(function, existingSubclassFuncs, - subclass, templateClass)) { - continue; - } - - std::unique_ptr<AbstractMetaFunction> f(function->copy()); - f->setArguments(AbstractMetaArgumentList()); - - if (!function->isVoid()) { - auto returnType = inheritTemplateType(templateTypes, function->type()); - if (!returnType.has_value()) - continue; - f->setType(returnType.value()); - } - - const AbstractMetaArgumentList &arguments = function->arguments(); - for (const AbstractMetaArgument &argument : arguments) { - auto argType = inheritTemplateType(templateTypes, argument.type()); - if (!argType.has_value()) - break; - AbstractMetaArgument arg = argument; - arg.setType(argType.value()); - f->addArgument(arg); - } - - if (f->arguments().size() < function->arguments().size()) - continue; - - // There is no base class in the target language to inherit from here, so - // the template instantiation is the class that implements the function. - f->setImplementingClass(subclass); - - // We also set it as the declaring class, since the superclass is - // supposed to disappear. This allows us to make certain function modifications - // on the inherited functions. - f->setDeclaringClass(subclass); - - if (f->isConstructor()) { - if (!subclass->isTypeDef()) - continue; - f->setName(subclass->name()); - f->setOriginalName(subclass->name()); - } - - ComplexTypeEntry* te = subclass->typeEntry(); - FunctionModificationList mods = function->modifications(templateClass); - for (int i = 0; i < mods.size(); ++i) { - FunctionModification mod = mods.at(i); - mod.setSignature(f->minimalSignature()); - - // If we ever need it... Below is the code to do - // substitution of the template instantation type inside - // injected code.. -#if 0 - if (mod.modifiers & Modification::CodeInjection) { - for (int j = 0; j < template_types.size(); ++j) { - CodeSnip &snip = mod.snips.last(); - QString code = snip.code(); - code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j), - template_types.at(j)->typeEntry()->qualifiedCppName()); - snip.codeList.clear(); - snip.addCode(code); - } - } -#endif - te->addFunctionModification(mod); + if (doInheritTemplateFunction(function, existingSubclassFuncs, + templateClass, subclass)) { + AbstractMetaFunctionCPtr f = inheritTemplateMember(function, templateTypes, + templateClass, subclass); + if (f) + AbstractMetaClass::addFunction(subclass, f); } - - - if (!applyArrayArgumentModifications(f->modifications(subclass), f.get(), - &errorMessage)) { - qCWarning(lcShiboken, "While specializing %s (%s): %s", - qPrintable(subclass->name()), qPrintable(templateClass->name()), - qPrintable(errorMessage)); - } - subclass->addFunction(AbstractMetaFunctionCPtr(f.release())); } // Take copy @@ -2845,8 +3358,7 @@ void AbstractMetaBuilderPrivate::inheritTemplateFunctions(AbstractMetaClass *sub for (const AbstractMetaField &field : templateClassFields) { // If the field is modified or the instantiation has a field named // the same as an existing field we have shadowing, so we need to skip it. - if (field.isModifiedRemoved(TypeSystem::All) - || field.isStatic() + if (field.isModifiedRemoved() || field.isStatic() || AbstractMetaField::find(existingSubclassFields, field.name()).has_value()) { continue; } @@ -2861,7 +3373,7 @@ void AbstractMetaBuilderPrivate::inheritTemplateFunctions(AbstractMetaClass *sub } } -void AbstractMetaBuilderPrivate::parseQ_Properties(AbstractMetaClass *metaClass, +void AbstractMetaBuilderPrivate::parseQ_Properties(const AbstractMetaClassPtr &metaClass, const QStringList &declarations) { const QStringList scopes = currentScope()->qualifiedName(); @@ -2872,7 +3384,7 @@ void AbstractMetaBuilderPrivate::parseQ_Properties(AbstractMetaClass *metaClass, if (spec.has_value()) { spec->setIndex(i); metaClass->addPropertySpec(spec.value()); - } else { + } else if (!errorMessage.isEmpty()) { QString message; QTextStream str(&message); str << metaClass->sourceLocation() << errorMessage; @@ -2901,63 +3413,35 @@ void AbstractMetaBuilderPrivate::parseQ_Properties(AbstractMetaClass *metaClass, } } -static AbstractMetaFunctionCPtr findCopyCtor(AbstractMetaClass* cls) -{ - for (const auto &f : cls->functions()) { - const AbstractMetaFunction::FunctionType t = f->functionType(); - if (t == AbstractMetaFunction::CopyConstructorFunction || t == AbstractMetaFunction::AssignmentOperatorFunction) - return f; - } - return {}; -} - -void AbstractMetaBuilderPrivate::setupClonable(AbstractMetaClass *cls) -{ - bool result = true; - - // find copy ctor for the current class - auto copyCtor = findCopyCtor(cls); - if (!copyCtor.isNull()) { // if exists a copy ctor in this class - result = copyCtor->isPublic(); - } else { // else... lets find one in the parent class - QQueue<AbstractMetaClass*> baseClasses; - if (cls->baseClass()) - baseClasses.enqueue(cls->baseClass()); - - while (!baseClasses.isEmpty()) { - AbstractMetaClass* currentClass = baseClasses.dequeue(); - if (currentClass->baseClass()) - baseClasses.enqueue(currentClass->baseClass()); - - copyCtor = findCopyCtor(currentClass); - if (copyCtor) { - result = copyCtor->isPublic(); - break; - } - } - } - cls->setHasCloneOperator(result); -} - -void AbstractMetaBuilderPrivate::setupExternalConversion(AbstractMetaClass *cls) +void AbstractMetaBuilderPrivate::setupExternalConversion(const AbstractMetaClassCPtr &cls) { const auto &convOps = cls->operatorOverloads(OperatorQueryOption::ConversionOp); for (const auto &func : convOps) { if (func->isModifiedRemoved()) continue; - AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, func->type().typeEntry()); + const auto metaClass = + AbstractMetaClass::findClass(m_metaClasses, func->type().typeEntry()); if (!metaClass) continue; metaClass->addExternalConversionOperator(func); } - const AbstractMetaClassList &innerClasses = cls->innerClasses(); - for (AbstractMetaClass *innerClass : innerClasses) + for (const auto &innerClass : cls->innerClasses()) setupExternalConversion(innerClass); } static void writeRejectLogFile(const QString &name, - const QMap<QString, AbstractMetaBuilder::RejectReason> &rejects) -{ + const AbstractMetaBuilderPrivate::RejectSet &rejects) +{ + static const QHash<AbstractMetaBuilder::RejectReason, QByteArray> descriptions ={ + {AbstractMetaBuilder::NotInTypeSystem, "Not in type system"_ba}, + {AbstractMetaBuilder::GenerationDisabled, "Generation disabled by type system"_ba}, + {AbstractMetaBuilder::RedefinedToNotClass, "Type redefined to not be a class"_ba}, + {AbstractMetaBuilder::UnmatchedReturnType, "Unmatched return type"_ba}, + {AbstractMetaBuilder::UnmatchedArgumentType, "Unmatched argument type"_ba}, + {AbstractMetaBuilder::UnmatchedOperator, "Unmatched operator"_ba}, + {AbstractMetaBuilder::Deprecated, "Deprecated"_ba} + }; + QFile f(name); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { qCWarning(lcShiboken, "%s", qPrintable(msgCannotOpenForWriting(f))); @@ -2966,70 +3450,37 @@ static void writeRejectLogFile(const QString &name, QTextStream s(&f); - - for (int reason = 0; reason < AbstractMetaBuilder::NoReason; ++reason) { - s << QString(72, QLatin1Char('*')) << Qt::endl; - switch (reason) { - case AbstractMetaBuilder::NotInTypeSystem: - s << "Not in type system"; - break; - case AbstractMetaBuilder::GenerationDisabled: - s << "Generation disabled by type system"; - break; - case AbstractMetaBuilder::RedefinedToNotClass: - s << "Type redefined to not be a class"; - break; - - case AbstractMetaBuilder::UnmatchedReturnType: - s << "Unmatched return type"; - break; - - case AbstractMetaBuilder::UnmatchedArgumentType: - s << "Unmatched argument type"; - break; - - case AbstractMetaBuilder::ApiIncompatible: - s << "Incompatible API"; - break; - - case AbstractMetaBuilder::Deprecated: - s << "Deprecated"; - break; - - default: - s << "unknown reason"; - break; + int lastReason = -1; + for (const auto &e : rejects) { + if (e.reason != lastReason) { + const QByteArray description = descriptions.value(e.reason, "Unknown reason"_ba); + const QByteArray underline(description.size(), '*'); + if (lastReason != -1) + s << '\n'; + s << underline << '\n' << description << '\n' << underline << "\n\n"; + lastReason = e.reason; } - s << Qt::endl; - - for (QMap<QString, AbstractMetaBuilder::RejectReason>::const_iterator it = rejects.constBegin(); - it != rejects.constEnd(); ++it) { - if (it.value() != reason) - continue; - s << " - " << it.key() << Qt::endl; - } - - s << QString(72, QLatin1Char('*')) << Qt::endl << Qt::endl; + s << " - " << e << '\n'; } - } void AbstractMetaBuilderPrivate::dumpLog() const { - writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_classes.log"), m_rejectedClasses); - writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_enums.log"), m_rejectedEnums); - writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_functions.log"), m_rejectedFunctions); - writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_fields.log"), m_rejectedFields); + writeRejectLogFile(m_logDirectory + u"mjb_rejected_classes.log"_s, m_rejectedClasses); + writeRejectLogFile(m_logDirectory + u"mjb_rejected_enums.log"_s, m_rejectedEnums); + writeRejectLogFile(m_logDirectory + u"mjb_rejected_functions.log"_s, m_rejectedFunctions); + writeRejectLogFile(m_logDirectory + u"mjb_rejected_fields.log"_s, m_rejectedFields); } -using ClassGraph = Graph<AbstractMetaClass *>; - -// Add a dependency of the class associated with typeEntry on clazz -static bool addClassDependency(const AbstractMetaClassList &classList, - const TypeEntry *typeEntry, - AbstractMetaClass *clazz, - ClassGraph *graph) +// Topological sorting of classes. Templates for use with +// AbstractMetaClassList/AbstractMetaClassCList. +// Add a dependency of the class associated with typeEntry on clazz. +template <class MetaClass> +static bool addClassDependency(const QList<std::shared_ptr<MetaClass> > &classList, + const TypeEntryCPtr &typeEntry, + std::shared_ptr<MetaClass> clazz, + Graph<std::shared_ptr<MetaClass> > *graph) { if (!typeEntry->isComplex() || typeEntry == clazz->typeEntry()) return false; @@ -3039,10 +3490,12 @@ static bool addClassDependency(const AbstractMetaClassList &classList, return graph->addEdge(c, clazz); } -AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClassList &classList, - const Dependencies &additionalDependencies) +template <class MetaClass> +static QList<std::shared_ptr<MetaClass> > + topologicalSortHelper(const QList<std::shared_ptr<MetaClass> > &classList, + const Dependencies &additionalDependencies) { - ClassGraph graph(classList.cbegin(), classList.cend()); + Graph<std::shared_ptr<MetaClass> > graph(classList.cbegin(), classList.cend()); for (const auto &dep : additionalDependencies) { if (!graph.addEdge(dep.parent, dep.child)) { @@ -3052,14 +3505,14 @@ AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const } } - for (AbstractMetaClass *clazz : classList) { + for (const auto &clazz : classList) { if (auto enclosingC = clazz->enclosingClass()) { - auto enclosing = const_cast<AbstractMetaClass *>(enclosingC); + const auto enclosing = std::const_pointer_cast<MetaClass>(enclosingC); graph.addEdge(enclosing, clazz); } - for (auto baseClass : clazz->baseClasses()) - graph.addEdge(baseClass, clazz); + for (const auto &baseClass : clazz->baseClasses()) + graph.addEdge(std::const_pointer_cast<MetaClass>(baseClass), clazz); for (const auto &func : clazz->functions()) { const AbstractMetaArgumentList &arguments = func->arguments(); @@ -3085,24 +3538,44 @@ AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const const auto result = graph.topologicalSort(); if (!result.isValid() && graph.nodeCount()) { - QTemporaryFile tempFile(QDir::tempPath() + QLatin1String("/cyclic_depXXXXXX.dot")); + QTemporaryFile tempFile(QDir::tempPath() + u"/cyclic_depXXXXXX.dot"_s); tempFile.setAutoRemove(false); - tempFile.open(); - graph.dumpDot(tempFile.fileName(), - [] (const AbstractMetaClass *c) { return c->name(); }); + const bool ok = tempFile.open(); + if (ok) { + graph.dumpDot(tempFile.fileName(), + [] (const AbstractMetaClassCPtr &c) { return c->name(); }); + } QString message; QTextStream str(&message); str << "Cyclic dependency of classes found:"; - for (auto c : result.cyclic) + for (const auto &c : result.cyclic) str << ' ' << c->name(); - str << ". Graph can be found at \"" << QDir::toNativeSeparators(tempFile.fileName()) << '"'; + str << '.'; + if (ok) { + str << " Graph can be found at \"" + << QDir::toNativeSeparators(tempFile.fileName()) << '"'; + } qCWarning(lcShiboken, "%s", qPrintable(message)); } return result.result; } +AbstractMetaClassList + AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClassList &classList, + const Dependencies &additionalDependencies) +{ + return topologicalSortHelper(classList, additionalDependencies); +} + +AbstractMetaClassCList + AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClassCList &classList, + const Dependencies &additionalDependencies) +{ + return topologicalSortHelper(classList, additionalDependencies); +} + void AbstractMetaBuilderPrivate::pushScope(const NamespaceModelItem &item) { // For purposes of type lookup, join all namespaces of the same name @@ -3116,8 +3589,8 @@ void AbstractMetaBuilderPrivate::pushScope(const NamespaceModelItem &item) } } if (candidates.size() > 1) { - NamespaceModelItem joined(new _NamespaceModelItem(m_scopes.constLast()->model(), - name, _CodeModelItem::Kind_Namespace)); + auto joined = std::make_shared<_NamespaceModelItem>(m_scopes.constLast()->model(), + name, _CodeModelItem::Kind_Namespace); joined->setScope(item->scope()); for (const auto &n : candidates) joined->appendNamespace(*n); @@ -3127,21 +3600,6 @@ void AbstractMetaBuilderPrivate::pushScope(const NamespaceModelItem &item) } } -AbstractMetaArgumentList AbstractMetaBuilderPrivate::reverseList(const AbstractMetaArgumentList &list) -{ - AbstractMetaArgumentList ret; - - int index = list.size(); - for (const AbstractMetaArgument &a : list) { - AbstractMetaArgument arg = a; - arg.setArgumentIndex(index); - ret.prepend(arg); - index--; - } - - return ret; -} - void AbstractMetaBuilder::setGlobalHeaders(const QFileInfoList &globalHeaders) { d->m_globalHeaders = globalHeaders; @@ -3165,13 +3623,18 @@ void AbstractMetaBuilder::setSkipDeprecated(bool value) d->m_skipDeprecated = value; } +void AbstractMetaBuilder::setApiExtractorFlags(ApiExtractorFlags flags) +{ + d->m_apiExtractorFlags = flags; +} + // PYSIDE-975: When receiving an absolute path name from the code model, try // to resolve it against the include paths set on shiboken in order to recreate // relative paths like #include <foo/bar.h>. static inline bool isFileSystemSlash(QChar c) { - return c == QLatin1Char('/') || c == QLatin1Char('\\'); + return c == u'/' || c == u'\\'; } static bool matchHeader(const QString &headerPath, const QString &fileName) @@ -3181,13 +3644,13 @@ static bool matchHeader(const QString &headerPath, const QString &fileName) #else static const Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; #endif - const int pathSize = headerPath.size(); + const auto pathSize = headerPath.size(); return fileName.size() > pathSize && isFileSystemSlash(fileName.at(pathSize)) && fileName.startsWith(headerPath, caseSensitivity); } -void AbstractMetaBuilderPrivate::setInclude(TypeEntry *te, const QString &path) const +void AbstractMetaBuilderPrivate::setInclude(const TypeEntryPtr &te, const QString &path) const { auto it = m_resolveIncludeHash.find(path); if (it == m_resolveIncludeHash.end()) { @@ -3235,9 +3698,9 @@ void AbstractMetaBuilder::formatDebug(QDebug &debug) const debug << "m_globalHeader=" << d->m_globalHeaders; debugFormatSequence(debug, "globalEnums", d->m_globalEnums, "\n"); debugFormatSequence(debug, "globalFunctions", d->m_globalFunctions, "\n"); - if (const int scopeCount = d->m_scopes.size()) { + if (const auto scopeCount = d->m_scopes.size()) { debug << "\n scopes[" << scopeCount << "]=("; - for (int i = 0; i < scopeCount; ++i) { + for (qsizetype i = 0; i < scopeCount; ++i) { if (i) debug << ", "; _CodeModelItem::formatKind(debug, d->m_scopes.at(i)->kind()); diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder.h index 97c324f51..cbd8c7034 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.h +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.h @@ -1,41 +1,18 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETABUILDER_H #define ABSTRACTMETABUILDER_H #include "abstractmetalang_typedefs.h" +#include "apiextractorflags.h" #include "header_paths.h" #include "typesystem_enums.h" +#include "typesystem_typedefs.h" #include "clangparser/compilersupport.h" -#include <QFileInfoList> +#include <QtCore/QFileInfoList> #include <optional> @@ -45,19 +22,22 @@ class AbstractMetaBuilderPrivate; class AbstractMetaClass; class AbstractMetaType; class AbstractMetaEnumValue; +class ComplexTypeEntry; class TypeInfo; class TypeEntry; class AbstractMetaBuilder { public: + Q_DISABLE_COPY_MOVE(AbstractMetaBuilder) + enum RejectReason { NotInTypeSystem, GenerationDisabled, RedefinedToNotClass, UnmatchedArgumentType, UnmatchedReturnType, - ApiIncompatible, + UnmatchedOperator, Deprecated, NoReason }; @@ -66,13 +46,18 @@ public: virtual ~AbstractMetaBuilder(); const AbstractMetaClassList &classes() const; + AbstractMetaClassList takeClasses(); const AbstractMetaClassList &templates() const; + AbstractMetaClassList takeTemplates(); const AbstractMetaClassList &smartPointers() const; + AbstractMetaClassList takeSmartPointers(); const AbstractMetaFunctionCList &globalFunctions() const; const AbstractMetaEnumList &globalEnums() const; - const QHash<const TypeEntry *, AbstractMetaEnum> &typeEntryToEnumsHash() const; + const QHash<TypeEntryCPtr, AbstractMetaEnum> &typeEntryToEnumsHash() const; + const QMultiHash<QString, QString> &typedefTargetToName() const; bool build(const QByteArrayList &arguments, + ApiExtractorFlags apiExtractorFlags = {}, bool addCompilerSupportArguments = true, LanguageLevel level = LanguageLevel::Default, unsigned clangFlags = 0); @@ -90,23 +75,66 @@ public: void setSkipDeprecated(bool value); + void setApiExtractorFlags(ApiExtractorFlags flags); + enum TranslateTypeFlag { - DontResolveType = 0x1 + DontResolveType = 0x1, + TemplateArgument = 0x2, + NoClassScopeLookup = 0x4 }; Q_DECLARE_FLAGS(TranslateTypeFlags, TranslateTypeFlag); static std::optional<AbstractMetaType> - translateType(const TypeInfo &_typei, AbstractMetaClass *currentClass = nullptr, + translateType(const TypeInfo &_typei, const AbstractMetaClassPtr ¤tClass = {}, TranslateTypeFlags flags = {}, QString *errorMessage = nullptr); static std::optional<AbstractMetaType> - translateType(const QString &t, AbstractMetaClass *currentClass = nullptr, + translateType(const QString &t, const AbstractMetaClassPtr ¤tClass = {}, TranslateTypeFlags flags = {}, QString *errorMessage = nullptr); + /// Performs a template specialization of the function. + /// \param function Function + /// \param templateTypes Instantiation types + /// \return Specialized copy of the function + static AbstractMetaFunctionPtr + inheritTemplateFunction(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes); + + static AbstractMetaClassPtr + inheritTemplateClass(const ComplexTypeEntryPtr &te, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaTypeList &templateTypes, + InheritTemplateFlags flags = {}); + + /// Performs a template specialization of the member function. + /// \param function Member function + /// \param templateTypes Instantiation types + /// \param templateClass Template class + /// \param subclass Specialized class + /// \return Specialized copy of the function + static AbstractMetaFunctionPtr + inheritTemplateMember(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaClassPtr &subclass); + static QString getSnakeCaseName(const QString &name); // Names under which an item will be registered to Python depending on snakeCase static QStringList definitionNames(const QString &name, TypeSystem::SnakeCase snakeCase); + static QString resolveScopePrefix(const AbstractMetaClassCPtr &scope, + QStringView value); + + static bool dontFixDefaultValue(QStringView expr); + + // For testing purposes + QString fixDefaultValue(const QString &expr, const AbstractMetaType &type, + const AbstractMetaClassCPtr &) const; + QString fixEnumDefault(const AbstractMetaType &type, const QString &expr, + const AbstractMetaClassCPtr & = {}) const; + + static void setCodeModelTestMode(bool b); + #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..68eef737a --- /dev/null +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder_helpers.cpp @@ -0,0 +1,202 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "abstractmetabuilder.h" +#include "abstractmetabuilder_p.h" +#include "abstractmetaenum.h" +#include "abstractmetafield.h" +#include "abstractmetalang.h" +#include "enumtypeentry.h" +#include "flagstypeentry.h" + +using namespace Qt::StringLiterals; + +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"::"_s; + if (value.startsWith(prefix)) + name.clear(); + else + name.prepend(prefix); + } + return name; +} + +QString AbstractMetaBuilder::resolveScopePrefix(const AbstractMetaClassCPtr &scope, + QStringView value) +{ + if (!scope) + return {}; + const QString &qualifiedCppName = scope->qualifiedCppName(); + const QStringViewList scopeList = + QStringView{qualifiedCppName}.split(u"::"_s, Qt::SkipEmptyParts); + return resolveScopePrefixHelper(scopeList, value); +} + +// Return the scope for fully qualifying the enumeration value +static QString resolveEnumValueScopePrefix(const AbstractMetaEnum &metaEnum, + QStringView value) +{ + AbstractMetaClassCPtr 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"::"_s, 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); +} + +bool AbstractMetaBuilderPrivate::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 isIntegerConstant(const QStringView expr) +{ + bool isNumber; + auto n = expr.toInt(&isNumber, /* guess base: 0x or decimal */ 0); + Q_UNUSED(n); + return isNumber; +} + +static bool isFloatConstant(const QStringView expr) +{ + bool isNumber; + auto d = expr.toDouble(&isNumber); + Q_UNUSED(d); + 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 AbstractMetaClassCPtr &klass) const +{ + // QFlags construct from integers, do not fix that + if (isIntegerConstant(expr)) + return expr; + + const QString field = qualifyStaticField(klass, expr); + if (!field.isEmpty()) + return field; + + const auto typeEntry = type.typeEntry(); + EnumTypeEntryCPtr enumTypeEntry; + FlagsTypeEntryCPtr flagsTypeEntry; + if (typeEntry->isFlags()) { + flagsTypeEntry = std::static_pointer_cast<const FlagsTypeEntry>(typeEntry); + enumTypeEntry = flagsTypeEntry->originator(); + } else { + Q_ASSERT(typeEntry->isEnum()); + enumTypeEntry = std::static_pointer_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 (isIntegerConstant(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 (!isIntegerConstant(token) && isQualifiedCppIdentifier(token)) + qualified.prepend(resolveEnumValueScopePrefix(metaEnum, token)); + qualifiedTokens.append(qualified); + } + const QString qualifiedExpression = qualifiedTokens.join(u" | "_s); + if (!typeCast) + return qualifiedExpression; + + result.replace(parenPos + 1, innerExpression.size(), qualifiedExpression); + return result; +} + +bool AbstractMetaBuilder::dontFixDefaultValue(QStringView expr) +{ + return expr.isEmpty() || expr == u"{}" || expr == u"nullptr" + || expr == u"NULL" || expr == u"true" || expr == u"false" + || (expr.startsWith(u'{') && expr.startsWith(u'}')) // initializer list + || (expr.startsWith(u'[') && expr.startsWith(u']')) // array + || expr.startsWith(u"Qt::") // Qt namespace constant + || isIntegerConstant(expr) || isFloatConstant(expr); +} + +QString AbstractMetaBuilderPrivate::qualifyStaticField(const AbstractMetaClassCPtr &c, + QStringView field) +{ + if (!c || c->fields().isEmpty()) + return {}; + // If there is a scope, ensure it matches the class + const auto lastQualifier = field.lastIndexOf(u"::"); + if (lastQualifier != -1 + && !c->qualifiedCppName().endsWith(field.left(lastQualifier))) { + return {}; + } + const auto fieldName = lastQualifier != -1 + ? field.mid(lastQualifier + 2) : field; + const auto fieldOpt = c->findField(fieldName); + if (!fieldOpt.has_value() || !fieldOpt.value().isStatic()) + return {}; + return AbstractMetaBuilder::resolveScopePrefix(c, field) + field.toString(); +} diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h index bcfd7bc73..d7aaba5b0 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETABUILDER_P_H #define ABSTRACTMETABUILDER_P_H @@ -35,24 +10,38 @@ #include "abstractmetalang.h" #include "abstractmetatype.h" #include "include.h" -#include "modifications.h" #include "typeparser.h" +#include "modifications_typedefs.h" +#include "typesystem_typedefs.h" -#include <QSet> -#include <QFileInfo> -#include <QList> +#include <QtCore/QFileInfo> +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QMultiHash> +#include <QtCore/QSet> #include <optional> +#include <set> class TypeDatabase; +struct RejectEntry +{ + AbstractMetaBuilder::RejectReason reason; + QString signature; + QString sortkey; + QString message; +}; + +bool operator<(const RejectEntry &re1, const RejectEntry &re2); + class AbstractMetaBuilderPrivate { public: struct TypeClassEntry { AbstractMetaType type; - const AbstractMetaClass *klass; + AbstractMetaClassCPtr klass; }; using TranslateTypeFlags = AbstractMetaBuilder::TranslateTypeFlags; @@ -60,74 +49,88 @@ public: Q_DISABLE_COPY(AbstractMetaBuilderPrivate) AbstractMetaBuilderPrivate(); - ~AbstractMetaBuilderPrivate(); static FileModelItem buildDom(QByteArrayList arguments, bool addCompilerSupportArguments, LanguageLevel level, unsigned clangFlags); - void traverseDom(const FileModelItem &dom); + void traverseDom(const FileModelItem &dom, ApiExtractorFlags flags); void dumpLog() const; - static AbstractMetaClassList classesTopologicalSorted(const AbstractMetaClassList &classList, - const Dependencies &additionalDependencies = {}); + + static AbstractMetaClassList + classesTopologicalSorted(const AbstractMetaClassList &classList, + const Dependencies &additionalDependencies = {}); + static AbstractMetaClassCList + classesTopologicalSorted(const AbstractMetaClassCList &classList, + const Dependencies &additionalDependencies = {}); + NamespaceModelItem popScope() { return m_scopes.takeLast(); } void pushScope(const NamespaceModelItem &item); NamespaceModelItem currentScope() const { return m_scopes.constLast(); } - AbstractMetaClass *argumentToClass(const ArgumentModelItem &, - const AbstractMetaClass *currentClass); + AbstractMetaClassPtr argumentToClass(const ArgumentModelItem &, + const AbstractMetaClassCPtr ¤tClass); - void addAbstractMetaClass(AbstractMetaClass *cls, const _CodeModelItem *item); - AbstractMetaClass *traverseTypeDef(const FileModelItem &dom, + void addAbstractMetaClass(const AbstractMetaClassPtr &cls, const _CodeModelItem *item); + AbstractMetaClassPtr traverseTypeDef(const FileModelItem &dom, const TypeDefModelItem &typeDef, - AbstractMetaClass *currentClass); + const AbstractMetaClassPtr ¤tClass); + AbstractMetaClassPtr traverseTypeDefHelper(const FileModelItem &dom, + const TypeDefModelItem &typeDef, + const AbstractMetaClassPtr ¤tClass); void traverseTypesystemTypedefs(); - AbstractMetaClass *traverseClass(const FileModelItem &dom, + AbstractMetaClassPtr traverseClass(const FileModelItem &dom, const ClassModelItem &item, - AbstractMetaClass *currentClass); - void traverseScopeMembers(const ScopeModelItem &item, AbstractMetaClass *metaClass); + const AbstractMetaClassPtr ¤tClass); + void traverseScopeMembers(const ScopeModelItem &item, + const AbstractMetaClassPtr &metaClass); void traverseClassMembers(const ClassModelItem &scopeItem); - void traverseUsingMembers(AbstractMetaClass *metaClass); + void traverseUsingMembers(const AbstractMetaClassPtr &metaClass) const; void traverseNamespaceMembers(const NamespaceModelItem &scopeItem); - bool setupInheritance(AbstractMetaClass *metaClass); - AbstractMetaClass *traverseNamespace(const FileModelItem &dom, + bool setupInheritance(const AbstractMetaClassPtr &metaClass); + AbstractMetaClassPtr traverseNamespace(const FileModelItem &dom, const NamespaceModelItem &item); std::optional<AbstractMetaEnum> traverseEnum(const EnumModelItem &item, - AbstractMetaClass *enclosing, + const AbstractMetaClassPtr &enclosing, const QSet<QString> &enumsDeclarations); - void traverseEnums(const ScopeModelItem &item, AbstractMetaClass *parent, + void traverseEnums(const ScopeModelItem &item, const AbstractMetaClassPtr &parent, const QStringList &enumsDeclarations); AbstractMetaFunctionRawPtrList classFunctionList(const ScopeModelItem &scopeItem, AbstractMetaClass::Attributes *constructorAttributes, - AbstractMetaClass *currentClass); - void traverseFunctions(ScopeModelItem item, AbstractMetaClass *parent); + const AbstractMetaClassPtr ¤tClass); + void traverseFunctions(const ScopeModelItem& item, + const AbstractMetaClassPtr &parent); static void applyFunctionModifications(AbstractMetaFunction *func); - void traverseFields(const ScopeModelItem &item, AbstractMetaClass *parent); + void traverseFields(const ScopeModelItem &item, const AbstractMetaClassPtr &parent); bool traverseStreamOperator(const FunctionModelItem &functionItem, - AbstractMetaClass *currentClass); + const AbstractMetaClassPtr ¤tClass); void traverseOperatorFunction(const FunctionModelItem &item, - AbstractMetaClass *currentClass); + const AbstractMetaClassPtr ¤tClass); AbstractMetaFunction *traverseAddedFunctionHelper(const AddedFunctionPtr &addedFunc, - AbstractMetaClass *metaClass, + const AbstractMetaClassPtr &metaClass, QString *errorMessage); bool traverseAddedGlobalFunction(const AddedFunctionPtr &addedFunc, QString *errorMessage); bool traverseAddedMemberFunction(const AddedFunctionPtr &addedFunc, - AbstractMetaClass *metaClass, + const AbstractMetaClassPtr &metaClass, QString *errorMessage); - AbstractMetaFunction *traverseFunction(const FunctionModelItem &function, - AbstractMetaClass *currentClass); + void rejectFunction(const FunctionModelItem &functionItem, + const AbstractMetaClassPtr ¤tClass, + AbstractMetaBuilder::RejectReason reason, + const QString &rejectReason); + AbstractMetaFunction *traverseFunction(const FunctionModelItem &function, + const AbstractMetaClassPtr ¤tClass); std::optional<AbstractMetaField> traverseField(const VariableModelItem &field, - const AbstractMetaClass *cls); - void checkFunctionModifications(); + const AbstractMetaClassCPtr &cls); + void checkFunctionModifications() const; void registerHashFunction(const FunctionModelItem &functionItem, - AbstractMetaClass *currentClass); + const AbstractMetaClassPtr ¤tClass); void registerToStringCapabilityIn(const NamespaceModelItem &namespaceItem); void registerToStringCapability(const FunctionModelItem &functionItem, - AbstractMetaClass *currentClass); + const AbstractMetaClassPtr ¤tClass); /** * A conversion operator function should not have its owner class as @@ -141,45 +144,67 @@ public: */ static void fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction); - void parseQ_Properties(AbstractMetaClass *metaClass, const QStringList &declarations); - void setupEquals(AbstractMetaClass *metaClass); - void setupComparable(AbstractMetaClass *metaClass); - static void setupClonable(AbstractMetaClass *cls); - void setupExternalConversion(AbstractMetaClass *cls); - static void setupFunctionDefaults(AbstractMetaFunction *metaFunction, - AbstractMetaClass *metaClass); - - static QString fixDefaultValue(const ArgumentModelItem &item, - const AbstractMetaType &type, - const AbstractMetaClass *, - int argumentIndex); + void parseQ_Properties(const AbstractMetaClassPtr &metaClass, + const QStringList &declarations); + void setupEquals(const AbstractMetaClassPtr &metaClass); + void setupComparable(const AbstractMetaClassPtr &metaClass); + void setupExternalConversion(const AbstractMetaClassCPtr &cls); + + static bool isQualifiedCppIdentifier(QStringView e); + QString fixDefaultValue(QString expr, const AbstractMetaType &type, + const AbstractMetaClassCPtr &) const; + QString fixSimpleDefaultValue(QStringView expr, + const AbstractMetaClassCPtr &klass) const; + + QString fixEnumDefault(const AbstractMetaType &type, const QString &expr, + const AbstractMetaClassCPtr &) const; + /// Qualify a static field name for default value expressions + static QString qualifyStaticField(const AbstractMetaClassCPtr &c, QStringView field); + std::optional<AbstractMetaType> - translateType(const TypeInfo &type, const AbstractMetaClass *currentClass, + translateType(const TypeInfo &type, const AbstractMetaClassCPtr ¤tClass, TranslateTypeFlags flags = {}, QString *errorMessage = nullptr); static std::optional<AbstractMetaType> - translateTypeStatic(const TypeInfo &type, const AbstractMetaClass *current, + translateTypeStatic(const TypeInfo &type, const AbstractMetaClassCPtr ¤t, AbstractMetaBuilderPrivate *d = nullptr, TranslateTypeFlags flags = {}, QString *errorMessageIn = nullptr); - static TypeEntries findTypeEntriesHelper(const QString &qualifiedName, const QString &name, - const AbstractMetaClass *currentClass = nullptr, - AbstractMetaBuilderPrivate *d = nullptr); - static TypeEntries findTypeEntries(const QString &qualifiedName, const QString &name, - const AbstractMetaClass *currentClass = nullptr, - AbstractMetaBuilderPrivate *d = nullptr, - QString *errorMessage = nullptr); + static TypeEntryCList findTypeEntriesHelper(const QString &qualifiedName, const QString &name, + TranslateTypeFlags flags = {}, + const AbstractMetaClassCPtr ¤tClass = {}, + AbstractMetaBuilderPrivate *d = nullptr); + static TypeEntryCList findTypeEntries(const QString &qualifiedName, const QString &name, + TranslateTypeFlags flags = {}, + const AbstractMetaClassCPtr ¤tClass = {}, + AbstractMetaBuilderPrivate *d = nullptr, + QString *errorMessage = nullptr); qint64 findOutValueFromString(const QString &stringValue, bool &ok); - AbstractMetaClass *findTemplateClass(const QString& name, const AbstractMetaClass *context, - TypeInfo *info = Q_NULLPTR, - ComplexTypeEntry **baseContainerType = Q_NULLPTR) const; - AbstractMetaClassList getBaseClasses(const AbstractMetaClass *metaClass) const; + AbstractMetaClassPtr findTemplateClass(const QString& name, const AbstractMetaClassCPtr &context, + TypeInfo *info = nullptr, + ComplexTypeEntryPtr *baseContainerType = nullptr) const; + AbstractMetaClassCList getBaseClasses(const AbstractMetaClassCPtr &metaClass) const; - static bool inheritTemplate(AbstractMetaClass *subclass, - const AbstractMetaClass *templateClass, + static bool inheritTemplate(const AbstractMetaClassPtr &subclass, + const AbstractMetaClassCPtr &templateClass, const TypeInfo &info); - void inheritTemplateFunctions(AbstractMetaClass *subclass); - std::optional<AbstractMetaType> + static bool inheritTemplate(const AbstractMetaClassPtr &subclass, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaTypeList &templateTypes, + InheritTemplateFlags flags = {}); + + static AbstractMetaFunctionPtr + inheritTemplateFunction(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes); + + static AbstractMetaFunctionPtr + inheritTemplateMember(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaClassPtr &subclass); + + static void inheritTemplateFunctions(const AbstractMetaClassPtr &subclass); + static std::optional<AbstractMetaType> inheritTemplateType(const AbstractMetaTypeList &templateTypes, const AbstractMetaType &metaType); @@ -187,30 +212,31 @@ public: static bool isEnum(const FileModelItem &dom, const QStringList &qualifiedName); void sortLists(); - static AbstractMetaArgumentList reverseList(const AbstractMetaArgumentList &list); - void setInclude(TypeEntry *te, const QString &path) const; + void setInclude(const TypeEntryPtr &te, const QString &path) const; static void fixArgumentNames(AbstractMetaFunction *func, const FunctionModificationList &mods); - void fillAddedFunctions(AbstractMetaClass *metaClass); - const AbstractMetaClass *resolveTypeSystemTypeDef(const AbstractMetaType &t) const; + void fillAddedFunctions(const AbstractMetaClassPtr &metaClass); + AbstractMetaClassCPtr resolveTypeSystemTypeDef(const AbstractMetaType &t) const; + + void fixSmartPointers(); - AbstractMetaBuilder *q; + AbstractMetaBuilder *q = nullptr; AbstractMetaClassList m_metaClasses; AbstractMetaClassList m_templates; AbstractMetaClassList m_smartPointers; - QHash<const _CodeModelItem *, AbstractMetaClass *> m_itemToClass; - QHash<const AbstractMetaClass *, const _CodeModelItem *> m_classToItem; + QHash<const _CodeModelItem *, AbstractMetaClassPtr > m_itemToClass; + QHash<AbstractMetaClassCPtr, const _CodeModelItem *> m_classToItem; AbstractMetaFunctionCList m_globalFunctions; AbstractMetaEnumList m_globalEnums; - using RejectMap = QMap<QString, AbstractMetaBuilder::RejectReason>; + using RejectSet = std::set<RejectEntry>; - RejectMap m_rejectedClasses; - RejectMap m_rejectedEnums; - RejectMap m_rejectedFunctions; - RejectMap m_rejectedFields; + RejectSet m_rejectedClasses; + RejectSet m_rejectedEnums; + RejectSet m_rejectedFunctions; + RejectSet m_rejectedFields; - QHash<const TypeEntry *, AbstractMetaEnum> m_enums; + QHash<TypeEntryCPtr, AbstractMetaEnum> m_enums; QList<NamespaceModelItem> m_scopes; @@ -218,9 +244,12 @@ public: QFileInfoList m_globalHeaders; QStringList m_headerPaths; mutable QHash<QString, Include> m_resolveIncludeHash; + QMultiHash<QString, QString> m_typedefTargetToName; QList<TypeClassEntry> m_typeSystemTypeDefs; // look up metatype->class for type system typedefs + ApiExtractorFlags m_apiExtractorFlags; bool m_skipDeprecated = false; static bool m_useGlobalHeader; + static bool m_codeModelTestMode; }; #endif // ABSTRACTMETBUILDER_P_H diff --git a/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp b/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp index ad64e58b9..780170c22 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp @@ -1,39 +1,20 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "abstractmetaenum.h" #include "abstractmetalang.h" #include "documentation.h" -#include "typesystem.h" +#include "enumtypeentry.h" #include "parser/enumvalue.h" +#include "qtcompat.h" + #include <QtCore/QDebug> +#include <algorithm> + +using namespace Qt::StringLiterals; + class AbstractMetaEnumValueData : public QSharedData { public: @@ -41,6 +22,7 @@ public: QString m_stringValue; EnumValue m_value; Documentation m_doc; + bool m_deprecated = false; }; AbstractMetaEnumValue::AbstractMetaEnumValue() : @@ -50,8 +32,8 @@ AbstractMetaEnumValue::AbstractMetaEnumValue() : AbstractMetaEnumValue::AbstractMetaEnumValue(const AbstractMetaEnumValue &) = default; AbstractMetaEnumValue &AbstractMetaEnumValue::operator=(const AbstractMetaEnumValue &) = default; -AbstractMetaEnumValue::AbstractMetaEnumValue(AbstractMetaEnumValue &&) = default; -AbstractMetaEnumValue &AbstractMetaEnumValue::operator=(AbstractMetaEnumValue &&) = default; +AbstractMetaEnumValue::AbstractMetaEnumValue(AbstractMetaEnumValue &&) noexcept = default; +AbstractMetaEnumValue &AbstractMetaEnumValue::operator=(AbstractMetaEnumValue &&) noexcept = default; AbstractMetaEnumValue::~AbstractMetaEnumValue() = default; EnumValue AbstractMetaEnumValue::value() const @@ -87,6 +69,17 @@ void AbstractMetaEnumValue::setName(const QString &name) d->m_name = name; } +bool AbstractMetaEnumValue::isDeprecated() const +{ + return d->m_deprecated; +} + +void AbstractMetaEnumValue::setDeprecated(bool deprecated) +{ + if (d->m_deprecated != deprecated) + d->m_deprecated = deprecated; +} + Documentation AbstractMetaEnumValue::documentation() const { return d->m_doc; @@ -103,29 +96,67 @@ void AbstractMetaEnumValue::setDocumentation(const Documentation &doc) class AbstractMetaEnumData : public QSharedData { public: - AbstractMetaEnumData() : m_hasQenumsDeclaration(false), m_signed(true) + AbstractMetaEnumData() : m_deprecated(false), + m_hasQenumsDeclaration(false), m_signed(true) { } + int unsignedUsedBits() const; + int signedUsedBits() const; + AbstractMetaEnumValueList m_enumValues; - EnumTypeEntry *m_typeEntry = nullptr; + EnumTypeEntryCPtr m_typeEntry; Documentation m_doc; + QString m_underlyingType; EnumKind m_enumKind = CEnum; Access m_access = Access::Public; + uint m_deprecated : 1; uint m_hasQenumsDeclaration : 1; uint m_signed : 1; }; +static int _usedBits(uint64_t v) +{ + return (v >> 32) ? 64 : (v >> 16) ? 32 : (v >> 8) ? 16 : 8; +} + +static int _usedBits(int64_t v) +{ + return (v >> 31) ? 64 : (v >> 15) ? 32 : (v >> 7) ? 16 : 8; +} + +int AbstractMetaEnumData::unsignedUsedBits() const +{ + uint64_t maxValue = 0; + for (const auto &v : m_enumValues) { + if (const auto uv = v.value().unsignedValue(); uv > maxValue) + maxValue = uv; + } + return _usedBits(maxValue); +} + +int AbstractMetaEnumData::signedUsedBits() const +{ + int64_t maxValue = 0; + for (const auto &v : m_enumValues) { + const auto sv = v.value().value(); + const auto absV = sv < 0 ? ~sv : sv; + if (absV > maxValue) + maxValue = absV; + } + return _usedBits(maxValue); +} + AbstractMetaEnum::AbstractMetaEnum() : d(new AbstractMetaEnumData) { } AbstractMetaEnum::AbstractMetaEnum(const AbstractMetaEnum &) = default; AbstractMetaEnum &AbstractMetaEnum::operator=(const AbstractMetaEnum&) = default; -AbstractMetaEnum::AbstractMetaEnum(AbstractMetaEnum &&) = default; -AbstractMetaEnum &AbstractMetaEnum::operator=(AbstractMetaEnum &&) = default; +AbstractMetaEnum::AbstractMetaEnum(AbstractMetaEnum &&) noexcept = default; +AbstractMetaEnum &AbstractMetaEnum::operator=(AbstractMetaEnum &&) noexcept = default; AbstractMetaEnum::~AbstractMetaEnum() = default; const AbstractMetaEnumValueList &AbstractMetaEnum::values() const @@ -133,6 +164,16 @@ const AbstractMetaEnumValueList &AbstractMetaEnum::values() const return d->m_enumValues; } +AbstractMetaEnumValueList AbstractMetaEnum::nonRejectedValues() const +{ + auto te = d->m_typeEntry; + AbstractMetaEnumValueList result = d->m_enumValues; + auto pred = [te](const AbstractMetaEnumValue &v) { + return te->isEnumValueRejected(v.name()); }; + result.erase(std::remove_if(result.begin(), result.end(), pred), result.end()); + return result; +} + void AbstractMetaEnum::addEnumValue(const AbstractMetaEnumValue &enumValue) { d->m_enumValues << enumValue; @@ -154,7 +195,7 @@ std::optional<AbstractMetaEnumValue> { if (isAnonymous()) return findMatchingEnumValue(d->m_enumValues, value); - const int sepPos = value.indexOf(QLatin1String("::")); + const int sepPos = value.indexOf(u"::"); if (sepPos == -1) return findMatchingEnumValue(d->m_enumValues, value); if (name() == value.left(sepPos)) @@ -170,7 +211,7 @@ QString AbstractMetaEnum::name() const QString AbstractMetaEnum::qualifiedCppName() const { return enclosingClass() - ? enclosingClass()->qualifiedCppName() + QLatin1String("::") + name() + ? enclosingClass()->qualifiedCppName() + u"::"_s + name() : name(); } @@ -185,6 +226,36 @@ void AbstractMetaEnum::setAccess(Access a) d->m_access = a; } +bool AbstractMetaEnum::isDeprecated() const +{ + return d->m_deprecated; +} + +void AbstractMetaEnum::setDeprecated(bool deprecated) +{ + if (d->m_deprecated != deprecated) + d->m_deprecated = deprecated; +} + +static bool isDeprecatedValue(const AbstractMetaEnumValue &v) +{ + return v.isDeprecated(); +}; + +bool AbstractMetaEnum::hasDeprecatedValues() const +{ + return std::any_of(d->m_enumValues.cbegin(), d->m_enumValues.cend(), + isDeprecatedValue); +} + +AbstractMetaEnumValueList AbstractMetaEnum::deprecatedValues() const +{ + AbstractMetaEnumValueList result; + std::copy_if(d->m_enumValues.cbegin(), d->m_enumValues.cend(), + std::back_inserter(result), isDeprecatedValue); + return result; +} + const Documentation &AbstractMetaEnum::documentation() const { return d->m_doc; @@ -208,7 +279,7 @@ QString AbstractMetaEnum::package() const QString AbstractMetaEnum::fullName() const { - return package() + QLatin1Char('.') + qualifier() + QLatin1Char('.') + name(); + return package() + u'.' + qualifier() + u'.' + name(); } EnumKind AbstractMetaEnum::enumKind() const @@ -238,12 +309,12 @@ void AbstractMetaEnum::setHasQEnumsDeclaration(bool on) d->m_hasQenumsDeclaration = on; } -EnumTypeEntry *AbstractMetaEnum::typeEntry() const +EnumTypeEntryCPtr AbstractMetaEnum::typeEntry() const { return d->m_typeEntry; } -void AbstractMetaEnum::setTypeEntry(EnumTypeEntry *entry) +void AbstractMetaEnum::setTypeEntry(const EnumTypeEntryCPtr &entry) { if (d->m_typeEntry != entry) d->m_typeEntry = entry; @@ -260,14 +331,39 @@ void AbstractMetaEnum::setSigned(bool s) d->m_signed = s; } +QString AbstractMetaEnum::underlyingType() const +{ + return d->m_underlyingType; +} + +void AbstractMetaEnum::setUnderlyingType(const QString &underlyingType) +{ + if (d->m_underlyingType != underlyingType) + d->m_underlyingType = underlyingType; +} + +int AbstractMetaEnum::usedBits() const +{ + return isSigned() ? d->signedUsedBits() : d->unsignedUsedBits(); +} + +QString AbstractMetaEnum::intTypeForSize(int usedBits, bool isSigned) +{ + QString result = u"int"_s + QString::number(usedBits) + u"_t"_s; + return isSigned ? result : u'u' + result; +} + #ifndef QT_NO_DEBUG_STREAM -static void formatMetaEnumValue(QDebug &d, const AbstractMetaEnumValue &v) +static void formatMetaEnumValue(QDebug &d, const AbstractMetaEnumValue &v, bool forceHex = false) { - const QString &name = v.stringValue(); - if (!name.isEmpty()) - d << name << '='; - d << v.value(); + d << v.name() << '='; + if (forceHex) + v.value().formatDebugHex(d); + else + v.value().formatDebug(d); + if (v.isDeprecated()) + d << " (deprecated)"; } QDebug operator<<(QDebug d, const AbstractMetaEnumValue &v) @@ -283,15 +379,19 @@ QDebug operator<<(QDebug d, const AbstractMetaEnumValue &v) static void formatMetaEnum(QDebug &d, const AbstractMetaEnum &e) { - d << e.fullName(); + d << '"' << e.fullName() << '"'; + if (e.isDeprecated()) + d << " (deprecated)"; + d << " \"" << e.underlyingType() << '"'; if (!e.isSigned()) - d << " (unsigned) "; - d << '['; + d << " (unsigned)"; + d << " ["; const AbstractMetaEnumValueList &values = e.values(); - for (int i = 0, count = values.size(); i < count; ++i) { + const bool hasFlags = e.typeEntry()->flags() != nullptr; + for (qsizetype i = 0, count = values.size(); i < count; ++i) { if (i) - d << ' '; - formatMetaEnumValue(d, values.at(i)); + d << ", "; + formatMetaEnumValue(d, values.at(i), hasFlags); } d << ']'; } diff --git a/sources/shiboken6/ApiExtractor/abstractmetaenum.h b/sources/shiboken6/ApiExtractor/abstractmetaenum.h index 2cf949f15..03d7a3082 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetaenum.h +++ b/sources/shiboken6/ApiExtractor/abstractmetaenum.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETAENUM_H #define ABSTRACTMETAENUM_H @@ -32,6 +7,7 @@ #include "abstractmetalang_typedefs.h" #include "enclosingclassmixin.h" #include "parser/codemodel_enums.h" +#include "typesystem_typedefs.h" #include <QtCore/QSharedDataPointer> #include <QtCore/QString> @@ -52,8 +28,8 @@ public: AbstractMetaEnumValue(); AbstractMetaEnumValue(const AbstractMetaEnumValue &); AbstractMetaEnumValue &operator=(const AbstractMetaEnumValue &); - AbstractMetaEnumValue(AbstractMetaEnumValue &&); - AbstractMetaEnumValue &operator=(AbstractMetaEnumValue &&); + AbstractMetaEnumValue(AbstractMetaEnumValue &&) noexcept; + AbstractMetaEnumValue &operator=(AbstractMetaEnumValue &&) noexcept; ~AbstractMetaEnumValue(); EnumValue value() const; @@ -65,9 +41,14 @@ public: QString name() const; void setName(const QString &name); + bool isDeprecated() const; + void setDeprecated(bool deprecated); + Documentation documentation() const; void setDocumentation(const Documentation& doc); + int usedBits() const; + private: QSharedDataPointer<AbstractMetaEnumValueData> d; }; @@ -78,11 +59,12 @@ public: AbstractMetaEnum(); AbstractMetaEnum(const AbstractMetaEnum &); AbstractMetaEnum &operator=(const AbstractMetaEnum &); - AbstractMetaEnum(AbstractMetaEnum &&); - AbstractMetaEnum &operator=(AbstractMetaEnum &&); + AbstractMetaEnum(AbstractMetaEnum &&) noexcept; + AbstractMetaEnum &operator=(AbstractMetaEnum &&) noexcept; ~AbstractMetaEnum(); const AbstractMetaEnumValueList &values() const; + AbstractMetaEnumValueList nonRejectedValues() const; void addEnumValue(const AbstractMetaEnumValue &enumValue); std::optional<AbstractMetaEnumValue> findEnumValue(QStringView value) const; @@ -95,6 +77,11 @@ public: bool isPrivate() const { return access() == Access::Private; } bool isProtected() const { return access() == Access::Protected; } + bool isDeprecated() const; + void setDeprecated(bool deprecated); + bool hasDeprecatedValues() const; + AbstractMetaEnumValueList deprecatedValues() const; + const Documentation &documentation() const; void setDocumentation(const Documentation& doc); @@ -113,12 +100,18 @@ public: bool hasQEnumsDeclaration() const; void setHasQEnumsDeclaration(bool on); - EnumTypeEntry *typeEntry() const; - void setTypeEntry(EnumTypeEntry *entry); + EnumTypeEntryCPtr typeEntry() const; + void setTypeEntry(const EnumTypeEntryCPtr &entry); bool isSigned() const; void setSigned(bool s); + QString underlyingType() const; + void setUnderlyingType(const QString &underlyingType); + + static QString intTypeForSize(int usedBits, bool isSigned); + int usedBits() const; + private: QSharedDataPointer<AbstractMetaEnumData> d; }; diff --git a/sources/shiboken6/ApiExtractor/abstractmetafield.cpp b/sources/shiboken6/ApiExtractor/abstractmetafield.cpp index 44e8ddc84..27a76d04d 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetafield.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetafield.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "abstractmetafield.h" #include "abstractmetabuilder.h" @@ -32,11 +7,16 @@ #include "abstractmetatype.h" #include "documentation.h" #include "modifications.h" -#include "typesystem.h" +#include "complextypeentry.h" +#include "typesystemtypeentry.h" #include "parser/codemodel.h" +#include "qtcompat.h" + #include <QtCore/QDebug> +using namespace Qt::StringLiterals; + class AbstractMetaFieldData : public QSharedData { public: @@ -56,15 +36,15 @@ AbstractMetaField::AbstractMetaField() : d(new AbstractMetaFieldData) AbstractMetaField::AbstractMetaField(const AbstractMetaField &) = default; AbstractMetaField &AbstractMetaField::operator=(const AbstractMetaField &) = default; -AbstractMetaField::AbstractMetaField(AbstractMetaField &&) = default; -AbstractMetaField &AbstractMetaField::operator=(AbstractMetaField &&) = default; +AbstractMetaField::AbstractMetaField(AbstractMetaField &&) noexcept = default; +AbstractMetaField &AbstractMetaField::operator=(AbstractMetaField &&) noexcept = default; AbstractMetaField::~AbstractMetaField() = default; // returned->setEnclosingClass(nullptr); std::optional<AbstractMetaField> AbstractMetaField::find(const AbstractMetaFieldList &haystack, - const QString &needle) + QStringView needle) { for (const auto &f : haystack) { if (f.name() == needle) @@ -76,7 +56,7 @@ std::optional<AbstractMetaField> /******************************************************************************* * Indicates that this field has a modification that removes it */ -bool AbstractMetaField::isModifiedRemoved(int types) const +bool AbstractMetaField::isModifiedRemoved() const { const FieldModificationList &mods = modifications(); for (const FieldModification &mod : mods) { @@ -87,6 +67,16 @@ bool AbstractMetaField::isModifiedRemoved(int types) const return false; } +bool AbstractMetaField::generateOpaqueContainer() const +{ + const FieldModificationList &mods = modifications(); + for (const FieldModification &mod : mods) { + if (mod.isOpaqueContainer()) + return true; + } + return false; +} + const AbstractMetaType &AbstractMetaField::type() const { return d->m_type; @@ -133,7 +123,7 @@ void AbstractMetaField::setStatic(bool s) QString AbstractMetaField::qualifiedCppName() const { - return enclosingClass()->qualifiedCppName() + QLatin1String("::") + return enclosingClass()->qualifiedCppName() + u"::"_s + originalName(); } @@ -212,7 +202,7 @@ TypeSystem::SnakeCase AbstractMetaField::snakeCase() const auto typeEntry = enclosingClass()->typeEntry(); const auto snakeCase = typeEntry->snakeCase(); return snakeCase != TypeSystem::SnakeCase::Unspecified - ? snakeCase : typeEntry->typeSystemTypeEntry()->snakeCase(); + ? snakeCase : typeSystemTypeEntry(typeEntry)->snakeCase(); } FieldModificationList AbstractMetaField::modifications() const diff --git a/sources/shiboken6/ApiExtractor/abstractmetafield.h b/sources/shiboken6/ApiExtractor/abstractmetafield.h index e6435f68d..0fa858791 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetafield.h +++ b/sources/shiboken6/ApiExtractor/abstractmetafield.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETAFIELD_H #define ABSTRACTMETAFIELD_H @@ -32,6 +7,7 @@ #include "abstractmetalang_typedefs.h" #include "parser/codemodel_enums.h" #include "typesystem_enums.h" +#include "modifications_typedefs.h" #include "typesystem_typedefs.h" #include "enclosingclassmixin.h" @@ -50,13 +26,14 @@ public: AbstractMetaField(); AbstractMetaField(const AbstractMetaField &); AbstractMetaField &operator=(const AbstractMetaField &); - AbstractMetaField(AbstractMetaField &&); - AbstractMetaField &operator=(AbstractMetaField &&); + AbstractMetaField(AbstractMetaField &&) noexcept; + AbstractMetaField &operator=(AbstractMetaField &&) noexcept; ~AbstractMetaField(); FieldModificationList modifications() const; - bool isModifiedRemoved(int types = TypeSystem::All) const; + bool isModifiedRemoved() const; + bool generateOpaqueContainer() const; const AbstractMetaType &type() const; void setType(const AbstractMetaType &type); @@ -94,7 +71,7 @@ public: TypeSystem::SnakeCase snakeCase() const; static std::optional<AbstractMetaField> - find(const AbstractMetaFieldList &haystack, const QString &needle); + find(const AbstractMetaFieldList &haystack, QStringView needle); #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const; diff --git a/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp b/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp index 2199d7fe2..11a02f154 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetafunction.cpp @@ -1,54 +1,42 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "abstractmetafunction.h" +#include "abstractmetaargument.h" #include "abstractmetabuilder.h" #include "abstractmetalang.h" #include "abstractmetalang_helpers.h" #include "abstractmetatype.h" +#include "addedfunction.h" #include <codemodel.h> #include "documentation.h" +#include "exception.h" #include "messages.h" +#include "codesnip.h" #include "modifications.h" -#include "propertyspec.h" #include "reporthandler.h" #include "sourcelocation.h" #include "typedatabase.h" -#include "typesystem.h" +#include "complextypeentry.h" +#include "containertypeentry.h" +#include "functiontypeentry.h" +#include "primitivetypeentry.h" +#include "typesystemtypeentry.h" + +#include "qtcompat.h" #include <QtCore/QDebug> #include <QtCore/QRegularExpression> +#include <algorithm> + +using namespace Qt::StringLiterals; + // Cache FunctionModificationList in a flat list per class (0 for global // functions, or typically owner/implementing/declaring class. struct ModificationCacheEntry { - const AbstractMetaClass *klass; + AbstractMetaClassCPtr klass; FunctionModificationList modifications; }; @@ -60,7 +48,6 @@ public: AbstractMetaFunctionPrivate() : m_constant(false), m_reverse(false), - m_explicit(false), m_pointerOperator(false), m_isCallOperator(false) { @@ -73,7 +60,10 @@ public: int overloadNumber(const AbstractMetaFunction *q) const; const FunctionModificationList &modifications(const AbstractMetaFunction *q, - const AbstractMetaClass *implementor) const; + const AbstractMetaClassCPtr &implementor) const; + + bool applyTypeModification(const AbstractMetaFunction *q, + const QString &type, int number, QString *errorMessage); QString m_name; QString m_originalName; @@ -81,22 +71,25 @@ public: mutable QString m_cachedMinimalSignature; mutable QString m_cachedSignature; mutable QString m_cachedModifiedName; + QString m_unresolvedSignature; - FunctionTypeEntry* m_typeEntry = nullptr; + FunctionTypeEntryPtr m_typeEntry; AbstractMetaFunction::FunctionType m_functionType = AbstractMetaFunction::NormalFunction; AbstractMetaType m_type; - const AbstractMetaClass *m_class = nullptr; - const AbstractMetaClass *m_implementingClass = nullptr; - const AbstractMetaClass *m_declaringClass = nullptr; + QString m_modifiedTypeName; + AbstractMetaClassCPtr m_class; + AbstractMetaClassCPtr m_implementingClass; + AbstractMetaClassCPtr m_declaringClass; mutable ModificationCache m_modificationCache; int m_propertySpecIndex = -1; AbstractMetaArgumentList m_arguments; AddedFunctionPtr m_addedFunction; SourceLocation m_sourceLocation; AbstractMetaFunction::Attributes m_attributes; + FunctionAttributes m_cppAttributes; + AbstractMetaFunction::Flags m_flags; uint m_constant : 1; uint m_reverse : 1; - uint m_explicit : 1; uint m_pointerOperator : 1; uint m_isCallOperator : 1; mutable int m_cachedOverloadNumber = TypeSystem::OverloadNumberUnset; @@ -107,13 +100,17 @@ public: TypeSystem::ExceptionHandling m_exceptionHandlingModification = TypeSystem::ExceptionHandling::Unspecified; }; -AbstractMetaFunction::AbstractMetaFunction(const AddedFunctionPtr &addedFunc) : +AbstractMetaFunction::AbstractMetaFunction(const QString &name) : AbstractMetaFunction() { + d->m_originalName = d->m_name = name; +} + +AbstractMetaFunction::AbstractMetaFunction(const AddedFunctionPtr &addedFunc) : + AbstractMetaFunction(addedFunc->name()) +{ d->m_addedFunction = addedFunc; setConstant(addedFunc->isConstant()); - setName(addedFunc->name()); - setOriginalName(addedFunc->name()); switch (addedFunc->access()) { case AddedFunction::Protected: setAccess(Access::Protected); @@ -122,9 +119,9 @@ AbstractMetaFunction::AbstractMetaFunction(const AddedFunctionPtr &addedFunc) : setAccess(Access::Public); break; } - AbstractMetaFunction::Attributes atts = AbstractMetaFunction::FinalInTargetLang; + AbstractMetaFunction::Attributes atts; if (addedFunc->isStatic()) - atts |= AbstractMetaFunction::Static; + setCppAttribute(FunctionAttribute::Static); if (addedFunc->isClassMethod()) atts |= AbstractMetaFunction::ClassMethod; setAttributes(atts); @@ -217,23 +214,19 @@ void AbstractMetaFunction::setPointerOperator(bool value) bool AbstractMetaFunction::isExplicit() const { - return d->m_explicit; + return d->m_cppAttributes.testFlag(FunctionAttribute::Explicit); } void AbstractMetaFunction::setExplicit(bool isExplicit) { - d->m_explicit = isExplicit; + d->m_cppAttributes.setFlag(FunctionAttribute::Explicit, isExplicit); } bool AbstractMetaFunction::returnsBool() const { if (d->m_type.typeUsagePattern() != AbstractMetaType::PrimitivePattern) return false; - auto *pte = static_cast<const PrimitiveTypeEntry *>(d->m_type.typeEntry()); - // Walk along typedefs - while (auto *referencedPte = pte->referencedTypeEntry()) - pte =referencedPte; - return pte->name() == u"bool"; + return basicReferencedTypeEntry(d->m_type.typeEntry())->name() == u"bool"; } bool AbstractMetaFunction::isOperatorBool() const @@ -268,12 +261,37 @@ void AbstractMetaFunction::operator-=(AbstractMetaFunction::Attribute attribute) d->m_attributes.setFlag(attribute, false); } +FunctionAttributes AbstractMetaFunction::cppAttributes() const +{ + return d->m_cppAttributes; +} + +void AbstractMetaFunction::setCppAttributes(FunctionAttributes a) +{ + d->m_cppAttributes = a; +} + +void AbstractMetaFunction::setCppAttribute(FunctionAttribute a, bool on) +{ + d->m_cppAttributes.setFlag(a, on); +} + +AbstractMetaFunction::Flags AbstractMetaFunction::flags() const +{ + return d->m_flags; +} + +void AbstractMetaFunction::setFlags(Flags f) +{ + d->m_flags = f; +} + /******************************************************************************* * Indicates that this function has a modification that removes it */ -bool AbstractMetaFunction::isModifiedRemoved(const AbstractMetaClass *cls) const +bool AbstractMetaFunction::isModifiedRemoved(AbstractMetaClassCPtr cls) const { - if (!isInGlobalScope() && cls == nullptr) + if (!isInGlobalScope() && !cls) cls = d->m_implementingClass; for (const auto &mod : modifications(cls)) { if (mod.isRemoved()) @@ -283,6 +301,17 @@ bool AbstractMetaFunction::isModifiedRemoved(const AbstractMetaClass *cls) const return false; } +bool AbstractMetaFunction::isModifiedFinal(AbstractMetaClassCPtr cls) const +{ + if (!isInGlobalScope() && cls == nullptr) + cls = d->m_implementingClass; + for (const auto &mod : modifications(cls)) { + if (mod.modifiers().testFlag(FunctionModification::Final)) + return true; + } + return false; +} + bool AbstractMetaFunction::isVoid() const { return d->m_type.isVoid(); @@ -298,12 +327,12 @@ void AbstractMetaFunction::setType(const AbstractMetaType &type) d->m_type = type; } -const AbstractMetaClass *AbstractMetaFunction::ownerClass() const +AbstractMetaClassCPtr AbstractMetaFunction::ownerClass() const { return d->m_class; } -void AbstractMetaFunction::setOwnerClass(const AbstractMetaClass *cls) +void AbstractMetaFunction::setOwnerClass(const AbstractMetaClassCPtr &cls) { d->m_class = cls; } @@ -327,7 +356,7 @@ AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const Abstra result |= EqualImplementor; // Attributes - if (attributes() == other->attributes()) + if (attributes() == other->attributes() && cppAttributes() == other->cppAttributes()) result |= EqualAttributes; // Compare types @@ -358,10 +387,10 @@ AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const Abstra maxArguments = arguments(); } - int minCount = minArguments.size(); - int maxCount = maxArguments.size(); + const auto minCount = minArguments.size(); + const auto maxCount = maxArguments.size(); bool same = true; - for (int i = 0; i < maxCount; ++i) { + for (qsizetype i = 0; i < maxCount; ++i) { if (i < minCount) { const AbstractMetaArgument &min_arg = minArguments.at(i); const AbstractMetaArgument &max_arg = maxArguments.at(i); @@ -384,10 +413,39 @@ AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const Abstra return result; } +// Is this the const overload of another function of equivalent return type? +bool AbstractMetaFunction::isConstOverloadOf(const AbstractMetaFunction *other) const +{ + const auto argumentCount = d->m_arguments.size(); + if (!isConstant() || other->isConstant() || name() != other->name() + || argumentCount != other->arguments().size()) { + return false; + } + + // Match "const Foo &getFoo() const" / "Foo &getFoo()" / "Foo getFoo() const" + const auto otherType = other->type(); + if (d->m_type.name() != otherType.name() + || d->m_type.indirectionsV() != otherType.indirectionsV()) { + return false; + } + + const auto &otherArguments = other->arguments(); + for (qsizetype a = 0; a < argumentCount; ++a) { + if (d->m_arguments.at(a).type() != otherArguments.at(a).type()) + return false; + } + return true; +} + AbstractMetaFunction *AbstractMetaFunction::copy() const { auto *cpy = new AbstractMetaFunction; cpy->setAttributes(attributes()); + auto ca = cppAttributes(); + // Historical bug: explicit was not copied! (causing nontypetemplate_test.py fail) + ca.setFlag(FunctionAttribute::Explicit, false); + cpy->setCppAttributes(ca); + cpy->setFlags(flags()); cpy->setAccess(access()); cpy->setName(name()); cpy->setOriginalName(originalName()); @@ -400,6 +458,7 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const cpy->setExceptionSpecification(d->m_exceptionSpecification); cpy->setAllowThreadModification(d->m_allowThreadModification); cpy->setExceptionHandlingModification(d->m_exceptionHandlingModification); + cpy->d->m_modifiedTypeName = d->m_modifiedTypeName; cpy->d->m_addedFunction = d->m_addedFunction; cpy->d->m_arguments = d->m_arguments; @@ -423,35 +482,50 @@ bool AbstractMetaFunction::generateBinding() const { switch (d->m_functionType) { case ConversionOperator: + if (d->m_name != u"operator int" && d->m_name != u"operator double") + return false; + break; case AssignmentOperatorFunction: case MoveAssignmentOperatorFunction: + case AbstractMetaFunction::MoveConstructorFunction: return false; default: + if (!isWhiteListed()) + return false; break; } + // Can we access the wrapper in case of a protected method? If not, + // disable for consistency regardless of avoidProtectedHack. + if (isProtected()) { + const auto typeFlags = ownerClass()->typeEntry()->typeFlags(); + if (typeFlags.testFlag(ComplexTypeEntry::DisableWrapper)) + return false; + } if (isPrivate() && d->m_functionType != EmptyFunction) return false; - return d->m_name != u"qt_metacall" && !usesRValueReferences() - && !isModifiedRemoved(); + // RValue references only for user-specified + // functions (<add-function>/<declare-function>/<function>) + return d->m_name != u"qt_metacall" && + (!usesRValueReferences() || d->m_addedFunction || d->m_typeEntry) + && !isModifiedRemoved(); } -QStringList AbstractMetaFunction::introspectionCompatibleSignatures(const QStringList &resolvedArguments) const +bool AbstractMetaFunction::isWhiteListed() const { - AbstractMetaArgumentList arguments = this->arguments(); - if (arguments.size() == resolvedArguments.size()) { - QString signature = name() + QLatin1Char('(') + resolvedArguments.join(QLatin1Char(',')) + QLatin1Char(')'); - return QStringList(TypeDatabase::normalizedSignature(signature)); - } - QStringList returned; - - const AbstractMetaArgument &argument = arguments.at(resolvedArguments.size()); - QStringList minimalTypeSignature = argument.type().minimalSignature().split(QLatin1String("::")); - for (int i = 0; i < minimalTypeSignature.size(); ++i) { - returned += introspectionCompatibleSignatures(QStringList(resolvedArguments) - << QStringList(minimalTypeSignature.mid(minimalTypeSignature.size() - i - 1)).join(QLatin1String("::"))); + switch (d->m_functionType) { + case NormalFunction: + case SignalFunction: + case SlotFunction: + if (auto dc = declaringClass()) { + const QSet<QString> &whiteList = dc->typeEntry()->generateFunctions(); + return whiteList.isEmpty() || whiteList.contains(d->m_name) + || whiteList.contains(minimalSignature()); + } + break; + default: + break; } - - return returned; + return true; } QString AbstractMetaFunctionPrivate::signature() const @@ -459,22 +533,22 @@ QString AbstractMetaFunctionPrivate::signature() const if (m_cachedSignature.isEmpty()) { m_cachedSignature = m_originalName; - m_cachedSignature += QLatin1Char('('); + m_cachedSignature += u'('; - for (int i = 0; i < m_arguments.count(); ++i) { + for (qsizetype i = 0; i < m_arguments.size(); ++i) { const AbstractMetaArgument &a = m_arguments.at(i); const AbstractMetaType &t = a.type(); if (i > 0) - m_cachedSignature += QLatin1String(", "); + m_cachedSignature += u", "_s; m_cachedSignature += t.cppSignature(); // We need to have the argument names in the qdoc files - m_cachedSignature += QLatin1Char(' '); + m_cachedSignature += u' '; m_cachedSignature += a.name(); } - m_cachedSignature += QLatin1Char(')'); + m_cachedSignature += u')'; if (m_constant) - m_cachedSignature += QLatin1String(" const"); + m_cachedSignature += u" const"_s; } return m_cachedSignature; } @@ -484,6 +558,25 @@ QString AbstractMetaFunction::signature() const return d->signature(); } +QString AbstractMetaFunction::classQualifiedSignature() const +{ + QString result; + if (d->m_implementingClass) + result += d->m_implementingClass->qualifiedCppName() + u"::"_s; + result += signature(); + return result; +} + +QString AbstractMetaFunction::unresolvedSignature() const +{ + return d->m_unresolvedSignature; +} + +void AbstractMetaFunction::setUnresolvedSignature(const QString &s) +{ + d->m_unresolvedSignature = s; +} + bool AbstractMetaFunction::isConstant() const { return d->m_constant; @@ -496,31 +589,47 @@ void AbstractMetaFunction::setConstant(bool constant) bool AbstractMetaFunction::isUserAdded() const { - return !d->m_addedFunction.isNull() && !d->m_addedFunction->isDeclaration(); + return d->m_addedFunction && !d->m_addedFunction->isDeclaration(); +} + +bool AbstractMetaFunction::isUserAddedPythonOverride() const +{ + return d->m_addedFunction && d->m_addedFunction->isPythonOverride(); } bool AbstractMetaFunction::isUserDeclared() const { - return !d->m_addedFunction.isNull() && d->m_addedFunction->isDeclaration(); + return d->m_addedFunction && d->m_addedFunction->isDeclaration(); } int AbstractMetaFunction::actualMinimumArgumentCount() const { - AbstractMetaArgumentList arguments = this->arguments(); - int count = 0; - for (int i = 0; i < arguments.size(); ++i && ++count) { - if (argumentRemoved(i + 1)) + for (qsizetype i = 0, size = d->m_arguments.size(); i < size; ++i && ++count) { + const auto &arg = d->m_arguments.at(i); + if (arg.isModifiedRemoved()) --count; - else if (!arguments.at(i).defaultValueExpression().isEmpty()) + else if (!arg.defaultValueExpression().isEmpty()) break; } return count; } +int AbstractMetaFunction::actualArgumentIndex(int index) const +{ + if (index < 0 || index >= int(d->m_arguments.size())) + throw Exception(msgArgumentIndexOutOfRange(this, index)); + int result = 0; + for (int i = 0; i < index; ++i) { + if (!d->m_arguments.at(i).isModifiedRemoved()) + ++result; + } + return result; +} + // Returns reference counts for argument at idx, or all arguments if idx == -2 -QList<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaClass *cls, int idx) const +QList<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaClassCPtr &cls, int idx) const { QList<ReferenceCount> returned; @@ -535,7 +644,7 @@ QList<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaCl return returned; } -ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClass *cls, int idx) const +ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClassCPtr &cls, int idx) const { for (const auto &mod : modifications(cls)) { for (const ArgumentModification &argumentMod : mod.argument_mods()) { @@ -564,6 +673,11 @@ QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int return QString(); } +bool AbstractMetaFunction::hasConversionRule(TypeSystem::Language language, int idx) const +{ + return !conversionRule(language, idx).isEmpty(); +} + // FIXME If we remove a arg. in the method at the base class, it will not reflect here. bool AbstractMetaFunction::argumentRemoved(int key) const { @@ -579,28 +693,28 @@ bool AbstractMetaFunction::argumentRemoved(int key) const return false; } -const AbstractMetaClass *AbstractMetaFunction::targetLangOwner() const +AbstractMetaClassCPtr AbstractMetaFunction::targetLangOwner() const { return d->m_class && d->m_class->isInvisibleNamespace() ? d->m_class->targetLangEnclosingClass() : d->m_class; } -const AbstractMetaClass *AbstractMetaFunction::declaringClass() const +AbstractMetaClassCPtr AbstractMetaFunction::declaringClass() const { return d->m_declaringClass; } -void AbstractMetaFunction::setDeclaringClass(const AbstractMetaClass *cls) +void AbstractMetaFunction::setDeclaringClass(const AbstractMetaClassCPtr &cls) { d->m_declaringClass = cls; } -const AbstractMetaClass *AbstractMetaFunction::implementingClass() const +AbstractMetaClassCPtr AbstractMetaFunction::implementingClass() const { return d->m_implementingClass; } -void AbstractMetaFunction::setImplementingClass(const AbstractMetaClass *cls) +void AbstractMetaFunction::setImplementingClass(const AbstractMetaClassCPtr &cls) { d->m_implementingClass = cls; } @@ -625,13 +739,23 @@ void AbstractMetaFunction::addArgument(const AbstractMetaArgument &argument) d->m_arguments << argument; } +static bool modifiedDeprecated(const FunctionModification &mod) +{ + return mod.modifiers().testFlag(FunctionModification::Deprecated); +} + +static bool modifiedUndeprecated(const FunctionModification &mod) +{ + return mod.modifiers().testFlag(FunctionModification::Undeprecated); +} + bool AbstractMetaFunction::isDeprecated() const { - for (const auto &modification : modifications(declaringClass())) { - if (modification.isDeprecated()) - return true; - } - return false; + const auto &mods = modifications(declaringClass()); + + return d->m_cppAttributes.testFlag(FunctionAttribute::Deprecated) + ? std::none_of(mods.cbegin(), mods.cend(), modifiedUndeprecated) + : std::any_of(mods.cbegin(), mods.cend(), modifiedDeprecated); } bool AbstractMetaFunction::isConstructor() const @@ -676,6 +800,24 @@ void AbstractMetaFunction::setFunctionType(AbstractMetaFunction::FunctionType ty d->m_functionType = type; } +std::optional<AbstractMetaFunction::ComparisonOperatorType> +AbstractMetaFunction::comparisonOperatorType() const +{ + if (d->m_functionType != ComparisonOperator) + return {}; + static const QHash<QString, ComparisonOperatorType> mapping = { + {u"operator=="_s, OperatorEqual}, + {u"operator!="_s, OperatorNotEqual}, + {u"operator<"_s, OperatorLess}, + {u"operator<="_s, OperatorLessEqual}, + {u"operator>"_s, OperatorGreater}, + {u"operator>="_s, OperatorGreaterEqual} + }; + const auto it = mapping.constFind(originalName()); + Q_ASSERT(it != mapping.constEnd()); + return it.value(); +} + // Auto-detect whether a function should be wrapped into // Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS, that is, temporarily release // the GIL (global interpreter lock). Doing so is required for any thread-wait @@ -685,8 +827,13 @@ void AbstractMetaFunction::setFunctionType(AbstractMetaFunction::FunctionType ty bool AbstractMetaFunction::autoDetectAllowThread() const { // Disallow for simple getter functions. - const bool maybeGetter = d->m_constant != 0 && !isVoid() && d->m_arguments.isEmpty(); - return !maybeGetter; + return !maybeAccessor(); +} + +bool AbstractMetaFunction::maybeAccessor() const +{ + return d->m_functionType == NormalFunction && d->m_class != nullptr + && d->m_constant != 0 && !isVoid() && d->m_arguments.isEmpty(); } SourceLocation AbstractMetaFunction::sourceLocation() const @@ -699,12 +846,12 @@ void AbstractMetaFunction::setSourceLocation(const SourceLocation &sourceLocatio d->m_sourceLocation = sourceLocation; } -static inline TypeSystem::AllowThread allowThreadMod(const AbstractMetaClass *klass) +static inline TypeSystem::AllowThread allowThreadMod(const AbstractMetaClassCPtr &klass) { return klass->typeEntry()->allowThread(); } -static inline bool hasAllowThreadMod(const AbstractMetaClass *klass) +static inline bool hasAllowThreadMod(const AbstractMetaClassCPtr &klass) { return allowThreadMod(klass) != TypeSystem::AllowThread::Unspecified; } @@ -737,7 +884,7 @@ bool AbstractMetaFunction::allowThread() const return result; } -TypeSystem::Ownership AbstractMetaFunction::argumentTargetOwnership(const AbstractMetaClass *cls, int idx) const +TypeSystem::Ownership AbstractMetaFunction::argumentTargetOwnership(const AbstractMetaClassCPtr &cls, int idx) const { for (const auto &modification : modifications(cls)) { for (const ArgumentModification &argumentModification : modification.argument_mods()) { @@ -749,18 +896,22 @@ TypeSystem::Ownership AbstractMetaFunction::argumentTargetOwnership(const Abstra return TypeSystem::UnspecifiedOwnership; } -QString AbstractMetaFunction::typeReplaced(int key) const +const QString &AbstractMetaFunction::modifiedTypeName() const { - for (const auto &modification : modifications(declaringClass())) { - for (const ArgumentModification &argumentModification : modification.argument_mods()) { - if (argumentModification.index() == key - && !argumentModification.modifiedType().isEmpty()) { - return argumentModification.modifiedType(); - } - } - } + return d->m_modifiedTypeName; +} - return QString(); +bool AbstractMetaFunction::generateOpaqueContainerReturn() const +{ + if (!isTypeModified() || d->m_type.typeUsagePattern() != AbstractMetaType::ContainerPattern) + return false; + // Needs to be a reference to a container, allow by value only for spans + if (d->m_type.referenceType() != LValueReference) { + auto cte = std::static_pointer_cast<const ContainerTypeEntry>(d->m_type.typeEntry()); + if (cte->containerKind() != ContainerTypeEntry::SpanContainer) + return false; + } + return d->m_type.generateOpaqueContainerForGetter(d->m_modifiedTypeName); } bool AbstractMetaFunction::isModifiedToArray(int argumentIndex) const @@ -774,6 +925,56 @@ bool AbstractMetaFunction::isModifiedToArray(int argumentIndex) const return false; } +// Note: The declaring class must be correctly set for this to work. +bool AbstractMetaFunctionPrivate::applyTypeModification(const AbstractMetaFunction *q, + const QString &type, + int number, QString *errorMessage) +{ + if (number < 0 || number > m_arguments.size()) { + *errorMessage = + msgTypeModificationFailed(type, number, q, + msgArgumentOutOfRange(number, 0, m_arguments.size())); + return false; + } + + // Modified return types may have unparseable types like Python tuples + if (number == 0) { + m_modifiedTypeName = type; + return true; + } + + auto typeOpt = AbstractMetaType::fromString(type, errorMessage); + if (!typeOpt.has_value()) { + *errorMessage = msgTypeModificationFailed(type, number, q, *errorMessage); + return false; + } + m_arguments[number - 1].setModifiedType(typeOpt.value()); + return true; +} + +void AbstractMetaFunction::applyTypeModifications() +{ + QString errorMessage; + for (const auto &modification : modifications(declaringClass())) { + for (const ArgumentModification &am : modification.argument_mods()) { + const int n = am.index(); + if (am.isTypeModified() + && !d->applyTypeModification(this, am.modifiedType(), + n, &errorMessage)) { + throw Exception(errorMessage); + } else if (am.isRemoved() && n != 0) { + if (n < 1 || n > d->m_arguments.size()) { + errorMessage = + msgArgumentRemovalFailed(this, n, + msgArgumentOutOfRange(n, 1, d->m_arguments.size())); + throw Exception(errorMessage); + } + d->m_arguments[n - 1].setModifiedRemoved(true); + } + } + } +} + QString AbstractMetaFunction::pyiTypeReplaced(int argumentIndex) const { for (const auto &modification : modifications(declaringClass())) { @@ -796,28 +997,26 @@ QString AbstractMetaFunction::pyiTypeReplaced(int argumentIndex) const QString AbstractMetaFunctionPrivate::formatMinimalSignature(const AbstractMetaFunction *q, bool comment) const { - QString result = m_originalName + QLatin1Char('('); - for (int i = 0; i < m_arguments.count(); ++i) { + QString result = m_originalName + u'('; + for (qsizetype i = 0; i < m_arguments.size(); ++i) { + const auto &argument = m_arguments.at(i); if (i > 0) - result += QLatin1Char(','); - - QString typeName; - if (comment) - typeName = q->typeReplaced(i + 1); - if (typeName.isEmpty()) - typeName = m_arguments.at(i).type().minimalSignature(); - result += typeName; + result += u','; + + const auto &type = comment ? argument.modifiedType() : argument.type(); + result += type.minimalSignature(); + if (comment && argument.hasDefaultValueExpression()) + result += u'='; } - result += QLatin1Char(')'); + result += u')'; if (m_constant) - result += QLatin1String("const"); + result += u"const"_s; result = TypeDatabase::normalizedSignature(result); if (comment && !q->isVoid()) { - QString typeName = q->typeReplaced(0); - if (typeName.isEmpty()) - typeName = q->type().minimalSignature(); - result += QStringLiteral("->") + typeName; + result += u"->"_s; + result += q->isTypeModified() + ? q->modifiedTypeName() : q->type().minimalSignature(); } return result; } @@ -829,6 +1028,14 @@ QString AbstractMetaFunction::minimalSignature() const return d->m_cachedMinimalSignature; } +QStringList AbstractMetaFunction::modificationSignatures() const +{ + QStringList result{minimalSignature()}; + if (d->m_unresolvedSignature != result.constFirst()) + result.append(d->m_unresolvedSignature); + return result; +} + QString AbstractMetaFunction::signatureComment() const { return d->formatMinimalSignature(this, true); @@ -837,25 +1044,28 @@ QString AbstractMetaFunction::signatureComment() const QString AbstractMetaFunction::debugSignature() const { QString result; - const bool isOverride = attributes() & AbstractMetaFunction::OverriddenCppMethod; - const bool isFinal = attributes() & AbstractMetaFunction::FinalCppMethod; - if (!isOverride && !isFinal && (attributes() & AbstractMetaFunction::VirtualCppMethod)) - result += QLatin1String("virtual "); + const auto attributes = cppAttributes(); + const bool isOverride = attributes.testFlag(FunctionAttribute::Override); + const bool isFinal = attributes.testFlag(FunctionAttribute::Final); + if (!isOverride && !isFinal && (attributes.testFlag(FunctionAttribute::Virtual))) + result += u"virtual "_s; + if (d->m_implementingClass) + result += d->m_implementingClass->qualifiedCppName() + u"::"_s; result += minimalSignature(); if (isOverride) - result += QLatin1String(" override"); + result += u" override"_s; if (isFinal) - result += QLatin1String(" final"); + result += u" final"_s; return result; } FunctionModificationList AbstractMetaFunction::findClassModifications(const AbstractMetaFunction *f, - const AbstractMetaClass *implementor) + AbstractMetaClassCPtr implementor) { - const QString signature = f->minimalSignature(); + const auto signatures = f->modificationSignatures(); FunctionModificationList mods; while (implementor) { - mods += implementor->typeEntry()->functionModifications(signature); + mods += implementor->typeEntry()->functionModifications(signatures); if ((implementor == implementor->baseClass()) || (implementor == f->implementingClass() && !mods.isEmpty())) { break; @@ -867,15 +1077,16 @@ FunctionModificationList AbstractMetaFunction::findClassModifications(const Abst FunctionModificationList AbstractMetaFunction::findGlobalModifications(const AbstractMetaFunction *f) { - return TypeDatabase::instance()->functionModifications(f->minimalSignature()); + auto *td = TypeDatabase::instance(); + return td->globalFunctionModifications(f->modificationSignatures()); } const FunctionModificationList & AbstractMetaFunctionPrivate::modifications(const AbstractMetaFunction *q, - const AbstractMetaClass *implementor) const + const AbstractMetaClassCPtr &implementor) const { - if (!m_addedFunction.isNull()) - return m_addedFunction->modifications; + if (m_addedFunction) + return m_addedFunction->modifications(); for (const auto &ce : m_modificationCache) { if (ce.klass == implementor) return ce.modifications; @@ -889,9 +1100,9 @@ const FunctionModificationList & } const FunctionModificationList & - AbstractMetaFunction::modifications(const AbstractMetaClass *implementor) const + AbstractMetaFunction::modifications(AbstractMetaClassCPtr implementor) const { - if (implementor == nullptr) + if (!implementor) implementor = d->m_class; return d->modifications(this, implementor); } @@ -901,9 +1112,15 @@ void AbstractMetaFunction::clearModificationsCache() d->m_modificationCache.clear(); } +const DocModificationList AbstractMetaFunction::addedFunctionDocModifications() const +{ + return d->m_addedFunction + ? d->m_addedFunction->docModifications() : DocModificationList{}; +} + QString AbstractMetaFunction::argumentName(int index, bool /* create */, - const AbstractMetaClass * /* implementor */) const + AbstractMetaClassCPtr /* implementor */) const { return d->m_arguments[--index].name(); } @@ -918,19 +1135,30 @@ void AbstractMetaFunction::setPropertySpecIndex(int i) d->m_propertySpecIndex = i; } -FunctionTypeEntry *AbstractMetaFunction::typeEntry() const +FunctionTypeEntryPtr AbstractMetaFunction::typeEntry() const { return d->m_typeEntry; } -void AbstractMetaFunction::setTypeEntry(FunctionTypeEntry *typeEntry) +void AbstractMetaFunction::setTypeEntry(const FunctionTypeEntryPtr &typeEntry) { d->m_typeEntry = typeEntry; } +QString AbstractMetaFunction::targetLangPackage() const +{ + if (d->m_addedFunction != nullptr) + return d->m_addedFunction->targetLangPackage(); + if (d->m_class != nullptr) + return d->m_class->typeEntry()->targetLangPackage(); + if (d->m_typeEntry != nullptr) + return d->m_typeEntry->targetLangPackage(); + return {}; +} + bool AbstractMetaFunction::isCallOperator() const { - return d->m_name == QLatin1String("operator()"); + return d->m_name == u"operator()"; } bool AbstractMetaFunction::hasInjectedCode() const @@ -1011,7 +1239,7 @@ bool AbstractMetaFunction::hasSignatureModifications() const bool AbstractMetaFunction::isConversionOperator(const QString &funcName) { - return funcName.startsWith(QLatin1String("operator ")); + return funcName.startsWith(u"operator "); } ExceptionSpecification AbstractMetaFunction::exceptionSpecification() const @@ -1024,12 +1252,12 @@ void AbstractMetaFunction::setExceptionSpecification(ExceptionSpecification e) d->m_exceptionSpecification = e; } -static inline TypeSystem::ExceptionHandling exceptionMod(const AbstractMetaClass *klass) +static inline TypeSystem::ExceptionHandling exceptionMod(const AbstractMetaClassCPtr &klass) { return klass->typeEntry()->exceptionHandling(); } -static inline bool hasExceptionMod(const AbstractMetaClass *klass) +static inline bool hasExceptionMod(const AbstractMetaClassCPtr &klass) { return exceptionMod(klass) != TypeSystem::ExceptionHandling::Unspecified; } @@ -1082,11 +1310,11 @@ bool AbstractMetaFunction::isOperatorOverload(const QString &funcName) if (isConversionOperator(funcName)) return true; - static const QRegularExpression opRegEx(QLatin1String("^operator([+\\-\\*/%=&\\|\\^\\<>!][=]?" + static const QRegularExpression opRegEx(u"^operator([+\\-\\*/%=&\\|\\^\\<>!][=]?" "|\\+\\+|\\-\\-|&&|\\|\\||<<[=]?|>>[=]?|~" "|\\[\\]|\\s+delete\\[?\\]?" "|\\(\\)" - "|\\s+new\\[?\\]?)$")); + "|\\s+new\\[?\\]?)$"_s); Q_ASSERT(opRegEx.isValid()); return opRegEx.match(funcName).hasMatch(); } @@ -1113,22 +1341,27 @@ bool AbstractMetaFunction::isComparisonOperator() const return d->m_functionType == ComparisonOperator; } +bool AbstractMetaFunction::isSymmetricalComparisonOperator() const +{ + if (d->m_functionType != ComparisonOperator || d->m_class == nullptr) + return false; + AbstractMetaType classType(d->m_class->typeEntry()); + classType.decideUsagePattern(); + return std::all_of(d->m_arguments.constBegin(), d->m_arguments.constEnd(), + [classType](const AbstractMetaArgument &a) { + return a.type().isEquivalent(classType);}); +} + bool AbstractMetaFunction::isIncDecrementOperator() const { return d->m_functionType == IncrementOperator || d->m_functionType == DecrementOperator; } - bool AbstractMetaFunction::isLogicalOperator() const { return d->m_functionType == LogicalOperator; } -bool AbstractMetaFunction::isSubscriptOperator() const -{ - return d->m_functionType == SubscriptOperator; -} - bool AbstractMetaFunction::isAssignmentOperator() const { return d->m_functionType == AssignmentOperatorFunction @@ -1178,7 +1411,7 @@ bool AbstractMetaFunction::isInplaceOperator() const bool AbstractMetaFunction::isVirtual() const { - return d->m_attributes.testFlag(AbstractMetaFunction::VirtualCppMethod); + return d->m_cppAttributes.testFlag(FunctionAttribute::Virtual); } QString AbstractMetaFunctionPrivate::modifiedName(const AbstractMetaFunction *q) const @@ -1203,7 +1436,7 @@ QString AbstractMetaFunction::modifiedName() const AbstractMetaFunctionCPtr AbstractMetaFunction::find(const AbstractMetaFunctionCList &haystack, - const QString &needle) + QAnyStringView needle) { for (const auto &f : haystack) { if (f->name() == needle) @@ -1241,6 +1474,8 @@ bool AbstractMetaFunction::matches(OperatorQueryOptions query) const break; case AbstractMetaFunction::ComparisonOperator: result = query.testFlag(OperatorQueryOption::ComparisonOp); + if (!result && query.testFlag(OperatorQueryOption::SymmetricalComparisonOp)) + result = isSymmetricalComparisonOperator(); break; default: break; @@ -1299,17 +1534,14 @@ TypeSystem::SnakeCase AbstractMetaFunction::snakeCase() const return mod.snakeCase(); } - if (d->m_typeEntry) { // Global function - const auto snakeCase = d->m_typeEntry->snakeCase(); - return snakeCase != TypeSystem::SnakeCase::Unspecified - ? snakeCase : d->m_typeEntry->typeSystemTypeEntry()->snakeCase(); - } + if (d->m_typeEntry) // Global function + return typeSystemTypeEntry(d->m_typeEntry)->snakeCase(); if (d->m_class) { auto typeEntry = d->m_class->typeEntry(); const auto snakeCase = typeEntry->snakeCase(); return snakeCase != TypeSystem::SnakeCase::Unspecified - ? snakeCase : typeEntry->typeSystemTypeEntry()->snakeCase(); + ? snakeCase : typeSystemTypeEntry(typeEntry)->snakeCase(); } return TypeSystem::SnakeCase::Disabled; } @@ -1323,7 +1555,7 @@ bool AbstractMetaFunction::injectedCodeUsesPySelf() const bool AbstractMetaFunction::injectedCodeCallsPythonOverride() const { static const QRegularExpression - overrideCallRegexCheck(QStringLiteral(R"(PyObject_Call\s*\(\s*%PYTHON_METHOD_OVERRIDE\s*,)")); + overrideCallRegexCheck(R"(PyObject_Call\s*\(\s*%PYTHON_METHOD_OVERRIDE\s*,)"_L1); Q_ASSERT(overrideCallRegexCheck.isValid()); return injectedCodeContains(overrideCallRegexCheck, TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode); @@ -1333,13 +1565,13 @@ bool AbstractMetaFunction::injectedCodeHasReturnValueAttribution(TypeSystem::Lan { if (language == TypeSystem::TargetLangCode) { static const QRegularExpression - retValAttributionRegexCheck_target(QStringLiteral(R"(%PYARG_0\s*=[^=]\s*.+)")); + retValAttributionRegexCheck_target(R"(%PYARG_0\s*=[^=]\s*.+)"_L1); Q_ASSERT(retValAttributionRegexCheck_target.isValid()); return injectedCodeContains(retValAttributionRegexCheck_target, TypeSystem::CodeSnipPositionAny, language); } static const QRegularExpression - retValAttributionRegexCheck_native(QStringLiteral(R"(%0\s*=[^=]\s*.+)")); + retValAttributionRegexCheck_native(R"(%0\s*=[^=]\s*.+)"_L1); Q_ASSERT(retValAttributionRegexCheck_native.isValid()); return injectedCodeContains(retValAttributionRegexCheck_native, TypeSystem::CodeSnipPositionAny, language); } @@ -1363,6 +1595,38 @@ bool AbstractMetaFunction::isVisibilityModifiedToPrivate() const return false; } +struct ComparisonOperator +{ + const char *cppOperator; + const char *pythonOpCode; +}; + +using ComparisonOperatorMapping = + QHash<AbstractMetaFunction::ComparisonOperatorType, ComparisonOperator>; + +static const ComparisonOperatorMapping &comparisonOperatorMapping() +{ + static const ComparisonOperatorMapping result = { + {AbstractMetaFunction::OperatorEqual, {"==", "Py_EQ"}}, + {AbstractMetaFunction::OperatorNotEqual, {"!=", "Py_NE"}}, + {AbstractMetaFunction::OperatorLess, {"<", "Py_LT"}}, + {AbstractMetaFunction::OperatorLessEqual, {"<=", "Py_LE"}}, + {AbstractMetaFunction::OperatorGreater, {">", "Py_GT"}}, + {AbstractMetaFunction::OperatorGreaterEqual, {">=", "Py_GE"}} + }; + return result; +} + +const char * AbstractMetaFunction::pythonRichCompareOpCode(ComparisonOperatorType ct) +{ + return comparisonOperatorMapping().value(ct).pythonOpCode; +} + +const char * AbstractMetaFunction::cppComparisonOperator(ComparisonOperatorType ct) +{ + return comparisonOperatorMapping().value(ct).cppOperator; +} + #ifndef QT_NO_DEBUG_STREAM void AbstractMetaFunction::formatDebugBrief(QDebug &debug) const { @@ -1388,12 +1652,15 @@ void AbstractMetaFunction::formatDebugVerbose(QDebug &debug) const if (d->m_exceptionHandlingModification != TypeSystem::ExceptionHandling::Unspecified) debug << " exeption-mod " << int(d->m_exceptionHandlingModification); debug << '('; - for (int i = 0, count = d->m_arguments.size(); i < count; ++i) { + for (qsizetype i = 0, count = d->m_arguments.size(); i < count; ++i) { if (i) debug << ", "; debug << d->m_arguments.at(i); } - debug << "), signature=\"" << minimalSignature() << '"'; + const QString signature = minimalSignature(); + debug << "), signature=\"" << signature << '"'; + if (signature != d->m_unresolvedSignature) + debug << ", unresolvedSignature=\"" << d->m_unresolvedSignature << '"'; if (d->m_constant) debug << " [const]"; if (d->m_reverse) @@ -1402,9 +1669,9 @@ void AbstractMetaFunction::formatDebugVerbose(QDebug &debug) const debug << " [userAdded]"; if (isUserDeclared()) debug << " [userDeclared]"; - if (d->m_explicit) + if (d->m_cppAttributes.testFlag(FunctionAttribute::Explicit)) debug << " [explicit]"; - if (attributes().testFlag(AbstractMetaFunction::Deprecated)) + if (d->m_cppAttributes.testFlag(FunctionAttribute::Deprecated)) debug << " [deprecated]"; if (d->m_pointerOperator) debug << " [operator->]"; diff --git a/sources/shiboken6/ApiExtractor/abstractmetafunction.h b/sources/shiboken6/ApiExtractor/abstractmetafunction.h index 20e2e6d90..e252e439d 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetafunction.h +++ b/sources/shiboken6/ApiExtractor/abstractmetafunction.h @@ -1,42 +1,21 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETAFUNCTION_H #define ABSTRACTMETAFUNCTION_H #include "abstractmetalang_enums.h" #include "abstractmetalang_typedefs.h" -#include "abstractmetaargument.h" #include "typesystem_enums.h" +#include "modifications_typedefs.h" #include "typesystem_typedefs.h" +#include "parser/codemodel_enums.h" +#include <QtCore/QMetaObject> #include <QtCore/QScopedPointer> +#include <optional> + QT_FORWARD_DECLARE_CLASS(QDebug) QT_FORWARD_DECLARE_CLASS(QRegularExpression) @@ -53,6 +32,8 @@ class AbstractMetaFunction { Q_GADGET public: + Q_DISABLE_COPY_MOVE(AbstractMetaFunction) + enum FunctionType { ConstructorFunction, CopyConstructorFunction, @@ -84,6 +65,12 @@ public: }; Q_ENUM(FunctionType) + enum ComparisonOperatorType { + OperatorEqual, OperatorNotEqual, OperatorLess, OperatorLessEqual, + OperatorGreater, OperatorGreaterEqual + }; + Q_ENUM(ComparisonOperatorType) + enum CompareResultFlag { EqualName = 0x00000001, EqualArguments = 0x00000002, @@ -105,29 +92,18 @@ public: enum Attribute { None = 0x00000000, - Friendly = 0x00000001, - - Abstract = 0x00000002, - Static = 0x00000004, ClassMethod = 0x00000008, - FinalInTargetLang = 0x00000010, - GetterFunction = 0x00000020, SetterFunction = 0x00000040, PropertyReader = 0x00000100, PropertyWriter = 0x00000200, PropertyResetter = 0x00000400, + PropertyNotify = 0x00000800, - Invokable = 0x00001000, - - VirtualCppMethod = 0x00010000, - OverriddenCppMethod = 0x00020000, - FinalCppMethod = 0x00040000, // Add by meta builder (implicit constructors, inherited methods, etc) AddedMethod = 0x001000000, - Deprecated = 0x002000000 }; Q_DECLARE_FLAGS(Attributes, Attribute) Q_FLAG(Attribute) @@ -138,17 +114,33 @@ public: void operator+=(Attribute attribute); void operator-=(Attribute attribute); - bool isFinalInTargetLang() const; + FunctionAttributes cppAttributes() const; + void setCppAttributes(FunctionAttributes a); + void setCppAttribute(FunctionAttribute a, bool on = true); + + enum class Flag { // Internal flags not relevant for comparing functions + // Binary operator whose leading/trailing argument was removed by metabuilder + OperatorLeadingClassArgumentRemoved = 0x1, + OperatorTrailingClassArgumentRemoved = 0x2, + OperatorClassArgumentByValue = 0x4, // The removed class argument was passed by value + InheritedFromTemplate = 0x8, // Inherited from a template in metabuilder + HiddenFriend = 0x10, + PrivateSignal = 0x20 // Private Qt signal (cannot emit from client code) + }; + Q_DECLARE_FLAGS(Flags, Flag) + + Flags flags() const; + void setFlags(Flags f); + bool isAbstract() const; bool isClassMethod() const; bool isStatic() const; - bool isInvokable() const; bool isPropertyReader() const; bool isPropertyWriter() const; bool isPropertyResetter() const; - bool isFriendly() const; AbstractMetaFunction(); + explicit AbstractMetaFunction(const QString &name); explicit AbstractMetaFunction(const AddedFunctionPtr &addedFunc); ~AbstractMetaFunction(); @@ -210,9 +202,11 @@ public: bool isArithmeticOperator() const; bool isBitwiseOperator() const; // Includes shift operator bool isComparisonOperator() const; + /// Returns whether this is a comparison accepting owner class + /// (bool operator==(QByteArray,QByteArray) but not bool operator==(QByteArray,const char *) + bool isSymmetricalComparisonOperator() const; bool isIncDecrementOperator() const; bool isLogicalOperator() const; - bool isSubscriptOperator() const; bool isAssignmentOperator() const; // Assignment or move assignment bool isGetter() const; /// Returns whether it is a Qt-style isNull() method suitable for nb_bool @@ -233,12 +227,15 @@ public: QString modifiedName() const; QString minimalSignature() const; + /// List of signatures matched for modifications + QStringList modificationSignatures() const; // Signature with replaced argument types and return type for overload // decisor comment. QString signatureComment() const; QString debugSignature() const; // including virtual/override/final, etc., for debugging only. - bool isModifiedRemoved(const AbstractMetaClass *cls = nullptr) const; + bool isModifiedRemoved(AbstractMetaClassCPtr cls = {}) const; + bool isModifiedFinal(AbstractMetaClassCPtr cls = {}) const; bool isVoid() const; @@ -246,25 +243,27 @@ public: void setType(const AbstractMetaType &type); // The class that has this function as a member. - const AbstractMetaClass *ownerClass() const; - void setOwnerClass(const AbstractMetaClass *cls); + AbstractMetaClassCPtr ownerClass() const; + void setOwnerClass(const AbstractMetaClassCPtr &cls); // Owner excluding invisible namespaces - const AbstractMetaClass *targetLangOwner() const; + AbstractMetaClassCPtr targetLangOwner() const; // The first class in a hierarchy that declares the function - const AbstractMetaClass *declaringClass() const; - void setDeclaringClass(const AbstractMetaClass *cls); + AbstractMetaClassCPtr declaringClass() const; + void setDeclaringClass(const AbstractMetaClassCPtr &cls); // The class that actually implements this function - const AbstractMetaClass *implementingClass() const; - void setImplementingClass(const AbstractMetaClass *cls); + AbstractMetaClassCPtr implementingClass() const; + void setImplementingClass(const AbstractMetaClassCPtr &cls); const AbstractMetaArgumentList &arguments() const; AbstractMetaArgumentList &arguments(); void setArguments(const AbstractMetaArgumentList &arguments); void addArgument(const AbstractMetaArgument &argument); int actualMinimumArgumentCount() const; + // Return the argument index accounting for the isModifiedRemoved arguments [0..n-1] + int actualArgumentIndex(int index) const; bool isDeprecated() const; bool isDestructor() const { return functionType() == DestructorFunction; } @@ -276,40 +275,61 @@ public: bool isSignal() const { return functionType() == SignalFunction; } bool isSlot() const { return functionType() == SlotFunction; } bool isEmptyFunction() const { return functionType() == EmptyFunction; } + bool maybeAccessor() const; FunctionType functionType() const; void setFunctionType(FunctionType type); + std::optional<ComparisonOperatorType> comparisonOperatorType() const; + bool usesRValueReferences() const; bool generateBinding() const; + // Returns whether the function is contained in the positive list of the + // type entry if one is specified. + bool isWhiteListed() const; - QStringList introspectionCompatibleSignatures(const QStringList &resolvedArguments = QStringList()) const; QString signature() const; + /// Return a signature qualified by class name, for error reporting. + QString classQualifiedSignature() const; + + /// Signature with unresolved typedefs as seen by the code parser + QString unresolvedSignature() const; + void setUnresolvedSignature(const QString &); bool isConstant() const; void setConstant(bool constant); /// Returns true if the AbstractMetaFunction was added by the user via the type system description. bool isUserAdded() const; + bool isUserAddedPythonOverride() const; /// Returns true if the AbstractMetaFunction was declared by the user via /// the type system description. bool isUserDeclared() const; CompareResult compareTo(const AbstractMetaFunction *other) const; + bool isConstOverloadOf(const AbstractMetaFunction *other) const; bool operator <(const AbstractMetaFunction &a) const; AbstractMetaFunction *copy() const; QString conversionRule(TypeSystem::Language language, int idx) const; - QList<ReferenceCount> referenceCounts(const AbstractMetaClass *cls, int idx = -2) const; - ArgumentOwner argumentOwner(const AbstractMetaClass *cls, int idx) const; + bool hasConversionRule(TypeSystem::Language language, int idx) const; + QList<ReferenceCount> + referenceCounts(const AbstractMetaClassCPtr &cls, int idx = -2) const; + ArgumentOwner argumentOwner(const AbstractMetaClassCPtr &cls, int idx) const; // Returns the ownership rules for the given argument (target lang). - TypeSystem::Ownership argumentTargetOwnership(const AbstractMetaClass *cls, int idx) const; + TypeSystem::Ownership + argumentTargetOwnership(const AbstractMetaClassCPtr &cls, int idx) const; + + const QString &modifiedTypeName() const; + bool isTypeModified() const { return !modifiedTypeName().isEmpty(); } + bool generateOpaqueContainerReturn() const; - QString typeReplaced(int argument_index) const; bool isModifiedToArray(int argumentIndex) const; + void applyTypeModifications(); + /// Return the (modified) type for the signature; modified-pyi-type, modified-type QString pyiTypeReplaced(int argumentIndex) const; @@ -340,29 +360,32 @@ public: */ bool hasSignatureModifications() const; - const FunctionModificationList &modifications(const AbstractMetaClass *implementor = nullptr) const; + const FunctionModificationList &modifications(AbstractMetaClassCPtr implementor = {}) const; void clearModificationsCache(); + const DocModificationList addedFunctionDocModifications() const; + static FunctionModificationList findClassModifications(const AbstractMetaFunction *f, - const AbstractMetaClass *implementor); + AbstractMetaClassCPtr implementor); static FunctionModificationList findGlobalModifications(const AbstractMetaFunction *f); /** * Return the argument name if there is a modification the renamed value will be returned */ - QString argumentName(int index, bool create = true, const AbstractMetaClass *cl = nullptr) const; + QString argumentName(int index, bool create = true, AbstractMetaClassCPtr cl = {}) const; int propertySpecIndex() const; void setPropertySpecIndex(int i); - FunctionTypeEntry* typeEntry() const; + FunctionTypeEntryPtr typeEntry() const; + void setTypeEntry(const FunctionTypeEntryPtr &typeEntry); - void setTypeEntry(FunctionTypeEntry* typeEntry); + QString targetLangPackage() const; bool isCallOperator() const; static AbstractMetaFunctionCPtr - find(const AbstractMetaFunctionCList &haystack, const QString &needle); + find(const AbstractMetaFunctionCList &haystack, QAnyStringView needle); bool matches(OperatorQueryOptions) const; @@ -408,6 +431,9 @@ public: SourceLocation sourceLocation() const; void setSourceLocation(const SourceLocation &sourceLocation); + static const char *pythonRichCompareOpCode(ComparisonOperatorType ct); + static const char *cppComparisonOperator(ComparisonOperatorType ct); + private: template <class Predicate> bool traverseCodeSnips(Predicate predicate, @@ -418,19 +444,14 @@ private: QScopedPointer<AbstractMetaFunctionPrivate> d; }; -inline bool AbstractMetaFunction::isFinalInTargetLang() const -{ - return attributes().testFlag(FinalInTargetLang); -} - inline bool AbstractMetaFunction::isAbstract() const { - return attributes().testFlag(Abstract); + return cppAttributes().testFlag(FunctionAttribute::Abstract); } inline bool AbstractMetaFunction::isStatic() const { - return attributes().testFlag(Static); + return cppAttributes().testFlag(FunctionAttribute::Static); } inline bool AbstractMetaFunction::isClassMethod() const @@ -438,11 +459,6 @@ inline bool AbstractMetaFunction::isClassMethod() const return attributes().testFlag(ClassMethod); } -inline bool AbstractMetaFunction::isInvokable() const -{ - return attributes().testFlag(Invokable); -} - inline bool AbstractMetaFunction::isPropertyReader() const { return attributes().testFlag(PropertyReader); @@ -458,15 +474,12 @@ inline bool AbstractMetaFunction::isPropertyResetter() const return attributes().testFlag(PropertyResetter); } -inline bool AbstractMetaFunction::isFriendly() const -{ - return attributes().testFlag(Friendly); -} - Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::CompareResult) Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::Attributes); +Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::Flags); + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const AbstractMetaFunction *af); #endif diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang.cpp b/sources/shiboken6/ApiExtractor/abstractmetalang.cpp index 080257346..fb49cc9d0 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetalang.cpp @@ -1,36 +1,15 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "abstractmetalang.h" +#include "anystringview_helpers.h" #include "abstractmetalang_helpers.h" +#include "abstractmetaargument.h" #include "abstractmetaenum.h" #include "abstractmetafunction.h" +#include "abstractmetatype.h" #include "abstractmetafield.h" +#include "parser/codemodel.h" #include "documentation.h" #include "messages.h" #include "modifications.h" @@ -38,13 +17,18 @@ #include "reporthandler.h" #include "sourcelocation.h" #include "typedatabase.h" -#include "typesystem.h" +#include "enumtypeentry.h" +#include "namespacetypeentry.h" #include "usingmember.h" +#include "qtcompat.h" + #include <QtCore/QDebug> #include <algorithm> +using namespace Qt::StringLiterals; + bool function_sorter(const AbstractMetaFunctionCPtr &a, const AbstractMetaFunctionCPtr &b) { return a->signature() < b->signature(); @@ -66,24 +50,30 @@ public: m_hasPrivateDestructor(false), m_hasProtectedDestructor(false), m_hasVirtualDestructor(false), - m_hasHashFunction(false), - m_hasEqualsOperator(false), - m_hasCloneOperator(false), m_isTypeDef(false), m_hasToStringCapability(false), + m_valueTypeWithCopyConstructorOnly(false), m_hasCachedWrapper(false) { } void addFunction(const AbstractMetaFunctionCPtr &function); + static AbstractMetaFunction * + createFunction(const QString &name, AbstractMetaFunction::FunctionType t, + Access access, const AbstractMetaArgumentList &arguments, + const AbstractMetaType &returnType, const AbstractMetaClassPtr &q); void addConstructor(AbstractMetaFunction::FunctionType t, Access access, const AbstractMetaArgumentList &arguments, - AbstractMetaClass *q); - void addUsingConstructors(AbstractMetaClass *q); - bool isUsingMember(const AbstractMetaClass *c, const QString &memberName, + const AbstractMetaClassPtr &q); + void addUsingConstructors(const AbstractMetaClassPtr &q); + void sortFunctions(); + void setFunctions(const AbstractMetaFunctionCList &functions, + const AbstractMetaClassCPtr &q); + bool isUsingMember(const AbstractMetaClassCPtr &c, const QString &memberName, Access minimumAccess) const; bool hasConstructors() const; + qsizetype indexOfProperty(const QString &name) const; uint m_hasVirtuals : 1; uint m_isPolymorphic : 1; @@ -97,33 +87,33 @@ public: uint m_hasPrivateDestructor : 1; uint m_hasProtectedDestructor : 1; uint m_hasVirtualDestructor : 1; - uint m_hasHashFunction : 1; - uint m_hasEqualsOperator : 1; - uint m_hasCloneOperator : 1; uint m_isTypeDef : 1; uint m_hasToStringCapability : 1; + uint m_valueTypeWithCopyConstructorOnly : 1; mutable uint m_hasCachedWrapper : 1; Documentation m_doc; - const AbstractMetaClass *m_enclosingClass = nullptr; - AbstractMetaClass *m_defaultSuperclass = nullptr; - AbstractMetaClassList m_baseClasses; // Real base classes after setting up inheritance + AbstractMetaClassCPtr m_enclosingClass; + AbstractMetaClassCPtr m_defaultSuperclass; + AbstractMetaClassCList m_baseClasses; // Real base classes after setting up inheritance AbstractMetaTypeList m_baseTemplateInstantiations; - const AbstractMetaClass *m_extendedNamespace = nullptr; + AbstractMetaClassCPtr m_extendedNamespace; - const AbstractMetaClass *m_templateBaseClass = nullptr; + AbstractMetaClassCPtr m_templateBaseClass; AbstractMetaFunctionCList m_functions; + AbstractMetaFunctionCList m_userAddedPythonOverrides; AbstractMetaFieldList m_fields; AbstractMetaEnumList m_enums; QList<QPropertySpec> m_propertySpecs; - AbstractMetaClassList m_innerClasses; + AbstractMetaClassCList m_innerClasses; + QString m_hashFunction; AbstractMetaFunctionCList m_externalConversionOperators; QStringList m_baseClassNames; // Base class names from C++, including rejected - TypeEntries m_templateArgs; - ComplexTypeEntry *m_typeEntry = nullptr; + TypeEntryCList m_templateArgs; + ComplexTypeEntryPtr m_typeEntry; SourceLocation m_sourceLocation; UsingMembers m_usingMembers; @@ -160,24 +150,6 @@ void AbstractMetaClass::operator-=(AbstractMetaClass::Attribute attribute) d->m_attributes.setFlag(attribute, false); } -/******************************************************************************* - * Returns true if this class is a subclass of the given class - */ -bool AbstractMetaClass::inheritsFrom(const AbstractMetaClass *cls) const -{ - Q_ASSERT(cls); - - const AbstractMetaClass *clazz = this; - while (clazz) { - if (clazz == cls) - return true; - - clazz = clazz->baseClass(); - } - - return false; -} - bool AbstractMetaClass::isPolymorphic() const { return d->m_isPolymorphic; @@ -206,29 +178,16 @@ AbstractMetaFunctionCList AbstractMetaClass::functionsInTargetLang() const FunctionQueryOptions default_flags = FunctionQueryOption::NormalFunctions | FunctionQueryOption::Visible | FunctionQueryOption::NotRemoved; - // Only public functions in final classes - // default_flags |= isFinal() ? WasPublic : 0; - FunctionQueryOptions public_flags; - if (isFinalInTargetLang()) - public_flags |= FunctionQueryOption::WasPublic; - // Constructors - AbstractMetaFunctionCList returned = queryFunctions(FunctionQueryOption::Constructors - | default_flags | public_flags); - - // Final functions - returned += queryFunctions(FunctionQueryOption::FinalInTargetLangFunctions - | FunctionQueryOption::NonStaticFunctions - | default_flags | public_flags); + AbstractMetaFunctionCList returned = queryFunctions(FunctionQueryOption::AnyConstructor + | default_flags); - // Virtual functions - returned += queryFunctions(FunctionQueryOption::VirtualInTargetLangFunctions - | FunctionQueryOption::NonStaticFunctions - | default_flags | public_flags); + returned += queryFunctions(FunctionQueryOption::NonStaticFunctions + | default_flags); // Static functions returned += queryFunctions(FunctionQueryOption::StaticFunctions - | default_flags | public_flags); + | default_flags); // Empty, private functions, since they aren't caught by the other ones returned += queryFunctions(FunctionQueryOption::Empty | FunctionQueryOption::Invisible); @@ -238,7 +197,7 @@ AbstractMetaFunctionCList AbstractMetaClass::functionsInTargetLang() const AbstractMetaFunctionCList AbstractMetaClass::implicitConversions() const { - if (!hasCloneOperator() && !hasExternalConversionOperators()) + if (!isCopyConstructible() && !hasExternalConversionOperators()) return {}; AbstractMetaFunctionCList returned; @@ -250,7 +209,6 @@ AbstractMetaFunctionCList AbstractMetaClass::implicitConversions() const for (const auto &f : list) { if ((f->actualMinimumArgumentCount() == 1 || f->arguments().size() == 1 || f->isConversionOperator()) && !f->isExplicit() - && f->functionType() != AbstractMetaFunction::CopyConstructorFunction && !f->usesRValueReferences() && !f->isModifiedRemoved() && f->wasPublic()) { @@ -348,15 +306,15 @@ bool AbstractMetaClass::hasStaticFields() const void AbstractMetaClass::sortFunctions() { - std::sort(d->m_functions.begin(), d->m_functions.end(), function_sorter); + d->sortFunctions(); } -const AbstractMetaClass *AbstractMetaClass::templateBaseClass() const +AbstractMetaClassCPtr AbstractMetaClass::templateBaseClass() const { return d->m_templateBaseClass; } -void AbstractMetaClass::setTemplateBaseClass(const AbstractMetaClass *cls) +void AbstractMetaClass::setTemplateBaseClass(const AbstractMetaClassCPtr &cls) { d->m_templateBaseClass = cls; } @@ -366,48 +324,29 @@ const AbstractMetaFunctionCList &AbstractMetaClass::functions() const return d->m_functions; } -void AbstractMetaClass::setFunctions(const AbstractMetaFunctionCList &functions) -{ - d->m_functions = functions; - - // Functions must be sorted by name before next loop - sortFunctions(); - - for (const auto &f : qAsConst(d->m_functions)) { - qSharedPointerConstCast<AbstractMetaFunction>(f)->setOwnerClass(this); - if (!f->isPublic()) - d->m_hasNonpublic = true; - } -} - -bool AbstractMetaClass::hasDefaultToStringFunction() const +const AbstractMetaFunctionCList &AbstractMetaClass::userAddedPythonOverrides() const { - const auto &funcs = queryFunctionsByName(QLatin1String("toString")); - for (const auto &f : funcs) { - if (!f->actualMinimumArgumentCount()) - return true; - } - return false; + return d->m_userAddedPythonOverrides; } -bool AbstractMetaClass::hasEqualsOperator() const +void AbstractMetaClassPrivate::sortFunctions() { - return d->m_hasEqualsOperator; + std::sort(m_functions.begin(), m_functions.end(), function_sorter); } -void AbstractMetaClass::setHasEqualsOperator(bool on) +void AbstractMetaClassPrivate::setFunctions(const AbstractMetaFunctionCList &functions, + const AbstractMetaClassCPtr &q) { - d->m_hasEqualsOperator = on; -} + m_functions = functions; -bool AbstractMetaClass::hasCloneOperator() const -{ - return d->m_hasCloneOperator; -} + // Functions must be sorted by name before next loop + sortFunctions(); -void AbstractMetaClass::setHasCloneOperator(bool on) -{ - d->m_hasCloneOperator = on; + for (const auto &f : std::as_const(m_functions)) { + std::const_pointer_cast<AbstractMetaFunction>(f)->setOwnerClass(q); + if (!f->isPublic()) + m_hasNonpublic = true; + } } const QList<QPropertySpec> &AbstractMetaClass::propertySpecs() const @@ -420,9 +359,16 @@ void AbstractMetaClass::addPropertySpec(const QPropertySpec &spec) d->m_propertySpecs << spec; } +void AbstractMetaClass::setPropertyDocumentation(const QString &name, const Documentation &doc) +{ + const auto index = d->indexOfProperty(name); + if (index >= 0) + d->m_propertySpecs[index].setDocumentation(doc); +} + void AbstractMetaClassPrivate::addFunction(const AbstractMetaFunctionCPtr &function) { - Q_ASSERT(!function->signature().startsWith(QLatin1Char('('))); + Q_ASSERT(!function->signature().startsWith(u'(')); if (!function->isDestructor()) m_functions << function; @@ -432,12 +378,31 @@ void AbstractMetaClassPrivate::addFunction(const AbstractMetaFunctionCPtr &funct m_hasVirtuals |= function->isVirtual(); m_isPolymorphic |= m_hasVirtuals; m_hasNonpublic |= !function->isPublic(); + m_hasNonPrivateConstructor |= !function->isPrivate() + && function->functionType() == AbstractMetaFunction::ConstructorFunction; } -void AbstractMetaClass::addFunction(const AbstractMetaFunctionCPtr &function) +void AbstractMetaClass::addFunction(const AbstractMetaClassPtr &klass, + const AbstractMetaFunctionCPtr &function) { - qSharedPointerConstCast<AbstractMetaFunction>(function)->setOwnerClass(this); - d->addFunction(function); + auto nonConstF = std::const_pointer_cast<AbstractMetaFunction>(function); + nonConstF->setOwnerClass(klass); + + // Set the default value of the declaring class. This may be changed + // in fixFunctions later on + nonConstF->setDeclaringClass(klass); + + // Some of the queries below depend on the implementing class being set + // to function properly. Such as function modifications + nonConstF->setImplementingClass(klass); + + if (function->isUserAddedPythonOverride()) { + nonConstF->setConstant(false); + nonConstF->setCppAttribute(FunctionAttribute::Static); + klass->d->m_userAddedPythonOverrides.append(function); + } else { + klass->d->addFunction(function); + } } bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const @@ -475,32 +440,32 @@ QString AbstractMetaClass::baseClassName() const } // Attribute "default-superclass" -AbstractMetaClass *AbstractMetaClass::defaultSuperclass() const +AbstractMetaClassCPtr AbstractMetaClass::defaultSuperclass() const { return d->m_defaultSuperclass; } -void AbstractMetaClass::setDefaultSuperclass(AbstractMetaClass *s) +void AbstractMetaClass::setDefaultSuperclass(const AbstractMetaClassPtr &s) { d->m_defaultSuperclass = s; } -AbstractMetaClass *AbstractMetaClass::baseClass() const +AbstractMetaClassCPtr AbstractMetaClass::baseClass() const { return d->m_baseClasses.value(0, nullptr); } -const AbstractMetaClassList &AbstractMetaClass::baseClasses() const +const AbstractMetaClassCList &AbstractMetaClass::baseClasses() const { Q_ASSERT(inheritanceDone() || !needsInheritanceSetup()); return d->m_baseClasses; } // base classes including "defaultSuperclass". -AbstractMetaClassList AbstractMetaClass::typeSystemBaseClasses() const +AbstractMetaClassCList AbstractMetaClass::typeSystemBaseClasses() const { - AbstractMetaClassList result = d->m_baseClasses; - if (d->m_defaultSuperclass != nullptr) { + AbstractMetaClassCList result = d->m_baseClasses; + if (d->m_defaultSuperclass) { result.removeAll(d->m_defaultSuperclass); result.prepend(d->m_defaultSuperclass); } @@ -508,25 +473,25 @@ AbstractMetaClassList AbstractMetaClass::typeSystemBaseClasses() const } // Recursive list of all base classes including defaultSuperclass -AbstractMetaClassList AbstractMetaClass::allTypeSystemAncestors() const +AbstractMetaClassCList AbstractMetaClass::allTypeSystemAncestors() const { - AbstractMetaClassList result; - const AbstractMetaClassList baseClasses = typeSystemBaseClasses(); - for (AbstractMetaClass *base : baseClasses) { + AbstractMetaClassCList result; + const auto baseClasses = typeSystemBaseClasses(); + for (const auto &base : baseClasses) { result.append(base); result.append(base->allTypeSystemAncestors()); } return result; } -void AbstractMetaClass::addBaseClass(AbstractMetaClass *baseClass) +void AbstractMetaClass::addBaseClass(const AbstractMetaClassCPtr &baseClass) { Q_ASSERT(baseClass); d->m_baseClasses.append(baseClass); d->m_isPolymorphic |= baseClass->isPolymorphic(); } -void AbstractMetaClass::setBaseClass(AbstractMetaClass *baseClass) +void AbstractMetaClass::setBaseClass(const AbstractMetaClassCPtr &baseClass) { if (baseClass) { d->m_baseClasses.prepend(baseClass); @@ -534,27 +499,27 @@ void AbstractMetaClass::setBaseClass(AbstractMetaClass *baseClass) } } -const AbstractMetaClass *AbstractMetaClass::extendedNamespace() const +AbstractMetaClassCPtr AbstractMetaClass::extendedNamespace() const { return d->m_extendedNamespace; } -void AbstractMetaClass::setExtendedNamespace(const AbstractMetaClass *e) +void AbstractMetaClass::setExtendedNamespace(const AbstractMetaClassCPtr &e) { d->m_extendedNamespace = e; } -const AbstractMetaClassList &AbstractMetaClass::innerClasses() const +const AbstractMetaClassCList &AbstractMetaClass::innerClasses() const { return d->m_innerClasses; } -void AbstractMetaClass::addInnerClass(AbstractMetaClass *cl) +void AbstractMetaClass::addInnerClass(const AbstractMetaClassPtr &cl) { d->m_innerClasses << cl; } -void AbstractMetaClass::setInnerClasses(const AbstractMetaClassList &innerClasses) +void AbstractMetaClass::setInnerClasses(const AbstractMetaClassCList &innerClasses) { d->m_innerClasses = innerClasses; } @@ -577,19 +542,19 @@ bool AbstractMetaClass::isInvisibleNamespace() const && !NamespaceTypeEntry::isVisibleScope(d->m_typeEntry); } -static bool qObjectPredicate(const AbstractMetaClass *c) -{ - return c->qualifiedCppName() == QLatin1String("QObject"); -} - -bool AbstractMetaClass::isQObject() const +bool AbstractMetaClass::isInlineNamespace() const { - return qObjectPredicate(this) || recurseClassHierarchy(this, qObjectPredicate) != nullptr; + bool result = false; + if (d->m_typeEntry->isNamespace()) { + const auto nte = std::static_pointer_cast<const NamespaceTypeEntry>(d->m_typeEntry); + result = nte->isInlineNamespace(); + } + return result; } bool AbstractMetaClass::isQtNamespace() const { - return isNamespace() && name() == QLatin1String("Qt"); + return isNamespace() && name() == u"Qt"; } QString AbstractMetaClass::qualifiedCppName() const @@ -599,15 +564,15 @@ QString AbstractMetaClass::qualifiedCppName() const bool AbstractMetaClass::hasFunction(const QString &str) const { - return !findFunction(str).isNull(); + return bool(findFunction(str)); } -AbstractMetaFunctionCPtr AbstractMetaClass::findFunction(const QString &functionName) const +AbstractMetaFunctionCPtr AbstractMetaClass::findFunction(QAnyStringView functionName) const { return AbstractMetaFunction::find(d->m_functions, functionName); } -AbstractMetaFunctionCList AbstractMetaClass::findFunctions(const QString &functionName) const +AbstractMetaFunctionCList AbstractMetaClass::findFunctions(QAnyStringView functionName) const { AbstractMetaFunctionCList result; std::copy_if(d->m_functions.cbegin(), d->m_functions.cend(), @@ -640,15 +605,6 @@ AbstractMetaFunctionCPtr AbstractMetaClass::findQtIsNullMethod() const return *it; } -bool AbstractMetaClass::hasProtectedFunctions() const -{ - for (const auto &func : d->m_functions) { - if (func->isProtected()) - return true; - } - return false; -} - bool AbstractMetaClass::hasProtectedFields() const { for (const AbstractMetaField &field : d->m_fields) { @@ -658,17 +614,12 @@ bool AbstractMetaClass::hasProtectedFields() const return false; } -bool AbstractMetaClass::hasProtectedMembers() const -{ - return hasProtectedFields() || hasProtectedFunctions(); -} - -const TypeEntries &AbstractMetaClass::templateArguments() const +const TypeEntryCList &AbstractMetaClass::templateArguments() const { return d->m_templateArgs; } -void AbstractMetaClass::setTemplateArguments(const TypeEntries &args) +void AbstractMetaClass::setTemplateArguments(const TypeEntryCList &args) { d->m_templateArgs = args; } @@ -683,36 +634,41 @@ void AbstractMetaClass::setBaseClassNames(const QStringList &names) d->m_baseClassNames = names; } -const ComplexTypeEntry *AbstractMetaClass::typeEntry() const +ComplexTypeEntryCPtr AbstractMetaClass::typeEntry() const { return d->m_typeEntry; } -ComplexTypeEntry *AbstractMetaClass::typeEntry() +ComplexTypeEntryPtr AbstractMetaClass::typeEntry() { return d->m_typeEntry; } -void AbstractMetaClass::setTypeEntry(ComplexTypeEntry *type) +void AbstractMetaClass::setTypeEntry(const ComplexTypeEntryPtr &type) { d->m_typeEntry = type; } -void AbstractMetaClass::setHasHashFunction(bool on) +QString AbstractMetaClass::hashFunction() const { - d->m_hasHashFunction = on; + return d->m_hashFunction; +} + +void AbstractMetaClass::setHashFunction(const QString &f) +{ + d->m_hashFunction = f; } bool AbstractMetaClass::hasHashFunction() const { - return d->m_hasHashFunction; + return !d->m_hashFunction.isEmpty(); } // Search whether a functions is a property setter/getter/reset AbstractMetaClass::PropertyFunctionSearchResult AbstractMetaClass::searchPropertyFunction(const QString &name) const { - for (int i = 0, size = d->m_propertySpecs.size(); i < size; ++i) { + for (qsizetype i = 0, size = d->m_propertySpecs.size(); i < size; ++i) { const auto &propertySpec = d->m_propertySpecs.at(i); if (name == propertySpec.read()) return PropertyFunctionSearchResult{i, PropertyFunction::Read}; @@ -720,6 +676,8 @@ AbstractMetaClass::PropertyFunctionSearchResult return PropertyFunctionSearchResult{i, PropertyFunction::Write}; if (name == propertySpec.reset()) return PropertyFunctionSearchResult{i, PropertyFunction::Reset}; + if (name == propertySpec.notify()) + return PropertyFunctionSearchResult{i, PropertyFunction::Notify}; } return PropertyFunctionSearchResult{-1, PropertyFunction::Read}; } @@ -727,10 +685,9 @@ AbstractMetaClass::PropertyFunctionSearchResult std::optional<QPropertySpec> AbstractMetaClass::propertySpecByName(const QString &name) const { - for (const auto &propertySpec : d->m_propertySpecs) { - if (name == propertySpec.name()) - return propertySpec; - } + const auto index = d->indexOfProperty(name); + if (index >= 0) + return d->m_propertySpecs.at(index); return {}; } @@ -812,7 +769,16 @@ bool AbstractMetaClass::deleteInMainThread() const bool AbstractMetaClassPrivate::hasConstructors() const { return AbstractMetaClass::queryFirstFunction(m_functions, - FunctionQueryOption::Constructors) != nullptr; + FunctionQueryOption::AnyConstructor) != nullptr; +} + +qsizetype AbstractMetaClassPrivate::indexOfProperty(const QString &name) const +{ + for (qsizetype i = 0; i < m_propertySpecs.size(); ++i) { + if (m_propertySpecs.at(i).name() == name) + return i; + } + return -1; } bool AbstractMetaClass::hasConstructors() const @@ -837,51 +803,95 @@ bool AbstractMetaClass::hasCopyConstructor() const bool AbstractMetaClass::hasPrivateCopyConstructor() const { const auto copyCt = copyConstructor(); - return !copyCt.isNull() && copyCt->isPrivate(); + return copyCt && copyCt->isPrivate(); } void AbstractMetaClassPrivate::addConstructor(AbstractMetaFunction::FunctionType t, Access access, const AbstractMetaArgumentList &arguments, - AbstractMetaClass *q) + const AbstractMetaClassPtr &q) { - auto *f = new AbstractMetaFunction; - f->setType(AbstractMetaType::createVoid()); - f->setOriginalName(q->name()); - f->setName(q->name()); - f->setOwnerClass(q); - f->setFunctionType(t); - f->setArguments(arguments); - f->setDeclaringClass(q); - f->setAccess(access); + auto *f = createFunction(q->name(), t, access, arguments, AbstractMetaType::createVoid(), q); if (access != Access::Private) m_hasNonPrivateConstructor = true; - f->setAttributes(AbstractMetaFunction::FinalInTargetLang - | AbstractMetaFunction::AddedMethod); - f->setImplementingClass(q); - + f->setAttributes(AbstractMetaFunction::AddedMethod); addFunction(AbstractMetaFunctionCPtr(f)); } -void AbstractMetaClass::addDefaultConstructor() +void AbstractMetaClass::addDefaultConstructor(const AbstractMetaClassPtr &klass) { - d->addConstructor(AbstractMetaFunction::ConstructorFunction, - Access::Public, {}, this); + klass->d->addConstructor(AbstractMetaFunction::ConstructorFunction, + Access::Public, {}, klass); } -void AbstractMetaClass::addDefaultCopyConstructor() +void AbstractMetaClass::addDefaultCopyConstructor(const AbstractMetaClassPtr &klass) { - AbstractMetaType argType(typeEntry()); + AbstractMetaType argType(klass->typeEntry()); argType.setReferenceType(LValueReference); argType.setConstant(true); argType.setTypeUsagePattern(AbstractMetaType::ValuePattern); AbstractMetaArgument arg; arg.setType(argType); - arg.setName(name()); + arg.setName(klass->name()); + + klass->d->addConstructor(AbstractMetaFunction::CopyConstructorFunction, + Access::Public, {arg}, klass); +} + +AbstractMetaFunction * + AbstractMetaClassPrivate::createFunction(const QString &name, + AbstractMetaFunction::FunctionType t, + Access access, + const AbstractMetaArgumentList &arguments, + const AbstractMetaType &returnType, + const AbstractMetaClassPtr &q) +{ + auto *f = new AbstractMetaFunction(name); + f->setType(returnType); + f->setOwnerClass(q); + f->setFunctionType(t); + f->setArguments(arguments); + f->setDeclaringClass(q); + f->setAccess(access); + f->setImplementingClass(q); + return f; +} - d->addConstructor(AbstractMetaFunction::CopyConstructorFunction, - Access::Public, {arg}, this); +static AbstractMetaType boolType() +{ + auto boolType = TypeDatabase::instance()->findType(u"bool"_s); + Q_ASSERT(boolType); + AbstractMetaType result(boolType); + result.decideUsagePattern(); + return result; +} + +// Helper to synthesize comparison operators from a spaceship operator. Since +// shiboken also generates code for comparing to different types, this fits +// better than of handling it in the generator code. +void AbstractMetaClass::addSynthesizedComparisonOperators(const AbstractMetaClassPtr &c) +{ + static const auto returnType = boolType(); + + AbstractMetaType selfType(c->typeEntry()); + selfType.setConstant(true); + selfType.setReferenceType(LValueReference); + selfType.decideUsagePattern(); + AbstractMetaArgument selfArgument; + selfArgument.setType(selfType); + selfArgument.setName(u"rhs"_s); + AbstractMetaArgumentList arguments(1, selfArgument); + + static const char *operators[] + = {"operator==", "operator!=", "operator<", "operator<=", "operator>", "operator>="}; + for (auto *op : operators) { + auto *f = AbstractMetaClassPrivate::createFunction(QLatin1StringView(op), + AbstractMetaFunction::ComparisonOperator, + Access::Public, arguments, + returnType, c); + c->d->addFunction(AbstractMetaFunctionCPtr(f)); + } } bool AbstractMetaClass::hasNonPrivateConstructor() const @@ -974,6 +984,8 @@ bool AbstractMetaClass::isDefaultConstructible() const // (non-ref or not const value). static bool defaultConstructibleField(const AbstractMetaField &f) { + if (f.isStatic()) + return true; const auto &type = f.type(); return type.referenceType() == NoReference && !(type.indirections() == 0 && type.isConstant()); // no const values @@ -984,7 +996,7 @@ bool AbstractMetaClass::isImplicitlyDefaultConstructible() const return std::all_of(d->m_fields.cbegin(), d->m_fields.cend(), defaultConstructibleField) && std::all_of(d->m_baseClasses.cbegin(), d->m_baseClasses.cend(), - [] (const AbstractMetaClass *c) { + [] (const AbstractMetaClassCPtr &c) { return c->isDefaultConstructible(); }); } @@ -992,6 +1004,7 @@ bool AbstractMetaClass::isImplicitlyDefaultConstructible() const static bool canAddDefaultConstructorHelper(const AbstractMetaClass *cls) { return !cls->isNamespace() + && !cls->hasDeletedDefaultConstructor() && !cls->attributes().testFlag(AbstractMetaClass::HasRejectedConstructor) && !cls->hasPrivateDestructor(); } @@ -1018,7 +1031,7 @@ bool AbstractMetaClass::isImplicitlyCopyConstructible() const { // Fields are currently not considered return std::all_of(d->m_baseClasses.cbegin(), d->m_baseClasses.cend(), - [] (const AbstractMetaClass *c) { + [] (const AbstractMetaClassCPtr &c) { return c->isCopyConstructible(); }); } @@ -1033,6 +1046,21 @@ bool AbstractMetaClass::canAddDefaultCopyConstructor() const return isImplicitlyCopyConstructible(); } +static bool classHasParentManagement(const AbstractMetaClassCPtr &c) +{ + const auto flags = c->typeEntry()->typeFlags(); + return flags.testFlag(ComplexTypeEntry::ParentManagement); +} + +TypeEntryCPtr parentManagementEntry(const AbstractMetaClassCPtr &klass) +{ + if (klass->typeEntry()->isObject()) { + if (auto c = recurseClassHierarchy(klass, classHasParentManagement)) + return c->typeEntry(); + } + return nullptr; +} + bool AbstractMetaClass::generateExceptionHandling() const { return queryFirstFunction(d->m_functions, FunctionQueryOption::Visible @@ -1097,7 +1125,7 @@ void AbstractMetaClass::addUsingMember(const UsingMember &um) d->m_usingMembers.append(um); } -bool AbstractMetaClassPrivate::isUsingMember(const AbstractMetaClass *c, +bool AbstractMetaClassPrivate::isUsingMember(const AbstractMetaClassCPtr &c, const QString &memberName, Access minimumAccess) const { @@ -1108,13 +1136,21 @@ bool AbstractMetaClassPrivate::isUsingMember(const AbstractMetaClass *c, return it != m_usingMembers.cend() && it->access >= minimumAccess; } -bool AbstractMetaClass::isUsingMember(const AbstractMetaClass *c, +bool AbstractMetaClass::isUsingMember(const AbstractMetaClassCPtr &c, const QString &memberName, Access minimumAccess) const { return d->isUsingMember(c, memberName, minimumAccess); } +bool AbstractMetaClass::hasUsingMemberFor(const QString &memberName) const +{ + return std::any_of(d->m_usingMembers.cbegin(), d->m_usingMembers.cend(), + [&memberName](const UsingMember &um) { + return um.memberName == memberName; + }); +} + /* Goes through the list of functions and returns a list of all functions matching all of the criteria in \a query. */ @@ -1131,35 +1167,32 @@ bool AbstractMetaClass::queryFunction(const AbstractMetaFunction *f, FunctionQue if (query.testFlag(FunctionQueryOption::Visible) && f->isPrivate()) return false; - if (query.testFlag(FunctionQueryOption::VirtualInTargetLangFunctions) && f->isFinalInTargetLang()) - return false; - if (query.testFlag(FunctionQueryOption::Invisible) && !f->isPrivate()) return false; if (query.testFlag(FunctionQueryOption::Empty) && !f->isEmptyFunction()) return false; - if (query.testFlag(FunctionQueryOption::WasPublic) && !f->wasPublic()) - return false; - if (query.testFlag(FunctionQueryOption::ClassImplements) && f->ownerClass() != f->implementingClass()) return false; - if (query.testFlag(FunctionQueryOption::FinalInTargetLangFunctions) && !f->isFinalInTargetLang()) - return false; - if (query.testFlag(FunctionQueryOption::VirtualInCppFunctions) && !f->isVirtual()) return false; if (query.testFlag(FunctionQueryOption::Signals) && (!f->isSignal())) return false; - if (query.testFlag(FunctionQueryOption::Constructors) + if (query.testFlag(FunctionQueryOption::AnyConstructor) && (!f->isConstructor() || f->ownerClass() != f->implementingClass())) { return false; } + if (query.testFlag(FunctionQueryOption::Constructors) + && (f->functionType() != AbstractMetaFunction::ConstructorFunction + || f->ownerClass() != f->implementingClass())) { + return false; + } + if (query.testFlag(FunctionQueryOption::CopyConstructor) && (!f->isCopyConstructor() || f->ownerClass() != f->implementingClass())) { return false; @@ -1206,7 +1239,7 @@ AbstractMetaFunctionCList AbstractMetaClass::queryFunctionList(const AbstractMet { AbstractMetaFunctionCList result; for (const auto &f : list) { - if (queryFunction(f.data(), query)) + if (queryFunction(f.get(), query)) result.append(f); } return result; @@ -1216,7 +1249,7 @@ AbstractMetaFunctionCPtr AbstractMetaClass::queryFirstFunction(const AbstractMet FunctionQueryOptions query) { for (const auto &f : list) { - if (queryFunction(f.data(), query)) + if (queryFunction(f.get(), query)) return f; } return {}; @@ -1243,7 +1276,7 @@ AbstractMetaFunctionCList AbstractMetaClass::cppSignalFunctions() const } std::optional<AbstractMetaField> - AbstractMetaClass::findField(const QString &name) const + AbstractMetaClass::findField(QStringView name) const { return AbstractMetaField::find(d->m_fields, name); } @@ -1284,7 +1317,7 @@ std::optional<AbstractMetaEnum> std::optional<AbstractMetaEnumValue> AbstractMetaClass::findEnumValue(const QString &enumValueName) const { - for (const AbstractMetaEnum &e : qAsConst(d->m_enums)) { + for (const AbstractMetaEnum &e : std::as_const(d->m_enums)) { auto v = e.findEnumValue(enumValueName); if (v.has_value()) return v; @@ -1306,7 +1339,7 @@ void AbstractMetaClass::getEnumsToBeGenerated(AbstractMetaEnumList *enumList) co void AbstractMetaClass::getEnumsFromInvisibleNamespacesToBeGenerated(AbstractMetaEnumList *enumList) const { if (isNamespace()) { - invisibleNamespaceRecursion([enumList](AbstractMetaClass *c) { + invisibleNamespaceRecursion([enumList](const AbstractMetaClassCPtr &c) { c->getEnumsToBeGenerated(enumList); }); } @@ -1315,7 +1348,7 @@ void AbstractMetaClass::getEnumsFromInvisibleNamespacesToBeGenerated(AbstractMet void AbstractMetaClass::getFunctionsFromInvisibleNamespacesToBeGenerated(AbstractMetaFunctionCList *funcList) const { if (isNamespace()) { - invisibleNamespaceRecursion([funcList](AbstractMetaClass *c) { + invisibleNamespaceRecursion([funcList](const AbstractMetaClassCPtr &c) { funcList->append(c->functions()); }); } @@ -1323,19 +1356,19 @@ void AbstractMetaClass::getFunctionsFromInvisibleNamespacesToBeGenerated(Abstrac QString AbstractMetaClass::fullName() const { - return package() + QLatin1Char('.') + d->m_typeEntry->targetLangName(); + return package() + u'.' + d->m_typeEntry->targetLangName(); } -static void addExtraIncludeForType(AbstractMetaClass *metaClass, const AbstractMetaType &type) +static void addExtraIncludeForType(const AbstractMetaClassPtr &metaClass, + const AbstractMetaType &type) { Q_ASSERT(metaClass); - const TypeEntry *entry = type.typeEntry(); - if (entry && entry->isComplex()) { - const auto *centry = static_cast<const ComplexTypeEntry *>(entry); - ComplexTypeEntry *class_entry = metaClass->typeEntry(); - if (class_entry && centry->include().isValid()) - class_entry->addExtraInclude(centry->include()); + const auto entry = type.typeEntry(); + + if (entry && entry->include().isValid()) { + const auto class_entry = metaClass->typeEntry(); + class_entry->addArgumentInclude(entry->include()); } if (type.hasInstantiations()) { @@ -1344,7 +1377,7 @@ static void addExtraIncludeForType(AbstractMetaClass *metaClass, const AbstractM } } -static void addExtraIncludesForFunction(AbstractMetaClass *metaClass, +static void addExtraIncludesForFunction(const AbstractMetaClassPtr &metaClass, const AbstractMetaFunctionCPtr &meta_function) { Q_ASSERT(metaClass); @@ -1352,8 +1385,12 @@ static void addExtraIncludesForFunction(AbstractMetaClass *metaClass, addExtraIncludeForType(metaClass, meta_function->type()); const AbstractMetaArgumentList &arguments = meta_function->arguments(); - for (const AbstractMetaArgument &argument : arguments) - addExtraIncludeForType(metaClass, argument.type()); + for (const AbstractMetaArgument &argument : arguments) { + const auto &type = argument.type(); + addExtraIncludeForType(metaClass, type); + if (argument.modifiedType() != type) + addExtraIncludeForType(metaClass, argument.modifiedType()); + } } static bool addSuperFunction(const AbstractMetaFunctionCPtr &f) @@ -1375,7 +1412,7 @@ static bool addSuperFunction(const AbstractMetaFunctionCPtr &f) // Add constructors imported via "using" from the base classes. This is not // needed for normal hidden inherited member functions since we generate a // cast to the base class to call them into binding code. -void AbstractMetaClassPrivate::addUsingConstructors(AbstractMetaClass *q) +void AbstractMetaClassPrivate::addUsingConstructors(const AbstractMetaClassPtr &q) { // Restricted to the non-constructor case currently to avoid // having to compare the parameter lists of existing constructors. @@ -1384,14 +1421,13 @@ void AbstractMetaClassPrivate::addUsingConstructors(AbstractMetaClass *q) return; } - for (auto superClass : m_baseClasses) { + for (const auto &superClass : m_baseClasses) { // Find any "using base-constructor" directives if (isUsingMember(superClass, superClass->name(), Access::Protected)) { // Add to derived class with parameter lists. const auto ctors = superClass->queryFunctions(FunctionQueryOption::Constructors); for (const auto &ctor : ctors) { - if (ctor->functionType() == AbstractMetaFunction::ConstructorFunction - && !ctor->isPrivate()) { + if (!ctor->isPrivate()) { addConstructor(AbstractMetaFunction::ConstructorFunction, ctor->access(), ctor->arguments(), q); } @@ -1400,50 +1436,61 @@ void AbstractMetaClassPrivate::addUsingConstructors(AbstractMetaClass *q) } } -void AbstractMetaClass::fixFunctions() +static inline bool isSignal(const AbstractMetaFunctionCPtr &f) +{ + return f->isSignal(); +} + +void AbstractMetaClass::fixFunctions(const AbstractMetaClassPtr &klass) { + auto *d = klass->d.data(); if (d->m_functionsFixed) return; d->m_functionsFixed = true; - AbstractMetaFunctionCList funcs = functions(); + AbstractMetaFunctionCList funcs = klass->functions(); AbstractMetaFunctionCList nonRemovedFuncs; nonRemovedFuncs.reserve(funcs.size()); - d->addUsingConstructors(this); + d->addUsingConstructors(klass); - for (const auto &f : qAsConst(funcs)) { + for (const auto &f : std::as_const(funcs)) { // Fishy: Setting up of implementing/declaring/base classes changes // the applicable modifications; clear cached ones. - qSharedPointerConstCast<AbstractMetaFunction>(f)->clearModificationsCache(); + std::const_pointer_cast<AbstractMetaFunction>(f)->clearModificationsCache(); if (!f->isModifiedRemoved()) nonRemovedFuncs.append(f); } - for (auto superClass : d->m_baseClasses) { - superClass->fixFunctions(); + for (const auto &superClassC : d->m_baseClasses) { + for (const auto &pof : superClassC->userAddedPythonOverrides()) { + auto *clonedPof = pof->copy(); + clonedPof->setOwnerClass(klass); + d->m_userAddedPythonOverrides.append(AbstractMetaFunctionCPtr{clonedPof}); + } + + auto superClass = std::const_pointer_cast<AbstractMetaClass>(superClassC); + AbstractMetaClass::fixFunctions(superClass); // Since we always traverse the complete hierarchy we are only // interrested in what each super class implements, not what // we may have propagated from their base classes again. AbstractMetaFunctionCList superFuncs; - // Super classes can never be final - if (superClass->isFinalInTargetLang()) { - qCWarning(lcShiboken).noquote().nospace() - << "Final class '" << superClass->name() << "' set to non-final, as it is extended by other classes"; - *superClass -= AbstractMetaClass::FinalInTargetLang; - } superFuncs = superClass->queryFunctions(FunctionQueryOption::ClassImplements); + // We are not interested in signals as no bindings are generated for them; + // they cause documentation warnings. + superFuncs.erase(std::remove_if(superFuncs.begin(), superFuncs.end(), isSignal), + superFuncs.end()); const auto virtuals = superClass->queryFunctions(FunctionQueryOption::VirtualInCppFunctions); superFuncs += virtuals; QSet<AbstractMetaFunctionCPtr> funcsToAdd; - for (const auto &sf : qAsConst(superFuncs)) { + for (const auto &sf : std::as_const(superFuncs)) { if (sf->isModifiedRemoved()) continue; // skip functions added in base classes - if (sf->isUserAdded() && sf->declaringClass() != this) + if (sf->isUserAdded() && sf->declaringClass() != klass) continue; // Skip base class comparison operators declared as members (free @@ -1454,35 +1501,25 @@ void AbstractMetaClass::fixFunctions() // we generally don't care about private functions, but we have to get the ones that are // virtual in case they override abstract functions. bool add = addSuperFunction(sf); - for (const auto &cf : qAsConst(nonRemovedFuncs)) { - AbstractMetaFunctionPtr f(qSharedPointerConstCast<AbstractMetaFunction>(cf)); - const AbstractMetaFunction::CompareResult cmp = cf->compareTo(sf.data()); + for (const auto &cf : std::as_const(nonRemovedFuncs)) { + AbstractMetaFunctionPtr f(std::const_pointer_cast<AbstractMetaFunction>(cf)); + const AbstractMetaFunction::CompareResult cmp = cf->compareTo(sf.get()); if (cmp & AbstractMetaFunction::EqualModifiedName) { add = false; if (cmp & AbstractMetaFunction::EqualArguments) { - // Same function, propegate virtual... - if (!(cmp & AbstractMetaFunction::EqualAttributes)) { - if (!f->isEmptyFunction()) { - if (!sf->isFinalInTargetLang() && f->isFinalInTargetLang()) { - *f -= AbstractMetaFunction::FinalInTargetLang; - } -#if 0 - if (!f->isFinalInTargetLang() && f->isPrivate()) { - f->setFunctionType(AbstractMetaFunction::EmptyFunction); - f->setVisibility(AbstractMetaAttributes::Protected); - *f += AbstractMetaAttributes::FinalInTargetLang; - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("private virtual function '%1' in '%2'") - .arg(f->signature(), f->implementingClass()->name()); - } -#endif - } + // Set "override" in case it was not spelled out (since it + // is then not detected by clang parsing). + const auto attributes = cf->cppAttributes(); + if (attributes.testFlag(FunctionAttribute::Virtual) + && !attributes.testFlag(FunctionAttribute::Override) + && !attributes.testFlag(FunctionAttribute::Final)) { + f->setCppAttribute(FunctionAttribute::Override); } if (f->access() != sf->access()) { qCWarning(lcShiboken, "%s", - qPrintable(msgFunctionVisibilityModified(this, f.data()))); + qPrintable(msgFunctionVisibilityModified(klass, f.get()))); #if 0 // If new visibility is private, we can't // do anything. If it isn't, then we @@ -1494,43 +1531,12 @@ void AbstractMetaClass::fixFunctions() // Private overrides of abstract functions have to go into the class or // the subclasses will not compile as non-abstract classes. // But they don't need to be implemented, since they can never be called. - if (f->isPrivate()) { + if (f->isPrivate()) f->setFunctionType(AbstractMetaFunction::EmptyFunction); - *f += AbstractMetaFunction::FinalInTargetLang; - } } // Set the class which first declares this function, afawk f->setDeclaringClass(sf->declaringClass()); - - if (sf->isFinalInTargetLang() && !sf->isPrivate() && !f->isPrivate() && !sf->isStatic() && !f->isStatic()) { - // Shadowed funcion, need to make base class - // function non-virtual - if (f->implementingClass() != sf->implementingClass() && f->implementingClass()->inheritsFrom(sf->implementingClass())) { - - // Check whether the superclass method has been redefined to non-final - - bool hasNonFinalModifier = false; - bool isBaseImplPrivate = false; - const FunctionModificationList &mods = sf->modifications(sf->implementingClass()); - for (const FunctionModification &mod : mods) { - if (mod.isNonFinal()) { - hasNonFinalModifier = true; - break; - } - if (mod.isPrivate()) { - isBaseImplPrivate = true; - break; - } - } - - if (!hasNonFinalModifier && !isBaseImplPrivate) { - qCWarning(lcShiboken, "%s", - qPrintable(msgShadowingFunction(sf.data(), f.data()))); - } - } - } - } if (cmp & AbstractMetaFunction::EqualDefaultValueOverload) { @@ -1558,7 +1564,7 @@ void AbstractMetaClass::fixFunctions() funcsToAdd << sf; } - for (const auto &f : qAsConst(funcsToAdd)) { + for (const auto &f : std::as_const(funcsToAdd)) { AbstractMetaFunction *copy = f->copy(); (*copy) += AbstractMetaFunction::AddedMethod; funcs.append(AbstractMetaFunctionCPtr(copy)); @@ -1567,16 +1573,19 @@ void AbstractMetaClass::fixFunctions() bool hasPrivateConstructors = false; bool hasPublicConstructors = false; - for (const auto &func : qAsConst(funcs)) { - for (const auto &mod : func->modifications(this)) { + // Apply modifications after the declaring class has been set + for (const auto &func : std::as_const(funcs)) { + auto ncFunc = std::const_pointer_cast<AbstractMetaFunction>(func); + for (const auto &mod : func->modifications(klass)) { if (mod.isRenameModifier()) - qSharedPointerConstCast<AbstractMetaFunction>(func)->setName(mod.renamedToName()); + ncFunc->setName(mod.renamedToName()); } + ncFunc->applyTypeModifications(); // Make sure class is abstract if one of the functions is if (func->isAbstract()) { - (*this) += AbstractMetaClass::Abstract; - (*this) -= AbstractMetaClass::FinalInTargetLang; + (*klass) += AbstractMetaClass::Abstract; + (*klass) -= AbstractMetaClass::FinalInTargetLang; } if (func->isConstructor()) { @@ -1589,15 +1598,15 @@ void AbstractMetaClass::fixFunctions() // Make sure that we include files for all classes that are in use - addExtraIncludesForFunction(this, func); + addExtraIncludesForFunction(klass, func); } if (hasPrivateConstructors && !hasPublicConstructors) { - (*this) += AbstractMetaClass::Abstract; - (*this) -= AbstractMetaClass::FinalInTargetLang; + (*klass) += AbstractMetaClass::Abstract; + (*klass) -= AbstractMetaClass::FinalInTargetLang; } - setFunctions(funcs); + d->setFunctions(funcs, klass); } bool AbstractMetaClass::needsInheritanceSetup() const @@ -1606,6 +1615,7 @@ bool AbstractMetaClass::needsInheritanceSetup() const switch (d->m_typeEntry->type()) { case TypeEntry::NamespaceType: case TypeEntry::SmartPointerType: + case TypeEntry::ContainerType: return false; default: break; @@ -1628,26 +1638,6 @@ bool AbstractMetaClass::inheritanceDone() const * Other stuff... */ - -std::optional<AbstractMetaEnum> - AbstractMetaClass::findEnum(const AbstractMetaClassList &classes, - const EnumTypeEntry *entry) -{ - Q_ASSERT(entry->isEnum()); - - auto scopeEntry = entry->parent(); - AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes, scopeEntry); - if (!metaClass) { - qCWarning(lcShiboken, "%s", qPrintable(msgClassOfEnumNotFound(entry))); - return {}; - } - - QString qualifiedName = entry->qualifiedCppName(); - const int pos = qualifiedName.lastIndexOf(QLatin1String("::")); - const QString enumName = pos > 0 ? qualifiedName.mid(pos + 2) : qualifiedName; - return metaClass->findEnum(enumName); -} - std::optional<AbstractMetaEnumValue> AbstractMetaClass::findEnumValue(const AbstractMetaClassList &classes, const QString &name) @@ -1657,11 +1647,11 @@ std::optional<AbstractMetaEnumValue> if (lst.size() > 1) { const auto &prefixName = lst.at(0); const auto &enumName = lst.at(1); - if (AbstractMetaClass *cl = findClass(classes, prefixName.toString())) + if (auto cl = findClass(classes, prefixName)) return cl->findEnumValue(enumName.toString()); } - for (AbstractMetaClass *metaClass : classes) { + for (const auto &metaClass : classes) { auto enumValue = metaClass->findEnumValue(name); if (enumValue.has_value()) return enumValue; @@ -1675,12 +1665,12 @@ std::optional<AbstractMetaEnumValue> /// Target language base name or complete Target language package.class name. template <class It> -static It findClassHelper(It begin, It end, const QString &name) +static It findClassHelper(It begin, It end, QAnyStringView name) { if (name.isEmpty() || begin == end) return end; - if (name.contains(u'.')) { // Search target lang name + if (asv_contains(name,'.')) { // Search target lang name for (auto it = begin; it != end; ++it) { if ((*it)->fullName() == name) return it; @@ -1693,7 +1683,7 @@ static It findClassHelper(It begin, It end, const QString &name) return it; } - if (name.contains(u"::")) // Qualified, cannot possibly match name + if (asv_contains(name, "::")) // Qualified, cannot possibly match name return end; for (auto it = begin; it != end; ++it) { @@ -1704,32 +1694,32 @@ static It findClassHelper(It begin, It end, const QString &name) return end; } -AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassList &classes, - const QString &name) +AbstractMetaClassPtr AbstractMetaClass::findClass(const AbstractMetaClassList &classes, + QAnyStringView name) { auto it =findClassHelper(classes.cbegin(), classes.cend(), name); return it != classes.cend() ? *it : nullptr; } -const AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassCList &classes, - const QString &name) +AbstractMetaClassCPtr AbstractMetaClass::findClass(const AbstractMetaClassCList &classes, + QAnyStringView name) { auto it = findClassHelper(classes.cbegin(), classes.cend(), name); return it != classes.cend() ? *it : nullptr; } -AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassList &classes, - const TypeEntry *typeEntry) +AbstractMetaClassPtr AbstractMetaClass::findClass(const AbstractMetaClassList &classes, + const TypeEntryCPtr &typeEntry) { - for (AbstractMetaClass *c : classes) { + for (AbstractMetaClassPtr c : classes) { if (c->typeEntry() == typeEntry) return c; } return nullptr; } -const AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassCList &classes, - const TypeEntry *typeEntry) +AbstractMetaClassCPtr AbstractMetaClass::findClass(const AbstractMetaClassCList &classes, + const TypeEntryCPtr &typeEntry) { for (auto c : classes) { if (c->typeEntry() == typeEntry) @@ -1738,13 +1728,42 @@ const AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassCLi return nullptr; } -const AbstractMetaClass *AbstractMetaClass::findBaseClass(const QString &qualifiedName) const +/// Returns true if this class is a subclass of the given class +bool inheritsFrom(const AbstractMetaClassCPtr &c, const AbstractMetaClassCPtr &cls) { - if (d->m_templateBaseClass != nullptr - && d->m_templateBaseClass->qualifiedCppName() == qualifiedName) { - return d->m_templateBaseClass; + Q_ASSERT(cls != nullptr); + + if (c == cls || c->templateBaseClass() == cls) + return true; + + return bool(recurseClassHierarchy(c, [cls](const AbstractMetaClassCPtr &c) { + return cls.get() == c.get(); + })); +} + +bool inheritsFrom(const AbstractMetaClassCPtr &c, QAnyStringView name) +{ + if (c->qualifiedCppName() == name) + return true; + + if (c->templateBaseClass() != nullptr + && c->templateBaseClass()->qualifiedCppName() == name) { + return true; } - return recurseClassHierarchy(this, [&qualifiedName](const AbstractMetaClass *c) { + + return bool(recurseClassHierarchy(c, [&name](const AbstractMetaClassCPtr &c) { + return c->qualifiedCppName() == name; + })); +} + +AbstractMetaClassCPtr findBaseClass(const AbstractMetaClassCPtr &c, + const QString &qualifiedName) +{ + auto tp = c->templateBaseClass(); + if (tp && tp->qualifiedCppName() == qualifiedName) + return tp; + + return recurseClassHierarchy(c, [&qualifiedName](const AbstractMetaClassCPtr &c) { return c->qualifiedCppName() == qualifiedName; }); } @@ -1761,21 +1780,35 @@ bool AbstractMetaClass::isCopyable() const return false; auto copyable = d->m_typeEntry->copyable(); return copyable == ComplexTypeEntry::CopyableSet - || (copyable == ComplexTypeEntry::Unknown && hasCloneOperator()); + || (copyable == ComplexTypeEntry::Unknown && isCopyConstructible()); } bool AbstractMetaClass::isValueTypeWithCopyConstructorOnly() const { - if (!typeEntry()->isValue()) + return d->m_valueTypeWithCopyConstructorOnly; +} + +void AbstractMetaClass::setValueTypeWithCopyConstructorOnly(bool v) +{ + d->m_valueTypeWithCopyConstructorOnly = v; +} + +bool AbstractMetaClass::determineValueTypeWithCopyConstructorOnly(const AbstractMetaClassCPtr &c, + bool avoidProtectedHack) +{ + + if (!c->typeEntry()->isValue()) return false; - if (attributes().testFlag(AbstractMetaClass::HasRejectedDefaultConstructor)) + if (c->attributes().testFlag(AbstractMetaClass::HasRejectedDefaultConstructor)) return false; - const auto ctors = queryFunctions(FunctionQueryOption::Constructors); + const auto ctors = c->queryFunctions(FunctionQueryOption::AnyConstructor); bool copyConstructorFound = false; for (const auto &ctor : ctors) { switch (ctor->functionType()) { case AbstractMetaFunction::ConstructorFunction: - return false; + if (!ctor->isPrivate() && (ctor->isPublic() || !avoidProtectedHack)) + return false; + break; case AbstractMetaFunction::CopyConstructorFunction: copyConstructorFound = true; break; @@ -1796,8 +1829,8 @@ void AbstractMetaClass::format(QDebug &debug) const if (debug.verbosity() > 2) debug << static_cast<const void *>(this) << ", "; debug << '"' << qualifiedCppName(); - if (const int count = d->m_templateArgs.size()) { - for (int i = 0; i < count; ++i) + if (const auto count = d->m_templateArgs.size()) { + for (qsizetype i = 0; i < count; ++i) debug << (i ? ',' : '<') << d->m_templateArgs.at(i)->qualifiedCppName(); debug << '>'; } @@ -1808,9 +1841,25 @@ void AbstractMetaClass::format(QDebug &debug) const debug << " [final]"; if (attributes().testFlag(AbstractMetaClass::Deprecated)) debug << " [deprecated]"; + + if (d->m_hasPrivateConstructor) + debug << " [private constructor]"; + if (d->m_hasDeletedDefaultConstructor) + debug << " [deleted default constructor]"; + if (d->m_hasDeletedCopyConstructor) + debug << " [deleted copy constructor]"; + if (d->m_hasPrivateDestructor) + debug << " [private destructor]"; + if (d->m_hasProtectedDestructor) + debug << " [protected destructor]"; + if (d->m_hasVirtualDestructor) + debug << " [virtual destructor]"; + if (d->m_valueTypeWithCopyConstructorOnly) + debug << " [value type with copy constructor only]"; + if (!d->m_baseClasses.isEmpty()) { debug << ", inherits "; - for (auto b : d->m_baseClasses) + for (const auto &b : d->m_baseClasses) debug << " \"" << b->name() << '"'; } @@ -1825,13 +1874,13 @@ void AbstractMetaClass::format(QDebug &debug) const if (auto templateBase = templateBaseClass()) { const auto &instantiatedTypes = templateBaseClassInstantiations(); debug << ", instantiates \"" << templateBase->name(); - for (int i = 0, count = instantiatedTypes.size(); i < count; ++i) + for (qsizetype i = 0, count = instantiatedTypes.size(); i < count; ++i) debug << (i ? ',' : '<') << instantiatedTypes.at(i).name(); debug << ">\""; } - if (const int count = d->m_propertySpecs.size()) { + if (const auto count = d->m_propertySpecs.size()) { debug << ", properties (" << count << "): ["; - for (int i = 0; i < count; ++i) { + for (qsizetype i = 0; i < count; ++i) { if (i) debug << ", "; d->m_propertySpecs.at(i).formatDebug(debug); @@ -1845,18 +1894,18 @@ void AbstractMetaClass::formatMembers(QDebug &debug) const if (!d->m_enums.isEmpty()) debug << ", enums[" << d->m_enums.size() << "]=" << d->m_enums; if (!d->m_functions.isEmpty()) { - const int count = d->m_functions.size(); + const auto count = d->m_functions.size(); debug << ", functions=[" << count << "]("; - for (int i = 0; i < count; ++i) { + for (qsizetype i = 0; i < count; ++i) { if (i) debug << ", "; d->m_functions.at(i)->formatDebugBrief(debug); } debug << ')'; } - if (const int count = d->m_fields.size()) { + if (const auto count = d->m_fields.size()) { debug << ", fields=[" << count << "]("; - for (int i = 0; i < count; ++i) { + for (qsizetype i = 0; i < count; ++i) { if (i) debug << ", "; d->m_fields.at(i).formatDebug(debug); @@ -1875,6 +1924,18 @@ void AbstractMetaClass::setSourceLocation(const SourceLocation &sourceLocation) d->m_sourceLocation = sourceLocation; } +AbstractMetaClassCList allBaseClasses(const AbstractMetaClassCPtr metaClass) +{ + AbstractMetaClassCList result; + recurseClassHierarchy(metaClass, [&result] (const AbstractMetaClassCPtr &c) { + if (!result.contains(c)) + result.append(c); + return false; + }); + result.removeFirst(); // remove self + return result; +} + QDebug operator<<(QDebug debug, const UsingMember &d) { QDebugStateSaver saver(debug); @@ -1885,20 +1946,38 @@ QDebug operator<<(QDebug debug, const UsingMember &d) return debug; } -QDebug operator<<(QDebug d, const AbstractMetaClass *ac) +void formatMetaClass(QDebug &ddebug, const AbstractMetaClass *ac) { - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "AbstractMetaClass("; - if (ac) { - ac->format(d); - if (d.verbosity() > 2) - ac->formatMembers(d); + QDebugStateSaver saver(ddebug); + ddebug.noquote(); + ddebug.nospace(); + ddebug << "AbstractMetaClass("; + if (ac != nullptr) { + ac->format(ddebug); + if (ddebug.verbosity() > 2) + ac->formatMembers(ddebug); } else { - d << '0'; + ddebug << '0'; } - d << ')'; + ddebug << ')'; +} + +QDebug operator<<(QDebug d, const AbstractMetaClassCPtr &ac) +{ + formatMetaClass(d, ac.get()); + return d; +} + +QDebug operator<<(QDebug d, const AbstractMetaClassPtr &ac) +{ + formatMetaClass(d, ac.get()); return d; } + +QDebug operator<<(QDebug d, const AbstractMetaClass *ac) +{ + formatMetaClass(d, ac); + return d; +} + #endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang.h b/sources/shiboken6/ApiExtractor/abstractmetalang.h index 6f1971df9..3dc876690 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetalang.h +++ b/sources/shiboken6/ApiExtractor/abstractmetalang.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETALANG_H #define ABSTRACTMETALANG_H @@ -32,7 +7,6 @@ #include "abstractmetalang_enums.h" #include "abstractmetalang_typedefs.h" #include "enclosingclassmixin.h" -#include "typesystem_enums.h" #include "typesystem_typedefs.h" #include <QtCore/qobjectdefs.h> @@ -73,7 +47,8 @@ public: HasRejectedDefaultConstructor = 0x00000020, FinalCppClass = 0x00000100, - Deprecated = 0x00000200 + Deprecated = 0x00000200, + Struct = 0x00000400 }; Q_DECLARE_FLAGS(Attributes, Attribute) Q_FLAG(Attribute) @@ -91,11 +66,13 @@ public: ~AbstractMetaClass(); const AbstractMetaFunctionCList &functions() const; + const AbstractMetaFunctionCList &userAddedPythonOverrides() const; void setFunctions(const AbstractMetaFunctionCList &functions); - void addFunction(const AbstractMetaFunctionCPtr &function); + static void addFunction(const AbstractMetaClassPtr &klass, + const AbstractMetaFunctionCPtr &function); bool hasFunction(const QString &str) const; - AbstractMetaFunctionCPtr findFunction(const QString& functionName) const; - AbstractMetaFunctionCList findFunctions(const QString& functionName) const; + AbstractMetaFunctionCPtr findFunction(QAnyStringView functionName) const; + AbstractMetaFunctionCList findFunctions(QAnyStringView functionName) const; AbstractMetaFunctionCPtr findOperatorBool() const; // Find a Qt-style isNull() method suitable for nb_bool AbstractMetaFunctionCPtr findQtIsNullMethod() const; @@ -106,8 +83,8 @@ public: bool hasCopyConstructor() const; bool hasPrivateCopyConstructor() const; - void addDefaultConstructor(); - void addDefaultCopyConstructor(); + static void addDefaultConstructor(const AbstractMetaClassPtr &klass); + static void addDefaultCopyConstructor(const AbstractMetaClassPtr &klass); bool hasNonPrivateConstructor() const; void setHasNonPrivateConstructor(bool value); @@ -138,14 +115,17 @@ public: bool isImplicitlyCopyConstructible() const; bool canAddDefaultCopyConstructor() const; + static void addSynthesizedComparisonOperators(const AbstractMetaClassPtr &c); + bool generateExceptionHandling() const; CppWrapper cppWrapper() const; const UsingMembers &usingMembers() const; void addUsingMember(const UsingMember &um); - bool isUsingMember(const AbstractMetaClass *c, const QString &memberName, + bool isUsingMember(const AbstractMetaClassCPtr &c, const QString &memberName, Access minimumAccess) const; + bool hasUsingMemberFor(const QString &memberName) const; AbstractMetaFunctionCList queryFunctionsByName(const QString &name) const; static bool queryFunction(const AbstractMetaFunction *f, FunctionQueryOptions query); @@ -181,7 +161,7 @@ public: void addField(const AbstractMetaField &field); bool hasStaticFields() const; - std::optional<AbstractMetaField> findField(const QString &name) const; + std::optional<AbstractMetaField> findField(QStringView name) const; const AbstractMetaEnumList &enums() const; AbstractMetaEnumList &enums(); @@ -208,42 +188,40 @@ public: QString baseClassName() const; - AbstractMetaClass *defaultSuperclass() const; // Attribute "default-superclass" - void setDefaultSuperclass(AbstractMetaClass *s); + AbstractMetaClassCPtr defaultSuperclass() const; // Attribute "default-superclass" + void setDefaultSuperclass(const AbstractMetaClassPtr &s); - AbstractMetaClass *baseClass() const; - const AbstractMetaClassList &baseClasses() const; + AbstractMetaClassCPtr baseClass() const; + const AbstractMetaClassCList &baseClasses() const; // base classes including defaultSuperclass - AbstractMetaClassList typeSystemBaseClasses() const; + AbstractMetaClassCList typeSystemBaseClasses() const; // Recursive list of all base classes including defaultSuperclass - AbstractMetaClassList allTypeSystemAncestors() const; + AbstractMetaClassCList allTypeSystemAncestors() const; - void addBaseClass(AbstractMetaClass *base_class); - void setBaseClass(AbstractMetaClass *base_class); + void addBaseClass(const AbstractMetaClassCPtr &base_class); + void setBaseClass(const AbstractMetaClassCPtr &base_class); /** * \return the namespace from another package which this namespace extends. */ - const AbstractMetaClass *extendedNamespace() const; - void setExtendedNamespace(const AbstractMetaClass *e); + AbstractMetaClassCPtr extendedNamespace() const; + void setExtendedNamespace(const AbstractMetaClassCPtr &e); - const AbstractMetaClassList &innerClasses() const; - void addInnerClass(AbstractMetaClass* cl); - void setInnerClasses(const AbstractMetaClassList &innerClasses); + const AbstractMetaClassCList &innerClasses() const; + void addInnerClass(const AbstractMetaClassPtr &cl); + void setInnerClasses(const AbstractMetaClassCList &innerClasses); QString package() const; bool isNamespace() const; bool isInvisibleNamespace() const; - - bool isQObject() const; + bool isInlineNamespace() const; bool isQtNamespace() const; QString qualifiedCppName() const; bool hasSignals() const; - bool inheritsFrom(const AbstractMetaClass *other) const; /** * Says if the class that declares or inherits a virtual function. @@ -252,60 +230,46 @@ public: bool isPolymorphic() const; /** - * Tells if this class has one or more functions that are protected. - * \return true if the class has protected functions. - */ - bool hasProtectedFunctions() const; - - /** * Tells if this class has one or more fields (member variables) that are protected. * \return true if the class has protected fields. */ bool hasProtectedFields() const; - /** - * Tells if this class has one or more members (functions or fields) that are protected. - * \return true if the class has protected members. - */ - bool hasProtectedMembers() const; - - const TypeEntries &templateArguments() const; - void setTemplateArguments(const TypeEntries &); + const TypeEntryCList &templateArguments() const; + void setTemplateArguments(const TypeEntryCList &); // only valid during metabuilder's run const QStringList &baseClassNames() const; void setBaseClassNames(const QStringList &names); - const ComplexTypeEntry *typeEntry() const; - ComplexTypeEntry *typeEntry(); - void setTypeEntry(ComplexTypeEntry *type); + ComplexTypeEntryCPtr typeEntry() const; + ComplexTypeEntryPtr typeEntry(); + void setTypeEntry(const ComplexTypeEntryPtr &type); - void setHasHashFunction(bool on); + /// Returns the global hash function as found by the code parser + QString hashFunction() const; + void setHashFunction(const QString &); + /// Returns whether the class has a qHash() overload. Currently unused, + /// specified in type system. bool hasHashFunction() const; - bool hasDefaultToStringFunction() const; - - bool hasEqualsOperator() const; - void setHasEqualsOperator(bool on); - - bool hasCloneOperator() const; - void setHasCloneOperator(bool on); - const QList<QPropertySpec> &propertySpecs() const; void addPropertySpec(const QPropertySpec &spec); + void setPropertyDocumentation(const QString &name, const Documentation &doc); // Helpers to search whether a functions is a property setter/getter/reset enum class PropertyFunction { Read, Write, - Reset + Reset, + Notify }; struct PropertyFunctionSearchResult { - int index; + qsizetype index; PropertyFunction function; }; @@ -323,8 +287,8 @@ public: void sortFunctions(); - const AbstractMetaClass *templateBaseClass() const; - void setTemplateBaseClass(const AbstractMetaClass *cls); + AbstractMetaClassCPtr templateBaseClass() const; + void setTemplateBaseClass(const AbstractMetaClassCPtr &cls); bool hasTemplateBaseClassInstantiations() const; const AbstractMetaTypeList &templateBaseClassInstantiations() const; @@ -347,27 +311,28 @@ public: bool isObjectType() const; bool isCopyable() const; bool isValueTypeWithCopyConstructorOnly() const; - - static AbstractMetaClass *findClass(const AbstractMetaClassList &classes, - const QString &name); - static const AbstractMetaClass *findClass(const AbstractMetaClassCList &classes, - const QString &name); - static AbstractMetaClass *findClass(const AbstractMetaClassList &classes, - const TypeEntry* typeEntry); - static const AbstractMetaClass *findClass(const AbstractMetaClassCList &classes, - const TypeEntry* typeEntry); - const AbstractMetaClass *findBaseClass(const QString &qualifiedName) const; + void setValueTypeWithCopyConstructorOnly(bool v); + static bool determineValueTypeWithCopyConstructorOnly(const AbstractMetaClassCPtr &c, + bool avoidProtectedHack); + + static AbstractMetaClassPtr findClass(const AbstractMetaClassList &classes, + QAnyStringView name); + static AbstractMetaClassCPtr findClass(const AbstractMetaClassCList &classes, + QAnyStringView name); + static AbstractMetaClassPtr findClass(const AbstractMetaClassList &classes, + const TypeEntryCPtr &typeEntry); + static AbstractMetaClassCPtr findClass(const AbstractMetaClassCList &classes, + const TypeEntryCPtr &typeEntry); + AbstractMetaClassCPtr findBaseClass(const QString &qualifiedName) const; static std::optional<AbstractMetaEnumValue> findEnumValue(const AbstractMetaClassList &classes, const QString &string); - static std::optional<AbstractMetaEnum> findEnum(const AbstractMetaClassList &classes, - const EnumTypeEntry *entry); SourceLocation sourceLocation() const; void setSourceLocation(const SourceLocation &sourceLocation); // For AbstractMetaBuilder - void fixFunctions(); + static void fixFunctions(const AbstractMetaClassPtr &klass); bool needsInheritanceSetup() const; void setInheritanceDone(bool b); bool inheritanceDone() const; @@ -379,17 +344,15 @@ private: #ifndef QT_NO_DEBUG_STREAM void format(QDebug &d) const; void formatMembers(QDebug &d) const; + friend QDebug operator<<(QDebug d, const AbstractMetaClassCPtr &ac); + friend QDebug operator<<(QDebug d, const AbstractMetaClassPtr &ac); friend QDebug operator<<(QDebug d, const AbstractMetaClass *ac); + friend void formatMetaClass(QDebug &, const AbstractMetaClass *); #endif QScopedPointer<AbstractMetaClassPrivate> d; }; -inline bool AbstractMetaClass::isFinalInTargetLang() const -{ - return attributes().testFlag(FinalInTargetLang); -} - inline bool AbstractMetaClass::isAbstract() const { return attributes().testFlag(Abstract); @@ -398,7 +361,7 @@ inline bool AbstractMetaClass::isAbstract() const template <class Function> void AbstractMetaClass::invisibleNamespaceRecursion(Function f) const { - for (auto ic : innerClasses()) { + for (const auto &ic : innerClasses()) { if (ic->isInvisibleNamespace()) { f(ic); ic->invisibleNamespaceRecursion(f); @@ -406,6 +369,23 @@ void AbstractMetaClass::invisibleNamespaceRecursion(Function f) const } } +bool inheritsFrom(const AbstractMetaClassCPtr &c, const AbstractMetaClassCPtr &other); +bool inheritsFrom(const AbstractMetaClassCPtr &c, QAnyStringView name); +inline bool isQObject(const AbstractMetaClassCPtr &c) +{ + return inheritsFrom(c, "QObject"); +} + +AbstractMetaClassCPtr findBaseClass(const AbstractMetaClassCPtr &c, + const QString &qualifiedName); + +/// Return type entry of the base class that declares the parent management +TypeEntryCPtr parentManagementEntry(const AbstractMetaClassCPtr &klass); +inline bool hasParentManagement(const AbstractMetaClassCPtr &c) +{ return bool(parentManagementEntry(c)); } + +AbstractMetaClassCList allBaseClasses(const AbstractMetaClassCPtr metaClass); + Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaClass::CppWrapper); Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaClass::Attributes); diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h b/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h index c78e84320..9047c6bcd 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h +++ b/sources/shiboken6/ApiExtractor/abstractmetalang_enums.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETALANG_ENUMS_H #define ABSTRACTMETALANG_ENUMS_H @@ -32,21 +7,19 @@ #include <QtCore/QFlags> enum class FunctionQueryOption { - Constructors = 0x0000001, // Only constructors - CopyConstructor = 0x0000002, // Only copy constructors + AnyConstructor = 0x0000001, // Any constructor (copy/move) + Constructors = 0x0000002, // Constructors except copy/move + CopyConstructor = 0x0000004, // Only copy constructors //Destructors = 0x0000002, // Only destructors. Not included in class. - FinalInTargetLangFunctions = 0x0000008, // Only functions that are non-virtual in TargetLang ClassImplements = 0x0000020, // Only functions implemented by the current class StaticFunctions = 0x0000080, // Only static functions Signals = 0x0000100, // Only signals NormalFunctions = 0x0000200, // Only functions that aren't signals Visible = 0x0000400, // Only public and protected functions - WasPublic = 0x0001000, // Only functions that were originally public NonStaticFunctions = 0x0004000, // No static functions Empty = 0x0008000, // Empty overrides of abstract functions Invisible = 0x0010000, // Only private functions VirtualInCppFunctions = 0x0020000, // Only functions that are virtual in C++ - VirtualInTargetLangFunctions = 0x0080000, // Only functions which are virtual in TargetLang NotRemoved = 0x0400000, // Only functions that have not been removed OperatorOverloads = 0x2000000, // Only functions that are operator overloads GenerateExceptionHandling = 0x4000000, @@ -58,14 +31,17 @@ Q_DECLARE_FLAGS(FunctionQueryOptions, FunctionQueryOption) Q_DECLARE_OPERATORS_FOR_FLAGS(FunctionQueryOptions) enum class OperatorQueryOption { - ArithmeticOp = 0x01, // Arithmetic: +, -, *, /, %, +=, -=, *=, /=, %=, unary+, unary- - IncDecrementOp = 0x02, // ++, -- - BitwiseOp = 0x04, // Bitwise: <<, <<=, >>, >>=, ~, &, &=, |, |=, ^, ^= - ComparisonOp = 0x08, // Comparison: <, <=, >, >=, !=, == - LogicalOp = 0x10, // Logical: !, &&, || - ConversionOp = 0x20, // Conversion: operator [const] TYPE() - SubscriptionOp = 0x40, // Subscription: [] - AssignmentOp = 0x80 // Assignment: = + ArithmeticOp = 0x01, // Arithmetic: +, -, *, /, %, +=, -=, *=, /=, %=, unary+, unary- + IncDecrementOp = 0x02, // ++, -- + BitwiseOp = 0x04, // Bitwise: <<, <<=, >>, >>=, ~, &, &=, |, |=, ^, ^= + ComparisonOp = 0x08, // Comparison: <, <=, >, >=, !=, == + // Comparing to instances of owner class: <, <=, >, >=, !=, == + // (bool operator==(QByteArray,QByteArray) but not bool operator==(QByteArray,const char *) + SymmetricalComparisonOp = 0x10, + LogicalOp = 0x20, // Logical: !, &&, || + ConversionOp = 0x40, // Conversion: operator [const] TYPE() + SubscriptionOp = 0x80, // Subscription: [] + AssignmentOp = 0x100 // Assignment: = }; Q_DECLARE_FLAGS(OperatorQueryOptions, OperatorQueryOption) diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang_helpers.h b/sources/shiboken6/ApiExtractor/abstractmetalang_helpers.h index afe5c954a..2a053ceaf 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetalang_helpers.h +++ b/sources/shiboken6/ApiExtractor/abstractmetalang_helpers.h @@ -1,49 +1,27 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETALANG_HELPERS_H #define ABSTRACTMETALANG_HELPERS_H +#include "abstractmetalang_typedefs.h" + template <class MetaClass> -MetaClass *findByName(QList<MetaClass *> haystack, QStringView needle) +std::shared_ptr<MetaClass> findByName(const QList<std::shared_ptr<MetaClass> > &haystack, + QStringView needle) { - for (MetaClass *c : haystack) { + for (const auto &c : haystack) { if (c->name() == needle) return c; } - return nullptr; + return {}; } // Helper for recursing the base classes of an AbstractMetaClass. // Returns the class for which the predicate is true. template <class Predicate> -const AbstractMetaClass *recurseClassHierarchy(const AbstractMetaClass *klass, - Predicate pred) +AbstractMetaClassCPtr recurseClassHierarchy(const AbstractMetaClassCPtr &klass, + Predicate pred) { if (pred(klass)) return klass; @@ -51,7 +29,7 @@ const AbstractMetaClass *recurseClassHierarchy(const AbstractMetaClass *klass, if (auto r = recurseClassHierarchy(base, pred)) return r; } - return nullptr; + return {}; } #endif // ABSTRACTMETALANG_HELPERS_H diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h b/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h index cdfcdab1e..802f549cf 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h +++ b/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h @@ -1,37 +1,13 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETALANG_TYPEDEFS_H #define ABSTRACTMETALANG_TYPEDEFS_H -#include <QtCore/QSharedPointer> #include <QtCore/QList> +#include <memory> + class AbstractMetaClass; class AbstractMetaField; class AbstractMetaArgument; @@ -41,12 +17,14 @@ class AbstractMetaFunction; class AbstractMetaType; struct UsingMember; -using AbstractMetaFunctionPtr = QSharedPointer<AbstractMetaFunction>; -using AbstractMetaFunctionCPtr = QSharedPointer<const AbstractMetaFunction>; +using AbstractMetaFunctionPtr = std::shared_ptr<AbstractMetaFunction>; +using AbstractMetaFunctionCPtr = std::shared_ptr<const AbstractMetaFunction>; +using AbstractMetaClassPtr = std::shared_ptr<AbstractMetaClass>; +using AbstractMetaClassCPtr = std::shared_ptr<const AbstractMetaClass>; using AbstractMetaArgumentList = QList<AbstractMetaArgument>; -using AbstractMetaClassList = QList<AbstractMetaClass *>; -using AbstractMetaClassCList = QList<const AbstractMetaClass *>; +using AbstractMetaClassList = QList<AbstractMetaClassPtr>; +using AbstractMetaClassCList = QList<AbstractMetaClassCPtr>; using AbstractMetaEnumList = QList<AbstractMetaEnum>; using AbstractMetaEnumValueList = QList<AbstractMetaEnumValue>; using AbstractMetaFieldList = QList<AbstractMetaField>; diff --git a/sources/shiboken6/ApiExtractor/abstractmetatype.cpp b/sources/shiboken6/ApiExtractor/abstractmetatype.cpp index 075315d58..dcfc74bbb 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetatype.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetatype.cpp @@ -1,50 +1,114 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "abstractmetatype.h" +#include "abstractmetabuilder.h" +#include "abstractmetalang.h" +#include "messages.h" #include "typedatabase.h" -#include "typesystem.h" -#include "parser/codemodel.h" +#include "containertypeentry.h" +#include "enumtypeentry.h" +#include "flagstypeentry.h" + +#include "qtcompat.h" +#include "typeinfo.h" #ifndef QT_NO_DEBUG_STREAM # include <QtCore/QDebug> #endif +#include <QtCore/QHash> #include <QtCore/QSharedData> -#include <QtCore/QSharedPointer> #include <QtCore/QStack> -using AbstractMetaTypeCPtr = QSharedPointer<const AbstractMetaType>; +#include <memory> + +using namespace Qt::StringLiterals; + +using AbstractMetaTypeCPtr = std::shared_ptr<const AbstractMetaType>; + +const QSet<QString> &AbstractMetaType::cppFloatTypes() +{ + static const QSet<QString> result{u"double"_s, u"float"_s}; + return result; +} + +const QSet<QString> &AbstractMetaType::cppSignedCharTypes() +{ + static const QSet<QString> result{u"char"_s, u"signed char"_s}; + return result; +} + +const QSet<QString> &AbstractMetaType::cppUnsignedCharTypes() +{ + static const QSet<QString> result{u"unsigned char"_s}; + return result; +} + +const QSet<QString> &AbstractMetaType::cppCharTypes() +{ + static const QSet<QString> result = cppSignedCharTypes() | cppUnsignedCharTypes(); + return result; +} + +const QSet<QString> &AbstractMetaType::cppSignedIntTypes() +{ + static QSet<QString> result; + if (result.isEmpty()) { + result = {u"char"_s, u"signed char"_s, u"short"_s, u"short int"_s, + u"signed short"_s, u"signed short int"_s, + u"int"_s, u"signed int"_s, + u"long"_s, u"long int"_s, + u"signed long"_s, u"signed long int"_s, + u"long long"_s, u"long long int"_s, + u"signed long long int"_s, + u"ptrdiff_t"_s}; + result |= cppSignedCharTypes(); + } + return result; +} + +const QSet<QString> &AbstractMetaType::cppUnsignedIntTypes() +{ + static QSet<QString> result; + if (result.isEmpty()) { + result = {u"unsigned short"_s, u"unsigned short int"_s, + u"unsigned"_s, u"unsigned int"_s, + u"unsigned long"_s, u"unsigned long int"_s, + u"unsigned long long"_s, + u"unsigned long long int"_s, + u"size_t"_s}; + result |= cppUnsignedCharTypes(); + } + return result; +} + +const QSet<QString> &AbstractMetaType::cppIntegralTypes() +{ + static QSet<QString> result; + if (result.isEmpty()) { + result |= cppSignedIntTypes(); + result |= cppUnsignedIntTypes(); + result.insert(u"bool"_s); + } + return result; +} + +const QSet<QString> &AbstractMetaType::cppPrimitiveTypes() +{ + static QSet<QString> result; + if (result.isEmpty()) { + result |= cppIntegralTypes(); + result |= cppFloatTypes(); + result.insert(u"wchar_t"_s); + } + return result; +} class AbstractMetaTypeData : public QSharedData { public: - AbstractMetaTypeData(const TypeEntry *t); + AbstractMetaTypeData(const TypeEntryCPtr &t); int actualIndirections() const; bool passByConstRef() const; @@ -53,9 +117,14 @@ public: bool hasTemplateChildren() const; QString formatSignature(bool minimal) const; QString formatPythonSignature() const; + bool isEquivalent(const AbstractMetaTypeData &rhs) const; bool equals(const AbstractMetaTypeData &rhs) const; + QStringList instantiationCppSignatures() const; - const TypeEntry *m_typeEntry; + template <class Predicate> + bool generateOpaqueContainer(Predicate p) const; + + TypeEntryCPtr m_typeEntry; AbstractMetaTypeList m_instantiations; mutable QString m_cachedCppSignature; mutable QString m_cachedPythonSignature; @@ -77,7 +146,7 @@ public: AbstractMetaTypeList m_children; }; -AbstractMetaTypeData::AbstractMetaTypeData(const TypeEntry *t) : +AbstractMetaTypeData::AbstractMetaTypeData(const TypeEntryCPtr &t) : m_typeEntry(t), m_constant(false), m_volatile(false), @@ -86,21 +155,32 @@ AbstractMetaTypeData::AbstractMetaTypeData(const TypeEntry *t) : { } -AbstractMetaType::AbstractMetaType(const TypeEntry *t) : d(new AbstractMetaTypeData(t)) +QStringList AbstractMetaTypeData::instantiationCppSignatures() const { + QStringList result; + for (const auto &i : m_instantiations) + result.append(i.cppSignature()); + return result; } -AbstractMetaType::AbstractMetaType() : d(new AbstractMetaTypeData(nullptr)) +AbstractMetaType::AbstractMetaType(const TypeEntryCPtr &t) : + d(new AbstractMetaTypeData(t)) { + Q_ASSERT(t); +} + +AbstractMetaType::AbstractMetaType() +{ + *this = AbstractMetaType::createVoid(); } AbstractMetaType &AbstractMetaType::operator=(const AbstractMetaType &) = default; AbstractMetaType::AbstractMetaType(const AbstractMetaType &rhs) = default; -AbstractMetaType::AbstractMetaType(AbstractMetaType &&) = default; +AbstractMetaType::AbstractMetaType(AbstractMetaType &&) noexcept = default; -AbstractMetaType &AbstractMetaType::operator=(AbstractMetaType &&) = default; +AbstractMetaType &AbstractMetaType::operator=(AbstractMetaType &&) noexcept = default; AbstractMetaType::~AbstractMetaType() = default; @@ -151,16 +231,21 @@ const AbstractMetaTypeList &AbstractMetaType::instantiations() const return d->m_instantiations; } +QStringList AbstractMetaType::instantiationCppSignatures() const +{ + return d->instantiationCppSignatures(); +} + // For applying the <array> function argument modification: change into a type // where "int *" becomes "int[]". bool AbstractMetaType::applyArrayModification(QString *errorMessage) { if (d->m_pattern == AbstractMetaType::NativePointerAsArrayPattern) { - *errorMessage = QLatin1String("<array> modification already applied."); + *errorMessage = u"<array> modification already applied."_s; return false; } - if (!d->m_arrayElementType.isNull()) { + if (d->m_arrayElementType) { QTextStream(errorMessage) << "The type \"" << cppSignature() << "\" is an array of " << d->m_arrayElementType->name() << '.'; return false; @@ -184,12 +269,12 @@ bool AbstractMetaType::applyArrayModification(QString *errorMessage) return true; } -const TypeEntry *AbstractMetaType::typeEntry() const +TypeEntryCPtr AbstractMetaType::typeEntry() const { return d->m_typeEntry; } -void AbstractMetaType::setTypeEntry(const TypeEntry *type) +void AbstractMetaType::setTypeEntry(const TypeEntryCPtr &type) { if (d->m_typeEntry != type) d->m_typeEntry = type; @@ -208,13 +293,13 @@ QString AbstractMetaType::originalTypeDescription() const void AbstractMetaType::setOriginalTemplateType(const AbstractMetaType &type) { - if (d->m_originalTemplateType.isNull() || *d->m_originalTemplateType != type) + if (!d->m_originalTemplateType || *d->m_originalTemplateType != type) d->m_originalTemplateType.reset(new AbstractMetaType(type)); } const AbstractMetaType *AbstractMetaType::originalTemplateType() const { - return d->m_originalTemplateType.data(); + return d->m_originalTemplateType.get(); } AbstractMetaType AbstractMetaType::getSmartPointerInnerType() const @@ -243,7 +328,7 @@ AbstractMetaTypeList AbstractMetaType::nestedArrayTypes() const } break; case NativePointerAsArrayPattern: - result.append(*d->m_arrayElementType.data()); + result.append(*d->m_arrayElementType.get()); break; default: break; @@ -271,6 +356,12 @@ bool AbstractMetaType::passByValue() const return d->passByValue(); } +bool AbstractMetaType::useStdMove() const +{ + return (isUniquePointer() && d->passByValue()) + || d->m_referenceType == RValueReference; +} + ReferenceType AbstractMetaType::referenceType() const { return d->m_referenceType; @@ -349,17 +440,28 @@ int AbstractMetaType::arrayElementCount() const const AbstractMetaType *AbstractMetaType::arrayElementType() const { - return d->m_arrayElementType.data(); + return d->m_arrayElementType.get(); } void AbstractMetaType::setArrayElementType(const AbstractMetaType &t) { - if (d->m_arrayElementType.isNull() || *d->m_arrayElementType != t) { + if (!d->m_arrayElementType || *d->m_arrayElementType != t) { d->m_arrayElementType.reset(new AbstractMetaType(t)); d->m_signaturesDirty = true; } } +AbstractMetaType AbstractMetaType::plainType() const +{ + AbstractMetaType result = *this; + result.clearIndirections(); + result.setReferenceType(NoReference); + result.setConstant(false); + result.setVolatile(false); + result.decideUsagePattern(); + return result; +} + QString AbstractMetaType::cppSignature() const { const AbstractMetaTypeData *cd = d.constData(); @@ -467,10 +569,33 @@ bool AbstractMetaType::hasTemplateChildren() const static inline QString formatArraySize(int e) { QString result; - result += QLatin1Char('['); + result += u'['; if (e >= 0) result += QString::number(e); - result += QLatin1Char(']'); + result += u']'; + return result; +} + +// Return the number of template parameters; remove the default +// non template type parameter of std::span from the signature. +static qsizetype stripDefaultTemplateArgs(const TypeEntryCPtr &te, + const AbstractMetaTypeList &instantiations) +{ + static const char16_t dynamicExtent64[] = u"18446744073709551615"; // size_t(-1) + static const char16_t dynamicExtent32[] = u"4294967295"; + + qsizetype result = instantiations.size(); + if (result == 0 || !te->isContainer()) + return result; + auto cte = std::static_pointer_cast<const ContainerTypeEntry>(te); + if (cte->containerKind() != ContainerTypeEntry::SpanContainer) + return result; + const auto lastTe = instantiations.constLast().typeEntry(); + if (lastTe->type() == TypeEntry::ConstantValueType) { + const QString &name = lastTe->name(); + if (name == dynamicExtent64 || name == dynamicExtent32) + --result; + } return result; } @@ -478,13 +603,13 @@ QString AbstractMetaTypeData::formatSignature(bool minimal) const { QString result; if (m_constant) - result += QLatin1String("const "); + result += u"const "_s; if (m_volatile) - result += QLatin1String("volatile "); + result += u"volatile "_s; if (m_pattern == AbstractMetaType::ArrayPattern) { // Build nested array dimensions a[2][3] in correct order result += m_arrayElementType->minimalSignature(); - const int arrayPos = result.indexOf(QLatin1Char('[')); + const int arrayPos = result.indexOf(u'['); if (arrayPos != -1) result.insert(arrayPos, formatArraySize(m_arrayElementCount)); else @@ -493,29 +618,30 @@ QString AbstractMetaTypeData::formatSignature(bool minimal) const result += m_typeEntry->qualifiedCppName(); } if (!m_instantiations.isEmpty()) { - result += QLatin1Char('<'); + result += u'<'; if (minimal) - result += QLatin1Char(' '); - for (int i = 0, size = m_instantiations.size(); i < size; ++i) { + result += u' '; + const auto size = stripDefaultTemplateArgs(m_typeEntry, m_instantiations); + for (qsizetype i = 0; i < size; ++i) { if (i > 0) - result += QLatin1Char(','); + result += u','; result += m_instantiations.at(i).minimalSignature(); } - result += QLatin1String(" >"); + result += u'>'; } if (!minimal && (!m_indirections.isEmpty() || m_referenceType != NoReference)) - result += QLatin1Char(' '); + result += u' '; for (Indirection i : m_indirections) result += TypeInfo::indirectionKeyword(i); switch (m_referenceType) { case NoReference: break; case LValueReference: - result += QLatin1Char('&'); + result += u'&'; break; case RValueReference: - result += QLatin1String("&&"); + result += u"&&"_s; break; } return result; @@ -541,7 +667,7 @@ QString AbstractMetaTypeData::formatPythonSignature() const */ QString result; if (m_pattern == AbstractMetaType::NativePointerAsArrayPattern) - result += QLatin1String("array "); + result += u"array "_s; // We no longer use the "const" qualifier for heuristics. Instead, // NativePointerAsArrayPattern indicates when we have <array> in XML. // if (m_typeEntry->isPrimitive() && isConstant()) @@ -549,12 +675,12 @@ QString AbstractMetaTypeData::formatPythonSignature() const if (!m_typeEntry->isPrimitive() && !m_typeEntry->isSmartPointer()) { const QString package = m_typeEntry->targetLangPackage(); if (!package.isEmpty()) - result += package + QLatin1Char('.'); + result += package + u'.'; } if (m_pattern == AbstractMetaType::ArrayPattern) { // Build nested array dimensions a[2][3] in correct order result += m_arrayElementType->formatPythonSignature(); - const int arrayPos = result.indexOf(QLatin1Char('[')); + const int arrayPos = result.indexOf(u'['); if (arrayPos != -1) result.insert(arrayPos, formatArraySize(m_arrayElementCount)); else @@ -563,22 +689,24 @@ QString AbstractMetaTypeData::formatPythonSignature() const result += m_typeEntry->targetLangName(); } if (!m_instantiations.isEmpty()) { - result += QLatin1Char('['); - for (int i = 0, size = m_instantiations.size(); i < size; ++i) { + result += u'['; + for (qsizetype i = 0, size = m_instantiations.size(); i < size; ++i) { if (i > 0) - result += QLatin1String(", "); + result += u", "_s; result += m_instantiations.at(i).formatPythonSignature(); } - result += QLatin1Char(']'); + result += u']'; } if (m_typeEntry->isPrimitive()) for (Indirection i : m_indirections) result += TypeInfo::indirectionKeyword(i); - // If it is a flags type, we replace it with the full name: - // "PySide6.QtCore.Qt.ItemFlags" instead of "PySide6.QtCore.QFlags<Qt.ItemFlag>" - if (m_typeEntry->isFlags()) - result = m_typeEntry->qualifiedTargetLangName(); - result.replace(QLatin1String("::"), QLatin1String(".")); + // If it is a flags type, we replace it with the full name of the enum: + // "PySide6.QtCore.Qt.ItemFlag" instead of "PySide6.QtCore.QFlags<Qt.ItemFlag>" + if (m_typeEntry->isFlags()) { + const auto fte = std::static_pointer_cast<const FlagsTypeEntry>(m_typeEntry); + result = fte->originator()->qualifiedTargetLangName(); + } + result.replace(u"::"_s, u"."_s); return result; } @@ -589,7 +717,7 @@ QString AbstractMetaType::formatPythonSignature() const bool AbstractMetaType::isCppPrimitive() const { - return d->m_pattern == PrimitivePattern && d->m_typeEntry->isCppPrimitive(); + return d->m_pattern == PrimitivePattern && ::isCppPrimitive(d->m_typeEntry); } bool AbstractMetaType::isConstant() const @@ -620,12 +748,12 @@ void AbstractMetaType::setVolatile(bool v) static bool equalsCPtr(const AbstractMetaTypeCPtr &t1, const AbstractMetaTypeCPtr &t2) { - if (t1.isNull() != t2.isNull()) + if (bool(t1) != bool(t2)) return false; - return t1.isNull() || *t1 == *t2; + return !t1 || *t1 == *t2; } -bool AbstractMetaTypeData::equals(const AbstractMetaTypeData &rhs) const +bool AbstractMetaTypeData::isEquivalent(const AbstractMetaTypeData &rhs) const { if (m_typeEntry != rhs.m_typeEntry || m_indirections != rhs.m_indirections @@ -633,11 +761,6 @@ bool AbstractMetaTypeData::equals(const AbstractMetaTypeData &rhs) const return false; } - if (m_constant != rhs.m_constant || m_volatile != rhs.m_volatile - || m_referenceType != rhs.m_referenceType) { - return false; - } - if (!equalsCPtr(m_arrayElementType, rhs.m_arrayElementType)) return false; @@ -649,19 +772,30 @@ bool AbstractMetaTypeData::equals(const AbstractMetaTypeData &rhs) const return true; } -bool AbstractMetaType::equals(const AbstractMetaType &rhs) const +bool AbstractMetaTypeData::equals(const AbstractMetaTypeData &rhs) const +{ + return m_constant == rhs.m_constant && m_volatile == rhs.m_volatile + && m_referenceType == rhs.m_referenceType && isEquivalent(rhs); +} + +bool comparesEqual(const AbstractMetaType &lhs, const AbstractMetaType &rhs) noexcept +{ + return lhs.d->equals(*rhs.d); +} + +bool AbstractMetaType::isEquivalent(const AbstractMetaType &rhs) const { - return d->equals(*rhs.d); + return d->isEquivalent(*rhs.d); } const AbstractMetaType *AbstractMetaType::viewOn() const { - return d->m_viewOn.data(); + return d->m_viewOn.get(); } void AbstractMetaType::setViewOn(const AbstractMetaType &v) { - if (d->m_viewOn.isNull() || *d->m_viewOn != v) + if (!d->m_viewOn || *d->m_viewOn != v) d->m_viewOn.reset(new AbstractMetaType(v)); } @@ -669,7 +803,7 @@ AbstractMetaType AbstractMetaType::createVoid() { static QScopedPointer<AbstractMetaType> metaType; if (metaType.isNull()) { - static const TypeEntry *voidTypeEntry = TypeDatabase::instance()->findType(QLatin1String("void")); + static TypeEntryCPtr voidTypeEntry = TypeDatabase::instance()->findType(u"void"_s); Q_ASSERT(voidTypeEntry); metaType.reset(new AbstractMetaType(voidTypeEntry)); metaType->decideUsagePattern(); @@ -677,12 +811,55 @@ AbstractMetaType AbstractMetaType::createVoid() return *metaType.data(); } +void AbstractMetaType::dereference(QString *type) +{ + type->prepend(u"(*"_s); + type->append(u')'); +} + +QString AbstractMetaType::dereferencePrefix(qsizetype n) +{ + const QChar c = n > 0 ? u'*' : u'&'; + return QString(qAbs(n), c); +} + +void AbstractMetaType::applyDereference(QString *type, qsizetype n) +{ + if (n == 0) + return; + + type->prepend(dereferencePrefix(n)); + type->prepend(u'('); + type->append(u')'); +} + +bool AbstractMetaType::stripDereference(QString *type) +{ + if (type->startsWith(u"(*") && type->endsWith(u')')) { + type->chop(1); + type->remove(0, 2); + *type = type->trimmed(); + return true; + } + if (type->startsWith(u'*')) { + type->remove(0, 1); + *type = type->trimmed(); + return true; + } + return false; +} + // Query functions for generators bool AbstractMetaType::isObjectType() const { return d->m_typeEntry->isObject(); } +bool AbstractMetaType::isUniquePointer() const +{ + return isSmartPointer() && d->m_typeEntry->isUniquePointer(); +} + bool AbstractMetaType::isPointer() const { return !d->m_indirections.isEmpty() @@ -699,19 +876,19 @@ bool AbstractMetaType::isCString() const { return isNativePointer() && d->m_indirections.size() == 1 - && name() == QLatin1String("char"); + && name() == u"char"; } bool AbstractMetaType::isVoidPointer() const { return isNativePointer() && d->m_indirections.size() == 1 - && name() == QLatin1String("void"); + && name() == u"void"; } bool AbstractMetaType::isUserPrimitive() const { - return d->m_indirections.isEmpty() && d->m_typeEntry->isUserPrimitive(); + return d->m_indirections.isEmpty() && ::isUserPrimitive(d->m_typeEntry); } bool AbstractMetaType::isObjectTypeUsedAsValueType() const @@ -730,15 +907,15 @@ bool AbstractMetaType::isPointerToWrapperType() const return (isObjectType() && d->m_indirections.size() == 1) || isValuePointer(); } -bool AbstractMetaType::shouldDereferencePointer() const +bool AbstractMetaType::isWrapperPassedByReference() const { return d->m_referenceType == LValueReference && isWrapperType() - && !isPointer(); + && !isPointer(); } bool AbstractMetaType::isCppIntegralPrimitive() const { - return d->m_typeEntry->isCppIntegralPrimitive(); + return ::isCppIntegralPrimitive(d->m_typeEntry); } bool AbstractMetaType::isExtendedCppPrimitive() const @@ -747,7 +924,129 @@ bool AbstractMetaType::isExtendedCppPrimitive() const return true; if (!d->m_indirections.isEmpty()) return false; - return d->m_typeEntry->isExtendedCppPrimitive(); + return ::isExtendedCppPrimitive(d->m_typeEntry); +} + +bool AbstractMetaType::isValueTypeWithCopyConstructorOnly() const +{ + bool result = false; + if (d->m_typeEntry->isComplex()) { + const auto cte = std::static_pointer_cast<const ComplexTypeEntry>(d->m_typeEntry); + result = cte->isValueTypeWithCopyConstructorOnly(); + } + return result; +} + +bool AbstractMetaType::valueTypeWithCopyConstructorOnlyPassed() const +{ + return (passByValue() || passByConstRef()) + && isValueTypeWithCopyConstructorOnly(); +} + +using AbstractMetaTypeCache = QHash<QString, AbstractMetaType>; + +Q_GLOBAL_STATIC(AbstractMetaTypeCache, metaTypeFromStringCache) + +std::optional<AbstractMetaType> +AbstractMetaType::fromString(const QString &typeSignatureIn, QString *errorMessage) +{ + auto &cache = *metaTypeFromStringCache(); + auto it = cache.find(typeSignatureIn); + if (it != cache.end()) + return it.value(); + + QString typeSignature = typeSignatureIn.trimmed(); + if (typeSignature.startsWith(u"::")) + typeSignature.remove(0, 2); + + it = cache.find(typeSignature); + if (it == cache.end()) { + auto metaType = + AbstractMetaBuilder::translateType(typeSignature, nullptr, {}, errorMessage); + if (Q_UNLIKELY(!metaType.has_value())) { + if (errorMessage) + errorMessage->prepend(msgCannotBuildMetaType(typeSignature)); + return {}; + } + if (typeSignature != typeSignatureIn) + cache.insert(typeSignatureIn, metaType.value()); + it = cache.insert(typeSignature, metaType.value()); + } + return it.value(); +} + +AbstractMetaType AbstractMetaType::fromTypeEntry(const TypeEntryCPtr &typeEntry) +{ + QString typeName = typeEntry->qualifiedCppName(); + if (typeName.startsWith(u"::")) + typeName.remove(0, 2); + auto &cache = *metaTypeFromStringCache(); + auto it = cache.find(typeName); + if (it != cache.end()) + return it.value(); + AbstractMetaType metaType = AbstractMetaType(typeEntry).plainType(); + cache.insert(typeName, metaType); + return metaType; +} + +AbstractMetaType AbstractMetaType::fromAbstractMetaClass(const AbstractMetaClassCPtr &metaClass) +{ + return fromTypeEntry(metaClass->typeEntry()); +} + +template <class Predicate> // Predicate(containerTypeEntry, signature) +bool AbstractMetaTypeData::generateOpaqueContainer(Predicate pred) const +{ + // Allow for passing containers by pointer as well. + if (!m_typeEntry->isContainer()) + return false; + if (m_indirections.size() > 1) + return false; + auto containerTypeEntry = std::static_pointer_cast<const ContainerTypeEntry>(m_typeEntry); + auto kind = containerTypeEntry->containerKind(); + if (kind != ContainerTypeEntry::ListContainer && kind != ContainerTypeEntry::SpanContainer) + return false; + + const auto &firstInstantiation = m_instantiations.constFirst(); + if (firstInstantiation.referenceType() != NoReference) + return false; + switch (firstInstantiation.typeEntry()->type()) { + case TypeEntry::PrimitiveType: + case TypeEntry::FlagsType: + case TypeEntry::EnumType: + case TypeEntry::BasicValueType: + case TypeEntry::ObjectType: + case TypeEntry::CustomType: + break; + default: + return false; + } + + return pred(containerTypeEntry, instantiationCppSignatures()); +} + +// Simple predicate for checking whether an opaque container should be generated +static bool opaqueContainerPredicate(const ContainerTypeEntryCPtr &t, + const QStringList &instantiations) +{ + return t->generateOpaqueContainer(instantiations); +} + +bool AbstractMetaType::generateOpaqueContainer() const +{ + return d->generateOpaqueContainer(opaqueContainerPredicate); +} + +// Helper for determining whether a function should return an opaque container, +// that is, the function return type is modified accordingly +// (cf AbstractMetaFunction::generateOpaqueContainerReturn()) +bool AbstractMetaType::generateOpaqueContainerForGetter(const QString &modifiedType) const +{ + auto predicate = [&modifiedType](const ContainerTypeEntryCPtr &t, + const QStringList &instantiations) { + return t->opaqueContainerName(instantiations) == modifiedType; + }; + return d->generateOpaqueContainer(predicate); } #ifndef QT_NO_DEBUG_STREAM @@ -769,7 +1068,7 @@ void AbstractMetaType::formatDebug(QDebug &debug) const for (auto i : indirections) debug << ' ' << TypeInfo::indirectionKeyword(i); } - if (referenceType()) + if (referenceType() != NoReference) debug << ", reftype=" << referenceType(); if (isConstant()) debug << ", [const]"; @@ -780,9 +1079,9 @@ void AbstractMetaType::formatDebug(QDebug &debug) const << "\", arrayElementCount=" << arrayElementCount(); } const auto &instantiations = this->instantiations(); - if (const int instantiationsSize = instantiations.size()) { + if (const auto instantiationsSize = instantiations.size()) { debug << ", instantiations[" << instantiationsSize << "]=<"; - for (int i = 0; i < instantiationsSize; ++i) { + for (qsizetype i = 0; i < instantiationsSize; ++i) { if (i) debug << ", "; instantiations.at(i).formatDebug(debug); diff --git a/sources/shiboken6/ApiExtractor/abstractmetatype.h b/sources/shiboken6/ApiExtractor/abstractmetatype.h index 599321262..8a1ecdf20 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetatype.h +++ b/sources/shiboken6/ApiExtractor/abstractmetatype.h @@ -1,40 +1,22 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ABSTRACTMETATYPE_H #define ABSTRACTMETATYPE_H +#include "abstractmetalang_enums.h" #include "abstractmetalang_typedefs.h" #include "parser/codemodel_enums.h" +#include "typedatabase_typedefs.h" +#include <QtCore/QtCompare> #include <QtCore/qobjectdefs.h> +#include <QtCore/QHashFunctions> #include <QtCore/QSharedDataPointer> #include <QtCore/QList> +#include <QtCore/QSet> + +#include <optional> QT_FORWARD_DECLARE_CLASS(QDebug) @@ -67,11 +49,11 @@ public: Q_ENUM(TypeUsagePattern) AbstractMetaType(); - explicit AbstractMetaType(const TypeEntry *t); + explicit AbstractMetaType(const TypeEntryCPtr &t); AbstractMetaType(const AbstractMetaType &); AbstractMetaType &operator=(const AbstractMetaType &); - AbstractMetaType(AbstractMetaType &&); - AbstractMetaType &operator=(AbstractMetaType &&); + AbstractMetaType(AbstractMetaType &&) noexcept; + AbstractMetaType &operator=(AbstractMetaType &&) noexcept; ~AbstractMetaType(); QString package() const; @@ -87,6 +69,7 @@ public: const AbstractMetaTypeList &instantiations() const; void addInstantiation(const AbstractMetaType &inst); void setInstantiations(const AbstractMetaTypeList &insts); + QStringList instantiationCppSignatures() const; QString minimalSignature() const { return formatSignature(true); } @@ -123,6 +106,7 @@ public: // returns true if the type was used as a smart pointer bool isSmartPointer() const { return typeUsagePattern() == SmartPointerPattern; } + bool isUniquePointer() const; // returns true if the type was used as a flag bool isFlags() const { return typeUsagePattern() == FlagsPattern; } @@ -137,6 +121,7 @@ public: bool passByConstRef() const; bool passByValue() const; + bool useStdMove() const; ReferenceType referenceType() const; void setReferenceType(ReferenceType ref); @@ -160,14 +145,17 @@ public: AbstractMetaTypeList nestedArrayTypes() const; + /// Strip const/indirections/reference from the type + AbstractMetaType plainType() const; + QString cppSignature() const; QString pythonSignature() const; bool applyArrayModification(QString *errorMessage); - const TypeEntry *typeEntry() const; - void setTypeEntry(const TypeEntry *type); + TypeEntryCPtr typeEntry() const; + void setTypeEntry(const TypeEntryCPtr &type); void setOriginalTypeDescription(const QString &otd); QString originalTypeDescription() const; @@ -184,7 +172,8 @@ public: bool hasTemplateChildren() const; - bool equals(const AbstractMetaType &rhs) const; + /// Is equivalent from the POV of argument passing (differ by const ref) + bool isEquivalent(const AbstractMetaType &rhs) const; // View on: Type to use for function argument conversion, fex // std::string_view -> std::string for foo(std::string_view); @@ -194,6 +183,23 @@ public: static AbstractMetaType createVoid(); + /// Builds an AbstractMetaType object from a QString. + /// Returns nullopt if no type could be built from the string. + /// \param typeSignature The string describing the type to be built. + /// \return A new AbstractMetaType object or nullopt in case of failure. + static std::optional<AbstractMetaType> + fromString(const QString &typeSignatureIn, QString *errorMessage = nullptr); + /// Creates an AbstractMetaType object from a TypeEntry. + static AbstractMetaType fromTypeEntry(const TypeEntryCPtr &typeEntry); + /// Creates an AbstractMetaType object from an AbstractMetaClass. + static AbstractMetaType fromAbstractMetaClass(const AbstractMetaClassCPtr &metaClass); + + static void dereference(QString *type); // "foo" -> "(*foo)" + /// Apply the result of shouldDereferenceArgument() + static QString dereferencePrefix(qsizetype n); // Return the prefix **/& as as required + static void applyDereference(QString *type, qsizetype n); + static bool stripDereference(QString *type); // "(*foo)" -> "foo" + // Query functions for generators /// Check if type is a pointer. bool isPointer() const; @@ -214,20 +220,46 @@ public: /// Checks if the type is an Object/QObject or pointer to Value Type. /// In other words, tells if the type is "T*" and T has a Python wrapper. bool isPointerToWrapperType() const; - /// Checks if a meta type should be dereferenced by the Python method wrapper passing it to C++. - bool shouldDereferencePointer() const; + /// Wrapper type passed by reference + bool isWrapperPassedByReference() const; /// Returns true if the type is a C++ integral primitive, /// i.e. bool, char, int, long, and their unsigned counterparts. bool isCppIntegralPrimitive() const; /// Returns true if the type is an extended C++ primitive, a void*, /// a const char*, or a std::string (cf isCppPrimitive()). bool isExtendedCppPrimitive() const; + /// Returns whether the underlying type is a value type with copy constructor only + bool isValueTypeWithCopyConstructorOnly() const; + /// Returns whether the type (function argument) is a value type with + /// copy constructor only is passed as value or const-ref and thus + /// no default value can be constructed. + bool valueTypeWithCopyConstructorOnlyPassed() const; + /// Returns whether to generate an opaque container for the type + bool generateOpaqueContainer() const; + /// Returns whether to generate an opaque container for a getter + bool generateOpaqueContainerForGetter(const QString &modifiedType) const; + + /// Types for which libshiboken has built-in primitive converters + static const QSet<QString> &cppFloatTypes(); + static const QSet<QString> &cppSignedCharTypes(); + static const QSet<QString> &cppUnsignedCharTypes(); + static const QSet<QString> &cppCharTypes(); + static const QSet<QString> &cppSignedIntTypes(); + static const QSet<QString> &cppUnsignedIntTypes(); + static const QSet<QString> &cppIntegralTypes(); + static const QSet<QString> &cppPrimitiveTypes(); #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &debug) const; #endif private: + friend size_t qHash(const AbstractMetaType &t, size_t seed = 0) noexcept + { return qHash(t.typeEntry().get(), seed); } + friend bool comparesEqual(const AbstractMetaType &lhs, + const AbstractMetaType &rhs) noexcept; + Q_DECLARE_EQUALITY_COMPARABLE(AbstractMetaType) + friend class AbstractMetaTypeData; QSharedDataPointer<AbstractMetaTypeData> d; @@ -236,11 +268,6 @@ private: QString formatPythonSignature() const; }; -inline bool operator==(const AbstractMetaType &t1, const AbstractMetaType &t2) -{ return t1.equals(t2); } -inline bool operator!=(const AbstractMetaType &t1, const AbstractMetaType &t2) -{ return !t1.equals(t2); } - #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const AbstractMetaType &at); QDebug operator<<(QDebug d, const AbstractMetaType *at); diff --git a/sources/shiboken6/ApiExtractor/addedfunction.cpp b/sources/shiboken6/ApiExtractor/addedfunction.cpp new file mode 100644 index 000000000..9d95b734c --- /dev/null +++ b/sources/shiboken6/ApiExtractor/addedfunction.cpp @@ -0,0 +1,216 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "addedfunction.h" +#include "addedfunction_p.h" +#include "typeparser.h" + +#include <QtCore/QDebug> + +using namespace Qt::StringLiterals; + +constexpr auto callOperator = "operator()"_L1; + +// Helpers to split a parameter list of <add-function>, <declare-function> +// (@ denoting names), like +// "void foo(QList<X,Y> &@list@ = QList<X,Y>{1,2}, int @b@=5, ...)" +namespace AddedFunctionParser { + +QDebug operator<<(QDebug d, const Argument &a) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "Argument(type=\"" << a.type << '"'; + if (!a.name.isEmpty()) + d << ", name=\"" << a.name << '"'; + if (!a.defaultValue.isEmpty()) + d << ", defaultValue=\"" << a.defaultValue << '"'; + d << ')'; + return d; +} + +// Helper for finding the end of a function parameter, observing +// nested template parameters or lists. +static qsizetype parameterTokenEnd(qsizetype startPos, QStringView paramString) +{ + const auto end = paramString.size(); + int nestingLevel = 0; + for (qsizetype p = startPos; p < end; ++p) { + switch (paramString.at(p).toLatin1()) { + case ',': + if (nestingLevel == 0) + return p; + break; + case '<': // templates + case '{': // initializer lists of default values + case '(': // initialization, function pointers + case '[': // array dimensions + ++nestingLevel; + break; + case '>': + case '}': + case ')': + case ']': + --nestingLevel; + break; + } + } + return end; +} + +// Split a function parameter list into string tokens containing one +// parameters (including default value, etc). +static QList<QStringView> splitParameterTokens(QStringView paramString) +{ + QList<QStringView> result; + qsizetype startPos = 0; + for ( ; startPos < paramString.size(); ) { + const auto end = parameterTokenEnd(startPos, paramString); + result.append(paramString.mid(startPos, end - startPos).trimmed()); + startPos = end + 1; + } + return result; +} + +// Split a function parameter list +Arguments splitParameters(QStringView paramString, QString *errorMessage) +{ + Arguments result; + const QList<QStringView> tokens = splitParameterTokens(paramString); + + for (const auto &t : tokens) { + Argument argument; + // Check defaultValue, "int @b@=5" + const auto equalPos = t.lastIndexOf(u'='); + if (equalPos != -1) { + const int defaultValuePos = equalPos + 1; + argument.defaultValue = + t.mid(defaultValuePos, t.size() - defaultValuePos).trimmed().toString(); + } + QString typeString = (equalPos != -1 ? t.left(equalPos) : t).trimmed().toString(); + // Check @name@ + const auto atPos = typeString.indexOf(u'@'); + if (atPos != -1) { + const int namePos = atPos + 1; + const int nameEndPos = typeString.indexOf(u'@', namePos); + if (nameEndPos == -1) { + if (errorMessage != nullptr) { + *errorMessage = u"Mismatched @ in \""_s + + paramString.toString() + u'"'; + } + return {}; + } + argument.name = typeString.mid(namePos, nameEndPos - namePos).trimmed(); + typeString.remove(atPos, nameEndPos - atPos + 1); + } + argument.type = typeString.trimmed(); + result.append(argument); + } + + return result; +} + +} // namespace AddedFunctionParser + +AddedFunction::AddedFunction(const QString &name, const QList<Argument> &arguments, + const TypeInfo &returnType) : + m_name(name), + m_arguments(arguments), + m_returnType(returnType) +{ +} + +AddedFunction::AddedFunctionPtr + AddedFunction::createAddedFunction(const QString &signatureIn, const QString &returnTypeIn, + QString *errorMessage) + +{ + errorMessage->clear(); + + QList<Argument> arguments; + const TypeInfo returnType = returnTypeIn.isEmpty() + ? TypeInfo::voidType() + : TypeParser::parse(returnTypeIn, errorMessage); + if (!errorMessage->isEmpty()) + return {}; + + QStringView signature = QStringView{signatureIn}.trimmed(); + + // Skip past "operator()(...)" + const auto parenSearchStartPos = signature.startsWith(callOperator) + ? callOperator.size() : 0; + const auto openParenPos = signature.indexOf(u'(', parenSearchStartPos); + if (openParenPos < 0) { + return AddedFunctionPtr(new AddedFunction(signature.toString(), + arguments, returnType)); + } + + const QString name = signature.left(openParenPos).trimmed().toString(); + const auto closingParenPos = signature.lastIndexOf(u')'); + if (closingParenPos < 0) { + *errorMessage = u"Missing closing parenthesis"_s; + return {}; + } + + // Check for "foo() const" + bool isConst = false; + const auto signatureLength = signature.length(); + const auto qualifierLength = signatureLength - closingParenPos - 1; + if (qualifierLength >= 5 + && signature.right(qualifierLength).contains(u"const")) { + isConst = true; + } + + const auto paramString = signature.mid(openParenPos + 1, closingParenPos - openParenPos - 1); + const auto params = AddedFunctionParser::splitParameters(paramString, errorMessage); + if (params.isEmpty() && !errorMessage->isEmpty()) + return {}; + for (const auto &p : params) { + TypeInfo type = p.type == u"..." + ? TypeInfo::varArgsType() : TypeParser::parse(p.type, errorMessage); + if (!errorMessage->isEmpty()) { + errorMessage->prepend(u"Unable to parse added function "_s + signatureIn + + u": "_s); + return {}; + } + arguments.append({type, p.name, p.defaultValue}); + } + + auto result = std::make_shared<AddedFunction>(name, arguments, returnType); + result->setConstant(isConst); + return result; +} + +QDebug operator<<(QDebug d, const AddedFunction::Argument &a) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "Argument("; + d << a.typeInfo; + if (!a.name.isEmpty()) + d << ' ' << a.name; + if (!a.defaultValue.isEmpty()) + d << " = " << a.defaultValue; + d << ')'; + return d; +} + +QDebug operator<<(QDebug d, const AddedFunction &af) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AddedFunction("; + if (af.access() == AddedFunction::Protected) + d << "protected"; + if (af.isStatic()) + d << " static"; + d << af.returnType() << ' ' << af.name() << '(' << af.arguments() << ')'; + if (af.isConstant()) + d << " const"; + if (af.isDeclaration()) + d << " [declaration]"; + return d; +} diff --git a/sources/shiboken6/ApiExtractor/addedfunction.h b/sources/shiboken6/ApiExtractor/addedfunction.h new file mode 100644 index 000000000..b8d189b7a --- /dev/null +++ b/sources/shiboken6/ApiExtractor/addedfunction.h @@ -0,0 +1,113 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef ADDEDFUNCTION_H +#define ADDEDFUNCTION_H + +#include "modifications.h" +#include "parser/typeinfo.h" + +#include <QtCore/QList> +#include <QtCore/QString> + +#include <memory> + +QT_FORWARD_DECLARE_CLASS(QDebug) + +/// \internal +/// Struct used to store information about functions added by the typesystem. +/// This info will be used later to create a fake AbstractMetaFunction which +/// will be inserted into the right AbstractMetaClass. +struct AddedFunction +{ + using AddedFunctionPtr = std::shared_ptr<AddedFunction>; + + /// Function access types. + enum Access { + Protected = 0x1, + Public = 0x2 + }; + + struct Argument + { + TypeInfo typeInfo; + QString name; + QString defaultValue; + }; + + /// Creates a new AddedFunction with a signature and a return type. + explicit AddedFunction(const QString &name, const QList<Argument> &arguments, + const TypeInfo &returnType); + + static AddedFunctionPtr createAddedFunction(const QString &signatureIn, + const QString &returnTypeIn, + QString *errorMessage); + + AddedFunction() = default; + + /// Returns the function name. + QString name() const { return m_name; } + + /// Set the function access type. + void setAccess(Access access) { m_access = access; } + + /// Returns the function access type. + Access access() const { return m_access; } + + /// Returns the function return type. + const TypeInfo &returnType() const { return m_returnType; } + + /// Returns a list of argument type infos. + const QList<Argument> &arguments() const { return m_arguments; } + + /// Returns true if this is a constant method. + bool isConstant() const { return m_isConst; } + void setConstant(bool c) { m_isConst = c; }; + + /// Set this method static. + void setStatic(bool value) { m_isStatic = value; } + + /// Set this method as a classmethod. + void setClassMethod(bool value) { m_isClassMethod = value; } + + /// Returns true if this is a static method. + bool isStatic() const { return m_isStatic; } + + /// Returns true if this is a class method. + bool isClassMethod() const { return m_isClassMethod; } + + bool isDeclaration() const { return m_isDeclaration; } // <declare-function> + void setDeclaration(bool value) { m_isDeclaration = value; } + + bool isPythonOverride() const { return m_isPythonOverride; } + void setPythonOverride(bool o) { m_isPythonOverride = o; } + + const FunctionModificationList &modifications() const { return m_modifications; } + FunctionModificationList &modifications() { return m_modifications; } + + const DocModificationList &docModifications() const { return m_docModifications; } + DocModificationList &docModifications() { return m_docModifications; } + void addDocModification(const DocModification &m) { m_docModifications.append(m); } + + QString targetLangPackage() const { return m_targetLangPackage; } + void setTargetLangPackage(const QString &p) { m_targetLangPackage = p; } + +private: + QString m_name; + QList<Argument> m_arguments; + TypeInfo m_returnType; + FunctionModificationList m_modifications; + DocModificationList m_docModifications; + QString m_targetLangPackage; + Access m_access = Public; + bool m_isConst = false; + bool m_isClassMethod = false; + bool m_isStatic = false; + bool m_isDeclaration = false; + bool m_isPythonOverride = false; +}; + +QDebug operator<<(QDebug d, const AddedFunction::Argument &a); +QDebug operator<<(QDebug d, const AddedFunction &af); + +#endif // ADDEDFUNCTION_H diff --git a/sources/shiboken6/ApiExtractor/addedfunction_p.h b/sources/shiboken6/ApiExtractor/addedfunction_p.h new file mode 100644 index 000000000..40b69a5df --- /dev/null +++ b/sources/shiboken6/ApiExtractor/addedfunction_p.h @@ -0,0 +1,45 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef ADDEDFUNCTION_P_H +#define ADDEDFUNCTION_P_H + +#include <QtCore/QtCompare> +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QStringView> + +QT_BEGIN_NAMESPACE +class QDebug; +QT_END_NAMESPACE + +// Helpers to split a parameter list of <add-function>, <declare-function> +// in a separate header for testing purposes + +namespace AddedFunctionParser { + +struct Argument +{ + QString type; + QString name; + QString defaultValue; + + friend bool comparesEqual(const Argument &lhs, const Argument &rhs) noexcept + { + return lhs.type == rhs.type && lhs.name == rhs.name + && lhs.defaultValue == rhs.defaultValue; + } + Q_DECLARE_EQUALITY_COMPARABLE(Argument) +}; + +using Arguments = QList<Argument>; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const Argument &a); +#endif + +Arguments splitParameters(QStringView paramString, QString *errorMessage = nullptr); + +} // namespace AddedFunctionParser + +#endif // MODIFICATIONS_P_H diff --git a/sources/shiboken6/ApiExtractor/anystringview_helpers.cpp b/sources/shiboken6/ApiExtractor/anystringview_helpers.cpp new file mode 100644 index 000000000..35d2d535a --- /dev/null +++ b/sources/shiboken6/ApiExtractor/anystringview_helpers.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "anystringview_helpers.h" + +#include <QtCore/QString> // Must go before QAnyStringView for operator<<(QTextStream,QASV)! +#include <QtCore/QAnyStringView> +#include <QtCore/QDebug> +#include <QtCore/QTextStream> + +#include <cstring> + +QTextStream &operator<<(QTextStream &str, QAnyStringView asv) +{ + asv.visit([&str](auto s) { str << s; }); + return str; +} + +static bool asv_containsImpl(QLatin1StringView v, char c) +{ + return v.contains(uint16_t(c)); +} + +static bool asv_containsImpl(QUtf8StringView v, char c) +{ + return std::strchr(v.data(), c) != nullptr; +} + +static bool asv_containsImpl(QStringView v, char c) +{ + return v.contains(uint16_t(c)); +} + +bool asv_contains(QAnyStringView asv, char needle) +{ + return asv.visit([needle](auto s) { return asv_containsImpl(s, needle); }); +} + +static bool asv_containsImpl(QLatin1StringView v, const char *c) +{ + return v.contains(QLatin1StringView(c)); +} +static bool asv_containsImpl(QUtf8StringView v, const char *c) +{ + return std::strstr(v.data(), c) != nullptr; +} + +static bool asv_containsImpl(QStringView v, const char *c) +{ + return v.contains(QLatin1StringView(c)); +} + +bool asv_contains(QAnyStringView asv, const char *needle) +{ + return asv.visit([needle](auto s) { return asv_containsImpl(s, needle); }); +} diff --git a/sources/shiboken6/ApiExtractor/anystringview_helpers.h b/sources/shiboken6/ApiExtractor/anystringview_helpers.h new file mode 100644 index 000000000..e1e6ab7f0 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/anystringview_helpers.h @@ -0,0 +1,18 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef ANYSTRINGVIEW_STREAM_H +#define ANYSTRINGVIEW_STREAM_H + +#include <QtCore/QtClassHelperMacros> + +QT_FORWARD_DECLARE_CLASS(QAnyStringView) +QT_FORWARD_DECLARE_CLASS(QTextStream) +QT_FORWARD_DECLARE_CLASS(QDebug) + +QTextStream &operator<<(QTextStream &str, QAnyStringView asv); + +bool asv_contains(QAnyStringView asv, char needle); +bool asv_contains(QAnyStringView asv, const char *needle); + +#endif // ANYSTRINGVIEW_STREAM_H diff --git a/sources/shiboken6/ApiExtractor/apiextractor.cpp b/sources/shiboken6/ApiExtractor/apiextractor.cpp index cee8bbdcd..83ee4437e 100644 --- a/sources/shiboken6/ApiExtractor/apiextractor.cpp +++ b/sources/shiboken6/ApiExtractor/apiextractor.cpp @@ -1,156 +1,314 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "apiextractor.h" #include "apiextractorresult.h" +#include "abstractmetaargument.h" +#include "abstractmetabuilder.h" +#include "abstractmetaenum.h" +#include "abstractmetafield.h" +#include "abstractmetafunction.h" #include "abstractmetalang.h" +#include "codesnip.h" +#include "exception.h" +#include "messages.h" +#include "modifications.h" +#include "optionsparser.h" +#include "reporthandler.h" +#include "typedatabase.h" +#include "customconversion.h" +#include "containertypeentry.h" +#include "primitivetypeentry.h" +#include "smartpointertypeentry.h" +#include "typedefentry.h" +#include "namespacetypeentry.h" +#include "typesystemtypeentry.h" + +#include "qtcompat.h" + +#include <QtCore/QDir> +#include <QtCore/QDebug> +#include <QtCore/QTemporaryFile> -#include <QDir> -#include <QDebug> -#include <QTemporaryFile> #include <algorithm> #include <iostream> #include <iterator> -#include "reporthandler.h" -#include "typesystem.h" -#include "fileout.h" -#include "abstractmetabuilder.h" -#include "abstractmetaenum.h" -#include "typedatabase.h" -#include "typesystem.h" +using namespace Qt::StringLiterals; -#include <algorithm> -#include <iterator> +struct InstantiationCollectContext +{ + AbstractMetaTypeList instantiatedContainers; + InstantiatedSmartPointers instantiatedSmartPointers; + QStringList instantiatedContainersNames; +}; -ApiExtractor::ApiExtractor() +struct ApiExtractorOptions { - // Environment TYPESYSTEMPATH - QString envTypesystemPaths = QFile::decodeName(qgetenv("TYPESYSTEMPATH")); - if (!envTypesystemPaths.isEmpty()) - TypeDatabase::instance()->addTypesystemPath(envTypesystemPaths); + QString m_typeSystemFileName; + QFileInfoList m_cppFileNames; + HeaderPaths m_includePaths; + QStringList m_clangOptions; + QString m_logDirectory; + LanguageLevel m_languageLevel = LanguageLevel::Default; + bool m_skipDeprecated = false; +}; + +static inline QString languageLevelDescription() +{ + return u"C++ Language level (c++11..c++17, default="_s + + QLatin1StringView(clang::languageLevelOption(clang::emulatedCompilerLanguageLevel())) + + u')'; } -ApiExtractor::~ApiExtractor() +QList<OptionDescription> ApiExtractor::options() { - delete m_builder; + return { + {u"use-global-header"_s, + u"Use the global headers in generated code."_s}, + {u"clang-option"_s, + u"Option to be passed to clang"_s}, + {u"clang-options"_s, + u"A comma-separated list of options to be passed to clang"_s}, + {u"skip-deprecated"_s, + u"Skip deprecated functions"_s}, + {u"-F<path>"_s, {} }, + {u"framework-include-paths="_s + OptionsParser::pathSyntax(), + u"Framework include paths used by the C++ parser"_s}, + {u"-isystem<path>"_s, {} }, + {u"system-include-paths="_s + OptionsParser::pathSyntax(), + u"System include paths used by the C++ parser"_s}, + {u"language-level=, -std=<level>"_s, + languageLevelDescription()}, + }; } -void ApiExtractor::addTypesystemSearchPath (const QString& path) +class ApiExtractorOptionsParser : public OptionsParser { - TypeDatabase::instance()->addTypesystemPath(path); +public: + explicit ApiExtractorOptionsParser(ApiExtractorOptions *o) : m_options(o) {} + + bool handleBoolOption(const QString &key, OptionSource source) override; + bool handleOption(const QString &key, const QString &value, + OptionSource source) override; + +private: + void parseIncludePathOption(const QString &value, HeaderType headerType); + void parseIncludePathOption(const QStringList &values, HeaderType headerType); + void setLanguageLevel(const QString &value); + + ApiExtractorOptions *m_options; +}; + +void ApiExtractorOptionsParser::parseIncludePathOption(const QString &value, + HeaderType headerType) +{ + if (value.isEmpty()) + throw Exception(u"Empty value passed to include path option"_s); + const auto path = QFile::encodeName(QDir::cleanPath(value)); + m_options->m_includePaths.append(HeaderPath{path, headerType}); } -void ApiExtractor::addTypesystemSearchPath(const QStringList& paths) +void ApiExtractorOptionsParser::parseIncludePathOption(const QStringList &values, + HeaderType headerType) { - for (const QString &path : paths) - addTypesystemSearchPath(path); + for (const auto &value : values) + parseIncludePathOption(value, headerType); } -void ApiExtractor::setTypesystemKeywords(const QStringList &keywords) +void ApiExtractorOptionsParser::setLanguageLevel(const QString &value) { - TypeDatabase::instance()->setTypesystemKeywords(keywords); + const QByteArray languageLevelBA = value.toLatin1(); + const LanguageLevel level = clang::languageLevelFromOption(languageLevelBA.constData()); + if (level == LanguageLevel::Default) + throw Exception(msgInvalidLanguageLevel(value)); + m_options->m_languageLevel = level; +} + +bool ApiExtractorOptionsParser::handleBoolOption(const QString &key, OptionSource source) +{ + static const auto isystemOption = "isystem"_L1; + + switch (source) { + case OptionSource::CommandLine: + case OptionSource::ProjectFile: + if (key == u"use-global-header") { + AbstractMetaBuilder::setUseGlobalHeader(true); + return true; + } + if (key == u"skip-deprecated") { + m_options->m_skipDeprecated = true; + return true; + } + break; + + case OptionSource::CommandLineSingleDash: + if (key.startsWith(u'I')) { // Shorthand path arguments -I/usr/include... + parseIncludePathOption(key.sliced(1), HeaderType::Standard); + return true; + } + if (key.startsWith(u'F')) { + parseIncludePathOption(key.sliced(1), HeaderType::Framework); + return true; + } + if (key.startsWith(isystemOption)) { + parseIncludePathOption(key.sliced(isystemOption.size()), HeaderType::System); + return true; + } + break; + } + return false; } -void ApiExtractor::addIncludePath(const HeaderPath& path) +bool ApiExtractorOptionsParser::handleOption(const QString &key, const QString &value, + OptionSource source) { - m_includePaths << path; + if (source == OptionSource::CommandLineSingleDash) { + if (key == u"std") { + setLanguageLevel(value); + return true; + } + return false; + } + + if (key == u"clang-option") { + m_options->m_clangOptions.append(value); + return true; + } + if (key == u"clang-options") { + m_options->m_clangOptions.append(value.split(u',', Qt::SkipEmptyParts)); + return true; + } + if (key == u"include-paths") { + parseIncludePathOption(value.split(QDir::listSeparator(), Qt::SkipEmptyParts), + HeaderType::Standard); + return true; + } + if (key == u"framework-include-paths") { + parseIncludePathOption(value.split(QDir::listSeparator(), Qt::SkipEmptyParts), + HeaderType::Framework); + return true; + } + if (key == u"system-include-paths") { + parseIncludePathOption(value.split(QDir::listSeparator(), Qt::SkipEmptyParts), + HeaderType::System); + return true; + } + if (key == u"language-level") { + setLanguageLevel(value); + return true; + } + + if (source == OptionSource::ProjectFile) { + if (key == u"include-path") { + parseIncludePathOption(value, HeaderType::Standard); + return true; + } + if (key == u"framework-include-path") { + parseIncludePathOption(value, HeaderType::Framework); + return true; + } + if (key == u"system-include-path") { + parseIncludePathOption(value, HeaderType::System); + return true; + } + } + + return false; } -void ApiExtractor::addIncludePath(const HeaderPaths& paths) +std::shared_ptr<OptionsParser> ApiExtractor::createOptionsParser() { - m_includePaths << paths; + return std::make_shared<ApiExtractorOptionsParser>(d); } -void ApiExtractor::setLogDirectory(const QString& logDir) +struct ApiExtractorPrivate : public ApiExtractorOptions +{ + bool runHelper(ApiExtractorFlags flags); + + static QString getSimplifiedContainerTypeName(const AbstractMetaType &type); + void addInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context, + const AbstractMetaType &type, + const QString &contextName); + void collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context, + const AbstractMetaFunctionCPtr &func); + void collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context, + const AbstractMetaClassCPtr &metaClass); + void collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context); + void collectInstantiatedOpqaqueContainers(InstantiationCollectContext &context); + void collectContainerTypesFromSnippets(InstantiationCollectContext &context); + void collectContainerTypesFromConverterMacros(InstantiationCollectContext &context, + const QString &code, + bool toPythonMacro); + void addInstantiatedSmartPointer(InstantiationCollectContext &context, + const AbstractMetaType &type); + + AbstractMetaBuilder *m_builder = nullptr; +}; + +ApiExtractor::ApiExtractor() : + d(new ApiExtractorPrivate) { - m_logDirectory = logDir; } -void ApiExtractor::setCppFileNames(const QFileInfoList &cppFileName) +ApiExtractor::~ApiExtractor() { - m_cppFileNames = cppFileName; + delete d->m_builder; + delete d; } -void ApiExtractor::setTypeSystem(const QString& typeSystemFileName) +HeaderPaths ApiExtractor::includePaths() const { - m_typeSystemFileName = typeSystemFileName; + return d->m_includePaths; } -void ApiExtractor::setSkipDeprecated(bool value) +void ApiExtractor::setLogDirectory(const QString& logDir) { - m_skipDeprecated = value; - if (m_builder) - m_builder->setSkipDeprecated(m_skipDeprecated); + d->m_logDirectory = logDir; } -void ApiExtractor::setSuppressWarnings ( bool value ) +void ApiExtractor::setCppFileNames(const QFileInfoList &cppFileName) { - TypeDatabase::instance()->setSuppressWarnings(value); + d->m_cppFileNames = cppFileName; } -void ApiExtractor::setSilent ( bool value ) +QFileInfoList ApiExtractor::cppFileNames() const { - ReportHandler::setSilent(value); + return d->m_cppFileNames; } -bool ApiExtractor::setApiVersion(const QString& package, const QString &version) +void ApiExtractor::setTypeSystem(const QString& typeSystemFileName) { - return TypeDatabase::setApiVersion(package, version); + d->m_typeSystemFileName = typeSystemFileName; } -void ApiExtractor::setDropTypeEntries(const QStringList &dropEntries) +QString ApiExtractor::typeSystem() const { - TypeDatabase::instance()->setDropTypeEntries(dropEntries); + return d->m_typeSystemFileName; } const AbstractMetaEnumList &ApiExtractor::globalEnums() const { - Q_ASSERT(m_builder); - return m_builder->globalEnums(); + Q_ASSERT(d->m_builder); + return d->m_builder->globalEnums(); } const AbstractMetaFunctionCList &ApiExtractor::globalFunctions() const { - Q_ASSERT(m_builder); - return m_builder->globalFunctions(); + Q_ASSERT(d->m_builder); + return d->m_builder->globalFunctions(); } const AbstractMetaClassList &ApiExtractor::classes() const { - Q_ASSERT(m_builder); - return m_builder->classes(); + Q_ASSERT(d->m_builder); + return d->m_builder->classes(); } const AbstractMetaClassList &ApiExtractor::smartPointers() const { - Q_ASSERT(m_builder); - return m_builder->smartPointers(); + Q_ASSERT(d->m_builder); + return d->m_builder->smartPointers(); } // Add defines required for parsing Qt code headers @@ -171,7 +329,7 @@ static void addPySideExtensions(QByteArrayList *a) a->append(QByteArrayLiteral("-DQSIMD_H")); } -bool ApiExtractor::runHelper(bool usePySideExtensions) +bool ApiExtractorPrivate::runHelper(ApiExtractorFlags flags) { if (m_builder) return false; @@ -181,9 +339,8 @@ bool ApiExtractor::runHelper(bool usePySideExtensions) return false; } - const QString pattern = QDir::tempPath() + QLatin1Char('/') - + m_cppFileNames.constFirst().baseName() - + QStringLiteral("_XXXXXX.hpp"); + const QString pattern = QDir::tempPath() + u'/' + + m_cppFileNames.constFirst().baseName() + "_XXXXXX.hpp"_L1; QTemporaryFile ppFile(pattern); bool autoRemove = !qEnvironmentVariableIsSet("KEEP_TEMP_FILES"); // make sure that a tempfile can be written @@ -192,7 +349,7 @@ bool ApiExtractor::runHelper(bool usePySideExtensions) << ": " << qPrintable(ppFile.errorString()) << '\n'; return false; } - for (const auto &cppFileName : qAsConst(m_cppFileNames)) { + for (const auto &cppFileName : std::as_const(m_cppFileNames)) { ppFile.write("#include \""); ppFile.write(cppFileName.absoluteFilePath().toLocal8Bit()); ppFile.write("\"\n"); @@ -204,6 +361,7 @@ bool ApiExtractor::runHelper(bool usePySideExtensions) m_builder->setGlobalHeaders(m_cppFileNames); m_builder->setSkipDeprecated(m_skipDeprecated); m_builder->setHeaderPaths(m_includePaths); + m_builder->setApiExtractorFlags(flags); QByteArrayList arguments; const auto clangOptionsSize = m_clangOptions.size(); @@ -220,19 +378,20 @@ bool ApiExtractor::runHelper(bool usePySideExtensions) arguments.append(m_clangOptions.at(i).toUtf8()); } - for (const HeaderPath &headerPath : qAsConst(m_includePaths)) + for (const HeaderPath &headerPath : std::as_const(m_includePaths)) arguments.append(HeaderPath::includeOption(headerPath)); + if (flags.testFlag(ApiExtractorFlag::UsePySideExtensions)) + addPySideExtensions(&arguments); arguments.append(QFile::encodeName(preprocessedCppFileName)); + if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { qCInfo(lcShiboken).noquote().nospace() << "clang language level: " << int(m_languageLevel) << "\nclang arguments: " << arguments; } - if (usePySideExtensions) - addPySideExtensions(&arguments); - - const bool result = m_builder->build(arguments, addCompilerSupportArguments, m_languageLevel); + const bool result = m_builder->build(arguments, flags, addCompilerSupportArguments, + m_languageLevel); if (!result) autoRemove = false; if (!autoRemove) { @@ -248,42 +407,408 @@ static inline void classListToCList(const AbstractMetaClassList &list, AbstractM std::copy(list.cbegin(), list.cend(), std::back_inserter(*target)); } -std::optional<ApiExtractorResult> ApiExtractor::run(bool usePySideExtensions) +std::optional<ApiExtractorResult> ApiExtractor::run(ApiExtractorFlags flags) { - if (!runHelper(usePySideExtensions)) + if (!d->runHelper(flags)) return {}; + InstantiationCollectContext collectContext; + d->collectInstantiatedContainersAndSmartPointers(collectContext); + ApiExtractorResult result; - classListToCList(m_builder->classes(), &result.m_metaClasses); - classListToCList(m_builder->smartPointers(), &result.m_smartPointers); - result.m_globalFunctions = m_builder->globalFunctions(); - result.m_globalEnums = m_builder->globalEnums(); - result.m_enums = m_builder->typeEntryToEnumsHash(); + classListToCList(d->m_builder->takeClasses(), &result.m_metaClasses); + classListToCList(d->m_builder->takeSmartPointers(), &result.m_smartPointers); + result.m_globalFunctions = d->m_builder->globalFunctions(); + result.m_globalEnums = d->m_builder->globalEnums(); + result.m_enums = d->m_builder->typeEntryToEnumsHash(); + result.m_flags = flags; + result.m_typedefTargetToName = d->m_builder->typedefTargetToName(); + qSwap(result.m_instantiatedContainers, collectContext.instantiatedContainers); + qSwap(result.m_instantiatedSmartPointers, collectContext.instantiatedSmartPointers); return result; } LanguageLevel ApiExtractor::languageLevel() const { - return m_languageLevel; + return d->m_languageLevel; } -void ApiExtractor::setLanguageLevel(LanguageLevel languageLevel) +QStringList ApiExtractor::clangOptions() const { - m_languageLevel = languageLevel; + return d->m_clangOptions; } -QStringList ApiExtractor::clangOptions() const +AbstractMetaFunctionPtr + ApiExtractor::inheritTemplateFunction(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes) +{ + return AbstractMetaBuilder::inheritTemplateFunction(function, templateTypes); +} + +AbstractMetaFunctionPtr + ApiExtractor::inheritTemplateMember(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaClassPtr &subclass) { - return m_clangOptions; + return AbstractMetaBuilder::inheritTemplateMember(function, templateTypes, + templateClass, subclass); } -void ApiExtractor::setClangOptions(const QStringList &co) +AbstractMetaClassPtr ApiExtractor::inheritTemplateClass(const ComplexTypeEntryPtr &te, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaTypeList &templateTypes, + InheritTemplateFlags flags) { - m_clangOptions = co; + return AbstractMetaBuilder::inheritTemplateClass(te, templateClass, + templateTypes, flags); } -void ApiExtractor::setUseGlobalHeader(bool h) +QString ApiExtractorPrivate::getSimplifiedContainerTypeName(const AbstractMetaType &type) { - AbstractMetaBuilder::setUseGlobalHeader(h); + const QString signature = type.cppSignature(); + if (!type.typeEntry()->isContainer() && !type.typeEntry()->isSmartPointer()) + return signature; + QString typeName = signature; + if (type.isConstant()) + typeName.remove(0, sizeof("const ") / sizeof(char) - 1); + switch (type.referenceType()) { + case NoReference: + break; + case LValueReference: + typeName.chop(1); + break; + case RValueReference: + typeName.chop(2); + break; + } + while (typeName.endsWith(u'*') || typeName.endsWith(u' ')) + typeName.chop(1); + return typeName; +} + +// Strip a "const QSharedPtr<const Foo> &" or similar to "QSharedPtr<Foo>" (PYSIDE-1016/454) +AbstractMetaType canonicalSmartPtrInstantiation(const AbstractMetaType &type) +{ + const AbstractMetaTypeList &instantiations = type.instantiations(); + Q_ASSERT(instantiations.size() == 1); + const bool needsFix = type.isConstant() || type.referenceType() != NoReference; + const bool pointeeNeedsFix = instantiations.constFirst().isConstant(); + if (!needsFix && !pointeeNeedsFix) + return type; + auto fixedType = type; + fixedType.setReferenceType(NoReference); + fixedType.setConstant(false); + if (pointeeNeedsFix) { + auto fixedPointeeType = instantiations.constFirst(); + fixedPointeeType.setConstant(false); + fixedType.setInstantiations(AbstractMetaTypeList(1, fixedPointeeType)); + } + return fixedType; +} + +static inline TypeEntryCPtr pointeeTypeEntry(const AbstractMetaType &smartPtrType) +{ + return smartPtrType.instantiations().constFirst().typeEntry(); +} + +static AbstractMetaType simplifiedType(AbstractMetaType type) +{ + type.setIndirections(0); + type.setConstant(false); + type.setReferenceType(NoReference); + type.decideUsagePattern(); + return type; +} + +void +ApiExtractorPrivate::addInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context, + const AbstractMetaType &type, + const QString &contextName) +{ + for (const auto &t : type.instantiations()) + addInstantiatedContainersAndSmartPointers(context, t, contextName); + const auto typeEntry = type.typeEntry(); + const bool isContainer = typeEntry->isContainer(); + if (!isContainer + && !(typeEntry->isSmartPointer() && typeEntry->generateCode())) { + return; + } + if (type.hasTemplateChildren()) { + const auto piece = isContainer ? "container"_L1 : "smart pointer"_L1; + QString warning = + QString::fromLatin1("Skipping instantiation of %1 '%2' because it has template" + " arguments.").arg(piece, type.originalTypeDescription()); + if (!contextName.isEmpty()) + warning.append(" Calling context: "_L1 + contextName); + + qCWarning(lcShiboken).noquote().nospace() << warning; + return; + + } + if (isContainer) { + const QString typeName = getSimplifiedContainerTypeName(type); + if (!context.instantiatedContainersNames.contains(typeName)) { + context.instantiatedContainersNames.append(typeName); + context.instantiatedContainers.append(simplifiedType(type)); + } + return; + } + + // Is smart pointer. Check if the (const?) pointee is already known for the given + // smart pointer type entry. + auto pt = pointeeTypeEntry(type); + const bool present = + std::any_of(context.instantiatedSmartPointers.cbegin(), + context.instantiatedSmartPointers.cend(), + [typeEntry, pt] (const InstantiatedSmartPointer &smp) { + return smp.type.typeEntry() == typeEntry + && pointeeTypeEntry(smp.type) == pt; + }); + if (!present) + addInstantiatedSmartPointer(context, type); +} + +// Create a modification that invalidates the pointee argument of a smart +// pointer constructor or reset(). +static FunctionModification invalidateArgMod(const AbstractMetaFunctionCPtr &f, int index = 1) +{ + ArgumentModification argMod; + argMod.setTargetOwnerShip(TypeSystem::CppOwnership); + argMod.setIndex(index); + FunctionModification funcMod; + funcMod.setSignature(f->minimalSignature()); + funcMod.setArgument_mods({argMod}); + return funcMod; +} + +static void addOwnerModification(const AbstractMetaFunctionCList &functions, + const ComplexTypeEntryPtr &typeEntry) +{ + for (const auto &f : functions) { + if (!f->arguments().isEmpty() + && f->arguments().constFirst().type().indirections() > 0) { + std::const_pointer_cast<AbstractMetaFunction>(f)->clearModificationsCache(); + typeEntry->addFunctionModification(invalidateArgMod(f)); + } + } +} + +void ApiExtractorPrivate::addInstantiatedSmartPointer(InstantiationCollectContext &context, + const AbstractMetaType &type) +{ + InstantiatedSmartPointer smp; + smp.type = canonicalSmartPtrInstantiation(type); + smp.smartPointer = AbstractMetaClass::findClass(m_builder->smartPointers(), + type.typeEntry()); + Q_ASSERT(smp.smartPointer); + + const auto &instantiatedType = type.instantiations().constFirst(); + const auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(smp.smartPointer->typeEntry()); + QString name = ste->getTargetName(smp.type); + auto parentTypeEntry = ste->parent(); + InheritTemplateFlags flags; + + auto colonPos = name.lastIndexOf(u"::"); + const bool withinNameSpace = colonPos != -1; + if (withinNameSpace) { // user defined + const QString nameSpace = name.left(colonPos); + name.remove(0, colonPos + 2); + const auto nameSpaces = TypeDatabase::instance()->findNamespaceTypes(nameSpace); + if (nameSpaces.isEmpty()) + throw Exception(msgNamespaceNotFound(name)); + parentTypeEntry = nameSpaces.constFirst(); + } else { + flags.setFlag(InheritTemplateFlag::SetEnclosingClass); + } + + TypedefEntryPtr typedefEntry(new TypedefEntry(name, ste->name(), ste->version(), + parentTypeEntry)); + typedefEntry->setTargetLangPackage(ste->targetLangPackage()); + auto instantiationEntry = TypeDatabase::initializeTypeDefEntry(typedefEntry, ste); + + smp.specialized = ApiExtractor::inheritTemplateClass(instantiationEntry, smp.smartPointer, + {instantiatedType}, flags); + Q_ASSERT(smp.specialized); + if (withinNameSpace) { // move class to desired namespace + const auto enclClass = AbstractMetaClass::findClass(m_builder->classes(), parentTypeEntry); + Q_ASSERT(enclClass); + auto specialized = std::const_pointer_cast<AbstractMetaClass>(smp.specialized); + specialized->setEnclosingClass(enclClass); + enclClass->addInnerClass(specialized); + } + + if (instantiationEntry->isComplex()) { + addOwnerModification(smp.specialized->queryFunctions(FunctionQueryOption::Constructors), + instantiationEntry); + if (!ste->resetMethod().isEmpty()) { + addOwnerModification(smp.specialized->findFunctions(ste->resetMethod()), + instantiationEntry); + } + } + + context.instantiatedSmartPointers.append(smp); +} + +void +ApiExtractorPrivate::collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context, + const AbstractMetaFunctionCPtr &func) +{ + addInstantiatedContainersAndSmartPointers(context, func->type(), func->signature()); + for (const AbstractMetaArgument &arg : func->arguments()) { + const auto argType = arg.type(); + const auto type = argType.viewOn() != nullptr ? *argType.viewOn() : argType; + addInstantiatedContainersAndSmartPointers(context, type, func->signature()); + } +} + +void +ApiExtractorPrivate::collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context, + const AbstractMetaClassCPtr &metaClass) +{ + if (!metaClass->typeEntry()->generateCode()) + return; + for (const auto &func : metaClass->functions()) + collectInstantiatedContainersAndSmartPointers(context, func); + for (const auto &func : metaClass->userAddedPythonOverrides()) + collectInstantiatedContainersAndSmartPointers(context, func); + for (const AbstractMetaField &field : metaClass->fields()) + addInstantiatedContainersAndSmartPointers(context, field.type(), field.name()); + + // The list of inner classes might be extended when smart pointer + // instantiations are specified to be in namespaces. + const auto &innerClasses = metaClass->innerClasses(); + for (auto i = innerClasses.size() - 1; i >= 0; --i) { + const auto innerClass = innerClasses.at(i); + if (!innerClass->typeEntry()->isSmartPointer()) + collectInstantiatedContainersAndSmartPointers(context, innerClass); + } +} + +void +ApiExtractorPrivate::collectInstantiatedContainersAndSmartPointers(InstantiationCollectContext &context) +{ + collectInstantiatedOpqaqueContainers(context); + for (const auto &func : m_builder->globalFunctions()) + collectInstantiatedContainersAndSmartPointers(context, func); + for (const auto &metaClass : m_builder->classes()) + collectInstantiatedContainersAndSmartPointers(context, metaClass); + collectContainerTypesFromSnippets(context); +} + +// Whether to generate an opaque container: If the instantiation type is in +// the current package or, for primitive types, if the container is in the +// current package. +static bool generateOpaqueContainer(const AbstractMetaType &type, + const TypeSystemTypeEntryCPtr &moduleEntry) +{ + auto te = type.instantiations().constFirst().typeEntry(); + auto typeModuleEntry = typeSystemTypeEntry(te); + return typeModuleEntry == moduleEntry + || (te->isPrimitive() && typeSystemTypeEntry(type.typeEntry()) == moduleEntry); +} + +void ApiExtractorPrivate::collectInstantiatedOpqaqueContainers(InstantiationCollectContext &context) +{ + // Add all instantiations of opaque containers for types from the current + // module. + auto *td = TypeDatabase::instance(); + const auto moduleEntry = TypeDatabase::instance()->defaultTypeSystemType(); + const auto &containers = td->containerTypes(); + for (const auto &container : containers) { + for (const auto &oc : container->opaqueContainers()) { + QString errorMessage; + const QString typeName = container->qualifiedCppName() + oc.templateParameters(); + auto typeOpt = AbstractMetaType::fromString(typeName, &errorMessage); + if (typeOpt.has_value() + && generateOpaqueContainer(typeOpt.value(), moduleEntry)) { + addInstantiatedContainersAndSmartPointers(context, typeOpt.value(), + u"opaque containers"_s); + } + } + } +} + +static void getCode(QStringList &code, const CodeSnipList &codeSnips) +{ + for (const CodeSnip &snip : std::as_const(codeSnips)) + code.append(snip.code()); +} + +static void getCode(QStringList &code, const TypeEntryCPtr &type) +{ + if (type->isComplex()) + getCode(code, std::static_pointer_cast<const ComplexTypeEntry>(type)->codeSnips()); + else if (type->isTypeSystem()) + getCode(code, std::static_pointer_cast<const TypeSystemTypeEntry>(type)->codeSnips()); + + auto customConversion = CustomConversion::getCustomConversion(type); + if (!customConversion) + return; + + if (!customConversion->nativeToTargetConversion().isEmpty()) + code.append(customConversion->nativeToTargetConversion()); + + const auto &toCppConversions = customConversion->targetToNativeConversions(); + if (toCppConversions.isEmpty()) + return; + + for (const auto &toNative : std::as_const(toCppConversions)) + code.append(toNative.conversion()); +} + +void ApiExtractorPrivate::collectContainerTypesFromSnippets(InstantiationCollectContext &context) +{ + QStringList snips; + auto *td = TypeDatabase::instance(); + const PrimitiveTypeEntryCList &primitiveTypeList = td->primitiveTypes(); + for (const auto &type : primitiveTypeList) + getCode(snips, type); + const ContainerTypeEntryCList &containerTypeList = td->containerTypes(); + for (const auto &type : containerTypeList) + getCode(snips, type); + for (const auto &metaClass : m_builder->classes()) + getCode(snips, metaClass->typeEntry()); + + const auto moduleEntry = td->defaultTypeSystemType(); + Q_ASSERT(moduleEntry); + getCode(snips, moduleEntry); + + for (const auto &func : m_builder->globalFunctions()) + getCode(snips, func->injectedCodeSnips()); + + for (const QString &code : std::as_const(snips)) { + collectContainerTypesFromConverterMacros(context, code, true); + collectContainerTypesFromConverterMacros(context, code, false); + } +} + +void +ApiExtractorPrivate::collectContainerTypesFromConverterMacros(InstantiationCollectContext &context, + const QString &code, + bool toPythonMacro) +{ + QString convMacro = toPythonMacro ? u"%CONVERTTOPYTHON["_s : u"%CONVERTTOCPP["_s; + const qsizetype offset = toPythonMacro ? sizeof("%CONVERTTOPYTHON") : sizeof("%CONVERTTOCPP"); + qsizetype start = 0; + QString errorMessage; + while ((start = code.indexOf(convMacro, start)) != -1) { + int end = code.indexOf(u']', start); + start += offset; + if (code.at(start) != u'%') { + QString typeString = code.mid(start, end - start); + auto type = AbstractMetaType::fromString(typeString, &errorMessage); + if (type.has_value()) { + const QString &d = type->originalTypeDescription(); + addInstantiatedContainersAndSmartPointers(context, type.value(), d); + } else { + QString m; + QTextStream(&m) << __FUNCTION__ << ": Cannot translate type \"" + << typeString << "\": " << errorMessage; + throw Exception(m); + } + } + start = end; + } } #ifndef QT_NO_DEBUG_STREAM @@ -311,7 +836,7 @@ QDebug operator<<(QDebug d, const ApiExtractor &ae) d.setVerbosity(3); // Trigger verbose output of AbstractMetaClass d << "ApiExtractor(typeSystem=\"" << ae.typeSystem() << "\", cppFileNames=\"" << ae.cppFileNames() << ", "; - ae.m_builder->formatDebug(d); + ae.d->m_builder->formatDebug(d); d << ')'; return d; } diff --git a/sources/shiboken6/ApiExtractor/apiextractor.h b/sources/shiboken6/ApiExtractor/apiextractor.h index f7e3685f5..feae9454c 100644 --- a/sources/shiboken6/ApiExtractor/apiextractor.h +++ b/sources/shiboken6/ApiExtractor/apiextractor.h @@ -1,109 +1,83 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef APIEXTRACTOR_H #define APIEXTRACTOR_H #include "abstractmetalang_typedefs.h" +#include "apiextractorflags.h" #include "header_paths.h" -#include "typedatabase_typedefs.h" -#include "typesystem_typedefs.h" #include "clangparser/compilersupport.h" -#include <QFileInfoList> -#include <QStringList> +#include "typesystem_typedefs.h" + +#include <QtCore/QFileInfoList> +#include <QtCore/QStringList> #include <optional> class ApiExtractorResult; -class AbstractMetaBuilder; class AbstractMetaClass; class AbstractMetaEnum; class AbstractMetaFunction; -class AbstractMetaType; -class ContainerTypeEntry; -class EnumTypeEntry; -class FlagsTypeEntry; -class PrimitiveTypeEntry; -class TypeEntry; +class ComplexTypeEntry; +struct OptionDescription; +class OptionsParser; QT_BEGIN_NAMESPACE class QDebug; class QIODevice; QT_END_NAMESPACE +struct ApiExtractorPrivate; + class ApiExtractor { public: - Q_DISABLE_COPY(ApiExtractor) + Q_DISABLE_COPY_MOVE(ApiExtractor) ApiExtractor(); ~ApiExtractor(); + static QList<OptionDescription> options(); + std::shared_ptr<OptionsParser> createOptionsParser(); + void setTypeSystem(const QString& typeSystemFileName); - QString typeSystem() const { return m_typeSystemFileName; } + QString typeSystem() const; void setCppFileNames(const QFileInfoList &cppFileNames); - QFileInfoList cppFileNames() const { return m_cppFileNames; } - void setSkipDeprecated(bool value); - static void setSuppressWarnings(bool value); - static void setSilent(bool value); - static void addTypesystemSearchPath(const QString &path); - static void addTypesystemSearchPath(const QStringList& paths); - static void setTypesystemKeywords(const QStringList& keywords); - void addIncludePath(const HeaderPath& path); - void addIncludePath(const HeaderPaths& paths); - HeaderPaths includePaths() const { return m_includePaths; } + QFileInfoList cppFileNames() const; + HeaderPaths includePaths() const; void setLogDirectory(const QString& logDir); - static bool setApiVersion(const QString &package, const QString &version); - static void setDropTypeEntries(const QStringList &dropEntries); LanguageLevel languageLevel() const; - void setLanguageLevel(LanguageLevel languageLevel); QStringList clangOptions() const; - void setClangOptions(const QStringList &co); - static void setUseGlobalHeader(bool h); const AbstractMetaEnumList &globalEnums() const; const AbstractMetaFunctionCList &globalFunctions() const; const AbstractMetaClassList &classes() const; const AbstractMetaClassList &smartPointers() const; - std::optional<ApiExtractorResult> run(bool usePySideExtensions); + std::optional<ApiExtractorResult> run(ApiExtractorFlags flags); + + /// Forwards to AbstractMetaBuilder::inheritTemplateFunction() + static AbstractMetaFunctionPtr + inheritTemplateFunction(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes); + + /// Forwards to AbstractMetaBuilder::inheritTemplateMember() + static AbstractMetaFunctionPtr + inheritTemplateMember(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaClassPtr &subclass); + + /// Forwards to AbstractMetaBuilder::inheritTemplateClass() + static AbstractMetaClassPtr + inheritTemplateClass(const ComplexTypeEntryPtr &te, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaTypeList &templateTypes, + InheritTemplateFlags flags = {}); private: - bool runHelper(bool usePySideExtensions); - - QString m_typeSystemFileName; - QFileInfoList m_cppFileNames; - HeaderPaths m_includePaths; - QStringList m_clangOptions; - AbstractMetaBuilder* m_builder = nullptr; - QString m_logDirectory; - LanguageLevel m_languageLevel = LanguageLevel::Default; - bool m_skipDeprecated = false; + ApiExtractorPrivate *d; #ifndef QT_NO_DEBUG_STREAM friend QDebug operator<<(QDebug d, const ApiExtractor &ae); diff --git a/sources/shiboken6/ApiExtractor/apiextractorflags.h b/sources/shiboken6/ApiExtractor/apiextractorflags.h new file mode 100644 index 000000000..4fe6ecc1a --- /dev/null +++ b/sources/shiboken6/ApiExtractor/apiextractorflags.h @@ -0,0 +1,26 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef APIEXTRACTORFLAGS_H +#define APIEXTRACTORFLAGS_H + +#include <QtCore/QFlags> + +enum class ApiExtractorFlag +{ + UsePySideExtensions = 0x1, + AvoidProtectedHack = 0x2 +}; + +Q_DECLARE_FLAGS(ApiExtractorFlags, ApiExtractorFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(ApiExtractorFlags) + +enum class InheritTemplateFlag +{ + SetEnclosingClass = 0x1 +}; + +Q_DECLARE_FLAGS(InheritTemplateFlags, InheritTemplateFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(InheritTemplateFlags) + +#endif // APIEXTRACTORFLAGS_H diff --git a/sources/shiboken6/ApiExtractor/apiextractorresult.cpp b/sources/shiboken6/ApiExtractor/apiextractorresult.cpp index 04566ada2..2a48a30d1 100644 --- a/sources/shiboken6/ApiExtractor/apiextractorresult.cpp +++ b/sources/shiboken6/ApiExtractor/apiextractorresult.cpp @@ -1,48 +1,82 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "apiextractorresult.h" #include "abstractmetalang.h" #include "abstractmetaenum.h" -#include "typesystem.h" +#include "enumtypeentry.h" +#include "flagstypeentry.h" -std::optional<AbstractMetaEnum> ApiExtractorResult::findAbstractMetaEnum(const TypeEntry *typeEntry) const +ApiExtractorResult::ApiExtractorResult() = default; + +ApiExtractorResult::ApiExtractorResult(const ApiExtractorResult &) = default; + +ApiExtractorResult &ApiExtractorResult::operator=(const ApiExtractorResult &) = default; + +ApiExtractorResult::ApiExtractorResult(ApiExtractorResult &&) noexcept = default; + +ApiExtractorResult &ApiExtractorResult::operator=(ApiExtractorResult &&) noexcept = default; + +ApiExtractorResult::~ApiExtractorResult() = default; + +const AbstractMetaEnumList &ApiExtractorResult::globalEnums() const +{ + return m_globalEnums; +} + +const AbstractMetaFunctionCList &ApiExtractorResult::globalFunctions() const +{ + return m_globalFunctions; +} + +const AbstractMetaClassCList &ApiExtractorResult::classes() const +{ + return m_metaClasses; +} + +const AbstractMetaClassCList &ApiExtractorResult::smartPointers() const +{ + return m_smartPointers; +} + +const AbstractMetaTypeList &ApiExtractorResult::instantiatedContainers() const +{ + return m_instantiatedContainers; +} + +const InstantiatedSmartPointers &ApiExtractorResult::instantiatedSmartPointers() const +{ + return m_instantiatedSmartPointers; +} + +const QMultiHash<QString, QString> &ApiExtractorResult::typedefTargetToName() const +{ + return m_typedefTargetToName; +} + +ApiExtractorFlags ApiExtractorResult::flags() const +{ + return m_flags; +} + +void ApiExtractorResult::setFlags(ApiExtractorFlags f) +{ + m_flags = f; +} + +std::optional<AbstractMetaEnum> + ApiExtractorResult::findAbstractMetaEnum(TypeEntryCPtr typeEntry) const { if (typeEntry && typeEntry->isFlags()) - typeEntry = static_cast<const FlagsTypeEntry *>(typeEntry)->originator(); + typeEntry = std::static_pointer_cast<const FlagsTypeEntry>(typeEntry)->originator(); const auto it = m_enums.constFind(typeEntry); if (it == m_enums.constEnd()) return {}; return it.value(); } -AbstractMetaFunctionCList ApiExtractorResult::implicitConversions(const TypeEntry *type) const +AbstractMetaFunctionCList ApiExtractorResult::implicitConversions(const TypeEntryCPtr &type) const { if (type->isValue()) { if (auto metaClass = AbstractMetaClass::findClass(m_metaClasses, type)) diff --git a/sources/shiboken6/ApiExtractor/apiextractorresult.h b/sources/shiboken6/ApiExtractor/apiextractorresult.h index 18b07a1b7..88a2093f1 100644 --- a/sources/shiboken6/ApiExtractor/apiextractorresult.h +++ b/sources/shiboken6/ApiExtractor/apiextractorresult.h @@ -1,75 +1,78 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef APIEXTRACTORRESULT_H #define APIEXTRACTORRESULT_H -#include "abstractmetalang.h" -#include "abstractmetaenum.h" +#include "apiextractorflags.h" #include "abstractmetatype.h" +#include "abstractmetalang_typedefs.h" #include "typesystem_typedefs.h" #include <QtCore/QHash> +#include <QtCore/QMultiHash> #include <optional> +class ApiExtractorResultData; + +struct InstantiatedSmartPointer +{ + AbstractMetaClassCPtr smartPointer; // Template class + AbstractMetaClassCPtr specialized; // Specialized for type + AbstractMetaType type; +}; + +using InstantiatedSmartPointers = QList<InstantiatedSmartPointer>; + /// Result of an ApiExtractor run. -/// Note: The class lists in here are flat, non-owning lists, currently -/// (pending introduction of QSharedPointer for AbstractMetaClass); the -/// ApiExtractor/AbstractMetaBuilder must be kept alive during the -/// generator run since it owns the classes. class ApiExtractorResult { - friend class ApiExtractor; public: - const AbstractMetaEnumList &globalEnums() const { return m_globalEnums; } - const AbstractMetaFunctionCList &globalFunctions() const { return m_globalFunctions; } - const AbstractMetaClassCList &classes() const { return m_metaClasses; } - const AbstractMetaClassCList &smartPointers() const { return m_smartPointers; } + ApiExtractorResult(); + ApiExtractorResult(const ApiExtractorResult &); + ApiExtractorResult &operator=(const ApiExtractorResult &); + ApiExtractorResult(ApiExtractorResult &&) noexcept; + ApiExtractorResult &operator=(ApiExtractorResult &&) noexcept; + ~ApiExtractorResult(); + + const AbstractMetaEnumList &globalEnums() const; + const AbstractMetaFunctionCList &globalFunctions() const; + const AbstractMetaClassCList &classes() const; + const AbstractMetaClassCList &smartPointers() const; + + const AbstractMetaTypeList &instantiatedContainers() const; + const InstantiatedSmartPointers &instantiatedSmartPointers() const; + + const QMultiHash<QString, QString> &typedefTargetToName() const; // Query functions for the generators - std::optional<AbstractMetaEnum> findAbstractMetaEnum(const TypeEntry* typeEntry) const; + std::optional<AbstractMetaEnum> + findAbstractMetaEnum(TypeEntryCPtr typeEntry) const; /// Retrieves a list of constructors used in implicit conversions /// available on the given type. The TypeEntry must be a value-type /// or else it will return an empty list. /// \param type a TypeEntry that is expected to be a value-type /// \return a list of constructors that could be used as implicit converters - AbstractMetaFunctionCList implicitConversions(const TypeEntry *type) const; + AbstractMetaFunctionCList implicitConversions(const TypeEntryCPtr &type) const; AbstractMetaFunctionCList implicitConversions(const AbstractMetaType &metaType) const; + ApiExtractorFlags flags() const; + void setFlags(ApiExtractorFlags f); + private: AbstractMetaClassCList m_metaClasses; AbstractMetaClassCList m_smartPointers; AbstractMetaFunctionCList m_globalFunctions; AbstractMetaEnumList m_globalEnums; + AbstractMetaTypeList m_instantiatedContainers; + InstantiatedSmartPointers m_instantiatedSmartPointers; + QHash<TypeEntryCPtr, AbstractMetaEnum> m_enums; + QMultiHash<QString, QString> m_typedefTargetToName; + ApiExtractorFlags m_flags; - QHash<const TypeEntry *, AbstractMetaEnum> m_enums; + friend class ApiExtractor; }; #endif // APIEXTRACTORRESULT_H diff --git a/sources/shiboken6/ApiExtractor/arraytypeentry.h b/sources/shiboken6/ApiExtractor/arraytypeentry.h new file mode 100644 index 000000000..5b9bb191e --- /dev/null +++ b/sources/shiboken6/ApiExtractor/arraytypeentry.h @@ -0,0 +1,28 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef ARRAYTYPEENTRY_H +#define ARRAYTYPEENTRY_H + +#include "typesystem.h" + +class ArrayTypeEntryPrivate; + +class ArrayTypeEntry : public TypeEntry +{ +public: + explicit ArrayTypeEntry(const TypeEntryCPtr &nested_type, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + void setNestedTypeEntry(const TypeEntryPtr &nested); + TypeEntryCPtr nestedTypeEntry() const; + + TypeEntry *clone() const override; + +protected: + explicit ArrayTypeEntry(ArrayTypeEntryPrivate *d); + + QString buildTargetLangName() const override; +}; + +#endif // ARRAYTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp index de0f2eb4f..31e7efb05 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp @@ -1,38 +1,16 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "clangbuilder.h" #include "compilersupport.h" #include "clangutils.h" +#include "clangdebugutils.h" #include <codemodel.h> #include <reporthandler.h> +#include "qtcompat.h" + #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QHash> @@ -44,10 +22,9 @@ #include <cstring> #include <ctype.h> -namespace clang { +using namespace Qt::StringLiterals; -static inline QString colonColon() { return QStringLiteral("::"); } -static inline QString templateBrackets() { return QStringLiteral("<>"); } +namespace clang { static inline bool isClassCursor(const CXCursor &c) { @@ -69,9 +46,9 @@ static inline bool withinClassDeclaration(const CXCursor &cursor) static QString fixTypeName(QString t) { // Fix "Foo &" -> "Foo&", similarly "Bar **" -> "Bar**" - int pos = t.size() - 1; - for (; pos >= 0 && (t.at(pos) == QLatin1Char('&') || t.at(pos) == QLatin1Char('*')); --pos) {} - if (pos > 0 && t.at(pos) == QLatin1Char(' ')) + auto pos = t.size() - 1; + for (; pos >= 0 && (t.at(pos) == u'&' || t.at(pos) == u'*'); --pos) {} + if (pos > 0 && t.at(pos) == u' ') t.remove(pos, 1); return t; } @@ -81,13 +58,13 @@ static QString fixTypeName(QString t) // the class name "Foo<T1,T2>" is the scope for nested items. static bool insertTemplateParameterIntoClassName(const QString &parmName, QString *name) { - if (Q_UNLIKELY(!name->endsWith(QLatin1Char('>')))) + if (Q_UNLIKELY(!name->endsWith(u'>'))) return false; - const bool needsComma = name->at(name->size() - 2) != QLatin1Char('<'); - const int insertionPos = name->size() - 1; + const bool needsComma = name->at(name->size() - 2) != u'<'; + const auto insertionPos = name->size() - 1; name->insert(insertionPos, parmName); if (needsComma) - name->insert(insertionPos, QLatin1Char(',')); + name->insert(insertionPos, u','); return true; } @@ -136,14 +113,27 @@ static bool isSigned(CXTypeKind kind) class BuilderPrivate { public: + Q_DISABLE_COPY_MOVE(BuilderPrivate) + + enum class SpecialSystemHeader { + None, + Types, + OpenGL, + WhiteListed, + WhiteListedPath + }; + using CursorClassHash = QHash<CXCursor, ClassModelItem>; - using CursorTypedefHash = QHash<CXCursor, TypeDefModelItem>; using TypeInfoHash = QHash<CXType, TypeInfo>; explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv), m_model(new CodeModel) { m_scopeStack.push(NamespaceModelItem(new _FileModelItem(m_model))); } + ~BuilderPrivate() + { + delete m_model; + } // Determine scope from top item. Note that the scope list does not necessarily // match the scope stack in case of forward-declared inner classes whose definition @@ -196,13 +186,12 @@ public: void addField(const CXCursor &cursor); static QString cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor); - QString getBaseClassName(CXType type) const; + std::pair<QString, ClassModelItem> getBaseClass(CXType type) const; void addBaseClass(const CXCursor &cursor); - template <class Item> - void qualifyTypeDef(const CXCursor &typeRefCursor, const QSharedPointer<Item> &item) const; - - bool visitHeader(const char *cFileName) const; + SpecialSystemHeader specialSystemHeader(const QString &fileName) const; + bool visitHeader(const QString &fileName) const; + static const char *specialSystemHeaderReason(SpecialSystemHeader sh); void setFileName(const CXCursor &cursor, _CodeModelItem *item); @@ -215,7 +204,6 @@ public: // classes can be correctly parented in case of forward-declared inner classes // (QMetaObject::Connection) CursorClassHash m_cursorClassHash; - CursorTypedefHash m_cursorTypedefHash; mutable TypeInfoHash m_typeInfoHash; // Cache type information mutable QHash<QString, TemplateTypeAliasModelItem> m_templateTypeAliases; @@ -226,21 +214,22 @@ public: ArgumentModelItem m_currentArgument; VariableModelItem m_currentField; TemplateTypeAliasModelItem m_currentTemplateTypeAlias; - QByteArrayList m_systemIncludes; // files, like "memory" - QByteArrayList m_systemIncludePaths; // paths, like "/usr/include/Qt/" + QStringList m_forceProcessSystemIncludes; // files, like "memory" + QStringList m_forceProcessSystemIncludePaths; // paths, like "/usr/include/Qt/" QString m_usingTypeRef; // Base classes in "using Base::member;" bool m_withinUsingDeclaration = false; int m_anonymousEnumCount = 0; CodeModel::FunctionType m_currentFunctionType = CodeModel::Normal; bool m_withinFriendDecl = false; + mutable QHash<QString, SpecialSystemHeader> m_systemHeaders; }; bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t) { QString className = getCursorSpelling(cursor); m_currentClass.reset(new _ClassModelItem(m_model, className)); - setFileName(cursor, m_currentClass.data()); + setFileName(cursor, m_currentClass.get()); m_currentClass->setClassType(t); // Some inner class? Note that it does not need to be (lexically) contained in a // class since it is possible to forward declare an inner class: @@ -283,10 +272,9 @@ static QString msgCannotDetermineException(const std::string_view &snippetV) const qsizetype length = qsizetype(truncate ? newLine : snippetV.size()); QString snippet = QString::fromUtf8(snippetV.data(), length); if (truncate) - snippet += QStringLiteral("..."); + snippet += "..."_L1; - return QLatin1String("Cannot determine exception specification: \"") - + snippet + QLatin1Char('"'); + return u"Cannot determine exception specification: \""_s + snippet + u'"'; } // Return whether noexcept(<value>) throws. noexcept() takes a constexpr value. @@ -343,11 +331,13 @@ FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor, { QString name = getCursorSpelling(cursor); // Apply type fixes to "operator X &" -> "operator X&" - if (name.startsWith(QLatin1String("operator "))) + if (name.startsWith(u"operator ")) name = fixTypeName(name); - FunctionModelItem result(new _FunctionModelItem(m_model, name)); - setFileName(cursor, result.data()); - result->setType(createTypeInfo(clang_getCursorResultType(cursor))); + auto result = std::make_shared<_FunctionModelItem>(m_model, name); + setFileName(cursor, result.get()); + const auto type = clang_getCursorResultType(cursor); + result->setType(createTypeInfo(type)); + result->setScopeResolution(hasScopeResolution(type)); result->setFunctionType(t); result->setScope(m_scope); result->setStatic(clang_Cursor_getStorageClass(cursor) == CX_SC_Static); @@ -356,7 +346,7 @@ FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor, case CXAvailability_Available: break; case CXAvailability_Deprecated: - result->setDeprecated(true); + result->setAttribute(FunctionAttribute::Deprecated); break; case CXAvailability_NotAvailable: // "Foo(const Foo&) = delete;" result->setDeleted(true); @@ -395,13 +385,13 @@ FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor, m_currentFunctionType == CodeModel::Signal || m_currentFunctionType == CodeModel::Slot ? m_currentFunctionType // by annotation : functionTypeFromCursor(cursor); - isTemplateCode |= m_currentClass->name().endsWith(QLatin1Char('>')); + isTemplateCode |= m_currentClass->name().endsWith(u'>'); auto result = createFunction(cursor, functionType, isTemplateCode); result->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor))); result->setConstant(clang_CXXMethod_isConst(cursor) != 0); - result->setStatic(clang_CXXMethod_isStatic(cursor) != 0); - result->setVirtual(clang_CXXMethod_isVirtual(cursor) != 0); - result->setAbstract(clang_CXXMethod_isPureVirtual(cursor) != 0); + result->setAttribute(FunctionAttribute::Static, clang_CXXMethod_isStatic(cursor) != 0); + result->setAttribute(FunctionAttribute::Virtual, clang_CXXMethod_isVirtual(cursor) != 0); + result->setAttribute(FunctionAttribute::Abstract, clang_CXXMethod_isPureVirtual(cursor) != 0); return result; } @@ -417,13 +407,14 @@ void BuilderPrivate::qualifyConstructor(const CXCursor &cursor) && m_currentFunction->arguments().size() == 1 && clang_CXXConstructor_isCopyConstructor(cursor) == 0 && clang_CXXConstructor_isMoveConstructor(cursor) == 0) { - m_currentFunction->setExplicit(clang_CXXConstructor_isConvertingConstructor(cursor) == 0); + m_currentFunction->setAttribute(FunctionAttribute::Explicit, + clang_CXXConstructor_isConvertingConstructor(cursor) == 0); } } TemplateParameterModelItem BuilderPrivate::createTemplateParameter(const CXCursor &cursor) const { - return TemplateParameterModelItem(new _TemplateParameterModelItem(m_model, getCursorSpelling(cursor))); + return std::make_shared<_TemplateParameterModelItem>(m_model, getCursorSpelling(cursor)); } TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const CXCursor &cursor) const @@ -436,11 +427,12 @@ TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const // CXCursor_VarDecl, CXCursor_FieldDecl cursors void BuilderPrivate::addField(const CXCursor &cursor) { - VariableModelItem field(new _VariableModelItem(m_model, getCursorSpelling(cursor))); + auto field = std::make_shared<_VariableModelItem>(m_model, getCursorSpelling(cursor)); field->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor))); field->setScope(m_scope); field->setType(createTypeInfo(cursor)); field->setMutable(clang_CXXField_isMutable(cursor) != 0); + setFileName(cursor, field.get()); m_currentField = field; m_scopeStack.back()->addVariable(field); } @@ -449,14 +441,14 @@ void BuilderPrivate::addField(const CXCursor &cursor) static QStringList qualifiedName(const QString &t) { QStringList result; - int end = t.indexOf(QLatin1Char('<')); + int end = t.indexOf(u'<'); if (end == -1) - end = t.indexOf(QLatin1Char('(')); + end = t.indexOf(u'('); if (end == -1) end = t.size(); int lastPos = 0; while (true) { - const int nextPos = t.indexOf(colonColon(), lastPos); + const int nextPos = t.indexOf(u"::"_s, lastPos); if (nextPos < 0 || nextPos >= end) break; result.append(t.mid(lastPos, nextPos - lastPos)); @@ -520,7 +512,7 @@ void BuilderPrivate::addTemplateInstantiations(const CXType &type, && !t->instantiations().isEmpty(); if (!parsed) t->setInstantiations({}); - const QPair<int, int> pos = parsed + const auto pos = parsed ? parseTemplateArgumentList(*typeName, dummyTemplateArgumentHandler) : t->parseTemplateArgumentList(*typeName); if (pos.first != -1 && pos.second != -1 && pos.second > pos.first) @@ -574,7 +566,7 @@ TypeInfo BuilderPrivate::createTypeInfoUncached(const CXType &type, typeInfo.setConstant(clang_isConstQualifiedType(nestedType) != 0); typeInfo.setVolatile(clang_isVolatileQualifiedType(nestedType) != 0); - QString typeName = getTypeName(nestedType); + QString typeName = getResolvedTypeName(nestedType); while (TypeInfo::stripLeadingConst(&typeName) || TypeInfo::stripLeadingVolatile(&typeName)) { } @@ -584,21 +576,21 @@ TypeInfo BuilderPrivate::createTypeInfoUncached(const CXType &type, // the typedef source is named "type-parameter-0-0". Convert it back to the // template parameter name. The CXTypes are the same for all templates and // must not be cached. - if (!m_currentClass.isNull() && typeName.startsWith(QLatin1String("type-parameter-0-"))) { + if (m_currentClass && typeName.startsWith(u"type-parameter-0-")) { if (cacheable != nullptr) *cacheable = false; bool ok; const int n = QStringView{typeName}.mid(17).toInt(&ok); if (ok) { auto currentTemplate = currentTemplateClass(); - if (!currentTemplate.isNull() && n < currentTemplate->templateParameters().size()) + if (currentTemplate && n < currentTemplate->templateParameters().size()) typeName = currentTemplate->templateParameters().at(n)->name(); } } // Obtain template instantiations if the name has '<' (thus excluding // typedefs like "std::string". - if (typeName.contains(QLatin1Char('<'))) + if (typeName.contains(u'<')) addTemplateInstantiations(nestedType, &typeName, &typeInfo); typeInfo.setQualifiedName(qualifiedName(typeName)); @@ -622,19 +614,18 @@ TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const void BuilderPrivate::addTypeDef(const CXCursor &cursor, const CXType &cxType) { const QString target = getCursorSpelling(cursor); - TypeDefModelItem item(new _TypeDefModelItem(m_model, target)); - setFileName(cursor, item.data()); + auto item = std::make_shared<_TypeDefModelItem>(m_model, target); + setFileName(cursor, item.get()); item->setType(createTypeInfo(cxType)); item->setScope(m_scope); m_scopeStack.back()->addTypeDef(item); - m_cursorTypedefHash.insert(cursor, item); } ClassModelItem BuilderPrivate::currentTemplateClass() const { - for (int i = m_scopeStack.size() - 1; i >= 0; --i) { - auto klass = qSharedPointerDynamicCast<_ClassModelItem>(m_scopeStack.at(i)); - if (!klass.isNull() && klass->isTemplate()) + for (auto i = m_scopeStack.size() - 1; i >= 0; --i) { + auto klass = std::dynamic_pointer_cast<_ClassModelItem>(m_scopeStack.at(i)); + if (klass && klass->isTemplate()) return klass; } return {}; @@ -644,7 +635,7 @@ void BuilderPrivate::startTemplateTypeAlias(const CXCursor &cursor) { const QString target = getCursorSpelling(cursor); m_currentTemplateTypeAlias.reset(new _TemplateTypeAliasModelItem(m_model, target)); - setFileName(cursor, m_currentTemplateTypeAlias.data()); + setFileName(cursor, m_currentTemplateTypeAlias.get()); m_currentTemplateTypeAlias->setScope(m_scope); } @@ -669,11 +660,17 @@ QString BuilderPrivate::cursorValueExpression(BaseVisitor *bv, const CXCursor &c if (equalSign == std::string::npos) return QString(); ++equalSign; - return QString::fromLocal8Bit(snippet.data() + equalSign, - qsizetype(snippet.size() - equalSign)).trimmed(); + QString result = QString::fromLocal8Bit(snippet.data() + equalSign, + qsizetype(snippet.size() - equalSign)); + // Fix a default expression as read from code. Simplify white space + result.remove(u'\r'); + return result.contains(u'"') ? result.trimmed() : result.simplified(); } // Resolve a type (loop over aliases/typedefs), for example for base classes +// Note: TypeAliasTemplateDecl ("using QVector<T>=QList<T>") is automatically +// resolved by clang_getTypeDeclaration(), but it stops at +// TypeAliasDecl / TypedefDecl. struct TypeDeclaration { @@ -681,47 +678,41 @@ struct TypeDeclaration CXCursor declaration; }; -static TypeDeclaration resolveType(CXType type) +static inline bool isTypeAliasDecl(const CXCursor &cursor) +{ + const auto kind = clang_getCursorKind(cursor); + return kind == CXCursor_TypeAliasDecl || kind == CXCursor_TypedefDecl; +} + +static TypeDeclaration resolveBaseClassType(CXType type) { CXCursor decl = clang_getTypeDeclaration(type); - if (type.kind != CXType_Unexposed) { - while (true) { - auto kind = clang_getCursorKind(decl); - if (kind != CXCursor_TypeAliasDecl && kind != CXCursor_TypedefDecl) - break; - type = clang_getTypedefDeclUnderlyingType(decl); - decl = clang_getTypeDeclaration(type); - } + auto resolvedType = clang_getCursorType(decl); + if (resolvedType.kind != CXType_Invalid && resolvedType.kind != type.kind) + type = resolvedType; + while (isTypeAliasDecl(decl)) { + type = clang_getTypedefDeclUnderlyingType(decl); + decl = clang_getTypeDeclaration(type); } return {type, decl}; } // Note: Return the baseclass for cursors like CXCursor_CXXBaseSpecifier, // where the cursor spelling has "struct baseClass". -QString BuilderPrivate::getBaseClassName(CXType type) const +std::pair<QString, ClassModelItem> BuilderPrivate::getBaseClass(CXType type) const { - const auto decl = resolveType(type); + const auto decl = resolveBaseClassType(type); // Note: spelling has "struct baseClass", use type - QString baseClassName; - if (decl.type.kind == CXType_Unexposed) { - // The type is unexposed when the base class is a template type alias: - // "class QItemSelection : public QList<X>" where QList is aliased to QVector. - // Try to resolve via code model. - TypeInfo info = createTypeInfo(decl.type); - auto parentScope = m_scopeStack.at(m_scopeStack.size() - 2); // Current is class. - auto resolved = TypeInfo::resolveType(info, parentScope); - if (resolved != info) - baseClassName = resolved.toString(); - } - if (baseClassName.isEmpty()) - baseClassName = getTypeName(decl.type); + QString baseClassName = getTypeName(decl.type); + if (baseClassName.startsWith(u"std::")) // Simplify "std::" types + baseClassName = createTypeInfo(decl.type).toString(); auto it = m_cursorClassHash.constFind(decl.declaration); // Not found: Set unqualified name. This happens in cases like // "class X : public std::list<...>", "template<class T> class Foo : public T" // and standard types like true_type, false_type. if (it == m_cursorClassHash.constEnd()) - return baseClassName; + return {baseClassName, {}}; // Completely qualify the class name by looking it up and taking its scope // plus the actual baseClass stripped off any scopes. Consider: @@ -735,13 +726,13 @@ QString BuilderPrivate::getBaseClassName(CXType type) const // "std::vector<T>"). const QStringList &baseScope = it.value()->scope(); if (!baseScope.isEmpty()) { - const int lastSep = baseClassName.lastIndexOf(colonColon()); + const int lastSep = baseClassName.lastIndexOf(u"::"_s); if (lastSep >= 0) - baseClassName.remove(0, lastSep + colonColon().size()); - baseClassName.prepend(colonColon()); - baseClassName.prepend(baseScope.join(colonColon())); + baseClassName.remove(0, lastSep + u"::"_s.size()); + baseClassName.prepend(u"::"_s); + baseClassName.prepend(baseScope.join(u"::"_s)); } - return baseClassName; + return {baseClassName, it.value()}; } // Add a base class to the current class from CXCursor_CXXBaseSpecifier @@ -749,39 +740,8 @@ void BuilderPrivate::addBaseClass(const CXCursor &cursor) { Q_ASSERT(clang_getCursorKind(cursor) == CXCursor_CXXBaseSpecifier); const auto access = accessPolicy(clang_getCXXAccessSpecifier(cursor)); - QString baseClassName = getBaseClassName(clang_getCursorType(cursor)); - m_currentClass->addBaseClass(baseClassName, access); -} - -static inline CXCursor definitionFromTypeRef(const CXCursor &typeRefCursor) -{ - Q_ASSERT(typeRefCursor.kind == CXCursor_TypeRef); - return clang_getTypeDeclaration(clang_getCursorType(typeRefCursor)); -} - -// Qualify function arguments or fields that are typedef'ed from another scope: -// enum ConversionFlag {}; -// typedef QFlags<ConversionFlag> ConversionFlags; -// class QTextCodec { -// enum ConversionFlag {}; -// typedef QFlags<ConversionFlag> ConversionFlags; -// struct ConverterState { -// explicit ConverterState(ConversionFlags); -// ^^ qualify to QTextCodec::ConversionFlags -// ConversionFlags m_flags; -// ^^ ditto - -template <class Item> // ArgumentModelItem, VariableModelItem -void BuilderPrivate::qualifyTypeDef(const CXCursor &typeRefCursor, const QSharedPointer<Item> &item) const -{ - TypeInfo type = item->type(); - if (type.qualifiedName().size() == 1) { // item's type is unqualified. - const auto it = m_cursorTypedefHash.constFind(definitionFromTypeRef(typeRefCursor)); - if (it != m_cursorTypedefHash.constEnd() && !it.value()->scope().isEmpty()) { - type.setQualifiedName(it.value()->scope() + type.qualifiedName()); - item->setType(type); - } - } + const auto baseClass = getBaseClass(clang_getCursorType(cursor)); + m_currentClass->addBaseClass({baseClass.first, baseClass.second, access}); } void BuilderPrivate::setFileName(const CXCursor &cursor, _CodeModelItem *item) @@ -805,103 +765,115 @@ Builder::~Builder() delete d; } -static const char *cBaseName(const char *fileName) +static QString baseName(QString path) { - const char *lastSlash = std::strrchr(fileName, '/'); + qsizetype lastSlash = path.lastIndexOf(u'/'); #ifdef Q_OS_WIN - if (lastSlash == nullptr) - lastSlash = std::strrchr(fileName, '\\'); + if (lastSlash < 0) + lastSlash = path.lastIndexOf(u'\\'); #endif - return lastSlash != nullptr ? (lastSlash + 1) : fileName; + if (lastSlash > 0) + path.remove(0, lastSlash + 1); + return path; } -static inline bool cCompareFileName(const char *f1, const char *f2) +const char * BuilderPrivate::specialSystemHeaderReason(BuilderPrivate::SpecialSystemHeader sh) { -#ifdef Q_OS_WIN - return _stricmp(f1, f2) == 0; -#else - return std::strcmp(f1, f2) == 0; -#endif -} - -#ifdef Q_OS_UNIX -template<size_t N> -static bool cStringStartsWith(const char *str, const char (&prefix)[N]) -{ - return std::strncmp(prefix, str, N - 1) == 0; + static const QHash<SpecialSystemHeader, const char *> mapping { + {SpecialSystemHeader::OpenGL, "OpenGL"}, + {SpecialSystemHeader::Types, "types"}, + {SpecialSystemHeader::WhiteListed, "white listed"}, + {SpecialSystemHeader::WhiteListedPath, "white listed path"} + }; + return mapping.value(sh, ""); } -#endif -static bool cStringStartsWith(const char *str, const QByteArray &prefix) +bool BuilderPrivate::visitHeader(const QString &fileName) const { - return std::strncmp(prefix.constData(), str, int(prefix.size())) == 0; + auto it = m_systemHeaders.find(fileName); + if (it == m_systemHeaders.end()) { + it = m_systemHeaders.insert(fileName, specialSystemHeader(fileName)); + if (ReportHandler::isDebug(ReportHandler::MediumDebug)) { + const QString &name = QDir::toNativeSeparators(fileName); + if (it.value() == SpecialSystemHeader::None) { + qCInfo(lcShiboken, "Skipping system header %s", qPrintable(name)); + } else { + qCInfo(lcShiboken, "Parsing system header %s (%s)", + qPrintable(name), specialSystemHeaderReason(it.value())); + } + } + } + return it.value() != SpecialSystemHeader::None; } -bool BuilderPrivate::visitHeader(const char *cFileName) const +BuilderPrivate::SpecialSystemHeader + BuilderPrivate::specialSystemHeader(const QString &fileName) const { // Resolve OpenGL typedefs although the header is considered a system header. - const char *baseName = cBaseName(cFileName); - if (cCompareFileName(baseName, "gl.h")) - return true; -#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) - if (cStringStartsWith(cFileName, "/usr/include/stdint.h")) - return true; -#endif -#ifdef Q_OS_LINUX - if (cStringStartsWith(cFileName, "/usr/include/stdlib.h") - || cStringStartsWith(cFileName, "/usr/include/sys/types.h")) { - return true; + const QString baseName = clang::baseName(fileName); + if (baseName == u"gl.h" + || baseName == u"gl2.h" + || baseName == u"gl3.h" + || baseName == u"gl31.h" + || baseName == u"gl32.h" + || baseName == u"stdint.h" // Windows: int32_t, uint32_t + || baseName == u"stddef.h") { // size_t` + return SpecialSystemHeader::OpenGL; } -#endif // Q_OS_LINUX -#ifdef Q_OS_MACOS - // Parse the following system headers to get the correct typdefs for types like - // int32_t, which are used in the macOS implementation of OpenGL framework. - if (cCompareFileName(baseName, "gltypes.h") - || cStringStartsWith(cFileName, "/usr/include/_types") - || cStringStartsWith(cFileName, "/usr/include/_types") - || cStringStartsWith(cFileName, "/usr/include/sys/_types")) { - return true; - } -#endif // Q_OS_MACOS - if (baseName) { - for (const auto &systemInclude : m_systemIncludes) { - if (systemInclude == baseName) - return true; + + switch (clang::platform()) { + case Platform::Unix: + if (fileName == u"/usr/include/stdlib.h" + || baseName == u"types.h" + || baseName == u"stdint-intn.h" // int32_t + || baseName == u"stdint-uintn.h") { // uint32_t + return SpecialSystemHeader::Types; } + break; + case Platform::macOS: + // Parse the following system headers to get the correct typdefs for types like + // int32_t, which are used in the macOS implementation of OpenGL framework. + // They are installed under /Applications/Xcode.app/Contents/Developer/Platforms... + if (baseName == u"gltypes.h" + || fileName.contains(u"/usr/include/_types") + || fileName.contains(u"/usr/include/sys/_types")) { + return SpecialSystemHeader::Types; + } + break; + default: + break; } - for (const auto &systemIncludePath : m_systemIncludePaths) { - if (cStringStartsWith(cFileName, systemIncludePath)) - return true; + + // When building against system Qt (as it happens with yocto / Boot2Qt), the Qt headers are + // considered system headers by clang_Location_isInSystemHeader, and shiboken will not + // process them. We need to explicitly process them by checking against the list of + // include paths that were passed to shiboken's --force-process-system-include-paths option + // or specified via the <system-include> xml tag. + if (m_forceProcessSystemIncludes.contains(baseName)) + return SpecialSystemHeader::WhiteListed; + + if (std::any_of(m_forceProcessSystemIncludePaths.cbegin(), + m_forceProcessSystemIncludePaths.cend(), + [fileName](const QString &p) { return fileName.startsWith(p); })) { + return SpecialSystemHeader::WhiteListedPath; } - return false; + + return SpecialSystemHeader::None; } -bool Builder::visitLocation(const CXSourceLocation &location) const +bool Builder::visitLocation(const QString &fileName, LocationType locationType) const { - if (clang_Location_isInSystemHeader(location) == 0) - return true; - CXFile file; // void * - unsigned line; - unsigned column; - unsigned offset; - clang_getExpansionLocation(location, &file, &line, &column, &offset); - const CXString cxFileName = clang_getFileName(file); - // Has been observed to be 0 for invalid locations - bool result = false; - if (const char *cFileName = clang_getCString(cxFileName)) { - result = d->visitHeader(cFileName); - clang_disposeString(cxFileName); - } - return result; + return locationType != LocationType::System || d->visitHeader(fileName); } -void Builder::setSystemIncludes(const QByteArrayList &systemIncludes) +void Builder::setForceProcessSystemIncludes(const QStringList &systemIncludes) { for (const auto &i : systemIncludes) { - if (i.endsWith('/')) - d->m_systemIncludePaths.append(i); + QFileInfo fi(i); + if (fi.exists() && fi.isDir()) + d->m_forceProcessSystemIncludePaths.append(i); else - d->m_systemIncludes.append(i); + d->m_forceProcessSystemIncludes.append(i); } } @@ -910,14 +882,14 @@ FileModelItem Builder::dom() const Q_ASSERT(!d->m_scopeStack.isEmpty()); auto rootScope = d->m_scopeStack.constFirst(); rootScope->purgeClassDeclarations(); - return qSharedPointerDynamicCast<_FileModelItem>(rootScope); + return std::dynamic_pointer_cast<_FileModelItem>(rootScope); } static QString msgOutOfOrder(const CXCursor &cursor, const char *expectedScope) { - return getCursorKindName(cursor.kind) + QLatin1Char(' ') - + getCursorSpelling(cursor) + QLatin1String(" encountered outside ") - + QLatin1String(expectedScope) + QLatin1Char('.'); + return getCursorKindName(cursor.kind) + u' ' + + getCursorSpelling(cursor) + u" encountered outside "_s + + QLatin1StringView(expectedScope) + u'.'; } static CodeModel::ClassType codeModelClassTypeFromCursor(CXCursorKind kind) @@ -944,12 +916,16 @@ static NamespaceType namespaceType(const CXCursor &cursor) static QString enumType(const CXCursor &cursor) { QString name = getCursorSpelling(cursor); // "enum Foo { v1, v2 };" + if (name.contains(u"unnamed enum")) // Clang 16.0 + return {}; if (name.isEmpty()) { // PYSIDE-1228: For "typedef enum { v1, v2 } Foo;", type will return // "Foo" as expected. Care must be taken to exclude real anonymous enums. name = getTypeName(clang_getCursorType(cursor)); - if (name.contains(QLatin1String("(anonymous"))) + if (name.contains(u"(unnamed") // Clang 12.0.1 + || name.contains(u"(anonymous")) { // earlier name.clear(); + } } return name; } @@ -962,16 +938,16 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) break; case CXCursor_AnnotateAttr: { const QString annotation = getCursorSpelling(cursor); - if (annotation == QLatin1String("qt_slot")) + if (annotation == u"qt_slot") d->m_currentFunctionType = CodeModel::Slot; - else if (annotation == QLatin1String("qt_signal")) + else if (annotation == u"qt_signal") d->m_currentFunctionType = CodeModel::Signal; else d->m_currentFunctionType = CodeModel::Normal; } break; case CXCursor_CXXBaseSpecifier: - if (d->m_currentClass.isNull()) { + if (!d->m_currentClass) { const Diagnostic d(msgOutOfOrder(cursor, "class"), cursor, CXDiagnostic_Error); qWarning() << d; appendDiagnostic(d); @@ -993,15 +969,15 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) || !d->addClass(cursor, CodeModel::Class)) { return Skip; } - d->m_currentClass->setName(d->m_currentClass->name() + templateBrackets()); - d->m_scope.back() += templateBrackets(); + d->m_currentClass->setName(d->m_currentClass->name() + "<>"_L1); + d->m_scope.back() += "<>"_L1; break; case CXCursor_EnumDecl: { QString name = enumType(cursor); EnumKind kind = CEnum; if (name.isEmpty()) { kind = AnonymousEnum; - name = QStringLiteral("enum_") + QString::number(++d->m_anonymousEnumCount); + name = "enum_"_L1 + QString::number(++d->m_anonymousEnumCount); #if !CLANG_NO_ENUMDECL_ISSCOPED } else if (clang_EnumDecl_isScoped(cursor) != 0) { #else @@ -1010,17 +986,21 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) kind = EnumClass; } d->m_currentEnum.reset(new _EnumModelItem(d->m_model, name)); - d->setFileName(cursor, d->m_currentEnum.data()); + d->setFileName(cursor, d->m_currentEnum.get()); d->m_currentEnum->setScope(d->m_scope); d->m_currentEnum->setEnumKind(kind); - d->m_currentEnum->setSigned(isSigned(clang_getEnumDeclIntegerType(cursor).kind)); - if (!qSharedPointerDynamicCast<_ClassModelItem>(d->m_scopeStack.back()).isNull()) + if (clang_getCursorAvailability(cursor) == CXAvailability_Deprecated) + d->m_currentEnum->setDeprecated(true); + const auto enumType = fullyResolveType(clang_getEnumDeclIntegerType(cursor)); + d->m_currentEnum->setSigned(isSigned(enumType.kind)); + d->m_currentEnum->setUnderlyingType(getTypeName(enumType)); + if (std::dynamic_pointer_cast<_ClassModelItem>(d->m_scopeStack.back())) d->m_currentEnum->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor))); } break; case CXCursor_EnumConstantDecl: { const QString name = getCursorSpelling(cursor); - if (d->m_currentEnum.isNull()) { + if (!d->m_currentEnum) { const Diagnostic d(msgOutOfOrder(cursor, "enum"), cursor, CXDiagnostic_Error); qWarning() << d; appendDiagnostic(d); @@ -1031,9 +1011,11 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) enumValue.setValue(clang_getEnumConstantDeclValue(cursor)); else enumValue.setUnsignedValue(clang_getEnumConstantDeclUnsignedValue(cursor)); - EnumeratorModelItem enumConstant(new _EnumeratorModelItem(d->m_model, name)); + auto enumConstant = std::make_shared<_EnumeratorModelItem>(d->m_model, name); enumConstant->setStringValue(d->cursorValueExpression(this, cursor)); enumConstant->setValue(enumValue); + if (clang_getCursorAvailability(cursor) == CXAvailability_Deprecated) + enumConstant->setDeprecated(true); d->m_currentEnum->addEnumerator(enumConstant); } break; @@ -1077,6 +1059,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) } } d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, true); + d->setFileName(cursor, d->m_currentFunction.get()); d->m_scopeStack.back()->addFunction(d->m_currentFunction); break; case CXCursor_FunctionDecl: @@ -1084,13 +1067,14 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) // operators). Note: CXTranslationUnit_SkipFunctionBodies must be off for // clang_isCursorDefinition() to work here. if (!d->m_withinFriendDecl || clang_isCursorDefinition(cursor) != 0) { - int scope = d->m_scopeStack.size() - 1; // enclosing class + auto scope = d->m_scopeStack.size() - 1; // enclosing class if (d->m_withinFriendDecl) { // Friend declaration: go back to namespace or file scope. for (--scope; d->m_scopeStack.at(scope)->kind() == _CodeModelItem::Kind_Class; --scope) { } } d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, false); + d->m_currentFunction->setHiddenFriend(d->m_withinFriendDecl); d->m_scopeStack.at(scope)->addFunction(d->m_currentFunction); } break; @@ -1099,10 +1083,10 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) if (type == NamespaceType::Anonymous) return Skip; const QString name = getCursorSpelling(cursor); - const NamespaceModelItem parentNamespaceItem = qSharedPointerDynamicCast<_NamespaceModelItem>(d->m_scopeStack.back()); - if (parentNamespaceItem.isNull()) { + const auto parentNamespaceItem = std::dynamic_pointer_cast<_NamespaceModelItem>(d->m_scopeStack.back()); + if (!parentNamespaceItem) { const QString message = msgOutOfOrder(cursor, "namespace") - + QLatin1String(" (current scope: ") + d->m_scopeStack.back()->name() + QLatin1Char(')'); + + u" (current scope: "_s + d->m_scopeStack.back()->name() + u')'; const Diagnostic d(message, cursor, CXDiagnostic_Error); qWarning() << d; appendDiagnostic(d); @@ -1112,7 +1096,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) // in subsequent modules. NamespaceModelItem namespaceItem = parentNamespaceItem->findNamespace(name); namespaceItem.reset(new _NamespaceModelItem(d->m_model, name)); - d->setFileName(cursor, namespaceItem.data()); + d->setFileName(cursor, namespaceItem.get()); namespaceItem->setScope(d->m_scope); namespaceItem->setType(type); parentNamespaceItem->addNamespace(namespaceItem); @@ -1122,10 +1106,12 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) case CXCursor_ParmDecl: // Skip in case of nested CXCursor_ParmDecls in case one parameter is a function pointer // and function pointer typedefs. - if (d->m_currentArgument.isNull() && !d->m_currentFunction.isNull()) { + if (!d->m_currentArgument && d->m_currentFunction) { const QString name = getCursorSpelling(cursor); d->m_currentArgument.reset(new _ArgumentModelItem(d->m_model, name)); - d->m_currentArgument->setType(d->createTypeInfo(cursor)); + const auto type = clang_getCursorType(cursor); + d->m_currentArgument->setScopeResolution(hasScopeResolution(type)); + d->m_currentArgument->setType(d->createTypeInfo(type)); d->m_currentFunction->addArgument(d->m_currentArgument); QString defaultValueExpression = d->cursorValueExpression(this, cursor); if (!defaultValueExpression.isEmpty()) { @@ -1141,16 +1127,16 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) const TemplateParameterModelItem tItem = cursor.kind == CXCursor_TemplateTemplateParameter ? d->createTemplateParameter(cursor) : d->createNonTypeTemplateParameter(cursor); // Apply to function/member template? - if (!d->m_currentFunction.isNull()) { + if (d->m_currentFunction) { d->m_currentFunction->setTemplateParameters(d->m_currentFunction->templateParameters() << tItem); - } else if (!d->m_currentTemplateTypeAlias.isNull()) { + } else if (d->m_currentTemplateTypeAlias) { d->m_currentTemplateTypeAlias->addTemplateParameter(tItem); - } else if (!d->m_currentClass.isNull()) { // Apply to class + } else if (d->m_currentClass) { // Apply to class const QString &tplParmName = tItem->name(); if (Q_UNLIKELY(!insertTemplateParameterIntoClassName(tplParmName, d->m_currentClass) || !insertTemplateParameterIntoClassName(tplParmName, &d->m_scope.back()))) { - const QString message = QStringLiteral("Error inserting template parameter \"") + tplParmName - + QStringLiteral("\" into ") + d->m_currentClass->name(); + const QString message = "Error inserting template parameter \""_L1 + tplParmName + + "\" into "_L1 + d->m_currentClass->name(); const Diagnostic d(message, cursor, CXDiagnostic_Error); qWarning() << d; appendDiagnostic(d); @@ -1164,7 +1150,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) d->startTemplateTypeAlias(cursor); break; case CXCursor_TypeAliasDecl: // May contain nested CXCursor_TemplateTypeParameter - if (d->m_currentTemplateTypeAlias.isNull()) { + if (!d->m_currentTemplateTypeAlias) { const CXType type = clang_getCanonicalType(clang_getCursorType(cursor)); if (type.kind > CXType_Unexposed) d->addTypeDef(cursor, type); @@ -1192,31 +1178,23 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) d->m_usingTypeRef = getCursorSpelling(cursor); break; case CXCursor_TypeRef: - if (!d->m_currentFunction.isNull()) { - if (d->m_currentArgument.isNull()) - d->qualifyTypeDef(cursor, d->m_currentFunction); // return type - else - d->qualifyTypeDef(cursor, d->m_currentArgument); - } else if (!d->m_currentField.isNull()) { - d->qualifyTypeDef(cursor, d->m_currentField); - } else if (d->m_withinUsingDeclaration && d->m_usingTypeRef.isEmpty()) { - d->m_usingTypeRef = d->getBaseClassName(clang_getCursorType(cursor)); - } + if (d->m_withinUsingDeclaration && d->m_usingTypeRef.isEmpty()) + d->m_usingTypeRef = d->getBaseClass(clang_getCursorType(cursor)).first; break; case CXCursor_CXXFinalAttr: - if (!d->m_currentFunction.isNull()) - d->m_currentFunction->setFinal(true); - else if (!d->m_currentClass.isNull()) + if (d->m_currentFunction) + d->m_currentFunction->setAttribute(FunctionAttribute::Final); + else if (d->m_currentClass) d->m_currentClass->setFinal(true); break; case CXCursor_CXXOverrideAttr: - if (!d->m_currentFunction.isNull()) - d->m_currentFunction->setOverride(true); + if (d->m_currentFunction) + d->m_currentFunction->setAttribute(FunctionAttribute::Override); break; case CXCursor_StaticAssert: // Check for Q_PROPERTY() (see PySide6/global.h.in for an explanation // how it is defined, and qdoc). - if (clang_isDeclaration(cursor.kind) && !d->m_currentClass.isNull()) { + if (clang_isDeclaration(cursor.kind) && d->m_currentClass) { auto snippet = getCodeSnippet(cursor); const auto length = snippet.size(); if (length > 12 && *snippet.rbegin() == ')' @@ -1228,7 +1206,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) break; // UsingDeclaration: consists of a TypeRef (base) and OverloadedDeclRef (member name) case CXCursor_UsingDeclaration: - if (!d->m_currentClass.isNull()) + if (d->m_currentClass) d->m_withinUsingDeclaration = true; break; case CXCursor_OverloadedDeclRef: @@ -1256,53 +1234,51 @@ bool Builder::endToken(const CXCursor &cursor) case CXCursor_ClassTemplatePartialSpecialization: d->popScope(); // Continue in outer class after leaving inner class? - if (ClassModelItem lastClass = qSharedPointerDynamicCast<_ClassModelItem>(d->m_scopeStack.back())) + if (auto lastClass = std::dynamic_pointer_cast<_ClassModelItem>(d->m_scopeStack.back())) d->m_currentClass = lastClass; else - d->m_currentClass.clear(); + d->m_currentClass.reset(); d->m_currentFunctionType = CodeModel::Normal; break; case CXCursor_EnumDecl: - // Add enum only if values were encountered, otherwise assume it - // is a forward declaration of an enum class. - if (!d->m_currentEnum.isNull() && d->m_currentEnum->hasValues()) + if (d->m_currentEnum) d->m_scopeStack.back()->addEnum(d->m_currentEnum); - d->m_currentEnum.clear(); + d->m_currentEnum.reset(); break; case CXCursor_FriendDecl: d->m_withinFriendDecl = false; break; case CXCursor_VarDecl: case CXCursor_FieldDecl: - d->m_currentField.clear(); + d->m_currentField.reset(); break; case CXCursor_Constructor: d->qualifyConstructor(cursor); - if (!d->m_currentFunction.isNull()) { + if (d->m_currentFunction) { d->m_currentFunction->_determineType(); - d->m_currentFunction.clear(); + d->m_currentFunction.reset(); } break; case CXCursor_Destructor: case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: - if (!d->m_currentFunction.isNull()) { + if (d->m_currentFunction) { d->m_currentFunction->_determineType(); - d->m_currentFunction.clear(); + d->m_currentFunction.reset(); } break; case CXCursor_ConversionFunction: - if (!d->m_currentFunction.isNull()) { + if (d->m_currentFunction) { d->m_currentFunction->setFunctionType(CodeModel::ConversionOperator); - d->m_currentFunction.clear(); + d->m_currentFunction.reset(); } break; case CXCursor_Namespace: d->popScope(); break; case CXCursor_ParmDecl: - d->m_currentArgument.clear(); + d->m_currentArgument.reset(); break; case CXCursor_TypeAliasTemplateDecl: d->m_currentTemplateTypeAlias.reset(); diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.h b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.h index dc37dff0f..b2ec6d304 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.h +++ b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CLANGBUILDER_H #define CLANGBUILDER_H @@ -39,14 +14,14 @@ class BuilderPrivate; class Builder : public BaseVisitor { public: - Q_DISABLE_COPY(Builder) + Q_DISABLE_COPY_MOVE(Builder) Builder(); ~Builder(); - void setSystemIncludes(const QByteArrayList &systemIncludes); + void setForceProcessSystemIncludes(const QStringList &systemIncludes); - bool visitLocation(const CXSourceLocation &location) const override; + bool visitLocation(const QString &fileName, LocationType locationType) const override; StartTokenResult startToken(const CXCursor &cursor) override; bool endToken(const CXCursor &cursor) override; diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.cpp index 7123c22d8..3c002da9c 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "clangdebugutils.h" #include "clangutils.h" @@ -32,8 +7,6 @@ #include <QtCore/QDebug> #include <QtCore/QString> -#include <string.h> - #ifndef QT_NO_DEBUG_STREAM #ifdef Q_OS_WIN @@ -44,7 +17,7 @@ const char pathSep = '/'; static const char *baseName(const char *fileName) { - const char *b = strrchr(fileName, pathSep); + const char *b = std::strrchr(fileName, pathSep); return b ? b + 1 : fileName; } @@ -74,59 +47,99 @@ QDebug operator<<(QDebug s, CX_CXXAccessSpecifier ac) return s; } -QDebug operator<<(QDebug s, const CXType &t) +struct formatCXTypeName +{ + explicit formatCXTypeName(const CXType &type) : m_type(type) {} + + const CXType &m_type; +}; + +QDebug operator<<(QDebug debug, const formatCXTypeName &ft) { - CXString typeSpelling = clang_getTypeSpelling(t); - s << typeSpelling; + CXString typeSpelling = clang_getTypeSpelling(ft.m_type); + debug << typeSpelling; clang_disposeString(typeSpelling); - return s; + return debug; } -QDebug operator<<(QDebug s, const CXCursor &cursor) +QDebug operator<<(QDebug debug, const CXType &type) { - QDebugStateSaver saver(s); - s.nospace(); - s.noquote(); + QDebugStateSaver saver(debug); + debug.nospace(); + debug.noquote(); + debug << "CXType("; + if (type.kind == CXType_Invalid) { + debug << "invalid)"; + return debug; + } + + debug << type.kind; + switch (type.kind) { + case CXType_Unexposed: + debug << " [unexposed]"; + break; + case CXType_Elaborated: + debug << " [elaborated]"; + break; + default: + break; + } + debug << ", " << formatCXTypeName(type) << ')'; + return debug; +} + +QDebug operator<<(QDebug debug, const CXCursor &cursor) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + debug.noquote(); const CXCursorKind kind = clang_getCursorKind(cursor); - s << kind; - if (kind >= CXCursor_FirstInvalid && kind <= CXCursor_LastInvalid) - return s; + debug << "CXCursor("; + if (kind >= CXCursor_FirstInvalid && kind <= CXCursor_LastInvalid) { + debug << "invalid)"; + return debug; + } + + const QString cursorSpelling = clang::getCursorSpelling(cursor); + debug << '"' << cursorSpelling << '"'; + CXString cursorDisplay = clang_getCursorDisplayName(cursor); + if (const char *dpy = clang_getCString(cursorDisplay)) { + const QString display = QString::fromUtf8(dpy); + if (display != cursorSpelling) + debug << ", display=\"" << dpy << '"'; + } + clang_disposeString(cursorDisplay); + + debug << ", kind=" << kind; + const CXType type = clang_getCursorType(cursor); switch (kind) { case CXCursor_CXXAccessSpecifier: - s << ' ' << clang_getCXXAccessSpecifier(cursor); + debug << ", " << clang_getCXXAccessSpecifier(cursor); break; case CXCursor_CXXBaseSpecifier: - s << ", inherits=\"" << clang::getCursorSpelling(clang_getTypeDeclaration(type)) << '"'; + debug << ", inherits=\"" << clang::getCursorSpelling(clang_getTypeDeclaration(type)) << '"'; break; case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_ConversionFunction: - s << ", result type=\"" << clang_getCursorResultType(cursor) << '"'; + debug << ", result type=\"" + << formatCXTypeName(clang_getCursorResultType(cursor)) << '"'; break; case CXCursor_TypedefDecl: - s << ", underlyingType=\"" << clang_getTypedefDeclUnderlyingType(cursor) << '"'; + debug << ", underlyingType=\"" + << formatCXTypeName(clang_getTypedefDeclUnderlyingType(cursor)) << '"'; break; default: break; } - if (type.kind != CXType_Invalid) - s << ", type=\"" << type << '"'; + debug << ", type=\"" << formatCXTypeName(type) << '"'; if (clang_Cursor_hasAttrs(cursor)) - s << ", [attrs]"; + debug << ", [attrs]"; - const QString cursorSpelling = clang::getCursorSpelling(cursor); - if (!cursorSpelling.isEmpty()) - s << ", spelling=\"" << cursorSpelling << '"'; - CXString cursorDisplay = clang_getCursorDisplayName(cursor); - if (const char *dpy = clang_getCString(cursorDisplay)) { - const QString display = QString::fromUtf8(dpy); - if (display != cursorSpelling) - s << ", display=\"" << dpy << '"'; - } - clang_disposeString(cursorDisplay); - return s; + debug << ')'; + return debug; } QDebug operator<<(QDebug s, const CXSourceLocation &location) diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.h b/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.h index ae3840fb4..7aac8a575 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.h +++ b/sources/shiboken6/ApiExtractor/clangparser/clangdebugutils.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CLANGDEBUGUTILS_H #define CLANGDEBUGUTILS_H -#include <QtCore/QtGlobal> +#include <QtCore/qtclasshelpermacros.h> #include <clang-c/Index.h> diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp index 8cf35641b..da6930476 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/clangparser.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "clangparser.h" #include "clangutils.h" @@ -38,6 +13,8 @@ #include <QtCore/QScopedArrayPointer> #include <QtCore/QString> +using namespace Qt::StringLiterals; + namespace clang { QString SourceFileCache::getFileName(CXFile file) @@ -64,7 +41,7 @@ std::string_view SourceFileCache::getCodeSnippet(const CXCursor &cursor, if (range.first.file != range.second.file) { if (errorMessage) - *errorMessage = QStringLiteral("Range spans several files"); + *errorMessage = "Range spans several files"_L1; return std::string_view(empty, 0); } @@ -73,7 +50,7 @@ std::string_view SourceFileCache::getCodeSnippet(const CXCursor &cursor, const QString fileName = getFileName(range.first.file); if (fileName.isEmpty()) { if (errorMessage) - *errorMessage = QStringLiteral("Range has no file"); + *errorMessage = "Range has no file"_L1; return std::string_view(empty, 0); } QFile file(fileName); @@ -108,9 +85,9 @@ std::string_view SourceFileCache::getCodeSnippet(const CXCursor &cursor, BaseVisitor::BaseVisitor() = default; BaseVisitor::~BaseVisitor() = default; -bool BaseVisitor::visitLocation(const CXSourceLocation &location) const +bool BaseVisitor::visitLocation(const QString &, LocationType locationType) const { - return clang_Location_isFromMainFile(location) != 0; + return locationType != LocationType::System; } BaseVisitor::StartTokenResult BaseVisitor::cbHandleStartToken(const CXCursor &cursor) @@ -148,6 +125,34 @@ std::string_view BaseVisitor::getCodeSnippet(const CXCursor &cursor) return result; } +bool BaseVisitor::_handleVisitLocation(const CXSourceLocation &location) +{ + CXFile cxFile; // void * + unsigned line; + unsigned column; + unsigned offset; + clang_getExpansionLocation(location, &cxFile, &line, &column, &offset); + + if (cxFile == m_currentCxFile) // Same file? + return m_visitCurrent; + + const QString fileName = getFileName(cxFile); + + LocationType locationType = LocationType::Unknown; + if (!fileName.isEmpty()) { + if (clang_Location_isFromMainFile(location) != 0) + locationType = LocationType::Main; + else if (clang_Location_isInSystemHeader(location) != 0) + locationType = LocationType::System; + else + locationType = LocationType::Other; + } + + m_currentCxFile = cxFile; + m_visitCurrent = visitLocation(fileName, locationType); + return m_visitCurrent; +} + QString BaseVisitor::getCodeSnippetString(const CXCursor &cursor) { const std::string_view result = getCodeSnippet(cursor); @@ -162,7 +167,7 @@ static CXChildVisitResult auto *bv = reinterpret_cast<BaseVisitor *>(clientData); const CXSourceLocation location = clang_getCursorLocation(cursor); - if (!bv->visitLocation(location)) + if (!bv->_handleVisitLocation(location)) return CXChildVisit_Continue; const BaseVisitor::StartTokenResult startResult = bv->cbHandleStartToken(cursor); @@ -210,9 +215,9 @@ static QByteArray msgCreateTranslationUnit(const QByteArrayList &clangArgs, unsi { QByteArray result = "clang_parseTranslationUnit2(0x"; result += QByteArray::number(flags, 16); - const int count = clangArgs.size(); + const auto count = clangArgs.size(); result += ", cmd[" + QByteArray::number(count) + "]="; - for (int i = 0; i < count; ++i) { + for (qsizetype i = 0; i < count; ++i) { const QByteArray &arg = clangArgs.at(i); if (i) result += ' '; @@ -243,7 +248,9 @@ static CXTranslationUnit createTranslationUnit(CXIndex index, "-Wno-expansion-to-defined", // Workaround for warnings in Darwin stdlib, see // https://github.com/darlinghq/darling/issues/204 #endif - "-Wno-constant-logical-operand" + "-Wno-constant-logical-operand", + "-x", + "c++" // Treat .h as C++, not C }; QByteArrayList clangArgs; @@ -251,6 +258,7 @@ static CXTranslationUnit createTranslationUnit(CXIndex index, clangArgs += emulatedCompilerOptions(); clangArgs += defaultArgs; } + clangArgs += detectVulkan(); clangArgs += args; QScopedArrayPointer<const char *> argv(byteArrayListToFlatArgV(clangArgs)); qDebug().noquote().nospace() << msgCreateTranslationUnit(clangArgs, flags); @@ -302,7 +310,7 @@ bool parse(const QByteArrayList &clangArgs, bool addCompilerSupportArguments, debug.nospace(); debug << "Errors in " << QDir::toNativeSeparators(QFile::decodeName(clangArgs.constLast())) << ":\n"; - for (const Diagnostic &diagnostic : qAsConst(diagnostics)) + for (const Diagnostic &diagnostic : std::as_const(diagnostics)) debug << diagnostic << '\n'; } diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangparser.h b/sources/shiboken6/ApiExtractor/clangparser/clangparser.h index d95ada602..4a46248e4 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangparser.h +++ b/sources/shiboken6/ApiExtractor/clangparser/clangparser.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CLANGPARSER_H #define CLANGPARSER_H @@ -33,11 +8,11 @@ #include <QtCore/QByteArrayList> #include <QtCore/QHash> -#include <QtCore/QPair> #include <QtCore/QString> #include <QtCore/QList> #include <string_view> +#include <utility> namespace clang { @@ -56,8 +31,16 @@ private: FileNameCache m_fileNameCache; }; +enum class LocationType +{ + Main, // Main header parsed for bindings + Other, // A header parsed for bindings + System, // A system header + Unknown // Clang internal +}; + class BaseVisitor { - Q_DISABLE_COPY(BaseVisitor) + Q_DISABLE_COPY_MOVE(BaseVisitor) public: using Diagnostics = QList<Diagnostic>; @@ -68,7 +51,7 @@ public: // Whether location should be visited. // defaults to clang_Location_isFromMainFile() - virtual bool visitLocation(const CXSourceLocation &location) const; + virtual bool visitLocation(const QString &fileName, LocationType locationType) const; virtual StartTokenResult startToken(const CXCursor &cursor) = 0; virtual bool endToken(const CXCursor &cursor) = 0; @@ -84,9 +67,14 @@ public: void setDiagnostics(const Diagnostics &d); void appendDiagnostic(const Diagnostic &d); + // For usage by the parser + bool _handleVisitLocation( const CXSourceLocation &location); + private: SourceFileCache m_fileCache; Diagnostics m_diagnostics; + CXFile m_currentCxFile{}; + bool m_visitCurrent = true; }; bool parse(const QByteArrayList &clangArgs, diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangutils.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangutils.cpp index c7d471547..1651e09ec 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangutils.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/clangutils.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "clangutils.h" @@ -33,38 +8,33 @@ #include <QtCore/QHashFunctions> #include <QtCore/QProcess> -bool operator==(const CXCursor &c1, const CXCursor &c2) +#include <string_view> + +bool operator==(const CXCursor &c1, const CXCursor &c2) noexcept { return c1.kind == c2.kind && c1.xdata == c2.xdata && std::equal(c1.data, c1.data + sizeof(c1.data) / sizeof(c1.data[0]), c2.data); } -size_t qHash(const CXCursor &c, size_t seed) +size_t qHash(const CXCursor &c, size_t seed) noexcept { - return qHash(c.kind) ^ qHash(c.xdata) ^ qHash(c.data[0]) - ^ qHash(c.data[1]) ^ qHash(c.data[2]) ^ seed; + return qHashMulti(seed, c.kind, c.xdata, c.data[0], c.data[1], c.data[2]); } -bool operator==(const CXType &t1, const CXType &t2) +bool operator==(const CXType &t1, const CXType &t2) noexcept { return t1.kind == t2.kind && t1.data[0] == t2.data[0] && t1.data[1] == t2.data[1]; } -size_t qHash(const CXType &ct, size_t seed) +size_t qHash(const CXType &ct, size_t seed) noexcept { - return size_t(ct.kind) ^ size_t(0xFFFFFFFF & quintptr(ct.data[0])) - ^ size_t(0xFFFFFFFF & quintptr(ct.data[1])) ^ seed; + return qHashMulti(seed, ct.kind, ct.data[0], ct.data[1]); } namespace clang { -bool SourceLocation::equals(const SourceLocation &rhs) const -{ - return file == rhs.file && offset == rhs.offset; -} - SourceLocation getExpansionLocation(const CXSourceLocation &location) { SourceLocation result; @@ -102,8 +72,8 @@ CXString getFileNameFromLocation(const CXSourceLocation &location) SourceRange getCursorRange(const CXCursor &cursor) { const CXSourceRange extent = clang_getCursorExtent(cursor); - return qMakePair(getExpansionLocation(clang_getRangeStart(extent)), - getExpansionLocation(clang_getRangeEnd(extent))); + return std::make_pair(getExpansionLocation(clang_getRangeStart(extent)), + getExpansionLocation(clang_getRangeEnd(extent))); } QString getCursorKindName(CXCursorKind cursorKind) @@ -130,6 +100,43 @@ QString getCursorDisplayName(const CXCursor &cursor) return result; } +static inline bool isBuiltinType(CXTypeKind kind) +{ + return kind >= CXType_FirstBuiltin && kind <= CXType_LastBuiltin; +} + +// Resolve elaborated types occurring with clang 16 +static CXType resolveElaboratedType(const CXType &type) +{ + if (!isBuiltinType(type.kind)) { + CXCursor decl = clang_getTypeDeclaration(type); + auto resolvedType = clang_getCursorType(decl); + if (resolvedType.kind != CXType_Invalid && resolvedType.kind != type.kind) + return resolvedType; + } + return type; +} + +// Resolve typedefs +static CXType resolveTypedef(const CXType &type) +{ + auto result = type; + while (result.kind == CXType_Typedef) { + auto decl = clang_getTypeDeclaration(result); + auto resolved = clang_getTypedefDeclUnderlyingType(decl); + if (resolved.kind == CXType_Invalid) + break; + result = resolved; + } + return result; +} + +// Fully resolve a type from elaborated & typedefs +CXType fullyResolveType(const CXType &type) +{ + return resolveTypedef(resolveElaboratedType(type)); +} + QString getTypeName(const CXType &type) { CXString typeSpelling = clang_getTypeSpelling(type); @@ -138,6 +145,23 @@ QString getTypeName(const CXType &type) return result; } +// Quick check for "::Type" +bool hasScopeResolution(const CXType &type) +{ + CXString typeSpelling = clang_getTypeSpelling(type); + std::string_view spelling = clang_getCString(typeSpelling); + const bool result = spelling.compare(0, 2, "::") == 0 + || spelling.find(" ::") != std::string::npos; + clang_disposeString(typeSpelling); + return result; +} + +// Resolve elaborated types occurring with clang 16 +QString getResolvedTypeName(const CXType &type) +{ + return getTypeName(resolveElaboratedType(type)); +} + Diagnostic::Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s) : message(m), source(Other), severity(s) { @@ -191,16 +215,17 @@ QList<Diagnostic> getDiagnostics(CXTranslationUnit tu) return result; } -QPair<int, int> parseTemplateArgumentList(const QString &l, - const TemplateArgumentHandler &handler, - int from) +std::pair<qsizetype, qsizetype> + parseTemplateArgumentList(const QString &l, + const TemplateArgumentHandler &handler, + qsizetype from) { - const int ltPos = l.indexOf(QLatin1Char('<'), from); + const auto ltPos = l.indexOf(u'<', from); if (ltPos == - 1) - return qMakePair(-1, -1); - int startPos = ltPos + 1; + return std::make_pair(-1, -1); + auto startPos = ltPos + 1; int level = 1; - for (int p = startPos, end = l.size(); p < end; ) { + for (qsizetype p = startPos, end = l.size(); p < end; ) { const char c = l.at(p).toLatin1(); switch (c) { case ',': @@ -209,9 +234,9 @@ QPair<int, int> parseTemplateArgumentList(const QString &l, ++p; if (c == '>') { if (--level == 0) - return qMakePair(ltPos, p); + return std::make_pair(ltPos, p); // Skip over next ',': "a<b<c,d>,e>" - for (; p < end && (l.at(p).isSpace() || l.at(p) == QLatin1Char(',')); ++p) {} + for (; p < end && (l.at(p).isSpace() || l.at(p) == u','); ++p) {} } startPos = p; break; @@ -225,7 +250,7 @@ QPair<int, int> parseTemplateArgumentList(const QString &l, break; } } - return qMakePair(-1, -1); + return std::make_pair(-1, -1); } CXDiagnosticSeverity maxSeverity(const QList<Diagnostic> &ds) @@ -281,9 +306,9 @@ QDebug operator<<(QDebug s, const Diagnostic &d) if (d.source != Diagnostic::Clang) s << " [other]"; - if (const int childMessagesCount = d.childMessages.size()) { + if (const auto childMessagesCount = d.childMessages.size()) { s << '\n'; - for (int i = 0; i < childMessagesCount; ++i) + for (qsizetype i = 0; i < childMessagesCount; ++i) s << " " << d.childMessages.at(i) << '\n'; } diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangutils.h b/sources/shiboken6/ApiExtractor/clangparser/clangutils.h index 4fcc833b1..fbbf95f1b 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangutils.h +++ b/sources/shiboken6/ApiExtractor/clangparser/clangutils.h @@ -1,49 +1,25 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CLANGUTILS_H #define CLANGUTILS_H #include <clang-c/Index.h> -#include <QtCore/QPair> #include <QtCore/QString> #include <QtCore/QStringList> +#include <QtCore/QtCompare> #include <QtCore/QList> #include <functional> +#include <utility> QT_FORWARD_DECLARE_CLASS(QDebug) -bool operator==(const CXCursor &c1, const CXCursor &c2); -size_t qHash(const CXCursor &c, size_t seed = 0); +bool operator==(const CXCursor &c1, const CXCursor &c2) noexcept; +size_t qHash(const CXCursor &c, size_t seed = 0) noexcept; -bool operator==(const CXType &t1, const CXType &t2); -size_t qHash(const CXType &ct, size_t seed); +bool operator==(const CXType &t1, const CXType &t2) noexcept; +size_t qHash(const CXType &ct, size_t seed = 0) noexcept; namespace clang { @@ -51,6 +27,9 @@ QString getCursorKindName(CXCursorKind cursorKind); QString getCursorSpelling(const CXCursor &cursor); QString getCursorDisplayName(const CXCursor &cursor); QString getTypeName(const CXType &type); +bool hasScopeResolution(const CXType &type); +CXType fullyResolveType(const CXType &type); +QString getResolvedTypeName(const CXType &type); inline QString getCursorTypeName(const CXCursor &cursor) { return getTypeName(clang_getCursorType(cursor)); } inline QString getCursorResultTypeName(const CXCursor &cursor) @@ -71,17 +50,18 @@ struct SourceLocation unsigned line = 0; unsigned column = 0; unsigned offset = 0; -}; - -inline bool operator==(const SourceLocation &l1, const SourceLocation &l2) -{ return l1.equals(l2); } -inline bool operator!=(const SourceLocation &l1, const SourceLocation &l2) -{ return !l1.equals(l2); } + friend constexpr bool comparesEqual(const SourceLocation &lhs, + const SourceLocation &rhs) noexcept + { + return lhs.file == rhs.file && lhs.offset == rhs.offset; + } + Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(SourceLocation) +}; SourceLocation getExpansionLocation(const CXSourceLocation &location); -using SourceRange =QPair<SourceLocation, SourceLocation>; +using SourceRange = std::pair<SourceLocation, SourceLocation>; SourceLocation getCursorLocation(const CXCursor &cursor); CXString getFileNameFromLocation(const CXSourceLocation &location); @@ -114,9 +94,10 @@ CXDiagnosticSeverity maxSeverity(const QList<Diagnostic> &ds); // with each match (level and string). Return begin and end of the list. using TemplateArgumentHandler = std::function<void (int, QStringView)>; -QPair<int, int> parseTemplateArgumentList(const QString &l, - const TemplateArgumentHandler &handler, - int from = 0); +std::pair<qsizetype, qsizetype> + parseTemplateArgumentList(const QString &l, + const TemplateArgumentHandler &handler, + qsizetype from = 0); #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug, const SourceLocation &); diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp index 7631916fb..4c13b141f 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp @@ -1,36 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "compilersupport.h" #include "header_paths.h" +#include "clangutils.h" #include <reporthandler.h> +#include "qtcompat.h" + #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFile> @@ -42,10 +20,11 @@ #include <clang-c/Index.h> -#include <string.h> #include <algorithm> #include <iterator> +using namespace Qt::StringLiterals; + namespace clang { QVersionNumber libClangVersion() @@ -53,6 +32,74 @@ QVersionNumber libClangVersion() return QVersionNumber(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR); } +static Compiler _compiler = +#if defined (Q_CC_CLANG) + Compiler::Clang; +#elif defined (Q_CC_MSVC) + Compiler::Msvc; +#else + Compiler::Gpp; +#endif + +Compiler compiler() { return _compiler; } + +bool setCompiler(const QString &name) +{ + bool result = true; + if (name == u"msvc") + _compiler = Compiler::Msvc; + else if (name == u"g++") + _compiler = Compiler::Gpp; + else if (name == u"clang") + _compiler = Compiler::Clang; + else + result = false; + return result; +} + +QString _compilerPath; // Pre-defined compiler path (from command line) + +const QString &compilerPath() +{ + return _compilerPath; +} + +void setCompilerPath(const QString &name) +{ + _compilerPath = name; +} + +static Platform _platform = +#if defined (Q_OS_DARWIN) + Platform::macOS; +#elif defined (Q_OS_WIN) + Platform::Windows; +#else + Platform::Unix; +#endif + +Platform platform() { return _platform; } + +bool setPlatform(const QString &name) +{ + bool result = true; + if (name == u"windows") + _platform = Platform::Windows; + else if (name == u"darwin") + _platform = Platform::macOS; + else if (name == u"unix") + _platform = Platform::Unix; + else + result = false; + return result; +} + +// 3/2024: Use a recent MSVC2022 for libclang 18.X +static QByteArray msvcCompatVersion() +{ + return libClangVersion() >= QVersionNumber(0, 64) ? "19.39"_ba : "19.26"_ba; +} + static bool runProcess(const QString &program, const QStringList &arguments, QByteArray *stdOutIn = nullptr, QByteArray *stdErrIn = nullptr) { @@ -91,11 +138,8 @@ static bool runProcess(const QString &program, const QStringList &arguments, return true; } -#if defined(Q_CC_GNU) - static QByteArray frameworkPath() { return QByteArrayLiteral(" (framework directory)"); } -# if defined(Q_OS_MACOS) static void filterHomebrewHeaderPaths(HeaderPaths &headerPaths) { QByteArray homebrewPrefix = qgetenv("HOMEBREW_OPT"); @@ -123,7 +167,6 @@ static void filterHomebrewHeaderPaths(HeaderPaths &headerPaths) } } } -# endif // Determine g++'s internal include paths from the output of // g++ -E -x c++ - -v </dev/null @@ -135,15 +178,20 @@ static void filterHomebrewHeaderPaths(HeaderPaths &headerPaths) static HeaderPaths gppInternalIncludePaths(const QString &compiler) { HeaderPaths result; - QStringList arguments; - arguments << QStringLiteral("-E") << QStringLiteral("-x") << QStringLiteral("c++") - << QStringLiteral("-") << QStringLiteral("-v"); + QStringList arguments{u"-E"_s, u"-x"_s, u"c++"_s, u"-"_s, u"-v"_s}; QByteArray stdOut; QByteArray stdErr; if (!runProcess(compiler, arguments, &stdOut, &stdErr)) return result; const QByteArrayList stdErrLines = stdErr.split('\n'); bool isIncludeDir = false; + + if (ReportHandler::isDebug(ReportHandler::MediumDebug)) + qCInfo(lcShiboken()).noquote().nospace() + << "gppInternalIncludePaths:\n compiler: " << compiler + << "\n stdOut: " << stdOut + << "\n stdErr: " << stdErr; + for (const QByteArray &line : stdErrLines) { if (isIncludeDir) { if (line.startsWith(QByteArrayLiteral("End of search list"))) { @@ -161,60 +209,27 @@ static HeaderPaths gppInternalIncludePaths(const QString &compiler) } } -# if defined(Q_OS_MACOS) - filterHomebrewHeaderPaths(result); -# endif + if (platform() == Platform::macOS) + filterHomebrewHeaderPaths(result); + return result; } -#endif // Q_CC_MSVC // Detect Vulkan as supported from Qt 5.10 by checking the environment variables. -static void detectVulkan(HeaderPaths *headerPaths) +QByteArrayList detectVulkan() { static const char *vulkanVariables[] = {"VULKAN_SDK", "VK_SDK_PATH"}; for (const char *vulkanVariable : vulkanVariables) { if (qEnvironmentVariableIsSet(vulkanVariable)) { - const QByteArray path = qgetenv(vulkanVariable) + QByteArrayLiteral("/include"); - headerPaths->append(HeaderPath{path, HeaderType::System}); - break; + const auto option = QByteArrayLiteral("-isystem") + + qgetenv(vulkanVariable) + + QByteArrayLiteral("/include"); + return {option}; } } + return {}; } -#if defined(Q_CC_GNU) -enum class LinuxDistribution { RedHat, CentOs, Other }; - -static LinuxDistribution linuxDistribution() -{ - const QString &productType = QSysInfo::productType(); - if (productType == QLatin1String("rhel")) - return LinuxDistribution::RedHat; - if (productType.compare(QLatin1String("centos"), Qt::CaseInsensitive) == 0) - return LinuxDistribution::CentOs; - return LinuxDistribution::Other; -} - -static bool checkProductVersion(const QVersionNumber &minimum, - const QVersionNumber &excludedMaximum) -{ - const QVersionNumber osVersion = QVersionNumber::fromString(QSysInfo::productVersion()); - return osVersion.isNull() || (osVersion >= minimum && osVersion < excludedMaximum); -} - -static inline bool needsGppInternalHeaders() -{ - const LinuxDistribution distro = linuxDistribution(); - switch (distro) { - case LinuxDistribution::RedHat: - case LinuxDistribution::CentOs: - return checkProductVersion(QVersionNumber(6, 10), QVersionNumber(8)); - case LinuxDistribution::Other: - break; - } - return false; -} -#endif // Q_CC_GNU - // For MSVC, we set the MS compatibility version and let Clang figure out its own // options and include paths. // For the others, we pass "-nostdinc" since libclang tries to add it's own system @@ -222,9 +237,7 @@ static inline bool needsGppInternalHeaders() // which causes std types not being found and construct -I/-F options from the // include paths of the host compiler. -#ifdef Q_CC_CLANG static QByteArray noStandardIncludeOption() { return QByteArrayLiteral("-nostdinc"); } -#endif // The clang builtin includes directory is used to find the definitions for // intrinsic functions and builtin types. It is necessary to use the clang @@ -234,35 +247,40 @@ static QByteArray noStandardIncludeOption() { return QByteArrayLiteral("-nostdin // Besides g++/Linux, as of MSVC 19.28.29334, MSVC needs clang includes // due to PYSIDE-1433, LLVM-47099 -#if !defined(Q_OS_DARWIN) -# define NEED_CLANG_BUILTIN_INCLUDES 1 -#else -# define NEED_CLANG_BUILTIN_INCLUDES 0 -#endif -#if NEED_CLANG_BUILTIN_INCLUDES +static bool needsClangBuiltinIncludes() +{ + return platform() != Platform::macOS; +} + +static QString queryLlvmConfigDir(const QString &arg) +{ + static const QString llvmConfig = QStandardPaths::findExecutable(u"llvm-config"_s); + if (llvmConfig.isEmpty()) + return {}; + QByteArray stdOut; + if (!runProcess(llvmConfig, QStringList{arg}, &stdOut)) + return {}; + const QString path = QFile::decodeName(stdOut.trimmed()); + if (!QFileInfo::exists(path)) { + qWarning(R"(%s: "%s" as returned by llvm-config "%s" does not exist.)", + __FUNCTION__, qPrintable(QDir::toNativeSeparators(path)), qPrintable(arg)); + return {}; + } + return path; +} + static QString findClangLibDir() { for (const char *envVar : {"LLVM_INSTALL_DIR", "CLANG_INSTALL_DIR"}) { if (qEnvironmentVariableIsSet(envVar)) { - const QString path = QFile::decodeName(qgetenv(envVar)) + QLatin1String("/lib"); + const QString path = QFile::decodeName(qgetenv(envVar)) + u"/lib"_s; if (QFileInfo::exists(path)) return path; qWarning("%s: %s as pointed to by %s does not exist.", __FUNCTION__, qPrintable(path), envVar); } } - const QString llvmConfig = - QStandardPaths::findExecutable(QLatin1String("llvm-config")); - if (!llvmConfig.isEmpty()) { - QByteArray stdOut; - if (runProcess(llvmConfig, QStringList{QLatin1String("--libdir")}, &stdOut)) { - const QString path = QFile::decodeName(stdOut.trimmed()); - if (QFileInfo::exists(path)) - return path; - qWarning("%s: %s as returned by llvm-config does not exist.", __FUNCTION__, qPrintable(path)); - } - } - return QString(); + return queryLlvmConfigDir(u"--libdir"_s); } static QString findClangBuiltInIncludesDir() @@ -272,7 +290,7 @@ static QString findClangBuiltInIncludesDir() if (!clangPathLibDir.isEmpty()) { QString candidate; QVersionNumber lastVersionNumber(1, 0, 0); - const QString clangDirName = clangPathLibDir + QLatin1String("/clang"); + const QString clangDirName = clangPathLibDir + u"/clang"_s; QDir clangDir(clangDirName); const QFileInfoList versionDirs = clangDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); @@ -289,26 +307,46 @@ static QString findClangBuiltInIncludesDir() } } if (!candidate.isEmpty()) - return candidate + QStringLiteral("/include"); + return candidate + "/include"_L1; } - return QString(); + return queryLlvmConfigDir(u"--includedir"_s); } -#endif // NEED_CLANG_BUILTIN_INCLUDES -#if defined(Q_CC_CLANG) || defined(Q_CC_GNU) -static QString compilerFromCMake(const QString &defaultCompiler) +QString compilerFromCMake() { -// Added !defined(Q_OS_DARWIN) due to PYSIDE-1032 -# if defined(CMAKE_CXX_COMPILER) && !defined(Q_OS_DARWIN) - Q_UNUSED(defaultCompiler); +#ifdef CMAKE_CXX_COMPILER return QString::fromLocal8Bit(CMAKE_CXX_COMPILER); -# else - return defaultCompiler; -# endif +#else + return {}; +#endif +} + +// Return a compiler suitable for determining the internal include paths +static QString compilerFromCMake(const QString &defaultCompiler) +{ + if (!compilerPath().isEmpty()) + return compilerPath(); + // Exclude macOS since cmakeCompiler returns the full path instead of the + // /usr/bin/clang shim, which results in the default SDK sysroot path + // missing (PYSIDE-1032) + if (platform() == Platform::macOS) + return defaultCompiler; + QString cmakeCompiler = compilerFromCMake(); + if (cmakeCompiler.isEmpty()) + return defaultCompiler; + QFileInfo fi(cmakeCompiler); + // Should be absolute by default, but a user may specify -DCMAKE_CXX_COMPILER=cl.exe + if (fi.isRelative()) + return cmakeCompiler; + if (fi.exists()) + return fi.absoluteFilePath(); + // The compiler may not exist in case something like icecream or + // a non-standard-path was used on the build machine. Check + // the executable. + cmakeCompiler = QStandardPaths::findExecutable(fi.fileName()); + return cmakeCompiler.isEmpty() ? defaultCompiler : cmakeCompiler; } -#endif // Q_CC_CLANG, Q_CC_GNU -#if NEED_CLANG_BUILTIN_INCLUDES static void appendClangBuiltinIncludes(HeaderPaths *p) { const QString clangBuiltinIncludesDir = @@ -318,61 +356,48 @@ static void appendClangBuiltinIncludes(HeaderPaths *p) "(neither by checking the environment variables LLVM_INSTALL_DIR, CLANG_INSTALL_DIR " " nor running llvm-config). This may lead to parse errors."); } else { - qCInfo(lcShiboken, "CLANG builtins includes directory: %s", + qCInfo(lcShiboken, "CLANG v%d.%d, builtins includes directory: %s", + CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR, qPrintable(clangBuiltinIncludesDir)); p->append(HeaderPath{QFile::encodeName(clangBuiltinIncludesDir), HeaderType::System}); } } -#endif // NEED_CLANG_BUILTIN_INCLUDES // Returns clang options needed for emulating the host compiler QByteArrayList emulatedCompilerOptions() { -#if defined(Q_CC_GNU) - // Needed to silence a warning, but needsGppInternalHeaders is used below. - // This seems to be a compiler bug on macOS. - Q_UNUSED(needsGppInternalHeaders); -#endif QByteArrayList result; -#if defined(Q_CC_MSVC) - HeaderPaths headerPaths; - result.append(QByteArrayLiteral("-fms-compatibility-version=19.26.28806")); - result.append(QByteArrayLiteral("-fdelayed-template-parsing")); - result.append(QByteArrayLiteral("-Wno-microsoft-enum-value")); - // Fix yvals_core.h: STL1000: Unexpected compiler version, expected Clang 7 or newer (MSVC2017 update) - result.append(QByteArrayLiteral("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH")); -# if NEED_CLANG_BUILTIN_INCLUDES - appendClangBuiltinIncludes(&headerPaths); -# endif // NEED_CLANG_BUILTIN_INCLUDES - -#elif defined(Q_CC_CLANG) - HeaderPaths headerPaths = gppInternalIncludePaths(compilerFromCMake(QStringLiteral("clang++"))); - result.append(noStandardIncludeOption()); -#elif defined(Q_CC_GNU) HeaderPaths headerPaths; + switch (compiler()) { + case Compiler::Msvc: + result.append("-fms-compatibility-version="_ba + msvcCompatVersion()); + result.append(QByteArrayLiteral("-fdelayed-template-parsing")); + result.append(QByteArrayLiteral("-Wno-microsoft-enum-value")); + result.append("/Zc:__cplusplus"_ba); + // Fix yvals_core.h: STL1000: Unexpected compiler version, expected Clang 7 or newer (MSVC2017 update) + result.append(QByteArrayLiteral("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH")); + if (needsClangBuiltinIncludes()) + appendClangBuiltinIncludes(&headerPaths); + break; + case Compiler::Clang: + headerPaths.append(gppInternalIncludePaths(compilerFromCMake(u"clang++"_s))); + result.append(noStandardIncludeOption()); + break; + case Compiler::Gpp: + if (needsClangBuiltinIncludes()) + appendClangBuiltinIncludes(&headerPaths); -# if NEED_CLANG_BUILTIN_INCLUDES - appendClangBuiltinIncludes(&headerPaths); -# endif // NEED_CLANG_BUILTIN_INCLUDES - - // Append the c++ include paths since Clang is unable to find <list> etc - // on RHEL 7 with g++ 6.3 or CentOS 7.2. - // A fix for this has been added to Clang 5.0, so, the code can be removed - // once Clang 5.0 is the minimum version. - if (needsGppInternalHeaders()) { - const HeaderPaths gppPaths = gppInternalIncludePaths(compilerFromCMake(QStringLiteral("g++"))); + // Append the c++ include paths since Clang is unable to find + // <type_traits> etc (g++ 11.3). + const HeaderPaths gppPaths = gppInternalIncludePaths(compilerFromCMake(u"g++"_s)); for (const HeaderPath &h : gppPaths) { - if (h.path.contains("c++") - || h.path.contains("sysroot")) { // centOS + if (h.path.contains("c++") || h.path.contains("sysroot")) headerPaths.append(h); - } } + break; } -#else - HeaderPaths headerPaths; -#endif - detectVulkan(&headerPaths); + std::transform(headerPaths.cbegin(), headerPaths.cend(), std::back_inserter(result), HeaderPath::includeOption); return result; diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h index d9e213e73..462e8f205 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h +++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef COMPILERSUPPORT_H #define COMPILERSUPPORT_H @@ -32,6 +7,7 @@ #include <QtCore/QByteArrayList> QT_FORWARD_DECLARE_CLASS(QVersionNumber) +QT_FORWARD_DECLARE_CLASS(QString) enum class LanguageLevel { Default, @@ -42,6 +18,18 @@ enum class LanguageLevel { Cpp1Z }; +enum class Compiler { + Msvc, + Gpp, + Clang +}; + +enum class Platform { + Unix, + Windows, + macOS +}; + namespace clang { QVersionNumber libClangVersion(); @@ -50,6 +38,19 @@ LanguageLevel emulatedCompilerLanguageLevel(); const char *languageLevelOption(LanguageLevel l); LanguageLevel languageLevelFromOption(const char *); + +QByteArrayList detectVulkan(); + +Compiler compiler(); +bool setCompiler(const QString &name); + +QString compilerFromCMake(); + +const QString &compilerPath(); +void setCompilerPath(const QString &name); + +Platform platform(); +bool setPlatform(const QString &name); } // namespace clang #endif // COMPILERSUPPORT_H diff --git a/sources/shiboken6/ApiExtractor/classdocumentation.cpp b/sources/shiboken6/ApiExtractor/classdocumentation.cpp new file mode 100644 index 000000000..637e4a422 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/classdocumentation.cpp @@ -0,0 +1,381 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "classdocumentation.h" +#include "messages.h" +#include "debughelpers_p.h" + +#include <QtCore/QDebug> +#include <QtCore/QBuffer> +#include <QtCore/QFile> +#include <QtCore/QXmlStreamReader> +#include <QtCore/QXmlStreamAttributes> +#include <QtCore/QXmlStreamWriter> + +#include <algorithm> + +using namespace Qt::StringLiterals; + +// Sort functions by name and argument count +static bool functionDocumentationLessThan(const FunctionDocumentation &f1, + const FunctionDocumentation &f2) +{ + const int nc = f1.name.compare(f2.name); + if (nc != 0) + return nc < 0; + return f1.parameters.size() < f2.parameters.size(); +} + +static void sortDocumentation(ClassDocumentation *cd) +{ + std::stable_sort(cd->enums.begin(), cd->enums.end(), + [] (const EnumDocumentation &e1, const EnumDocumentation &e2) { + return e1.name < e2.name; }); + std::stable_sort(cd->properties.begin(), cd->properties.end(), + [] (const PropertyDocumentation &p1, const PropertyDocumentation &p2) { + return p1.name < p2.name; }); + std::stable_sort(cd->functions.begin(), cd->functions.end(), + functionDocumentationLessThan); +} + +qsizetype ClassDocumentation::indexOfEnum(const QString &name) const +{ + for (qsizetype i = 0, size = enums.size(); i < size; ++i) { + if (enums.at(i).name == name) + return i; + } + return -1; +} + +FunctionDocumentationList ClassDocumentation::findFunctionCandidates(const QString &name, + bool constant) const +{ + FunctionDocumentationList result; + std::copy_if(functions.cbegin(), functions.cend(), + std::back_inserter(result), + [name, constant](const FunctionDocumentation &fd) { + return fd.constant == constant && fd.name == name; + }); + return result; +} + +static bool matches(const FunctionDocumentation &fd, const FunctionDocumentationQuery &q) +{ + return fd.name == q.name && fd.constant == q.constant && fd.parameters == q.parameters; +} + +qsizetype ClassDocumentation::indexOfFunction(const FunctionDocumentationList &fl, + const FunctionDocumentationQuery &q) +{ + for (qsizetype i = 0, size = fl.size(); i < size; ++i) { + if (matches(fl.at(i), q)) + return i; + } + return -1; +} + +qsizetype ClassDocumentation::indexOfProperty(const QString &name) const +{ + for (qsizetype i = 0, size = properties.size(); i < size; ++i) { + if (properties.at(i).name == name) + return i; + } + return -1; +} + +enum class WebXmlCodeTag +{ + Class, Description, Enum, Function, Header, Parameter, Property, Typedef, Other +}; + +static WebXmlCodeTag tag(QStringView name) +{ + if (name == u"class" || name == u"namespace") + return WebXmlCodeTag::Class; + if (name == u"enum") + return WebXmlCodeTag::Enum; + if (name == u"function") + return WebXmlCodeTag::Function; + if (name == u"description") + return WebXmlCodeTag::Description; + if (name == u"header") + return WebXmlCodeTag::Header; + if (name == u"parameter") + return WebXmlCodeTag::Parameter; + if (name == u"property") + return WebXmlCodeTag::Property; + if (name == u"typedef") + return WebXmlCodeTag::Typedef; + return WebXmlCodeTag::Other; +} + +static void parseWebXmlElement(WebXmlCodeTag tag, const QXmlStreamAttributes &attributes, + ClassDocumentation *cd) +{ + switch (tag) { + case WebXmlCodeTag::Class: + cd->name = attributes.value(u"name"_s).toString(); + cd->type = ClassDocumentation::Class; + break; + case WebXmlCodeTag::Header: + cd->name = attributes.value(u"name"_s).toString(); + cd->type = ClassDocumentation::Header; + break; + case WebXmlCodeTag::Enum: { + EnumDocumentation ed; + ed.name = attributes.value(u"name"_s).toString(); + cd->enums.append(ed); + } + break; + case WebXmlCodeTag::Function: { + FunctionDocumentation fd; + fd.name = attributes.value(u"name"_s).toString(); + fd.signature = attributes.value(u"signature"_s).toString(); + fd.returnType = attributes.value(u"type"_s).toString(); + fd.constant = attributes.value(u"const"_s) == u"true"; + cd->functions.append(fd); + } + break; + case WebXmlCodeTag::Parameter: + Q_ASSERT(!cd->functions.isEmpty()); + cd->functions.last().parameters.append(attributes.value(u"type"_s).toString()); + break; + case WebXmlCodeTag::Property: { + PropertyDocumentation pd; + pd.name = attributes.value(u"name"_s).toString(); + pd.brief = attributes.value(u"brief"_s).toString(); + cd->properties.append(pd); + } + break; + default: + break; + } +} + +// Retrieve the contents of <description> +static QString extractWebXmlDescription(QXmlStreamReader &reader) +{ + QBuffer buffer; + buffer.open(QIODeviceBase::WriteOnly); + QXmlStreamWriter writer(&buffer); + + do { + switch (reader.tokenType()) { + case QXmlStreamReader::StartElement: + writer.writeStartElement(reader.name().toString()); + writer.writeAttributes(reader.attributes()); + break; + case QXmlStreamReader::Characters: + writer.writeCharacters(reader.text().toString()); + break; + case QXmlStreamReader::EndElement: + writer.writeEndElement(); + if (reader.name() == u"description") { + buffer.close(); + return QString::fromUtf8(buffer.buffer()).trimmed(); + } + break; + default: + break; + } + reader.readNext(); + } while (!reader.atEnd()); + + return {}; +} + +static QString msgXmlError(const QString &fileName, const QXmlStreamReader &reader) +{ + QString result; + QTextStream(&result) << fileName << ':' << reader.lineNumber() << ':' + << reader.columnNumber() << ':' << reader.errorString(); + return result; +} + +std::optional<ClassDocumentation> parseWebXml(const QString &fileName, QString *errorMessage) +{ + ClassDocumentation result; + + QFile file(fileName); + if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) { + *errorMessage = msgCannotOpenForReading(file); + return std::nullopt; + } + + WebXmlCodeTag lastTag = WebXmlCodeTag::Other; + QXmlStreamReader reader(&file); + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::StartElement: { + const auto currentTag = tag(reader.name()); + parseWebXmlElement(currentTag, reader.attributes(), &result); + switch (currentTag) { // Store relevant tags in lastTag + case WebXmlCodeTag::Class: + case WebXmlCodeTag::Function: + case WebXmlCodeTag::Enum: + case WebXmlCodeTag::Header: + case WebXmlCodeTag::Property: + case WebXmlCodeTag::Typedef: + lastTag = currentTag; + break; + case WebXmlCodeTag::Description: { // Append the description to the element + QString *target = nullptr; + switch (lastTag) { + case WebXmlCodeTag::Class: + target = &result.description; + break; + case WebXmlCodeTag::Function: + target = &result.functions.last().description; + break; + case WebXmlCodeTag::Enum: + target = &result.enums.last().description; + break; + case WebXmlCodeTag::Property: + target = &result.properties.last().description; + default: + break; + } + if (target != nullptr && target->isEmpty()) + *target = extractWebXmlDescription(reader); + } + break; + default: + break; + } + } + default: + break; + } + } + + if (reader.error() != QXmlStreamReader::NoError) { + *errorMessage= msgXmlError(fileName, reader); + return std::nullopt; + } + + sortDocumentation(&result); + return result; +} + +QString webXmlModuleDescription(const QString &fileName, QString *errorMessage) +{ + QFile file(fileName); + if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) { + *errorMessage = msgCannotOpenForReading(file); + return {}; + } + + QString result; + QXmlStreamReader reader(&file); + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::StartElement: + if (reader.name() == u"description") + result = extractWebXmlDescription(reader); + break; + default: + break; + } + } + + if (reader.error() != QXmlStreamReader::NoError) { + *errorMessage= msgXmlError(fileName, reader); + return {}; + } + + return result; +} + +static void formatDescription(QDebug &debug, const QString &desc) +{ + debug << "description="; + if (desc.isEmpty()) { + debug << "<empty>"; + return; + } + if (debug.verbosity() < 3) + debug << desc.size() << " chars"; + else + debug << '"' << desc << '"'; +} + +QDebug operator<<(QDebug debug, const EnumDocumentation &e) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "Enum("; + if (e.name.isEmpty()) { + debug << "invalid"; + } else { + debug << e.name << ", "; + formatDescription(debug, e.description); + } + debug << ')'; + return debug; +} + +QDebug operator<<(QDebug debug, const PropertyDocumentation &p) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "Property("; + if (p.name.isEmpty()) { + debug << "invalid"; + } else { + debug << p.name << ", "; + formatDescription(debug, p.description); + } + debug << ')'; + return debug; +} + +QDebug operator<<(QDebug debug, const FunctionDocumentation &f) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "Function("; + if (f.name.isEmpty()) { + debug << "invalid"; + } else { + debug << f.name; + if (!f.returnType.isEmpty()) + debug << ", returns " << f.returnType; + if (f.constant) + debug << ", const"; + formatList(debug, ", parameters", f.parameters, ", "); + debug << ", signature=\"" << f.signature << "\", "; + formatDescription(debug, f.description); + } + debug << ')'; + return debug; +} + +QDebug operator<<(QDebug debug, const FunctionDocumentationQuery &q) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "FunctionQuery(" << q.name; + if (q.constant) + debug << ", const"; + formatList(debug, ", parameters", q.parameters); + debug << ')'; + return debug; +} + +QDebug operator<<(QDebug debug, const ClassDocumentation &c) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "Class(" << c.name << ", "; + formatDescription(debug, c.description); + formatList(debug, ", enums", c.enums); + formatList(debug, ", properties", c.properties); + formatList(debug, ", functions", c.functions); + debug << ')'; + return debug; +} diff --git a/sources/shiboken6/ApiExtractor/classdocumentation.h b/sources/shiboken6/ApiExtractor/classdocumentation.h new file mode 100644 index 000000000..d47101389 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/classdocumentation.h @@ -0,0 +1,82 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef CLASSDOCUMENTATION_H +#define CLASSDOCUMENTATION_H + +#include <QtCore/QStringList> + +#include <optional> + +QT_FORWARD_DECLARE_CLASS(QDebug) + +/// An enumeration in a WebXML/doxygen document +struct EnumDocumentation +{ + QString name; + QString description; +}; + +/// A QObject property in a WebXML/doxygen document +struct PropertyDocumentation +{ + QString name; + QString brief; + QString description; +}; + +/// Helper struct for querying a function in a WebXML/doxygen document +struct FunctionDocumentationQuery +{ + QString name; + QStringList parameters; + bool constant = false; +}; + +/// A function in a WebXML/doxygen document +struct FunctionDocumentation : public FunctionDocumentationQuery +{ + QString signature; + QString returnType; + QString description; +}; + +using FunctionDocumentationList = QList<FunctionDocumentation>; + +/// A WebXML/doxygen document +struct ClassDocumentation +{ + enum Type { + Class, // <class>, class/namespace + Header // <header>, grouped global functions/enums + }; + + qsizetype indexOfEnum(const QString &name) const; + FunctionDocumentationList findFunctionCandidates(const QString &name, + bool constant) const; + static qsizetype indexOfFunction(const FunctionDocumentationList &fl, + const FunctionDocumentationQuery &q); + qsizetype indexOfProperty(const QString &name) const; + + Type type = Type::Class; + QString name; + QString description; + + QList<EnumDocumentation> enums; + QList<PropertyDocumentation> properties; + FunctionDocumentationList functions; +}; + +/// Parse a WebXML class/namespace document +std::optional<ClassDocumentation> parseWebXml(const QString &fileName, QString *errorMessage); + +/// Extract the module description from a WebXML module document +QString webXmlModuleDescription(const QString &fileName, QString *errorMessage); + +QDebug operator<<(QDebug debug, const EnumDocumentation &e); +QDebug operator<<(QDebug debug, const PropertyDocumentation &p); +QDebug operator<<(QDebug debug, const FunctionDocumentationQuery &q); +QDebug operator<<(QDebug debug, const FunctionDocumentation &f); +QDebug operator<<(QDebug debug, const ClassDocumentation &c); + +#endif // CLASSDOCUMENTATION_H diff --git a/sources/shiboken6/ApiExtractor/cmake_uninstall.cmake b/sources/shiboken6/ApiExtractor/cmake_uninstall.cmake index df95fb9d8..4031b4e1a 100644 --- a/sources/shiboken6/ApiExtractor/cmake_uninstall.cmake +++ b/sources/shiboken6/ApiExtractor/cmake_uninstall.cmake @@ -1,3 +1,6 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") diff --git a/sources/shiboken6/ApiExtractor/codesnip.cpp b/sources/shiboken6/ApiExtractor/codesnip.cpp new file mode 100644 index 000000000..e2cd5eb35 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/codesnip.cpp @@ -0,0 +1,78 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "codesnip.h" + +#include "qtcompat.h" +#include "exception.h" +#include "typedatabase.h" + +#include <QtCore/QDebug> + +using namespace Qt::StringLiterals; + +QString TemplateInstance::expandCode() const +{ + const auto templateEntry = TypeDatabase::instance()->findTemplate(m_name); + if (!templateEntry) { + const QString m = u"<insert-template> referring to non-existing template '"_s + + m_name + u"'."_s; + throw Exception(m); + } + + QString code = templateEntry->code(); + for (auto it = replaceRules.cbegin(), end = replaceRules.cend(); it != end; ++it) + code.replace(it.key(), it.value()); + while (!code.isEmpty() && code.at(code.size() - 1).isSpace()) + code.chop(1); + QString result = u"// TEMPLATE - "_s + m_name + u" - START"_s; + if (!code.startsWith(u'\n')) + result += u'\n'; + result += code; + result += u"\n// TEMPLATE - "_s + m_name + u" - END\n"_s; + return result; +} + +// ---------------------- CodeSnipFragment +QString CodeSnipFragment::code() const +{ + return m_instance ? m_instance->expandCode() : m_code; +} + +// ---------------------- CodeSnipAbstract +QString CodeSnipAbstract::code() const +{ + QString res; + for (const CodeSnipFragment &codeFrag : codeList) + res.append(codeFrag.code()); + + return res; +} + +void CodeSnipAbstract::addCode(const QString &code) +{ + codeList.append(CodeSnipFragment(fixSpaces(code))); +} + +void CodeSnipAbstract::purgeEmptyFragments() +{ + auto end = std::remove_if(codeList.begin(), codeList.end(), + [](const CodeSnipFragment &f) { return f.isEmpty(); }); + codeList.erase(end, codeList.end()); +} + +QRegularExpression CodeSnipAbstract::placeHolderRegex(int index) +{ + return QRegularExpression(u'%' + QString::number(index) + "\\b"_L1); +} + +void purgeEmptyCodeSnips(QList<CodeSnip> *list) +{ + for (auto it = list->begin(); it != list->end(); ) { + it->purgeEmptyFragments(); + if (it->isEmpty()) + it = list->erase(it); + else + ++it; + } +} diff --git a/sources/shiboken6/ApiExtractor/codesnip.h b/sources/shiboken6/ApiExtractor/codesnip.h new file mode 100644 index 000000000..86834a1db --- /dev/null +++ b/sources/shiboken6/ApiExtractor/codesnip.h @@ -0,0 +1,107 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef CODESNIP_H +#define CODESNIP_H + +#include "codesniphelpers.h" +#include "typesystem_enums.h" + +#include <QtCore/QList> +#include <QtCore/QHash> +#include <QtCore/QString> + +#include <memory> + +class TemplateInstance +{ +public: + explicit TemplateInstance(const QString &name) : m_name(name) {} + + void addReplaceRule(const QString &name, const QString &value) + { + replaceRules[name] = value; + } + + QString expandCode() const; + + QString name() const + { + return m_name; + } + +private: + const QString m_name; + QHash<QString, QString> replaceRules; +}; + +using TemplateInstancePtr = std::shared_ptr<TemplateInstance>; + +class CodeSnipFragment +{ +public: + CodeSnipFragment() = default; + explicit CodeSnipFragment(const QString &code) : m_code(code) {} + explicit CodeSnipFragment(const TemplateInstancePtr &instance) : m_instance(instance) {} + + bool isEmpty() const { return m_code.isEmpty() && !m_instance; } + + QString code() const; + + TemplateInstancePtr instance() const { return m_instance; } + +private: + QString m_code; + std::shared_ptr<TemplateInstance> m_instance; +}; + +class CodeSnipAbstract : public CodeSnipHelpers +{ +public: + QString code() const; + + void addCode(const QString &code); + void addCode(QStringView code) { addCode(code.toString()); } + + void addTemplateInstance(const TemplateInstancePtr &ti) + { + codeList.append(CodeSnipFragment(ti)); + } + + bool isEmpty() const { return codeList.isEmpty(); } + void purgeEmptyFragments(); + + QList<CodeSnipFragment> codeList; + + static QRegularExpression placeHolderRegex(int index); +}; + +class TemplateEntry : public CodeSnipAbstract +{ +public: + explicit TemplateEntry(const QString &name) : m_name(name) {} + + QString name() const + { + return m_name; + } + +private: + QString m_name; +}; + +class CodeSnip : public CodeSnipAbstract +{ +public: + CodeSnip() = default; + explicit CodeSnip(TypeSystem::Language lang) : language(lang) {} + + TypeSystem::Language language = TypeSystem::TargetLangCode; + TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny; +}; + +/// Purge empty fragments and snippets caused by new line characters in +/// conjunction with <insert-template>. +void purgeEmptyCodeSnips(QList<CodeSnip> *list); + +#endif // CODESNIP_H diff --git a/sources/shiboken6/ApiExtractor/codesniphelpers.cpp b/sources/shiboken6/ApiExtractor/codesniphelpers.cpp index f9bae0a65..775cf10af 100644 --- a/sources/shiboken6/ApiExtractor/codesniphelpers.cpp +++ b/sources/shiboken6/ApiExtractor/codesniphelpers.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "codesniphelpers.h" @@ -51,9 +26,9 @@ QString CodeSnipHelpers::dedent(const QString &code) if (code.isEmpty()) return code; // Right trim if indent=0, or trim if single line - if (!code.at(0).isSpace() || !code.contains(QLatin1Char('\n'))) + if (!code.at(0).isSpace() || !code.contains(u'\n')) return code.trimmed(); - const auto lines = QStringView{code}.split(QLatin1Char('\n')); + const auto lines = QStringView{code}.split(u'\n'); int spacesToRemove = std::numeric_limits<int>::max(); for (const auto &line : lines) { if (!isEmpty(line)) { @@ -68,35 +43,35 @@ QString CodeSnipHelpers::dedent(const QString &code) for (const auto &line : lines) { if (!isEmpty(line) && spacesToRemove < line.size()) result += line.mid(spacesToRemove).toString(); - result += QLatin1Char('\n'); + result += u'\n'; } return result; } QString CodeSnipHelpers::fixSpaces(QString code) { - code.remove(QLatin1Char('\r')); + code.remove(u'\r'); // Check for XML <tag>\n<space>bla... - if (code.startsWith(QLatin1String("\n "))) + if (code.startsWith(u"\n ")) code.remove(0, 1); while (!code.isEmpty() && code.back().isSpace()) code.chop(1); code = dedent(code); - if (!code.isEmpty() && !code.endsWith(QLatin1Char('\n'))) - code.append(QLatin1Char('\n')); + if (!code.isEmpty() && !code.endsWith(u'\n')) + code.append(u'\n'); return code; } // Prepend a line to the code, observing indentation void CodeSnipHelpers::prependCode(QString *code, QString firstLine) { - while (!code->isEmpty() && code->front() == QLatin1Char('\n')) + while (!code->isEmpty() && code->front() == u'\n') code->remove(0, 1); if (!code->isEmpty() && code->front().isSpace()) { const int indent = firstNonBlank(*code); - firstLine.prepend(QString(indent, QLatin1Char(' '))); + firstLine.prepend(QString(indent, u' ')); } - if (!firstLine.endsWith(QLatin1Char('\n'))) - firstLine += QLatin1Char('\n'); + if (!firstLine.endsWith(u'\n')) + firstLine += u'\n'; code->prepend(firstLine); } diff --git a/sources/shiboken6/ApiExtractor/codesniphelpers.h b/sources/shiboken6/ApiExtractor/codesniphelpers.h index d7da05ea0..e7a7545da 100644 --- a/sources/shiboken6/ApiExtractor/codesniphelpers.h +++ b/sources/shiboken6/ApiExtractor/codesniphelpers.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CODESNIPHELPERS_H #define CODESNIPHELPERS_H diff --git a/sources/shiboken6/ApiExtractor/complextypeentry.h b/sources/shiboken6/ApiExtractor/complextypeentry.h new file mode 100644 index 000000000..5b884f2cc --- /dev/null +++ b/sources/shiboken6/ApiExtractor/complextypeentry.h @@ -0,0 +1,179 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef COMPLEXTYPEENTRY_H +#define COMPLEXTYPEENTRY_H + +#include "configurabletypeentry.h" +#include "typesystem_enums.h" +#include "modifications_typedefs.h" +#include "pymethoddefentry.h" + +#include <QtCore/QSet> + +class ComplexTypeEntryPrivate; + +struct TypeSystemPyMethodDefEntry : public PyMethodDefEntry +{ + QStringList signatures; +}; + +struct TypeSystemProperty +{ + bool isValid() const { return !name.isEmpty() && !read.isEmpty() && !type.isEmpty(); } + + QString type; + QString name; + QString read; + QString write; + QString reset; + QString designable; + QString notify; // Q_PROPERTY/C++ only + // Indicates whether actual code is generated instead of relying on libpyside. + bool generateGetSetDef = false; +}; + +class ComplexTypeEntry : public ConfigurableTypeEntry +{ +public: + enum TypeFlag { + DisableWrapper = 0x1, + Deprecated = 0x4, + ForceAbstract = 0x8, + // Indicates that the instances are used to create hierarchies + // like widgets; parent ownership heuristics are enabled for them. + ParentManagement = 0x10, + DisableQtMetaObjectFunctions = 0x20, + Typedef = 0x40 // Result of a <typedef-type> + }; + Q_DECLARE_FLAGS(TypeFlags, TypeFlag) + + enum CopyableFlag { + CopyableSet, + NonCopyableSet, + Unknown + }; + + explicit ComplexTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + bool isComplex() const override; + + TypeFlags typeFlags() const; + void setTypeFlags(TypeFlags flags); + + // Override command line options to generate nb_bool from + // operator bool or method isNull(). + TypeSystem::BoolCast operatorBoolMode() const; + void setOperatorBoolMode(TypeSystem::BoolCast b); + TypeSystem::BoolCast isNullMode() const; + void setIsNullMode(TypeSystem::BoolCast b); + + FunctionModificationList functionModifications() const; + void setFunctionModifications(const FunctionModificationList &functionModifications); + void addFunctionModification(const FunctionModification &functionModification); + FunctionModificationList functionModifications(const QStringList &signatures) const; + + const CodeSnipList &codeSnips() const; + CodeSnipList &codeSnips(); + void setCodeSnips(const CodeSnipList &codeSnips); + void addCodeSnip(const CodeSnip &codeSnip); + + void setDocModification(const DocModificationList& docMods); + /// Class documentation modifications + DocModificationList docModifications() const; + /// Function documentation modifications (matching signature) + DocModificationList functionDocModifications() const; + + /// Extra includes for function arguments determined by the meta builder. + const IncludeList &argumentIncludes() const; + void addArgumentInclude(const Include &newInclude); + + AddedFunctionList addedFunctions() const; + void setAddedFunctions(const AddedFunctionList &addedFunctions); + void addNewFunction(const AddedFunctionPtr &addedFunction); + + const QList<TypeSystemPyMethodDefEntry> &addedPyMethodDefEntrys() const; + void addPyMethodDef(const TypeSystemPyMethodDefEntry &p); + + // Functions specified in the "generate-functions" attribute + const QSet<QString> &generateFunctions() const; + void setGenerateFunctions(const QSet<QString> &f); + + void setFieldModifications(const FieldModificationList &mods); + FieldModificationList fieldModifications() const; + + const QList<TypeSystemProperty> &properties() const; + void addProperty(const TypeSystemProperty &p); + + QString defaultSuperclass() const; + void setDefaultSuperclass(const QString &sc); + + QString qualifiedCppName() const override; + + void setIsPolymorphicBase(bool on); + bool isPolymorphicBase() const; + + void setPolymorphicIdValue(const QString &value); + QString polymorphicIdValue() const; + + QString polymorphicNameFunction() const; + void setPolymorphicNameFunction(const QString &n); + + QString targetType() const; + void setTargetType(const QString &code); + + bool isGenericClass() const; + void setGenericClass(bool isGeneric); + + bool deleteInMainThread() const; + void setDeleteInMainThread(bool d); + + CopyableFlag copyable() const; + void setCopyable(CopyableFlag flag); + + TypeSystem::QtMetaTypeRegistration qtMetaTypeRegistration() const; + void setQtMetaTypeRegistration(TypeSystem::QtMetaTypeRegistration r); + + QString hashFunction() const; + void setHashFunction(const QString &hashFunction); + + void setBaseContainerType(const ComplexTypeEntryCPtr &baseContainer); + + ComplexTypeEntryCPtr baseContainerType() const; + + TypeSystem::ExceptionHandling exceptionHandling() const; + void setExceptionHandling(TypeSystem::ExceptionHandling e); + + TypeSystem::AllowThread allowThread() const; + void setAllowThread(TypeSystem::AllowThread allowThread); + + QString defaultConstructor() const; + void setDefaultConstructor(const QString& defaultConstructor); + bool hasDefaultConstructor() const; + + TypeEntry *clone() const override; + + void useAsTypedef(const ComplexTypeEntryCPtr &source); + + TypeSystem::SnakeCase snakeCase() const; + void setSnakeCase(TypeSystem::SnakeCase sc); + + // Determined by AbstractMetaBuilder from the code model. + bool isValueTypeWithCopyConstructorOnly() const; + void setValueTypeWithCopyConstructorOnly(bool v); + + // FIXME PYSIDE 7: Remove this + static bool isParentManagementEnabled(); + static void setParentManagementEnabled(bool e); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &debug) const override; +#endif +protected: + explicit ComplexTypeEntry(ComplexTypeEntryPrivate *d); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(ComplexTypeEntry::TypeFlags) + +#endif // COMPLEXTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp b/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp index 2380ee892..b6eda651c 100644 --- a/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp +++ b/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp @@ -1,38 +1,101 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "conditionalstreamreader.h" #include <QtCore/QDebug> +#include <QtCore/QHash> + +using namespace Qt::StringLiterals; + +// ProxyEntityResolver proxies a QXmlStreamEntityResolver set by the user +// on ConditionalStreamReader and stores entity definitions from the +// <?entity name value?> processing instruction in a cache +// (which is also used for the proxied resolver). +class ProxyEntityResolver : public QXmlStreamEntityResolver +{ +public: + QString resolveEntity(const QString& publicId, + const QString& systemId) override; + QString resolveUndeclaredEntity(const QString &name) override; + + QXmlStreamEntityResolver *source() const { return m_source; } + void setSource(QXmlStreamEntityResolver *s) { m_source = s; } + + void defineEntity(const QString &name, const QString &value) + { + m_undeclaredEntityCache.insert(name, value); + } + +private: + QHash<QString, QString> m_undeclaredEntityCache; + QXmlStreamEntityResolver *m_source = nullptr; +}; + +QString ProxyEntityResolver::resolveEntity(const QString &publicId, const QString &systemId) +{ + QString result; + if (m_source != nullptr) + result = m_source->resolveEntity(publicId, systemId); + if (result.isEmpty()) + result = QXmlStreamEntityResolver::resolveEntity(publicId, systemId); + return result; +} + +QString ProxyEntityResolver::resolveUndeclaredEntity(const QString &name) +{ + const auto it = m_undeclaredEntityCache.constFind(name); + if (it != m_undeclaredEntityCache.constEnd()) + return it.value(); + if (m_source == nullptr) + return {}; + const QString result = m_source->resolveUndeclaredEntity(name); + if (!result.isEmpty()) + defineEntity(name, result); + return result; +} + +ConditionalStreamReader::ConditionalStreamReader(QIODevice *iod) : + m_reader(iod) +{ + init(); +} + +ConditionalStreamReader::ConditionalStreamReader(const QString &s) : + m_reader(s) +{ + init(); +} + +void ConditionalStreamReader::init() +{ + m_proxyEntityResolver = new ProxyEntityResolver; + m_reader.setEntityResolver(m_proxyEntityResolver); +} + +ConditionalStreamReader::~ConditionalStreamReader() +{ + m_reader.setEntityResolver(nullptr); + delete m_proxyEntityResolver; +} + +void ConditionalStreamReader::setEntityResolver(QXmlStreamEntityResolver *resolver) +{ + m_proxyEntityResolver->setSource(resolver); +} + +QXmlStreamEntityResolver *ConditionalStreamReader::entityResolver() const +{ + return m_proxyEntityResolver->source(); +} QXmlStreamReader::TokenType ConditionalStreamReader::readNext() { auto exToken = readNextInternal(); + + if (exToken.second == PiTokens::EntityDefinition) + return readEntityDefinitonPi() ? exToken.first : QXmlStreamReader::Invalid; + if (exToken.second != PiTokens::If || conditionMatches()) return exToken.first; @@ -54,20 +117,43 @@ QXmlStreamReader::TokenType ConditionalStreamReader::readNext() return exToken.first; } +void ConditionalStreamReader::defineEntity(const QString &name, const QString &value) +{ + m_proxyEntityResolver->defineEntity(name, value); +} + +// Read an entity definition: "<?entity name value?>: +bool ConditionalStreamReader::readEntityDefinitonPi() +{ + const auto data = m_reader.processingInstructionData(); + const auto separator = data.indexOf(u' '); + if (separator <= 0 || separator == data.size() - 1) { + m_reader.raiseError(u"Malformed entity definition: "_s + data.toString()); + return false; + } + defineEntity(data.left(separator).toString(), + data.right(data.size() - separator - 1).toString()); + return true; +} + bool ConditionalStreamReader::conditionMatches() const { const auto keywords = m_reader.processingInstructionData().split(u' ', Qt::SkipEmptyParts); + if (keywords.isEmpty()) + return false; bool matches = false; + bool exclusionOnly = true; for (const auto &keyword : keywords) { if (keyword.startsWith(u'!')) { // exclusion '!windows' takes preference if (m_conditions.contains(keyword.mid(1))) return false; } else { + exclusionOnly = false; matches |= m_conditions.contains(keyword); } } - return matches; + return exclusionOnly || matches; } void ConditionalStreamReader::setConditions(const QStringList &newConditions) @@ -79,15 +165,15 @@ QStringList ConditionalStreamReader::platformConditions() { QStringList result; #if defined (Q_OS_UNIX) - result << QStringLiteral("unix"); + result << "unix"_L1; #endif #if defined (Q_OS_LINUX) - result << QStringLiteral("linux"); + result << "linux"_L1; #elif defined (Q_OS_MACOS) - result << QStringLiteral("darwin"); + result << "darwin"_L1; #elif defined (Q_OS_WINDOWS) - result << QStringLiteral("windows"); + result << "windows"_L1; #endif return result; } @@ -102,6 +188,8 @@ ConditionalStreamReader::ExtendedToken ConditionalStreamReader::readNextInternal piToken = PiTokens::If; else if (target == u"endif") piToken = PiTokens::Endif; + else if (target == u"entity") + piToken = PiTokens::EntityDefinition; } return {token, piToken}; } @@ -120,3 +208,4 @@ QDebug operator<<(QDebug dbg, const QXmlStreamAttributes &attrs) dbg << ')'; return dbg; } + diff --git a/sources/shiboken6/ApiExtractor/conditionalstreamreader.h b/sources/shiboken6/ApiExtractor/conditionalstreamreader.h index 691c5e21d..730697525 100644 --- a/sources/shiboken6/ApiExtractor/conditionalstreamreader.h +++ b/sources/shiboken6/ApiExtractor/conditionalstreamreader.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CONDITIONALSTREAMREADER_H #define CONDITIONALSTREAMREADER_H @@ -35,6 +10,8 @@ QT_FORWARD_DECLARE_CLASS(QDebug) +class ProxyEntityResolver; + /// ConditionalStreamReader encapsulates QXmlStreamReader, offering the same /// API (except readNextStartElement() and similar conveniences) and internally /// uses Processing Instructions like: @@ -43,17 +20,25 @@ QT_FORWARD_DECLARE_CLASS(QDebug) /// containing for example the OS. /// It should be possible to use it as a drop-in replacement for /// QXmlStreamReader for any parsing code based on readNext(). +/// It also allows for specifying entities using a Processing Instruction: +/// <?entity name value?> +/// which can be used in conjunction with conditional processing. class ConditionalStreamReader { public: + Q_DISABLE_COPY_MOVE(ConditionalStreamReader) + using TokenType = QXmlStreamReader::TokenType; - explicit ConditionalStreamReader(QIODevice *iod) : m_reader(iod) { } - explicit ConditionalStreamReader(const QString &s) : m_reader(s) { } + explicit ConditionalStreamReader(QIODevice *iod); + explicit ConditionalStreamReader(const QString &s); + ~ConditionalStreamReader(); QIODevice *device() const { return m_reader.device(); } - void setEntityResolver(QXmlStreamEntityResolver *resolver) { m_reader.setEntityResolver(resolver); } - QXmlStreamEntityResolver *entityResolver() const { return m_reader.entityResolver(); } + // Note: Caching of entity values is done internally by + // ConditionalStreamReader. + void setEntityResolver(QXmlStreamEntityResolver *resolver); + QXmlStreamEntityResolver *entityResolver() const; bool atEnd() const { return m_reader.atEnd(); } TokenType readNext(); @@ -78,20 +63,25 @@ public: bool hasError() const { return m_reader.hasError(); } + // Additional functions (not delegating to QXmlStreamReader) + void defineEntity(const QString &name, const QString &value); + const QStringList &conditions() const { return m_conditions; } void setConditions(const QStringList &newConditions); static QStringList platformConditions(); private: - enum class PiTokens { None, If, Endif }; + enum class PiTokens { None, If, Endif, EntityDefinition }; using ExtendedToken = std::pair<TokenType, PiTokens>; ExtendedToken readNextInternal(); - + void init(); bool conditionMatches() const; + bool readEntityDefinitonPi(); QXmlStreamReader m_reader; + ProxyEntityResolver *m_proxyEntityResolver = nullptr; QStringList m_conditions = ConditionalStreamReader::platformConditions(); }; diff --git a/sources/shiboken6/ApiExtractor/configurabletypeentry.h b/sources/shiboken6/ApiExtractor/configurabletypeentry.h new file mode 100644 index 000000000..59522e16c --- /dev/null +++ b/sources/shiboken6/ApiExtractor/configurabletypeentry.h @@ -0,0 +1,28 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef CONFIGURABLETYPEENTRY_H +#define CONFIGURABLETYPEENTRY_H + +#include "typesystem.h" + +class ConfigurableTypeEntryPrivate; + +class ConfigurableTypeEntry : public TypeEntry +{ +public: + explicit ConfigurableTypeEntry(const QString &entryName, Type t, + const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + TypeEntry *clone() const override; + + QString configCondition() const; + void setConfigCondition(const QString &c); + bool hasConfigCondition() const; + +protected: + explicit ConfigurableTypeEntry(ConfigurableTypeEntryPrivate *d); +}; + +#endif // CONFIGURABLETYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/constantvaluetypeentry.h b/sources/shiboken6/ApiExtractor/constantvaluetypeentry.h new file mode 100644 index 000000000..a16a7ad12 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/constantvaluetypeentry.h @@ -0,0 +1,23 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef CONSTANTVALUETYPEENTRY_H +#define CONSTANTVALUETYPEENTRY_H + +#include "typesystem.h" + +// For primitive values, typically to provide a dummy type for +// example the '2' in non-type template 'Array<2>'. +class ConstantValueTypeEntry : public TypeEntry +{ +public: + explicit ConstantValueTypeEntry(const QString& name, + const TypeEntryCPtr &parent); + + TypeEntry *clone() const override; + +protected: + explicit ConstantValueTypeEntry(TypeEntryPrivate *d); +}; + +#endif // CONSTANTVALUETYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/containertypeentry.h b/sources/shiboken6/ApiExtractor/containertypeentry.h new file mode 100644 index 000000000..b2003816b --- /dev/null +++ b/sources/shiboken6/ApiExtractor/containertypeentry.h @@ -0,0 +1,63 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef CONTAINERTYPEENTRY_H +#define CONTAINERTYPEENTRY_H + +#include "complextypeentry.h" +#include "customconversion_typedefs.h" + +class ContainerTypeEntryPrivate; + +struct OpaqueContainer // Generate an opaque container for an instantiation under name +{ + QStringList instantiations; + QString name; + + QString templateParameters() const; +}; + +using OpaqueContainers = QList<OpaqueContainer>; + +class ContainerTypeEntry : public ComplexTypeEntry +{ +public: + + enum ContainerKind { + ListContainer, + SetContainer, + MapContainer, + MultiMapContainer, + PairContainer, + SpanContainer, // Fixed size + }; + + explicit ContainerTypeEntry(const QString &entryName, ContainerKind containerKind, + const QVersionNumber &vr, const TypeEntryCPtr &parent); + + ContainerKind containerKind() const; + + /// Number of template parameters (except allocators) + qsizetype templateParameterCount() const; + + const OpaqueContainers &opaqueContainers() const; + void appendOpaqueContainers(const OpaqueContainers &l); + bool generateOpaqueContainer(const QStringList &instantiations) const; + QString opaqueContainerName(const QStringList &instantiations) const; + + bool hasCustomConversion() const; + void setCustomConversion(const CustomConversionPtr &customConversion); + CustomConversionPtr customConversion() const; + + TypeEntry *clone() const override; + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif +protected: + explicit ContainerTypeEntry(ContainerTypeEntryPrivate *d); +}; + +QDebug operator<<(QDebug d, const OpaqueContainer &oc); + +#endif // CONTAINERTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/customconversion.cpp b/sources/shiboken6/ApiExtractor/customconversion.cpp new file mode 100644 index 000000000..4cfd1b974 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/customconversion.cpp @@ -0,0 +1,197 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "customconversion.h" +#include "containertypeentry.h" +#include "customtypenentry.h" +#include "primitivetypeentry.h" +#include "valuetypeentry.h" + +#include <QtCore/qdebug.h> + +using namespace Qt::StringLiterals; + +CustomConversion::CustomConversion(const TypeEntryCPtr &ownerType) : + m_ownerType(ownerType) +{ +} + +TypeEntryCPtr CustomConversion::ownerType() const +{ + return m_ownerType; +} + +QString CustomConversion::nativeToTargetConversion() const +{ + return m_nativeToTargetConversion; +} + +void CustomConversion::setNativeToTargetConversion(const QString &nativeToTargetConversion) +{ + m_nativeToTargetConversion = nativeToTargetConversion; +} + +bool CustomConversion::replaceOriginalTargetToNativeConversions() const +{ + return m_replaceOriginalTargetToNativeConversions; +} + +void CustomConversion::setReplaceOriginalTargetToNativeConversions(bool r) +{ + m_replaceOriginalTargetToNativeConversions = r; +} + +bool CustomConversion::hasTargetToNativeConversions() const +{ + return !(m_targetToNativeConversions.isEmpty()); +} + +TargetToNativeConversions &CustomConversion::targetToNativeConversions() +{ + return m_targetToNativeConversions; +} + +const TargetToNativeConversions &CustomConversion::targetToNativeConversions() const +{ + return m_targetToNativeConversions; +} + +void CustomConversion::addTargetToNativeConversion(const QString &sourceTypeName, + const QString &sourceTypeCheck, + const QString &conversion) +{ + m_targetToNativeConversions.append(TargetToNativeConversion(sourceTypeName, + sourceTypeCheck, + conversion)); +} + +TargetToNativeConversion::TargetToNativeConversion(const QString &sourceTypeName, + const QString &sourceTypeCheck, + const QString &conversion) : + m_sourceTypeName(sourceTypeName), m_sourceTypeCheck(sourceTypeCheck), + m_conversion(conversion) +{ +} + +TypeEntryCPtr TargetToNativeConversion::sourceType() const +{ + return m_sourceType; +} + +void TargetToNativeConversion::setSourceType(const TypeEntryCPtr &sourceType) +{ + m_sourceType = sourceType; +} + +bool TargetToNativeConversion::isCustomType() const +{ + return m_sourceType == nullptr; +} + +QString TargetToNativeConversion::sourceTypeName() const +{ + return m_sourceTypeName; +} + +QString TargetToNativeConversion::sourceTypeCheck() const +{ + if (!m_sourceTypeCheck.isEmpty()) + return m_sourceTypeCheck; + + if (m_sourceType != nullptr && m_sourceType->isCustom()) { + const auto cte = std::static_pointer_cast<const CustomTypeEntry>(m_sourceType); + if (cte->hasCheckFunction()) { + QString result = cte->checkFunction(); + if (result != u"true") // For PyObject, which is always true + result += u"(%in)"_s; + return result; + } + } + + return {}; +} + +QString TargetToNativeConversion::conversion() const +{ + return m_conversion; +} + +void TargetToNativeConversion::setConversion(const QString &conversion) +{ + m_conversion = conversion; +} + +void TargetToNativeConversion::formatDebug(QDebug &debug) const +{ + debug << "(source=\"" << m_sourceTypeName << '"'; + if (debug.verbosity() > 2) + debug << ", conversion=\"" << m_conversion << '"'; + if (isCustomType()) + debug << ", [custom]"; + debug << ')'; +} + +CustomConversionPtr CustomConversion::getCustomConversion(const TypeEntryCPtr &type) +{ + if (type->isPrimitive()) + return std::static_pointer_cast<const PrimitiveTypeEntry>(type)->customConversion(); + if (type->isContainer()) + return std::static_pointer_cast<const ContainerTypeEntry>(type)->customConversion(); + if (type->isValue()) + return std::static_pointer_cast<const ValueTypeEntry>(type)->customConversion(); + return {}; +} + +void CustomConversion::formatDebug(QDebug &debug) const +{ + debug << "(owner=\"" << m_ownerType->qualifiedCppName() << '"'; + if (!m_nativeToTargetConversion.isEmpty()) + debug << ", nativeToTargetConversion=\"" << m_nativeToTargetConversion << '"'; + if (!m_targetToNativeConversions.isEmpty()) { + debug << ", targetToNativeConversions=["; + for (qsizetype i = 0, size = m_targetToNativeConversions.size(); i < size; ++i) { + if (i) + debug << ", "; + debug << m_targetToNativeConversions.at(i); + + } + debug << ']'; + } + if (m_replaceOriginalTargetToNativeConversions) + debug << ", [replaceOriginalTargetToNativeConversions]"; + debug << ')'; +} + +QDebug operator<<(QDebug debug, const TargetToNativeConversion &t) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "TargetToNativeConversion"; + t.formatDebug(debug); + return debug; +} + +QDebug operator<<(QDebug debug, const CustomConversion &c) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "CustomConversion"; + c.formatDebug(debug); + return debug; +} + +QDebug operator<<(QDebug debug, const CustomConversionPtr &cptr) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "CustomConversionPtr"; + if (auto *c = cptr.get()) { + c->formatDebug(debug); + } else { + debug << "(0)"; + } + return debug; +} diff --git a/sources/shiboken6/ApiExtractor/customconversion.h b/sources/shiboken6/ApiExtractor/customconversion.h new file mode 100644 index 000000000..fd0a67759 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/customconversion.h @@ -0,0 +1,81 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef CUSTOMCONVERSION_H +#define CUSTOMCONVERSION_H + +#include "customconversion_typedefs.h" +#include "typesystem_typedefs.h" + +#include <QtCore/QList> +#include <QtCore/QString> + +QT_FORWARD_DECLARE_CLASS(QDebug) + +class TypeEntry; + +class TargetToNativeConversion +{ +public: + explicit TargetToNativeConversion(const QString &sourceTypeName, + const QString &sourceTypeCheck, + const QString &conversion = {}); + + TypeEntryCPtr sourceType() const; + void setSourceType(const TypeEntryCPtr &sourceType); + bool isCustomType() const; + QString sourceTypeName() const; + QString sourceTypeCheck() const; + QString conversion() const; + void setConversion(const QString &conversion); + + void formatDebug(QDebug &d) const; + +private: + TypeEntryCPtr m_sourceType; + QString m_sourceTypeName; + QString m_sourceTypeCheck; + QString m_conversion; +}; + +using TargetToNativeConversions = QList<TargetToNativeConversion>; + +class CustomConversion +{ +public: + explicit CustomConversion(const TypeEntryCPtr &ownerType); + + TypeEntryCPtr ownerType() const; + QString nativeToTargetConversion() const; + void setNativeToTargetConversion(const QString &nativeToTargetConversion); + + /// Returns true if the target to C++ custom conversions should + /// replace the original existing ones, and false if the custom + /// conversions should be added to the original. + bool replaceOriginalTargetToNativeConversions() const; + void setReplaceOriginalTargetToNativeConversions(bool r); + + bool hasTargetToNativeConversions() const; + TargetToNativeConversions &targetToNativeConversions(); + const TargetToNativeConversions &targetToNativeConversions() const; + void addTargetToNativeConversion(const QString &sourceTypeName, + const QString &sourceTypeCheck, + const QString &conversion = QString()); + + /// Return the custom conversion of a type; helper for type system parser + static CustomConversionPtr getCustomConversion(const TypeEntryCPtr &type); + + void formatDebug(QDebug &debug) const; + +private: + TypeEntryCPtr m_ownerType; + QString m_nativeToTargetConversion; + TargetToNativeConversions m_targetToNativeConversions; + bool m_replaceOriginalTargetToNativeConversions = false; +}; + +QDebug operator<<(QDebug debug, const TargetToNativeConversion &t); +QDebug operator<<(QDebug debug, const CustomConversion &c); +QDebug operator<<(QDebug debug, const CustomConversionPtr &cptr); + +#endif // CUSTOMCONVERSION_H diff --git a/sources/shiboken6/ApiExtractor/customconversion_typedefs.h b/sources/shiboken6/ApiExtractor/customconversion_typedefs.h new file mode 100644 index 000000000..6528f7d7b --- /dev/null +++ b/sources/shiboken6/ApiExtractor/customconversion_typedefs.h @@ -0,0 +1,14 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef CUSTOMCONVERSION_TYPEDEFS_H +#define CUSTOMCONVERSION_TYPEDEFS_H + +#include <QtCore/QList> + +#include <memory> + +class CustomConversion; +using CustomConversionPtr = std::shared_ptr<CustomConversion>; + +#endif // CUSTOMCONVERSION_TYPEDEFS_H diff --git a/sources/shiboken6/ApiExtractor/customtypenentry.h b/sources/shiboken6/ApiExtractor/customtypenentry.h new file mode 100644 index 000000000..a57bb858f --- /dev/null +++ b/sources/shiboken6/ApiExtractor/customtypenentry.h @@ -0,0 +1,30 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef CUSTOMTYPENENTRY_H +#define CUSTOMTYPENENTRY_H + +#include "typesystem.h" + +class CustomTypeEntry : public TypeEntry +{ +public: + explicit CustomTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + TypeEntry *clone() const override; + + bool hasCheckFunction() const; + QString checkFunction() const; + void setCheckFunction(const QString &f); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +protected: + explicit CustomTypeEntry(TypeEntryPrivate *d); +}; + + +#endif // CUSTOMTYPENENTRY_H diff --git a/sources/shiboken6/ApiExtractor/debughelpers_p.h b/sources/shiboken6/ApiExtractor/debughelpers_p.h new file mode 100644 index 000000000..81ebbb3b9 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/debughelpers_p.h @@ -0,0 +1,56 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef DEBUGHELPERS_P_H +#define DEBUGHELPERS_P_H + +#include <QtCore/QDebug> +#include <memory> + +template <class T> +inline QDebug operator<<(QDebug debug, const std::shared_ptr<T> &ptr) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + debug << "std::shared_ptr(" << ptr.get() << ")"; + return debug; +} + +template <class It> +inline 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> +inline static void formatPtrSequence(QDebug &d, It i1, It i2, + const char *separator=", ") +{ + for (It i = i1; i != i2; ++i) { + if (i != i1) + d << separator; + d << i->get(); + } +} + +template <class Container> +static void formatList(QDebug &d, const char *name, const Container &c, + const char *separator=", ") +{ + if (const auto size = c.size()) { + d << ", " << name << '[' << size << "]=("; + for (qsizetype i = 0; i < size; ++i) { + if (i) + d << separator; + d << c.at(i); + } + d << ')'; + } +} + +#endif // DEBUGHELPERS_P_H diff --git a/sources/shiboken6/ApiExtractor/dependency.h b/sources/shiboken6/ApiExtractor/dependency.h index ee6301525..aa280de03 100644 --- a/sources/shiboken6/ApiExtractor/dependency.h +++ b/sources/shiboken6/ApiExtractor/dependency.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef DEPENDENCY_H #define DEPENDENCY_H @@ -38,8 +13,8 @@ class AbstractMetaClass; struct Dependency { - AbstractMetaClass *parent; - AbstractMetaClass *child; + AbstractMetaClassPtr parent; + AbstractMetaClassPtr child; }; using Dependencies = QList<Dependency>; diff --git a/sources/shiboken6/ApiExtractor/docparser.cpp b/sources/shiboken6/ApiExtractor/docparser.cpp index 9445adf81..468fe1098 100644 --- a/sources/shiboken6/ApiExtractor/docparser.cpp +++ b/sources/shiboken6/ApiExtractor/docparser.cpp @@ -1,44 +1,25 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + #include "docparser.h" +#include "abstractmetaargument.h" #include "abstractmetaenum.h" -#include "abstractmetafield.h" #include "abstractmetafunction.h" #include "abstractmetalang.h" +#include "abstractmetatype.h" #include "messages.h" #include "modifications.h" #include "reporthandler.h" -#include "typesystem.h" +#include "enumtypeentry.h" +#include "complextypeentry.h" #include "xmlutils.h" + +#include <QtCore/QBuffer> #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QTextStream> -#include <QBuffer> + +#include "qtcompat.h" #include <cstdlib> #ifdef HAVE_LIBXSLT @@ -48,15 +29,39 @@ #include <algorithm> -DocParser::DocParser() +using namespace Qt::StringLiterals; + +static inline bool isXpathDocModification(const DocModification &mod) { -#ifdef HAVE_LIBXSLT - xmlSubstituteEntitiesDefault(1); -#endif + return mod.mode() == TypeSystem::DocModificationXPathReplace; } +static inline bool isNotXpathDocModification(const DocModification &mod) +{ + return mod.mode() != TypeSystem::DocModificationXPathReplace; +} + +static void removeXpathDocModifications(DocModificationList *l) +{ + l->erase(std::remove_if(l->begin(), l->end(), isXpathDocModification), l->end()); +} + +static void removeNonXpathDocModifications(DocModificationList *l) +{ + l->erase(std::remove_if(l->begin(), l->end(), isNotXpathDocModification), l->end()); +} + +DocParser::DocParser() = default; DocParser::~DocParser() = default; +void DocParser::fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &) +{ +} + +void DocParser::fillGlobalEnumDocumentation(AbstractMetaEnum &) +{ +} + QString DocParser::getDocumentation(const XQueryPtr &xquery, const QString& query, const DocModificationList& mods) { @@ -73,9 +78,16 @@ QString DocParser::execXQuery(const XQueryPtr &xquery, const QString& query) return result; } +static bool usesRValueReference(const AbstractMetaArgument &a) +{ + return a.type().referenceType() == RValueReference; +} + bool DocParser::skipForQuery(const AbstractMetaFunctionCPtr &func) { // Skip private functions and copies created by AbstractMetaClass::fixFunctions() + // Note: Functions inherited from templates will cause warnings about missing + // documentation, but they should at least be listed. if (!func || func->isPrivate() || func->attributes().testFlag(AbstractMetaFunction::AddedMethod) || func->isModifiedRemoved() @@ -91,25 +103,95 @@ bool DocParser::skipForQuery(const AbstractMetaFunctionCPtr &func) default: break; } - return false; + + return std::any_of(func->arguments().cbegin(), func->arguments().cend(), + usesRValueReference); } -AbstractMetaFunctionCList DocParser::documentableFunctions(const AbstractMetaClass *metaClass) +DocModificationList DocParser::getDocModifications(const AbstractMetaClassCPtr &cppClass) + { - auto result = metaClass->functionsInTargetLang(); - for (int i = result.size() - 1; i >= 0; --i) { - if (DocParser::skipForQuery(result.at(i)) || result.at(i)->isUserAdded()) - result.removeAt(i); + auto result = cppClass->typeEntry()->docModifications(); + removeXpathDocModifications(&result); + return result; +} + +static void filterBySignature(const AbstractMetaFunctionCPtr &func, DocModificationList *l) +{ + if (!l->isEmpty()) { + const QString minimalSignature = func->minimalSignature(); + const auto filter = [&minimalSignature](const DocModification &mod) { + return mod.signature() != minimalSignature; + }; + l->erase(std::remove_if(l->begin(), l->end(), filter), l->end()); + } +} + +DocModificationList DocParser::getDocModifications(const AbstractMetaFunctionCPtr &func, + const AbstractMetaClassCPtr &cppClass) +{ + DocModificationList result; + if (func->isUserAdded()) { + result = func->addedFunctionDocModifications(); + removeXpathDocModifications(&result); + } else if (cppClass != nullptr) { + result = cppClass->typeEntry()->functionDocModifications(); + removeXpathDocModifications(&result); + filterBySignature(func, &result); } return result; } -static inline bool isXpathDocModification(const DocModification &mod) +DocModificationList DocParser::getXpathDocModifications(const AbstractMetaClassCPtr &cppClass) { - return mod.mode() == TypeSystem::DocModificationXPathReplace; + auto result = cppClass->typeEntry()->docModifications(); + removeNonXpathDocModifications(&result); + return result; +} + +DocModificationList DocParser::getXpathDocModifications(const AbstractMetaFunctionCPtr &func, + const AbstractMetaClassCPtr &cppClass) +{ + DocModificationList result; + if (func->isUserAdded()) { + result = func->addedFunctionDocModifications(); + removeNonXpathDocModifications(&result); + } else if (cppClass != nullptr) { + result = cppClass->typeEntry()->functionDocModifications(); + removeNonXpathDocModifications(&result); + filterBySignature(func, &result); + } + return result; } -QString DocParser::applyDocModifications(const DocModificationList& mods, const QString& xml) +QString DocParser::enumBaseClass(const AbstractMetaEnum &e) +{ + switch (e.typeEntry()->pythonEnumType()) { + case TypeSystem::PythonEnumType::IntEnum: + return u"IntEnum"_s; + case TypeSystem::PythonEnumType::Flag: + return u"Flag"_s; + case TypeSystem::PythonEnumType::IntFlag: + return u"IntFlag"_s; + default: + break; + } + return e.typeEntry()->flags() != nullptr ? u"Flag"_s : u"Enum"_s; +} + +AbstractMetaFunctionCList DocParser::documentableFunctions(const AbstractMetaClassCPtr &metaClass) +{ + auto result = metaClass->functionsInTargetLang(); + for (auto i = result.size() - 1; i >= 0; --i) { + if (DocParser::skipForQuery(result.at(i)) || result.at(i)->isUserAdded()) + result.removeAt(i); + } + result.append(metaClass->cppSignalFunctions()); + return result; +} + +QString DocParser::applyDocModifications(const DocModificationList& xpathMods, + const QString& xml) { const char xslPrefix[] = R"(<xsl:template match="/"> @@ -123,32 +205,28 @@ R"(<xsl:template match="/"> </xsl:template> )"; - if (mods.isEmpty() || xml.isEmpty() - || !std::any_of(mods.cbegin(), mods.cend(), isXpathDocModification)) { + if (xpathMods.isEmpty() || xml.isEmpty()) return xml; - } - QString xsl = QLatin1String(xslPrefix); - for (const DocModification &mod : mods) { - if (isXpathDocModification(mod)) { - QString xpath = mod.xpath(); - xpath.replace(QLatin1Char('"'), QLatin1String(""")); - xsl += QLatin1String("<xsl:template match=\"") - + xpath + QLatin1String("\">") - + mod.code() + QLatin1String("</xsl:template>\n"); - } + QString xsl = QLatin1StringView(xslPrefix); + for (const DocModification &mod : xpathMods) { + Q_ASSERT(isXpathDocModification(mod)); + QString xpath = mod.xpath(); + xpath.replace(u'"', u"""_s); + xsl += "<xsl:template match=\""_L1 + xpath + "\">"_L1 + + mod.code() + "</xsl:template>\n"_L1; } QString errorMessage; const QString result = xsl_transform(xml, xsl, &errorMessage); if (!errorMessage.isEmpty()) qCWarning(lcShibokenDoc, "%s", - qPrintable(msgXpathDocModificationError(mods, errorMessage))); + qPrintable(msgXpathDocModificationError(xpathMods, errorMessage))); if (result == xml) { - const QString message = QLatin1String("Query did not result in any modifications to \"") - + xml + QLatin1Char('"'); + const QString message = u"Query did not result in any modifications to \""_s + + xml + u'"'; qCWarning(lcShibokenDoc, "%s", - qPrintable(msgXpathDocModificationError(mods, message))); + qPrintable(msgXpathDocModificationError(xpathMods, message))); } return result; } diff --git a/sources/shiboken6/ApiExtractor/docparser.h b/sources/shiboken6/ApiExtractor/docparser.h index 206370bca..6d458b25a 100644 --- a/sources/shiboken6/ApiExtractor/docparser.h +++ b/sources/shiboken6/ApiExtractor/docparser.h @@ -1,38 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef DOCPARSER_H #define DOCPARSER_H -#include "typesystem_typedefs.h" #include "abstractmetalang_typedefs.h" +#include "modifications_typedefs.h" #include <QtCore/QString> -#include <QtCore/QSharedPointer> + +#include <memory> class AbstractMetaClass; class DocModification; @@ -40,16 +16,20 @@ class Documentation; class XQuery; +struct FunctionDocumentation; + class DocParser { public: - Q_DISABLE_COPY(DocParser) + Q_DISABLE_COPY_MOVE(DocParser) - using XQueryPtr = QSharedPointer<XQuery>; + using XQueryPtr = std::shared_ptr<XQuery>; DocParser(); virtual ~DocParser(); - virtual void fillDocumentation(AbstractMetaClass* metaClass) = 0; + virtual void fillDocumentation(const AbstractMetaClassPtr &metaClass) = 0; + virtual void fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &f); + virtual void fillGlobalEnumDocumentation(AbstractMetaEnum &e); /** * Process and retrieves documentation concerning the entire @@ -114,12 +94,25 @@ public: static bool skipForQuery(const AbstractMetaFunctionCPtr &func); + /// Helper to return the documentation modifications for a class + /// or a member function. + static DocModificationList getDocModifications(const AbstractMetaClassCPtr &cppClass); + static DocModificationList getDocModifications(const AbstractMetaFunctionCPtr &func, + const AbstractMetaClassCPtr &cppClass = {}); + static DocModificationList getXpathDocModifications(const AbstractMetaClassCPtr &cppClass); + static DocModificationList getXpathDocModifications(const AbstractMetaFunctionCPtr &func, + const AbstractMetaClassCPtr &cppClass = {}); + + static QString enumBaseClass(const AbstractMetaEnum &e); + protected: static QString getDocumentation(const XQueryPtr &xquery, const QString &query, const DocModificationList &mods); - static AbstractMetaFunctionCList documentableFunctions(const AbstractMetaClass *metaClass); + static AbstractMetaFunctionCList documentableFunctions(const AbstractMetaClassCPtr &metaClass); + + static QString applyDocModifications(const DocModificationList &xpathMods, const QString &xml); private: QString m_packageName; @@ -127,7 +120,6 @@ private: QString m_libSourceDir; static QString execXQuery(const XQueryPtr &xquery, const QString &query) ; - static QString applyDocModifications(const DocModificationList &mods, const QString &xml) ; }; #endif // DOCPARSER_H diff --git a/sources/shiboken6/ApiExtractor/documentation.cpp b/sources/shiboken6/ApiExtractor/documentation.cpp index f4c016d97..33cf0e9fb 100644 --- a/sources/shiboken6/ApiExtractor/documentation.cpp +++ b/sources/shiboken6/ApiExtractor/documentation.cpp @@ -1,33 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "documentation.h" +#include <QtCore/QDebug> + Documentation::Documentation(const QString &detailed, const QString &brief, Format fmt) : @@ -58,12 +35,6 @@ void Documentation::setFormat(Documentation::Format f) m_format = f; } -bool Documentation::equals(const Documentation &rhs) const -{ - return m_format == rhs.m_format && m_detailed == rhs.m_detailed - && m_brief == rhs.m_brief; -} - void Documentation::setDetailed(const QString &detailed) { m_detailed = detailed.trimmed(); @@ -73,3 +44,22 @@ void Documentation::setBrief(const QString &brief) { m_brief = brief.trimmed(); } + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const Documentation &d) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "Documentation("; + if (!d.isEmpty()) { + debug << "format=" << d.format(); + if (!d.brief().isEmpty()) + debug << ", brief=\"" << d.brief() << '"'; + if (!d.detailed().isEmpty()) + debug << ", detailed=\"" << d.detailed() << '"'; + } + debug << ')'; + return debug; +} +#endif // QT_NO_DEBUG_STREAM diff --git a/sources/shiboken6/ApiExtractor/documentation.h b/sources/shiboken6/ApiExtractor/documentation.h index df2a3fd6f..df9d5d614 100644 --- a/sources/shiboken6/ApiExtractor/documentation.h +++ b/sources/shiboken6/ApiExtractor/documentation.h @@ -1,35 +1,13 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef DOCUMENTATION_H #define DOCUMENTATION_H #include <QtCore/QString> +#include <QtCore/QtCompare> + +QT_FORWARD_DECLARE_CLASS(QDebug) class Documentation { @@ -67,14 +45,21 @@ public: void setBrief(const QString &brief); private: + friend bool comparesEqual(const Documentation &lhs, + const Documentation &rhs) noexcept + { + return lhs.m_format == rhs.m_format && lhs.m_detailed == rhs.m_detailed + && lhs.m_brief == rhs.m_brief; + } + Q_DECLARE_EQUALITY_COMPARABLE(Documentation) + QString m_detailed; QString m_brief; Format m_format = Documentation::Native; }; -inline bool operator==(const Documentation &d1, const Documentation &d2) -{ return d1.equals(d2); } -inline bool operator!=(const Documentation &d1, const Documentation &d2) -{ return !d1.equals(d2); } +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const Documentation &); +#endif #endif // DOCUMENTATION_H diff --git a/sources/shiboken6/ApiExtractor/dotview.cpp b/sources/shiboken6/ApiExtractor/dotview.cpp new file mode 100644 index 000000000..0bd192257 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/dotview.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "dotview.h" + +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QProcess> +#include <QtCore/QTemporaryFile> + +using namespace Qt::StringLiterals; + +bool showDotGraph(const QString &name, const QString &graph) +{ + constexpr auto imageType = "jpg"_L1; + + // Write out the graph to a temporary file + QTemporaryFile dotFile(QDir::tempPath() + u'/' + name + u"_XXXXXX.dot"_s); + if (!dotFile.open()) { + qWarning("Cannot open temporary file: %s", qPrintable(dotFile.errorString())); + return false; + } + const QString tempDotFile = dotFile.fileName(); + dotFile.write(graph.toUtf8()); + dotFile.close(); + + // Convert to image using "dot" + const QString imageFile = tempDotFile.left(tempDotFile.size() - 3) + imageType; + QProcess process; + process.start(u"dot"_s, {u"-T"_s + imageType, u"-o"_s + imageFile, tempDotFile}); + if (!process.waitForStarted() || !process.waitForFinished()) { + qWarning("Image conversion failed: %s", qPrintable(process.errorString())); + return false; + } + if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) { + qWarning("Image conversion failed (%d): %s", + process.exitCode(), + process.readAllStandardError().constData()); + return false; + } + + // Launch image. Should use QDesktopServices::openUrl(), + // but we don't link against QtGui +#ifdef Q_OS_UNIX + constexpr auto imageViewer = "gwenview"_L1; +#else + constexpr auto imageViewer = "mspaint"_L1; +#endif + if (!QProcess::startDetached(imageViewer, {imageFile})) { + qWarning("Failed to launch viewer: %s", qPrintable(imageViewer)); + return false; + } + qInfo().noquote().nospace() << "Viewing: " + << QDir::toNativeSeparators(tempDotFile) + << ' ' << QDir::toNativeSeparators(imageFile); + return true; +} diff --git a/sources/shiboken6/ApiExtractor/dotview.h b/sources/shiboken6/ApiExtractor/dotview.h new file mode 100644 index 000000000..87fb7db65 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/dotview.h @@ -0,0 +1,14 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef DOTVIEW_H +#define DOTVIEW_H + +#include <QtCore/QString> + +/// Show a dot digraph in an image viewer +/// \param name base name for files +/// \param graph graph +bool showDotGraph(const QString &name, const QString &graph); + +#endif // DOTVIEW_H diff --git a/sources/shiboken6/ApiExtractor/doxygenparser.cpp b/sources/shiboken6/ApiExtractor/doxygenparser.cpp index 90072c227..da790015f 100644 --- a/sources/shiboken6/ApiExtractor/doxygenparser.cpp +++ b/sources/shiboken6/ApiExtractor/doxygenparser.cpp @@ -1,57 +1,38 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "doxygenparser.h" +#include "abstractmetaargument.h" #include "abstractmetalang.h" #include "abstractmetafield.h" #include "abstractmetafunction.h" #include "abstractmetaenum.h" +#include "abstractmetatype.h" #include "documentation.h" #include "messages.h" #include "modifications.h" #include "propertyspec.h" #include "reporthandler.h" -#include "typesystem.h" +#include "complextypeentry.h" #include "xmlutils.h" +#include "qtcompat.h" + #include <QtCore/QFile> #include <QtCore/QDir> +using namespace Qt::StringLiterals; + static QString getSectionKindAttr(const AbstractMetaFunctionCPtr &func) { if (func->isSignal()) - return QLatin1String("signal"); + return u"signal"_s; QString kind = func->isPublic() - ? QLatin1String("public") : QLatin1String("protected"); + ? u"public"_s : u"protected"_s; if (func->isStatic()) - kind += QLatin1String("-static"); + kind += u"-static"_s; else if (func->isSlot()) - kind += QLatin1String("-slot"); + kind += u"-slot"_s; return kind; } @@ -60,7 +41,7 @@ Documentation DoxygenParser::retrieveModuleDocumentation() return retrieveModuleDocumentation(packageName()); } -void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass) +void DoxygenParser::fillDocumentation(const AbstractMetaClassPtr &metaClass) { if (!metaClass) return; @@ -68,18 +49,17 @@ void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass) QString doxyFileSuffix; if (metaClass->enclosingClass()) { doxyFileSuffix += metaClass->enclosingClass()->name(); - doxyFileSuffix += QLatin1String("_1_1"); // FIXME: Check why _1_1!! + doxyFileSuffix += u"_1_1"_s; // FIXME: Check why _1_1!! } doxyFileSuffix += metaClass->name(); - doxyFileSuffix += QLatin1String(".xml"); + doxyFileSuffix += u".xml"_s; - const char* prefixes[] = { "class", "struct", "namespace" }; + static constexpr QLatin1StringView prefixes[] = { "class"_L1, "struct"_L1, "namespace"_L1 }; bool isProperty = false; QString doxyFilePath; - for (const char *prefix : prefixes) { - doxyFilePath = documentationDataDirectory() + QLatin1Char('/') - + QLatin1String(prefix) + doxyFileSuffix; + for (const auto &prefix : prefixes) { + doxyFilePath = documentationDataDirectory() + u'/' + prefix + doxyFileSuffix; if (QFile::exists(doxyFilePath)) break; doxyFilePath.clear(); @@ -95,20 +75,20 @@ void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass) QString errorMessage; XQueryPtr xquery = XQuery::create(doxyFilePath, &errorMessage); - if (xquery.isNull()) { + if (!xquery) { qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); return; } - static const QList<QPair<Documentation::Type, QString>> docTags = { - { Documentation::Brief, QLatin1String("briefdescription") }, - { Documentation::Detailed, QLatin1String("detaileddescription") } + static const QList<std::pair<Documentation::Type, QString>> docTags = { + { Documentation::Brief, u"briefdescription"_s }, + { Documentation::Detailed, u"detaileddescription"_s } }; // Get class documentation Documentation classDoc; for (const auto &tag : docTags) { - const QString classQuery = QLatin1String("/doxygen/compounddef/") + tag.second; + const QString classQuery = u"/doxygen/compounddef/"_s + tag.second; QString doc = getDocumentation(xquery, classQuery, metaClass->typeEntry()->docModifications()); if (doc.isEmpty()) @@ -123,37 +103,37 @@ void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass) //Functions Documentation const auto &funcs = DocParser::documentableFunctions(metaClass); for (const auto &func : funcs) { - QString query = QLatin1String("/doxygen/compounddef/sectiondef"); + QString query = u"/doxygen/compounddef/sectiondef"_s; // properties if (func->isPropertyReader() || func->isPropertyWriter() || func->isPropertyResetter()) { const auto prop = metaClass->propertySpecs().at(func->propertySpecIndex()); - query += QLatin1String("[@kind=\"property\"]/memberdef/name[text()=\"") - + prop.name() + QLatin1String("\"]"); + query += u"[@kind=\"property\"]/memberdef/name[text()=\""_s + + prop.name() + u"\"]"_s; isProperty = true; } else { // normal methods QString kind = getSectionKindAttr(func); - query += QLatin1String("[@kind=\"") + kind - + QLatin1String("-func\"]/memberdef/name[text()=\"") - + func->originalName() + QLatin1String("\"]"); + query += u"[@kind=\""_s + kind + + u"-func\"]/memberdef/name[text()=\""_s + + func->originalName() + u"\"]"_s; if (func->arguments().isEmpty()) { - QString args = func->isConstant() ? QLatin1String("() const ") : QLatin1String("()"); - query += QLatin1String("/../argsstring[text()=\"") + args + QLatin1String("\"]"); + QString args = func->isConstant() ? u"() const"_s : u"()"_s; + query += u"/../argsstring[text()=\""_s + args + u"\"]"_s; } else { int i = 1; const AbstractMetaArgumentList &arguments = func->arguments(); for (const AbstractMetaArgument &arg : arguments) { if (!arg.type().isPrimitive()) { - query += QLatin1String("/../param[") + QString::number(i) - + QLatin1String("]/type/ref[text()=\"") + query += u"/../param["_s + QString::number(i) + + u"]/type/ref[text()=\""_s + arg.type().cppSignature().toHtmlEscaped() - + QLatin1String("\"]/../.."); + + u"\"]/../.."_s; } else { - query += QLatin1String("/../param[") + QString::number(i) - + QLatin1String("]/type[text(), \"") + query += u"/../param["_s + QString::number(i) + + u"]/type[text(), \""_s + arg.type().cppSignature().toHtmlEscaped() - + QLatin1String("\"]/.."); + + u"\"]/.."_s; } ++i; } @@ -163,22 +143,23 @@ void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass) for (const auto &tag : docTags) { QString funcQuery(query); if (!isProperty) { - funcQuery += QLatin1String("/../") + tag.second; + funcQuery += u"/../"_s + tag.second; } else { - funcQuery = QLatin1Char('(') + funcQuery; - funcQuery += QLatin1String("/../%1)[1]").arg(tag.second); + funcQuery = u'(' + funcQuery; + funcQuery += u"/../"_s + tag.second + u")[1]"_s; } - QString doc = getDocumentation(xquery, funcQuery, DocModificationList()); + QString doc = getDocumentation(xquery, funcQuery, + DocParser::getXpathDocModifications(func, metaClass)); if (doc.isEmpty()) { qCWarning(lcShibokenDoc, "%s", - qPrintable(msgCannotFindDocumentation(doxyFilePath, metaClass, func.data(), + qPrintable(msgCannotFindDocumentation(doxyFilePath, func.get(), funcQuery))); } else { funcDoc.setValue(doc, tag.first); } } - qSharedPointerConstCast<AbstractMetaFunction>(func)->setDocumentation(funcDoc); + std::const_pointer_cast<AbstractMetaFunction>(func)->setDocumentation(funcDoc); isProperty = false; } @@ -189,8 +170,8 @@ void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass) Documentation fieldDoc; for (const auto &tag : docTags) { - QString query = QLatin1String("/doxygen/compounddef/sectiondef/memberdef/name[text()=\"") - + field.name() + QLatin1String("\"]/../") + tag.second; + QString query = u"/doxygen/compounddef/sectiondef/memberdef/name[text()=\""_s + + field.name() + u"\"]/../"_s + tag.second; QString doc = getDocumentation(xquery, query, DocModificationList()); if (doc.isEmpty()) { qCWarning(lcShibokenDoc, "%s", @@ -205,8 +186,8 @@ void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass) //Enums for (AbstractMetaEnum &meta_enum : metaClass->enums()) { - QString query = QLatin1String("/doxygen/compounddef/sectiondef/memberdef[@kind=\"enum\"]/name[text()=\"") - + meta_enum.name() + QLatin1String("\"]/.."); + QString query = u"/doxygen/compounddef/sectiondef/memberdef[@kind=\"enum\"]/name[text()=\""_s + + meta_enum.name() + u"\"]/.."_s; QString doc = getDocumentation(xquery, query, DocModificationList()); if (doc.isEmpty()) { qCWarning(lcShibokenDoc, "%s", @@ -219,24 +200,24 @@ void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass) Documentation DoxygenParser::retrieveModuleDocumentation(const QString& name){ - QString sourceFile = documentationDataDirectory() + QLatin1String("/indexpage.xml"); + QString sourceFile = documentationDataDirectory() + u"/indexpage.xml"_s; if (!QFile::exists(sourceFile)) { qCWarning(lcShibokenDoc).noquote().nospace() << "Can't find doxygen XML file for module " << name << ", tried: " << QDir::toNativeSeparators(sourceFile); - return Documentation(); + return {}; } QString errorMessage; XQueryPtr xquery = XQuery::create(sourceFile, &errorMessage); - if (xquery.isNull()) { + if (!xquery) { qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); return {}; } // Module documentation - QString query = QLatin1String("/doxygen/compounddef/detaileddescription"); + QString query = u"/doxygen/compounddef/detaileddescription"_s; const QString doc = getDocumentation(xquery, query, DocModificationList()); return Documentation(doc, {}); } diff --git a/sources/shiboken6/ApiExtractor/doxygenparser.h b/sources/shiboken6/ApiExtractor/doxygenparser.h index ada64ac18..4f6a9e53c 100644 --- a/sources/shiboken6/ApiExtractor/doxygenparser.h +++ b/sources/shiboken6/ApiExtractor/doxygenparser.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef DOXYGENPARSER_H #define DOXYGENPARSER_H @@ -35,7 +10,7 @@ class DoxygenParser : public DocParser { public: DoxygenParser() = default; - void fillDocumentation(AbstractMetaClass *metaClass) override; + void fillDocumentation(const AbstractMetaClassPtr &metaClass) override; Documentation retrieveModuleDocumentation() override; Documentation retrieveModuleDocumentation(const QString& name) override; }; diff --git a/sources/shiboken6/ApiExtractor/enclosingclassmixin.cpp b/sources/shiboken6/ApiExtractor/enclosingclassmixin.cpp index 5d6394f11..2421ae527 100644 --- a/sources/shiboken6/ApiExtractor/enclosingclassmixin.cpp +++ b/sources/shiboken6/ApiExtractor/enclosingclassmixin.cpp @@ -1,38 +1,13 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "enclosingclassmixin.h" #include "abstractmetalang.h" -#include "typesystem.h" +#include "namespacetypeentry.h" -const AbstractMetaClass *EnclosingClassMixin::targetLangEnclosingClass() const +AbstractMetaClassCPtr EnclosingClassMixin::targetLangEnclosingClass() const { - auto result = m_enclosingClass; + auto result = m_enclosingClass.lock(); while (result && !NamespaceTypeEntry::isVisibleScope(result->typeEntry())) result = result->enclosingClass(); return result; diff --git a/sources/shiboken6/ApiExtractor/enclosingclassmixin.h b/sources/shiboken6/ApiExtractor/enclosingclassmixin.h index 61fbc816f..8d735d5ec 100644 --- a/sources/shiboken6/ApiExtractor/enclosingclassmixin.h +++ b/sources/shiboken6/ApiExtractor/enclosingclassmixin.h @@ -1,44 +1,24 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ENCLOSINGCLASSMIXIN_H #define ENCLOSINGCLASSMIXIN_H +#include "abstractmetalang_typedefs.h" + class AbstractMetaClass; class EnclosingClassMixin { public: - const AbstractMetaClass *enclosingClass() const { return m_enclosingClass; } - void setEnclosingClass(const AbstractMetaClass *cls) { m_enclosingClass = cls; } - const AbstractMetaClass *targetLangEnclosingClass() const; + + const AbstractMetaClassCPtr enclosingClass() const + { return m_enclosingClass.lock(); } + void setEnclosingClass(const AbstractMetaClassCPtr &cls) + { m_enclosingClass = cls; } + AbstractMetaClassCPtr targetLangEnclosingClass() const; private: - const AbstractMetaClass *m_enclosingClass = nullptr; + std::weak_ptr<const AbstractMetaClass> m_enclosingClass; }; #endif // ENCLOSINGCLASSMIXIN_H diff --git a/sources/shiboken6/ApiExtractor/enumtypeentry.h b/sources/shiboken6/ApiExtractor/enumtypeentry.h new file mode 100644 index 000000000..3360d7db5 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/enumtypeentry.h @@ -0,0 +1,51 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef ENUMTYPEENTRY_H +#define ENUMTYPEENTRY_H + +#include "configurabletypeentry.h" +#include "typesystem_enums.h" + +class EnumTypeEntryPrivate; + +// EnumTypeEntry is configurable for global enums only +class EnumTypeEntry : public ConfigurableTypeEntry +{ +public: + explicit EnumTypeEntry(const QString &entryName, + const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + TypeSystem::PythonEnumType pythonEnumType() const; + void setPythonEnumType(TypeSystem::PythonEnumType t); + + QString targetLangQualifier() const; + + QString qualifier() const; + + EnumValueTypeEntryCPtr nullValue() const; + void setNullValue(const EnumValueTypeEntryCPtr &n); + + void setFlags(const FlagsTypeEntryPtr &flags); + FlagsTypeEntryPtr flags() const; + + QString cppType() const; + void setCppType(const QString &t); + + bool isEnumValueRejected(const QString &name) const; + void addEnumValueRejection(const QString &name); + QStringList enumValueRejections() const; + + QString docFile() const; + void setDocFile(const QString &df); + + TypeEntry *clone() const override; +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif +protected: + explicit EnumTypeEntry(EnumTypeEntryPrivate *d); +}; + +#endif // ENUMTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/enumvaluetypeentry.h b/sources/shiboken6/ApiExtractor/enumvaluetypeentry.h new file mode 100644 index 000000000..006b84e0a --- /dev/null +++ b/sources/shiboken6/ApiExtractor/enumvaluetypeentry.h @@ -0,0 +1,31 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef ENUMVALUETYPEENTRY_H +#define ENUMVALUETYPEENTRY_H + +#include "typesystem.h" + +class EnumTypeEntry; +class EnumValueTypeEntryPrivate; + +// EnumValueTypeEntry is used for resolving integer type templates +// like array<EnumValue>. Note: Dummy entries for integer values will +// be created for non-type template parameters, where m_enclosingEnum==nullptr. +class EnumValueTypeEntry : public TypeEntry +{ +public: + explicit EnumValueTypeEntry(const QString& name, const QString& value, + const EnumTypeEntryCPtr &enclosingEnum, + bool isScopedEnum, const QVersionNumber &vr); + + QString value() const; + EnumTypeEntryCPtr enclosingEnum() const; + + TypeEntry *clone() const override; + +protected: + explicit EnumValueTypeEntry(EnumValueTypeEntryPrivate *d); +}; + +#endif // ENUMVALUETYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/exception.h b/sources/shiboken6/ApiExtractor/exception.h index 36e94638a..396b56f5d 100644 --- a/sources/shiboken6/ApiExtractor/exception.h +++ b/sources/shiboken6/ApiExtractor/exception.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef EXCEPTION_H #define EXCEPTION_H -#include <QString> +#include <QtCore/QString> #include <string> #include <exception> diff --git a/sources/shiboken6/ApiExtractor/fileout.cpp b/sources/shiboken6/ApiExtractor/fileout.cpp index 84455dd9e..6f9ec4d8a 100644 --- a/sources/shiboken6/ApiExtractor/fileout.cpp +++ b/sources/shiboken6/ApiExtractor/fileout.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "fileout.h" #include "messages.h" @@ -67,20 +42,20 @@ FileOut::~FileOut() } } -static QList<int> lcsLength(const QByteArrayList &a, const QByteArrayList &b) +static QList<qsizetype> lcsLength(const QByteArrayList &a, const QByteArrayList &b) { - const int height = a.size() + 1; - const int width = b.size() + 1; + const auto height = a.size() + 1; + const auto width = b.size() + 1; - QList<int> res(width * height, 0); + QList<qsizetype> res(width * height, 0); - for (int row = 1; row < height; row++) { - for (int col = 1; col < width; col++) { - if (a[row-1] == b[col-1]) - res[width * row + col] = res[width * (row-1) + col-1] + 1; + for (qsizetype row = 1; row < height; row++) { + for (qsizetype col = 1; col < width; col++) { + if (a.at(row - 1) == b.at(col - 1)) + res[width * row + col] = res[width * (row - 1) + col - 1] + 1; else - res[width * row + col] = qMax(res[width * row + col-1], - res[width * (row-1) + col]); + res[width * row + col] = qMax(res[width * row + col - 1], + res[width * (row - 1) + col]); } } return res; @@ -95,8 +70,8 @@ enum Type { struct Unit { Type type; - int start; - int end; + qsizetype start; + qsizetype end; void print(const QByteArrayList &a, const QByteArrayList &b) const; }; @@ -106,33 +81,33 @@ void Unit::print(const QByteArrayList &a, const QByteArrayList &b) const switch (type) { case Unchanged: if ((end - start) > 9) { - for (int i = start; i <= start + 2; i++) + for (auto i = start; i <= start + 2; ++i) std::printf(" %s\n", a.at(i).constData()); std::printf("%s=\n= %d more lines\n=%s\n", - colorInfo, end - start - 6, colorReset); - for (int i = end - 2; i <= end; i++) + colorInfo, int(end - start - 6), colorReset); + for (auto i = end - 2; i <= end; ++i) std::printf(" %s\n", a.at(i).constData()); } else { - for (int i = start; i <= end; i++) + for (auto i = start; i <= end; ++i) std::printf(" %s\n", a.at(i).constData()); } break; case Add: std::fputs(colorAdd, stdout); - for (int i = start; i <= end; i++) + for (auto i = start; i <= end; ++i) std::printf("+ %s\n", b.at(i).constData()); std::fputs(colorReset, stdout); break; case Delete: std::fputs(colorDelete, stdout); - for (int i = start; i <= end; i++) + for (auto i = start; i <= end; ++i) std::printf("- %s\n", a.at(i).constData()); std::fputs(colorReset, stdout); break; } } -static void unitAppend(Type type, int pos, QList<Unit> *units) +static void unitAppend(Type type, qsizetype pos, QList<Unit> *units) { if (!units->isEmpty() && units->last().type == type) units->last().end = pos; @@ -140,9 +115,9 @@ static void unitAppend(Type type, int pos, QList<Unit> *units) units->append(Unit{type, pos, pos}); } -static QList<Unit> diffHelper(const QList<int> &lcs, - const QByteArrayList &a, const QByteArrayList &b, - int row, int col) +static QList<Unit> diffHelper(const QList<qsizetype> &lcs, + const QByteArrayList &a, const QByteArrayList &b, + qsizetype row, qsizetype col) { if (row > 0 && col > 0 && a.at(row - 1) == b.at(col - 1)) { QList<Unit> result = diffHelper(lcs, a, b, row - 1, col - 1); @@ -150,7 +125,7 @@ static QList<Unit> diffHelper(const QList<int> &lcs, return result; } - const int width = b.size() + 1; + const auto width = b.size() + 1; if (col > 0 && (row == 0 || lcs.at(width * row + col -1 ) >= lcs.at(width * (row - 1) + col))) { QList<Unit> result = diffHelper(lcs, a, b, row, col - 1); @@ -200,7 +175,7 @@ FileOut::State FileOut::done() if (!FileOut::m_dryRun) { QDir dir(info.absolutePath()); if (!dir.mkpath(dir.absolutePath())) { - const QString message = QStringLiteral("Unable to create directory '%1'") + const QString message = QString::fromLatin1("Unable to create directory '%1'") .arg(QDir::toNativeSeparators(dir.absolutePath())); throw Exception(message); } diff --git a/sources/shiboken6/ApiExtractor/fileout.h b/sources/shiboken6/ApiExtractor/fileout.h index 5b5f33578..b11ad1e20 100644 --- a/sources/shiboken6/ApiExtractor/fileout.h +++ b/sources/shiboken6/ApiExtractor/fileout.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef FILEOUT_H #define FILEOUT_H @@ -39,7 +14,7 @@ class FileOut { QByteArray m_buffer; public: - Q_DISABLE_COPY(FileOut) + Q_DISABLE_COPY_MOVE(FileOut) enum State { Unchanged, Success }; diff --git a/sources/shiboken6/ApiExtractor/flagstypeentry.h b/sources/shiboken6/ApiExtractor/flagstypeentry.h new file mode 100644 index 000000000..6eddcd12b --- /dev/null +++ b/sources/shiboken6/ApiExtractor/flagstypeentry.h @@ -0,0 +1,36 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef FLAGSTYPEENTRY_H +#define FLAGSTYPEENTRY_H + +#include "typesystem.h" + +class EnumTypeEntry; +class FlagsTypeEntryPrivate; + +// FlagsTypeEntry is configurable for global flags only +class FlagsTypeEntry : public TypeEntry +{ +public: + explicit FlagsTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + QString originalName() const; + void setOriginalName(const QString &s); + + QString flagsName() const; + void setFlagsName(const QString &name); + + EnumTypeEntryPtr originator() const; + void setOriginator(const EnumTypeEntryPtr &e); + + TypeEntry *clone() const override; + +protected: + explicit FlagsTypeEntry(FlagsTypeEntryPrivate *d); + + QString buildTargetLangName() const override; +}; + +#endif // FLAGSTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/functiontypeentry.h b/sources/shiboken6/ApiExtractor/functiontypeentry.h new file mode 100644 index 000000000..53aa1fad6 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/functiontypeentry.h @@ -0,0 +1,35 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef FUNCTIONTYPEENTRY_H +#define FUNCTIONTYPEENTRY_H + +#include "typesystem.h" + +class FunctionTypeEntryPrivate; + +class FunctionTypeEntry : public TypeEntry +{ +public: + explicit FunctionTypeEntry(const QString& name, const QString& signature, + const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + const QStringList &signatures() const; + bool hasSignature(const QString& signature) const; + void addSignature(const QString& signature); + + QString docFile() const; + void setDocFile(const QString &df); + + TypeEntry *clone() const override; + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +protected: + explicit FunctionTypeEntry(FunctionTypeEntryPrivate *d); +}; + +#endif // FUNCTIONTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/graph.h b/sources/shiboken6/ApiExtractor/graph.h index 0961f85af..447a26da0 100644 --- a/sources/shiboken6/ApiExtractor/graph.h +++ b/sources/shiboken6/ApiExtractor/graph.h @@ -1,34 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef GRAPH_H #define GRAPH_H +#include "dotview.h" + #include <QtCore/QDebug> #include <QtCore/QFile> #include <QtCore/QHash> @@ -98,6 +75,10 @@ public: /// \param f function returning the name of a node template <class NameFunction> bool dumpDot(const QString& fileName, NameFunction f) const; + template <class NameFunction> + void formatDot(QTextStream &str, NameFunction f) const; + template <class NameFunction> + bool showGraph(const QString &name, NameFunction f) const; void format(QDebug &debug) const; @@ -251,6 +232,15 @@ bool Graph<Node>::dumpDot(const QString& fileName, if (!output.open(QIODevice::WriteOnly)) return false; QTextStream s(&output); + formatDot(s, nameFunction); + return true; +} + +template <class Node> +template <class NameFunction> +void Graph<Node>::formatDot(QTextStream &s, + NameFunction nameFunction) const +{ s << "digraph D {\n"; for (const auto &nodeEntry : m_nodeEntries) { if (!nodeEntry.targets.isEmpty()) { @@ -260,7 +250,16 @@ bool Graph<Node>::dumpDot(const QString& fileName, } } s << "}\n"; - return true; +} + +template <class Node> +template <class NameFunction> +bool Graph<Node>::showGraph(const QString &name, NameFunction f) const +{ + QString graph; + QTextStream s(&graph); + formatDot(s, f); + return showDotGraph(name, graph); } template <class Node> diff --git a/sources/shiboken6/ApiExtractor/header_paths.h b/sources/shiboken6/ApiExtractor/header_paths.h index 0c25702ef..af4a768e8 100644 --- a/sources/shiboken6/ApiExtractor/header_paths.h +++ b/sources/shiboken6/ApiExtractor/header_paths.h @@ -1,37 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef HEADER_PATHS_H #define HEADER_PATHS_H -#include <QByteArray> -#include <QList> -#include <QString> +#include <QtCore/QByteArray> +#include <QtCore/QList> enum class HeaderType { diff --git a/sources/shiboken6/ApiExtractor/icecc.cmake b/sources/shiboken6/ApiExtractor/icecc.cmake index b2bf071aa..fa8d3b7cf 100644 --- a/sources/shiboken6/ApiExtractor/icecc.cmake +++ b/sources/shiboken6/ApiExtractor/icecc.cmake @@ -1,3 +1,6 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + include (CMakeForceCompiler) option(ENABLE_ICECC "Enable icecc checking, for distributed compilation") if (ENABLE_ICECC) diff --git a/sources/shiboken6/ApiExtractor/include.cpp b/sources/shiboken6/ApiExtractor/include.cpp index ea31d000a..aee6b7337 100644 --- a/sources/shiboken6/ApiExtractor/include.cpp +++ b/sources/shiboken6/ApiExtractor/include.cpp @@ -1,56 +1,44 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "include.h" #include "textstream.h" -#include <QDebug> -#include <QDir> -#include <QTextStream> -#include <QHash> + +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QHash> +#include <QtCore/QTextStream> + +#include "qtcompat.h" + +#include <algorithm> + +using namespace Qt::StringLiterals; QString Include::toString() const { if (m_type == IncludePath) - return QLatin1String("#include <") + m_name + QLatin1Char('>'); + return u"#include <"_s + m_name + u'>'; if (m_type == LocalPath) - return QLatin1String("#include \"") + m_name + QLatin1Char('"'); - return QLatin1String("import ") + m_name + QLatin1Char(';'); + return u"#include \""_s + m_name + u'"'; + return u"import "_s + m_name + u';'; } -size_t qHash(const Include& inc) +Qt::strong_ordering compareThreeWay(const Include &lhs, const Include &rhs) noexcept { - return qHash(inc.m_name); + if (lhs.m_type < rhs.m_type) + return Qt::strong_ordering::less; + if (lhs.m_type > rhs.m_type) + return Qt::strong_ordering::greater; + if (auto c = lhs.m_name.compare(rhs.m_name)) + return c < 0 ? Qt::strong_ordering::less : Qt::strong_ordering::greater; + return Qt::strong_ordering::equal; } -QTextStream& operator<<(QTextStream& out, const Include& include) +QTextStream& operator<<(QTextStream& out, const Include& g) { - if (include.isValid()) - out << include.toString() << Qt::endl; + if (g.isValid()) + out << g.toString() << Qt::endl; return out; } @@ -61,6 +49,19 @@ TextStream& operator<<(TextStream& out, const Include& include) return out; } +TextStream& operator<<(TextStream &out, const IncludeGroup& g) +{ + if (!g.includes.isEmpty()) { + if (!g.title.isEmpty()) + out << "\n// " << g.title << "\n"; + auto includes = g.includes; + std::sort(includes.begin(), includes.end()); + for (const Include &inc : std::as_const(includes)) + out << inc.toString() << '\n'; + } + return out; +} + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const Include &i) { diff --git a/sources/shiboken6/ApiExtractor/include.h b/sources/shiboken6/ApiExtractor/include.h index 405a8e3fb..875a941f9 100644 --- a/sources/shiboken6/ApiExtractor/include.h +++ b/sources/shiboken6/ApiExtractor/include.h @@ -1,36 +1,13 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef INCLUDE_H #define INCLUDE_H -#include <QString> -#include <QList> +#include <QtCore/QtCompare> +#include <QtCore/QHashFunctions> +#include <QtCore/QString> +#include <QtCore/QList> QT_BEGIN_NAMESPACE class QTextStream; @@ -67,23 +44,25 @@ public: QString toString() const; - bool operator<(const Include& other) const + int compare(const Include &rhs) const; + +private: + friend size_t qHash(Include &inc, size_t seed = 0) noexcept { - return m_name < other.m_name; + return qHashMulti(seed, inc.m_type, inc.m_name); } - - bool operator==(const Include& other) const + friend bool comparesEqual(const Include &lhs, const Include &rhs) noexcept { - return m_type == other.m_type && m_name == other.m_name; + return lhs.m_type == rhs.m_type && lhs.m_name == rhs.m_name; } + friend Qt::strong_ordering compareThreeWay(const Include &lhs, + const Include &rhs) noexcept; + Q_DECLARE_STRONGLY_ORDERED(Include) - friend size_t qHash(const Include&); - private: - IncludeType m_type = IncludePath; - QString m_name; + IncludeType m_type = IncludePath; + QString m_name; }; -size_t qHash(const Include& inc); QTextStream& operator<<(QTextStream& out, const Include& include); TextStream& operator<<(TextStream& out, const Include& include); #ifndef QT_NO_DEBUG_STREAM @@ -92,4 +71,25 @@ QDebug operator<<(QDebug d, const Include &i); using IncludeList = QList<Include>; +struct IncludeGroup +{ + QString title; + IncludeList includes; + + void append(const Include &include) + { + IncludeGroup::appendInclude(include, &includes); + } + + static void appendInclude(const Include &include, IncludeList *list) + { + if (include.isValid() && !list->contains(include)) + list->append(include); + } +}; + +TextStream& operator<<(TextStream &out, const IncludeGroup& include); + +using IncludeGroupList = QList<IncludeGroup>; + #endif diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp index 1f79000e2..f9f46f520 100644 --- a/sources/shiboken6/ApiExtractor/messages.cpp +++ b/sources/shiboken6/ApiExtractor/messages.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "messages.h" #include "abstractmetaenum.h" @@ -34,21 +9,40 @@ #include "modifications.h" #include "sourcelocation.h" #include "typedatabase.h" -#include "typesystem.h" +#include "functiontypeentry.h" +#include "enumtypeentry.h" +#include "smartpointertypeentry.h" #include <codemodel.h> -#include <QtCore/QCoreApplication> +#include "qtcompat.h" + #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFile> #include <QtCore/QStringList> #include <QtCore/QXmlStreamReader> -static inline QString colonColon() { return QStringLiteral("::"); } +using namespace Qt::StringLiterals; // abstractmetabuilder.cpp -QString msgNoFunctionForModification(const AbstractMetaClass *klass, +static QTextStream &operator<<(QTextStream &s, Access a) +{ + switch (a) { + case Access::Public: + s << "public"; + break; + case Access::Protected: + s << "protected"; + break; + case Access::Private: + s << "private"; + break; + } + return s; +} + +QString msgNoFunctionForModification(const AbstractMetaClassCPtr &klass, const QString &signature, const QString &originalSignature, const QStringList &possibleSignatures, @@ -68,8 +62,8 @@ QString msgNoFunctionForModification(const AbstractMetaClass *klass, str << " " << s << '\n'; } else if (!allFunctions.isEmpty()) { str << "\n No candidates were found. Member functions:\n"; - const int maxCount = qMin(10, allFunctions.size()); - for (int f = 0; f < maxCount; ++f) + const auto maxCount = qMin(qsizetype(10), allFunctions.size()); + for (qsizetype f = 0; f < maxCount; ++f) str << " " << allFunctions.at(f)->minimalSignature() << '\n'; if (maxCount < allFunctions.size()) str << " ...\n"; @@ -77,6 +71,67 @@ QString msgNoFunctionForModification(const AbstractMetaClass *klass, return result; } +QString msgArgumentIndexOutOfRange(const AbstractMetaFunction *func, int index) +{ + QString result; + QTextStream str(&result); + str <<"Index " << index << " out of range for " << func->classQualifiedSignature() << '.'; + return result; +} + +QString msgTypeModificationFailed(const QString &type, int n, + const AbstractMetaFunction *func, + const QString &why) +{ + QString result; + QTextStream str(&result); + str << "Unable to modify the "; + if (n == 0) + str << "return type"; + else + str << "type of argument " << n; + + str << " of "; + if (auto c = func->ownerClass()) + str << c->name() << "::"; + str << func->signature() << " to \"" << type << "\": " << why; + return result; +} + +QString msgInvalidArgumentModification(const AbstractMetaFunctionCPtr &func, + int argIndex) +{ + QString result; + QTextStream str(&result); + str << "Invalid "; + if (argIndex == 0) + str << "return type modification"; + else + str << "modification of argument " << argIndex; + str << " for " << func->classQualifiedSignature(); + return result; +} + +QString msgArgumentOutOfRange(int number, int minValue, int maxValue) +{ + QString result; + QTextStream(&result) << "Argument number " << number + << " out of range " << minValue << ".." << maxValue << '.'; + return result; +} + +QString msgArgumentRemovalFailed(const AbstractMetaFunction *func, int n, + const QString &why) +{ + QString result; + QTextStream str(&result); + str << "Unable to remove argument " << n << " of "; + if (auto c = func->ownerClass()) + str << c->name() << "::"; + str << func->signature() << ": " << why; + return result; +} + template <class Stream> static void msgFormatEnumType(Stream &str, const EnumModelItem &enumItem, @@ -84,7 +139,7 @@ static void msgFormatEnumType(Stream &str, { switch (enumItem->enumKind()) { case CEnum: - str << "Enum '" << enumItem->qualifiedName().join(colonColon()) << '\''; + str << "Enum '" << enumItem->qualifiedName().join(u"::"_s) << '\''; break; case AnonymousEnum: { const EnumeratorList &values = enumItem->enumerators(); @@ -107,7 +162,7 @@ static void msgFormatEnumType(Stream &str, } break; case EnumClass: - str << "Scoped enum '" << enumItem->qualifiedName().join(colonColon()) << '\''; + str << "Scoped enum '" << enumItem->qualifiedName().join(u"::"_s) << '\''; break; } if (!className.isEmpty()) @@ -115,7 +170,7 @@ static void msgFormatEnumType(Stream &str, } static void formatAddedFuncError(const QString &addedFuncName, - const AbstractMetaClass *context, + const AbstractMetaClassCPtr &context, QTextStream &str) { if (context) { @@ -131,12 +186,12 @@ static void formatAddedFuncError(const QString &addedFuncName, QString msgAddedFunctionInvalidArgType(const QString &addedFuncName, const QStringList &typeName, int pos, const QString &why, - const AbstractMetaClass *context) + const AbstractMetaClassCPtr &context) { QString result; QTextStream str(&result); formatAddedFuncError(addedFuncName, context, str); - str << "Unable to translate type \"" << typeName.join(colonColon()) + str << "Unable to translate type \"" << typeName.join(u"::"_s) << "\" of argument " << pos << " of added function \"" << addedFuncName << "\": " << why; return result; @@ -144,18 +199,18 @@ QString msgAddedFunctionInvalidArgType(const QString &addedFuncName, QString msgAddedFunctionInvalidReturnType(const QString &addedFuncName, const QStringList &typeName, const QString &why, - const AbstractMetaClass *context) + const AbstractMetaClassCPtr &context) { QString result; QTextStream str(&result); formatAddedFuncError(addedFuncName, context, str); - str << "Unable to translate return type \"" << typeName.join(colonColon()) + str << "Unable to translate return type \"" << typeName.join(u"::"_s) << "\" of added function \"" << addedFuncName << "\": " << why; return result; } -QString msgUnnamedArgumentDefaultExpression(const AbstractMetaClass *context, +QString msgUnnamedArgumentDefaultExpression(const AbstractMetaClassCPtr &context, int n, const QString &className, const AbstractMetaFunction *f) { @@ -168,7 +223,7 @@ QString msgUnnamedArgumentDefaultExpression(const AbstractMetaClass *context, return result; } -QString msgClassOfEnumNotFound(const EnumTypeEntry *entry) +QString msgClassOfEnumNotFound(const EnumTypeEntryCPtr &entry) { QString result; QTextStream str(&result); @@ -185,13 +240,14 @@ QString msgNoEnumTypeEntry(const EnumModelItem &enumItem, QTextStream str(&result); str << enumItem->sourceLocation(); msgFormatEnumType(str, enumItem, className); - str << " does not have a type entry"; + str << " does not have a type entry (type systems: " + << TypeDatabase::instance()->loadedTypeSystemNames() << ')'; return result; } QString msgNoEnumTypeConflict(const EnumModelItem &enumItem, const QString &className, - const TypeEntry *t) + const TypeEntryCPtr &t) { QString result; QDebug debug(&result); // Use the debug operator for TypeEntry::Type @@ -209,22 +265,28 @@ QString msgNamespaceNoTypeEntry(const NamespaceModelItem &item, QString result; QTextStream str(&result); str << item->sourceLocation() << "namespace '" << fullName - << "' does not have a type entry"; + << "' does not have a type entry (type systems: " + << TypeDatabase::instance()->loadedTypeSystemNames() << ')'; return result; } -QString msgAmbiguousVaryingTypesFound(const QString &qualifiedName, const TypeEntries &te) +QString msgNamespaceNotFound(const QString &name) { - QString result = QLatin1String("Ambiguous types of varying types found for \"") + qualifiedName - + QLatin1String("\": "); + return u"namespace '"_s + name + u"' not found."_s; +} + +QString msgAmbiguousVaryingTypesFound(const QString &qualifiedName, const TypeEntryCList &te) +{ + QString result = u"Ambiguous types of varying types found for \""_s + qualifiedName + + u"\": "_s; QDebug(&result) << te; return result; } -QString msgAmbiguousTypesFound(const QString &qualifiedName, const TypeEntries &te) +QString msgAmbiguousTypesFound(const QString &qualifiedName, const TypeEntryCList &te) { - QString result = QLatin1String("Ambiguous types found for \"") + qualifiedName - + QLatin1String("\": "); + QString result = u"Ambiguous types found for \""_s + qualifiedName + + u"\": "_s; QDebug(&result) << te; return result; } @@ -245,9 +307,9 @@ QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n, QString msgUnmatchedReturnType(const FunctionModelItem &functionItem, const QString &why) { - return QLatin1String("unmatched return type '") + return u"unmatched return type '"_s + functionItem->type().toString() - + QLatin1String("': ") + why; + + u"': "_s + why; } QString msgSkippingFunction(const FunctionModelItem &functionItem, @@ -255,11 +317,13 @@ QString msgSkippingFunction(const FunctionModelItem &functionItem, { QString result; QTextStream str(&result); - str << functionItem->sourceLocation() << "skipping "; - if (functionItem->isAbstract()) + str << functionItem->sourceLocation() << "skipping " + << functionItem->accessPolicy() << ' '; + const bool isAbstract = functionItem->attributes().testFlag(FunctionAttribute::Abstract); + if (isAbstract) str << "abstract "; str << "function '" << signature << "', " << why; - if (functionItem->isAbstract()) { + if (isAbstract) { str << "\nThis will lead to compilation errors due to not " "being able to instantiate the wrapper."; } @@ -272,13 +336,12 @@ QString msgShadowingFunction(const AbstractMetaFunction *f1, auto f2Class = f2->implementingClass(); QString result; QTextStream str(&result); - str << f2Class->sourceLocation() << "Shadowing: " << f1->implementingClass()->name() - << "::" << f1->signature() << " and " << f2Class->name() << "::" - << f2->signature(); + str << f2Class->sourceLocation() << "Shadowing: " << f1->classQualifiedSignature() + << " and " << f2->classQualifiedSignature(); return result; } -QString msgSignalOverloaded(const AbstractMetaClass *c, +QString msgSignalOverloaded(const AbstractMetaClassCPtr &c, const AbstractMetaFunction *f) { QString result; @@ -293,47 +356,59 @@ QString msgSkippingField(const VariableModelItem &field, const QString &classNam { QString result; QTextStream str(&result); - str << field->sourceLocation() << "skipping field '" << className - << "::" << field->name() << "' with unmatched type '" << type << '\''; + str << field->sourceLocation() << "skipping " << field->accessPolicy() + << " field '" << className << "::" << field->name() + << "' with unmatched type '" << type << '\''; return result; } static const char msgCompilationError[] = "This could potentially lead to compilation errors."; -QString msgTypeNotDefined(const TypeEntry *entry) +QString msgTypeNotDefined(const TypeEntryCPtr &entry) { QString result; QTextStream str(&result); + const bool hasConfigCondition = entry->isComplex() + && std::static_pointer_cast<const ConfigurableTypeEntry>(entry)->hasConfigCondition(); str << entry->sourceLocation() << "type '" <<entry->qualifiedCppName() - << "' is specified in typesystem, but not defined. " << msgCompilationError; + << "' is specified in typesystem, but not defined"; + if (hasConfigCondition) + str << " (disabled by configuration?)."; + else + str << ". " << msgCompilationError; return result; } -QString msgGlobalFunctionNotDefined(const FunctionTypeEntry *fte, - const QString &signature) +QString msgGlobalFunctionNotDefined(const FunctionTypeEntryCPtr &fte, + const QString &signature, + const QStringList &candidates) { QString result; QTextStream str(&result); str << fte->sourceLocation() << "Global function '" << signature - << "' is specified in typesystem, but not defined. " << msgCompilationError; + << "' is specified in typesystem, but not defined."; + if (!candidates.isEmpty()) + str << " Candidates are: " << candidates.join(u", "_s); + str << ' ' << msgCompilationError; return result; } QString msgStrippingArgument(const FunctionModelItem &f, int i, const QString &originalSignature, - const ArgumentModelItem &arg) + const ArgumentModelItem &arg, + const QString &reason) { QString result; QTextStream str(&result); str << f->sourceLocation() << "Stripping argument #" << (i + 1) << " of " << originalSignature << " due to unmatched type \"" << arg->type().toString() << "\" with default expression \"" - << arg->defaultValueExpression() << "\"."; + << arg->defaultValueExpression() << "\": " << reason; return result; } -QString msgEnumNotDefined(const EnumTypeEntry *t) +QString msgEnumNotDefined(const EnumTypeEntryCPtr &t) { QString result; QTextStream str(&result); @@ -342,7 +417,7 @@ QString msgEnumNotDefined(const EnumTypeEntry *t) return result; } -QString msgUnknownBase(const AbstractMetaClass *metaClass, +QString msgUnknownBase(const AbstractMetaClassCPtr &metaClass, const QString &baseClassName) { QString result; @@ -352,7 +427,7 @@ QString msgUnknownBase(const AbstractMetaClass *metaClass, return result; } -QString msgBaseNotInTypeSystem(const AbstractMetaClass *metaClass, +QString msgBaseNotInTypeSystem(const AbstractMetaClassCPtr &metaClass, const QString &baseClassName) { QString result; @@ -375,20 +450,18 @@ QString msgArrayModificationFailed(const FunctionModelItem &functionItem, QString msgCannotResolveEntity(const QString &name, const QString &reason) { - return QLatin1String("Cannot resolve entity \"") + name - + QLatin1String("\": ") + reason; + return u"Cannot resolve entity \""_s + name + u"\": "_s + reason; } QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason) { - return function + QLatin1String(": Cannot use parameter ") - + QString::number(i + 1) + QLatin1String(" as an array: ") + reason; + return function + u": Cannot use parameter "_s + + QString::number(i + 1) + u" as an array: "_s + reason; } QString msgUnableToTranslateType(const QString &t, const QString &why) { - return QLatin1String("Unable to translate type \"") - + t + QLatin1String("\": ") + why; + return u"Unable to translate type \""_s + t + u"\": "_s + why; } QString msgUnableToTranslateType(const TypeInfo &typeInfo, @@ -399,24 +472,24 @@ QString msgUnableToTranslateType(const TypeInfo &typeInfo, QString msgCannotFindTypeEntry(const QString &t) { - return QLatin1String("Cannot find type entry for \"") + t + QLatin1String("\"."); + return u"Cannot find type entry for \""_s + t + u"\"."_s; } QString msgCannotFindTypeEntryForSmartPointer(const QString &t, const QString &smartPointerType) { - return QLatin1String("Cannot find type entry \"") + t - + QLatin1String("\" for instantiation of \"") + smartPointerType + QLatin1String("\"."); + return u"Cannot find type entry \""_s + t + + u"\" for instantiation of \""_s +smartPointerType + u"\"."_s; } QString msgInvalidSmartPointerType(const TypeInfo &i) { - return QLatin1String("Invalid smart pointer type \"") + i.toString() + QLatin1String("\"."); + return u"Invalid smart pointer type \""_s +i.toString() + u"\"."_s; } QString msgCannotFindSmartPointerInstantion(const TypeInfo &i) { - return QLatin1String("Cannot find instantiation of smart pointer type for \"") - + i.toString() + QLatin1String("\"."); + return u"Cannot find instantiation of smart pointer type for \""_s + + i.toString() + u"\"."_s; } QString msgCannotTranslateTemplateArgument(int i, @@ -442,9 +515,9 @@ QString msgDisallowThread(const AbstractMetaFunction *f) QString msgNamespaceToBeExtendedNotFound(const QString &namespaceName, const QString &packageName) { - return QLatin1String("The namespace '") + namespaceName - + QLatin1String("' to be extended cannot be found in package ") - + packageName + QLatin1Char('.'); + return u"The namespace '"_s + namespaceName + + u"' to be extended cannot be found in package "_s + + packageName + u'.'; } QString msgPropertyTypeParsingFailed(const QString &name, const QString &typeName, @@ -459,12 +532,11 @@ QString msgPropertyTypeParsingFailed(const QString &name, const QString &typeNam QString msgPropertyExists(const QString &className, const QString &name) { - return QLatin1String("class ") + className - + QLatin1String(" already has a property \"") + name - + QLatin1String("\" (defined by Q_PROPERTY)."); + return u"class "_s + className + u" already has a property \""_s + + name + u"\" (defined by Q_PROPERTY)."_s; } -QString msgFunctionVisibilityModified(const AbstractMetaClass *c, +QString msgFunctionVisibilityModified(const AbstractMetaClassCPtr &c, const AbstractMetaFunction *f) { QString result; @@ -474,7 +546,7 @@ QString msgFunctionVisibilityModified(const AbstractMetaClass *c, return result; } -QString msgUsingMemberClassNotFound(const AbstractMetaClass *c, +QString msgUsingMemberClassNotFound(const AbstractMetaClassCPtr &c, const QString &baseClassName, const QString &memberName) { @@ -492,40 +564,73 @@ QString msgCannotFindDocumentation(const QString &fileName, const QString &query) { QString result; - QTextStream(&result) << "Cannot find documentation for " << what - << ' ' << name << " in:\n " << QDir::toNativeSeparators(fileName) - << "\n using query:\n " << query; + QTextStream str(&result); + str << "Cannot find documentation for " << what + << ' ' << name << " in:\n " << QDir::toNativeSeparators(fileName); + if (!query.isEmpty()) + str << "\n using query:\n " << query; + return result; +} + +QString msgFallbackForDocumentation(const QString &fileName, + const char *what, const QString &name, + const QString &query) +{ + QString result; + QTextStream str(&result); + str << "Fallback used while trying to find documentation for " << what + << ' ' << name << " in:\n " << QDir::toNativeSeparators(fileName); + if (!query.isEmpty()) + str << "\n using query:\n " << query; + return result; +} + +static QString functionDescription(const AbstractMetaFunction *function) +{ + QString result = u'"' + function->classQualifiedSignature() + u'"'; + if (function->flags().testFlag(AbstractMetaFunction::Flag::HiddenFriend)) + result += u" (hidden friend)"_s; + if (function->flags().testFlag(AbstractMetaFunction::Flag::InheritedFromTemplate)) + result += u" (inherited from template)"_s; return result; } QString msgCannotFindDocumentation(const QString &fileName, - const AbstractMetaClass *metaClass, const AbstractMetaFunction *function, const QString &query) { - const QString name = metaClass->name() + QLatin1String("::") - + function->minimalSignature(); - return msgCannotFindDocumentation(fileName, "function", name, query); + return msgCannotFindDocumentation(fileName, "function", + functionDescription(function), query); +} + +QString msgFallbackForDocumentation(const QString &fileName, + const AbstractMetaFunction *function, + const QString &query) +{ + return msgFallbackForDocumentation(fileName, "function", + functionDescription(function), query); } QString msgCannotFindDocumentation(const QString &fileName, - const AbstractMetaClass *metaClass, + const AbstractMetaClassCPtr &metaClass, const AbstractMetaEnum &e, const QString &query) { - return msgCannotFindDocumentation(fileName, "enum", - metaClass->name() + QLatin1String("::") + e.name(), - query); + QString name = e.name(); + if (metaClass != nullptr) + name.prepend(metaClass->name() + "::"_L1); + return msgCannotFindDocumentation(fileName, "enum", name, query); } QString msgCannotFindDocumentation(const QString &fileName, - const AbstractMetaClass *metaClass, + const AbstractMetaClassCPtr &metaClass, const AbstractMetaField &f, const QString &query) { - return msgCannotFindDocumentation(fileName, "field", - metaClass->name() + QLatin1String("::") + f.name(), - query); + QString name = f.name(); + if (metaClass != nullptr) + name.prepend(metaClass->name() + "::"_L1); + return msgCannotFindDocumentation(fileName, "field", name, query); } QString msgXpathDocModificationError(const DocModificationList& mods, @@ -553,13 +658,13 @@ QString msgXpathDocModificationError(const DocModificationList& mods, QString msgCannotOpenForReading(const QFile &f) { - return QStringLiteral("Failed to open file '%1' for reading: %2") + return QString::fromLatin1("Failed to open file '%1' for reading: %2") .arg(QDir::toNativeSeparators(f.fileName()), f.errorString()); } QString msgCannotOpenForWriting(const QFile &f) { - return QStringLiteral("Failed to open file '%1' for writing: %2") + return QString::fromLatin1("Failed to open file '%1' for writing: %2") .arg(QDir::toNativeSeparators(f.fileName()), f.errorString()); } @@ -576,80 +681,64 @@ QString msgWriteFailed(const QFile &f, qsizetype size) QString msgCannotUseEnumAsInt(const QString &name) { - return QLatin1String("Cannot convert the protected scoped enum \"") + name - + QLatin1String("\" to type int when generating wrappers for the protected hack. " - "Compilation errors may occur when used as a function argument."); + return u"Cannot convert the protected scoped enum \""_s + name + + u"\" to type int when generating wrappers for the protected hack. " + "Compilation errors may occur when used as a function argument."_s; } -QString msgConversionTypesDiffer(const QString &varType, const QString &conversionType) +QString msgCannotFindSmartPointerGetter(const SmartPointerTypeEntryCPtr &te) { - QString result; - QTextStream str(&result); - str << "Types of receiver variable ('" << varType - << "') and %%CONVERTTOCPP type system variable ('" << conversionType - << "') differ"; - QString strippedVarType = varType; - QString strippedConversionType = conversionType; - TypeInfo::stripQualifiers(&strippedVarType); - TypeInfo::stripQualifiers(&strippedConversionType); - if (strippedVarType == strippedConversionType) - str << " in qualifiers. Please make sure the type is a distinct token"; - str << '.'; - return result; + return u"Getter \""_s + te->getter() + u"()\" of smart pointer \""_s + + te->name() + u"\" not found."_s; } -QString msgCannotFindSmartPointer(const QString &instantiationType, - const AbstractMetaClassCList &pointers) +QString msgCannotFindSmartPointerMethod(const SmartPointerTypeEntryCPtr &te, const QString &m) { - QString result; - QTextStream str(&result); - str << "Unable to find smart pointer type for " << instantiationType << " (known types:"; - for (auto t : pointers) { - auto typeEntry = t->typeEntry(); - str << ' ' << typeEntry->targetLangName() << '/' << typeEntry->qualifiedCppName(); - } - str << ")."; - return result; + return u"Method \""_s + m + u"()\" of smart pointer \""_s + + te->name() + u"\" not found."_s; +} + +QString msgMethodNotFound(const AbstractMetaClassCPtr &klass, const QString &name) +{ + return u"Method \""_s + name + u"\" not found in class "_s + + klass->name() + u'.'; } // main.cpp -QString msgLeftOverArguments(const QVariantMap &remainingArgs) +QString msgLeftOverArguments(const QString &remainingArgs, const QStringList &argV) { QString message; QTextStream str(&message); - str << "shiboken: Called with wrong arguments:"; - for (auto it = remainingArgs.cbegin(), end = remainingArgs.cend(); it != end; ++it) { - str << ' ' << it.key(); - const QString value = it.value().toString(); - if (!value.isEmpty()) - str << ' ' << value; - } - str << "\nCommand line: " << QCoreApplication::arguments().join(QLatin1Char(' ')); + str << "shiboken: Unprocessed arguments: " << remainingArgs + << "\nCommand line: " << argV.join(u' '); return message; } QString msgInvalidVersion(const QString &package, const QString &version) { - return QLatin1String("Invalid version \"") + version - + QLatin1String("\" specified for package ") + package + QLatin1Char('.'); + return u"Invalid version \""_s + version + + u"\" specified for package "_s + package + u'.'; } QString msgCyclicDependency(const QString &funcName, const QString &graphName, - const QList<const AbstractMetaFunction *> &involvedConversions) + const AbstractMetaFunctionCList &cyclic, + const AbstractMetaFunctionCList &involvedConversions) { QString result; QTextStream str(&result); str << "Cyclic dependency found on overloaddata for \"" << funcName - << "\" method! The graph boy saved the graph at \"" - << QDir::toNativeSeparators(graphName) << "\"."; - if (const int count = involvedConversions.size()) { + << "\" method! The graph boy saved the graph at \"" << QDir::toNativeSeparators(graphName) + << "\". Cyclic functions:"; + for (const auto &c : cyclic) + str << ' ' << c->signature(); + if (const auto count = involvedConversions.size()) { str << " Implicit conversions (" << count << "): "; - for (int i = 0; i < count; ++i) { + for (qsizetype i = 0; i < count; ++i) { if (i) str << ", \""; str << involvedConversions.at(i)->signature() << '"'; - if (const AbstractMetaClass *c = involvedConversions.at(i)->implementingClass()) + if (const auto c = involvedConversions.at(i)->implementingClass()) str << '(' << c->name() << ')'; } } @@ -658,19 +747,28 @@ QString msgCyclicDependency(const QString &funcName, const QString &graphName, // shibokengenerator.cpp -QString msgClassNotFound(const TypeEntry *t) +QString msgClassNotFound(const TypeEntryCPtr &t) { - return QLatin1String("Could not find class \"") + return u"Could not find class \""_s + t->qualifiedCppName() - + QLatin1String("\" in the code model. Maybe it is forward declared?"); + + u"\" in the code model. Maybe it is forward declared?"_s; +} + +QString msgEnclosingClassNotFound(const TypeEntryCPtr &t) +{ + QString result; + QTextStream str(&result); + str << "Warning: Enclosing class \"" << t->parent()->name() + << "\" of class \"" << t->name() << "\" not found."; + return result; } -QString msgUnknownOperator(const AbstractMetaFunction* func) +QString msgUnknownOperator(const AbstractMetaFunction *func) { - QString result = QLatin1String("Unknown operator: \"") + func->originalName() - + QLatin1Char('"'); - if (const AbstractMetaClass *c = func->implementingClass()) - result += QLatin1String(" in class: ") + c->name(); + QString result = u"Unknown operator: \""_s + func->originalName() + + u'"'; + if (const auto c = func->implementingClass()) + result += u" in class: "_s + c->name(); return result; } @@ -680,7 +778,7 @@ QString msgWrongIndex(const char *varName, const QString &capture, QString result; QTextStream str(&result); str << "Wrong index for " << varName << " variable (" << capture << ") on "; - if (const AbstractMetaClass *c = func->implementingClass()) + if (const auto c = func->implementingClass()) str << c->name() << "::"; str << func->signature(); return result; @@ -698,8 +796,7 @@ QString msgCannotFindType(const QString &type, const QString &variable, QString msgCannotBuildMetaType(const QString &s) { - return QLatin1String("Unable to build meta type for \"") - + s + QLatin1String("\": "); + return u"Unable to build meta type for \""_s + s + u"\": "_s; } QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type, const QString &why) @@ -723,17 +820,17 @@ QString msgRejectReason(const TypeRejection &r, const QString &needle) QTextStream str(&result); switch (r.matchType) { case TypeRejection::ExcludeClass: - str << " matches class exclusion \"" << r.className.pattern() << '"'; + str << "matches class exclusion \"" << r.className.pattern() << '"'; break; case TypeRejection::Function: case TypeRejection::Field: case TypeRejection::Enum: - str << " matches class \"" << r.className.pattern() << "\" and \"" + str << "matches class \"" << r.className.pattern() << "\" and \"" << r.pattern.pattern() << '"'; break; case TypeRejection::ArgumentType: case TypeRejection::ReturnType: - str << " matches class \"" << r.className.pattern() << "\" and \"" + str << "matches class \"" << r.className.pattern() << "\" and \"" << needle << "\" matches \"" << r.pattern.pattern() << '"'; break; } @@ -745,36 +842,36 @@ QString msgRejectReason(const TypeRejection &r, const QString &needle) QString msgCannotFindNamespaceToExtend(const QString &name, const QString &extendsPackage) { - return QLatin1String("Cannot find namespace ") + name - + QLatin1String(" in package ") + extendsPackage; + return u"Cannot find namespace "_s + name + + u" in package "_s + extendsPackage; } QString msgExtendingNamespaceRequiresPattern(const QString &name) { - return QLatin1String("Namespace ") + name - + QLatin1String(" requires a file pattern since it extends another namespace."); + return u"Namespace "_s + name + + u" requires a file pattern since it extends another namespace."_s; } QString msgInvalidRegularExpression(const QString &pattern, const QString &why) { - return QLatin1String("Invalid pattern \"") + pattern + QLatin1String("\": ") + why; + return u"Invalid pattern \""_s + pattern + u"\": "_s + why; } QString msgNoRootTypeSystemEntry() { - return QLatin1String("Type system entry appears out of order, there does not seem to be a root type system element."); + return u"Type system entry appears out of order, there does not seem to be a root type system element."_s; } QString msgIncorrectlyNestedName(const QString &name) { - return QLatin1String("Nesting types by specifying '::' is no longer supported (") - + name + QLatin1String(")."); + return u"Nesting types by specifying '::' is no longer supported ("_s + + name + u")."_s; } QString msgCannotFindView(const QString &viewedName, const QString &name) { - return QLatin1String("Unable to find viewed type ") + viewedName - + QLatin1String(" for ") + name; + return u"Unable to find viewed type "_s + viewedName + + u" for "_s + name; } QString msgCannotFindSnippet(const QString &file, const QString &snippetLabel) @@ -786,6 +883,21 @@ QString msgCannotFindSnippet(const QString &file, const QString &snippetLabel) return result; } +QString msgSnippetError(const QString &context, const char *what) +{ + return "Error processing code snippet of "_L1 + context + + ": "_L1 + QString::fromUtf8(what); +} + +QString msgUnableToResolveTypedef(const QString &sourceType, const QString &sourceName) +{ + QString result; + QTextStream(&result) << "Unable to resolve typedef \"" << sourceType + << "\": Could not find a value, container, object or smart pointer type named \"" + << sourceName << "\"."; + return result; +} + // cppgenerator.cpp QString msgPureVirtualFunctionRemoved(const AbstractMetaFunction *f) @@ -811,3 +923,60 @@ QString msgUnknownTypeInArgumentTypeReplacement(const QString &typeReplaced, << "', the generated code may be broken."; return result; } + +QString msgDuplicateBuiltInTypeEntry(const QString &name) +{ + return u"A type entry duplicating the built-in type \""_s + + name + u"\" was found. It is ignored."_s; +} + +QString msgDuplicateTypeEntry(const QString &name) +{ + return u"Duplicate type entry: '"_s + name + u"'."_s; +} + +QString msgInvalidTargetLanguageApiName(const QString &name) +{ + return u"Invalid target language API name \""_s + + name + u"\"."_s; +} + +QString msgUnknownCheckFunction(const TypeEntryCPtr &t) +{ + return u"Unknown check function for type: '"_s + + t->qualifiedCppName() + u"'."_s; +} + +QString msgArgumentClassNotFound(const AbstractMetaFunctionCPtr &func, + const TypeEntryCPtr &t) +{ + QString result; + QTextStream(&result) << "Internal Error: Class \"" << t->qualifiedCppName() + << "\" for \"" << func->classQualifiedSignature() << "\" not found!"; + return result; +} + +QString msgMissingCustomConversion(const TypeEntryCPtr &t) +{ + QString result; + QTextStream(&result) << "Entry \"" << t->qualifiedCppName() + << "\" is missing a custom conversion."; + return result; +} + +QString msgUnknownArrayPointerConversion(const QString &s) +{ + return u"Warning: Falling back to pointer conversion for unknown array type \""_s + + s + u"\""_s; +} + +QString msgMissingProjectFileMarker(const QString &name, const QByteArray &startMarker) +{ + return u"First line of project file \""_s + QDir::toNativeSeparators(name) + + u"\" must be the string \""_s + QString::fromLatin1(startMarker) + u"\"."_s; +} + +QString msgInvalidLanguageLevel(const QString &l) +{ + return u"Invalid argument for language level: \""_s + l + u"\"."_s; +} diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h index 434d33ff5..2899cbdfa 100644 --- a/sources/shiboken6/ApiExtractor/messages.h +++ b/sources/shiboken6/ApiExtractor/messages.h @@ -1,44 +1,19 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef MESSAGES_H #define MESSAGES_H #include "abstractmetalang_typedefs.h" #include "parser/codemodel_fwd.h" +#include "modifications_typedefs.h" #include "typesystem_typedefs.h" -#include <QtCore/QMap> #include <QtCore/QString> -#include <QtCore/QList> class EnumTypeEntry; class FunctionTypeEntry; +class SmartPointerTypeEntry; class TypeEntry; class TypeInfo; struct TypeRejection; @@ -50,23 +25,37 @@ QT_FORWARD_DECLARE_CLASS(QXmlStreamReader) QString msgAddedFunctionInvalidArgType(const QString &addedFuncName, const QStringList &typeName, int pos, const QString &why, - const AbstractMetaClass *context = nullptr); + const AbstractMetaClassCPtr &context = {}); QString msgAddedFunctionInvalidReturnType(const QString &addedFuncName, const QStringList &typeName, const QString &why, - const AbstractMetaClass *context = nullptr); + const AbstractMetaClassCPtr &context = {}); -QString msgUnnamedArgumentDefaultExpression(const AbstractMetaClass *context, +QString msgUnnamedArgumentDefaultExpression(const AbstractMetaClassCPtr &context, int n, const QString &className, const AbstractMetaFunction *f); -QString msgNoFunctionForModification(const AbstractMetaClass *klass, +QString msgArgumentIndexOutOfRange(const AbstractMetaFunction *func, int index); + +QString msgNoFunctionForModification(const AbstractMetaClassCPtr &klass, const QString &signature, const QString &originalSignature, const QStringList &possibleSignatures, const AbstractMetaFunctionCList &allFunctions); -QString msgClassOfEnumNotFound(const EnumTypeEntry *entry); +QString msgTypeModificationFailed(const QString &type, int n, + const AbstractMetaFunction *func, + const QString &why); + +QString msgInvalidArgumentModification(const AbstractMetaFunctionCPtr &func, + int argIndex); + +QString msgArgumentOutOfRange(int number, int minValue, int maxValue); + +QString msgArgumentRemovalFailed(const AbstractMetaFunction *func, int n, + const QString &why); + +QString msgClassOfEnumNotFound(const EnumTypeEntryCPtr &entry); QString msgNoEnumTypeEntry(const EnumModelItem &enumItem, const QString &className); @@ -74,13 +63,15 @@ QString msgNoEnumTypeEntry(const EnumModelItem &enumItem, QString msgNoEnumTypeConflict(const EnumModelItem &enumItem, const QString &className, - const TypeEntry *t); + const TypeEntryCPtr &t); QString msgNamespaceNoTypeEntry(const NamespaceModelItem &item, const QString &fullName); -QString msgAmbiguousVaryingTypesFound(const QString &qualifiedName, const TypeEntries &te); -QString msgAmbiguousTypesFound(const QString &qualifiedName, const TypeEntries &te); +QString msgNamespaceNotFound(const QString &name); + +QString msgAmbiguousVaryingTypesFound(const QString &qualifiedName, const TypeEntryCList &te); +QString msgAmbiguousTypesFound(const QString &qualifiedName, const TypeEntryCList &te); QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n, const QString &why); @@ -91,7 +82,7 @@ QString msgUnmatchedReturnType(const FunctionModelItem &functionItem, QString msgShadowingFunction(const AbstractMetaFunction *f1, const AbstractMetaFunction *f2); -QString msgSignalOverloaded(const AbstractMetaClass *c, +QString msgSignalOverloaded(const AbstractMetaClassCPtr &c, const AbstractMetaFunction *f); QString msgSkippingFunction(const FunctionModelItem &functionItem, @@ -100,21 +91,23 @@ QString msgSkippingFunction(const FunctionModelItem &functionItem, QString msgSkippingField(const VariableModelItem &field, const QString &className, const QString &type); -QString msgTypeNotDefined(const TypeEntry *entry); +QString msgTypeNotDefined(const TypeEntryCPtr &entry); -QString msgGlobalFunctionNotDefined(const FunctionTypeEntry *fte, - const QString &signature); +QString msgGlobalFunctionNotDefined(const FunctionTypeEntryCPtr &fte, + const QString &signature, + const QStringList &candidates); QString msgStrippingArgument(const FunctionModelItem &f, int i, const QString &originalSignature, - const ArgumentModelItem &arg); + const ArgumentModelItem &arg, + const QString &reason); -QString msgEnumNotDefined(const EnumTypeEntry *t); +QString msgEnumNotDefined(const EnumTypeEntryCPtr &t); -QString msgUnknownBase(const AbstractMetaClass *metaClass, +QString msgUnknownBase(const AbstractMetaClassCPtr &metaClass, const QString &baseClassName); -QString msgBaseNotInTypeSystem(const AbstractMetaClass *metaClass, +QString msgBaseNotInTypeSystem(const AbstractMetaClassCPtr &metaClass, const QString &baseClassName); QString msgArrayModificationFailed(const FunctionModelItem &functionItem, @@ -148,29 +141,36 @@ QString msgPropertyTypeParsingFailed(const QString &name, const QString &typeNam const QString &why); QString msgPropertyExists(const QString &className, const QString &name); -QString msgFunctionVisibilityModified(const AbstractMetaClass *c, +QString msgFunctionVisibilityModified(const AbstractMetaClassCPtr &c, const AbstractMetaFunction *f); -QString msgUsingMemberClassNotFound(const AbstractMetaClass *c, +QString msgUsingMemberClassNotFound(const AbstractMetaClassCPtr &c, const QString &baseClassName, const QString &memberName); QString msgCannotFindDocumentation(const QString &fileName, const char *what, const QString &name, - const QString &query); + const QString &query = {}); + +QString msgFallbackForDocumentation(const QString &fileName, + const char *what, const QString &name, + const QString &query = {}); QString msgCannotFindDocumentation(const QString &fileName, - const AbstractMetaClass *metaClass, const AbstractMetaFunction *function, - const QString &query); + const QString &query = {}); + +QString msgFallbackForDocumentation(const QString &fileName, + const AbstractMetaFunction *function, + const QString &query = {}); QString msgCannotFindDocumentation(const QString &fileName, - const AbstractMetaClass *metaClass, + const AbstractMetaClassCPtr &metaClass, const AbstractMetaEnum &e, - const QString &query); + const QString &query = {}); QString msgCannotFindDocumentation(const QString &fileName, - const AbstractMetaClass *metaClass, + const AbstractMetaClassCPtr &metaClass, const AbstractMetaField &f, const QString &query); @@ -185,12 +185,13 @@ QString msgWriteFailed(const QFile &f, qsizetype size); QString msgCannotUseEnumAsInt(const QString &name); -QString msgConversionTypesDiffer(const QString &varType, const QString &conversionType); +QString msgCannotFindSmartPointerGetter(const SmartPointerTypeEntryCPtr &); + +QString msgCannotFindSmartPointerMethod(const SmartPointerTypeEntryCPtr &te, const QString &m); -QString msgCannotFindSmartPointer(const QString &instantiationType, - const AbstractMetaClassCList &pointers); +QString msgMethodNotFound(const AbstractMetaClassCPtr &klass, const QString &name); -QString msgLeftOverArguments(const QVariantMap &remainingArgs); +QString msgLeftOverArguments(const QString &remainingArgs, const QStringList &argV); QString msgInvalidVersion(const QString &package, const QString &version); @@ -208,13 +209,18 @@ QString msgIncorrectlyNestedName(const QString &name); QString msgCannotFindView(const QString &viewedName, const QString &name); QString msgCannotFindSnippet(const QString &file, const QString &snippetLabel); +QString msgSnippetError(const QString &context, const char *what); +QString msgUnableToResolveTypedef(const QString &sourceType, const QString &sourceName); QString msgCyclicDependency(const QString &funcName, const QString &graphName, - const QList<const AbstractMetaFunction *> &involvedConversions); + const AbstractMetaFunctionCList &cyclic, + const AbstractMetaFunctionCList &involvedConversions); -QString msgClassNotFound(const TypeEntry *t); +QString msgClassNotFound(const TypeEntryCPtr &t); -QString msgUnknownOperator(const AbstractMetaFunction* func); +QString msgEnclosingClassNotFound(const TypeEntryCPtr &t); + +QString msgUnknownOperator(const AbstractMetaFunction *func); QString msgWrongIndex(const char *varName, const QString &capture, const AbstractMetaFunction *func); @@ -234,4 +240,21 @@ QString msgPureVirtualFunctionRemoved(const AbstractMetaFunction *f); QString msgUnknownTypeInArgumentTypeReplacement(const QString &typeReplaced, const AbstractMetaFunction *f); +QString msgDuplicateBuiltInTypeEntry(const QString &name); +QString msgDuplicateTypeEntry(const QString &name); +QString msgInvalidTargetLanguageApiName(const QString &name); + +QString msgUnknownCheckFunction(const TypeEntryCPtr &t); + +QString msgArgumentClassNotFound(const AbstractMetaFunctionCPtr &func, + const TypeEntryCPtr &t); + +QString msgMissingCustomConversion(const TypeEntryCPtr &t); + +QString msgUnknownArrayPointerConversion(const QString &s); + +QString msgMissingProjectFileMarker(const QString &name, const QByteArray &startMarker); + +QString msgInvalidLanguageLevel(const QString &l); + #endif // MESSAGES_H diff --git a/sources/shiboken6/ApiExtractor/modifications.cpp b/sources/shiboken6/ApiExtractor/modifications.cpp index f5afef124..d876e8035 100644 --- a/sources/shiboken6/ApiExtractor/modifications.cpp +++ b/sources/shiboken6/ApiExtractor/modifications.cpp @@ -1,102 +1,18 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "modifications.h" -#include "modifications_p.h" -#include "exception.h" -#include "typedatabase.h" -#include "typeparser.h" -#include "typesystem.h" +#include "codesnip.h" + +#include "qtcompat.h" #include <QtCore/QDebug> +#include <QtCore/QRegularExpression> #include <algorithm> #include <limits> -static inline QString callOperator() { return QStringLiteral("operator()"); } - -QString TemplateInstance::expandCode() const -{ - TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name); - if (!templateEntry) { - const QString m = QLatin1String("<insert-template> referring to non-existing template '") - + m_name + QLatin1String("'."); - throw Exception(m); - } - - QString code = templateEntry->code(); - for (auto it = replaceRules.cbegin(), end = replaceRules.cend(); it != end; ++it) - code.replace(it.key(), it.value()); - while (!code.isEmpty() && code.at(code.size() - 1).isSpace()) - code.chop(1); - QString result = QLatin1String("// TEMPLATE - ") + m_name + QLatin1String(" - START"); - if (!code.startsWith(QLatin1Char('\n'))) - result += QLatin1Char('\n'); - result += code; - result += QLatin1String("\n// TEMPLATE - ") + m_name + QLatin1String(" - END\n"); - return result; -} - -// ---------------------- CodeSnipFragment -QString CodeSnipFragment::code() const -{ - return m_instance ? m_instance->expandCode() : m_code; -} - -// ---------------------- CodeSnipAbstract -QString CodeSnipAbstract::code() const -{ - QString res; - for (const CodeSnipFragment &codeFrag : codeList) - res.append(codeFrag.code()); - - return res; -} - -void CodeSnipAbstract::addCode(const QString &code) -{ - codeList.append(CodeSnipFragment(fixSpaces(code))); -} - -QRegularExpression CodeSnipAbstract::placeHolderRegex(int index) -{ - return QRegularExpression(QLatin1Char('%') + QString::number(index) + QStringLiteral("\\b")); -} - -// ---------------------- Modification -QString FunctionModification::accessModifierString() const -{ - if (isPrivate()) return QLatin1String("private"); - if (isProtected()) return QLatin1String("protected"); - if (isPublic()) return QLatin1String("public"); - if (isFriendly()) return QLatin1String("friendly"); - return QString(); -} +using namespace Qt::StringLiterals; // ---------------------- FieldModification @@ -108,6 +24,7 @@ public: bool m_readable = true; bool m_writable = true; bool m_removed = false; + bool m_opaqueContainer = false; TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified; }; @@ -117,8 +34,8 @@ FieldModification::FieldModification() : d(new FieldModificationData) FieldModification::FieldModification(const FieldModification &) = default; FieldModification &FieldModification::operator=(const FieldModification &) = default; -FieldModification::FieldModification(FieldModification &&) = default; -FieldModification &FieldModification::operator=(FieldModification &&) = default; +FieldModification::FieldModification(FieldModification &&) noexcept = default; +FieldModification &FieldModification::operator=(FieldModification &&) noexcept = default; FieldModification::~FieldModification() = default; QString FieldModification::name() const @@ -181,190 +98,26 @@ void FieldModification::setRemoved(bool r) d->m_removed = r; } -TypeSystem::SnakeCase FieldModification::snakeCase() const -{ - return d->snakeCase; -} - -void FieldModification::setSnakeCase(TypeSystem::SnakeCase s) -{ - if (d->snakeCase != s) - d->snakeCase = s; -} - -// Helpers to split a parameter list of <add-function>, <declare-function> -// (@ denoting names), like -// "void foo(QList<X,Y> &@list@ = QList<X,Y>{1,2}, int @b@=5, ...)" -namespace AddedFunctionParser { - -bool Argument::equals(const Argument &rhs) const +bool FieldModification::isOpaqueContainer() const { - return type == rhs.type && name == rhs.name && defaultValue == rhs.defaultValue; + return d->m_opaqueContainer; } -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const Argument &a) +void FieldModification::setOpaqueContainer(bool r) { - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "Argument(type=\"" << a.type << '"'; - if (!a.name.isEmpty()) - d << ", name=\"" << a.name << '"'; - if (!a.defaultValue.isEmpty()) - d << ", defaultValue=\"" << a.defaultValue << '"'; - d << ')'; - return d; + if (d->m_opaqueContainer != r) + d->m_opaqueContainer = r; } -#endif // QT_NO_DEBUG_STREAM - -// Helper for finding the end of a function parameter, observing -// nested template parameters or lists. -static int parameterTokenEnd(int startPos, QStringView paramString) -{ - const int end = paramString.size(); - int nestingLevel = 0; - for (int p = startPos; p < end; ++p) { - switch (paramString.at(p).toLatin1()) { - case ',': - if (nestingLevel == 0) - return p; - break; - case '<': // templates - case '{': // initializer lists of default values - case '(': // initialization, function pointers - case '[': // array dimensions - ++nestingLevel; - break; - case '>': - case '}': - case ')': - case ']': - --nestingLevel; - break; - } - } - return end; -} - -// Split a function parameter list into string tokens containing one -// parameters (including default value, etc). -static QList<QStringView> splitParameterTokens(QStringView paramString) -{ - QList<QStringView> result; - int startPos = 0; - for ( ; startPos < paramString.size(); ) { - int end = parameterTokenEnd(startPos, paramString); - result.append(paramString.mid(startPos, end - startPos).trimmed()); - startPos = end + 1; - } - return result; -} - -// Split a function parameter list -Arguments splitParameters(QStringView paramString, QString *errorMessage) -{ - Arguments result; - const QList<QStringView> tokens = splitParameterTokens(paramString); - for (const auto &t : tokens) { - Argument argument; - // Check defaultValue, "int @b@=5" - const int equalPos = t.lastIndexOf(QLatin1Char('=')); - if (equalPos != -1) { - const int defaultValuePos = equalPos + 1; - argument.defaultValue = - t.mid(defaultValuePos, t.size() - defaultValuePos).trimmed().toString(); - } - QString typeString = (equalPos != -1 ? t.left(equalPos) : t).trimmed().toString(); - // Check @name@ - const int atPos = typeString.indexOf(QLatin1Char('@')); - if (atPos != -1) { - const int namePos = atPos + 1; - const int nameEndPos = typeString.indexOf(QLatin1Char('@'), namePos); - if (nameEndPos == -1) { - if (errorMessage != nullptr) { - *errorMessage = QLatin1String("Mismatched @ in \"") - + paramString.toString() + QLatin1Char('"'); - } - return {}; - } - argument.name = typeString.mid(namePos, nameEndPos - namePos).trimmed(); - typeString.remove(atPos, nameEndPos - atPos + 1); - } - argument.type = typeString.trimmed(); - result.append(argument); - } - - return result; -} - -} // namespace AddedFunctionParser - -AddedFunction::AddedFunction(const QString &name, const QList<Argument> &arguments, - const TypeInfo &returnType) : - m_name(name), - m_arguments(arguments), - m_returnType(returnType) +TypeSystem::SnakeCase FieldModification::snakeCase() const { + return d->snakeCase; } -AddedFunction::AddedFunctionPtr - AddedFunction::createAddedFunction(const QString &signatureIn, const QString &returnTypeIn, - QString *errorMessage) - +void FieldModification::setSnakeCase(TypeSystem::SnakeCase s) { - errorMessage->clear(); - - QList<Argument> arguments; - const TypeInfo returnType = returnTypeIn.isEmpty() - ? TypeInfo::voidType() - : TypeParser::parse(returnTypeIn, errorMessage); - if (!errorMessage->isEmpty()) - return {}; - - QStringView signature = QStringView{signatureIn}.trimmed(); - - // Skip past "operator()(...)" - const int parenSearchStartPos = signature.startsWith(callOperator()) - ? callOperator().size() : 0; - const int openParenPos = signature.indexOf(QLatin1Char('('), parenSearchStartPos); - if (openParenPos < 0) { - return AddedFunctionPtr(new AddedFunction(signature.toString(), - arguments, returnType)); - } - - const QString name = signature.left(openParenPos).trimmed().toString(); - const int closingParenPos = signature.lastIndexOf(QLatin1Char(')')); - if (closingParenPos < 0) { - *errorMessage = QLatin1String("Missing closing parenthesis"); - return {}; - } - - // Check for "foo() const" - bool isConst = false; - const int signatureLength = signature.length(); - const int qualifierLength = signatureLength - closingParenPos - 1; - if (qualifierLength >= 5 - && signature.right(qualifierLength).contains(QLatin1String("const"))) { - isConst = true; - } - - const auto paramString = signature.mid(openParenPos + 1, closingParenPos - openParenPos - 1); - const auto params = AddedFunctionParser::splitParameters(paramString, errorMessage); - if (params.isEmpty() && !errorMessage->isEmpty()) - return {}; - for (const auto &p : params) { - TypeInfo type = p.type == QLatin1String("...") - ? TypeInfo::varArgsType() : TypeParser::parse(p.type, errorMessage); - if (!errorMessage->isEmpty()) - return {}; - arguments.append({type, p.name, p.defaultValue}); - } - - AddedFunctionPtr result(new AddedFunction(name, arguments, returnType)); - result->setConstant(isConst); - return result; + if (d->snakeCase != s) + d->snakeCase = s; } // Remove the parameter names enclosed in '@' from an added function signature @@ -413,17 +166,29 @@ QDebug operator<<(QDebug d, const CodeSnip &s) QDebugStateSaver saver(d); d.noquote(); d.nospace(); - d << "CodeSnip(language=" << s.language << ", position=" << s.position << ", \""; - for (const auto &f : s.codeList) { - const QString &code = f.code(); - const auto lines = QStringView{code}.split(QLatin1Char('\n')); - for (int i = 0, size = lines.size(); i < size; ++i) { - if (i) - d << "\\n"; - d << lines.at(i).trimmed(); + const auto size = s.codeList.size(); + d << "CodeSnip(language=" << s.language << ", position=" << s.position + << ", fragments[" << size << "]="; + for (qsizetype i = 0; i < size; ++i) { + const auto &f = s.codeList.at(i); + if (i) + d << ", "; + d << '#' << i << ' '; + if (!f.instance()) { + d << '"'; + const QString &code = f.code(); + const auto lines = QStringView{code}.split(u'\n'); + for (qsizetype i = 0, size = lines.size(); i < size; ++i) { + if (i) + d << "\\n"; + d << lines.at(i).trimmed(); + } + d << '"'; + } else { + d << "template=\"" << f.instance()->name() << '"'; } } - d << "\")"; + d << ')'; return d; } @@ -462,11 +227,11 @@ ArgumentModification::ArgumentModification(int idx) : d(new ArgumentModification ArgumentModification::ArgumentModification(const ArgumentModification &) = default; ArgumentModification &ArgumentModification::operator=(const ArgumentModification &) = default; -ArgumentModification::ArgumentModification(ArgumentModification &&) = default; -ArgumentModification &ArgumentModification::operator=(ArgumentModification &&) = default; +ArgumentModification::ArgumentModification(ArgumentModification &&) noexcept = default; +ArgumentModification &ArgumentModification::operator=(ArgumentModification &&) noexcept = default; ArgumentModification::~ArgumentModification() = default; -QString ArgumentModification::modifiedType() const +const QString &ArgumentModification::modifiedType() const { return d->modified_type; } @@ -477,6 +242,11 @@ void ArgumentModification::setModifiedType(const QString &value) d->modified_type = value; } +bool ArgumentModification::isTypeModified() const +{ + return !d->modified_type.isEmpty(); +} + QString ArgumentModification::pyiType() const { return d->pyiType; @@ -639,7 +409,6 @@ public: QString m_originalSignature; QRegularExpression m_signaturePattern; int m_overloadNumber = TypeSystem::OverloadNumberUnset; - bool m_thread = false; bool removed = false; TypeSystem::AllowThread m_allowThread = TypeSystem::AllowThread::Unspecified; TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; @@ -652,8 +421,8 @@ FunctionModification::FunctionModification() : d(new FunctionModificationData) FunctionModification::FunctionModification(const FunctionModification &) = default; FunctionModification &FunctionModification::operator=(const FunctionModification &) = default; -FunctionModification::FunctionModification(FunctionModification &&) = default; -FunctionModification &FunctionModification::operator=(FunctionModification &&) = default; +FunctionModification::FunctionModification(FunctionModification &&) noexcept = default; +FunctionModification &FunctionModification::operator=(FunctionModification &&) noexcept = default; FunctionModification::~FunctionModification() = default; void FunctionModification::formatDebug(QDebug &debug) const @@ -669,8 +438,6 @@ void FunctionModification::formatDebug(QDebug &debug) const debug << ", renamedToName=\"" << d->renamedToName << '"'; if (d->m_allowThread != TypeSystem::AllowThread::Unspecified) debug << ", allowThread=" << int(d->m_allowThread); - if (d->m_thread) - debug << ", thread"; if (d->m_exceptionHandling != TypeSystem::ExceptionHandling::Unspecified) debug << ", exceptionHandling=" << int(d->m_exceptionHandling); if (!d->m_snips.isEmpty()) @@ -773,17 +540,6 @@ void FunctionModification::setSnips(const CodeSnipList &snips) } // ---------------------- FunctionModification -void FunctionModification::setIsThread(bool flag) -{ - if (d->m_thread != flag) - d->m_thread = flag; -} - -bool FunctionModification::isThread() const -{ - return d->m_thread; -} - FunctionModification::AllowThread FunctionModification::allowThread() const { return d->m_allowThread; @@ -795,21 +551,26 @@ void FunctionModification::setAllowThread(FunctionModification::AllowThread allo d->m_allowThread = allow; } -bool FunctionModification::matches(const QString &functionSignature) const +bool FunctionModification::matches(const QStringList &functionSignatures) const { - return d->m_signature.isEmpty() - ? d->m_signaturePattern.match(functionSignature).hasMatch() - : d->m_signature == functionSignature; + if (!d->m_signature.isEmpty()) + return functionSignatures.contains(d->m_signature); + + for (const auto &s : functionSignatures) { + if (d->m_signaturePattern.match(s).hasMatch()) + return true; + } + return false; } bool FunctionModification::setSignature(const QString &s, QString *errorMessage) { - if (s.startsWith(QLatin1Char('^'))) { + if (s.startsWith(u'^')) { d->m_signaturePattern.setPattern(s); if (!d->m_signaturePattern.isValid()) { if (errorMessage) { - *errorMessage = QLatin1String("Invalid signature pattern: \"") - + s + QLatin1String("\": ") + d->m_signaturePattern.errorString(); + *errorMessage = u"Invalid signature pattern: \""_s + + s + u"\": "_s + d->m_signaturePattern.errorString(); } return false; } @@ -891,6 +652,9 @@ QDebug operator<<(QDebug d, const ArgumentModification &a) d << ", native ownership=" << a.nativeOwnership(); if (!a.renamedToName().isEmpty()) d << ", renamed_to=\"" << a.renamedToName() << '"'; + const auto &rules = a.conversionRules(); + if (!rules.isEmpty()) + d << ", conversionRules[" << rules.size() << "]=" << rules; d << ", owner=" << a.owner() << ')'; return d; } @@ -905,37 +669,4 @@ QDebug operator<<(QDebug d, const FunctionModification &fm) d << ')'; return d; } - -QDebug operator<<(QDebug d, const AddedFunction::Argument &a) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "Argument("; - d << a.typeInfo; - if (!a.name.isEmpty()) - d << ' ' << a.name; - if (!a.defaultValue.isEmpty()) - d << " = " << a.defaultValue; - d << ')'; - return d; -} - -QDebug operator<<(QDebug d, const AddedFunction &af) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "AddedFunction("; - if (af.access() == AddedFunction::Protected) - d << "protected"; - if (af.isStatic()) - d << " static"; - d << af.returnType() << ' ' << af.name() << '(' << af.arguments() << ')'; - if (af.isConstant()) - d << " const"; - if (af.isDeclaration()) - d << " [declaration]"; - return d; -} #endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken6/ApiExtractor/modifications.h b/sources/shiboken6/ApiExtractor/modifications.h index 3335c8098..27a38f1aa 100644 --- a/sources/shiboken6/ApiExtractor/modifications.h +++ b/sources/shiboken6/ApiExtractor/modifications.h @@ -1,46 +1,18 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef MODIFICATIONS_H #define MODIFICATIONS_H #include "typesystem_enums.h" -#include "typesystem_typedefs.h" -#include "codesniphelpers.h" -#include "parser/typeinfo.h" +#include "modifications_typedefs.h" #include <QtCore/QList> -#include <QtCore/QRegularExpression> #include <QtCore/QSharedDataPointer> -#include <QtCore/QSharedPointer> #include <QtCore/QString> class ArgumentModificationData; +class CodeSnip; class FunctionModificationData; class ModificationData; class FieldModificationData; @@ -49,28 +21,6 @@ QT_BEGIN_NAMESPACE class QDebug; QT_END_NAMESPACE -class TemplateInstance -{ -public: - explicit TemplateInstance(const QString &name) : m_name(name) {} - - void addReplaceRule(const QString &name, const QString &value) - { - replaceRules[name] = value; - } - - QString expandCode() const; - - QString name() const - { - return m_name; - } - -private: - const QString m_name; - QHash<QString, QString> replaceRules; -}; - struct ReferenceCount { enum Action { // 0x01 - 0xff @@ -107,71 +57,6 @@ struct ArgumentOwner int index = InvalidIndex; }; -class CodeSnipFragment -{ -public: - CodeSnipFragment() = default; - explicit CodeSnipFragment(const QString &code) : m_code(code) {} - explicit CodeSnipFragment(TemplateInstance *instance) : m_instance(instance) {} - - QString code() const; - -private: - QString m_code; - TemplateInstance *m_instance = nullptr; -}; - -class CodeSnipAbstract : public CodeSnipHelpers -{ -public: - QString code() const; - - void addCode(const QString &code); - void addCode(QStringView code) { addCode(code.toString()); } - - void addTemplateInstance(TemplateInstance *ti) - { - codeList.append(CodeSnipFragment(ti)); - } - - QList<CodeSnipFragment> codeList; - - static QRegularExpression placeHolderRegex(int index); -}; - -class CustomFunction : public CodeSnipAbstract -{ -public: - explicit CustomFunction(const QString &n = QString()) : name(n) {} - - QString name; - QString paramName; -}; - -class TemplateEntry : public CodeSnipAbstract -{ -public: - explicit TemplateEntry(const QString &name) : m_name(name) {} - - QString name() const - { - return m_name; - } - -private: - QString m_name; -}; - -class CodeSnip : public CodeSnipAbstract -{ -public: - CodeSnip() = default; - explicit CodeSnip(TypeSystem::Language lang) : language(lang) {} - - TypeSystem::Language language = TypeSystem::TargetLangCode; - TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny; -}; - class ArgumentModification { public: @@ -179,8 +64,8 @@ public: explicit ArgumentModification(int idx); ArgumentModification(const ArgumentModification &); ArgumentModification &operator=(const ArgumentModification &); - ArgumentModification(ArgumentModification &&); - ArgumentModification &operator=(ArgumentModification &&); + ArgumentModification(ArgumentModification &&) noexcept; + ArgumentModification &operator=(ArgumentModification &&) noexcept; ~ArgumentModification(); // Reference count flags for this argument @@ -188,8 +73,9 @@ public: void addReferenceCount(const ReferenceCount &value); // The text given for the new type of the argument - QString modifiedType() const; + const QString &modifiedType() const; void setModifiedType(const QString &value); + bool isTypeModified() const; QString pyiType() const; void setPyiType(const QString &value); @@ -206,8 +92,8 @@ public: void setNativeOwnership(TypeSystem::Ownership o); // Different conversion rules - const CodeSnipList &conversionRules() const; - CodeSnipList &conversionRules(); + const QList<CodeSnip> &conversionRules() const; + QList<CodeSnip> &conversionRules(); // QObject parent(owner) of this argument ArgumentOwner owner() const; @@ -248,15 +134,14 @@ public: FunctionModification(); FunctionModification(const FunctionModification &); FunctionModification &operator=(const FunctionModification &); - FunctionModification(FunctionModification &&); - FunctionModification &operator=(FunctionModification &&); + FunctionModification(FunctionModification &&) noexcept; + FunctionModification &operator=(FunctionModification &&) noexcept; ~FunctionModification(); enum ModifierFlag { Private = 0x0001, Protected = 0x0002, - Public = 0x0003, - Friendly = 0x0004, + Public = 0x0004, AccessModifierMask = 0x000f, Final = 0x0010, @@ -269,7 +154,8 @@ public: CodeInjection = 0x1000, Rename = 0x2000, Deprecated = 0x4000, - ReplaceExpression = 0x8000 + Undeprecated = 0x8000, + ReplaceExpression = 0x10000 }; Q_DECLARE_FLAGS(Modifiers, ModifierFlag); @@ -304,10 +190,6 @@ public: { return accessModifier() == Public; } - bool isFriendly() const - { - return accessModifier() == Friendly; - } bool isFinal() const { return modifiers().testFlag(Final); @@ -316,7 +198,6 @@ public: { return modifiers().testFlag(NonFinal); } - QString accessModifierString() const; bool isDeprecated() const { @@ -336,13 +217,11 @@ public: { return modifiers().testFlag(CodeInjection); } - void setIsThread(bool flag); - bool isThread() const; AllowThread allowThread() const; void setAllowThread(AllowThread allow); - bool matches(const QString &functionSignature) const; + bool matches(const QStringList &functionSignatures) const; bool setSignature(const QString &s, QString *errorMessage = nullptr); QString signature() const; @@ -356,10 +235,10 @@ public: int overloadNumber() const; void setOverloadNumber(int overloadNumber); - const CodeSnipList &snips() const; - CodeSnipList &snips(); + const QList<CodeSnip> &snips() const; + QList<CodeSnip> &snips(); void appendSnip(const CodeSnip &snip); - void setSnips(const CodeSnipList &snips); + void setSnips(const QList<CodeSnip> &snips); const QList<ArgumentModification> &argument_mods() const; QList<ArgumentModification> &argument_mods(); @@ -380,6 +259,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(FunctionModification::Modifiers) #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const ReferenceCount &); +QDebug operator<<(QDebug d, const CodeSnip &s); QDebug operator<<(QDebug d, const ArgumentOwner &a); QDebug operator<<(QDebug d, const ArgumentModification &a); QDebug operator<<(QDebug d, const FunctionModification &fm); @@ -391,8 +271,8 @@ public: FieldModification(); FieldModification(const FieldModification &); FieldModification &operator=(const FieldModification &); - FieldModification(FieldModification &&); - FieldModification &operator=(FieldModification &&); + FieldModification(FieldModification &&) noexcept; + FieldModification &operator=(FieldModification &&) noexcept; ~FieldModification(); QString name() const; @@ -411,6 +291,9 @@ public: bool isRemoved() const; void setRemoved(bool r); + bool isOpaqueContainer() const; + void setOpaqueContainer(bool r); + TypeSystem::SnakeCase snakeCase() const; void setSnakeCase(TypeSystem::SnakeCase s); @@ -418,121 +301,6 @@ private: QSharedDataPointer<FieldModificationData> d; }; -/** -* \internal -* Struct used to store information about functions added by the typesystem. -* This info will be used later to create a fake AbstractMetaFunction which -* will be inserted into the right AbstractMetaClass. -*/ -struct AddedFunction -{ - using AddedFunctionPtr = QSharedPointer<AddedFunction>; - - /// Function access types. - enum Access { - Protected = 0x1, - Public = 0x2 - }; - - struct Argument - { - TypeInfo typeInfo; - QString name; - QString defaultValue; - }; - - /// Creates a new AddedFunction with a signature and a return type. - explicit AddedFunction(const QString &name, const QList<Argument> &arguments, - const TypeInfo &returnType); - - static AddedFunctionPtr createAddedFunction(const QString &signatureIn, - const QString &returnTypeIn, - QString *errorMessage); - - AddedFunction() = default; - - /// Returns the function name. - QString name() const - { - return m_name; - } - - /// Set the function access type. - void setAccess(Access access) - { - m_access = access; - } - - /// Returns the function access type. - Access access() const - { - return m_access; - } - - /// Returns the function return type. - TypeInfo returnType() const - { - return m_returnType; - } - - /// Returns a list of argument type infos. - const QList<Argument> &arguments() const - { - return m_arguments; - } - - /// Returns true if this is a constant method. - bool isConstant() const - { - return m_isConst; - } - void setConstant(bool c) { m_isConst = c; }; - - /// Set this method static. - void setStatic(bool value) - { - m_isStatic = value; - } - - /// Set this method as a classmethod. - void setClassMethod(bool value) - { - m_isClassMethod = value; - } - - /// Returns true if this is a static method. - bool isStatic() const - { - return m_isStatic; - } - - /// Returns true if this is a class method. - bool isClassMethod() const - { - return m_isClassMethod; - } - - bool isDeclaration() const { return m_isDeclaration; } // <declare-function> - void setDeclaration(bool value) { m_isDeclaration = value; } - - FunctionModificationList modifications; - -private: - QString m_name; - QList<Argument> m_arguments; - TypeInfo m_returnType; - Access m_access = Public; - bool m_isConst = false; - bool m_isClassMethod = false; - bool m_isStatic = false; - bool m_isDeclaration = false; -}; - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const AddedFunction::Argument &a); -QDebug operator<<(QDebug d, const AddedFunction &af); -#endif - class DocModification { public: diff --git a/sources/shiboken6/ApiExtractor/modifications_p.h b/sources/shiboken6/ApiExtractor/modifications_p.h deleted file mode 100644 index c8f18308e..000000000 --- a/sources/shiboken6/ApiExtractor/modifications_p.h +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ - -#ifndef MODIFICATIONS_P_H -#define MODIFICATIONS_P_H - -#include <QtCore/QList> -#include <QtCore/QString> -#include <QtCore/QStringView> - -QT_BEGIN_NAMESPACE -class QDebug; -QT_END_NAMESPACE - -// Helpers to split a parameter list of <add-function>, <declare-function> -// in a separate header for testing purposes - -namespace AddedFunctionParser { - -struct Argument -{ - bool equals(const Argument &rhs) const; - - QString type; - QString name; - QString defaultValue; -}; - -using Arguments = QList<Argument>; - -inline bool operator==(const Argument &a1, const Argument &a2) { return a1.equals(a2); } -inline bool operator!=(const Argument &a1, const Argument &a2) { return !a1.equals(a2); } - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const Argument &a); -#endif - -Arguments splitParameters(QStringView paramString, QString *errorMessage = nullptr); - -} // namespace AddedFunctionParser - -#endif // MODIFICATIONS_P_H diff --git a/sources/shiboken6/ApiExtractor/modifications_typedefs.h b/sources/shiboken6/ApiExtractor/modifications_typedefs.h new file mode 100644 index 000000000..3b86c55d3 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/modifications_typedefs.h @@ -0,0 +1,25 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef MODIFICATIONS_TYPEDEFS_H +#define MODIFICATIONS_TYPEDEFS_H + +#include <QtCore/QList> + +#include <memory> + +class CodeSnip; +class DocModification; + +struct AddedFunction; +class FieldModification; +class FunctionModification; + +using AddedFunctionPtr = std::shared_ptr<AddedFunction>; +using AddedFunctionList = QList<AddedFunctionPtr>; +using CodeSnipList = QList<CodeSnip>; +using DocModificationList = QList<DocModification>; +using FieldModificationList = QList<FieldModification>; +using FunctionModificationList = QList<FunctionModification>; + +#endif // MODIFICATIONS_TYPEDEFS_H diff --git a/sources/shiboken6/ApiExtractor/namespacetypeentry.h b/sources/shiboken6/ApiExtractor/namespacetypeentry.h new file mode 100644 index 000000000..6ffd38430 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/namespacetypeentry.h @@ -0,0 +1,51 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef NAMESPACETYPEENTRY_H +#define NAMESPACETYPEENTRY_H + +#include "complextypeentry.h" + +class NamespaceTypeEntryPrivate; + +class NamespaceTypeEntry : public ComplexTypeEntry +{ +public: + explicit NamespaceTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + TypeEntry *clone() const override; + + NamespaceTypeEntryCPtr extends() const; + void setExtends(const NamespaceTypeEntryCPtr &e); + + const QRegularExpression &filePattern() const; // restrict files + void setFilePattern(const QRegularExpression &r); + + bool hasPattern() const; + + bool matchesFile(const QString &needle) const; + + bool isVisible() const; + void setVisibility(TypeSystem::Visibility v); + + // C++ 11 inline namespace, from code model + bool isInlineNamespace() const; + void setInlineNamespace(bool i); + + static bool isVisibleScope(const TypeEntryCPtr &e); + static bool isVisibleScope(const TypeEntry *e); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + + // Whether to generate "using namespace" into wrapper + bool generateUsing() const; + void setGenerateUsing(bool generateUsing); + +protected: + explicit NamespaceTypeEntry(NamespaceTypeEntryPrivate *d); +}; + +#endif // NAMESPACETYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/objecttypeentry.h b/sources/shiboken6/ApiExtractor/objecttypeentry.h new file mode 100644 index 000000000..da91e8ff4 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/objecttypeentry.h @@ -0,0 +1,21 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef OBJECTTYPEENTRY_H +#define OBJECTTYPEENTRY_H + +#include "complextypeentry.h" + +class ObjectTypeEntry : public ComplexTypeEntry +{ +public: + explicit ObjectTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + TypeEntry *clone() const override; + +protected: + explicit ObjectTypeEntry(ComplexTypeEntryPrivate *d); +}; + +#endif // OBJECTTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/optionsparser.cpp b/sources/shiboken6/ApiExtractor/optionsparser.cpp new file mode 100644 index 000000000..f2e64c7e4 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/optionsparser.cpp @@ -0,0 +1,232 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "optionsparser.h" +#include "messages.h" +#include "exception.h" + +#include <QtCore/QDir> +#include <QtCore/QTextStream> + +using namespace Qt::StringLiterals; + +template <class Stream> void formatBoolOption(Stream &s, const BoolOption &bo) +{ + switch (bo.source) { + case OptionSource::CommandLine: + s << "--"; + break; + case OptionSource::CommandLineSingleDash: + s << '-'; + break; + default: + break; + } + s << bo.option; + if (bo.source == OptionSource::ProjectFile) + s << " (project)"; +} + +template <class Stream> void formatOptionValue(Stream &s, const OptionValue &ov) +{ + switch (ov.source) { + case OptionSource::CommandLine: + s << "--"; + break; + case OptionSource::CommandLineSingleDash: + s << '-'; + break; + default: + break; + } + s << ov.option << '=' << ov.value; + if (ov.source == OptionSource::ProjectFile) + s << " (project)"; +} + +QTextStream &operator<<(QTextStream &s, const BoolOption &bo) +{ + formatBoolOption(s, bo); + return s; +} + +QTextStream &operator<<(QTextStream &s, const OptionValue &ov) +{ + formatOptionValue(s, ov); + return s; +} + +QDebug operator<<(QDebug debug, const BoolOption &bo) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + formatBoolOption(debug, bo); + return debug; +} + +QDebug operator<<(QDebug debug, const OptionValue &v) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + formatOptionValue(debug, v); + return debug; +} + +QDebug operator<<(QDebug debug, const Options &v) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "Options("; + if (!v.boolOptions.isEmpty()) + debug << "bools=" << v.boolOptions; + if (!v.valueOptions.isEmpty()) + debug << ", option values=" << v.valueOptions; + if (!v.positionalArguments.isEmpty()) + debug << ", pos=" << v.positionalArguments; + debug << ')'; + return debug; +} + +QTextStream &operator<<(QTextStream &s, const OptionDescription &od) +{ + if (!od.name.startsWith(u'-')) + s << "--"; + s << od.name; + if (od.description.isEmpty()) { // For formatting {{"-s", ""}, {"--short", "descr"}} + s << ", "; + } else { + s << '\n'; + const auto lines = QStringView{od.description}.split(u'\n'); + for (const auto &line : lines) + s << " " << line << '\n'; + s << '\n'; + } + return s; +} + +QTextStream &operator<<(QTextStream &s, const OptionDescriptions &options) +{ + s.setFieldAlignment(QTextStream::AlignLeft); + for (const auto &od : options) + s << od; + return s; +} + +OptionsParser::OptionsParser() noexcept = default; +OptionsParser::~OptionsParser() = default; + +const QString &OptionsParser::pathSyntax() +{ + static const QString result = + u"<path>["_s + QDir::listSeparator() + u"<path>"_s + + QDir::listSeparator() + u"...]"_s; + return result; +} + +bool OptionsParser::handleBoolOption(const QString &, OptionSource) +{ + return false; +} + +bool OptionsParser::handleOption(const QString &, const QString &, OptionSource) +{ + return false; +} + +void OptionsParser::process(Options *o) +{ + for (auto i = o->boolOptions.size() - 1; i >= 0; --i) { + const auto &opt = o->boolOptions.at(i); + if (handleBoolOption(opt.option, opt.source)) + o->boolOptions.removeAt(i); + } + for (auto i = o->valueOptions.size() - 1; i >= 0; --i) { + const auto &opt = o->valueOptions.at(i); + if (handleOption(opt.option, opt.value, opt.source)) + o->valueOptions.removeAt(i); + } +} + +bool OptionsParserList::handleBoolOption(const QString &key, OptionSource source) +{ + for (const auto &p : std::as_const(m_parsers)) { + if (p->handleBoolOption(key, source)) + return true; + } + return false; +} + +bool OptionsParserList::handleOption(const QString &key, const QString &value, OptionSource source) +{ + for (const auto &p : std::as_const(m_parsers)) { + if (p->handleOption(key, value, source)) + return true; + } + return false; +} + +static void processOption(const QString &o, OptionSource source, + BoolOptions *bools, OptionValues *values) +{ + const auto equals = o.indexOf(u'='); + if (equals == -1) { + bools->append({o.trimmed(), source}); + } else { + QString key = o.left(equals).trimmed(); + QString value = o.mid(equals + 1).trimmed(); + if (!value.isEmpty()) + values->append({key, value, source}); + } +} + +static void readProjectFile(const QString &name, Options *o) +{ + const auto startMarker = "[generator-project]"_ba; + + QFile file(name); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + throw Exception(msgCannotOpenForReading(file)); + + if (file.atEnd() || file.readLine().trimmed() != startMarker) + throw Exception(msgMissingProjectFileMarker(name, startMarker)); + + while (!file.atEnd()) { + const QByteArray lineB = file.readLine().trimmed(); + if (!lineB.isEmpty() && !lineB.startsWith('#')) { + processOption(QString::fromUtf8(lineB), OptionSource::ProjectFile, + &o->boolOptions, &o->valueOptions); + } + } +} + +void Options::setOptions(const QStringList &argv) +{ + const auto projectFileOption = "--project-file="_L1; + for (const auto &o : argv) { + if (o.startsWith(projectFileOption)) { + readProjectFile(o.sliced(projectFileOption.size()), this); + } else if (o.startsWith(u"--")) { + processOption(o.sliced(2), OptionSource::CommandLine, + &boolOptions, &valueOptions); + } else if (o.startsWith(u'-')) { + processOption(o.sliced(1), OptionSource::CommandLineSingleDash, + &boolOptions, &valueOptions); + } else { + positionalArguments.append(o); + } + } +} + +QString Options::msgUnprocessedOptions() const +{ + QString result; + QTextStream str(&result); + for (const auto &b : boolOptions) + str << b << ' '; + for (const auto &v : valueOptions) + str << v << ' '; + return result.trimmed(); +} diff --git a/sources/shiboken6/ApiExtractor/optionsparser.h b/sources/shiboken6/ApiExtractor/optionsparser.h new file mode 100644 index 000000000..d5557dc15 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/optionsparser.h @@ -0,0 +1,98 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef OPTIONSPARSER_H +#define OPTIONSPARSER_H + +#include <QtCore/QString> +#include <QtCore/QStringList> + +#include <memory> + +QT_FORWARD_DECLARE_CLASS(QTextStream) + +enum class OptionSource +{ + CommandLine, // "--option" + CommandLineSingleDash, // "-o" + ProjectFile +}; + +struct BoolOption +{ + QString option; + OptionSource source = OptionSource::CommandLine; +}; + +struct OptionValue // --option=value pair +{ + QString option; + QString value; + OptionSource source = OptionSource::CommandLine; +}; + +using BoolOptions = QList<BoolOption>; +using OptionValues = QList<OptionValue>; + +struct Options // Options from command line and project file +{ + void setOptions(const QStringList &argv); + QString msgUnprocessedOptions() const; + + BoolOptions boolOptions; + OptionValues valueOptions; + QStringList positionalArguments; +}; + +struct OptionDescription // For help formatting +{ + QString name; + QString description; +}; + +using OptionDescriptions = QList<OptionDescription>; + +QTextStream &operator<<(QTextStream &s, const BoolOption &bo); +QTextStream &operator<<(QTextStream &s, const OptionValue &ov); +QTextStream &operator<<(QTextStream &s, const OptionDescription &od); +QTextStream &operator<<(QTextStream &s, const OptionDescriptions &options); + +class OptionsParser +{ +public: + Q_DISABLE_COPY_MOVE(OptionsParser) + + virtual ~OptionsParser(); + + // Return true to indicate the option was processed. + virtual bool handleBoolOption(const QString &key, OptionSource source); + virtual bool handleOption(const QString &key, const QString &value, OptionSource source); + + void process(Options *); + + static const QString &pathSyntax(); + +protected: + OptionsParser() noexcept; +}; + +class OptionsParserList : public OptionsParser +{ +public: + using OptionsParserPtr = std::shared_ptr<OptionsParser>; + + void append(const OptionsParserPtr &parser) { m_parsers.append(parser); } + void clear() { m_parsers.clear(); } + + bool handleBoolOption(const QString &key, OptionSource source) override; + bool handleOption(const QString &key, const QString &value, OptionSource source) override; + +private: + QList<OptionsParserPtr> m_parsers; +}; + +QDebug operator<<(QDebug debug, const BoolOption &bo); +QDebug operator<<(QDebug debug, const OptionValue &v); +QDebug operator<<(QDebug debug, const Options &v); + +#endif // OPTIONSPARSER_H diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp index 82f5e1a2c..259a706dc 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp +++ b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp @@ -1,61 +1,29 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "codemodel.h" #include <sourcelocation.h> +#include <debughelpers_p.h> #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QRegularExpression> #include <algorithm> -#include <functional> -#include <iostream> -// Predicate to find an item by name in a list of QSharedPointer<Item> -template <class T> class ModelItemNamePredicate -{ -public: - explicit ModelItemNamePredicate(const QString &name) : m_name(name) {} - bool operator()(const QSharedPointer<T> &item) const { return item->name() == m_name; } - -private: - const QString m_name; -}; +using namespace Qt::StringLiterals; template <class T> -static QSharedPointer<T> findModelItem(const QList<QSharedPointer<T> > &list, const QString &name) +static std::shared_ptr<T> findModelItem(const QList<std::shared_ptr<T> > &list, + QAnyStringView name) { - const auto it = std::find_if(list.cbegin(), list.cend(), ModelItemNamePredicate<T>(name)); - return it != list.cend() ? *it : QSharedPointer<T>(); + using ItemPtr = std::shared_ptr<T>; + auto pred = [name](const ItemPtr &item) { return item->name() == name; }; + const auto it = std::find_if(list.cbegin(), list.cend(), pred); + return it != list.cend() ? *it : ItemPtr{}; } // --------------------------------------------------------------------------- @@ -76,7 +44,7 @@ void CodeModel::addFile(const FileModelItem &item) m_files.append(item); } -FileModelItem CodeModel::findFile(const QString &name) const +FileModelItem CodeModel::findFile(QAnyStringView name) const { return findModelItem(m_files, name); } @@ -94,11 +62,11 @@ static CodeModelItem findRecursion(const ScopeModelItem &scope, return tp; if (TemplateTypeAliasModelItem tta = scope->findTemplateTypeAlias(nameSegment)) return tta; - return CodeModelItem(); + return {}; } if (auto nestedClass = scope->findClass(nameSegment)) return findRecursion(nestedClass, qualifiedName, segment + 1); - if (auto namespaceItem = qSharedPointerDynamicCast<_NamespaceModelItem>(scope)) { + if (auto namespaceItem = std::dynamic_pointer_cast<_NamespaceModelItem>(scope)) { for (const auto &nestedNamespace : namespaceItem->namespaces()) { if (nestedNamespace->name() == nameSegment) { if (auto item = findRecursion(nestedNamespace, qualifiedName, segment + 1)) @@ -106,7 +74,7 @@ static CodeModelItem findRecursion(const ScopeModelItem &scope, } } } - return CodeModelItem(); + return {}; } CodeModelItem CodeModel::findItem(const QStringList &qualifiedName, const ScopeModelItem &scope) @@ -143,7 +111,7 @@ QDebug operator<<(QDebug d, const CodeModel *m) d << "CodeModel("; if (m) { const NamespaceModelItem globalNamespaceP = m->globalNamespace(); - if (globalNamespaceP.data()) + if (globalNamespaceP) globalNamespaceP->formatDebug(d); } else { d << '0'; @@ -256,27 +224,27 @@ SourceLocation _CodeModelItem::sourceLocation() const return SourceLocation(m_fileName, m_startLine); } -#ifndef QT_NO_DEBUG_STREAM -template <class It> -void formatSequence(QDebug &d, It i1, It i2, const char *separator=", ") +const _ScopeModelItem *_CodeModelItem::enclosingScope() const { - for (It i = i1; i != i2; ++i) { - if (i != i1) - d << separator; - d << *i; - } + return m_enclosingScope; } -template <class It> -static void formatPtrSequence(QDebug &d, It i1, It i2, const char *separator=", ") +void _CodeModelItem::setEnclosingScope(const _ScopeModelItem *s) +{ + m_enclosingScope = s; +} + +_ScopeModelItem::_ScopeModelItem(CodeModel *model, int kind) + : _CodeModelItem(model, kind) +{ +} + +_ScopeModelItem::_ScopeModelItem(CodeModel *model, const QString &name, int kind) + : _CodeModelItem(model, name, kind) { - for (It i = i1; i != i2; ++i) { - if (i != i1) - d << separator; - d << i->data(); - } } +#ifndef QT_NO_DEBUG_STREAM void _CodeModelItem::formatKind(QDebug &d, int k) { switch (k) { @@ -377,14 +345,6 @@ void _ClassModelItem::setTemplateParameters(const TemplateParameterList &templat m_templateParameters = templateParameters; } -void _ClassModelItem::addBaseClass(const QString &name, Access accessPolicy) -{ - _ClassModelItem::BaseClass baseClass; - baseClass.name = name; - baseClass.accessPolicy = accessPolicy; - m_baseClasses.append(baseClass); -} - bool _ClassModelItem::extendsClass(const QString &name) const { for (const BaseClass &bc : m_baseClasses) { @@ -394,6 +354,16 @@ bool _ClassModelItem::extendsClass(const QString &name) const return false; } +_ClassModelItem::_ClassModelItem(CodeModel *model, int kind) + : _ScopeModelItem(model, kind) +{ +} + +_ClassModelItem::_ClassModelItem(CodeModel *model, const QString &name, int kind) + : _ScopeModelItem(model, name, kind) +{ +} + const QList<_ClassModelItem::UsingMember> &_ClassModelItem::usingMembers() const { return m_usingMembers; @@ -436,9 +406,9 @@ template <class List> static void formatModelItemList(QDebug &d, const char *prefix, const List &l, const char *separator = ", ") { - if (const int size = l.size()) { + if (const auto size = l.size()) { d << prefix << '[' << size << "]("; - for (int i = 0; i < size; ++i) { + for (qsizetype i = 0; i < size; ++i) { if (i) d << separator; l.at(i)->formatDebug(d); @@ -455,7 +425,7 @@ void _ClassModelItem::formatDebug(QDebug &d) const d << " [final]"; d << ", inherits="; d << ", inherits="; - for (int i = 0, size = m_baseClasses.size(); i < size; ++i) { + for (qsizetype i = 0, size = m_baseClasses.size(); i < size; ++i) { if (i) d << ", "; d << m_baseClasses.at(i).name << " (" << m_baseClasses.at(i).accessPolicy << ')'; @@ -474,12 +444,12 @@ void _ClassModelItem::formatDebug(QDebug &d) const // --------------------------------------------------------------------------- FunctionModelItem _ScopeModelItem::declaredFunction(const FunctionModelItem &item) { - for (const FunctionModelItem &fun : qAsConst(m_functions)) { + for (const FunctionModelItem &fun : std::as_const(m_functions)) { if (fun->name() == item->name() && fun->isSimilar(item)) return fun; } - return FunctionModelItem(); + return {}; } _ScopeModelItem::~_ScopeModelItem() = default; @@ -492,30 +462,54 @@ void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration) void _ScopeModelItem::addClass(const ClassModelItem &item) { m_classes.append(item); + item->setEnclosingScope(this); } void _ScopeModelItem::addFunction(const FunctionModelItem &item) { m_functions.append(item); + item->setEnclosingScope(this); } void _ScopeModelItem::addVariable(const VariableModelItem &item) { m_variables.append(item); + item->setEnclosingScope(this); } void _ScopeModelItem::addTypeDef(const TypeDefModelItem &item) { m_typeDefs.append(item); + item->setEnclosingScope(this); } void _ScopeModelItem::addTemplateTypeAlias(const TemplateTypeAliasModelItem &item) { m_templateTypeAliases.append(item); + item->setEnclosingScope(this); +} + +qsizetype _ScopeModelItem::indexOfEnum(const QString &name) const +{ + for (qsizetype i = 0, size = m_enums.size(); i < size; ++i) { + if (m_enums.at(i)->name() == name) + return i; + } + return -1; } void _ScopeModelItem::addEnum(const EnumModelItem &item) { + item->setEnclosingScope(this); + // A forward declaration of an enum ("enum class Foo;") is undistinguishable + // from an enum without values ("enum class QCborTag {}"), so, add all + // enums and replace existing ones without values by ones with values. + const int index = indexOfEnum(item->name()); + if (index >= 0) { + if (item->hasValues() && !m_enums.at(index)->hasValues()) + m_enums[index] = item; + return; + } m_enums.append(item); } @@ -555,12 +549,12 @@ template class LIBSAMPLE_EXPORT Tpl<54>; */ void _ScopeModelItem::purgeClassDeclarations() { - for (int i = m_classes.size() - 1; i >= 0; --i) { + for (auto i = m_classes.size() - 1; i >= 0; --i) { auto klass = m_classes.at(i); // For an empty class, check if there is a matching template // definition, and remove it if this is the case. if (!klass->isTemplate() && klass->isEmpty()) { - const QString definitionPrefix = klass->name() + QLatin1Char('<'); + const QString definitionPrefix = klass->name() + u'<'; const bool definitionFound = std::any_of(m_classes.cbegin(), m_classes.cend(), [definitionPrefix] (const ClassModelItem &c) { @@ -624,57 +618,135 @@ void _ScopeModelItem::formatDebug(QDebug &d) const } #endif // !QT_NO_DEBUG_STREAM -namespace { // Predicate to match a non-template class name against the class list. // "Vector" should match "Vector" as well as "Vector<T>" (as seen for methods // from within the class "Vector"). -class ClassNamePredicate +static bool matchClassNameNonTemplatePart(const ClassModelItem &item, const QString &name) { -public: - explicit ClassNamePredicate(const QString &name) : m_name(name) {} - bool operator()(const ClassModelItem &item) const - { - const QString &itemName = item->name(); - if (!itemName.startsWith(m_name)) - return false; - return itemName.size() == m_name.size() || itemName.at(m_name.size()) == QLatin1Char('<'); - } - -private: - const QString m_name; -}; -} // namespace + const QString &itemName = item->name(); + if (!itemName.startsWith(name)) + return false; + return itemName.size() == name.size() || itemName.at(name.size()) == u'<'; +} ClassModelItem _ScopeModelItem::findClass(const QString &name) const { // A fully qualified template is matched by name only - const ClassList::const_iterator it = name.contains(QLatin1Char('<')) - ? std::find_if(m_classes.begin(), m_classes.end(), ModelItemNamePredicate<_ClassModelItem>(name)) - : std::find_if(m_classes.begin(), m_classes.end(), ClassNamePredicate(name)); + const ClassList::const_iterator it = name.contains(u'<') + ? std::find_if(m_classes.begin(), m_classes.end(), + [&name](const ClassModelItem &item) { + return item->name() == name; }) + : std::find_if(m_classes.begin(), m_classes.end(), + [&name](const ClassModelItem &item) { + return matchClassNameNonTemplatePart(item, name); }); return it != m_classes.end() ? *it : ClassModelItem(); } -VariableModelItem _ScopeModelItem::findVariable(const QString &name) const +VariableModelItem _ScopeModelItem::findVariable(QAnyStringView name) const { return findModelItem(m_variables, name); } -TypeDefModelItem _ScopeModelItem::findTypeDef(const QString &name) const +TypeDefModelItem _ScopeModelItem::findTypeDef(QAnyStringView name) const { return findModelItem(m_typeDefs, name); } -TemplateTypeAliasModelItem _ScopeModelItem::findTemplateTypeAlias(const QString &name) const +TemplateTypeAliasModelItem _ScopeModelItem::findTemplateTypeAlias(QAnyStringView name) const { return findModelItem(m_templateTypeAliases, name); } -EnumModelItem _ScopeModelItem::findEnum(const QString &name) const +EnumModelItem _ScopeModelItem::findEnum(QAnyStringView name) const { return findModelItem(m_enums, name); } -FunctionList _ScopeModelItem::findFunctions(const QString &name) const +_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"::"_s; + scopePrefix += name() + u"::"_s; + + 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"::"_s; + 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.get() != scope && sibling->name() == scope->name()) { + if (const auto e = findEnumByValueRecursion(sibling.get(), + 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) { + auto *c = base.klass.get(); + 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(QAnyStringView name) const { FunctionList result; for (const FunctionModelItem &func : m_functions) { @@ -685,16 +757,25 @@ FunctionList _ScopeModelItem::findFunctions(const QString &name) const } // --------------------------------------------------------------------------- -_NamespaceModelItem::~_NamespaceModelItem() +_NamespaceModelItem::_NamespaceModelItem(CodeModel *model, int kind) + : _ScopeModelItem(model, kind) { } +_NamespaceModelItem::_NamespaceModelItem(CodeModel *model, const QString &name, int kind) + : _ScopeModelItem(model, name, kind) +{ +} + +_NamespaceModelItem::~_NamespaceModelItem() = default; + void _NamespaceModelItem::addNamespace(NamespaceModelItem item) { + item->setEnclosingScope(this); m_namespaces.append(item); } -NamespaceModelItem _NamespaceModelItem::findNamespace(const QString &name) const +NamespaceModelItem _NamespaceModelItem::findNamespace(QAnyStringView name) const { return findModelItem(m_namespaces, name); } @@ -726,10 +807,18 @@ void _NamespaceModelItem::formatDebug(QDebug &d) const #endif // !QT_NO_DEBUG_STREAM // --------------------------------------------------------------------------- -_ArgumentModelItem::~_ArgumentModelItem() +_ArgumentModelItem::_ArgumentModelItem(CodeModel *model, int kind) + : _CodeModelItem(model, kind) { } +_ArgumentModelItem::_ArgumentModelItem(CodeModel *model, const QString &name, int kind) + : _CodeModelItem(model, name, kind) +{ +} + +_ArgumentModelItem::~_ArgumentModelItem() = default; + TypeInfo _ArgumentModelItem::type() const { return m_type; @@ -750,11 +839,23 @@ void _ArgumentModelItem::setDefaultValue(bool defaultValue) m_defaultValue = defaultValue; } +bool _ArgumentModelItem::scopeResolution() const +{ + return m_scopeResolution; +} + +void _ArgumentModelItem::setScopeResolution(bool v) +{ + m_scopeResolution = v; +} + #ifndef QT_NO_DEBUG_STREAM void _ArgumentModelItem::formatDebug(QDebug &d) const { _CodeModelItem::formatDebug(d); d << ", type=" << m_type; + if (m_scopeResolution) + d << ", [m_scope resolution]"; if (m_defaultValue) d << ", defaultValue=\"" << m_defaultValueExpression << '"'; } @@ -773,12 +874,12 @@ bool _FunctionModelItem::isSimilar(const FunctionModelItem &other) const if (isVariadics() != other->isVariadics()) return false; - if (arguments().count() != other->arguments().count()) + if (arguments().size() != other->arguments().size()) return false; // ### check the template parameters - for (int i = 0; i < arguments().count(); ++i) { + for (qsizetype i = 0; i < arguments().size(); ++i) { ArgumentModelItem arg1 = arguments().at(i); ArgumentModelItem arg2 = other->arguments().at(i); @@ -789,6 +890,16 @@ bool _FunctionModelItem::isSimilar(const FunctionModelItem &other) const return true; } +_FunctionModelItem::_FunctionModelItem(CodeModel *model, int kind) + : _MemberModelItem(model, kind), m_flags(0) +{ +} + +_FunctionModelItem::_FunctionModelItem(CodeModel *model, const QString &name, int kind) + : _MemberModelItem(model, name, kind), m_flags(0) +{ +} + ArgumentList _FunctionModelItem::arguments() const { return m_arguments; @@ -819,55 +930,76 @@ void _FunctionModelItem::setVariadics(bool isVariadics) m_isVariadics = isVariadics; } -bool _FunctionModelItem::isDefaultConstructor() const +bool _FunctionModelItem::scopeResolution() const { - return m_functionType == CodeModel::Constructor - && (m_arguments.isEmpty() || m_arguments.constFirst()->defaultValue()); + return m_scopeResolution; } -bool _FunctionModelItem::isNoExcept() const +void _FunctionModelItem::setScopeResolution(bool v) { - return m_exceptionSpecification == ExceptionSpecification::NoExcept; + m_scopeResolution = v; } -ExceptionSpecification _FunctionModelItem::exceptionSpecification() const +bool _FunctionModelItem::isDefaultConstructor() const { - return m_exceptionSpecification; + return m_functionType == CodeModel::Constructor + && (m_arguments.isEmpty() || m_arguments.constFirst()->defaultValue()); } -void _FunctionModelItem::setExceptionSpecification(ExceptionSpecification e) +bool _FunctionModelItem::isSpaceshipOperator() const { - m_exceptionSpecification = e; + return m_functionType == CodeModel::ComparisonOperator + && name() == u"operator<=>"; } -bool _FunctionModelItem::isDeleted() const +bool _FunctionModelItem::isNoExcept() const { - return m_isDeleted; + return m_exceptionSpecification == ExceptionSpecification::NoExcept; } -void _FunctionModelItem::setDeleted(bool d) +bool _FunctionModelItem::isOperator() const { - m_isDeleted = d; + bool result = false; + switch (m_functionType) { + case CodeModel::CallOperator: + case CodeModel::ConversionOperator: + case CodeModel::DereferenceOperator: + case CodeModel::ReferenceOperator: + case CodeModel::ArrowOperator: + case CodeModel::ArithmeticOperator: + case CodeModel::IncrementOperator: + case CodeModel::DecrementOperator: + case CodeModel::BitwiseOperator: + case CodeModel::LogicalOperator: + case CodeModel::ShiftOperator: + case CodeModel::SubscriptOperator: + case CodeModel::ComparisonOperator: + result = true; + break; + default: + break; + } + return result; } -bool _FunctionModelItem::isDeprecated() const +ExceptionSpecification _FunctionModelItem::exceptionSpecification() const { - return m_isDeprecated; + return m_exceptionSpecification; } -void _FunctionModelItem::setDeprecated(bool d) +void _FunctionModelItem::setExceptionSpecification(ExceptionSpecification e) { - m_isDeprecated = d; + m_exceptionSpecification = e; } -bool _FunctionModelItem::isVirtual() const +bool _FunctionModelItem::isDeleted() const { - return m_isVirtual; + return m_isDeleted; } -void _FunctionModelItem::setVirtual(bool isVirtual) +void _FunctionModelItem::setDeleted(bool d) { - m_isVirtual = isVirtual; + m_isDeleted = d; } bool _FunctionModelItem::isInline() const @@ -875,60 +1007,19 @@ bool _FunctionModelItem::isInline() const return m_isInline; } -bool _FunctionModelItem::isOverride() const -{ - return m_isOverride; -} - -void _FunctionModelItem::setOverride(bool o) -{ - m_isOverride = o; -} - -bool _FunctionModelItem::isFinal() const -{ - return m_isFinal; -} - -void _FunctionModelItem::setFinal(bool f) -{ - m_isFinal = f; -} - void _FunctionModelItem::setInline(bool isInline) { m_isInline = isInline; } -bool _FunctionModelItem::isExplicit() const -{ - return m_isExplicit; -} - -void _FunctionModelItem::setExplicit(bool isExplicit) -{ - m_isExplicit = isExplicit; -} - -bool _FunctionModelItem::isAbstract() const +bool _FunctionModelItem::isHiddenFriend() const { - return m_isAbstract; + return m_isHiddenFriend; } -void _FunctionModelItem::setAbstract(bool isAbstract) +void _FunctionModelItem::setHiddenFriend(bool f) { - m_isAbstract = isAbstract; -} - -// Qt -bool _FunctionModelItem::isInvokable() const -{ - return m_isInvokable; -} - -void _FunctionModelItem::setInvokable(bool isInvokable) -{ - m_isInvokable = isInvokable; + m_isHiddenFriend = f; } QString _FunctionModelItem::typeSystemSignature() const // For dumping out type system files @@ -936,7 +1027,7 @@ QString _FunctionModelItem::typeSystemSignature() const // For dumping out type QString result; QTextStream str(&result); str << name() << '('; - for (int a = 0, size = m_arguments.size(); a < size; ++a) { + for (qsizetype a = 0, size = m_arguments.size(); a < size; ++a) { if (a) str << ','; m_arguments.at(a)->type().formatTypeSystemSignature(str); @@ -980,6 +1071,7 @@ static const NameFunctionTypeHash &nameToOperatorFunction() {u"operator>=", CodeModel::ComparisonOperator}, {u"operator==", CodeModel::ComparisonOperator}, {u"operator!=", CodeModel::ComparisonOperator}, + {u"operator<=>", CodeModel::ComparisonOperator}, {u"operator!", CodeModel::LogicalOperator}, {u"operator&&", CodeModel::LogicalOperator}, {u"operator||", CodeModel::LogicalOperator}, @@ -1054,20 +1146,22 @@ void _FunctionModelItem::formatDebug(QDebug &d) const d << " [deleted!]"; if (m_isInline) d << " [inline]"; - if (m_isVirtual) + if (m_attributes.testFlag(FunctionAttribute::Virtual)) d << " [virtual]"; - if (m_isOverride) + if (m_attributes.testFlag(FunctionAttribute::Override)) d << " [override]"; - if (m_isDeprecated) + if (m_attributes.testFlag(FunctionAttribute::Deprecated)) d << " [deprecated]"; - if (m_isFinal) + if (m_attributes.testFlag(FunctionAttribute::Final)) d << " [final]"; - if (m_isAbstract) + if (m_attributes.testFlag(FunctionAttribute::Abstract)) d << " [abstract]"; - if (m_isExplicit) + if (m_attributes.testFlag(FunctionAttribute::Explicit)) d << " [explicit]"; if (m_isInvokable) d << " [invokable]"; + if (m_scopeResolution) + d << " [scope resolution]"; formatModelItemList(d, ", arguments=", m_arguments); if (m_isVariadics) d << ",..."; @@ -1075,6 +1169,16 @@ void _FunctionModelItem::formatDebug(QDebug &d) const #endif // !QT_NO_DEBUG_STREAM // --------------------------------------------------------------------------- +_TypeDefModelItem::_TypeDefModelItem(CodeModel *model, int kind) + : _CodeModelItem(model, kind) +{ +} + +_TypeDefModelItem::_TypeDefModelItem(CodeModel *model, const QString &name, int kind) + : _CodeModelItem(model, name, kind) +{ +} + TypeInfo _TypeDefModelItem::type() const { return m_type; @@ -1126,7 +1230,7 @@ void _TemplateTypeAliasModelItem::formatDebug(QDebug &d) const { _CodeModelItem::formatDebug(d); d << ", <"; - for (int i = 0, count = m_templateParameters.size(); i < count; ++i) { + for (qsizetype i = 0, count = m_templateParameters.size(); i < count; ++i) { if (i) d << ", "; d << m_templateParameters.at(i)->name(); @@ -1136,6 +1240,16 @@ void _TemplateTypeAliasModelItem::formatDebug(QDebug &d) const #endif // !QT_NO_DEBUG_STREAM // --------------------------------------------------------------------------- +_EnumModelItem::_EnumModelItem(CodeModel *model, const QString &name, int kind) + : _CodeModelItem(model, name, kind) +{ +} + +_EnumModelItem::_EnumModelItem(CodeModel *model, int kind) + : _CodeModelItem(model, kind) +{ +} + Access _EnumModelItem::accessPolicy() const { return m_accessPolicy; @@ -1158,6 +1272,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; @@ -1168,6 +1291,26 @@ void _EnumModelItem::setSigned(bool s) m_signed = s; } +QString _EnumModelItem::underlyingType() const +{ + return m_underlyingType; +} + +void _EnumModelItem::setUnderlyingType(const QString &underlyingType) +{ + m_underlyingType = underlyingType; +} + +bool _EnumModelItem::isDeprecated() const +{ + return m_deprecated; +} + +void _EnumModelItem::setDeprecated(bool d) +{ + m_deprecated = d; +} + #ifndef QT_NO_DEBUG_STREAM void _EnumModelItem::formatDebug(QDebug &d) const { @@ -1182,6 +1325,8 @@ void _EnumModelItem::formatDebug(QDebug &d) const d << " (class)"; break; } + if (m_deprecated) + d << " (deprecated)"; if (!m_signed) d << " (unsigned)"; formatModelItemList(d, ", enumerators=", m_enumerators); @@ -1191,6 +1336,16 @@ void _EnumModelItem::formatDebug(QDebug &d) const // --------------------------------------------------------------------------- _EnumeratorModelItem::~_EnumeratorModelItem() = default; +_EnumeratorModelItem::_EnumeratorModelItem(CodeModel *model, int kind) + : _CodeModelItem(model, kind) +{ +} + +_EnumeratorModelItem::_EnumeratorModelItem(CodeModel *model, const QString &name, int kind) + : _CodeModelItem(model, name, kind) +{ +} + QString _EnumeratorModelItem::stringValue() const { return m_stringValue; @@ -1201,17 +1356,40 @@ void _EnumeratorModelItem::setStringValue(const QString &value) m_stringValue = value; } +bool _EnumeratorModelItem::isDeprecated() const +{ + return m_deprecated; +} + +void _EnumeratorModelItem::setDeprecated(bool d) +{ + m_deprecated = d; +} + #ifndef QT_NO_DEBUG_STREAM void _EnumeratorModelItem::formatDebug(QDebug &d) const { _CodeModelItem::formatDebug(d); d << ", value=" << m_value << ", stringValue=\"" << m_stringValue << '"'; + if (m_deprecated) + d << " (deprecated)"; } #endif // !QT_NO_DEBUG_STREAM // --------------------------------------------------------------------------- _TemplateParameterModelItem::~_TemplateParameterModelItem() = default; +_TemplateParameterModelItem::_TemplateParameterModelItem(CodeModel *model, int kind) + : _CodeModelItem(model, kind) +{ +} + +_TemplateParameterModelItem::_TemplateParameterModelItem(CodeModel *model, + const QString &name, int kind) + : _CodeModelItem(model, name, kind) +{ +} + TypeInfo _TemplateParameterModelItem::type() const { return m_type; @@ -1275,6 +1453,16 @@ void _MemberModelItem::setStatic(bool isStatic) m_isStatic = isStatic; } +_MemberModelItem::_MemberModelItem(CodeModel *model, int kind) + : _CodeModelItem(model, kind), m_flags(0) +{ +} + +_MemberModelItem::_MemberModelItem(CodeModel *model, const QString &name, int kind) + : _CodeModelItem(model, name, kind), m_flags(0) +{ +} + bool _MemberModelItem::isConstant() const { return m_isConstant; diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.h b/sources/shiboken6/ApiExtractor/parser/codemodel.h index 75ad60aaf..b31c09163 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel.h +++ b/sources/shiboken6/ApiExtractor/parser/codemodel.h @@ -1,31 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CODEMODEL_H @@ -37,13 +12,14 @@ #include "typeinfo.h" #include <QtCore/QHash> -#include <QtCore/QPair> #include <QtCore/QSet> #include <QtCore/QString> #include <QtCore/QStringList> #include <QtCore/QList> +#include <QtCore/QWeakPointer> #include <optional> +#include <utility> QT_FORWARD_DECLARE_CLASS(QDebug) @@ -56,7 +32,7 @@ class CodeModel { Q_GADGET public: - Q_DISABLE_COPY(CodeModel) + Q_DISABLE_COPY_MOVE(CodeModel) enum FunctionType { Normal, @@ -98,7 +74,7 @@ public: NamespaceModelItem globalNamespace() const; void addFile(const FileModelItem &item); - FileModelItem findFile(const QString &name) const; + FileModelItem findFile(QAnyStringView name) const; static CodeModelItem findItem(const QStringList &qualifiedName, const ScopeModelItem &scope); @@ -115,8 +91,9 @@ QDebug operator<<(QDebug d, const CodeModel *m); class _CodeModelItem { - Q_DISABLE_COPY(_CodeModelItem) public: + Q_DISABLE_COPY_MOVE(_CodeModelItem) + enum Kind { /* These are bit-flags resembling inheritance */ Kind_Scope = 0x1, @@ -167,6 +144,9 @@ public: inline CodeModel *model() const { return m_model; } + const _ScopeModelItem *enclosingScope() const; + void setEnclosingScope(const _ScopeModelItem *s); + #ifndef QT_NO_DEBUG_STREAM static void formatKind(QDebug &d, int k); virtual void formatDebug(QDebug &d) const; @@ -178,6 +158,7 @@ protected: private: CodeModel *m_model; + const _ScopeModelItem *m_enclosingScope = nullptr; int m_kind; int m_startLine; int m_startColumn; @@ -195,12 +176,13 @@ QDebug operator<<(QDebug d, const _CodeModelItem *t); class _ScopeModelItem: public _CodeModelItem { public: + Q_DISABLE_COPY_MOVE(_ScopeModelItem) DECLARE_MODEL_NODE(Scope) ~_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; } @@ -214,11 +196,21 @@ public: void addVariable(const VariableModelItem &item); ClassModelItem findClass(const QString &name) const; - EnumModelItem findEnum(const QString &name) const; - FunctionList findFunctions(const QString &name) const; - TypeDefModelItem findTypeDef(const QString &name) const; - TemplateTypeAliasModelItem findTemplateTypeAlias(const QString &name) const; - VariableModelItem findVariable(const QString &name) const; + EnumModelItem findEnum(QAnyStringView name) const; + + struct FindEnumByValueReturn + { + operator bool() const { return bool(item); } + + EnumModelItem item; + QString qualifiedName; + }; + FindEnumByValueReturn findEnumByValue(QStringView value) const; + + FunctionList findFunctions(QAnyStringView name) const; + TypeDefModelItem findTypeDef(QAnyStringView name) const; + TemplateTypeAliasModelItem findTemplateTypeAlias(QAnyStringView name) const; + VariableModelItem findVariable(QAnyStringView name) const; void addEnumsDeclaration(const QString &enumsDeclaration); QStringList enumsDeclarations() const { return m_enumsDeclarations; } @@ -233,10 +225,9 @@ public: #endif protected: - explicit _ScopeModelItem(CodeModel *model, int kind = __node_kind) - : _CodeModelItem(model, kind) {} - explicit _ScopeModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _CodeModelItem(model, name, kind) {} + explicit _ScopeModelItem(CodeModel *model, int kind = __node_kind); + explicit _ScopeModelItem(CodeModel *model, const QString &name, + int kind = __node_kind); void appendScope(const _ScopeModelItem &other); @@ -245,6 +236,15 @@ protected: #endif 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; @@ -259,11 +259,13 @@ private: class _ClassModelItem: public _ScopeModelItem { public: + Q_DISABLE_COPY_MOVE(_ClassModelItem) DECLARE_MODEL_NODE(Class) struct BaseClass { QString name; + ClassModelItem klass; // Might be null in case of templates Access accessPolicy = Access::Public; }; @@ -274,19 +276,18 @@ public: Access access = Access::Public; }; - explicit _ClassModelItem(CodeModel *model, int kind = __node_kind) - : _ScopeModelItem(model, kind), m_classType(CodeModel::Class) {} - explicit _ClassModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _ScopeModelItem(model, name, kind), m_classType(CodeModel::Class) {} + explicit _ClassModelItem(CodeModel *model, int kind = __node_kind); + explicit _ClassModelItem(CodeModel *model, const QString &name, + int kind = __node_kind); ~_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, Access accessPolicy); - void addBaseClass(const QString &name, Access accessPolicy); + void addBaseClass(const BaseClass &b) { m_baseClasses.append(b); } TemplateParameterList templateParameters() const; void setTemplateParameters(const TemplateParameterList &templateParameters); @@ -313,7 +314,7 @@ private: QList<BaseClass> m_baseClasses; QList<UsingMember> m_usingMembers; TemplateParameterList m_templateParameters; - CodeModel::ClassType m_classType; + CodeModel::ClassType m_classType = CodeModel::Class; QStringList m_propertyDeclarations; bool m_final = false; @@ -322,12 +323,12 @@ private: class _NamespaceModelItem: public _ScopeModelItem { public: + Q_DISABLE_COPY_MOVE(_NamespaceModelItem) DECLARE_MODEL_NODE(Namespace) - explicit _NamespaceModelItem(CodeModel *model, int kind = __node_kind) - : _ScopeModelItem(model, kind) {} - explicit _NamespaceModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _ScopeModelItem(model, name, kind) {} + explicit _NamespaceModelItem(CodeModel *model, int kind = __node_kind); + explicit _NamespaceModelItem(CodeModel *model, const QString &name, + int kind = __node_kind); ~_NamespaceModelItem(); const NamespaceList &namespaces() const { return m_namespaces; } @@ -337,7 +338,7 @@ public: void addNamespace(NamespaceModelItem item); - NamespaceModelItem findNamespace(const QString &name) const; + NamespaceModelItem findNamespace(QAnyStringView name) const; void appendNamespace(const _NamespaceModelItem &other); @@ -353,24 +354,23 @@ private: class _FileModelItem: public _NamespaceModelItem { public: + Q_DISABLE_COPY_MOVE(_FileModelItem) DECLARE_MODEL_NODE(File) - explicit _FileModelItem(CodeModel *model, int kind = __node_kind) - : _NamespaceModelItem(model, kind) {} - explicit _FileModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _NamespaceModelItem(model, name, kind) {} + using _NamespaceModelItem::_NamespaceModelItem; + ~_FileModelItem(); }; class _ArgumentModelItem: public _CodeModelItem { public: + Q_DISABLE_COPY_MOVE(_ArgumentModelItem) DECLARE_MODEL_NODE(Argument) - explicit _ArgumentModelItem(CodeModel *model, int kind = __node_kind) - : _CodeModelItem(model, kind), m_defaultValue(false) {} - explicit _ArgumentModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _CodeModelItem(model, name, kind), m_defaultValue(false) {} + explicit _ArgumentModelItem(CodeModel *model, int kind = __node_kind); + explicit _ArgumentModelItem(CodeModel *model, const QString &name, + int kind = __node_kind); ~_ArgumentModelItem(); TypeInfo type() const; @@ -382,6 +382,10 @@ public: QString defaultValueExpression() const { return m_defaultValueExpression; } void setDefaultValueExpression(const QString &expr) { m_defaultValueExpression = expr; } + // Argument type has scope resolution "::ArgumentType" + bool scopeResolution() const; + void setScopeResolution(bool v); + #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; #endif @@ -389,18 +393,19 @@ public: private: TypeInfo m_type; QString m_defaultValueExpression; - bool m_defaultValue; + bool m_defaultValue = false; + bool m_scopeResolution = false; }; class _MemberModelItem: public _CodeModelItem { public: + Q_DISABLE_COPY_MOVE(_MemberModelItem) DECLARE_MODEL_NODE(Member) - explicit _MemberModelItem(CodeModel *model, int kind = __node_kind) - : _CodeModelItem(model, kind), m_accessPolicy(Access::Public), m_flags(0) {} - explicit _MemberModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _CodeModelItem(model, name, kind), m_accessPolicy(Access::Public), m_flags(0) {} + explicit _MemberModelItem(CodeModel *model, int kind = __node_kind); + explicit _MemberModelItem(CodeModel *model, const QString &name, + int kind = __node_kind); ~_MemberModelItem(); bool isConstant() const; @@ -443,7 +448,7 @@ public: private: TemplateParameterList m_templateParameters; TypeInfo m_type; - Access m_accessPolicy; + Access m_accessPolicy = Access::Public; union { struct { uint m_isConstant: 1; @@ -463,12 +468,12 @@ private: class _FunctionModelItem: public _MemberModelItem { public: + Q_DISABLE_COPY_MOVE(_FunctionModelItem) DECLARE_MODEL_NODE(Function) - explicit _FunctionModelItem(CodeModel *model, int kind = __node_kind) - : _MemberModelItem(model, kind), m_functionType(CodeModel::Normal), m_flags(0) {} - explicit _FunctionModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _MemberModelItem(model, name, kind), m_functionType(CodeModel::Normal), m_flags(0) {} + explicit _FunctionModelItem(CodeModel *model, int kind = __node_kind); + explicit _FunctionModelItem(CodeModel *model, const QString &name, + int kind = __node_kind); ~_FunctionModelItem(); ArgumentList arguments() const; @@ -480,42 +485,34 @@ public: static std::optional<CodeModel::FunctionType> functionTypeFromName(QStringView name); + FunctionAttributes attributes() const { return m_attributes; } + void setAttributes(FunctionAttributes a) { m_attributes = a; } + void setAttribute(FunctionAttribute a, bool on = true) { m_attributes.setFlag(a, on); } + bool isDeleted() const; void setDeleted(bool d); - bool isDeprecated() const; - void setDeprecated(bool d); - - bool isVirtual() const; - void setVirtual(bool isVirtual); - - bool isOverride() const; - void setOverride(bool o); - - bool isFinal() const; - void setFinal(bool f); - bool isInline() const; void setInline(bool isInline); - bool isExplicit() const; - void setExplicit(bool isExplicit); - - bool isInvokable() const; // Qt - void setInvokable(bool isInvokable); // Qt - - bool isAbstract() const; - void setAbstract(bool isAbstract); + bool isHiddenFriend() const; + void setHiddenFriend(bool f); bool isVariadics() const; void setVariadics(bool isVariadics); + bool scopeResolution() const; // Return type has scope resolution "::ReturnType" + void setScopeResolution(bool v); + bool isDefaultConstructor() const; + bool isSpaceshipOperator() const; bool isSimilar(const FunctionModelItem &other) const; bool isNoExcept() const; + bool isOperator() const; + ExceptionSpecification exceptionSpecification() const; void setExceptionSpecification(ExceptionSpecification e); @@ -532,19 +529,16 @@ private: CodeModel::FunctionType _determineTypeHelper() const; ArgumentList m_arguments; - CodeModel::FunctionType m_functionType; + FunctionAttributes m_attributes; + CodeModel::FunctionType m_functionType = CodeModel::Normal; union { struct { uint m_isDeleted: 1; - uint m_isVirtual: 1; - uint m_isOverride: 1; - uint m_isFinal: 1; - uint m_isDeprecated: 1; uint m_isInline: 1; - uint m_isAbstract: 1; - uint m_isExplicit: 1; uint m_isVariadics: 1; + uint m_isHiddenFriend: 1; uint m_isInvokable : 1; // Qt + uint m_scopeResolution: 1; }; uint m_flags; }; @@ -556,10 +550,7 @@ class _VariableModelItem: public _MemberModelItem public: DECLARE_MODEL_NODE(Variable) - explicit _VariableModelItem(CodeModel *model, int kind = __node_kind) - : _MemberModelItem(model, kind) {} - explicit _VariableModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _MemberModelItem(model, name, kind) {} + using _MemberModelItem::_MemberModelItem; }; class _TypeDefModelItem: public _CodeModelItem @@ -567,10 +558,9 @@ class _TypeDefModelItem: public _CodeModelItem public: DECLARE_MODEL_NODE(TypeDef) - explicit _TypeDefModelItem(CodeModel *model, int kind = __node_kind) - : _CodeModelItem(model, kind) {} - explicit _TypeDefModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _CodeModelItem(model, name, kind) {} + explicit _TypeDefModelItem(CodeModel *model, int kind = __node_kind); + explicit _TypeDefModelItem(CodeModel *model, const QString &name, + int kind = __node_kind); TypeInfo type() const; void setType(const TypeInfo &type); @@ -610,12 +600,11 @@ private: class _EnumModelItem: public _CodeModelItem { public: + Q_DISABLE_COPY_MOVE(_EnumModelItem) DECLARE_MODEL_NODE(Enum) - explicit _EnumModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _CodeModelItem(model, name, kind) {} - explicit _EnumModelItem(CodeModel *model, int kind = __node_kind) - : _CodeModelItem(model, kind) {} + explicit _EnumModelItem(CodeModel *model, const QString &name, int kind = __node_kind); + explicit _EnumModelItem(CodeModel *model, int kind = __node_kind); ~_EnumModelItem(); Access accessPolicy() const; @@ -628,29 +617,39 @@ 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 + bool isDeprecated() const; + void setDeprecated(bool d); + bool isSigned() const; void setSigned(bool s); + QString underlyingType() const; + void setUnderlyingType(const QString &underlyingType); + private: + QString m_underlyingType; Access m_accessPolicy = Access::Public; EnumeratorList m_enumerators; EnumKind m_enumKind = CEnum; + bool m_deprecated = false; bool m_signed = true; }; class _EnumeratorModelItem: public _CodeModelItem { public: + Q_DISABLE_COPY_MOVE(_EnumeratorModelItem) DECLARE_MODEL_NODE(Enumerator) - explicit _EnumeratorModelItem(CodeModel *model, int kind = __node_kind) - : _CodeModelItem(model, kind) {} - explicit _EnumeratorModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _CodeModelItem(model, name, kind) {} + explicit _EnumeratorModelItem(CodeModel *model, int kind = __node_kind); + explicit _EnumeratorModelItem(CodeModel *model, const QString &name, + int kind = __node_kind); ~_EnumeratorModelItem(); QString stringValue() const; @@ -659,6 +658,9 @@ public: EnumValue value() const { return m_value; } void setValue(EnumValue v) { m_value = v; } + bool isDeprecated() const; + void setDeprecated(bool d); + #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; #endif @@ -666,17 +668,18 @@ public: private: QString m_stringValue; EnumValue m_value; + bool m_deprecated = false; }; class _TemplateParameterModelItem: public _CodeModelItem { public: + Q_DISABLE_COPY_MOVE(_TemplateParameterModelItem) DECLARE_MODEL_NODE(TemplateParameter) - explicit _TemplateParameterModelItem(CodeModel *model, int kind = __node_kind) - : _CodeModelItem(model, kind), m_defaultValue(false) {} - explicit _TemplateParameterModelItem(CodeModel *model, const QString &name, int kind = __node_kind) - : _CodeModelItem(model, name, kind), m_defaultValue(false) {} + explicit _TemplateParameterModelItem(CodeModel *model, int kind = __node_kind); + explicit _TemplateParameterModelItem(CodeModel *model, const QString &name, + int kind = __node_kind); ~_TemplateParameterModelItem(); TypeInfo type() const; @@ -691,9 +694,7 @@ public: private: TypeInfo m_type; - bool m_defaultValue; + bool m_defaultValue = false; }; #endif // CODEMODEL_H - -// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h index 4f5121a08..e5c429bd0 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h +++ b/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h @@ -1,34 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CODEMODEL_ENUMS_H #define CODEMODEL_ENUMS_H +#include <QtCore/qflags.h> + enum ReferenceType { NoReference, LValueReference, @@ -68,4 +45,17 @@ enum class Access Public }; +enum class FunctionAttribute { + Abstract = 0x00000001, + Static = 0x00000002, + Virtual = 0x00000004, + Override = 0x00000008, + Final = 0x00000010, + Deprecated = 0x00000020, // Code annotation + Explicit = 0x00000040, // Constructor +}; + +Q_DECLARE_FLAGS(FunctionAttributes, FunctionAttribute) +Q_DECLARE_OPERATORS_FOR_FLAGS(FunctionAttributes) + #endif // CODEMODEL_ENUMS_H diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel_fwd.h b/sources/shiboken6/ApiExtractor/parser/codemodel_fwd.h index b138f2a2f..f0a25c9db 100644 --- a/sources/shiboken6/ApiExtractor/parser/codemodel_fwd.h +++ b/sources/shiboken6/ApiExtractor/parser/codemodel_fwd.h @@ -1,38 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CODEMODEL_FWD_H #define CODEMODEL_FWD_H #include <QtCore/QList> -#include <QtCore/QSharedPointer> + +#include <memory> // forward declarations class CodeModel; @@ -52,20 +28,20 @@ class _VariableModelItem; class _MemberModelItem; class TypeInfo; -using ArgumentModelItem = QSharedPointer<_ArgumentModelItem>; -using ClassModelItem = QSharedPointer<_ClassModelItem>; -using CodeModelItem = QSharedPointer<_CodeModelItem>; -using EnumModelItem = QSharedPointer<_EnumModelItem>; -using EnumeratorModelItem = QSharedPointer<_EnumeratorModelItem>; -using FileModelItem = QSharedPointer<_FileModelItem>; -using FunctionModelItem = QSharedPointer<_FunctionModelItem>; -using NamespaceModelItem = QSharedPointer<_NamespaceModelItem>; -using ScopeModelItem = QSharedPointer<_ScopeModelItem>; -using TemplateParameterModelItem = QSharedPointer<_TemplateParameterModelItem>; -using TypeDefModelItem = QSharedPointer<_TypeDefModelItem>; -using TemplateTypeAliasModelItem = QSharedPointer<_TemplateTypeAliasModelItem>; -using VariableModelItem = QSharedPointer<_VariableModelItem>; -using MemberModelItem = QSharedPointer<_MemberModelItem>; +using ArgumentModelItem = std::shared_ptr<_ArgumentModelItem>; +using ClassModelItem = std::shared_ptr<_ClassModelItem>; +using CodeModelItem = std::shared_ptr<_CodeModelItem>; +using EnumModelItem = std::shared_ptr<_EnumModelItem>; +using EnumeratorModelItem = std::shared_ptr<_EnumeratorModelItem>; +using FileModelItem = std::shared_ptr<_FileModelItem>; +using FunctionModelItem = std::shared_ptr<_FunctionModelItem>; +using NamespaceModelItem = std::shared_ptr<_NamespaceModelItem>; +using ScopeModelItem = std::shared_ptr<_ScopeModelItem>; +using TemplateParameterModelItem = std::shared_ptr<_TemplateParameterModelItem>; +using TypeDefModelItem = std::shared_ptr<_TypeDefModelItem>; +using TemplateTypeAliasModelItem = std::shared_ptr<_TemplateTypeAliasModelItem>; +using VariableModelItem = std::shared_ptr<_VariableModelItem>; +using MemberModelItem = std::shared_ptr<_MemberModelItem>; using ArgumentList = QList<ArgumentModelItem>; using ClassList = QList<ClassModelItem>; diff --git a/sources/shiboken6/ApiExtractor/parser/enumvalue.cpp b/sources/shiboken6/ApiExtractor/parser/enumvalue.cpp index 2ee7398ea..3749e16a8 100644 --- a/sources/shiboken6/ApiExtractor/parser/enumvalue.cpp +++ b/sources/shiboken6/ApiExtractor/parser/enumvalue.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "enumvalue.h" @@ -32,12 +7,34 @@ #include <QtCore/QString> #include <QtCore/QTextStream> +using namespace Qt::StringLiterals; + QString EnumValue::toString() const { return m_type == EnumValue::Signed ? QString::number(m_value) : QString::number(m_unsignedValue); } +QString EnumValue::toHex(int fieldWidth) const +{ + QString result; + QTextStream str(&result); + // Note: Qt goofes up formatting of negative padded hex numbers, it ends up + // with "0x00-1". Write '-' before. + if (isNegative()) + str << '-'; + str << "0x" << Qt::hex; + if (fieldWidth) { + str.setFieldWidth(fieldWidth); + str.setPadChar(u'0'); + } + if (m_type == EnumValue::Signed) + str << qAbs(m_value); + else + str << m_unsignedValue; + return result; +} + void EnumValue::setValue(qint64 v) { m_value = v; @@ -50,11 +47,37 @@ void EnumValue::setUnsignedValue(quint64 v) m_type = Unsigned; } -bool EnumValue::equals(const EnumValue &rhs) const +EnumValue EnumValue::toUnsigned() const { - if (m_type != rhs.m_type) + if (m_type == Unsigned) + return *this; + EnumValue result; + result.setUnsignedValue(m_value < 0 ? quint64(-m_value) : quint64(m_value)); + return result; +} + +bool comparesEqual(const EnumValue &lhs, const EnumValue &rhs) noexcept +{ + if (lhs.m_type != rhs.m_type) return false; - return m_type == Signed ? m_value == rhs.m_value : m_unsignedValue == rhs.m_unsignedValue; + return lhs.m_type == EnumValue::Signed + ? lhs.m_value == rhs.m_value : lhs.m_unsignedValue == rhs.m_unsignedValue; +} + +void EnumValue::formatDebugHex(QDebug &d) const +{ + d << "0x" << Qt::hex; + formatDebug(d); + d << Qt::dec; +} + +void EnumValue::formatDebug(QDebug &d) const +{ + + if (m_type == EnumValue::Signed) + d << m_value; + else + d << m_unsignedValue << 'u'; } #ifndef QT_NO_DEBUG_STREAM @@ -64,10 +87,7 @@ QDebug operator<<(QDebug d,const EnumValue &v) d.nospace(); d.noquote(); d << "EnumValue("; - if (v.m_type == EnumValue::Signed) - d << v.m_value; - else - d << v.m_unsignedValue << 'u'; + v.formatDebug(d); d << ')'; return d; } diff --git a/sources/shiboken6/ApiExtractor/parser/enumvalue.h b/sources/shiboken6/ApiExtractor/parser/enumvalue.h index 3cd7d01a4..bbd5a712d 100644 --- a/sources/shiboken6/ApiExtractor/parser/enumvalue.h +++ b/sources/shiboken6/ApiExtractor/parser/enumvalue.h @@ -1,35 +1,12 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef ENUMVALUE_H #define ENUMVALUE_H -#include <QtCore/QtGlobal> +#include <QtCore/qtypes.h> +#include <QtCore/qtclasshelpermacros.h> +#include <QtCore/QtCompare> QT_FORWARD_DECLARE_CLASS(QDebug) QT_FORWARD_DECLARE_CLASS(QString) @@ -45,18 +22,29 @@ public: }; QString toString() const; + QString toHex(int fieldWidth = 0) const; Type type() { return m_type; } qint64 value() const { return m_value; } quint64 unsignedValue() const { return m_unsignedValue; } bool isNullValue() const { return m_type == Signed ? m_value == 0 : m_unsignedValue == 0u; } + bool isNegative() const { return m_type == Signed && m_value < 0; } void setValue(qint64 v); void setUnsignedValue(quint64 v); + EnumValue toUnsigned() const; + bool equals(const EnumValue &rhs) const; + void formatDebug(QDebug &d) const; + void formatDebugHex(QDebug &d) const; + private: + friend bool comparesEqual(const EnumValue &lhs, + const EnumValue &rhs) noexcept; + Q_DECLARE_EQUALITY_COMPARABLE(EnumValue) + #ifndef QT_NO_DEBUG_STREAM friend QDebug operator<<(QDebug, const EnumValue &); #endif @@ -70,9 +58,4 @@ private: Type m_type = Signed; }; -inline bool operator==(const EnumValue &e1, const EnumValue &e2) -{ return e1.equals(e2); } -inline bool operator!=(const EnumValue &e1, const EnumValue &e2) -{ return !e1.equals(e2); } - #endif // ENUMVALUE_H diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp index e3fdeac84..f8c5c31d8 100644 --- a/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp +++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.cpp @@ -1,37 +1,15 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "typeinfo.h" #include "codemodel.h" #include <clangparser/clangutils.h> +#include <debughelpers_p.h> + +#include "qtcompat.h" #include <QtCore/QDebug> #include <QtCore/QStack> @@ -39,6 +17,8 @@ #include <iostream> +using namespace Qt::StringLiterals; + class TypeInfoData : public QSharedData { @@ -67,10 +47,10 @@ public: }; }; - ReferenceType m_referenceType; + ReferenceType m_referenceType = NoReference; }; -TypeInfoData::TypeInfoData() : flags(0), m_referenceType(NoReference) +TypeInfoData::TypeInfoData() : flags(0) { } @@ -81,9 +61,8 @@ TypeInfo::TypeInfo() : d(new TypeInfoData) TypeInfo::~TypeInfo() = default; TypeInfo::TypeInfo(const TypeInfo &) = default; TypeInfo& TypeInfo::operator=(const TypeInfo &) = default; -TypeInfo::TypeInfo(TypeInfo &&) = default; -TypeInfo& TypeInfo::operator=(TypeInfo &&) = default; - +TypeInfo::TypeInfo(TypeInfo &&) noexcept = default; +TypeInfo &TypeInfo::operator=(TypeInfo &&) noexcept = default; static inline TypeInfo createType(const QString &name) { @@ -94,13 +73,13 @@ static inline TypeInfo createType(const QString &name) TypeInfo TypeInfo::voidType() { - static const TypeInfo result = createType(QLatin1String("void")); + static const TypeInfo result = createType(u"void"_s); return result; } TypeInfo TypeInfo::varArgsType() { - static const TypeInfo result = createType(QLatin1String("...")); + static const TypeInfo result = createType(u"..."_s); return result; } @@ -119,7 +98,7 @@ TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs) __result.setArrayElements(__result.arrayElements() + __rhs.arrayElements()); - const auto instantiations = __rhs.instantiations(); + const auto &instantiations = __rhs.instantiations(); for (const auto &i : instantiations) __result.addInstantiation(i); @@ -148,7 +127,7 @@ bool TypeInfoData::isVoid() const && m_arguments.isEmpty() && m_arrayElements.isEmpty() && m_instantiations.isEmpty() && m_qualifiedName.size() == 1 - && m_qualifiedName.constFirst() == QLatin1String("void"); + && m_qualifiedName.constFirst() == u"void"; } bool TypeInfo::isVoid() const @@ -287,6 +266,12 @@ void TypeInfo::clearInstantiations() d->m_instantiations.clear(); } +bool TypeInfo::isPlain() const +{ + return d->m_constant == 0 && d->m_volatile == 0 && d->m_referenceType == NoReference + && d->m_indirections.isEmpty() && d->m_arrayElements.isEmpty(); +} + TypeInfo TypeInfo::resolveType(TypeInfo const &__type, const ScopeModelItem &__scope) { CodeModel *__model = __scope->model(); @@ -307,34 +292,34 @@ TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, con otherType.setQualifiedName(__item->qualifiedName()); } - if (TypeDefModelItem __typedef = qSharedPointerDynamicCast<_TypeDefModelItem>(__item)) { + if (TypeDefModelItem __typedef = std::dynamic_pointer_cast<_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()) { + if (nextItem.get() ==__item.get()) { std::cerr << "** WARNING Bailing out recursion of " << __FUNCTION__ - << "() on " << qPrintable(__type.qualifiedName().join(QLatin1String("::"))) + << "() on " << qPrintable(__type.qualifiedName().join(u"::"_s)) << std::endl; return otherType; } return resolveType(nextItem, combined, __scope); } - if (TemplateTypeAliasModelItem templateTypeAlias = qSharedPointerDynamicCast<_TemplateTypeAliasModelItem>(__item)) { + if (TemplateTypeAliasModelItem templateTypeAlias = std::dynamic_pointer_cast<_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]; + const auto count = qMin(aliasInstantiations.size(), concreteInstantiations.size()); + for (qsizetype i = 0; i < count; ++i) + aliasInstantiations[i] = concreteInstantiations.at(i); combined.setInstantiations(aliasInstantiations); - const CodeModelItem nextItem = __scope->model()->findItem(combined.qualifiedName(), __scope); + const CodeModelItem nextItem = CodeModel::findItem(combined.qualifiedName(), __scope); if (!nextItem) return combined; return resolveType(nextItem, combined, __scope); @@ -362,6 +347,10 @@ public: while (level < m_parseStack.size()) m_parseStack.pop(); TypeInfo instantiation; + if (name.startsWith(u"const ")) { + instantiation.setConstant(true); + name = name.mid(6); + } instantiation.setQualifiedName(qualifiedName(name)); top()->addInstantiation(instantiation); } @@ -382,7 +371,8 @@ private: QStack<TypeInfo *> m_parseStack; }; -QPair<int, int> TypeInfo::parseTemplateArgumentList(const QString &l, int from) +std::pair<qsizetype, qsizetype> + TypeInfo::parseTemplateArgumentList(const QString &l, qsizetype from) { return clang::parseTemplateArgumentList(l, clang::TemplateArgumentHandler(TypeInfoTemplateArgumentHandler(this)), from); } @@ -391,23 +381,23 @@ QString TypeInfo::toString() const { QString tmp; if (isConstant()) - tmp += QLatin1String("const "); + tmp += u"const "_s; if (isVolatile()) - tmp += QLatin1String("volatile "); + tmp += u"volatile "_s; - tmp += d->m_qualifiedName.join(QLatin1String("::")); + tmp += d->m_qualifiedName.join(u"::"_s); - if (const int instantiationCount = d->m_instantiations.size()) { - tmp += QLatin1Char('<'); - for (int i = 0; i < instantiationCount; ++i) { + if (const auto instantiationCount = d->m_instantiations.size()) { + tmp += u'<'; + for (qsizetype i = 0; i < instantiationCount; ++i) { if (i) - tmp += QLatin1String(", "); + tmp += u", "_s; tmp += d->m_instantiations.at(i).toString(); } - if (tmp.endsWith(QLatin1Char('>'))) - tmp += QLatin1Char(' '); - tmp += QLatin1Char('>'); + if (tmp.endsWith(u'>')) + tmp += u' '; + tmp += u'>'; } for (Indirection i : d->m_indirections) @@ -417,40 +407,37 @@ QString TypeInfo::toString() const case NoReference: break; case LValueReference: - tmp += QLatin1Char('&'); + tmp += u'&'; break; case RValueReference: - tmp += QLatin1String("&&"); + tmp += u"&&"_s; break; } if (isFunctionPointer()) { - tmp += QLatin1String(" (*)("); - for (int i = 0; i < d->m_arguments.count(); ++i) { + tmp += u" (*)("_s; + for (qsizetype i = 0; i < d->m_arguments.size(); ++i) { if (i != 0) - tmp += QLatin1String(", "); + tmp += u", "_s; tmp += d->m_arguments.at(i).toString(); } - tmp += QLatin1Char(')'); + tmp += u')'; } - for (const QString &elt : d->m_arrayElements) { - tmp += QLatin1Char('['); - tmp += elt; - tmp += QLatin1Char(']'); - } + for (const QString &elt : d->m_arrayElements) + tmp += u'[' + elt + u']'; return tmp; } bool TypeInfoData::equals(const TypeInfoData &other) const { - if (m_arrayElements.count() != other.m_arrayElements.count()) + if (m_arrayElements.size() != other.m_arrayElements.size()) return false; #if defined (RXX_CHECK_ARRAY_ELEMENTS) // ### it'll break - for (int i = 0; i < arrayElements().count(); ++i) { + for (qsizetype i = 0; i < arrayElements().size(); ++i) { QString elt1 = arrayElements().at(i).trimmed(); QString elt2 = other.arrayElements().at(i).trimmed(); @@ -465,34 +452,31 @@ bool TypeInfoData::equals(const TypeInfoData &other) const && m_instantiations == other.m_instantiations; } -bool TypeInfo::equals(const TypeInfo &other) const + +bool comparesEqual(const TypeInfo &lhs, const TypeInfo &rhs) noexcept { - return d.data() == other.d.data() || d->equals(*other.d); + return lhs.d.data() == rhs.d.data() || lhs.d->equals(*rhs.d); } QString TypeInfo::indirectionKeyword(Indirection i) { - return i == Indirection::Pointer - ? QStringLiteral("*") : QStringLiteral("*const"); + return i == Indirection::Pointer ? "*"_L1 : "*const"_L1; } -static inline QString constQualifier() { return QStringLiteral("const"); } -static inline QString volatileQualifier() { return QStringLiteral("volatile"); } - bool TypeInfo::stripLeadingConst(QString *s) { - return stripLeadingQualifier(constQualifier(), s); + return stripLeadingQualifier("const"_L1, s); } bool TypeInfo::stripLeadingVolatile(QString *s) { - return stripLeadingQualifier(volatileQualifier(), s); + return stripLeadingQualifier("volatile"_L1, s); } -bool TypeInfo::stripLeadingQualifier(const QString &qualifier, QString *s) +bool TypeInfo::stripLeadingQualifier(QLatin1StringView qualifier, QString *s) { // "const int x" - const int qualifierSize = qualifier.size(); + const auto qualifierSize = qualifier.size(); if (s->size() < qualifierSize + 1 || !s->startsWith(qualifier) || !s->at(qualifierSize).isSpace()) { return false; @@ -508,10 +492,8 @@ void TypeInfo::stripQualifiers(QString *s) { stripLeadingConst(s); stripLeadingVolatile(s); - while (s->endsWith(QLatin1Char('&')) || s->endsWith(QLatin1Char('*')) - || s->endsWith(QLatin1Char(' '))) { + while (s->endsWith(u'&') || s->endsWith(u'*') || s->endsWith(u' ')) s->chop(1); - } } // Helper functionality to simplify a raw standard type as returned by @@ -522,7 +504,7 @@ void TypeInfo::stripQualifiers(QString *s) bool TypeInfoData::isStdType() const { return m_qualifiedName.size() > 1 - && m_qualifiedName.constFirst() == QLatin1String("std"); + && m_qualifiedName.constFirst() == u"std"; } bool TypeInfo::isStdType() const @@ -532,15 +514,15 @@ bool TypeInfo::isStdType() const static inline bool discardStdType(const QString &name) { - return name == QLatin1String("allocator") || name == QLatin1String("less"); + return name == u"allocator" || name == u"less"; } void TypeInfoData::simplifyStdType() { Q_ASSERT(isStdType()); - if (m_qualifiedName.at(1).startsWith(QLatin1String("__"))) + if (m_qualifiedName.at(1).startsWith(u"__")) m_qualifiedName.removeAt(1); - for (int t = m_instantiations.size() - 1; t >= 0; --t) { + for (auto t = m_instantiations.size() - 1; t >= 0; --t) { if (m_instantiations.at(t).isStdType()) { if (discardStdType(m_instantiations.at(t).qualifiedName().constLast())) m_instantiations.removeAt(t); @@ -560,7 +542,7 @@ void TypeInfo::formatTypeSystemSignature(QTextStream &str) const { if (d->m_constant) str << "const "; - str << d->m_qualifiedName.join(QLatin1String("::")); + str << d->m_qualifiedName.join(u"::"_s); switch (d->m_referenceType) { case NoReference: break; @@ -584,16 +566,6 @@ void TypeInfo::formatTypeSystemSignature(QTextStream &str) 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; - } -} - void TypeInfo::formatDebug(QDebug &debug) const { debug << '"'; diff --git a/sources/shiboken6/ApiExtractor/parser/typeinfo.h b/sources/shiboken6/ApiExtractor/parser/typeinfo.h index 38e585726..e4f363b67 100644 --- a/sources/shiboken6/ApiExtractor/parser/typeinfo.h +++ b/sources/shiboken6/ApiExtractor/parser/typeinfo.h @@ -1,31 +1,6 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TYPEINFO_H #define TYPEINFO_H @@ -35,8 +10,11 @@ #include <QtCore/QString> #include <QtCore/QSharedDataPointer> +#include <QtCore/QtCompare> #include <QtCore/QStringList> +#include <utility> + QT_FORWARD_DECLARE_CLASS(QDebug) QT_FORWARD_DECLARE_CLASS(QTextStream) @@ -53,8 +31,8 @@ public: ~TypeInfo(); TypeInfo(const TypeInfo &); TypeInfo& operator=(const TypeInfo &); - TypeInfo(TypeInfo &&); - TypeInfo& operator=(TypeInfo &&); + TypeInfo(TypeInfo &&) noexcept; + TypeInfo &operator=(TypeInfo &&) noexcept; static TypeInfo voidType(); static TypeInfo varArgsType(); @@ -102,11 +80,12 @@ public: void addInstantiation(const TypeInfo &i); void clearInstantiations(); - bool isStdType() const; + bool isPlain() const; // neither const,volatile, no indirections/references, array - QPair<int, int> parseTemplateArgumentList(const QString &l, int from = 0); + bool isStdType() const; - bool equals(const TypeInfo &other) const; + std::pair<qsizetype, qsizetype> + parseTemplateArgumentList(const QString &l, qsizetype from = 0); // ### arrays and templates?? @@ -125,12 +104,16 @@ public: static bool stripLeadingConst(QString *s); static bool stripLeadingVolatile(QString *s); - static bool stripLeadingQualifier(const QString &qualifier, QString *s); + static bool stripLeadingQualifier(QLatin1StringView qualifier, QString *s); static void stripQualifiers(QString *s); void simplifyStdType(); private: + friend bool comparesEqual(const TypeInfo &lhs, + const TypeInfo &rhs) noexcept; + Q_DECLARE_EQUALITY_COMPARABLE(TypeInfo) + QSharedDataPointer<TypeInfoData> d; friend class TypeInfoTemplateArgumentHandler; @@ -138,12 +121,6 @@ private: static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, const ScopeModelItem &__scope); }; -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 diff --git a/sources/shiboken6/ApiExtractor/predefined_templates.cpp b/sources/shiboken6/ApiExtractor/predefined_templates.cpp new file mode 100644 index 000000000..992f735ac --- /dev/null +++ b/sources/shiboken6/ApiExtractor/predefined_templates.cpp @@ -0,0 +1,276 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "predefined_templates.h" + +#include "qtcompat.h" + +using namespace Qt::StringLiterals; + +static QString pySequenceToCppContainer(const QString &insertFunc, + bool reserve) +{ + QString result = u"(%out).clear();\n"_s; + if (reserve) { + result += uR"(if (PyList_Check(%in)) { + const Py_ssize_t size = PySequence_Size(%in); + if (size > 10) + (%out).reserve(size); +} + +)"_s; + } + + result += uR"(Shiboken::AutoDecRef it(PyObject_GetIter(%in)); +while (true) { + Shiboken::AutoDecRef pyItem(PyIter_Next(it.object())); + if (pyItem.isNull()) { + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + break; + } + %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem); + (%out).)"_s; + + result += insertFunc; + result += uR"((cppItem); +} +)"_s; + return result; +} + +// Convert a sequence to a limited/fixed array +static QString pySequenceToCppArray() +{ + return uR"(Shiboken::AutoDecRef it(PyObject_GetIter(%in)); +for (auto oit = std::begin(%out), oend = std::end(%out); oit != oend; ++oit) { + Shiboken::AutoDecRef pyItem(PyIter_Next(it.object())); + if (pyItem.isNull()) { + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + break; + } + %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem); + *oit = cppItem; +} +)"_s; +} + +static constexpr auto stlMapKeyAccessor = "->first"_L1; +static constexpr auto stlMapValueAccessor = "->second"_L1; +static constexpr auto qtMapKeyAccessor = ".key()"_L1; +static constexpr auto qtMapValueAccessor = ".value()"_L1; + +static QString cppMapToPyDict(bool isQMap) +{ + return uR"(PyObject *%out = PyDict_New(); +for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ++it) { + const auto &key = it)"_s + + (isQMap ? qtMapKeyAccessor : stlMapKeyAccessor) + + uR"(; + const auto &value = it)"_s + + (isQMap ? qtMapValueAccessor : stlMapValueAccessor) + + uR"(; + PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key); + PyObject *pyValue = %CONVERTTOPYTHON[%INTYPE_1](value); + PyDict_SetItem(%out, pyKey, pyValue); + Py_DECREF(pyKey); + Py_DECREF(pyValue); +} +return %out; +)"_s; +} + +static QString pyDictToCppMap(bool isQMap) +{ + return uR"(PyObject *key; +PyObject *value; +%out.clear(); +Py_ssize_t pos = 0; +while (PyDict_Next(%in, &pos, &key, &value)) { + %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key); + %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value); + %out.insert()"_s + // STL needs a pair + + (isQMap ? u"cppKey, cppValue"_s : u"{cppKey, cppValue}"_s) + uR"(); +} +)"_s; +} + +// Convert a STL or Qt multi map to Dict of Lists using upperBound() +static QString cppMultiMapToPyDict(bool isQMultiMap) +{ + return uR"(PyObject *%out = PyDict_New(); + for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ) { + const auto &key = it)"_s + + (isQMultiMap ? qtMapKeyAccessor : stlMapKeyAccessor) + + uR"(; + PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key); + auto upper = %in.)"_s + + (isQMultiMap ? u"upperBound"_s : u"upper_bound"_s) + + uR"((key); + const auto count = Py_ssize_t(std::distance(it, upper)); + PyObject *pyValues = PyList_New(count); + Py_ssize_t idx = 0; + for (; it != upper; ++it, ++idx) { + const auto &cppItem = it.value(); + PyList_SET_ITEM(pyValues, idx, %CONVERTTOPYTHON[%INTYPE_1](cppItem)); + } + PyDict_SetItem(%out, pyKey, pyValues); + Py_DECREF(pyKey); + } + return %out; +)"_s; +} + +// Convert a STL or Qt multi hash to Dict of Lists using equalRange() +static QString cppMultiHashToPyDict(bool isQMultiHash) +{ + return uR"(PyObject *%out = PyDict_New(); + for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ) { + const auto &key = it)"_s + + (isQMultiHash ? qtMapKeyAccessor : stlMapKeyAccessor) + + uR"(; + PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key); + auto range = %in.equal_range(key); + const auto count = Py_ssize_t(std::distance(range.first, range.second)); + PyObject *pyValues = PyList_New(count); + Py_ssize_t idx = 0; + for (; it != range.second; ++it, ++idx) { + const auto &cppItem = it.value(); + PyList_SET_ITEM(pyValues, idx, %CONVERTTOPYTHON[%INTYPE_1](cppItem)); + } + PyDict_SetItem(%out, pyKey, pyValues); + Py_DECREF(pyKey); + } + return %out; +)"_s; +} + +// Convert Dict of Lists to a STL or Qt multi hash/map +static QString pyDictToCppMultiHash(bool isQMultiHash) +{ + return uR"(PyObject *key; + PyObject *values; + %out.clear(); + Py_ssize_t pos = 0; + while (PyDict_Next(%in, &pos, &key, &values)) { + %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key); + const Py_ssize_t size = PySequence_Size(values); + for (Py_ssize_t i = 0; i < size; ++i) { + Shiboken::AutoDecRef value(PySequence_GetItem(values, i)); + %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value); + %out.insert()"_s + + (isQMultiHash ? u"cppKey, cppValue"_s : u"{cppKey, cppValue}"_s) + + uR"(); + } + } +)"_s; +} + +const PredefinedTemplates &predefinedTemplates() +{ + static const PredefinedTemplates result{ + {u"shiboken_conversion_pylong_to_cpp"_s, + u"%out = %OUTTYPE(PyLong_AsLong(%in));\n"_s}, + + // QPair/std::pair + {u"shiboken_conversion_pysequence_to_cpppair"_s, + uR"(%out.first = %CONVERTTOCPP[%OUTTYPE_0](PySequence_Fast_GET_ITEM(%in, 0)); +%out.second = %CONVERTTOCPP[%OUTTYPE_1](PySequence_Fast_GET_ITEM(%in, 1)); +)"_s}, + + {u"shiboken_conversion_cpppair_to_pytuple"_s, + uR"(PyObject *%out = PyTuple_New(2); +PyTuple_SET_ITEM(%out, 0, %CONVERTTOPYTHON[%INTYPE_0](%in.first)); +PyTuple_SET_ITEM(%out, 1, %CONVERTTOPYTHON[%INTYPE_1](%in.second)); +return %out; +)"_s}, + + // Sequential containers + {u"shiboken_conversion_cppsequence_to_pylist"_s, + uR"(PyObject *%out = PyList_New(Py_ssize_t(%in.size())); +Py_ssize_t idx = 0; +for (auto it = std::cbegin(%in), end = std::cend(%in); it != end; ++it, ++idx) { + const auto &cppItem = *it; + PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem)); +} +return %out;)"_s}, + + // PySet + {u"shiboken_conversion_cppsequence_to_pyset"_s, + uR"(PyObject *%out = PySet_New(nullptr); +for (const auto &cppItem : %in) { + PySet_Add(%out, %CONVERTTOPYTHON[%INTYPE_0](cppItem)); +} +return %out;)"_s}, + + {u"shiboken_conversion_pyiterable_to_cppsequentialcontainer"_s, + pySequenceToCppContainer(u"push_back"_s, false)}, + {u"shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve"_s, + pySequenceToCppContainer(u"push_back"_s, true)}, + {u"shiboken_conversion_pyiterable_to_cpparray"_s, + pySequenceToCppArray()}, + {u"shiboken_conversion_pyiterable_to_cppsetcontainer"_s, + pySequenceToCppContainer(u"insert"_s, false)}, + + // Maps + {u"shiboken_conversion_stdmap_to_pydict"_s, + cppMapToPyDict(false)}, + {u"shiboken_conversion_qmap_to_pydict"_s, + cppMapToPyDict(true)}, + {u"shiboken_conversion_pydict_to_stdmap"_s, + pyDictToCppMap(false)}, + {u"shiboken_conversion_pydict_to_qmap"_s, + pyDictToCppMap(true)}, + + // Multi maps + {u"shiboken_conversion_stdmultimap_to_pydict"_s, + cppMultiMapToPyDict(false)}, + {u"shiboken_conversion_qmultimap_to_pydict"_s, + cppMultiMapToPyDict(true)}, + + // Multi hashes + {u"shiboken_conversion_stdunorderedmultimap_to_pydict"_s, + cppMultiHashToPyDict(false)}, + {u"shiboken_conversion_qmultihash_to_pydict"_s, + cppMultiHashToPyDict(true)}, + + // STL multi hash/map + {u"shiboken_conversion_pydict_to_stdmultimap"_s, + pyDictToCppMultiHash(false)}, + {u"shiboken_conversion_pydict_to_qmultihash"_s, + pyDictToCppMultiHash(true)} + }; + + return result; +} + +QByteArray containerTypeSystemSnippet(const char *name, const char *type, + const char *include, + const char *nativeToTarget, + const char *targetToNativeType, + const char *targetToNative) +{ + QByteArray result = QByteArrayLiteral("<container-type name=\"") + + name + QByteArrayLiteral("\" type=\"") + type + R"("> + <include file-name=")" + include + R"(" location="global"/> + <conversion-rule> + <native-to-target> + <insert-template name=")" + nativeToTarget + R"("/> + </native-to-target> +)"; + if (targetToNativeType != nullptr) { + result += QByteArrayLiteral(R"( <target-to-native> + <add-conversion type=")") + targetToNativeType + + QByteArrayLiteral(R"("> + <insert-template name=")") + targetToNative + QByteArrayLiteral(R"("/> + </add-conversion> + </target-to-native> +)"); + } +result += QByteArrayLiteral(R"( </conversion-rule> +</container-type> +)"); + return result; +} diff --git a/sources/shiboken6/ApiExtractor/predefined_templates.h b/sources/shiboken6/ApiExtractor/predefined_templates.h new file mode 100644 index 000000000..0cc2c7f32 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/predefined_templates.h @@ -0,0 +1,27 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef PREDEFINED_TEMPLATES_H +#define PREDEFINED_TEMPLATES_H + +#include <QtCore/QList> +#include <QtCore/QString> + +struct PredefinedTemplate +{ + QString name; + QString content; +}; + +using PredefinedTemplates = QList<PredefinedTemplate>; + +const PredefinedTemplates &predefinedTemplates(); + +// Create an XML snippet for a container type. +QByteArray containerTypeSystemSnippet(const char *name, const char *type, + const char *include, + const char *nativeToTarget, + const char *targetToNativeType = nullptr, + const char *targetToNative = nullptr); + +#endif // PREDEFINED_TEMPLATES_H diff --git a/sources/shiboken6/ApiExtractor/primitivetypeentry.h b/sources/shiboken6/ApiExtractor/primitivetypeentry.h new file mode 100644 index 000000000..6faaf7a61 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/primitivetypeentry.h @@ -0,0 +1,72 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef PRIMITIVETYPEENTRY_H +#define PRIMITIVETYPEENTRY_H + +#include "typesystem.h" +#include "customconversion_typedefs.h" + +class PrimitiveTypeEntryPrivate; + +/// A PrimitiveTypeEntry is user-defined type with conversion rules, a C++ +/// primitive type for which a PrimitiveTypeConverter exists in libshiboken +/// or a typedef to a C++ primitive type as determined by AbstractMetaBuilder. +class PrimitiveTypeEntry : public TypeEntry +{ +public: + explicit PrimitiveTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + QString defaultConstructor() const; + void setDefaultConstructor(const QString& defaultConstructor); + bool hasDefaultConstructor() const; + + /** + * The PrimitiveTypeEntry pointed by this type entry if it + * represents a typedef). + * \return the type referenced by the typedef, or a null pointer + * if the current object is not an typedef + */ + PrimitiveTypeEntryPtr referencedTypeEntry() const; + + /** + * Defines type referenced by this entry. + * \param referencedTypeEntry type referenced by this entry + */ + void setReferencedTypeEntry(PrimitiveTypeEntryPtr referencedTypeEntry); + + /// Returns whether this entry references another entry. + bool referencesType() const; + + bool preferredTargetLangType() const; + void setPreferredTargetLangType(bool b); + + bool hasCustomConversion() const; + void setCustomConversion(const CustomConversionPtr &customConversion); + CustomConversionPtr customConversion() const; + + TypeEntry *clone() const override; + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +protected: + explicit PrimitiveTypeEntry(PrimitiveTypeEntryPrivate *d); +}; + +/// Finds the most basic primitive type that the typedef represents, +/// i.e. a type that is not an typedef'ed. +/// \return the most basic non-typedef'ed primitive type represented +/// by this typedef or self in case it is not a reference. +PrimitiveTypeEntryCPtr basicReferencedTypeEntry(const PrimitiveTypeEntryCPtr &e); +PrimitiveTypeEntryCPtr basicReferencedTypeEntry(const TypeEntryCPtr &e); + +/// Finds the basic primitive type that the typedef represents +/// and was explicitly specified in the type system. +/// \return the basic primitive type that was explicitly specified in +/// the type system. +PrimitiveTypeEntryCPtr basicReferencedNonBuiltinTypeEntry(const PrimitiveTypeEntryCPtr &e); + +#endif // PRIMITIVETYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/propertyspec.cpp b/sources/shiboken6/ApiExtractor/propertyspec.cpp index f66eeeaf6..32b756fad 100644 --- a/sources/shiboken6/ApiExtractor/propertyspec.cpp +++ b/sources/shiboken6/ApiExtractor/propertyspec.cpp @@ -1,38 +1,16 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "propertyspec.h" #include "abstractmetalang.h" #include "abstractmetabuilder_p.h" #include "abstractmetatype.h" -#include "codemodel.h" +#include "documentation.h" #include "messages.h" -#include "typesystem.h" +#include "complextypeentry.h" +#include "typeinfo.h" + +#include "qtcompat.h" #include <QtCore/QHash> @@ -42,6 +20,8 @@ #include <algorithm> +using namespace Qt::StringLiterals; + class QPropertySpecData : public QSharedData { public: @@ -52,6 +32,7 @@ public: m_write(ts.write), m_designable(ts.designable), m_reset(ts.reset), + m_notify(ts.notify), m_type(type), m_generateGetSetDef(ts.generateGetSetDef) { @@ -62,6 +43,8 @@ public: QString m_write; QString m_designable; QString m_reset; + QString m_notify; + Documentation m_documentation; AbstractMetaType m_type; int m_index = -1; // Indicates whether actual code is generated instead of relying on libpyside. @@ -76,8 +59,8 @@ QPropertySpec::QPropertySpec(const TypeSystemProperty &ts, QPropertySpec::QPropertySpec(const QPropertySpec &) = default; QPropertySpec &QPropertySpec::operator=(const QPropertySpec &) = default; -QPropertySpec::QPropertySpec(QPropertySpec &&) = default; -QPropertySpec &QPropertySpec::operator=(QPropertySpec &&) = default; +QPropertySpec::QPropertySpec(QPropertySpec &&) noexcept = default; +QPropertySpec &QPropertySpec::operator=(QPropertySpec &&) noexcept = default; QPropertySpec::~QPropertySpec() = default; const AbstractMetaType &QPropertySpec::type() const @@ -91,7 +74,7 @@ void QPropertySpec::setType(const AbstractMetaType &t) d->m_type = t; } -const TypeEntry *QPropertySpec::typeEntry() const +TypeEntryCPtr QPropertySpec::typeEntry() const { return d->m_type.typeEntry(); } @@ -107,6 +90,17 @@ void QPropertySpec::setName(const QString &name) d->m_name = name; } +Documentation QPropertySpec::documentation() const +{ + return d->m_documentation; +} + +void QPropertySpec::setDocumentation(const Documentation &doc) +{ + if (d->m_documentation != doc) + d->m_documentation = doc; +} + QString QPropertySpec::read() const { return d->m_read; @@ -156,6 +150,17 @@ void QPropertySpec::setReset(const QString &reset) d->m_reset = reset; } +QString QPropertySpec::notify() const +{ + return d->m_notify; +} + +void QPropertySpec::setNotify(const QString ¬ify) +{ + if (d->m_notify != notify) + d->m_notify = notify; +} + int QPropertySpec::index() const { return d->m_index; @@ -184,13 +189,15 @@ void QPropertySpec::setGenerateGetSetDef(bool generateGetSetDef) TypeSystemProperty QPropertySpec::typeSystemPropertyFromQ_Property(const QString &declarationIn, QString *errorMessage) { - enum class PropertyToken { None, Read, Write, Designable, Reset }; + enum class PropertyToken { None, Read, Write, Designable, Reset, Notify, Member }; static const QHash<QString, PropertyToken> tokenLookup = { - {QStringLiteral("READ"), PropertyToken::Read}, - {QStringLiteral("WRITE"), PropertyToken::Write}, - {QStringLiteral("DESIGNABLE"), PropertyToken::Designable}, - {QStringLiteral("RESET"), PropertyToken::Reset} + {"READ"_L1, PropertyToken::Read}, + {"WRITE"_L1, PropertyToken::Write}, + {"DESIGNABLE"_L1, PropertyToken::Designable}, + {"RESET"_L1, PropertyToken::Reset}, + {"NOTIFY"_L1, PropertyToken::Notify}, + {"MEMBER"_L1, PropertyToken::Member} }; errorMessage->clear(); @@ -200,7 +207,7 @@ TypeSystemProperty QPropertySpec::typeSystemPropertyFromQ_Property(const QString // Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged) const QString declaration = declarationIn.simplified(); - auto propertyTokens = declaration.split(QLatin1Char(' '), Qt::SkipEmptyParts); + auto propertyTokens = declaration.split(u' ', Qt::SkipEmptyParts); // To properly parse complicated type declarations like // "Q_PROPERTY(const QList<QString > *objectName READ objectName ..." @@ -209,17 +216,17 @@ TypeSystemProperty QPropertySpec::typeSystemPropertyFromQ_Property(const QString const auto it = std::find_if(propertyTokens.cbegin(), propertyTokens.cend(), [](const QString &t) { return tokenLookup.contains(t); }); if (it == propertyTokens.cend()) { - *errorMessage = QLatin1String("Invalid property specification, READ missing"); + *errorMessage = u"Invalid property specification, READ missing"_s; return result; } - const int firstToken = int(it - propertyTokens.cbegin()); + const auto firstToken = qsizetype(it - propertyTokens.cbegin()); if (firstToken < 2) { - *errorMessage = QLatin1String("Insufficient number of tokens in property specification"); + *errorMessage = u"Insufficient number of tokens in property specification"_s; return result; } - for (int pos = firstToken; pos + 1 < propertyTokens.size(); pos += 2) { + for (qsizetype pos = firstToken; pos + 1 < propertyTokens.size(); pos += 2) { switch (tokenLookup.value(propertyTokens.at(pos))) { case PropertyToken::Read: result.read = propertyTokens.at(pos + 1); @@ -233,17 +240,25 @@ TypeSystemProperty QPropertySpec::typeSystemPropertyFromQ_Property(const QString case PropertyToken::Designable: result.designable = propertyTokens.at(pos + 1); break; + case PropertyToken::Notify: + result.notify = propertyTokens.at(pos + 1); + break; + case PropertyToken::Member: + // Ignore MEMBER tokens introduced by QTBUG-16852 as Python + // properties are anyways generated for fields. + return {}; + case PropertyToken::None: break; } } - const int namePos = firstToken - 1; + const auto namePos = firstToken - 1; result.name = propertyTokens.at(namePos); result.type = propertyTokens.constFirst(); - for (int pos = 1; pos < namePos; ++pos) - result.type += QLatin1Char(' ') + propertyTokens.at(pos); + for (qsizetype pos = 1; pos < namePos; ++pos) + result.type += u' ' + propertyTokens.at(pos); // Fix errors like "Q_PROPERTY(QXYSeries *series .." to be of type "QXYSeries*" while (!result.name.isEmpty() && !result.name.at(0).isLetter()) { @@ -251,7 +266,7 @@ TypeSystemProperty QPropertySpec::typeSystemPropertyFromQ_Property(const QString result.name.remove(0, 1); } if (!result.isValid()) - *errorMessage = QLatin1String("Incomplete property specification"); + *errorMessage = u"Incomplete property specification"_s; return result; } @@ -259,7 +274,7 @@ TypeSystemProperty QPropertySpec::typeSystemPropertyFromQ_Property(const QString // the AbstractMetaType from the type string. std::optional<QPropertySpec> QPropertySpec::fromTypeSystemProperty(AbstractMetaBuilderPrivate *b, - AbstractMetaClass *metaClass, + const AbstractMetaClassPtr &metaClass, const TypeSystemProperty &ts, const QStringList &scopes, QString *errorMessage) @@ -275,7 +290,7 @@ std::optional<QPropertySpec> auto type = b->translateType(info, metaClass, {}, &typeError); if (!type.has_value()) { const QStringList qualifiedName = info.qualifiedName(); - for (int j = scopes.size(); j >= 0 && !type; --j) { + for (auto j = scopes.size(); j >= 0 && !type; --j) { info.setQualifiedName(scopes.mid(0, j) + qualifiedName); type = b->translateType(info, metaClass, {}, &typeError); } @@ -292,7 +307,7 @@ std::optional<QPropertySpec> // via TypeSystemProperty. std::optional<QPropertySpec> QPropertySpec::parseQ_Property(AbstractMetaBuilderPrivate *b, - AbstractMetaClass *metaClass, + const AbstractMetaClassPtr &metaClass, const QString &declarationIn, const QStringList &scopes, QString *errorMessage) @@ -315,6 +330,8 @@ void QPropertySpec::formatDebug(QDebug &debug) const debug << ", reset=" << d->m_reset; if (!d->m_designable.isEmpty()) debug << ", designable=" << d->m_designable; + if (!d->m_documentation.isEmpty()) + debug << ", doc=\"" << d->m_documentation << '"'; } QDebug operator<<(QDebug d, const QPropertySpec &p) diff --git a/sources/shiboken6/ApiExtractor/propertyspec.h b/sources/shiboken6/ApiExtractor/propertyspec.h index 4121f72d2..9e2e0f3d4 100644 --- a/sources/shiboken6/ApiExtractor/propertyspec.h +++ b/sources/shiboken6/ApiExtractor/propertyspec.h @@ -1,36 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef PROPERTYSPEC_H #define PROPERTYSPEC_H class AbstractMetaType; +#include "abstractmetalang_typedefs.h" +#include "typesystem_typedefs.h" + #include <QtCore/QStringList> #include <QtCore/QSharedDataPointer> @@ -39,6 +17,7 @@ class AbstractMetaType; class AbstractMetaClass; class AbstractMetaBuilderPrivate; class AbstractMetaType; +class Documentation; class TypeEntry; struct TypeSystemProperty; @@ -54,8 +33,8 @@ public: const AbstractMetaType &type); QPropertySpec(const QPropertySpec &); QPropertySpec &operator=(const QPropertySpec &); - QPropertySpec(QPropertySpec &&); - QPropertySpec &operator=(QPropertySpec &&); + QPropertySpec(QPropertySpec &&) noexcept; + QPropertySpec &operator=(QPropertySpec &&) noexcept; ~QPropertySpec(); static TypeSystemProperty typeSystemPropertyFromQ_Property(const QString &declarationIn, @@ -64,14 +43,14 @@ public: static std::optional<QPropertySpec> fromTypeSystemProperty(AbstractMetaBuilderPrivate *b, - AbstractMetaClass *metaClass, + const AbstractMetaClassPtr &metaClass, const TypeSystemProperty &ts, const QStringList &scopes, QString *errorMessage); static std::optional<QPropertySpec> parseQ_Property(AbstractMetaBuilderPrivate *b, - AbstractMetaClass *metaClass, + const AbstractMetaClassPtr &metaClass, const QString &declarationIn, const QStringList &scopes, QString *errorMessage); @@ -79,11 +58,14 @@ public: const AbstractMetaType &type() const; void setType(const AbstractMetaType &t); - const TypeEntry *typeEntry() const; + TypeEntryCPtr typeEntry() const; QString name() const; void setName(const QString &name); + Documentation documentation() const; + void setDocumentation(const Documentation &doc); + QString read() const; void setRead(const QString &read); @@ -97,6 +79,9 @@ public: QString reset() const; void setReset(const QString &reset); + QString notify() const; // Q_PROPERTY/C++ only + void setNotify(const QString ¬ify); + int index() const; void setIndex(int index); diff --git a/sources/shiboken6/ApiExtractor/pymethoddefentry.cpp b/sources/shiboken6/ApiExtractor/pymethoddefentry.cpp new file mode 100644 index 000000000..64d44378b --- /dev/null +++ b/sources/shiboken6/ApiExtractor/pymethoddefentry.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "pymethoddefentry.h" +#include "textstream.h" + +#include <QtCore/QDebug> + +TextStream &operator<<(TextStream &str, const castToPyCFunction &c) +{ + str << "reinterpret_cast<PyCFunction>(" << c.m_function << ')'; + return str; +} + +TextStream &operator<<(TextStream &s, const PyMethodDefEntry &e) +{ + s << "{\"" << e.name << "\", " << castToPyCFunction(e.function) <<", "; + if (e.methFlags.isEmpty()) { + s << '0'; + } else { + for (qsizetype i = 0, size = e.methFlags.size(); i < size; ++i) { + if (i) + s << '|'; + s << e.methFlags.at(i); + } + } + if (e.doc.isEmpty()) + s << ", nullptr"; + else + s << ", R\"(" << e.doc << ")\""; + s << '}'; + return s; +} + +TextStream &operator<<(TextStream &s, const PyMethodDefEntries &entries) +{ + for (const auto &e : entries) + s << e << ",\n"; + return s; +} + +QDebug operator<<(QDebug debug, const PyMethodDefEntry &e) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + debug << "PyMethodDefEntry(\"" << e.name << "\", " << e.function + << ", " << e.methFlags; + if (!e.doc.isEmpty()) + debug << ", \"" << e.doc << '"'; + debug << ')'; + return debug; +} diff --git a/sources/shiboken6/ApiExtractor/pymethoddefentry.h b/sources/shiboken6/ApiExtractor/pymethoddefentry.h new file mode 100644 index 000000000..a8694eb30 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/pymethoddefentry.h @@ -0,0 +1,38 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef PYMETHODDEFENTRY_H +#define PYMETHODDEFENTRY_H + +#include <QtCore/QByteArrayList> +#include <QtCore/QString> + +QT_FORWARD_DECLARE_CLASS(QDebug) + +class TextStream; + +struct castToPyCFunction +{ + explicit castToPyCFunction(QAnyStringView function) noexcept : + m_function(function) {} + + QAnyStringView m_function; +}; + +struct PyMethodDefEntry +{ + QString name; + QString function; + QByteArrayList methFlags; // "METH_O" etc. + QString doc; +}; + +using PyMethodDefEntries = QList<PyMethodDefEntry>; + +TextStream &operator<<(TextStream &str, const castToPyCFunction &e); +TextStream &operator<<(TextStream &s, const PyMethodDefEntry &e); +TextStream &operator<<(TextStream &s, const PyMethodDefEntries &e); + +QDebug operator<<(QDebug debug, const PyMethodDefEntry &e); + +#endif // PYMETHODDEFENTRY_H diff --git a/sources/shiboken6/ApiExtractor/pythontypeentry.h b/sources/shiboken6/ApiExtractor/pythontypeentry.h new file mode 100644 index 000000000..2e0fbda97 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/pythontypeentry.h @@ -0,0 +1,29 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef PYTHONTYPEENTRY_H +#define PYTHONTYPEENTRY_H + +#include "customtypenentry.h" +#include "typesystem_enums.h" + +class PythonTypeEntry : public CustomTypeEntry +{ +public: + explicit PythonTypeEntry(const QString &entryName, + const QString &checkFunction, + TypeSystem::CPythonType type); + + TypeEntry *clone() const override; + + TypeSystem::CPythonType cPythonType() const; + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +protected: + explicit PythonTypeEntry(TypeEntryPrivate *d); +}; + +#endif // PYTHONTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/qtcompat.h b/sources/shiboken6/ApiExtractor/qtcompat.h new file mode 100644 index 000000000..3837dcfd2 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/qtcompat.h @@ -0,0 +1,37 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef QTCOMPAT_H +#define QTCOMPAT_H + +#include <QtCore/qtconfigmacros.h> + +#if QT_VERSION < 0x060400 + +// QTBUG-98434, provide literals of Qt 6.4 for compatibility. + +# include <QtCore/QString> + +# define QLatin1StringView QLatin1String + +namespace Qt { +inline namespace Literals { +inline namespace StringLiterals { + +constexpr inline QLatin1String operator"" _L1(const char *str, size_t size) noexcept +{ + return QLatin1String(str, qsizetype(size)); +} + +inline QString operator"" _s(const char16_t *str, size_t size) noexcept +{ + return QString(QStringPrivate(nullptr, const_cast<char16_t *>(str), qsizetype(size))); +} + +} // StringLiterals +} // Literals +} // Qt + +#endif // < 6.4 + +#endif // QTCOMPAT_H diff --git a/sources/shiboken6/ApiExtractor/qtdocparser.cpp b/sources/shiboken6/ApiExtractor/qtdocparser.cpp index 9214dc6f4..5bd99bbd8 100644 --- a/sources/shiboken6/ApiExtractor/qtdocparser.cpp +++ b/sources/shiboken6/ApiExtractor/qtdocparser.cpp @@ -1,72 +1,69 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "qtdocparser.h" +#include "classdocumentation.h" +#include "abstractmetaargument.h" #include "abstractmetaenum.h" -#include "abstractmetafield.h" #include "abstractmetafunction.h" #include "abstractmetalang.h" +#include "abstractmetatype.h" #include "documentation.h" #include "modifications.h" #include "messages.h" #include "propertyspec.h" #include "reporthandler.h" -#include "typesystem.h" -#include "xmlutils.h" +#include "flagstypeentry.h" +#include "complextypeentry.h" +#include "functiontypeentry.h" +#include "enumtypeentry.h" + +#include "qtcompat.h" #include <QtCore/QDir> #include <QtCore/QFile> -#include <QtCore/QTextStream> -#include <QtCore/QXmlStreamAttributes> -#include <QtCore/QXmlStreamReader> -#include <QUrl> +#include <QtCore/QUrl> + +using namespace Qt::StringLiterals; + +enum { debugFunctionSearch = 0 }; -static inline QString briefStartElement() { return QStringLiteral("<brief>"); } -static inline QString briefEndElement() { return QStringLiteral("</brief>"); } +constexpr auto briefStartElement = "<brief>"_L1; +constexpr auto briefEndElement = "</brief>"_L1; +constexpr auto webxmlSuffix = ".webxml"_L1; Documentation QtDocParser::retrieveModuleDocumentation() { return retrieveModuleDocumentation(packageName()); } -static void formatFunctionArgTypeQuery(QTextStream &str, const AbstractMetaArgument &arg) +static void formatPreQualifications(QTextStream &str, const AbstractMetaType &type) { - const AbstractMetaType &metaType = arg.type(); - if (metaType.isConstant()) + if (type.isConstant()) str << "const " ; +} + +static void formatPostQualifications(QTextStream &str, const AbstractMetaType &type) +{ + if (type.referenceType() == LValueReference) + str << " &"; + else if (type.referenceType() == RValueReference) + str << " &&"; + else if (type.indirections()) + str << ' ' << QByteArray(type.indirections(), '*'); +} + +static void formatFunctionUnqualifiedArgTypeQuery(QTextStream &str, + const AbstractMetaType &metaType) +{ switch (metaType.typeUsagePattern()) { case AbstractMetaType::FlagsPattern: { // Modify qualified name "QFlags<Qt::AlignmentFlag>" with name "Alignment" // to "Qt::Alignment" as seen by qdoc. - const auto *flagsEntry = static_cast<const FlagsTypeEntry *>(metaType.typeEntry()); + const auto flagsEntry = std::static_pointer_cast<const FlagsTypeEntry>(metaType.typeEntry()); QString name = flagsEntry->qualifiedCppName(); - if (name.endsWith(QLatin1Char('>')) && name.startsWith(QLatin1String("QFlags<"))) { - const int lastColon = name.lastIndexOf(QLatin1Char(':')); + if (name.endsWith(u'>') && name.startsWith(u"QFlags<")) { + const int lastColon = name.lastIndexOf(u':'); if (lastColon != -1) { name.replace(lastColon + 1, name.size() - lastColon - 1, metaType.name()); name.remove(0, 7); @@ -80,10 +77,13 @@ static void formatFunctionArgTypeQuery(QTextStream &str, const AbstractMetaArgum case AbstractMetaType::ContainerPattern: { // QVector<int> str << metaType.typeEntry()->qualifiedCppName() << '<'; const auto instantiations = metaType.instantiations(); - for (int i = 0, size = instantiations.size(); i < size; ++i) { + for (qsizetype i = 0, size = instantiations.size(); i < size; ++i) { if (i) str << ", "; - str << instantiations.at(i).typeEntry()->qualifiedCppName(); + const auto &instantiation = instantiations.at(i); + formatPreQualifications(str, instantiation); + str << instantiation.typeEntry()->qualifiedCppName(); + formatPostQualifications(str, instantiation); } str << '>'; } @@ -92,170 +92,209 @@ static void formatFunctionArgTypeQuery(QTextStream &str, const AbstractMetaArgum str << metaType.typeEntry()->qualifiedCppName(); break; } - - if (metaType.referenceType() == LValueReference) - str << " &"; - else if (metaType.referenceType() == RValueReference) - str << " &&"; - else if (metaType.indirections()) - str << ' ' << QByteArray(metaType.indirections(), '*'); } -enum FunctionMatchFlags -{ - MatchArgumentCount = 0x1, - MatchArgumentType = 0x2, - DescriptionOnly = 0x4 -}; - -static QString functionXQuery(const QString &classQuery, - const AbstractMetaFunctionCPtr &func, - unsigned matchFlags = MatchArgumentCount | MatchArgumentType - | DescriptionOnly) +static QString formatFunctionArgTypeQuery(const AbstractMetaType &metaType) { QString result; - QTextStream str(&result); - const AbstractMetaArgumentList &arguments = func->arguments(); - str << classQuery << "/function[@name=\"" << func->originalName() - << "\" and @const=\"" << (func->isConstant() ? "true" : "false") << '"'; - if (matchFlags & MatchArgumentCount) - str << " and count(parameter)=" << arguments.size(); - str << ']'; - if (!arguments.isEmpty() && (matchFlags & MatchArgumentType)) { - for (int i = 0, size = arguments.size(); i < size; ++i) { - str << "/parameter[" << (i + 1) << "][@type=\""; - // Fixme: Use arguments.at(i)->type()->originalTypeDescription() - // instead to get unresolved typedefs? - formatFunctionArgTypeQuery(str, arguments.at(i)); - str << "\"]/.."; - } - } - if (matchFlags & DescriptionOnly) - str << "/description"; + QTextStream str(&result);formatPreQualifications(str, metaType); + formatFunctionUnqualifiedArgTypeQuery(str, metaType); + formatPostQualifications(str, metaType); return result; } -static QStringList signaturesFromWebXml(QString w) +QString QtDocParser::functionDocumentation(const QString &sourceFileName, + const ClassDocumentation &classDocumentation, + const AbstractMetaClassCPtr &metaClass, + const AbstractMetaFunctionCPtr &func, + QString *errorMessage) { - QStringList result; - if (w.isEmpty()) - return result; - w.prepend(QLatin1String("<root>")); // Fake root element - w.append(QLatin1String("</root>")); - QXmlStreamReader reader(w); - while (!reader.atEnd()) { - if (reader.readNext() == QXmlStreamReader::StartElement - && reader.name() == QLatin1String("function")) { - result.append(reader.attributes().value(QStringLiteral("signature")).toString()); - } - } - return result; -} + errorMessage->clear(); -static QString msgArgumentCountMatch(const AbstractMetaFunction *func, - const QStringList &matches) -{ - QString result; - QTextStream str(&result); - str << "\n Note: Querying for the argument count==" - << func->arguments().size() << " only yields " << matches.size() - << " matches"; - if (!matches.isEmpty()) - str << ": \"" << matches.join(QLatin1String("\", \"")) << '"'; - return result; + const QString docString = + queryFunctionDocumentation(sourceFileName, classDocumentation, metaClass, + func, errorMessage); + + const auto funcModifs = DocParser::getXpathDocModifications(func, metaClass); + return docString.isEmpty() || funcModifs.isEmpty() + ? docString : applyDocModifications(funcModifs, docString); } QString QtDocParser::queryFunctionDocumentation(const QString &sourceFileName, - const AbstractMetaClass* metaClass, - const QString &classQuery, + const ClassDocumentation &classDocumentation, + const AbstractMetaClassCPtr &metaClass, const AbstractMetaFunctionCPtr &func, - const DocModificationList &signedModifs, - const XQueryPtr &xquery, QString *errorMessage) { - DocModificationList funcModifs; - for (const DocModification &funcModif : signedModifs) { - if (funcModif.signature() == func->minimalSignature()) - funcModifs.append(funcModif); + // Search candidates by name and const-ness + FunctionDocumentationList candidates = + classDocumentation.findFunctionCandidates(func->name(), func->isConstant()); + if (candidates.isEmpty()) { + *errorMessage = msgCannotFindDocumentation(sourceFileName, func.get()) + + u" (no matches)"_s; + return {}; } - // Properties - if (func->isPropertyReader() || func->isPropertyWriter() || func->isPropertyResetter()) { - const auto prop = metaClass->propertySpecs().at(func->propertySpecIndex()); - const QString propertyQuery = classQuery + QLatin1String("/property[@name=\"") - + prop.name() + QLatin1String("\"]/description"); - const QString properyDocumentation = getDocumentation(xquery, propertyQuery, funcModifs); - if (properyDocumentation.isEmpty()) { - *errorMessage = - msgCannotFindDocumentation(sourceFileName, metaClass, func.data(), - propertyQuery); + // Try an exact query + FunctionDocumentationQuery fq; + fq.name = func->name(); + fq.constant = func->isConstant(); + for (const auto &arg : func->arguments()) + fq.parameters.append(formatFunctionArgTypeQuery(arg.type())); + + const auto funcFlags = func->flags(); + // Re-add arguments removed by the metabuilder to binary operator functions + if (funcFlags.testFlag(AbstractMetaFunction::Flag::OperatorLeadingClassArgumentRemoved) + || funcFlags.testFlag(AbstractMetaFunction::Flag::OperatorTrailingClassArgumentRemoved)) { + QString classType = metaClass->qualifiedCppName(); + if (!funcFlags.testFlag(AbstractMetaFunction::Flag::OperatorClassArgumentByValue)) { + classType.prepend(u"const "_s); + classType.append(u" &"_s); } - return properyDocumentation; + if (funcFlags.testFlag(AbstractMetaFunction::Flag::OperatorLeadingClassArgumentRemoved)) + fq.parameters.prepend(classType); + else + fq.parameters.append(classType); } - // Query with full match of argument types - const QString fullQuery = functionXQuery(classQuery, func); - const QString result = getDocumentation(xquery, fullQuery, funcModifs); - if (!result.isEmpty()) - return result; - *errorMessage = msgCannotFindDocumentation(sourceFileName, metaClass, func.data(), fullQuery); - if (func->arguments().isEmpty()) // No arguments, can't be helped - return result; - // Test whether some mismatch in argument types occurred by checking for - // the argument count only. Include the outer <function> element. - QString countOnlyQuery = functionXQuery(classQuery, func, MatchArgumentCount); - QStringList signatures = - signaturesFromWebXml(getDocumentation(xquery, countOnlyQuery, funcModifs)); - if (signatures.size() == 1) { - // One match was found. Repeat the query restricted to the <description> - // element and use the result with a warning. - countOnlyQuery = functionXQuery(classQuery, func, MatchArgumentCount | DescriptionOnly); - errorMessage->append(QLatin1String("\n Falling back to \"") + signatures.constFirst() - + QLatin1String("\" obtained by matching the argument count only.")); - return getDocumentation(xquery, countOnlyQuery, funcModifs); + const qsizetype index = ClassDocumentation::indexOfFunction(candidates, fq); + + if (debugFunctionSearch) { + qDebug() << __FUNCTION__ << metaClass->name() << fq << funcFlags << "returns" + << index << "\n " << candidates.value(index) << "\n " << candidates; } - *errorMessage += msgArgumentCountMatch(func.data(), signatures); - return result; + + if (index != -1) + return candidates.at(index).description; + + // Fallback: Try matching by argument count + const auto parameterCount = func->arguments().size(); + auto pend = std::remove_if(candidates.begin(), candidates.end(), + [parameterCount](const FunctionDocumentation &fd) { + return fd.parameters.size() != parameterCount; }); + candidates.erase(pend, candidates.end()); + if (candidates.size() == 1) { + const auto &match = candidates.constFirst(); + QTextStream(errorMessage) << msgFallbackForDocumentation(sourceFileName, func.get()) + << "\n Falling back to \"" << match.signature + << "\" obtained by matching the argument count only."; + return candidates.constFirst().description; + } + + QTextStream(errorMessage) << msgCannotFindDocumentation(sourceFileName, func.get()) + << " (" << candidates.size() << " candidates matching the argument count)"; + return {}; } // Extract the <brief> section from a WebXML (class) documentation and remove it // from the source. static QString extractBrief(QString *value) { - const auto briefStart = value->indexOf(briefStartElement()); + const auto briefStart = value->indexOf(briefStartElement); if (briefStart < 0) return {}; - const auto briefEnd = value->indexOf(briefEndElement(), - briefStart + briefStartElement().size()); + const auto briefEnd = value->indexOf(briefEndElement, + briefStart + briefStartElement.size()); if (briefEnd < briefStart) return {}; - const auto briefLength = briefEnd + briefEndElement().size() - briefStart; + const auto briefLength = briefEnd + briefEndElement.size() - briefStart; QString briefValue = value->mid(briefStart, briefLength); - briefValue.insert(briefValue.size() - briefEndElement().size(), - QLatin1String("<rst> More_...</rst>")); + briefValue.insert(briefValue.size() - briefEndElement.size(), + u"<rst> More_...</rst>"_s); value->remove(briefStart, briefLength); return briefValue; } -void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) +// Find the webxml file for global functions/enums +// by the doc-file typesystem attribute or via include file. +static QString findGlobalWebXmLFile(const QString &documentationDataDirectory, + const QString &docFile, + const Include &include) +{ + QString result; + if (!docFile.isEmpty()) { + result = documentationDataDirectory + u'/' + docFile; + if (!result.endsWith(webxmlSuffix)) + result += webxmlSuffix; + return QFileInfo::exists(result) ? result : QString{}; + } + if (include.name().isEmpty()) + return {}; + // qdoc "\headerfile <QtLogging>" directive produces "qtlogging.webxml" + result = documentationDataDirectory + u'/' + + QFileInfo(include.name()).baseName() + webxmlSuffix; + if (QFileInfo::exists(result)) + return result; + // qdoc "\headerfile <qdrawutil.h>" produces "qdrawutil-h.webxml" + result.insert(result.size() - webxmlSuffix.size(), "-h"_L1); + return QFileInfo::exists(result) ? result : QString{}; +} + +void QtDocParser::fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &f) +{ + auto te = f->typeEntry(); + if (te == nullptr) + return; + + const QString sourceFileName = + findGlobalWebXmLFile(documentationDataDirectory(), te->docFile(), te->include()); + if (sourceFileName.isEmpty()) + return; + + QString errorMessage; + auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage); + if (!classDocumentationO.has_value()) { + qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); + return; + } + const QString detailed = + functionDocumentation(sourceFileName, classDocumentationO.value(), + {}, f, &errorMessage); + if (!errorMessage.isEmpty()) + qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); + const Documentation documentation(detailed, {}); + f->setDocumentation(documentation); +} + +void QtDocParser::fillGlobalEnumDocumentation(AbstractMetaEnum &e) +{ + auto te = e.typeEntry(); + const QString sourceFileName = + findGlobalWebXmLFile(documentationDataDirectory(), te->docFile(), te->include()); + if (sourceFileName.isEmpty()) + return; + + QString errorMessage; + auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage); + if (!classDocumentationO.has_value()) { + qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); + return; + } + if (!extractEnumDocumentation(classDocumentationO.value(), e)) { + qCWarning(lcShibokenDoc, "%s", + qPrintable(msgCannotFindDocumentation(sourceFileName, {}, e, {}))); + } +} + +void QtDocParser::fillDocumentation(const AbstractMetaClassPtr &metaClass) { if (!metaClass) return; - const AbstractMetaClass* context = metaClass->enclosingClass(); - while(context) { - if (context->enclosingClass() == nullptr) + auto context = metaClass->enclosingClass(); + while (context) { + if (!context->enclosingClass()) break; context = context->enclosingClass(); } - QString sourceFileRoot = documentationDataDirectory() + QLatin1Char('/') + QString sourceFileRoot = documentationDataDirectory() + u'/' + metaClass->qualifiedCppName().toLower(); - sourceFileRoot.replace(QLatin1String("::"), QLatin1String("-")); + sourceFileRoot.replace(u"::"_s, u"-"_s); - QFileInfo sourceFile(sourceFileRoot + QStringLiteral(".webxml")); + QFileInfo sourceFile(sourceFileRoot + webxmlSuffix); if (!sourceFile.exists()) - sourceFile.setFile(sourceFileRoot + QStringLiteral(".xml")); + sourceFile.setFile(sourceFileRoot + ".xml"_L1); if (!sourceFile.exists()) { qCWarning(lcShibokenDoc).noquote().nospace() << "Can't find qdoc file for class " << metaClass->name() << ", tried: " @@ -265,33 +304,26 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) const QString sourceFileName = sourceFile.absoluteFilePath(); QString errorMessage; - XQueryPtr xquery = XQuery::create(sourceFileName, &errorMessage); - if (xquery.isNull()) { + + const auto classDocumentationO = parseWebXml(sourceFileName, &errorMessage); + if (!classDocumentationO.has_value()) { qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); return; } - QString className = metaClass->name(); - - // Class/Namespace documentation - const QString classQuery = QLatin1String("/WebXML/document/") - + (metaClass->isNamespace() ? QLatin1String("namespace") : QLatin1String("class")) - + QLatin1String("[@name=\"") + className + QLatin1String("\"]"); - QString query = classQuery + QLatin1String("/description"); - - DocModificationList signedModifs, classModifs; - const DocModificationList &mods = metaClass->typeEntry()->docModifications(); - for (const DocModification &docModif : mods) { - if (docModif.signature().isEmpty()) - classModifs.append(docModif); - else - signedModifs.append(docModif); + const auto &classDocumentation = classDocumentationO.value(); + for (const auto &p : classDocumentation.properties) { + Documentation doc(p.description, p.brief); + metaClass->setPropertyDocumentation(p.name, doc); } - QString docString = getDocumentation(xquery, query, classModifs); + QString docString = applyDocModifications(DocParser::getXpathDocModifications(metaClass), + classDocumentation.description); + if (docString.isEmpty()) { + QString className = metaClass->name(); qCWarning(lcShibokenDoc, "%s", - qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, query))); + qPrintable(msgCannotFindDocumentation(sourceFileName, "class", className, {}))); } const QString brief = extractBrief(&docString); @@ -305,12 +337,12 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) const auto &funcs = DocParser::documentableFunctions(metaClass); for (const auto &func : funcs) { const QString detailed = - queryFunctionDocumentation(sourceFileName, metaClass, classQuery, - func, signedModifs, xquery, &errorMessage); + functionDocumentation(sourceFileName, classDocumentation, + metaClass, func, &errorMessage); if (!errorMessage.isEmpty()) qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); const Documentation documentation(detailed, {}); - qSharedPointerConstCast<AbstractMetaFunction>(func)->setDocumentation(documentation); + std::const_pointer_cast<AbstractMetaFunction>(func)->setDocumentation(documentation); } #if 0 // Fields @@ -326,24 +358,41 @@ void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass) #endif // Enums for (AbstractMetaEnum &meta_enum : metaClass->enums()) { - query.clear(); - QTextStream(&query) << classQuery << "/enum[@name=\"" - << meta_enum.name() << "\"]/description"; - doc.setValue(getDocumentation(xquery, query, DocModificationList())); - if (doc.isEmpty()) { + if (!extractEnumDocumentation(classDocumentation, meta_enum)) { qCWarning(lcShibokenDoc, "%s", - qPrintable(msgCannotFindDocumentation(sourceFileName, metaClass, meta_enum, query))); + qPrintable(msgCannotFindDocumentation(sourceFileName, metaClass, meta_enum, {}))); } - meta_enum.setDocumentation(doc); } } +bool QtDocParser::extractEnumDocumentation(const ClassDocumentation &classDocumentation, + AbstractMetaEnum &meta_enum) +{ + Documentation enumDoc; + const auto index = classDocumentation.indexOfEnum(meta_enum.name()); + if (index == -1) + return false; + QString doc = classDocumentation.enums.at(index).description; + const auto firstPara = doc.indexOf(u"<para>"); + if (firstPara != -1) { + const QString baseClass = QtDocParser::enumBaseClass(meta_enum); + if (baseClass != "Enum"_L1) { + const QString note = "(inherits <teletype>enum."_L1 + baseClass + + "</teletype>) "_L1; + doc.insert(firstPara + 6, note); + } + } + enumDoc.setValue(doc); + meta_enum.setDocumentation(enumDoc); + return true; +} + static QString qmlReferenceLink(const QFileInfo &qmlModuleFi) { QString result; QTextStream(&result) << "<para>The module also provides <link" - << " type=\"page\"" - << " page=\"http://doc.qt.io/qt-5/" << qmlModuleFi.baseName() << ".html\"" + << R"( type="page" page="https://doc.qt.io/qt-)" << QT_VERSION_MAJOR + << '/' << qmlModuleFi.baseName() << R"(.html")" << ">QML types</link>.</para>"; return result; } @@ -353,13 +402,13 @@ Documentation QtDocParser::retrieveModuleDocumentation(const QString& name) // TODO: This method of acquiring the module name supposes that the target language uses // dots as module separators in package names. Improve this. QString moduleName = name; - moduleName.remove(0, name.lastIndexOf(QLatin1Char('.')) + 1); - const QString prefix = documentationDataDirectory() + QLatin1Char('/') + moduleName.remove(0, name.lastIndexOf(u'.') + 1); + if (moduleName == u"QtQuickControls2") + moduleName.chop(1); + const QString prefix = documentationDataDirectory() + u'/' + moduleName.toLower(); - QString sourceFile = prefix + QLatin1String(".xml"); - if (!QFile::exists(sourceFile)) - sourceFile = prefix + QLatin1String("-module.webxml"); + const QString sourceFile = prefix + u"-index.webxml"_s; if (!QFile::exists(sourceFile)) { qCWarning(lcShibokenDoc).noquote().nospace() << "Can't find qdoc file for module " << name << ", tried: " @@ -368,27 +417,24 @@ Documentation QtDocParser::retrieveModuleDocumentation(const QString& name) } QString errorMessage; - XQueryPtr xquery = XQuery::create(sourceFile, &errorMessage); - if (xquery.isNull()) { + QString docString = webXmlModuleDescription(sourceFile, &errorMessage); + if (!errorMessage.isEmpty()) { qCWarning(lcShibokenDoc, "%s", qPrintable(errorMessage)); return {}; } - // Module documentation - QString query = QLatin1String("/WebXML/document/module[@name=\"") - + moduleName + QLatin1String("\"]/description"); - const QString detailed = getDocumentation(xquery, query, DocModificationList()); - Documentation doc(detailed, {}); + Documentation doc(docString, {}); if (doc.isEmpty()) { - qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotFindDocumentation(sourceFile, "module", name, query))); + qCWarning(lcShibokenDoc, "%s", + qPrintable(msgCannotFindDocumentation(sourceFile, "module", name))); return doc; } // If a QML module info file exists, insert a link to the Qt docs. - const QFileInfo qmlModuleFi(prefix + QLatin1String("-qmlmodule.webxml")); + const QFileInfo qmlModuleFi(prefix + u"-qmlmodule.webxml"_s); if (qmlModuleFi.isFile()) { QString docString = doc.detailed(); - const int pos = docString.lastIndexOf(QLatin1String("</description>")); + const int pos = docString.lastIndexOf(u"</description>"); if (pos != -1) { docString.insert(pos, qmlReferenceLink(qmlModuleFi)); doc.setDetailed(docString); diff --git a/sources/shiboken6/ApiExtractor/qtdocparser.h b/sources/shiboken6/ApiExtractor/qtdocparser.h index 4cc335282..f6ba5e47a 100644 --- a/sources/shiboken6/ApiExtractor/qtdocparser.h +++ b/sources/shiboken6/ApiExtractor/qtdocparser.h @@ -1,52 +1,39 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef QTDOCPARSER_H #define QTDOCPARSER_H #include "docparser.h" +struct ClassDocumentation; + class QtDocParser : public DocParser { public: QtDocParser() = default; - void fillDocumentation(AbstractMetaClass* metaClass) override; + void fillDocumentation(const AbstractMetaClassPtr &metaClass) override; + void fillGlobalFunctionDocumentation(const AbstractMetaFunctionPtr &f) override; + void fillGlobalEnumDocumentation(AbstractMetaEnum &e) override; + Documentation retrieveModuleDocumentation() override; Documentation retrieveModuleDocumentation(const QString& name) override; private: + static QString functionDocumentation(const QString &sourceFileName, + const ClassDocumentation &classDocumentation, + const AbstractMetaClassCPtr &metaClass, + const AbstractMetaFunctionCPtr &func, + QString *errorMessage); + static QString queryFunctionDocumentation(const QString &sourceFileName, - const AbstractMetaClass* metaClass, - const QString &classQuery, + const ClassDocumentation &classDocumentation, + const AbstractMetaClassCPtr &metaClass, const AbstractMetaFunctionCPtr &func, - const DocModificationList &signedModifs, - const XQueryPtr &xquery, QString *errorMessage); + static bool extractEnumDocumentation(const ClassDocumentation &classDocumentation, + AbstractMetaEnum &meta_enum); + }; #endif // QTDOCPARSER_H diff --git a/sources/shiboken6/ApiExtractor/reporthandler.cpp b/sources/shiboken6/ApiExtractor/reporthandler.cpp index f0c5bf31e..23066ba21 100644 --- a/sources/shiboken6/ApiExtractor/reporthandler.cpp +++ b/sources/shiboken6/ApiExtractor/reporthandler.cpp @@ -1,40 +1,19 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "reporthandler.h" -#include "typesystem.h" #include "typedatabase.h" + +#include "qtcompat.h" + #include <QtCore/QElapsedTimer> #include <QtCore/QSet> #include <cstring> #include <cstdarg> #include <cstdio> +using namespace Qt::StringLiterals; + #if defined(_WINDOWS) || defined(NOCOLOR) #define COLOR_END "" #define COLOR_WHITE "" @@ -54,6 +33,7 @@ static ReportHandler::DebugLevel m_debugLevel = ReportHandler::NoDebug; static QSet<QString> m_reportedWarnings; static QString m_prefix; static bool m_withinProgress = false; +static QByteArray m_progressMessage; static int m_step_warning = 0; static QElapsedTimer m_timer; @@ -84,11 +64,11 @@ void ReportHandler::setDebugLevel(ReportHandler::DebugLevel level) bool ReportHandler::setDebugLevelFromArg(const QString &level) { bool result = true; - if (level == QLatin1String("sparse")) + if (level == u"sparse") ReportHandler::setDebugLevel(ReportHandler::SparseDebug); - else if (level == QLatin1String("medium")) + else if (level == u"medium") ReportHandler::setDebugLevel(ReportHandler::MediumDebug); - else if (level == QLatin1String("full")) + else if (level == u"full") ReportHandler::setDebugLevel(ReportHandler::FullDebug); else result = false; @@ -123,7 +103,7 @@ void ReportHandler::setPrefix(const QString &p) void ReportHandler::messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &text) { // Check for file location separator added by SourceLocation - int fileLocationPos = text.indexOf(QLatin1String(":\t")); + int fileLocationPos = text.indexOf(u":\t"); if (type == QtWarningMsg) { if (m_silent || m_reportedWarnings.contains(text)) return; @@ -142,12 +122,12 @@ void ReportHandler::messageOutput(QtMsgType type, const QMessageLogContext &cont } QString message = m_prefix; if (!message.isEmpty()) - message.append(QLatin1Char(' ')); - const int prefixLength = message.size(); + message.append(u' '); + const auto prefixLength = message.size(); message.append(text); // Replace file location tab by space if (fileLocationPos >= 0) - message[prefixLength + fileLocationPos + 1] = QLatin1Char(' '); + message[prefixLength + fileLocationPos + 1] = u' '; fprintf(stderr, "%s\n", qPrintable(qFormatLogMessage(type, context, message))); } @@ -168,9 +148,13 @@ void ReportHandler::startProgress(const QByteArray& str) endProgress(); m_withinProgress = true; - const auto ts = '[' + timeStamp() + ']'; - std::printf("%s %8s %-60s", qPrintable(m_prefix), ts.constData(), str.constData()); - std::fflush(stdout); + m_progressMessage = str; +} + +static void indentStdout(qsizetype n) +{ + for (qsizetype i = 0; i < n; ++i) + fputc(' ', stdout); } void ReportHandler::endProgress() @@ -179,11 +163,23 @@ void ReportHandler::endProgress() return; m_withinProgress = false; + + std::fputs(m_prefix.toUtf8().constData(), stdout); + const auto ts = timeStamp(); + if (ts.size() < 6) + indentStdout(6 - ts.size()); + std::fputs(" [", stdout); + std::fputs(ts.constData(), stdout); + std::fputs("] ", stdout); + std::fputs(m_progressMessage.constData(), stdout); + if (m_progressMessage.size() < 60) + indentStdout(60 - m_progressMessage.size()); const char *endMessage = m_step_warning == 0 ? "[" COLOR_GREEN "OK" COLOR_END "]\n" : "[" COLOR_YELLOW "WARNING" COLOR_END "]\n"; std::fputs(endMessage, stdout); std::fflush(stdout); + m_progressMessage.clear(); m_step_warning = 0; } diff --git a/sources/shiboken6/ApiExtractor/reporthandler.h b/sources/shiboken6/ApiExtractor/reporthandler.h index 21f0e8933..b79adfa73 100644 --- a/sources/shiboken6/ApiExtractor/reporthandler.h +++ b/sources/shiboken6/ApiExtractor/reporthandler.h @@ -1,36 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef REPORTHANDLER_H #define REPORTHANDLER_H -#include <QLoggingCategory> -#include <QString> +#include <QtCore/QLoggingCategory> +#include <QtCore/QString> Q_DECLARE_LOGGING_CATEGORY(lcShiboken) Q_DECLARE_LOGGING_CATEGORY(lcShibokenDoc) diff --git a/sources/shiboken6/ApiExtractor/smartpointertypeentry.h b/sources/shiboken6/ApiExtractor/smartpointertypeentry.h new file mode 100644 index 000000000..7b712fe35 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/smartpointertypeentry.h @@ -0,0 +1,57 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef SMARTPOINTERTYPEENTRY_H +#define SMARTPOINTERTYPEENTRY_H + +#include "complextypeentry.h" + +class SmartPointerTypeEntryPrivate; + +struct SmartPointerInstantiation +{ + QString name; // user defined name + TypeEntryCPtr typeEntry; +}; + +class SmartPointerTypeEntry : public ComplexTypeEntry +{ +public: + using Instantiations = QList<SmartPointerInstantiation>; + + explicit SmartPointerTypeEntry(const QString &entryName, + const QString &getterName, + TypeSystem::SmartPointerType type, + const QString &refCountMethodName, + const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + TypeSystem::SmartPointerType smartPointerType() const; + + QString getter() const; + + QString refCountMethodName() const; + + QString valueCheckMethod() const; + void setValueCheckMethod(const QString &); + QString nullCheckMethod() const; + void setNullCheckMethod(const QString &); + QString resetMethod() const; + void setResetMethod(const QString &); + + TypeEntry *clone() const override; + + const Instantiations &instantiations() const; + void setInstantiations(const Instantiations &i); + bool matchesInstantiation(const TypeEntryCPtr &e) const; + + QString getTargetName(const AbstractMetaType &metaType) const; + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif +protected: + SmartPointerTypeEntry(SmartPointerTypeEntryPrivate *d); +}; + +#endif // SMARTPOINTERTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/sourcelocation.cpp b/sources/shiboken6/ApiExtractor/sourcelocation.cpp index 1ba66e05b..003f201ac 100644 --- a/sources/shiboken6/ApiExtractor/sourcelocation.cpp +++ b/sources/shiboken6/ApiExtractor/sourcelocation.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "sourcelocation.h" #include <QtCore/QDir> diff --git a/sources/shiboken6/ApiExtractor/sourcelocation.h b/sources/shiboken6/ApiExtractor/sourcelocation.h index 630a841d8..0b188dca3 100644 --- a/sources/shiboken6/ApiExtractor/sourcelocation.h +++ b/sources/shiboken6/ApiExtractor/sourcelocation.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef SOURCE_LOCATION_H #define SOURCE_LOCATION_H -#include <QString> +#include <QtCore/QString> QT_FORWARD_DECLARE_CLASS(QDebug) QT_FORWARD_DECLARE_CLASS(QTextStream) diff --git a/sources/shiboken6/ApiExtractor/templateargumententry.h b/sources/shiboken6/ApiExtractor/templateargumententry.h new file mode 100644 index 000000000..9f2338022 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/templateargumententry.h @@ -0,0 +1,26 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef TEMPLATEARGUMENTENTRY_H +#define TEMPLATEARGUMENTENTRY_H + +#include "typesystem.h" + +class TemplateArgumentEntryPrivate; + +class TemplateArgumentEntry : public TypeEntry +{ +public: + explicit TemplateArgumentEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + int ordinal() const; + void setOrdinal(int o); + + TypeEntry *clone() const override; + +protected: + explicit TemplateArgumentEntry(TemplateArgumentEntryPrivate *d); +}; + +#endif // TEMPLATEARGUMENTENTRY_H diff --git a/sources/shiboken6/ApiExtractor/tests/CMakeLists.txt b/sources/shiboken6/ApiExtractor/tests/CMakeLists.txt index 97ae0f850..76c014fbb 100644 --- a/sources/shiboken6/ApiExtractor/tests/CMakeLists.txt +++ b/sources/shiboken6/ApiExtractor/tests/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + set(CMAKE_AUTORCC ON) macro(declare_test testname) @@ -15,7 +18,7 @@ macro(declare_test testname) ${CMAKE_CURRENT_BINARY_DIR} ${apiextractor_SOURCE_DIR} ) - target_link_libraries(${testname} PRIVATE apiextractor Qt${QT_MAJOR_VERSION}::Test) + target_link_libraries(${testname} PRIVATE apiextractor Qt::Test) add_test(${testname} ${testname}) if (INSTALL_TESTS) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${testname} diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp index 850df753f..4b5da0c3a 100644 --- a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp @@ -1,95 +1,77 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testabstractmetaclass.h" #include "abstractmetabuilder.h" -#include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> #include <usingmember.h> #include <typesystem.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestAbstractMetaClass::testClassName() { - const char* cppCode ="class ClassName {};"; - const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"ClassName\"/></typesystem>"; + const char cppCode[] = "class ClassName {};"; + const char xmlCode[] = R"(<typesystem package="Foo"> + <value-type name="ClassName"/> +</typesystem>)"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 1); - QCOMPARE(classes[0]->name(), QLatin1String("ClassName")); + QCOMPARE(classes.size(), 1); + QCOMPARE(classes[0]->name(), u"ClassName"); } void TestAbstractMetaClass::testClassNameUnderNamespace() { - const char* cppCode ="namespace Namespace { class ClassName {}; }\n"; - const char* xmlCode = R"XML( + const char cppCode[] = "namespace Namespace { class ClassName {}; }\n"; + const char xmlCode[] = R"XML( <typesystem package="Foo"> <namespace-type name="Namespace"> <value-type name="ClassName"/> </namespace-type> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); // 1 namespace + 1 class - if (classes.constFirst()->name() != QLatin1String("ClassName")) + QCOMPARE(classes.size(), 2); // 1 namespace + 1 class + if (classes.constFirst()->name() != u"ClassName") qSwap(classes[0], classes[1]); - QCOMPARE(classes[0]->name(), QLatin1String("ClassName")); - QCOMPARE(classes[0]->qualifiedCppName(), QLatin1String("Namespace::ClassName")); - QCOMPARE(classes[1]->name(), QLatin1String("Namespace")); + QCOMPARE(classes[0]->name(), u"ClassName"); + QCOMPARE(classes[0]->qualifiedCppName(), u"Namespace::ClassName"); + QCOMPARE(classes[1]->name(), u"Namespace"); QVERIFY(classes[1]->isNamespace()); // Check ctors info QVERIFY(classes[0]->hasConstructors()); QCOMPARE(classes[0]->functions().size(), 2); // default ctor + copy ctor - auto ctors = classes[0]->queryFunctions(FunctionQueryOption::Constructors); + auto ctors = classes[0]->queryFunctions(FunctionQueryOption::AnyConstructor); QCOMPARE(ctors.size(), 2); - if (ctors.constFirst()->minimalSignature() != QLatin1String("ClassName()")) + if (ctors.constFirst()->minimalSignature() != u"ClassName()") qSwap(ctors[0], ctors[1]); QCOMPARE(ctors[0]->arguments().size(), 0); - QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("ClassName()")); + QCOMPARE(ctors[0]->minimalSignature(), u"ClassName()"); QCOMPARE(ctors[1]->arguments().size(), 1); - QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("ClassName(Namespace::ClassName)")); + QCOMPARE(ctors[1]->minimalSignature(), u"ClassName(Namespace::ClassName)"); QVERIFY(!classes[0]->hasPrivateDestructor()); - QVERIFY(classes[0]->hasCloneOperator()); // implicit default copy ctor - QVERIFY(!classes[0]->hasHashFunction()); + QVERIFY(classes[0]->isCopyConstructible()); // implicit default copy ctor // This method is buggy and nobody wants to fix it or needs it fixed :-/ // QVERIFY(classes[0]->hasNonPrivateConstructor()); } -static AbstractMetaFunctionCList virtualFunctions(const AbstractMetaClass *c) +static AbstractMetaFunctionCList virtualFunctions(const AbstractMetaClassCPtr &c) { AbstractMetaFunctionCList result; const auto &functions = c->functions(); @@ -128,18 +110,16 @@ public: </typesystem> )XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 4); - AbstractMetaClass* a = AbstractMetaClass::findClass(classes, QLatin1String("A")); - AbstractMetaClass* b = AbstractMetaClass::findClass(classes, QLatin1String("B")); - AbstractMetaClass* c = AbstractMetaClass::findClass(classes, QLatin1String("C")); - const AbstractMetaClass *f = AbstractMetaClass::findClass(classes, QLatin1String("F")); + QCOMPARE(classes.size(), 4); + const auto a = AbstractMetaClass::findClass(classes, "A"); + const auto b = AbstractMetaClass::findClass(classes, "B"); + const auto c = AbstractMetaClass::findClass(classes, "C"); + const auto f = AbstractMetaClass::findClass(classes, "F"); QVERIFY(f); - AbstractMetaClass* no_class = nullptr; - - QCOMPARE(a->baseClass(), no_class); + QCOMPARE(a->baseClass(), nullptr); QCOMPARE(b->baseClass(), a); QCOMPARE(c->baseClass(), b); QCOMPARE(f->baseClass(), c); @@ -179,11 +159,11 @@ public: const auto funcF = virtualFunctionsF.constFirst(); QCOMPARE(funcA->ownerClass(), a); - QVERIFY(funcC->attributes().testFlag(AbstractMetaFunction::VirtualCppMethod)); + QVERIFY(funcC->isVirtual()); QCOMPARE(funcB->ownerClass(), b); QCOMPARE(funcC->ownerClass(), c); - QVERIFY(funcC->attributes().testFlag(AbstractMetaFunction::OverriddenCppMethod)); - QVERIFY(funcF->attributes().testFlag(AbstractMetaFunction::FinalCppMethod)); + QVERIFY(funcC->cppAttributes().testFlag(FunctionAttribute::Override)); + QVERIFY(funcF->cppAttributes().testFlag(FunctionAttribute::Final)); QCOMPARE(funcA->declaringClass(), a); QCOMPARE(funcB->declaringClass(), a); @@ -214,48 +194,49 @@ class Derived : public Base {}; </typesystem> )XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - auto base = AbstractMetaClass::findClass(classes, QLatin1String("Base")); + const auto base = AbstractMetaClass::findClass(classes, "Base"); QVERIFY(base); QVERIFY(base->isPolymorphic()); - auto derived = AbstractMetaClass::findClass(classes, QLatin1String("Derived")); + const auto derived = AbstractMetaClass::findClass(classes, "Derived"); QVERIFY(derived); QVERIFY(derived->isPolymorphic()); } void TestAbstractMetaClass::testDefaultValues() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ class B {};\n\ void method(B b = B());\n\ };\n"; - const char* xmlCode = R"XML( + const char xmlCode[] = R"XML( <typesystem package="Foo"> <value-type name='A'> <value-type name='B'/> </value-type> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - QCOMPARE(classA->queryFunctionsByName(QLatin1String("method")).count(), 1); - const auto method = classA->queryFunctionsByName(QLatin1String("method")).constFirst(); + QCOMPARE(classes.size(), 2); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + const auto candidates = classA->queryFunctionsByName(u"method"_s); + QCOMPARE(candidates.size(), 1); + const auto &method = candidates.constFirst(); const AbstractMetaArgument &arg = method->arguments().constFirst(); QCOMPARE(arg.defaultValueExpression(), arg.originalDefaultValueExpression()); } void TestAbstractMetaClass::testModifiedDefaultValues() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ class B {};\n\ void method(B b = B());\n\ };\n"; - const char* xmlCode = R"XML( + const char xmlCode[] = R"XML( <typesystem package="Foo"> <value-type name='A'> <modify-function signature='method(A::B)'> @@ -267,39 +248,39 @@ void TestAbstractMetaClass::testModifiedDefaultValues() </value-type> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - const auto methodMatches = classA->queryFunctionsByName(QLatin1String("method")); - QCOMPARE(methodMatches.count(), 1); + QCOMPARE(classes.size(), 2); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + const auto methodMatches = classA->queryFunctionsByName(u"method"_s); + QCOMPARE(methodMatches.size(), 1); const auto method = methodMatches.constFirst(); const AbstractMetaArgument &arg = method->arguments().constFirst(); - QCOMPARE(arg.defaultValueExpression(), QLatin1String("Hello")); - QCOMPARE(arg.originalDefaultValueExpression(), QLatin1String("A::B()")); + QCOMPARE(arg.defaultValueExpression(), u"Hello"); + QCOMPARE(arg.originalDefaultValueExpression(), u"A::B()"); } void TestAbstractMetaClass::testInnerClassOfAPolymorphicOne() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ class B {};\n\ virtual void method();\n\ };\n"; - const char* xmlCode = R"XML( + const char xmlCode[] = R"XML( <typesystem package="Foo"> <object-type name='A'> <value-type name='B'/> </object-type> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classes.size(), 2); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); QVERIFY(classA->isPolymorphic()); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("A::B")); + const auto classB = AbstractMetaClass::findClass(classes, "A::B"); QVERIFY(classB); QVERIFY(!classB->isPolymorphic()); } @@ -321,15 +302,15 @@ void TestAbstractMetaClass::testForwardDeclaredInnerClass() </value-type> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classes.size(), 2); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("A::B")); + const auto classB = AbstractMetaClass::findClass(classes, "A::B"); QVERIFY(classB); - const auto fooF = classB->findFunction(QLatin1String("foo")); - QVERIFY(!fooF.isNull()); + const auto fooF = classB->findFunction("foo"); + QVERIFY(fooF); } void TestAbstractMetaClass::testSpecialFunctions() @@ -352,35 +333,35 @@ void TestAbstractMetaClass::testSpecialFunctions() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); + QCOMPARE(classes.size(), 2); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors); + auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor); QCOMPARE(ctors.size(), 2); QCOMPARE(ctors.constFirst()->functionType(), AbstractMetaFunction::ConstructorFunction); QCOMPARE(ctors.at(1)->functionType(), AbstractMetaFunction::CopyConstructorFunction); - auto assigmentOps = classA->queryFunctionsByName(QLatin1String("operator=")); + auto assigmentOps = classA->queryFunctionsByName(u"operator="_s); QCOMPARE(assigmentOps.size(), 1); QCOMPARE(assigmentOps.constFirst()->functionType(), AbstractMetaFunction::AssignmentOperatorFunction); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classB); - ctors = classB->queryFunctions(FunctionQueryOption::Constructors); + ctors = classB->queryFunctions(FunctionQueryOption::AnyConstructor); QCOMPARE(ctors.size(), 2); QCOMPARE(ctors.constFirst()->functionType(), AbstractMetaFunction::ConstructorFunction); QCOMPARE(ctors.at(1)->functionType(), AbstractMetaFunction::CopyConstructorFunction); - assigmentOps = classA->queryFunctionsByName(QLatin1String("operator=")); + assigmentOps = classA->queryFunctionsByName(u"operator="_s); QCOMPARE(assigmentOps.size(), 1); QCOMPARE(assigmentOps.constFirst()->functionType(), AbstractMetaFunction::AssignmentOperatorFunction); } void TestAbstractMetaClass::testClassDefaultConstructors() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {};\n\ \n\ struct B {\n\ @@ -406,7 +387,7 @@ void TestAbstractMetaClass::testClassDefaultConstructors() struct F {\n\ F(int, int);\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='int'/>\n\ <value-type name='A'/>\n\ @@ -418,163 +399,163 @@ void TestAbstractMetaClass::testClassDefaultConstructors() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 6); + QCOMPARE(classes.size(), 6); - AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); QCOMPARE(classA->functions().size(), 2); - auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors); + auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor); QCOMPARE(ctors.size(), 2); - if (ctors.constFirst()->minimalSignature() != QLatin1String("A()")) + if (ctors.constFirst()->minimalSignature() != u"A()") qSwap(ctors[0], ctors[1]); QCOMPARE(ctors[0]->arguments().size(), 0); - QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("A()")); + QCOMPARE(ctors[0]->minimalSignature(), u"A()"); QCOMPARE(ctors[1]->arguments().size(), 1); - QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("A(A)")); + QCOMPARE(ctors[1]->minimalSignature(), u"A(A)"); - AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classB); QCOMPARE(classB->functions().size(), 2); - QCOMPARE(classB->functions().constFirst()->minimalSignature(), QLatin1String("B()")); + QCOMPARE(classB->functions().constFirst()->minimalSignature(), u"B()"); - AbstractMetaClass* classC = AbstractMetaClass::findClass(classes, QLatin1String("C")); + const auto classC = AbstractMetaClass::findClass(classes, "C"); QVERIFY(classC); QCOMPARE(classC->functions().size(), 1); - QCOMPARE(classC->functions().constFirst()->minimalSignature(), QLatin1String("C(C)")); + QCOMPARE(classC->functions().constFirst()->minimalSignature(), u"C(C)"); - AbstractMetaClass* classD = AbstractMetaClass::findClass(classes, QLatin1String("D")); + const auto classD = AbstractMetaClass::findClass(classes, "D"); QVERIFY(classD); QCOMPARE(classD->functions().size(), 1); - QCOMPARE(classD->functions().constFirst()->minimalSignature(), QLatin1String("D(D)")); + QCOMPARE(classD->functions().constFirst()->minimalSignature(), u"D(D)"); QVERIFY(classD->functions().constFirst()->isPrivate()); - AbstractMetaClass* classE = AbstractMetaClass::findClass(classes, QLatin1String("E")); + const auto classE = AbstractMetaClass::findClass(classes, "E"); QVERIFY(classE); QVERIFY(classE->hasPrivateDestructor()); QCOMPARE(classE->functions().size(), 0); - AbstractMetaClass* classF = AbstractMetaClass::findClass(classes, QLatin1String("F")); + const auto classF = AbstractMetaClass::findClass(classes, "F"); QVERIFY(classF); - ctors = classF->queryFunctions(FunctionQueryOption::Constructors); + ctors = classF->queryFunctions(FunctionQueryOption::AnyConstructor); QCOMPARE(ctors.size(), 2); - if (ctors.constFirst()->minimalSignature() != QLatin1String("F(int,int)")) + if (ctors.constFirst()->minimalSignature() != u"F(int,int)") qSwap(ctors[0], ctors[1]); QCOMPARE(ctors[0]->arguments().size(), 2); - QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("F(int,int)")); + QCOMPARE(ctors[0]->minimalSignature(), u"F(int,int)"); QCOMPARE(ctors[1]->arguments().size(), 1); - QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("F(F)")); + QCOMPARE(ctors[1]->minimalSignature(), u"F(F)"); } void TestAbstractMetaClass::testClassInheritedDefaultConstructors() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ A();\n\ private: \n\ A(const A&);\n\ };\n\ struct B : public A {};\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <object-type name='A'/>\n\ <object-type name='B'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classes.size(), 2); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors); + auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor); QCOMPARE(ctors.size(), 2); - if (ctors.constFirst()->minimalSignature() != QLatin1String("A()")) + if (ctors.constFirst()->minimalSignature() != u"A()") qSwap(ctors[0], ctors[1]); QCOMPARE(ctors[0]->arguments().size(), 0); - QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("A()")); + QCOMPARE(ctors[0]->minimalSignature(), u"A()"); QCOMPARE(ctors[1]->arguments().size(), 1); - QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("A(A)")); + QCOMPARE(ctors[1]->minimalSignature(), u"A(A)"); QVERIFY(ctors[1]->isPrivate()); - AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classB); ctors = classB->queryFunctions(FunctionQueryOption::Constructors); QCOMPARE(ctors.size(), 1); QCOMPARE(ctors.constFirst()->arguments().size(), 0); - QCOMPARE(ctors.constFirst()->minimalSignature(), QLatin1String("B()")); + QCOMPARE(ctors.constFirst()->minimalSignature(), u"B()"); } void TestAbstractMetaClass::testAbstractClassDefaultConstructors() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ virtual void method() = 0;\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <object-type name='A'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 1); - AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classes.size(), 1); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); const auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors); QCOMPARE(ctors.size(), 1); QCOMPARE(ctors.constFirst()->arguments().size(), 0); - QCOMPARE(ctors.constFirst()->minimalSignature(), QLatin1String("A()")); + QCOMPARE(ctors.constFirst()->minimalSignature(), u"A()"); } void TestAbstractMetaClass::testObjectTypesMustNotHaveCopyConstructors() { - const char* cppCode ="struct A {};\n"; - const char* xmlCode = "\ + const char cppCode[] = "struct A {};\n"; + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <object-type name='A'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 1); - AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classes.size(), 1); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); const auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors); QCOMPARE(ctors.size(), 1); QCOMPARE(ctors.constFirst()->arguments().size(), 0); - QCOMPARE(ctors.constFirst()->minimalSignature(), QLatin1String("A()")); + QCOMPARE(ctors.constFirst()->minimalSignature(), u"A()"); } void TestAbstractMetaClass::testIsPolymorphic() { - const char* cppCode = "\ + const char cppCode[] = "\ class A\n\ {\n\ public:\n\ A();\n\ - inline bool abc() const {}\n\ + inline bool abc() const { return false; }\n\ };\n\ \n\ class B : public A\n\ {\n\ public:\n\ B();\n\ - inline bool abc() const {}\n\ + inline bool abc() const { return false; }\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='bool'/>\n\ <value-type name='A'/>\n\ @@ -582,13 +563,13 @@ void TestAbstractMetaClass::testIsPolymorphic() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - AbstractMetaClass* b = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classes.size(), 2); + const auto b = AbstractMetaClass::findClass(classes, "A"); QVERIFY(!b->isPolymorphic()); - AbstractMetaClass* a = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto a = AbstractMetaClass::findClass(classes, "B"); QVERIFY(!a->isPolymorphic()); } @@ -612,12 +593,12 @@ class Derived : public BaseAlias2 { )XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - auto base = AbstractMetaClass::findClass(classes, QLatin1String("Base")); + QCOMPARE(classes.size(), 2); + const auto base = AbstractMetaClass::findClass(classes, "Base"); QVERIFY(base); - auto derived = AbstractMetaClass::findClass(classes, QLatin1String("Derived")); + const auto derived = AbstractMetaClass::findClass(classes, "Derived"); QVERIFY(derived); QCOMPARE(derived->baseClasses().value(0), base); } @@ -663,7 +644,7 @@ void TestAbstractMetaClass::testFreeOperators() </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(code.constData(), xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); const auto classes = builder->classes(); QCOMPARE(classes.size(), 1); QVERIFY(classes.constFirst()->hasArithmeticOperatorOverload()); @@ -697,15 +678,15 @@ public: )XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - auto base = AbstractMetaClass::findClass(classes, QLatin1String("Base")); + QCOMPARE(classes.size(), 2); + const auto base = AbstractMetaClass::findClass(classes, "Base"); QVERIFY(base); - auto derived = AbstractMetaClass::findClass(classes, QLatin1String("Derived")); + const auto derived = AbstractMetaClass::findClass(classes, "Derived"); QVERIFY(derived); const auto usingMembers = derived->usingMembers(); - QCOMPARE(usingMembers.count(), 2); + QCOMPARE(usingMembers.size(), 2); for (const auto &um : usingMembers) { QCOMPARE(um.access, Access::Public); QCOMPARE(um.baseClass, base); @@ -752,13 +733,46 @@ void TestAbstractMetaClass::testUsingTemplateMembers() )XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(code.constData(), xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - auto valueList = AbstractMetaClass::findClass(classes, QLatin1String("ValueList")); + const auto valueList = AbstractMetaClass::findClass(classes, "ValueList"); QVERIFY(valueList); auto list = valueList->templateBaseClass(); - QVERIFY(valueList->isUsingMember(list, QLatin1String("append"), Access::Public)); - QCOMPARE(valueList->queryFunctionsByName(QLatin1String("append")).size(), 2); + QVERIFY(valueList->isUsingMember(list, u"append"_s, Access::Public)); + QCOMPARE(valueList->queryFunctionsByName(u"append"_s).size(), 2); +} + +void TestAbstractMetaClass::testGenerateFunctions() +{ + const char cppCode[] = R"CPP( +class TestClass { +public: + TestClass(); + + void alpha(int); + void beta(int); + void beta(double); + void gamma(int); +}; +)CPP"; + + const char xmlCode[] = R"XML( +<typesystem package='Foo'> + <object-type name='TestClass' generate-functions='beta(double);gamma'/> +</typesystem> +)XML"; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(builder); + AbstractMetaClassList classes = builder->classes(); + const auto tc = AbstractMetaClass::findClass(classes, "TestClass"); + // Verify that the constructor and 2 functions are generated. + const auto &functions = tc->functions(); + QCOMPARE(functions.size(), 5); + const auto generateCount = + std::count_if(functions.cbegin(), functions.cend(), + [](const auto &af) { return af->generateBinding(); }); + QCOMPARE(generateCount, 3); } QTEST_APPLESS_MAIN(TestAbstractMetaClass) diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h index ab171d6b7..a6bd2bf06 100644 --- a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h +++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTABSTRACTMETACLASS_H #define TESTABSTRACTMETACLASS_H -#include <QObject> +#include <QtCore/QObject> class AbstractMetaBuilder; @@ -57,6 +32,7 @@ private slots: void testUsingMembers(); void testUsingTemplateMembers_data(); void testUsingTemplateMembers(); + void testGenerateFunctions(); }; #endif // TESTABSTRACTMETACLASS_H diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp index 897940cd5..2c320c874 100644 --- a/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp @@ -1,40 +1,22 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testabstractmetatype.h" -#include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> +#include <abstractmetatype.h> #include <typesystem.h> #include <parser/codemodel.h> #include <typeparser.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestAbstractMetaType::parsing_data() { QTest::addColumn<QString>("input"); @@ -66,20 +48,20 @@ void TestAbstractMetaType::parsing() void TestAbstractMetaType::testConstCharPtrType() { - const char* cppCode ="const char* justAtest();\n"; - const char* xmlCode = "<typesystem package=\"Foo\">\n\ + const char cppCode[] = "const char* justAtest();\n"; + const char xmlCode[] = "<typesystem package=\"Foo\">\n\ <primitive-type name='char'/>\n\ <function signature='justAtest()' />\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); QCOMPARE(builder->globalFunctions().size(), 1); const auto func = builder->globalFunctions().constFirst(); AbstractMetaType rtype = func->type(); // Test properties of const char* QVERIFY(!rtype.isVoid()); - QCOMPARE(rtype.package(), QLatin1String("Foo")); - QCOMPARE(rtype.name(), QLatin1String("char")); + QCOMPARE(rtype.package(), u"Foo"); + QCOMPARE(rtype.name(), u"char"); QVERIFY(rtype.isConstant()); QVERIFY(!rtype.isArray()); QVERIFY(!rtype.isContainer()); @@ -93,9 +75,9 @@ void TestAbstractMetaType::testConstCharPtrType() void TestAbstractMetaType::testApiVersionSupported() { - const char* cppCode ="class foo {}; class foo2 {};\n\ + const char cppCode[] = "class foo {}; class foo2 {};\n\ void justAtest(); void justAtest3();\n"; - const char* xmlCode = "<typesystem package='Foo'>\n\ + const char xmlCode[] = "<typesystem package='Foo'>\n\ <value-type name='foo' since='0.1'/>\n\ <value-type name='foo2' since='1.0'/>\n\ <value-type name='foo3' since='1.1'/>\n\ @@ -104,8 +86,8 @@ void TestAbstractMetaType::testApiVersionSupported() <function signature='justAtest3()'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, - false, QLatin1String("1.0"))); - QVERIFY(!builder.isNull()); + false, u"1.0"_s)); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); QCOMPARE(classes.size(), 2); @@ -117,13 +99,13 @@ void TestAbstractMetaType::testApiVersionSupported() void TestAbstractMetaType::testApiVersionNotSupported() { - const char* cppCode ="class object {};\n"; - const char* xmlCode = "<typesystem package='Foo'>\n\ + const char cppCode[] = "class object {};\n"; + const char xmlCode[] = "<typesystem package='Foo'>\n\ <value-type name='object' since='0.1'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, - true, QLatin1String("0.1"))); - QVERIFY(!builder.isNull()); + true, u"0.1"_s)); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); QCOMPARE(classes.size(), 1); @@ -131,18 +113,18 @@ void TestAbstractMetaType::testApiVersionNotSupported() void TestAbstractMetaType::testCharType() { - const char* cppCode ="char justAtest(); class A {};\n"; - const char* xmlCode = "<typesystem package=\"Foo\">\n\ + const char cppCode[] = "char justAtest(); class A {};\n"; + const char xmlCode[] = "<typesystem package=\"Foo\">\n\ <primitive-type name='char'/>\n\ <value-type name='A'/>\n\ <function signature='justAtest()'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); QCOMPARE(classes.size(), 1); - QCOMPARE(classes.constFirst()->package(), QLatin1String("Foo")); + QCOMPARE(classes.constFirst()->package(), u"Foo"); const auto functions = builder->globalFunctions(); QCOMPARE(functions.size(), 1); @@ -150,8 +132,8 @@ void TestAbstractMetaType::testCharType() AbstractMetaType rtype = func->type(); // Test properties of const char* QVERIFY(!rtype.isVoid()); - QCOMPARE(rtype.package(), QLatin1String("Foo")); - QCOMPARE(rtype.name(), QLatin1String("char")); + QCOMPARE(rtype.package(), u"Foo"); + QCOMPARE(rtype.name(), u"char"); QVERIFY(!rtype.isConstant()); QVERIFY(!rtype.isArray()); QVERIFY(!rtype.isContainer()); @@ -165,28 +147,28 @@ void TestAbstractMetaType::testCharType() void TestAbstractMetaType::testTypedef() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ void someMethod();\n\ };\n\ typedef A B;\n\ typedef B C;\n"; - const char* xmlCode = "<typesystem package=\"Foo\">\n\ + const char xmlCode[] = "<typesystem package=\"Foo\">\n\ <value-type name='C' />\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); QCOMPARE(classes.size(), 1); - const AbstractMetaClass *c = AbstractMetaClass::findClass(classes, QLatin1String("C")); + const auto c = AbstractMetaClass::findClass(classes, "C"); QVERIFY(c); QVERIFY(c->isTypeDef()); } void TestAbstractMetaType::testTypedefWithTemplates() { - const char* cppCode ="\ + const char cppCode[] = "\ template<typename T>\n\ class A {};\n\ \n\ @@ -194,52 +176,52 @@ void TestAbstractMetaType::testTypedefWithTemplates() typedef A<B> C;\n\ \n\ void func(C c);\n"; - const char* xmlCode = "<typesystem package=\"Foo\">\n\ + const char xmlCode[] = "<typesystem package=\"Foo\">\n\ <container-type name='A' type='list'/>\n\ <value-type name='B' />\n\ <function signature='func(A<B>)'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); QCOMPARE(classes.size(), 1); const auto functions = builder->globalFunctions(); - QCOMPARE(functions.count(), 1); + QCOMPARE(functions.size(), 1); const auto function = functions.constFirst(); AbstractMetaArgumentList args = function->arguments(); - QCOMPARE(args.count(), 1); + QCOMPARE(args.size(), 1); const AbstractMetaArgument &arg = args.constFirst(); AbstractMetaType metaType = arg.type(); - QCOMPARE(metaType.cppSignature(), QLatin1String("A<B >")); + QCOMPARE(metaType.cppSignature(), u"A<B>"); } void TestAbstractMetaType::testObjectTypeUsedAsValue() { - const char* cppCode ="\ + const char cppCode[] = "\ class A {\n\ void method(A);\n\ };\n"; - const char* xmlCode = "<typesystem package='Foo'>\n\ + const char xmlCode[] = "<typesystem package='Foo'>\n\ <object-type name='A'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); QCOMPARE(classes.size(), 1); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const auto overloads = classA->queryFunctionsByName(QLatin1String("method")); - QCOMPARE(overloads.count(), 1); + const auto overloads = classA->queryFunctionsByName(u"method"_s); + QCOMPARE(overloads.size(), 1); const auto method = overloads.constFirst(); QVERIFY(method); AbstractMetaArgumentList args = method->arguments(); - QCOMPARE(args.count(), 1); + QCOMPARE(args.size(), 1); const AbstractMetaArgument &arg = args.constFirst(); AbstractMetaType metaType = arg.type(); - QCOMPARE(metaType.cppSignature(), QLatin1String("A")); + QCOMPARE(metaType.cppSignature(), u"A"); QVERIFY(metaType.isValue()); QVERIFY(metaType.typeEntry()->isObject()); } diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h index b39a27a54..fdcf0c787 100644 --- a/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h +++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTABSTRACTMETATYPE_H #define TESTABSTRACTMETATYPE_H -#include <QObject> +#include <QtCore/QObject> class TestAbstractMetaType : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp index 1c5e31f35..a891e1e28 100644 --- a/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp @@ -1,80 +1,67 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testaddfunction.h" -#include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> -#include <modifications.h> -#include <modifications_p.h> -#include <typesystem.h> +#include <abstractmetatype.h> +#include <codesnip.h> +#include <addedfunction.h> +#include <addedfunction_p.h> +#include <complextypeentry.h> +#include <primitivetypeentry.h> + +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + +static constexpr auto voidT = "void"_L1; void TestAddFunction::testParsingFuncNameAndConstness() { // generic test... - const char sig1[] = "func(type1, const type2, const type3* const)"; + static constexpr auto sig1 = "func(type1, const type2, const type3* const)"_L1; QString errorMessage; - auto f1 = AddedFunction::createAddedFunction(QLatin1String(sig1), QLatin1String("void"), - &errorMessage); - QVERIFY2(!f1.isNull(), qPrintable(errorMessage)); - QCOMPARE(f1->name(), QLatin1String("func")); - QCOMPARE(f1->arguments().count(), 3); + auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage); + QVERIFY2(f1, qPrintable(errorMessage)); + QCOMPARE(f1->name(), u"func"); + QCOMPARE(f1->arguments().size(), 3); TypeInfo retval = f1->returnType(); - QCOMPARE(retval.qualifiedName(), QStringList{QLatin1String("void")}); + QCOMPARE(retval.qualifiedName(), QStringList{voidT}); QCOMPARE(retval.indirections(), 0); QCOMPARE(retval.isConstant(), false); QCOMPARE(retval.referenceType(), NoReference); // test with a ugly template as argument and other ugly stuff - const char sig2[] = " _fu__nc_ ( type1, const type2, const Abc<int& , C<char*> * > * *@my_name@, const type3* const ) const "; - auto f2 = AddedFunction::createAddedFunction(QLatin1String(sig2), - QLatin1String("const Abc<int& , C<char*> * > * *"), + static constexpr auto sig2 = + " _fu__nc_ ( type1, const type2, const Abc<int& , C<char*> * >" + " * *@my_name@, const type3* const ) const "_L1; + auto f2 = AddedFunction::createAddedFunction(sig2, + u"const Abc<int& , C<char*> * > * *"_s, &errorMessage); - QVERIFY2(!f2.isNull(), qPrintable(errorMessage)); - QCOMPARE(f2->name(), QLatin1String("_fu__nc_")); + QVERIFY2(f2, qPrintable(errorMessage)); + QCOMPARE(f2->name(), u"_fu__nc_"); const auto &args = f2->arguments(); - QCOMPARE(args.count(), 4); + QCOMPARE(args.size(), 4); retval = f2->returnType(); - QCOMPARE(retval.qualifiedName(), QStringList{QLatin1String("Abc")}); + QCOMPARE(retval.qualifiedName(), QStringList{u"Abc"_s}); QCOMPARE(retval.instantiations().size(), 2); - QCOMPARE(retval.toString(), QLatin1String("const Abc<int&, C<char*>*>**")); + QCOMPARE(retval.toString(), u"const Abc<int&, C<char*>*>**"); QCOMPARE(retval.indirections(), 2); QCOMPARE(retval.isConstant(), true); QCOMPARE(retval.referenceType(), NoReference); QVERIFY(args.at(0).name.isEmpty()); QVERIFY(args.at(1).name.isEmpty()); - QCOMPARE(args.at(2).name, QLatin1String("my_name")); + QCOMPARE(args.at(2).name, u"my_name"); auto arg2Type = args.at(2).typeInfo; - QCOMPARE(arg2Type.qualifiedName(), QStringList{QLatin1String("Abc")}); + QCOMPARE(arg2Type.qualifiedName(), QStringList{u"Abc"_s}); QCOMPARE(arg2Type.instantiations().size(), 2); - QCOMPARE(arg2Type.toString(), QLatin1String("const Abc<int&, C<char*>*>**")); + QCOMPARE(arg2Type.toString(), u"const Abc<int&, C<char*>*>**"); QCOMPARE(arg2Type.indirections(), 2); QCOMPARE(arg2Type.isConstant(), true); QCOMPARE(arg2Type.referenceType(), NoReference); @@ -82,20 +69,17 @@ void TestAddFunction::testParsingFuncNameAndConstness() QVERIFY(args.at(3).name.isEmpty()); // function with no args. - const char sig3[] = "func()"; - auto f3 = AddedFunction::createAddedFunction(QLatin1String(sig3), QLatin1String("void"), - &errorMessage); - QVERIFY2(!f3.isNull(), qPrintable(errorMessage)); - QCOMPARE(f3->name(), QLatin1String("func")); - QCOMPARE(f3->arguments().count(), 0); + auto f3 = AddedFunction::createAddedFunction("func()"_L1, voidT, &errorMessage); + QVERIFY2(f3, qPrintable(errorMessage)); + QCOMPARE(f3->name(), u"func"); + QCOMPARE(f3->arguments().size(), 0); // const call operator - const char sig4[] = "operator()(int)const"; - auto f4 = AddedFunction::createAddedFunction(QLatin1String(sig4), QLatin1String("int"), - &errorMessage); - QVERIFY2(!f4.isNull(), qPrintable(errorMessage)); - QCOMPARE(f4->name(), QLatin1String("operator()")); - QCOMPARE(f4->arguments().count(), 1); + auto f4 = AddedFunction::createAddedFunction("operator()(int)const"_L1, + "int"_L1, &errorMessage); + QVERIFY2(f4, qPrintable(errorMessage)); + QCOMPARE(f4->name(), u"operator()"); + QCOMPARE(f4->arguments().size(), 1); QVERIFY(f4->isConstant()); } @@ -118,14 +102,15 @@ struct A { </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); - TypeDatabase* typeDb = TypeDatabase::instance(); + QVERIFY(builder); + auto *typeDb = TypeDatabase::instance(); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - QCOMPARE(classA->functions().count(), 5); // default ctor, default copy ctor, func a() and the added functions + // default ctor, default copy ctor, func a() and the added functions + QCOMPARE(classA->functions().size(), 5); - auto addedFunc = classA->findFunction(QLatin1String("b")); + auto addedFunc = classA->findFunction("b"); QVERIFY(addedFunc); QCOMPARE(addedFunc->access(), Access::Protected); QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction); @@ -139,14 +124,14 @@ struct A { QVERIFY(!addedFunc->isStatic()); AbstractMetaType returnType = addedFunc->type(); - QCOMPARE(returnType.typeEntry(), typeDb->findPrimitiveType(QLatin1String("int"))); + QCOMPARE(returnType.typeEntry(), typeDb->findPrimitiveType(u"int"_s)); const AbstractMetaArgumentList &args = addedFunc->arguments(); - QCOMPARE(args.count(), 3); + QCOMPARE(args.size(), 3); QCOMPARE(args.at(0).type().typeEntry(), returnType.typeEntry()); - QCOMPARE(args.at(1).defaultValueExpression(), QLatin1String("4.6")); - QCOMPARE(args.at(2).type().typeEntry(), typeDb->findType(QLatin1String("B"))); + QCOMPARE(args.at(1).defaultValueExpression(), u"4.6"); + QCOMPARE(args.at(2).type().typeEntry(), typeDb->findType(u"B"_s)); - auto addedCallOperator = classA->findFunction(QLatin1String("operator()")); + auto addedCallOperator = classA->findFunction("operator()"); QVERIFY(addedCallOperator); } @@ -161,11 +146,11 @@ void TestAddFunction::testAddFunctionConstructor() </value-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - QCOMPARE(classA->functions().count(), 3); // default and added ctors + QCOMPARE(classA->functions().size(), 3); // default and added ctors const auto addedFunc = classA->functions().constLast(); QCOMPARE(addedFunc->access(), Access::Public); QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::ConstructorFunction); @@ -184,11 +169,12 @@ void TestAddFunction::testAddFunctionTagDefaultValues() </value-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - QCOMPARE(classA->functions().count(), 3); // default ctor, default copy ctor and the added function + // default ctor, default copy ctor and the added function + QCOMPARE(classA->functions().size(), 3); const auto addedFunc = classA->functions().constLast(); QCOMPARE(addedFunc->access(), Access::Public); QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction); @@ -209,9 +195,9 @@ void TestAddFunction::testAddFunctionCodeSnippets() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); const auto addedFunc = classA->functions().constLast(); QVERIFY(addedFunc->hasInjectedCode()); @@ -219,13 +205,12 @@ void TestAddFunction::testAddFunctionCodeSnippets() void TestAddFunction::testAddFunctionWithoutParenteses() { - const char sig1[] = "func"; + static constexpr auto sig1 = "func"_L1; QString errorMessage; - auto f1 = AddedFunction::createAddedFunction(QLatin1String(sig1), QLatin1String("void"), - &errorMessage); - QVERIFY2(!f1.isNull(), qPrintable(errorMessage)); - QCOMPARE(f1->name(), QLatin1String("func")); - QCOMPARE(f1->arguments().count(), 0); + auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage); + QVERIFY2(f1, qPrintable(errorMessage)); + QCOMPARE(f1->name(), u"func"); + QCOMPARE(f1->arguments().size(), 0); QCOMPARE(f1->isConstant(), false); const char cppCode[] = "struct A {};\n"; @@ -239,25 +224,26 @@ void TestAddFunction::testAddFunctionWithoutParenteses() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const auto addedFunc = classA->findFunction(QLatin1String("func")); - QVERIFY(!addedFunc.isNull()); + const auto addedFunc = classA->findFunction(sig1); + QVERIFY(addedFunc); QVERIFY(addedFunc->hasInjectedCode()); - QCOMPARE(addedFunc->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode).count(), 1); + const auto snips = addedFunc->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, + TypeSystem::TargetLangCode); + QCOMPARE(snips.size(), 1); } void TestAddFunction::testAddFunctionWithDefaultArgs() { - const char sig1[] = "func"; + static constexpr auto sig1 = "func"_L1; QString errorMessage; - auto f1 = AddedFunction::createAddedFunction(QLatin1String(sig1), QLatin1String("void"), - &errorMessage); - QVERIFY2(!f1.isNull(), qPrintable(errorMessage)); - QCOMPARE(f1->name(), QLatin1String("func")); - QCOMPARE(f1->arguments().count(), 0); + auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage); + QVERIFY2(f1, qPrintable(errorMessage)); + QCOMPARE(f1->name(), u"func"); + QCOMPARE(f1->arguments().size(), 0); QCOMPARE(f1->isConstant(), false); const char cppCode[] = "struct A { };\n"; @@ -274,14 +260,14 @@ void TestAddFunction::testAddFunctionWithDefaultArgs() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const auto addedFunc = classA->findFunction(QLatin1String("func")); - QVERIFY(!addedFunc.isNull()); + const auto addedFunc = classA->findFunction(sig1); + QVERIFY(addedFunc); const AbstractMetaArgument &arg = addedFunc->arguments().at(1); - QCOMPARE(arg.defaultValueExpression(), QLatin1String("2")); + QCOMPARE(arg.defaultValueExpression(), u"2"); } void TestAddFunction::testAddFunctionAtModuleLevel() @@ -297,34 +283,33 @@ void TestAddFunction::testAddFunctionAtModuleLevel() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - TypeDatabase* typeDb = TypeDatabase::instance(); + auto *typeDb = TypeDatabase::instance(); - AddedFunctionList addedFuncs = typeDb->findGlobalUserFunctions(QLatin1String("func")); + AddedFunctionList addedFuncs = typeDb->findGlobalUserFunctions(u"func"_s); QCOMPARE(addedFuncs.size(), 1); - const FunctionModificationList mods = addedFuncs.constFirst()->modifications; + auto &mods = addedFuncs.constFirst()->modifications(); QCOMPARE(mods.size(), 1); QVERIFY(mods.constFirst().isCodeInjection()); CodeSnip snip = mods.constFirst().snips().constFirst(); - QCOMPARE(snip.code().trimmed(), QLatin1String("custom_code();")); + QCOMPARE(snip.code().trimmed(), u"custom_code();"); } void TestAddFunction::testAddFunctionWithVarargs() { - const char sig1[] = "func(int,char,...)"; QString errorMessage; - auto f1 = AddedFunction::createAddedFunction(QLatin1String(sig1), QLatin1String("void"), + auto f1 = AddedFunction::createAddedFunction("func(int,char,...)"_L1, voidT, &errorMessage); - QVERIFY2(!f1.isNull(), qPrintable(errorMessage)); - QCOMPARE(f1->name(), QLatin1String("func")); - QCOMPARE(f1->arguments().count(), 3); + QVERIFY2(f1, qPrintable(errorMessage)); + QCOMPARE(f1->name(), u"func"); + QCOMPARE(f1->arguments().size(), 3); QVERIFY(!f1->isConstant()); const char cppCode[] = "struct A {};\n"; @@ -338,12 +323,12 @@ void TestAddFunction::testAddFunctionWithVarargs() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const auto addedFunc = classA->findFunction(QLatin1String("func")); - QVERIFY(!addedFunc.isNull()); + const auto addedFunc = classA->findFunction("func"); + QVERIFY(addedFunc); const AbstractMetaArgument &arg = addedFunc->arguments().constLast(); QVERIFY(arg.type().isVarargs()); QVERIFY(arg.type().typeEntry()->isVarargs()); @@ -362,12 +347,12 @@ void TestAddFunction::testAddStaticFunction() </value-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const auto addedFunc = classA->findFunction(QLatin1String("func")); - QVERIFY(!addedFunc.isNull()); + const auto addedFunc = classA->findFunction("func"); + QVERIFY(addedFunc); QVERIFY(addedFunc->isStatic()); } @@ -387,13 +372,13 @@ void TestAddFunction::testAddGlobalFunction() <value-type name='B'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); const auto globalFuncs = builder->globalFunctions(); - QCOMPARE(globalFuncs.count(), 2); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(builder->classes(), QLatin1String("B")); + QCOMPARE(globalFuncs.size(), 2); + const auto classB = AbstractMetaClass::findClass(builder->classes(), "B"); QVERIFY(classB); - QVERIFY(!classB->findFunction(QLatin1String("globalFunc"))); - QVERIFY(!classB->findFunction(QLatin1String("globalFunc2"))); + QVERIFY(!classB->findFunction("globalFunc")); + QVERIFY(!classB->findFunction("globalFunc2")); QVERIFY(!globalFuncs[0]->injectedCodeSnips().isEmpty()); QVERIFY(!globalFuncs[1]->injectedCodeSnips().isEmpty()); } @@ -412,10 +397,10 @@ void TestAddFunction::testAddFunctionWithApiVersion() </add-function>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, - true, QLatin1String("0.1"))); - QVERIFY(!builder.isNull()); + true, u"0.1"_s)); + QVERIFY(builder); const auto globalFuncs = builder->globalFunctions(); - QCOMPARE(globalFuncs.count(), 1); + QCOMPARE(globalFuncs.size(), 1); } void TestAddFunction::testModifyAddedFunction() @@ -436,16 +421,16 @@ void TestAddFunction::testModifyAddedFunction() </typesystem> )"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - AbstractMetaClass* foo = AbstractMetaClass::findClass(classes, QLatin1String("Foo")); - const auto method = foo->findFunction(QLatin1String("method")); - QVERIFY(!method.isNull()); + const auto foo = AbstractMetaClass::findClass(classes, "Foo"); + const auto method = foo->findFunction("method"); + QVERIFY(method); QCOMPARE(method->arguments().size(), 2); const AbstractMetaArgument &arg = method->arguments().at(1); - QCOMPARE(arg.defaultValueExpression(), QLatin1String("0")); - QCOMPARE(arg.name(), QLatin1String("varName")); - QCOMPARE(method->argumentName(2), QLatin1String("varName")); + QCOMPARE(arg.defaultValueExpression(), u"0"); + QCOMPARE(arg.name(), u"varName"); + QCOMPARE(method->argumentName(2), u"varName"); } void TestAddFunction::testAddFunctionOnTypedef() @@ -453,8 +438,6 @@ void TestAddFunction::testAddFunctionOnTypedef() const char cppCode[] = "template<class T> class Foo { }; typedef Foo<int> FooInt;\n"; const char xmlCode[] = "\ <typesystem package='Package'>\n\ - <custom-type name='PySequence'/>\n\ - <primitive-type name='int'/>\n\ <value-type name='FooInt'>\n\ <add-function signature='FooInt(PySequence)'>\n\ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\ @@ -465,17 +448,17 @@ void TestAddFunction::testAddFunctionOnTypedef() </value-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - AbstractMetaClass* foo = AbstractMetaClass::findClass(classes, QLatin1String("FooInt")); + const auto foo = AbstractMetaClass::findClass(classes, "FooInt"); QVERIFY(foo); QVERIFY(foo->hasNonPrivateConstructor()); - const auto &lst = foo->queryFunctions(FunctionQueryOption::Constructors); + const auto &lst = foo->queryFunctions(FunctionQueryOption::AnyConstructor); for (const auto &f : lst) QVERIFY(f->signature().startsWith(f->name())); QCOMPARE(lst.size(), 2); - const auto method = foo->findFunction(QLatin1String("method")); - QVERIFY(!method.isNull()); + const auto method = foo->findFunction("method"); + QVERIFY(method); } void TestAddFunction::testAddFunctionWithTemplateArg() @@ -489,11 +472,11 @@ void TestAddFunction::testAddFunctionWithTemplateArg() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); QCOMPARE(builder->globalFunctions().size(), 1); const auto func = builder->globalFunctions().constFirst(); const AbstractMetaArgument &arg = func->arguments().constFirst(); - QCOMPARE(arg.type().instantiations().count(), 1); + QCOMPARE(arg.type().instantiations().size(), 1); } // Test splitting of <add-function> parameter lists. @@ -512,18 +495,18 @@ void TestAddFunction::testAddFunctionTypeParser_data() QTest::newRow("1-arg") << QString::fromLatin1("int @a@=42") - << Arguments{{QLatin1String("int"), QLatin1String("a"), QLatin1String("42")}}; + << Arguments{{u"int"_s, u"a"_s, u"42"_s}}; QTest::newRow("2-args") << QString::fromLatin1("double @d@, int @a@=42") - << Arguments{{QLatin1String("double"), QLatin1String("d"), {}}, - {QLatin1String("int"), QLatin1String("a"), QLatin1String("42")}}; + << Arguments{{u"double"_s, u"d"_s, {}}, + {u"int"_s, u"a"_s, u"42"_s}}; QTest::newRow("template-var_args") << QString::fromLatin1("const QList<X,Y> &@list@ = QList<X,Y>{1,2}, int @b@=5, ...") - << Arguments{{QLatin1String("const QList<X,Y> &"), QLatin1String("list"), QLatin1String("QList<X,Y>{1,2}")}, - {QLatin1String("int"), QLatin1String("b"), QLatin1String("5")}, - {QLatin1String("..."), {}, {}}}; + << Arguments{{u"const QList<X,Y> &"_s, u"list"_s, u"QList<X,Y>{1,2}"_s}, + {u"int"_s, u"b"_s, u"5"_s}, + {u"..."_s, {}, {}}}; } void TestAddFunction::testAddFunctionTypeParser() diff --git a/sources/shiboken6/ApiExtractor/tests/testaddfunction.h b/sources/shiboken6/ApiExtractor/tests/testaddfunction.h index 195633030..77339609f 100644 --- a/sources/shiboken6/ApiExtractor/tests/testaddfunction.h +++ b/sources/shiboken6/ApiExtractor/tests/testaddfunction.h @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTADDFUNCTION_H #define TESTADDFUNCTION_H -#include <QObject> +#include <QtCore/QObject> class TestAddFunction : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp b/sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp index 22cf7ab40..6e1820bed 100644 --- a/sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp @@ -1,48 +1,30 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testarrayargument.h" -#include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetaenum.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> -#include <typesystem.h> +#include <abstractmetatype.h> +#include <primitivetypeentry.h> #include <parser/enumvalue.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestArrayArgument::testArrayArgumentWithSizeDefinedByInteger() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ enum SomeEnum { Value0, Value1, NValues };\n\ void method(double[3]);\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='double'/>\n\ <object-type name='A'>\n\ @@ -52,19 +34,19 @@ void TestArrayArgument::testArrayArgumentWithSizeDefinedByInteger() QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(builder->classes(), "A"); QVERIFY(classA); const AbstractMetaArgument &arg = classA->functions().constLast()->arguments().constFirst(); QVERIFY(arg.type().isArray()); QCOMPARE(arg.type().arrayElementCount(), 3); - QCOMPARE(arg.type().arrayElementType()->name(), QLatin1String("double")); + QCOMPARE(arg.type().arrayElementType()->name(), u"double"); } -static QString functionMinimalSignature(const AbstractMetaClass *c, const QString &name) +static QString functionMinimalSignature(const AbstractMetaClassCPtr &c, const QString &name) { const auto f = c->findFunction(name); - return f.isNull() ? QString() : f->minimalSignature(); + return f ? f->minimalSignature() : QString(); } void TestArrayArgument::testArraySignature() @@ -90,33 +72,33 @@ void TestArrayArgument::testArraySignature() QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); - QCOMPARE(functionMinimalSignature(classA, QLatin1String("mi1")), - QLatin1String("mi1(int[5])")); - QCOMPARE(functionMinimalSignature(classA, QLatin1String("mi1c")), - QLatin1String("mi1c(const int[5])")); - QCOMPARE(functionMinimalSignature(classA, QLatin1String("mi1cu")), - QLatin1String("mi1cu(const int[])")); - QCOMPARE(functionMinimalSignature(classA, QLatin1String("mc1cu")), - QLatin1String("mc1cu(const char*)")); - QCOMPARE(functionMinimalSignature(classA, QLatin1String("mc1cup")), - QLatin1String("mc1cup(const char*[])")); - QCOMPARE(functionMinimalSignature(classA, QLatin1String("muc2")), - QLatin1String("muc2(unsigned char*[2][3])")); - QCOMPARE(functionMinimalSignature(classA, QLatin1String("mc2c")), - QLatin1String("mc2c(const char*[5][6])")); - QCOMPARE(functionMinimalSignature(classA, QLatin1String("mc2cu")), - QLatin1String("mc2cu(const char[][2])")); + const auto classA = AbstractMetaClass::findClass(builder->classes(), "A"); + QCOMPARE(functionMinimalSignature(classA, u"mi1"_s), + u"mi1(int[5])"); + QCOMPARE(functionMinimalSignature(classA, u"mi1c"_s), + u"mi1c(const int[5])"); + QCOMPARE(functionMinimalSignature(classA, u"mi1cu"_s), + u"mi1cu(const int[])"); + QCOMPARE(functionMinimalSignature(classA, u"mc1cu"_s), + u"mc1cu(const char*)"); + QCOMPARE(functionMinimalSignature(classA, u"mc1cup"_s), + u"mc1cup(const char*[])"); + QCOMPARE(functionMinimalSignature(classA, u"muc2"_s), + u"muc2(unsigned char*[2][3])"); + QCOMPARE(functionMinimalSignature(classA, u"mc2c"_s), + u"mc2c(const char*[5][6])"); + QCOMPARE(functionMinimalSignature(classA, u"mc2cu"_s), + u"mc2cu(const char[][2])"); } void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValue() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ enum SomeEnum { Value0, Value1, NValues };\n\ void method(double[NValues]);\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='double'/>\n\ <object-type name='A'>\n\ @@ -126,28 +108,28 @@ void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValue() QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); - AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + AbstractMetaClassPtr classA = AbstractMetaClass::findClass(builder->classes(), "A"); QVERIFY(classA); - auto someEnum = classA->findEnum(QLatin1String("SomeEnum")); + auto someEnum = classA->findEnum(u"SomeEnum"_s); QVERIFY(someEnum.has_value()); - auto nvalues = classA->findEnumValue(QLatin1String("NValues")); + auto nvalues = classA->findEnumValue(u"NValues"_s); QVERIFY(nvalues.has_value()); const AbstractMetaArgument &arg = classA->functions().constLast()->arguments().constFirst(); QVERIFY(arg.type().isArray()); QCOMPARE(arg.type().arrayElementCount(), nvalues->value().value()); - QCOMPARE(arg.type().arrayElementType()->name(), QLatin1String("double")); + QCOMPARE(arg.type().arrayElementType()->name(), u"double"); }; void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnum() { - const char* cppCode ="\ + const char cppCode[] = "\ enum SomeEnum { Value0, Value1, NValues };\n\ struct A {\n\ void method(double[NValues]);\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='double'/>\n\ <enum-type name='SomeEnum'/>\n\ @@ -156,8 +138,8 @@ void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnu </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + QVERIFY(builder); + const auto classA = AbstractMetaClass::findClass(builder->classes(), "A"); QVERIFY(classA); AbstractMetaEnum someEnum = builder->globalEnums().constFirst(); @@ -167,7 +149,7 @@ void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnu const AbstractMetaArgument &arg = classA->functions().constLast()->arguments().constFirst(); QVERIFY(arg.type().isArray()); QCOMPARE(arg.type().arrayElementCount(), nvalues->value().value()); - QCOMPARE(arg.type().arrayElementType()->name(), QLatin1String("double")); + QCOMPARE(arg.type().arrayElementType()->name(), u"double"); }; QTEST_APPLESS_MAIN(TestArrayArgument) diff --git a/sources/shiboken6/ApiExtractor/tests/testarrayargument.h b/sources/shiboken6/ApiExtractor/tests/testarrayargument.h index 2e58ae6ee..75ef0f792 100644 --- a/sources/shiboken6/ApiExtractor/tests/testarrayargument.h +++ b/sources/shiboken6/ApiExtractor/tests/testarrayargument.h @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTARRAYARGUMENT_H #define TESTARRAYARGUMENT_H -#include <QObject> +#include <QtCore/QObject> class TestArrayArgument : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp index 1d7ba9666..4829e6c33 100644 --- a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp @@ -1,40 +1,22 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testcodeinjection.h" -#include <QFileInfo> -#include <QDir> -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetalang.h> +#include <codesnip.h> #include <modifications.h> #include <textstream.h> -#include <typesystem.h> +#include <complextypeentry.h> +#include <valuetypeentry.h> + +#include <qtcompat.h> + +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; void TestCodeInjections::testReadFile_data() { @@ -59,38 +41,40 @@ void TestCodeInjections::testReadFile() QFETCH(QString, snippet); QFETCH(QString, expected); - const char* cppCode ="struct A {};\n"; + const char cppCode[] = "struct A {};\n"; int argc = 0; char *argv[] = {nullptr}; QCoreApplication app(argc, argv); - QString attribute = QLatin1String("file='") + filePath + QLatin1Char('\''); + QString attribute = u"file='"_s + filePath + u'\''; if (!snippet.isEmpty()) - attribute += QLatin1String(" snippet='") + snippet + QLatin1Char('\''); + attribute += u" snippet='"_s + snippet + u'\''; - QString xmlCode = QLatin1String("\ + QString xmlCode = u"\ <typesystem package=\"Foo\">\n\ <value-type name='A'>\n\ - <conversion-rule class='target' ") + attribute + QLatin1String("/>\n\ - <inject-code class='target' ") + attribute + QLatin1String("/>\n\ + <conversion-rule class='target' "_s + attribute + u"/>\n\ + <inject-code class='target' "_s + attribute + u"/>\n\ <value-type name='B'/>\n\ </value-type>\n\ - </typesystem>\n"); + </typesystem>\n"_s; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().constData())); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - QCOMPARE(classA->typeEntry()->codeSnips().count(), 1); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + QCOMPARE(classA->typeEntry()->codeSnips().size(), 1); QString code = classA->typeEntry()->codeSnips().constFirst().code(); QVERIFY(code.indexOf(expected) != -1); - code = classA->typeEntry()->targetConversionRule(); + QVERIFY(classA->typeEntry()->isValue()); + auto vte = std::static_pointer_cast<const ValueTypeEntry>(classA->typeEntry()); + code = vte->targetConversionRule(); QVERIFY(code.indexOf(expected) != -1); } void TestCodeInjections::testInjectWithValidApiVersion() { - const char* cppCode ="struct A {};\n"; - const char* xmlCode = "\ + const char cppCode[] = "struct A {};\n"; + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <value-type name='A'>\n\ <inject-code class='target' since='1.0'>\n\ @@ -100,17 +84,17 @@ void TestCodeInjections::testInjectWithValidApiVersion() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, - true, QLatin1String("1.0"))); - QVERIFY(!builder.isNull()); + true, u"1.0"_s)); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - QCOMPARE(classA->typeEntry()->codeSnips().count(), 1); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + QCOMPARE(classA->typeEntry()->codeSnips().size(), 1); } void TestCodeInjections::testInjectWithInvalidApiVersion() { - const char* cppCode ="struct A {};\n"; - const char* xmlCode = "\ + const char cppCode[] = "struct A {};\n"; + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <value-type name='A'>\n\ <inject-code class='target' since='1.0'>\n\ @@ -120,31 +104,28 @@ void TestCodeInjections::testInjectWithInvalidApiVersion() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, - true, QLatin1String("0.1"))); - QVERIFY(!builder.isNull()); + true, u"0.1"_s)); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - QCOMPARE(classA->typeEntry()->codeSnips().count(), 0); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + QCOMPARE(classA->typeEntry()->codeSnips().size(), 0); } void TestCodeInjections::testTextStream() { StringStream str(TextStream::Language::Cpp); - str << "void foo(int a, int b) {\n"; - { - Indentation i(str); - str << "if (a == b)\n" << indent << "return a;\n" << outdent - << "#if Q_OS_WIN\nprint()\n#endif\nreturn a + b;\n"; - } - str << "}\n\n// A table\n|" + str << "void foo(int a, int b) {\n" << indent + << "if (a == b)\n" << indent << "return a;\n" << outdent + << "#if Q_OS_WIN\nprint()\n#endif\nreturn a + b;\n" << outdent + << "}\n\n// A table\n|" << AlignedField("bla", 40, QTextStream::AlignRight) << "|\n|" << AlignedField("bla", 40, QTextStream::AlignLeft) << "|\n|" << AlignedField(QString(), 40, QTextStream::AlignLeft) << "|\n"; str << "\n2nd table\n|" << AlignedField("bla", 3, QTextStream::AlignLeft) << '|' << AlignedField(QString{}, 0, QTextStream::AlignLeft) << "|\n"; -static const char expected[] = R"(void foo(int a, int b) { +constexpr auto expected = R"(void foo(int a, int b) { if (a == b) return a; #if Q_OS_WIN @@ -160,9 +141,24 @@ static const char expected[] = R"(void foo(int a, int b) { 2nd table |bla|| -)"; +)"_L1; + + QCOMPARE(str.toString(), expected); +} + +void TestCodeInjections::testTextStreamRst() +{ + // Test that sphinx error: "Inline strong start-string without end-string." + // is avoided, that is, characters following a formatting end are escaped. + + StringStream str; + str << rstBold << "QObject" << rstBoldOff << "'s properties..." + << rstItalic << "some italic" << rstItalicOff << " followed by space."; + + static const char16_t expected[] = + uR"(**QObject**\'s properties...*some italic* followed by space.)"; - QCOMPARE(str.toString(), QLatin1String(expected)); + QCOMPARE(str.toString(), expected); } QTEST_APPLESS_MAIN(TestCodeInjections) diff --git a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.h b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.h index 05b95a11e..a164ea36e 100644 --- a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.h +++ b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTCODEINJECTIONS_H #define TESTCODEINJECTIONS_H -#include <QObject> +#include <QtCore/QObject> class AbstractMetaBuilder; @@ -42,6 +17,7 @@ private slots: void testInjectWithValidApiVersion(); void testInjectWithInvalidApiVersion(); void testTextStream(); + void testTextStreamRst(); }; #endif diff --git a/sources/shiboken6/ApiExtractor/tests/testcontainer.cpp b/sources/shiboken6/ApiExtractor/tests/testcontainer.cpp index 3ee39e4ec..0bb72b3c1 100644 --- a/sources/shiboken6/ApiExtractor/tests/testcontainer.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testcontainer.cpp @@ -1,41 +1,17 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testcontainer.h" #include <QtTest/QTest> #include "testutil.h" #include <abstractmetalang.h> #include <abstractmetatype.h> -#include <typesystem.h> +#include <complextypeentry.h> +#include <containertypeentry.h> void TestContainer::testContainerType() { - const char* cppCode ="\ + const char cppCode[] = "\ namespace std {\n\ template<class T>\n\ class list {\n\ @@ -44,7 +20,7 @@ void TestContainer::testContainerType() }\n\ class A : public std::list<int> {\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <namespace-type name='std' generate='no' />\n\ <container-type name='std::list' type='list' />\n\ @@ -52,21 +28,21 @@ void TestContainer::testContainerType() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); + QCOMPARE(classes.size(), 2); //search for class A - AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); auto baseContainer = classA->typeEntry()->baseContainerType(); QVERIFY(baseContainer); - QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(baseContainer)->containerKind(), + QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(baseContainer.get())->containerKind(), ContainerTypeEntry::ListContainer); } void TestContainer::testListOfValueType() { - const char* cppCode ="\ + const char cppCode[] = "\ namespace std {\n\ template<class T>\n\ class list {\n\ @@ -76,7 +52,7 @@ void TestContainer::testListOfValueType() class ValueType {};\n\ class A : public std::list<ValueType> {\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <namespace-type name='std' generate='no'/>\n\ <container-type name='std::list' type='list'/>\n\ @@ -85,13 +61,13 @@ void TestContainer::testListOfValueType() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 3); + QCOMPARE(classes.size(), 3); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - QCOMPARE(classA->templateBaseClassInstantiations().count(), 1); + QCOMPARE(classA->templateBaseClassInstantiations().size(), 1); const AbstractMetaType templateInstanceType = classA->templateBaseClassInstantiations().constFirst(); diff --git a/sources/shiboken6/ApiExtractor/tests/testcontainer.h b/sources/shiboken6/ApiExtractor/tests/testcontainer.h index 44e6636aa..3fd23c3f0 100644 --- a/sources/shiboken6/ApiExtractor/tests/testcontainer.h +++ b/sources/shiboken6/ApiExtractor/tests/testcontainer.h @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTCONTAINER_H #define TESTCONTAINER_H -#include <QObject> +#include <QtCore/QObject> class TestContainer : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp index 32071f533..8f2b277af 100644 --- a/sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp @@ -1,38 +1,19 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testconversionoperator.h" -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetafunction.h> #include <abstractmetalang.h> +#include <abstractmetatype.h> #include <typesystem.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestConversionOperator::testConversionOperator() { const char cppCode[] = "\ @@ -52,18 +33,18 @@ void TestConversionOperator::testConversionOperator() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); - const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + const auto classB = AbstractMetaClass::findClass(classes, "B"); + const auto classC = AbstractMetaClass::findClass(classes, "C"); QVERIFY(classA); QVERIFY(classB); QVERIFY(classC); - QCOMPARE(classA->functions().count(), 2); - QCOMPARE(classB->functions().count(), 3); - QCOMPARE(classC->functions().count(), 3); - QCOMPARE(classA->externalConversionOperators().count(), 2); + QCOMPARE(classA->functions().size(), 2); + QCOMPARE(classB->functions().size(), 3); + QCOMPARE(classC->functions().size(), 3); + QCOMPARE(classA->externalConversionOperators().size(), 2); AbstractMetaFunctionCPtr convOp; for (const auto &func : classB->functions()) { @@ -72,7 +53,7 @@ void TestConversionOperator::testConversionOperator() break; } } - QVERIFY(!convOp.isNull()); + QVERIFY(convOp); QVERIFY(classA->externalConversionOperators().contains(convOp)); } @@ -90,11 +71,11 @@ void TestConversionOperator::testConversionOperatorOfDiscardedClass() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - QCOMPARE(classA->externalConversionOperators().count(), 0); + QCOMPARE(classA->externalConversionOperators().size(), 0); } void TestConversionOperator::testRemovedConversionOperator() @@ -114,16 +95,16 @@ void TestConversionOperator::testRemovedConversionOperator() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classA); QVERIFY(classB); - QCOMPARE(classA->functions().count(), 2); - QCOMPARE(classB->functions().count(), 3); - QCOMPARE(classA->externalConversionOperators().count(), 0); - QCOMPARE(classA->implicitConversions().count(), 0); + QCOMPARE(classA->functions().size(), 2); + QCOMPARE(classB->functions().size(), 3); + QCOMPARE(classA->externalConversionOperators().size(), 0); + QCOMPARE(classA->implicitConversions().size(), 0); } void TestConversionOperator::testConversionOperatorReturningReference() @@ -140,24 +121,24 @@ void TestConversionOperator::testConversionOperatorReturningReference() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classA); QVERIFY(classB); - QCOMPARE(classA->functions().count(), 2); - QCOMPARE(classB->functions().count(), 3); - QCOMPARE(classA->externalConversionOperators().count(), 1); + QCOMPARE(classA->functions().size(), 2); + QCOMPARE(classB->functions().size(), 3); + QCOMPARE(classA->externalConversionOperators().size(), 1); QCOMPARE(classA->externalConversionOperators().constFirst()->type().cppSignature(), - QLatin1String("A")); + u"A"); QCOMPARE(classA->externalConversionOperators().constFirst()->ownerClass()->name(), - QLatin1String("B")); - QCOMPARE(classA->implicitConversions().count(), 1); + u"B"); + QCOMPARE(classA->implicitConversions().size(), 1); QCOMPARE(classA->implicitConversions().constFirst()->type().cppSignature(), - QLatin1String("A")); + u"A"); QCOMPARE(classA->implicitConversions().constFirst()->ownerClass()->name(), - QLatin1String("B")); + u"B"); } void TestConversionOperator::testConversionOperatorReturningConstReference() @@ -174,24 +155,24 @@ void TestConversionOperator::testConversionOperatorReturningConstReference() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classA); QVERIFY(classB); - QCOMPARE(classA->functions().count(), 2); - QCOMPARE(classB->functions().count(), 3); - QCOMPARE(classA->externalConversionOperators().count(), 1); + QCOMPARE(classA->functions().size(), 2); + QCOMPARE(classB->functions().size(), 3); + QCOMPARE(classA->externalConversionOperators().size(), 1); QCOMPARE(classA->externalConversionOperators().constFirst()->type().cppSignature(), - QLatin1String("A")); + u"A"_s); QCOMPARE(classA->externalConversionOperators().constFirst()->ownerClass()->name(), - QLatin1String("B")); - QCOMPARE(classA->implicitConversions().count(), 1); + u"B"_s); + QCOMPARE(classA->implicitConversions().size(), 1); QCOMPARE(classA->implicitConversions().constFirst()->type().cppSignature(), - QLatin1String("A")); + u"A"_s); QCOMPARE(classA->implicitConversions().constFirst()->ownerClass()->name(), - QLatin1String("B")); + u"B"_s); } QTEST_APPLESS_MAIN(TestConversionOperator) diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionoperator.h b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.h index b571a57a0..68288d240 100644 --- a/sources/shiboken6/ApiExtractor/tests/testconversionoperator.h +++ b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.h @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTCONVERSIONOPERATOR_H #define TESTCONVERSIONOPERATOR_H -#include <QObject> +#include <QtCore/QObject> class TestConversionOperator : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp index 1f244bd83..b5efd92a6 100644 --- a/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp @@ -1,64 +1,49 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testconversionruletag.h" -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetalang.h> -#include <typesystem.h> -#include <QFile> -#include <QTemporaryFile> +#include <complextypeentry.h> +#include <customconversion.h> +#include <primitivetypeentry.h> +#include <valuetypeentry.h> + +#include <qtcompat.h> + +#include <QtCore/QFile> +#include <QtCore/QTemporaryFile> +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; void TestConversionRuleTag::testConversionRuleTagWithFile() { // FIXME PYSIDE7 remove // temp file used later - const char conversionData[] = "Hi! I'm a conversion rule."; + constexpr auto conversionData = "Hi! I'm a conversion rule."_L1; QTemporaryFile file; - file.open(); - QCOMPARE(file.write(conversionData), qint64(sizeof(conversionData)-1)); + QVERIFY(file.open()); + QCOMPARE(file.write(conversionData.constData()), conversionData.size()); file.close(); const char cppCode[] = "struct A {};\n"; - QString xmlCode = QLatin1String("\ + QString xmlCode = u"\ <typesystem package='Foo'>\n\ <value-type name='A'>\n\ - <conversion-rule class='target' file='") + file.fileName() + QLatin1String("'/>\n\ + <conversion-rule class='target' file='"_s + file.fileName() + u"'/>\n\ </value-type>\n\ - </typesystem>\n"); + </typesystem>\n"_s; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().data())); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const ComplexTypeEntry* typeEntry = classA->typeEntry(); - QVERIFY(typeEntry->hasTargetConversionRule()); - QCOMPARE(typeEntry->targetConversionRule(), QLatin1String(conversionData)); + const auto typeEntry = classA->typeEntry(); + QVERIFY(typeEntry->isValue()); + auto vte = std::static_pointer_cast<const ValueTypeEntry>(typeEntry); + QVERIFY(vte->hasTargetConversionRule()); + QCOMPARE(vte->targetConversionRule(), conversionData); } void TestConversionRuleTag::testConversionRuleTagReplace() @@ -71,7 +56,7 @@ void TestConversionRuleTag::testConversionRuleTagReplace() struct B {\n\ A createA();\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='int'/>\n\ <primitive-type name='char'/>\n\ @@ -100,48 +85,49 @@ void TestConversionRuleTag::testConversionRuleTagReplace() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); - TypeDatabase* typeDb = TypeDatabase::instance(); - PrimitiveTypeEntry* typeA = typeDb->findPrimitiveType(QLatin1String("A")); + QVERIFY(builder); + auto *typeDb = TypeDatabase::instance(); + auto typeA = typeDb->findPrimitiveType(u"A"_s); QVERIFY(typeA); - CustomConversion* conversion = typeA->customConversion(); - QVERIFY(conversion); + QVERIFY(typeA->hasCustomConversion()); + auto conversion = typeA->customConversion(); QCOMPARE(typeA, conversion->ownerType()); QCOMPARE(conversion->nativeToTargetConversion().simplified(), - QLatin1String("DoThis(); return ConvertFromCppToPython(%IN);")); + u"DoThis(); return ConvertFromCppToPython(%IN);"); QVERIFY(conversion->replaceOriginalTargetToNativeConversions()); QVERIFY(conversion->hasTargetToNativeConversions()); QCOMPARE(conversion->targetToNativeConversions().size(), 3); - CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().at(0); - QVERIFY(toNative); - QCOMPARE(toNative->sourceTypeName(), QLatin1String("TargetNone")); - QVERIFY(toNative->isCustomType()); - QCOMPARE(toNative->sourceType(), nullptr); - QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("%IN == Target_None")); - QCOMPARE(toNative->conversion().simplified(), - QLatin1String("DoThat(); DoSomething(); %OUT = A();")); + QVERIFY(!conversion->targetToNativeConversions().isEmpty()); + auto toNative = conversion->targetToNativeConversions().at(0); + QCOMPARE(toNative.sourceTypeName(), u"TargetNone"); + QVERIFY(toNative.isCustomType()); + QCOMPARE(toNative.sourceType(), nullptr); + QCOMPARE(toNative.sourceTypeCheck(), u"%IN == Target_None"); + QCOMPARE(toNative.conversion().simplified(), + u"DoThat(); DoSomething(); %OUT = A();"); + QVERIFY(conversion->targetToNativeConversions().size() > 1); toNative = conversion->targetToNativeConversions().at(1); - QVERIFY(toNative); - QCOMPARE(toNative->sourceTypeName(), QLatin1String("B")); - QVERIFY(!toNative->isCustomType()); - TypeEntry* typeB = typeDb->findType(QLatin1String("B")); + QCOMPARE(toNative.sourceTypeName(), u"B"); + QVERIFY(!toNative.isCustomType()); + auto typeB = typeDb->findType(u"B"_s); QVERIFY(typeB); - QCOMPARE(toNative->sourceType(), typeB); - QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("CheckIfInputObjectIsB(%IN)")); - QCOMPARE(toNative->conversion().trimmed(), QLatin1String("%OUT = %IN.createA();")); + QCOMPARE(toNative.sourceType(), typeB); + QCOMPARE(toNative.sourceTypeCheck(), u"CheckIfInputObjectIsB(%IN)"); + QCOMPARE(toNative.conversion().trimmed(), u"%OUT = %IN.createA();"); + QVERIFY(conversion->targetToNativeConversions().size() > 2); toNative = conversion->targetToNativeConversions().at(2); - QVERIFY(toNative); - QCOMPARE(toNative->sourceTypeName(), QLatin1String("String")); - QVERIFY(toNative->isCustomType()); - QCOMPARE(toNative->sourceType(), nullptr); - QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("String_Check(%IN)")); - QCOMPARE(toNative->conversion().trimmed(), QLatin1String("%OUT = new A(String_AsString(%IN), String_GetSize(%IN));")); + QCOMPARE(toNative.sourceTypeName(), u"String"); + QVERIFY(toNative.isCustomType()); + QCOMPARE(toNative.sourceType(), nullptr); + QCOMPARE(toNative.sourceTypeCheck(), u"String_Check(%IN)"); + QCOMPARE(toNative.conversion().trimmed(), + u"%OUT = new A(String_AsString(%IN), String_GetSize(%IN));"); } void TestConversionRuleTag::testConversionRuleTagAdd() @@ -151,7 +137,7 @@ void TestConversionRuleTag::testConversionRuleTagAdd() Date();\n\ Date(int, int, int);\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='int'/>\n\ <value-type name='Date'>\n\ @@ -167,12 +153,14 @@ if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("Date")); + QVERIFY(builder); + const auto classA = AbstractMetaClass::findClass(builder->classes(), "Date"); QVERIFY(classA); - CustomConversion* conversion = classA->typeEntry()->customConversion(); - QVERIFY(conversion); + QVERIFY(classA->typeEntry()->isValue()); + auto vte = std::static_pointer_cast<const ValueTypeEntry>(classA->typeEntry()); + QVERIFY(vte->hasCustomConversion()); + auto conversion = vte->customConversion(); QCOMPARE(conversion->nativeToTargetConversion(), QString()); @@ -180,21 +168,21 @@ if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n\ QVERIFY(conversion->hasTargetToNativeConversions()); QCOMPARE(conversion->targetToNativeConversions().size(), 1); - CustomConversion::TargetToNativeConversion *toNative = - conversion->targetToNativeConversions().constFirst(); - QVERIFY(toNative); - QCOMPARE(toNative->sourceTypeName(), QLatin1String("TargetDate")); - QVERIFY(toNative->isCustomType()); - QCOMPARE(toNative->sourceType(), nullptr); - QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("TargetDate_Check(%IN)")); - QCOMPARE(toNative->conversion().trimmed(), - QLatin1String("if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n%OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));")); + QVERIFY(!conversion->targetToNativeConversions().isEmpty()); + const auto &toNative = conversion->targetToNativeConversions().constFirst(); + QCOMPARE(toNative.sourceTypeName(), u"TargetDate"); + QVERIFY(toNative.isCustomType()); + QCOMPARE(toNative.sourceType(), nullptr); + QCOMPARE(toNative.sourceTypeCheck(), u"TargetDate_Check(%IN)"); + QCOMPARE(toNative.conversion().trimmed(), + uR"(if (!TargetDateTimeAPI) TargetDateTime_IMPORT; +%OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));)"); } void TestConversionRuleTag::testConversionRuleTagWithInsertTemplate() { const char cppCode[] = "struct A {};"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='int'/>\n\ <!-- single line -->\n\ @@ -228,25 +216,25 @@ void TestConversionRuleTag::testConversionRuleTagWithInsertTemplate() "// TEMPLATE - target_to_native - END"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); - TypeDatabase* typeDb = TypeDatabase::instance(); - PrimitiveTypeEntry* typeA = typeDb->findPrimitiveType(QLatin1String("A")); + QVERIFY(builder); + auto *typeDb = TypeDatabase::instance(); + auto typeA = typeDb->findPrimitiveType(u"A"_s); QVERIFY(typeA); - CustomConversion* conversion = typeA->customConversion(); - QVERIFY(conversion); + QVERIFY(typeA->hasCustomConversion()); + auto conversion = typeA->customConversion(); QCOMPARE(typeA, conversion->ownerType()); QCOMPARE(conversion->nativeToTargetConversion().trimmed(), - QLatin1String(nativeToTargetExpected)); + QLatin1StringView(nativeToTargetExpected)); QVERIFY(conversion->hasTargetToNativeConversions()); QCOMPARE(conversion->targetToNativeConversions().size(), 1); - CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().constFirst(); - QVERIFY(toNative); - QCOMPARE(toNative->conversion().trimmed(), - QLatin1String(targetToNativeExpected)); + QVERIFY(!conversion->targetToNativeConversions().isEmpty()); + const auto &toNative = conversion->targetToNativeConversions().constFirst(); + QCOMPARE(toNative.conversion().trimmed(), + QLatin1StringView(targetToNativeExpected)); } QTEST_APPLESS_MAIN(TestConversionRuleTag) diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionruletag.h b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.h index 894bd3d71..64d496cc3 100644 --- a/sources/shiboken6/ApiExtractor/tests/testconversionruletag.h +++ b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.h @@ -1,34 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTCONVERSIONRULE_H #define TESTCONVERSIONRULE_H -#include <QObject> + +#include <QtCore/QObject> class TestConversionRuleTag : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp b/sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp index 7718d3df6..c3a3ebef0 100644 --- a/sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testctorinformation.h" #include "abstractmetabuilder.h" @@ -35,41 +10,47 @@ void TestCtorInformation::testCtorIsPrivate() { - const char* cppCode = "class Control { public: Control() {} };\n\ + const char cppCode[] = "class Control { public: Control() {} };\n\ class Subject { private: Subject() {} };\n\ class CtorLess { };\n"; - const char* xmlCode = "<typesystem package='Foo'>\n\ + const char xmlCode[] = "<typesystem package='Foo'>\n\ <value-type name='Control'/>\n\ <object-type name='Subject'/>\n\ <value-type name='CtorLess'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 3); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasNonPrivateConstructor(), true); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasNonPrivateConstructor(), false); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("CtorLess"))->hasNonPrivateConstructor(), true); + QCOMPARE(classes.size(), 3); + auto klass = AbstractMetaClass::findClass(classes, "Control"); + QVERIFY(klass); + QVERIFY(klass->hasNonPrivateConstructor()); + klass = AbstractMetaClass::findClass(classes, "Subject"); + QVERIFY(klass); + QVERIFY(!klass->hasNonPrivateConstructor()); + klass = AbstractMetaClass::findClass(classes, "CtorLess"); + QVERIFY(klass); + QVERIFY(klass->hasNonPrivateConstructor()); } void TestCtorInformation::testHasNonPrivateCtor() { - const char* cppCode = "template<typename T>\n\ + const char cppCode[] = "template<typename T>\n\ struct Base { Base(double) {} };\n\ typedef Base<int> Derived;\n"; - const char* xmlCode = "<typesystem package='Foo'>\n\ + const char xmlCode[] = "<typesystem package='Foo'>\n\ <primitive-type name='int'/>\n\ <primitive-type name='double'/>\n\ <object-type name='Base' generate='no'/>\n\ <object-type name='Derived'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - const AbstractMetaClass *base = AbstractMetaClass::findClass(classes, QLatin1String("Base")); + QCOMPARE(classes.size(), 2); + const auto base = AbstractMetaClass::findClass(classes, "Base"); QCOMPARE(base->hasNonPrivateConstructor(), true); - const AbstractMetaClass *derived = AbstractMetaClass::findClass(classes, QLatin1String("Derived")); + const auto derived = AbstractMetaClass::findClass(classes, "Derived"); QCOMPARE(derived->hasNonPrivateConstructor(), true); } diff --git a/sources/shiboken6/ApiExtractor/tests/testctorinformation.h b/sources/shiboken6/ApiExtractor/tests/testctorinformation.h index ee655d450..58f1648e4 100644 --- a/sources/shiboken6/ApiExtractor/tests/testctorinformation.h +++ b/sources/shiboken6/ApiExtractor/tests/testctorinformation.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTCTORINFORMATION_H #define TESTCTORINFORMATION_H -#include <QObject> +#include <QtCore/QObject> class AbstractMetaBuilder; diff --git a/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp index 1b03f9353..16f50e69d 100644 --- a/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp @@ -1,40 +1,20 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testdroptypeentries.h" -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetaenum.h> #include <abstractmetalang.h> #include <typesystem.h> #include <conditionalstreamreader.h> -static const char* cppCode ="\ +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + +static const char cppCode[] = "\ struct ValueA {};\n\ struct ValueB {};\n\ struct ObjectA {};\n\ @@ -49,7 +29,7 @@ static const char* cppCode ="\ void funcA();\n\ void funcB();\n"; -static const char* xmlCode = "\ +static const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <value-type name='ValueA'/>\n\ <value-type name='ValueB'/>\n\ @@ -68,61 +48,61 @@ static const char* xmlCode = "\ void TestDropTypeEntries::testDropEntries() { - const QStringList droppedEntries{QLatin1String("Foo.ValueB"), - QLatin1String("ObjectB"), // Check whether module can be omitted - QLatin1String("Foo.NamespaceA.InnerClassA"), - QLatin1String("Foo.NamespaceB"), QLatin1String("Foo.EnumB"), - QLatin1String("Foo.funcB()"), - QLatin1String("Foo.NamespaceA.InnerNamespaceA")}; + const QStringList droppedEntries{u"Foo.ValueB"_s, + u"ObjectB"_s, // Check whether module can be omitted + u"Foo.NamespaceA.InnerClassA"_s, + u"Foo.NamespaceB"_s, u"Foo.EnumB"_s, + u"Foo.funcB()"_s, + u"Foo.NamespaceA.InnerNamespaceA"_s}; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, QString(), droppedEntries)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ValueA"))); - QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("ValueB"))); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ObjectA"))); - QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("ObjectB"))); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA"))); - QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA::InnerClassA"))); - QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("NamespaceB"))); + QVERIFY(AbstractMetaClass::findClass(classes, "ValueA")); + QVERIFY(!AbstractMetaClass::findClass(classes, "ValueB")); + QVERIFY(AbstractMetaClass::findClass(classes, "ObjectA")); + QVERIFY(!AbstractMetaClass::findClass(classes, "ObjectB")); + QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA")); + QVERIFY(!AbstractMetaClass::findClass(classes, "NamespaceA::InnerClassA")); + QVERIFY(!AbstractMetaClass::findClass(classes, "NamespaceB")); AbstractMetaEnumList globalEnums = builder->globalEnums(); - QCOMPARE(globalEnums.count(), 1); - QCOMPARE(globalEnums.constFirst().name(), QLatin1String("EnumA")); + QCOMPARE(globalEnums.size(), 1); + QCOMPARE(globalEnums.constFirst().name(), u"EnumA"); - TypeDatabase* td = TypeDatabase::instance(); - QVERIFY(td->findType(QLatin1String("funcA"))); - QVERIFY(!td->findType(QLatin1String("funcB"))); + auto *td = TypeDatabase::instance(); + QVERIFY(td->findType(u"funcA"_s)); + QVERIFY(!td->findType(u"funcB"_s)); } void TestDropTypeEntries::testDontDropEntries() { QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ValueA"))); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ValueB"))); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ObjectA"))); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ObjectB"))); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA"))); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA::InnerClassA"))); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceB"))); + QVERIFY(AbstractMetaClass::findClass(classes, "ValueA")); + QVERIFY(AbstractMetaClass::findClass(classes, "ValueB")); + QVERIFY(AbstractMetaClass::findClass(classes, "ObjectA")); + QVERIFY(AbstractMetaClass::findClass(classes, "ObjectB")); + QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA")); + QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA::InnerClassA")); + QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceB")); QCOMPARE(builder->globalEnums().size(), 2); - TypeDatabase* td = TypeDatabase::instance(); - QVERIFY(td->findType(QLatin1String("funcA"))); - QVERIFY(td->findType(QLatin1String("funcB"))); + auto *td = TypeDatabase::instance(); + QVERIFY(td->findType(u"funcA"_s)); + QVERIFY(td->findType(u"funcB"_s)); } -static const char* cppCode2 ="\ +static const char cppCode2[] = "\ struct ValueA {\n\ void func();\n\ };\n"; -static const char* xmlCode2 = R"( +static const char xmlCode2[] = R"( <typesystem package='Foo'> <value-type name='ValueA'> <modify-function signature='func()' remove='all'/> @@ -132,24 +112,24 @@ static const char* xmlCode2 = R"( void TestDropTypeEntries::testDropEntryWithChildTags() { - QStringList droppedEntries(QLatin1String("Foo.ValueA")); + QStringList droppedEntries(u"Foo.ValueA"_s); QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false, QString(), droppedEntries)); - QVERIFY(!builder.isNull()); - QVERIFY(!AbstractMetaClass::findClass(builder->classes(), QLatin1String("ValueA"))); + QVERIFY(builder); + QVERIFY(!AbstractMetaClass::findClass(builder->classes(), "ValueA")); } void TestDropTypeEntries::testDontDropEntryWithChildTags() { QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false)); - QVERIFY(!builder.isNull()); - QVERIFY(AbstractMetaClass::findClass(builder->classes(), QLatin1String("ValueA"))); + QVERIFY(builder); + QVERIFY(AbstractMetaClass::findClass(builder->classes(), "ValueA")); } void TestDropTypeEntries::testConditionalParsing_data() { - const QString xml = QStringLiteral(R"(<?xml version="1.0" encoding="UTF-8"?> + const QString xml = R"(<?xml version="1.0" encoding="UTF-8"?> <root> <tag1>text</tag1> <?if keyword1?> @@ -162,31 +142,35 @@ void TestDropTypeEntries::testConditionalParsing_data() <?endif?> <?endif?> <tag5>text</tag5> -</root>)"); - - const QString root = QStringLiteral("root"); - const QString tag1 = QStringLiteral("tag1"); - const QString tag2 = QStringLiteral("tag2"); - const QString tag3 = QStringLiteral("tag3"); - const QString tag4 = QStringLiteral("tag4"); - const QString tag5 = QStringLiteral("tag5"); - const QString keyword1 = QStringLiteral("keyword1"); - const QString keyword2 = QStringLiteral("keyword2"); + <?if !keyword99?> <!-- Exclusion only --> + <tag6>text</tag6> + <?endif?> +</root>)"_L1; + + constexpr auto root = "root"_L1; + constexpr auto tag1 = "tag1"_L1; + constexpr auto tag2 = "tag2"_L1; + constexpr auto tag3 = "tag3"_L1; + constexpr auto tag4 = "tag4"_L1; + constexpr auto tag5 = "tag5"_L1; + constexpr auto tag6 = "tag6"_L1; + constexpr auto keyword1 = "keyword1"_L1; + constexpr auto keyword2 = "keyword2"_L1; QTest::addColumn<QString>("xml"); QTest::addColumn<QStringList>("keywords"); QTest::addColumn<QStringList>("expectedTags"); QTest::newRow("no-keywords") - << xml << QStringList{} << QStringList{root, tag1, tag5}; + << xml << QStringList{} << QStringList{root, tag1, tag5, tag6}; QTest::newRow("skip-nested-condition") << xml << QStringList{keyword1} - << QStringList{root, tag1, tag2, tag4, tag5}; + << QStringList{root, tag1, tag2, tag4, tag5, tag6}; QTest::newRow("both/check-not") << xml << QStringList{keyword1, keyword2} - << QStringList{root, tag1, tag2, tag3, tag5}; + << QStringList{root, tag1, tag2, tag3, tag5, tag6}; } // Parse XML and return a list of tags encountered @@ -218,4 +202,27 @@ void TestDropTypeEntries::testConditionalParsing() QCOMPARE(actualTags, expectedTags); } +void TestDropTypeEntries::testEntityParsing() +{ + const QString xml = R"(<?xml version="1.0" encoding="UTF-8"?> +<root> + <?entity testentity word1 word2?> + <text>bla &testentity;</text> +</root>)"_L1; + + QString actual; + ConditionalStreamReader reader(xml); + while (!reader.atEnd()) { + auto t = reader.readNext(); + switch (t) { + case QXmlStreamReader::Characters: + actual.append(reader.text()); + default: + break; + } + } + QVERIFY2(!reader.hasError(), qPrintable(reader.errorString())); + QCOMPARE(actual.trimmed(), u"bla word1 word2"); +} + QTEST_APPLESS_MAIN(TestDropTypeEntries) diff --git a/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h index 7746234ba..98717bd21 100644 --- a/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h +++ b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTDROPTYPEENTRIES_H #define TESTDROPTYPEENTRIES_H -#include <QObject> +#include <QtCore/QObject> class TestDropTypeEntries : public QObject { @@ -41,6 +16,7 @@ class TestDropTypeEntries : public QObject void testDontDropEntryWithChildTags(); void testConditionalParsing_data(); void testConditionalParsing(); + void testEntityParsing(); }; #endif diff --git a/sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp index 0eee8af24..2152d39de 100644 --- a/sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testdtorinformation.h" #include "abstractmetabuilder.h" @@ -35,83 +10,147 @@ void TestDtorInformation::testDtorIsPrivate() { - const char* cppCode ="class Control { public: ~Control() {} }; class Subject { private: ~Subject() {} };"; - const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"Control\"/><value-type name=\"Subject\"/></typesystem>"; + const char cppCode[] = R"(class Control { +public: + ~Control() {} +}; +class Subject { +private: + ~Subject() {} +}; +)"; + const char xmlCode[] = R"(<typesystem package="Foo"> + <value-type name="Control"/> + <value-type name="Subject"/> +</typesystem>)"; + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasPrivateDestructor(), false); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasPrivateDestructor(), true); + QCOMPARE(classes.size(), 2); + auto klass = AbstractMetaClass::findClass(classes, "Control"); + QVERIFY(klass); + QVERIFY(!klass->hasPrivateDestructor()); + klass = AbstractMetaClass::findClass(classes, "Subject"); + QVERIFY(klass); + QVERIFY(klass->hasPrivateDestructor()); } void TestDtorInformation::testDtorIsProtected() { - const char* cppCode ="class Control { public: ~Control() {} }; class Subject { protected: ~Subject() {} };"; - const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"Control\"/><value-type name=\"Subject\"/></typesystem>"; + const char cppCode[] = R"(class Control { +public: + ~Control() {} +}; +class Subject { +protected: + ~Subject() {} +}; +)"; + const char xmlCode[] = R"(<typesystem package="Foo"> + <value-type name="Control"/> + <value-type name="Subject"/> +</typesystem>)"; + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasProtectedDestructor(), false); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasProtectedDestructor(), true); + QCOMPARE(classes.size(), 2); + auto klass = AbstractMetaClass::findClass(classes, "Control"); + QVERIFY(klass); + QVERIFY(!klass->hasProtectedDestructor()); + klass = AbstractMetaClass::findClass(classes, "Subject"); + QVERIFY(klass); + QVERIFY(klass->hasProtectedDestructor()); } void TestDtorInformation::testDtorIsVirtual() { - const char* cppCode ="class Control { public: ~Control() {} }; class Subject { protected: virtual ~Subject() {} };"; - const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"Control\"/><value-type name=\"Subject\"/></typesystem>"; + const char cppCode[] = R"(class Control { +public: + ~Control() {} +}; +class Subject { +protected: + virtual ~Subject() {} +}; +)"; + const char xmlCode[] = R"(<typesystem package="Foo"> + <value-type name="Control"/> + <value-type name="Subject"/> +</typesystem>)"; + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasVirtualDestructor(), false); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasVirtualDestructor(), true); + QCOMPARE(classes.size(), 2); + auto klass = AbstractMetaClass::findClass(classes, "Control"); + QVERIFY(klass); + QVERIFY(!klass->hasVirtualDestructor()); + klass = AbstractMetaClass::findClass(classes, "Subject"); + QVERIFY(klass); + QVERIFY(klass->hasVirtualDestructor()); } void TestDtorInformation::testDtorFromBaseIsVirtual() { - const char* cppCode = R"CPP(class ControlBase { public: ~ControlBase() {} }; + const char cppCode[] = R"CPP(class ControlBase { public: ~ControlBase() {} }; class Control : public ControlBase {}; class SubjectBase { public: virtual ~SubjectBase() {} }; class Subject : public SubjectBase {}; )CPP"; - const char* xmlCode = R"XML(<typesystem package="Foo"><value-type name="ControlBase"/> + const char xmlCode[] = R"XML(<typesystem package="Foo"><value-type name="ControlBase"/> <value-type name="Control"/>" <value-type name="SubjectBase"/>" <value-type name="Subject"/> </typesystem> )XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 4); + QCOMPARE(classes.size(), 4); - auto klass = AbstractMetaClass::findClass(classes, QLatin1String("ControlBase")); + auto klass = AbstractMetaClass::findClass(classes, "ControlBase"); QVERIFY(klass); QVERIFY(!klass->hasVirtualDestructor()); - klass = AbstractMetaClass::findClass(classes, QLatin1String("Control")); + klass = AbstractMetaClass::findClass(classes, "Control"); QVERIFY(klass); QVERIFY(!klass->hasVirtualDestructor()); - klass = AbstractMetaClass::findClass(classes, QLatin1String("SubjectBase")); + klass = AbstractMetaClass::findClass(classes, "SubjectBase"); QVERIFY(klass); QVERIFY(klass->hasVirtualDestructor()); - klass = AbstractMetaClass::findClass(classes, QLatin1String("Subject")); + klass = AbstractMetaClass::findClass(classes, "Subject"); QVERIFY(klass); QVERIFY(klass->hasVirtualDestructor()); } void TestDtorInformation::testClassWithVirtualDtorIsPolymorphic() { - const char* cppCode ="class Control { public: virtual ~Control() {} }; class Subject { protected: virtual ~Subject() {} };"; - const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"Control\"/><value-type name=\"Subject\"/></typesystem>"; + const char cppCode[] = R"(class Control { +public: + virtual ~Control() {} +}; +class Subject { +protected: + virtual ~Subject() {} +}; +)"; + const char xmlCode[] = R"(<typesystem package="Foo"> + <value-type name="Control"/> + <value-type name="Subject"/> +</typesystem>)"; + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->isPolymorphic(), true); - QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->isPolymorphic(), true); + QCOMPARE(classes.size(), 2); + auto klass = AbstractMetaClass::findClass(classes, "Control"); + QVERIFY(klass); + QVERIFY(klass->isPolymorphic()); + klass = AbstractMetaClass::findClass(classes, "Subject"); + QVERIFY(klass); + QVERIFY(klass->isPolymorphic()); } QTEST_APPLESS_MAIN(TestDtorInformation) diff --git a/sources/shiboken6/ApiExtractor/tests/testdtorinformation.h b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.h index 0a57dd8d1..0f8cb59b3 100644 --- a/sources/shiboken6/ApiExtractor/tests/testdtorinformation.h +++ b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTDTORINFORMATION_H #define TESTDTORINFORMATION_H -#include <QObject> +#include <QtCore/QObject> class AbstractMetaBuilder; diff --git a/sources/shiboken6/ApiExtractor/tests/testenum.cpp b/sources/shiboken6/ApiExtractor/tests/testenum.cpp index df744e994..c7c2b8b3b 100644 --- a/sources/shiboken6/ApiExtractor/tests/testenum.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testenum.cpp @@ -1,43 +1,26 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testenum.h" -#include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetaenum.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> -#include <typesystem.h> +#include <abstractmetabuilder_p.h> +#include <enumtypeentry.h> +#include <flagstypeentry.h> #include <parser/enumvalue.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestEnum::testEnumCppSignature() { - const char* cppCode ="\ + const char cppCode[] = "\ enum GlobalEnum { A, B };\n\ \n\ struct A {\n\ @@ -45,7 +28,7 @@ void TestEnum::testEnumCppSignature() void method(ClassEnum);\n\ };\n\ void func(A::ClassEnum);\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <enum-type name='GlobalEnum'/>\n\ <value-type name='A'>\n\ @@ -55,52 +38,52 @@ void TestEnum::testEnumCppSignature() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 1); + QCOMPARE(classes.size(), 1); AbstractMetaEnumList globalEnums = builder->globalEnums(); - QCOMPARE(globalEnums.count(), 1); - QCOMPARE(globalEnums.constFirst().name(), QLatin1String("GlobalEnum")); + QCOMPARE(globalEnums.size(), 1); + QCOMPARE(globalEnums.constFirst().name(), u"GlobalEnum"); // enum as parameter of a function const auto functions = builder->globalFunctions(); - QCOMPARE(functions.count(), 1); - QCOMPARE(functions.constFirst()->arguments().count(), 1); + QCOMPARE(functions.size(), 1); + QCOMPARE(functions.constFirst()->arguments().size(), 1); QCOMPARE(functions.constFirst()->arguments().constFirst().type().cppSignature(), - QLatin1String("A::ClassEnum")); + u"A::ClassEnum"); // enum as parameter of a method - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - QCOMPARE(classA->enums().count(), 1); - const auto funcs = classA->queryFunctionsByName(QLatin1String("method")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + QCOMPARE(classA->enums().size(), 1); + const auto funcs = classA->queryFunctionsByName(u"method"_s); QVERIFY(!funcs.isEmpty()); const auto method = funcs.constFirst(); AbstractMetaArgument arg = method->arguments().constFirst(); - QCOMPARE(arg.type().name(), QLatin1String("ClassEnum")); - QCOMPARE(arg.type().cppSignature(), QLatin1String("A::ClassEnum")); - QCOMPARE(functions.constFirst()->arguments().count(), 1); + QCOMPARE(arg.type().name(), u"ClassEnum"); + QCOMPARE(arg.type().cppSignature(), u"A::ClassEnum"); + QCOMPARE(functions.constFirst()->arguments().size(), 1); arg = functions.constFirst()->arguments().constFirst(); - QCOMPARE(arg.type().name(), QLatin1String("ClassEnum")); - QCOMPARE(arg.type().cppSignature(), QLatin1String("A::ClassEnum")); + QCOMPARE(arg.type().name(), u"ClassEnum"); + QCOMPARE(arg.type().cppSignature(), u"A::ClassEnum"); AbstractMetaEnumList classEnums = classA->enums(); QVERIFY(!classEnums.isEmpty()); - QCOMPARE(classEnums.constFirst().name(), QLatin1String("ClassEnum")); - auto e = AbstractMetaClass::findEnumValue(classes, QLatin1String("CA")); + QCOMPARE(classEnums.constFirst().name(), u"ClassEnum"); + auto e = AbstractMetaClass::findEnumValue(classes, u"CA"_s); QVERIFY(e.has_value()); - e = AbstractMetaClass::findEnumValue(classes, QLatin1String("ClassEnum::CA")); + e = AbstractMetaClass::findEnumValue(classes, u"ClassEnum::CA"_s); QVERIFY(e.has_value()); } void TestEnum::testEnumWithApiVersion() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ enum ClassEnum { EnumA, EnumB };\n\ enum ClassEnum2 { EnumC, EnumD };\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <value-type name='A'>\n\ <enum-type name='ClassEnum' since='0.1'/>\n\ @@ -109,22 +92,22 @@ void TestEnum::testEnumWithApiVersion() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, - true, QLatin1String("0.1"))); - QVERIFY(!builder.isNull()); + true, u"0.1"_s)); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 1); - QCOMPARE(classes[0]->enums().count(), 1); + QCOMPARE(classes.size(), 1); + QCOMPARE(classes[0]->enums().size(), 1); } void TestEnum::testAnonymousEnum() { - const char* cppCode ="\ + const char cppCode[] = "\ enum { Global0, Global1 };\n\ struct A {\n\ enum { A0, A1 };\n\ enum { isThis = true, isThat = false };\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <!-- Uses the first value of the enum to identify it. -->\n\ <enum-type identified-by-value='Global0'/>\n\ @@ -136,101 +119,101 @@ void TestEnum::testAnonymousEnum() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaEnumList globalEnums = builder->globalEnums(); - QCOMPARE(globalEnums.count(), 1); + QCOMPARE(globalEnums.size(), 1); QCOMPARE(globalEnums.constFirst().typeEntry()->qualifiedCppName(), - QLatin1String("Global0")); + u"Global0"); QVERIFY(globalEnums.constFirst().isAnonymous()); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 1); - QCOMPARE(classes[0]->enums().count(), 2); + QCOMPARE(classes.size(), 1); + QCOMPARE(classes[0]->enums().size(), 2); - auto anonEnumA1 = classes[0]->findEnum(QLatin1String("A1")); + auto anonEnumA1 = classes[0]->findEnum(u"A1"_s); QVERIFY(anonEnumA1.has_value()); QVERIFY(anonEnumA1->isAnonymous()); - QCOMPARE(anonEnumA1->typeEntry()->qualifiedCppName(), QLatin1String("A::A1")); + QCOMPARE(anonEnumA1->typeEntry()->qualifiedCppName(), u"A::A1"); AbstractMetaEnumValue enumValueA0 = anonEnumA1->values().constFirst(); - QCOMPARE(enumValueA0.name(), QLatin1String("A0")); + QCOMPARE(enumValueA0.name(), u"A0"); QCOMPARE(enumValueA0.value().value(), 0); QCOMPARE(enumValueA0.stringValue(), QString()); AbstractMetaEnumValue enumValueA1 = anonEnumA1->values().constLast(); - QCOMPARE(enumValueA1.name(), QLatin1String("A1")); + QCOMPARE(enumValueA1.name(), u"A1"); QCOMPARE(enumValueA1.value().value(), 1); QCOMPARE(enumValueA1.stringValue(), QString()); - auto anonEnumIsThis = classes[0]->findEnum(QLatin1String("isThis")); + auto anonEnumIsThis = classes[0]->findEnum(u"isThis"_s); QVERIFY(anonEnumIsThis.has_value()); QVERIFY(anonEnumIsThis->isAnonymous()); - QCOMPARE(anonEnumIsThis->typeEntry()->qualifiedCppName(), QLatin1String("A::isThis")); + QCOMPARE(anonEnumIsThis->typeEntry()->qualifiedCppName(), u"A::isThis"); AbstractMetaEnumValue enumValueIsThis = anonEnumIsThis->values().constFirst(); - QCOMPARE(enumValueIsThis.name(), QLatin1String("isThis")); + QCOMPARE(enumValueIsThis.name(), u"isThis"); QCOMPARE(enumValueIsThis.value().value(), static_cast<int>(true)); - QCOMPARE(enumValueIsThis.stringValue(), QLatin1String("true")); + QCOMPARE(enumValueIsThis.stringValue(), u"true"); AbstractMetaEnumValue enumValueIsThat = anonEnumIsThis->values().constLast(); - QCOMPARE(enumValueIsThat.name(), QLatin1String("isThat")); + QCOMPARE(enumValueIsThat.name(), u"isThat"); QCOMPARE(enumValueIsThat.value().value(), static_cast<int>(false)); - QCOMPARE(enumValueIsThat.stringValue(), QLatin1String("false")); + QCOMPARE(enumValueIsThat.stringValue(), u"false"); } void TestEnum::testGlobalEnums() { - const char* cppCode ="\ + const char cppCode[] = "\ enum EnumA { A0, A1 };\n\ enum EnumB { B0 = 2, B1 = 0x4 };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <enum-type name='EnumA'/>\n\ <enum-type name='EnumB'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaEnumList globalEnums = builder->globalEnums(); - QCOMPARE(globalEnums.count(), 2); + QCOMPARE(globalEnums.size(), 2); AbstractMetaEnum enumA = globalEnums.constFirst(); - QCOMPARE(enumA.typeEntry()->qualifiedCppName(), QLatin1String("EnumA")); + QCOMPARE(enumA.typeEntry()->qualifiedCppName(), u"EnumA"); AbstractMetaEnumValue enumValueA0 = enumA.values().constFirst(); - QCOMPARE(enumValueA0.name(), QLatin1String("A0")); + QCOMPARE(enumValueA0.name(), u"A0"); QCOMPARE(enumValueA0.value().value(), 0); QCOMPARE(enumValueA0.stringValue(), QString()); AbstractMetaEnumValue enumValueA1 = enumA.values().constLast(); - QCOMPARE(enumValueA1.name(), QLatin1String("A1")); + QCOMPARE(enumValueA1.name(), u"A1"); QCOMPARE(enumValueA1.value().value(), 1); QCOMPARE(enumValueA1.stringValue(), QString()); AbstractMetaEnum enumB = globalEnums.constLast(); - QCOMPARE(enumB.typeEntry()->qualifiedCppName(), QLatin1String("EnumB")); + QCOMPARE(enumB.typeEntry()->qualifiedCppName(), u"EnumB"); AbstractMetaEnumValue enumValueB0 = enumB.values().constFirst(); - QCOMPARE(enumValueB0.name(), QLatin1String("B0")); + QCOMPARE(enumValueB0.name(), u"B0"); QCOMPARE(enumValueB0.value().value(), 2); - QCOMPARE(enumValueB0.stringValue(), QLatin1String("2")); + QCOMPARE(enumValueB0.stringValue(), u"2"); AbstractMetaEnumValue enumValueB1 = enumB.values().constLast(); - QCOMPARE(enumValueB1.name(), QLatin1String("B1")); + QCOMPARE(enumValueB1.name(), u"B1"); QCOMPARE(enumValueB1.value().value(), 4); - QCOMPARE(enumValueB1.stringValue(), QLatin1String("0x4")); + QCOMPARE(enumValueB1.stringValue(), u"0x4"); } void TestEnum::testEnumValueFromNeighbourEnum() { - const char* cppCode ="\ + const char cppCode[] = "\ namespace A {\n\ enum EnumA { ValueA0, ValueA1 };\n\ enum EnumB { ValueB0 = A::ValueA1, ValueB1 = ValueA0 };\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <namespace-type name='A'>\n\ <enum-type name='EnumA'/>\n\ @@ -239,44 +222,44 @@ void TestEnum::testEnumValueFromNeighbourEnum() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 1); - QCOMPARE(classes[0]->enums().count(), 2); + QCOMPARE(classes.size(), 1); + QCOMPARE(classes[0]->enums().size(), 2); - auto enumA = classes[0]->findEnum(QLatin1String("EnumA")); + auto enumA = classes[0]->findEnum(u"EnumA"_s); QVERIFY(enumA.has_value()); - QCOMPARE(enumA->typeEntry()->qualifiedCppName(), QLatin1String("A::EnumA")); + QCOMPARE(enumA->typeEntry()->qualifiedCppName(), u"A::EnumA"); AbstractMetaEnumValue enumValueA0 = enumA->values().constFirst(); - QCOMPARE(enumValueA0.name(), QLatin1String("ValueA0")); + QCOMPARE(enumValueA0.name(), u"ValueA0"); QCOMPARE(enumValueA0.value().value(), 0); QCOMPARE(enumValueA0.stringValue(), QString()); AbstractMetaEnumValue enumValueA1 = enumA->values().constLast(); - QCOMPARE(enumValueA1.name(), QLatin1String("ValueA1")); + QCOMPARE(enumValueA1.name(), u"ValueA1"); QCOMPARE(enumValueA1.value().value(), 1); QCOMPARE(enumValueA1.stringValue(), QString()); - auto enumB = classes[0]->findEnum(QLatin1String("EnumB")); + auto enumB = classes[0]->findEnum(u"EnumB"_s); QVERIFY(enumB.has_value()); - QCOMPARE(enumB->typeEntry()->qualifiedCppName(), QLatin1String("A::EnumB")); + QCOMPARE(enumB->typeEntry()->qualifiedCppName(), u"A::EnumB"); AbstractMetaEnumValue enumValueB0 = enumB->values().constFirst(); - QCOMPARE(enumValueB0.name(), QLatin1String("ValueB0")); + QCOMPARE(enumValueB0.name(), u"ValueB0"); QCOMPARE(enumValueB0.value().value(), 1); - QCOMPARE(enumValueB0.stringValue(), QLatin1String("A::ValueA1")); + QCOMPARE(enumValueB0.stringValue(), u"A::ValueA1"); AbstractMetaEnumValue enumValueB1 = enumB->values().constLast(); - QCOMPARE(enumValueB1.name(), QLatin1String("ValueB1")); + QCOMPARE(enumValueB1.name(), u"ValueB1"); QCOMPARE(enumValueB1.value().value(), 0); - QCOMPARE(enumValueB1.stringValue(), QLatin1String("ValueA0")); + QCOMPARE(enumValueB1.stringValue(), u"ValueA0"); } void TestEnum::testEnumValueFromExpression() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ enum EnumA : unsigned {\n\ ValueA0 = 3u,\n\ @@ -292,7 +275,7 @@ void TestEnum::testEnumValueFromExpression() ValueB0 = ~3,\n\ };\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <value-type name='A'>\n\ <enum-type name='EnumA'/>\n\ @@ -301,77 +284,77 @@ void TestEnum::testEnumValueFromExpression() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); - AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + AbstractMetaClassPtr classA = AbstractMetaClass::findClass(builder->classes(), "A"); QVERIFY(classA); - auto enumA = classA->findEnum(QLatin1String("EnumA")); + auto enumA = classA->findEnum(u"EnumA"_s); QVERIFY(enumA.has_value()); QVERIFY(!enumA->isSigned()); - QCOMPARE(enumA->typeEntry()->qualifiedCppName(), QLatin1String("A::EnumA")); + QCOMPARE(enumA->typeEntry()->qualifiedCppName(), u"A::EnumA"); AbstractMetaEnumValue valueA0 = enumA->values().at(0); - QCOMPARE(valueA0.name(), QLatin1String("ValueA0")); - QCOMPARE(valueA0.stringValue(), QLatin1String("3u")); + QCOMPARE(valueA0.name(), u"ValueA0"); + QCOMPARE(valueA0.stringValue(), u"3u"); QCOMPARE(valueA0.value().unsignedValue(), 3u); AbstractMetaEnumValue valueA1 = enumA->values().at(1); - QCOMPARE(valueA1.name(), QLatin1String("ValueA1")); - QCOMPARE(valueA1.stringValue(), QLatin1String("~3u")); + QCOMPARE(valueA1.name(), u"ValueA1"); + QCOMPARE(valueA1.stringValue(), u"~3u"); QCOMPARE(valueA1.value().unsignedValue(), ~3u); AbstractMetaEnumValue valueA2 = enumA->values().at(2); - QCOMPARE(valueA2.name(), QLatin1String("ValueA2")); - QCOMPARE(valueA2.stringValue(), QLatin1String("0xffffffff")); + QCOMPARE(valueA2.name(), u"ValueA2"); + QCOMPARE(valueA2.stringValue(), u"0xffffffff"); QCOMPARE(valueA2.value().unsignedValue(), 0xffffffffu); AbstractMetaEnumValue valueA3 = enumA->values().at(3); - QCOMPARE(valueA3.name(), QLatin1String("ValueA3")); - QCOMPARE(valueA3.stringValue(), QLatin1String("0xf0")); + QCOMPARE(valueA3.name(), u"ValueA3"); + QCOMPARE(valueA3.stringValue(), u"0xf0"); QCOMPARE(valueA3.value().unsignedValue(), 0xf0u); AbstractMetaEnumValue valueA4 = enumA->values().at(4); - QCOMPARE(valueA4.name(), QLatin1String("ValueA4")); - QCOMPARE(valueA4.stringValue(), QLatin1String("8 |ValueA3")); + QCOMPARE(valueA4.name(), u"ValueA4"); + QCOMPARE(valueA4.stringValue(), u"8 |ValueA3"); QCOMPARE(valueA4.value().unsignedValue(), 8|0xf0u); AbstractMetaEnumValue valueA5 = enumA->values().at(5); - QCOMPARE(valueA5.name(), QLatin1String("ValueA5")); - QCOMPARE(valueA5.stringValue(), QLatin1String("ValueA3|32")); + QCOMPARE(valueA5.name(), u"ValueA5"); + QCOMPARE(valueA5.stringValue(), u"ValueA3|32"); QCOMPARE(valueA5.value().unsignedValue(), 0xf0u|32); AbstractMetaEnumValue valueA6 = enumA->values().at(6); - QCOMPARE(valueA6.name(), QLatin1String("ValueA6")); - QCOMPARE(valueA6.stringValue(), QLatin1String("ValueA3 >> 1")); + QCOMPARE(valueA6.name(), u"ValueA6"); + QCOMPARE(valueA6.stringValue(), u"ValueA3 >> 1"); QCOMPARE(valueA6.value().unsignedValue(), 0xf0u >> 1); AbstractMetaEnumValue valueA7 = enumA->values().at(7); - QCOMPARE(valueA7.name(), QLatin1String("ValueA7")); - QCOMPARE(valueA7.stringValue(), QLatin1String("ValueA3 << 1")); + QCOMPARE(valueA7.name(), u"ValueA7"); + QCOMPARE(valueA7.stringValue(), u"ValueA3 << 1"); QCOMPARE(valueA7.value().unsignedValue(), 0xf0u << 1); - const auto enumB = classA->findEnum(QLatin1String("EnumB")); + const auto enumB = classA->findEnum(u"EnumB"_s); QVERIFY(enumB.has_value()); QVERIFY(enumB->isSigned()); - QCOMPARE(enumB->typeEntry()->qualifiedCppName(), QLatin1String("A::EnumB")); + QCOMPARE(enumB->typeEntry()->qualifiedCppName(), u"A::EnumB"); QCOMPARE(enumB->values().size(), 1); const AbstractMetaEnumValue valueB0 = enumB->values().at(0); - QCOMPARE(valueB0.name(), QLatin1String("ValueB0")); - QCOMPARE(valueB0.stringValue(), QLatin1String("~3")); + QCOMPARE(valueB0.name(), u"ValueB0"); + QCOMPARE(valueB0.stringValue(), u"~3"); QCOMPARE(valueB0.value().value(), ~3); } void TestEnum::testPrivateEnum() { - const char* cppCode ="\ + const char cppCode[] = "\ class A {\n\ private:\n\ enum PrivateEnum { Priv0 = 0x0f, Priv1 = 0xf0 };\n\ public:\n\ enum PublicEnum { Pub0 = Priv0, Pub1 = A::Priv1 };\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <value-type name='A'>\n\ <enum-type name='PublicEnum'/>\n\ @@ -379,62 +362,216 @@ void TestEnum::testPrivateEnum() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); - AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(builder->classes(), "A"); QVERIFY(classA); - QCOMPARE(classA->enums().count(), 2); + QCOMPARE(classA->enums().size(), 2); - auto privateEnum = classA->findEnum(QLatin1String("PrivateEnum")); + auto privateEnum = classA->findEnum(u"PrivateEnum"_s); QVERIFY(privateEnum.has_value()); QVERIFY(privateEnum->isPrivate()); - QCOMPARE(privateEnum->typeEntry()->qualifiedCppName(), QLatin1String("A::PrivateEnum")); + QCOMPARE(privateEnum->typeEntry()->qualifiedCppName(), u"A::PrivateEnum"); - auto publicEnum = classA->findEnum(QLatin1String("PublicEnum")); + auto publicEnum = classA->findEnum(u"PublicEnum"_s); QVERIFY(publicEnum.has_value()); - QCOMPARE(publicEnum->typeEntry()->qualifiedCppName(), QLatin1String("A::PublicEnum")); + QCOMPARE(publicEnum->typeEntry()->qualifiedCppName(), u"A::PublicEnum"); AbstractMetaEnumValue pub0 = publicEnum->values().constFirst(); - QCOMPARE(pub0.name(), QLatin1String("Pub0")); + QCOMPARE(pub0.name(), u"Pub0"); QCOMPARE(pub0.value().value(), 0x0f); - QCOMPARE(pub0.stringValue(), QLatin1String("Priv0")); + QCOMPARE(pub0.stringValue(), u"Priv0"); AbstractMetaEnumValue pub1 = publicEnum->values().constLast(); - QCOMPARE(pub1.name(), QLatin1String("Pub1")); + QCOMPARE(pub1.name(), u"Pub1"); QCOMPARE(pub1.value().value(), 0xf0); - QCOMPARE(pub1.stringValue(), QLatin1String("A::Priv1")); + QCOMPARE(pub1.stringValue(), u"A::Priv1"); } void TestEnum::testTypedefEnum() { - const char* cppCode ="\ + const char cppCode[] = "\ typedef enum EnumA {\n\ A0,\n\ A1,\n\ } EnumA;\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <enum-type name='EnumA'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaEnumList globalEnums = builder->globalEnums(); - QCOMPARE(globalEnums.count(), 1); + QCOMPARE(globalEnums.size(), 1); AbstractMetaEnum enumA = globalEnums.constFirst(); - QCOMPARE(enumA.typeEntry()->qualifiedCppName(), QLatin1String("EnumA")); + QCOMPARE(enumA.typeEntry()->qualifiedCppName(), u"EnumA"); AbstractMetaEnumValue enumValueA0 = enumA.values().constFirst(); - QCOMPARE(enumValueA0.name(), QLatin1String("A0")); + QCOMPARE(enumValueA0.name(), u"A0"); QCOMPARE(enumValueA0.value().value(), 0); - QCOMPARE(enumValueA0.stringValue(), QLatin1String("")); + QCOMPARE(enumValueA0.stringValue(), u""); AbstractMetaEnumValue enumValueA1 = enumA.values().constLast(); - QCOMPARE(enumValueA1.name(), QLatin1String("A1")); + QCOMPARE(enumValueA1.name(), u"A1"); QCOMPARE(enumValueA1.value().value(), 1); 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 +{ + std::shared_ptr<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) + return -1; + + const auto globalEnums = fixture->builder->globalEnums(); + if (globalEnums.size() != 1) + return -2; + + fixture->globalEnum = AbstractMetaType(globalEnums.constFirst().typeEntry()); + fixture->globalEnum.decideUsagePattern(); + + AbstractMetaClassCPtr testNamespace; + for (const auto &c : fixture->builder->classes()) { + if (c->name() == u"Test2") { + testNamespace = c; + break; + } + } + if (!testNamespace) + return -3; + + const auto namespaceEnums = testNamespace->enums(); + if (namespaceEnums.size() != 2) + return -4; + QList<EnumTypeEntryCPtr > enumTypeEntries{ + std::static_pointer_cast<const EnumTypeEntry>(namespaceEnums.at(0).typeEntry()), + std::static_pointer_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..452755490 100644 --- a/sources/shiboken6/ApiExtractor/tests/testenum.h +++ b/sources/shiboken6/ApiExtractor/tests/testenum.h @@ -1,34 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTENUM_H #define TESTENUM_H -#include <QObject> + +#include <QtCore/QObject> class TestEnum : public QObject { @@ -42,6 +18,8 @@ private slots: void testEnumValueFromExpression(); void testPrivateEnum(); void testTypedefEnum(); + void testEnumDefaultValues_data(); + void testEnumDefaultValues(); }; #endif diff --git a/sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp b/sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp index 90a6cd312..fcc409a42 100644 --- a/sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp @@ -1,41 +1,17 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testextrainclude.h" #include <QtTest/QTest> #include "testutil.h" #include <abstractmetalang.h> -#include <typesystem.h> +#include <complextypeentry.h> +#include <typesystemtypeentry.h> void TestExtraInclude::testClassExtraInclude() { - const char* cppCode ="struct A {};\n"; - const char* xmlCode = "\ + const char cppCode[] = "struct A {};\n"; + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <value-type name='A'>\n\ <extra-includes>\n\ @@ -45,20 +21,20 @@ void TestExtraInclude::testClassExtraInclude() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); QList<Include> includes = classA->typeEntry()->extraIncludes(); - QCOMPARE(includes.count(), 1); - QCOMPARE(includes.constFirst().name(), QLatin1String("header.h")); + QCOMPARE(includes.size(), 1); + QCOMPARE(includes.constFirst().name(), u"header.h"); } void TestExtraInclude::testGlobalExtraIncludes() { - const char* cppCode ="struct A {};\n"; - const char* xmlCode = "\ + const char cppCode[] = "struct A {};\n"; + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <extra-includes>\n\ <include file-name='header1.h' location='global'/>\n\ @@ -68,19 +44,19 @@ void TestExtraInclude::testGlobalExtraIncludes() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("A"))); + QVERIFY(AbstractMetaClass::findClass(classes, "A")); - TypeDatabase* td = TypeDatabase::instance(); - const TypeSystemTypeEntry *module = td->defaultTypeSystemType(); + auto *td = TypeDatabase::instance(); + TypeSystemTypeEntryCPtr module = td->defaultTypeSystemType(); QVERIFY(module); - QCOMPARE(module->name(), QLatin1String("Foo")); + QCOMPARE(module->name(), u"Foo"); QList<Include> includes = module->extraIncludes(); - QCOMPARE(includes.count(), 2); - QCOMPARE(includes.constFirst().name(), QLatin1String("header1.h")); - QCOMPARE(includes.constLast().name(), QLatin1String("header2.h")); + QCOMPARE(includes.size(), 2); + QCOMPARE(includes.constFirst().name(), u"header1.h"); + QCOMPARE(includes.constLast().name(), u"header2.h"); } QTEST_APPLESS_MAIN(TestExtraInclude) diff --git a/sources/shiboken6/ApiExtractor/tests/testextrainclude.h b/sources/shiboken6/ApiExtractor/tests/testextrainclude.h index 33c5377c7..6bcb57993 100644 --- a/sources/shiboken6/ApiExtractor/tests/testextrainclude.h +++ b/sources/shiboken6/ApiExtractor/tests/testextrainclude.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTEXTRAINCLUDE_H #define TESTEXTRAINCLUDE_H -#include <QObject> +#include <QtCore/QObject> class TestExtraInclude : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp index f58ea6f64..18eaf5774 100644 --- a/sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp @@ -1,38 +1,18 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testfunctiontag.h" -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetafunction.h> #include <modifications.h> #include <typesystem.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestFunctionTag::testFunctionTagForSpecificSignature() { const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy();\n"; @@ -43,9 +23,9 @@ void TestFunctionTag::testFunctionTagForSpecificSignature() <function signature='globalFunction(int)'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); - const TypeEntry *func = TypeDatabase::instance()->findType(QLatin1String("globalFunction")); + TypeEntryCPtr func = TypeDatabase::instance()->findType(u"globalFunction"_s); QVERIFY(func); QCOMPARE(builder->globalFunctions().size(), 1); } @@ -61,24 +41,24 @@ void TestFunctionTag::testFunctionTagForAllSignatures() <function signature='globalFunction(float)'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); - const TypeEntry *func = TypeDatabase::instance()->findType(QLatin1String("globalFunction")); + TypeEntryCPtr func = TypeDatabase::instance()->findType(u"globalFunction"_s); QVERIFY(func); QCOMPARE(builder->globalFunctions().size(), 2); } void TestFunctionTag::testRenameGlobalFunction() { - const char* cppCode ="void global_function_with_ugly_name();\n"; - const char* xmlCode = "\ + const char cppCode[] = "void global_function_with_ugly_name();\n"; + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <function signature='global_function_with_ugly_name()' rename='smooth'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); - const TypeEntry *func = TypeDatabase::instance()->findType(QLatin1String("global_function_with_ugly_name")); + TypeEntryCPtr func = TypeDatabase::instance()->findType(u"global_function_with_ugly_name"_s); QVERIFY(func); QCOMPARE(builder->globalFunctions().size(), 1); @@ -88,11 +68,11 @@ void TestFunctionTag::testRenameGlobalFunction() QCOMPARE(metaFunc->modifications().size(), 1); QVERIFY(metaFunc->modifications().constFirst().isRenameModifier()); QCOMPARE(metaFunc->modifications().constFirst().renamedToName(), - QLatin1String("smooth")); + u"smooth"); - QCOMPARE(metaFunc->name(), QLatin1String("smooth")); - QCOMPARE(metaFunc->originalName(), QLatin1String("global_function_with_ugly_name")); - QCOMPARE(metaFunc->minimalSignature(), QLatin1String("global_function_with_ugly_name()")); + QCOMPARE(metaFunc->name(), u"smooth"); + QCOMPARE(metaFunc->originalName(), u"global_function_with_ugly_name"); + QCOMPARE(metaFunc->minimalSignature(), u"global_function_with_ugly_name()"); } QTEST_APPLESS_MAIN(TestFunctionTag) diff --git a/sources/shiboken6/ApiExtractor/tests/testfunctiontag.h b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.h index d68499cd9..7c60cb4e0 100644 --- a/sources/shiboken6/ApiExtractor/tests/testfunctiontag.h +++ b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.h @@ -1,34 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTFUNCTIONTAG_H #define TESTFUNCTIONTAG_H -#include <QObject> + +#include <QtCore/QObject> class TestFunctionTag : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp index 9dcdec975..899d00ad4 100644 --- a/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp @@ -1,41 +1,18 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testimplicitconversions.h" #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> -#include <typesystem.h> +#include <abstractmetatype.h> +#include <complextypeentry.h> #include <QtTest/QTest> void TestImplicitConversions::testWithPrivateCtors() { - const char* cppCode ="\ + const char cppCode[] = "\ class B;\n\ class C;\n\ class A {\n\ @@ -45,35 +22,35 @@ void TestImplicitConversions::testWithPrivateCtors() };\n\ class B {};\n\ class C {};\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <value-type name='A'/>\n\ <value-type name='B'/>\n\ <value-type name='C'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 3); + QCOMPARE(classes.size(), 3); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + const auto classC = AbstractMetaClass::findClass(classes, "C"); const auto implicitConvs = classA->implicitConversions(); - QCOMPARE(implicitConvs.count(), 1); + QCOMPARE(implicitConvs.size(), 1); QCOMPARE(implicitConvs.constFirst()->arguments().constFirst().type().typeEntry(), classC->typeEntry()); } void TestImplicitConversions::testWithModifiedVisibility() { - const char* cppCode ="\ + const char cppCode[] = "\ class B;\n\ class A {\n\ public:\n\ A(const B&);\n\ };\n\ class B {};\n"; - const char* xmlCode = R"( + const char xmlCode[] = R"( <typesystem package='Foo'> <value-type name='A'> <modify-function signature='A(const B&)' access='private'/> @@ -82,13 +59,13 @@ void TestImplicitConversions::testWithModifiedVisibility() </typesystem> )"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QCOMPARE(classes.size(), 2); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + const auto classB = AbstractMetaClass::findClass(classes, "B"); const auto implicitConvs = classA->implicitConversions(); - QCOMPARE(implicitConvs.count(), 1); + QCOMPARE(implicitConvs.size(), 1); QCOMPARE(implicitConvs.constFirst()->arguments().constFirst().type().typeEntry(), classB->typeEntry()); } @@ -96,7 +73,7 @@ void TestImplicitConversions::testWithModifiedVisibility() void TestImplicitConversions::testWithAddedCtor() { - const char* cppCode ="\ + const char cppCode[] = "\ class B;\n\ class A {\n\ public:\n\ @@ -104,7 +81,7 @@ void TestImplicitConversions::testWithAddedCtor() };\n\ class B {};\n\ class C {};\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <custom-type name='TARGETLANGTYPE'/>\n\ <value-type name='A'>\n\ @@ -116,49 +93,49 @@ void TestImplicitConversions::testWithAddedCtor() <value-type name='C'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 3); + QCOMPARE(classes.size(), 3); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); auto implicitConvs = classA->implicitConversions(); - QCOMPARE(implicitConvs.count(), 2); + QCOMPARE(implicitConvs.size(), 2); // Added constructors with custom types should never result in implicit converters. - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); implicitConvs = classB->implicitConversions(); - QCOMPARE(implicitConvs.count(), 0); + QCOMPARE(implicitConvs.size(), 0); } void TestImplicitConversions::testWithExternalConversionOperator() { - const char* cppCode ="\ + const char cppCode[] = "\ class A {};\n\ struct B {\n\ operator A() const;\n\ };\n"; - const char* xmlCode = "\n\ + const char xmlCode[] = "\n\ <typesystem package='Foo'>\n\ <value-type name='A'/>\n\ <value-type name='B'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QCOMPARE(classes.size(), 2); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + const auto classB = AbstractMetaClass::findClass(classes, "B"); const auto implicitConvs = classA->implicitConversions(); - QCOMPARE(implicitConvs.count(), 1); + QCOMPARE(implicitConvs.size(), 1); const auto &externalConvOps = classA->externalConversionOperators(); - QCOMPARE(externalConvOps.count(), 1); + QCOMPARE(externalConvOps.size(), 1); AbstractMetaFunctionCPtr convOp; for (const auto &func : classB->functions()) { if (func->isConversionOperator()) convOp = func; } - QVERIFY(!convOp.isNull()); + QVERIFY(convOp); QCOMPARE(implicitConvs.constFirst(), convOp); } diff --git a/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h index da8ae4597..e0678c5f5 100644 --- a/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h +++ b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTIMPLICITCONVERSIONS_H #define TESTIMPLICITCONVERSIONS_H -#include <QObject> +#include <QtCore/QObject> class AbstractMetaBuilder; diff --git a/sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp index fda6614f0..23cf0f9ea 100644 --- a/sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp @@ -1,42 +1,19 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testinserttemplate.h" #include <QtTest/QTest> #include "testutil.h" #include <abstractmetalang.h> +#include <codesnip.h> #include <modifications.h> -#include <typesystem.h> +#include <complextypeentry.h> +#include <typesystemtypeentry.h> void TestInsertTemplate::testInsertTemplateOnClassInjectCode() { - const char* cppCode ="struct A{};\n"; - const char* xmlCode = "\ + const char cppCode[] = "struct A{};\n"; + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <template name='code_template'>\n\ code template content\n\ @@ -48,20 +25,20 @@ void TestInsertTemplate::testInsertTemplateOnClassInjectCode() </value-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 1); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classes.size(), 1); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - QCOMPARE(classA->typeEntry()->codeSnips().count(), 1); + QCOMPARE(classA->typeEntry()->codeSnips().size(), 1); QString code = classA->typeEntry()->codeSnips().constFirst().code(); - QVERIFY(code.contains(QLatin1String("code template content"))); + QVERIFY(code.contains(u"code template content")); } void TestInsertTemplate::testInsertTemplateOnModuleInjectCode() { - const char* cppCode =""; - const char* xmlCode = "\ + const char cppCode[] = ""; + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <template name='code_template'>\n\ code template content\n\ @@ -71,17 +48,16 @@ void TestInsertTemplate::testInsertTemplateOnModuleInjectCode() </inject-code>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); QVERIFY(classes.isEmpty()); - const TypeSystemTypeEntry *module = TypeDatabase::instance()->defaultTypeSystemType(); + TypeSystemTypeEntryCPtr module = TypeDatabase::instance()->defaultTypeSystemType(); QVERIFY(module); - QCOMPARE(module->name(), QLatin1String("Foo")); - QVERIFY(module); - QCOMPARE(module->codeSnips().count(), 1); + QCOMPARE(module->name(), u"Foo"); + QCOMPARE(module->codeSnips().size(), 1); QString code = module->codeSnips().constFirst().code().trimmed(); - QVERIFY(code.contains(QLatin1String("code template content"))); + QVERIFY(code.contains(u"code template content")); } QTEST_APPLESS_MAIN(TestInsertTemplate) diff --git a/sources/shiboken6/ApiExtractor/tests/testinserttemplate.h b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.h index 99b171933..f4f67abc0 100644 --- a/sources/shiboken6/ApiExtractor/tests/testinserttemplate.h +++ b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTINSERTTEMPLATE_H #define TESTINSERTTEMPLATE_H -#include <QObject> +#include <QtCore/QObject> class TestInsertTemplate : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp index 521f8d665..9cf2e0cc7 100644 --- a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp @@ -1,46 +1,26 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testmodifydocumentation.h" - -#include <QCoreApplication> -#include <QtCore/QTemporaryDir> -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetalang.h> +#include <abstractmetafunction.h> #include <documentation.h> #include <modifications.h> -#include <typesystem.h> +#include <complextypeentry.h> #include <qtdocparser.h> +#include <qtcompat.h> + +#include <QtCore/QCoreApplication> +#include <QtCore/QTemporaryDir> +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestModifyDocumentation::testModifyDocumentation() { - const char* cppCode ="struct B { void b(); }; class A {};\n"; + const char cppCode[] = "struct B { void b(); }; class A {};\n"; const char xmlCode[] = R"(<typesystem package="Foo"> <value-type name='B'> @@ -53,22 +33,22 @@ R"(<typesystem package="Foo"> </typesystem> )"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); - AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + QVERIFY(builder); + const auto classA = AbstractMetaClass::findClass(builder->classes(), "A"); QVERIFY(classA); DocModificationList docMods = classA->typeEntry()->docModifications(); - QCOMPARE(docMods.count(), 2); - QCOMPARE(docMods[0].code().trimmed(), QLatin1String("<brief>Modified Brief</brief>")); + QCOMPARE(docMods.size(), 2); + QCOMPARE(docMods[0].code().trimmed(), u"<brief>Modified Brief</brief>"); QCOMPARE(docMods[0].signature(), QString()); - QCOMPARE(docMods[1].code().trimmed(), QLatin1String("<para>Some changed contents here</para>")); + QCOMPARE(docMods[1].code().trimmed(), u"<para>Some changed contents here</para>"); QCOMPARE(docMods[1].signature(), QString()); // Create a temporary directory for the documentation file since libxml2 // cannot handle Qt resources. - QTemporaryDir tempDir(QDir::tempPath() + QLatin1String("/shiboken_testmodifydocXXXXXX")); + QTemporaryDir tempDir(QDir::tempPath() + u"/shiboken_testmodifydocXXXXXX"_s); QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString())); - const QString docFileName = QLatin1String("a.xml"); - QVERIFY(QFile::copy(QLatin1String(":/") + docFileName, tempDir.filePath(docFileName))); + constexpr auto docFileName = "a.xml"_L1; + QVERIFY(QFile::copy(u":/"_s + docFileName, tempDir.filePath(docFileName))); QtDocParser docParser; docParser.setDocumentationDataDirectory(tempDir.path()); @@ -89,7 +69,7 @@ R"(<?xml version="1.0"?> )"; const QString expectedDocSimplified = QString::fromLatin1(expectedDoc).simplified(); // Check whether the first modification worked. - QVERIFY(actualBriefSimplified.contains(QLatin1String("Modified Brief"))); + QVERIFY(actualBriefSimplified.contains(u"Modified Brief")); #ifndef HAVE_LIBXSLT // QtXmlPatterns is unable to handle para[3] in style sheets, @@ -99,6 +79,33 @@ R"(<?xml version="1.0"?> QCOMPARE(actualDocSimplified, expectedDocSimplified); } +void TestModifyDocumentation::testInjectAddedFunctionDocumentation() +{ + const char cppCode[] ="class A {};\n"; + const char xmlCode[] = R"XML( +<typesystem package="Foo"> + <value-type name='A'> + <add-function signature="foo(int@parameter_name@)"> + <inject-documentation format="target" mode="append"> + Injected documentation of added function foo. + </inject-documentation> + </add-function> + </value-type> +</typesystem> +)XML"; + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); + QVERIFY(builder); + const auto classA = AbstractMetaClass::findClass(builder->classes(), "A"); + QVERIFY(classA); + const auto f = classA->findFunction("foo"); + QVERIFY(f); + QVERIFY(f->isUserAdded()); + auto docMods = f->addedFunctionDocModifications(); + QCOMPARE(docMods.size(), 1); + const QString code = docMods.constFirst().code(); + QVERIFY(code.contains(u"Injected documentation of added function foo.")); +} + // We expand QTEST_MAIN macro but using QCoreApplication instead of QApplication // because this test needs an event loop but can't use QApplication to avoid a crash // on our ARMEL/FRAMANTLE buildbot diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h index 6428a5697..c1cc8f480 100644 --- a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h +++ b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h @@ -1,41 +1,17 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTMODIFYDOCUMENTATION_H #define TESTMODIFYDOCUMENTATION_H -#include <QObject> +#include <QtCore/QObject> class TestModifyDocumentation : public QObject { Q_OBJECT private slots: void testModifyDocumentation(); + void testInjectAddedFunctionDocumentation(); }; #endif diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp index 0d95d5abb..a7d40f70a 100644 --- a/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp @@ -1,40 +1,22 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testmodifyfunction.h" -#include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetabuilder_p.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> +#include <abstractmetatype.h> #include <modifications.h> #include <typesystem.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestModifyFunction::testRenameArgument_data() { QTest::addColumn<QByteArray>("pattern"); @@ -46,7 +28,7 @@ void TestModifyFunction::testRenameArgument() { QFETCH(QByteArray, pattern); - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ void method(int=0);\n\ };\n"; @@ -64,23 +46,23 @@ void TestModifyFunction::testRenameArgument() const QByteArray xmlCode = QByteArray(xmlCode1) + pattern + QByteArray(xmlCode2); QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.constData(), false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); - const auto func = classA->findFunction(QLatin1String("method")); - QVERIFY(!func.isNull()); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + const auto func = classA->findFunction("method"); + QVERIFY(func); - QCOMPARE(func->argumentName(1), QLatin1String("otherArg")); + QCOMPARE(func->argumentName(1), u"otherArg"); } void TestModifyFunction::testOwnershipTransfer() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {};\n\ struct B {\n\ virtual A* method();\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <object-type name='A' />\n\ <object-type name='B'>\n\ @@ -92,11 +74,11 @@ void TestModifyFunction::testOwnershipTransfer() </object-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); - const auto func = classB->findFunction(QLatin1String("method")); - QVERIFY(!func.isNull()); + const auto classB = AbstractMetaClass::findClass(classes, "B"); + const auto func = classB->findFunction("method"); + QVERIFY(func); QCOMPARE(func->argumentTargetOwnership(func->ownerClass(), 0), TypeSystem::CppOwnership); @@ -105,7 +87,7 @@ void TestModifyFunction::testOwnershipTransfer() void TestModifyFunction::invalidateAfterUse() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ virtual void call(int *a);\n\ };\n\ @@ -119,7 +101,7 @@ void TestModifyFunction::invalidateAfterUse() };\n\ struct E : D {\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='int'/>\n\ <object-type name='A'>\n\ @@ -141,48 +123,48 @@ void TestModifyFunction::invalidateAfterUse() <object-type name='E' />\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, - false, QLatin1String("0.1"))); - QVERIFY(!builder.isNull()); + false, u"0.1"_s)); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); - auto func = classB->findFunction(QLatin1String("call")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); + auto func = classB->findFunction("call"); QCOMPARE(func->modifications().size(), 1); QCOMPARE(func->modifications().at(0).argument_mods().size(), 1); QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse()); - const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C")); + const auto classC = AbstractMetaClass::findClass(classes, "C"); QVERIFY(classC); - func = classC->findFunction(QLatin1String("call")); + func = classC->findFunction("call"); QCOMPARE(func->modifications().size(), 1); QCOMPARE(func->modifications().at(0).argument_mods().size(), 1); QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse()); - func = classC->findFunction(QLatin1String("call2")); + func = classC->findFunction("call2"); QCOMPARE(func->modifications().size(), 1); QCOMPARE(func->modifications().at(0).argument_mods().size(), 1); QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse()); - const AbstractMetaClass *classD = AbstractMetaClass::findClass(classes, QLatin1String("D")); + AbstractMetaClassCPtr classD = AbstractMetaClass::findClass(classes, "D"); QVERIFY(classD); - func = classD->findFunction(QLatin1String("call")); + func = classD->findFunction("call"); QCOMPARE(func->modifications().size(), 1); QCOMPARE(func->modifications().at(0).argument_mods().size(), 1); QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse()); - func = classD->findFunction(QLatin1String("call2")); + func = classD->findFunction("call2"); QCOMPARE(func->modifications().size(), 1); QCOMPARE(func->modifications().at(0).argument_mods().size(), 1); QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse()); - const AbstractMetaClass *classE = AbstractMetaClass::findClass(classes, QLatin1String("E")); + const auto classE = AbstractMetaClass::findClass(classes, "E"); QVERIFY(classE); - func = classE->findFunction(QLatin1String("call")); + func = classE->findFunction("call"); QVERIFY(func); QCOMPARE(func->modifications().size(), 1); QCOMPARE(func->modifications().at(0).argument_mods().size(), 1); QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse()); - func = classE->findFunction(QLatin1String("call2")); + func = classE->findFunction("call2"); QVERIFY(func); QCOMPARE(func->modifications().size(), 1); QCOMPARE(func->modifications().at(0).argument_mods().size(), 1); @@ -191,13 +173,13 @@ void TestModifyFunction::invalidateAfterUse() void TestModifyFunction::testWithApiVersion() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {};\n\ struct B {\n\ virtual A* method();\n\ virtual B* methodB();\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <object-type name='A' />\n\ <object-type name='B'>\n\ @@ -214,16 +196,16 @@ void TestModifyFunction::testWithApiVersion() </object-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, - false, QLatin1String("0.1"))); - QVERIFY(!builder.isNull()); + false, u"0.1"_s)); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); - auto func = classB->findFunction(QLatin1String("method")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); + auto func = classB->findFunction("method"); auto returnOwnership = func->argumentTargetOwnership(func->ownerClass(), 0); QCOMPARE(returnOwnership, TypeSystem::CppOwnership); - func = classB->findFunction(QLatin1String("methodB")); + func = classB->findFunction("methodB"); returnOwnership = func->argumentTargetOwnership(func->ownerClass(), 0); QVERIFY(returnOwnership != TypeSystem::CppOwnership); } @@ -253,44 +235,44 @@ struct A { </typesystem> )XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, - false, QLatin1String("0.1"))); - QVERIFY(!builder.isNull()); + false, u"0.1"_s)); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); // Nothing specified, true - const auto f1 = classA->findFunction(QLatin1String("f1")); - QVERIFY(!f1.isNull()); + const auto f1 = classA->findFunction("f1"); + QVERIFY(f1); QVERIFY(!f1->allowThread()); // 'auto' specified, should be false for nontrivial function - const auto f2 = classA->findFunction(QLatin1String("f2")); - QVERIFY(!f2.isNull()); + const auto f2 = classA->findFunction("f2"); + QVERIFY(f2); QVERIFY(f2->allowThread()); // 'no' specified, should be false - const auto f3 = classA->findFunction(QLatin1String("f3")); - QVERIFY(!f3.isNull()); + const auto f3 = classA->findFunction("f3"); + QVERIFY(f3); QVERIFY(!f3->allowThread()); // Nothing specified, should be false for simple getter - const auto getter1 = classA->findFunction(QLatin1String("getter1")); - QVERIFY(!getter1.isNull()); + const auto getter1 = classA->findFunction("getter1"); + QVERIFY(getter1); QVERIFY(!getter1->allowThread()); // Forced to true simple getter - const auto getter2 = classA->findFunction(QLatin1String("getter2")); - QVERIFY(!getter2.isNull()); + const auto getter2 = classA->findFunction("getter2"); + QVERIFY(getter2); QVERIFY(getter2->allowThread()); // Forced to true simple getter } void TestModifyFunction::testGlobalFunctionModification() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {};\n\ void function(A* a = 0);\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='A'/>\n\ <function signature='function(A*)'>\n\ @@ -304,23 +286,24 @@ void TestModifyFunction::testGlobalFunctionModification() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); QCOMPARE(builder->globalFunctions().size(), 1); - FunctionModificationList mods = TypeDatabase::instance()->functionModifications(QLatin1String("function(A*)")); - QCOMPARE(mods.count(), 1); + auto *td = TypeDatabase::instance(); + FunctionModificationList mods = td->globalFunctionModifications({u"function(A*)"_s}); + QCOMPARE(mods.size(), 1); const QList<ArgumentModification> &argMods = mods.constFirst().argument_mods(); - QCOMPARE(argMods.count(), 1); + QCOMPARE(argMods.size(), 1); ArgumentModification argMod = argMods.constFirst(); - QCOMPARE(argMod.replacedDefaultExpression(), QLatin1String("A()")); + QCOMPARE(argMod.replacedDefaultExpression(), u"A()"); QVERIFY(!builder->globalFunctions().isEmpty()); const auto func = builder->globalFunctions().constFirst(); - QCOMPARE(func->arguments().count(), 1); + QCOMPARE(func->arguments().size(), 1); const AbstractMetaArgument &arg = func->arguments().constFirst(); - QCOMPARE(arg.type().cppSignature(), QLatin1String("A *")); - QCOMPARE(arg.originalDefaultValueExpression(), QLatin1String("0")); - QCOMPARE(arg.defaultValueExpression(), QLatin1String("A()")); + QCOMPARE(arg.type().cppSignature(), u"A *"); + QCOMPARE(arg.originalDefaultValueExpression(), u"0"); + QCOMPARE(arg.defaultValueExpression(), u"A()"); } // Tests modifications of exception handling and allow-thread @@ -451,44 +434,44 @@ void TestModifyFunction::testScopedModifications() QFETCH(bool, expectedAllowThread); QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode.constData(), xmlCode.constData(), false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(builder->classes(), "A"); QVERIFY(classA); - auto f = classA->findFunction(QStringLiteral("unspecified")); - QVERIFY(!f.isNull()); + auto f = classA->findFunction("unspecified"); + QVERIFY(f); QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Unknown); QCOMPARE(f->generateExceptionHandling(), expectedGenerateUnspecified); QCOMPARE(f->allowThread(), expectedAllowThread); - f = classA->findFunction(QStringLiteral("nonThrowing")); - QVERIFY(!f.isNull()); + f = classA->findFunction("nonThrowing"); + QVERIFY(f); QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::NoExcept); QCOMPARE(f->generateExceptionHandling(), expectedGenerateNonThrowing); - f = classA->findFunction(QStringLiteral("throwing")); - QVERIFY(!f.isNull()); + f = classA->findFunction("throwing"); + QVERIFY(f); QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Throws); QCOMPARE(f->generateExceptionHandling(), expectedGenerateThrowing); } void TestModifyFunction::testSnakeCaseRenaming_data() { - QTest::addColumn<QString>("name"); - QTest::addColumn<QString>("expected"); + QTest::addColumn<QLatin1StringView>("name"); + QTest::addColumn<QLatin1StringView>("expected"); QTest::newRow("s1") - << QStringLiteral("snakeCaseFunc") << QStringLiteral("snake_case_func"); + << "snakeCaseFunc"_L1 << "snake_case_func"_L1; QTest::newRow("s2") - << QStringLiteral("SnakeCaseFunc") << QStringLiteral("snake_case_func"); + << "SnakeCaseFunc"_L1 << "snake_case_func"_L1; QTest::newRow("consecutive-uppercase") - << QStringLiteral("snakeCAseFunc") << QStringLiteral("snakeCAseFunc"); + << "snakeCAseFunc"_L1 << "snakeCAseFunc"_L1; } void TestModifyFunction::testSnakeCaseRenaming() { - QFETCH(QString, name); - QFETCH(QString, expected); + QFETCH(QLatin1StringView, name); + QFETCH(QLatin1StringView, expected); const QString actual = AbstractMetaBuilder::getSnakeCaseName(name); QCOMPARE(actual, expected); diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h index a9a13a82b..8a4f5d826 100644 --- a/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h +++ b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTABSTRACTMETACLASS_H #define TESTABSTRACTMETACLASS_H -#include <QObject> +#include <QtCore/QObject> class TestModifyFunction : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp index 748adfc39..1cf4c8e0f 100644 --- a/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testmultipleinheritance.h" #include <QtTest/QTest> @@ -35,7 +10,7 @@ void TestMultipleInheritance::testVirtualClass() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ virtual ~A();\n\ virtual void theBug();\n\ @@ -47,7 +22,7 @@ void TestMultipleInheritance::testVirtualClass() };\n\ struct D : C {\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <object-type name='A' />\n\ <object-type name='B' />\n\ @@ -56,14 +31,14 @@ void TestMultipleInheritance::testVirtualClass() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 4); + QCOMPARE(classes.size(), 4); - const AbstractMetaClass *classD = AbstractMetaClass::findClass(classes, QLatin1String("D")); + const auto classD = AbstractMetaClass::findClass(classes, "D"); bool functionFound = false; for (const auto &f : classD->functions()) { - if (f->name() == QLatin1String("theBug")) { + if (f->name() == u"theBug") { functionFound = true; break; } diff --git a/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h index 5ee8a21ea..ec9935305 100644 --- a/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h +++ b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTMULTIPLEINHERITANCE_H #define TESTMULTIPLEINHERITANCE_H -#include <QObject> +#include <QtCore/QObject> class AbstractMetaBuilder; diff --git a/sources/shiboken6/ApiExtractor/tests/testnamespace.cpp b/sources/shiboken6/ApiExtractor/tests/testnamespace.cpp index 99aabe780..3773e614a 100644 --- a/sources/shiboken6/ApiExtractor/tests/testnamespace.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testnamespace.cpp @@ -1,41 +1,21 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testnamespace.h" -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetalang.h> #include <abstractmetaenum.h> #include <typesystem.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void NamespaceTest::testNamespaceMembers() { - const char* cppCode = "\ + const char cppCode[] = "\ namespace Namespace\n\ {\n\ enum Option {\n\ @@ -44,26 +24,26 @@ void NamespaceTest::testNamespaceMembers() };\n\ void foo(Option opt);\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <namespace-type name='Namespace'>\n\ <enum-type name='Option' />\n\ </namespace-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - AbstractMetaClass *ns = AbstractMetaClass::findClass(classes, QLatin1String("Namespace")); + const auto ns = AbstractMetaClass::findClass(classes, "Namespace"); QVERIFY(ns); - auto metaEnum = ns->findEnum(QLatin1String("Option")); + auto metaEnum = ns->findEnum(u"Option"_s); QVERIFY(metaEnum.has_value()); - const auto func = ns->findFunction(QLatin1String("foo")); - QVERIFY(!func.isNull()); + const auto func = ns->findFunction("foo"); + QVERIFY(func); } void NamespaceTest::testNamespaceInnerClassMembers() { - const char* cppCode = "\ + const char cppCode[] = "\ namespace OuterNamespace\n\ {\n\ namespace InnerNamespace {\n\ @@ -72,7 +52,7 @@ void NamespaceTest::testNamespaceInnerClassMembers() };\n\ };\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <namespace-type name='OuterNamespace'>\n\ <namespace-type name='InnerNamespace'>\n\ @@ -81,16 +61,16 @@ void NamespaceTest::testNamespaceInnerClassMembers() </namespace-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *ons = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace")); + const auto ons = AbstractMetaClass::findClass(classes, "OuterNamespace"); QVERIFY(ons); - const AbstractMetaClass *ins = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace")); + const auto ins = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace"); QVERIFY(ins); - const AbstractMetaClass *sc = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace::SomeClass")); + const auto sc = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace::SomeClass"); QVERIFY(sc); - const auto meth = sc->findFunction(QLatin1String("method")); - QVERIFY(!meth.isNull()); + const auto meth = sc->findFunction("method"); + QVERIFY(meth); } QTEST_APPLESS_MAIN(NamespaceTest) diff --git a/sources/shiboken6/ApiExtractor/tests/testnamespace.h b/sources/shiboken6/ApiExtractor/tests/testnamespace.h index 5153a28a3..af46bdea3 100644 --- a/sources/shiboken6/ApiExtractor/tests/testnamespace.h +++ b/sources/shiboken6/ApiExtractor/tests/testnamespace.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTNAMESPACE_H #define TESTNAMESPACE_H -#include <QObject> +#include <QtCore/QObject> // The class is named 'NamespaceTest' to avoid clashes with Qt COIN using // '-qtnamespace TestNamespace'. diff --git a/sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp index d536c0538..10ca1a0f6 100644 --- a/sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp @@ -1,42 +1,25 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testnestedtypes.h" -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetafunction.h> #include <abstractmetalang.h> +#include <abstractmetatype.h> +#include <codesnip.h> #include <modifications.h> -#include <typesystem.h> +#include <complextypeentry.h> +#include <primitivetypeentry.h> + +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; void TestNestedTypes::testNestedTypesModifications() { - const char* cppCode ="\ + const char cppCode[] = "\ namespace OuterNamespace {\n\ namespace InnerNamespace {\n\ struct SomeClass {\n\ @@ -44,7 +27,7 @@ void TestNestedTypes::testNestedTypesModifications() };\n\ };\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <namespace-type name='OuterNamespace'>\n\ <namespace-type name='InnerNamespace'>\n\ @@ -60,34 +43,35 @@ void TestNestedTypes::testNestedTypesModifications() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *ons = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace")); + const auto ons = AbstractMetaClass::findClass(classes, "OuterNamespace"); QVERIFY(ons); - const AbstractMetaClass *ins = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace")); + const auto ins = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace"); QVERIFY(ins); - QCOMPARE(ins->functions().count(), 1); - QCOMPARE(ins->typeEntry()->codeSnips().count(), 1); + QCOMPARE(ins->functions().size(), 1); + QCOMPARE(ins->typeEntry()->codeSnips().size(), 1); CodeSnip snip = ins->typeEntry()->codeSnips().constFirst(); - QCOMPARE(snip.code().trimmed(), QLatin1String("custom_code1();")); + QCOMPARE(snip.code().trimmed(), u"custom_code1();"); const auto addedFunc = ins->functions().constFirst(); QVERIFY(addedFunc->isUserAdded()); QCOMPARE(addedFunc->access(), Access::Public); QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction); QCOMPARE(addedFunc->type().minimalSignature(), - QLatin1String("OuterNamespace::InnerNamespace::SomeClass")); + u"OuterNamespace::InnerNamespace::SomeClass"); QCOMPARE(addedFunc->modifications().size(), 1); QVERIFY(addedFunc->modifications().constFirst().isCodeInjection()); snip = addedFunc->modifications().constFirst().snips().constFirst(); - QCOMPARE(snip.code().trimmed(), QLatin1String("custom_code2();")); + QCOMPARE(snip.code().trimmed(), u"custom_code2();"); - const AbstractMetaClass *sc = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace::SomeClass")); - QVERIFY(ins); - QCOMPARE(sc->functions().count(), 2); // default constructor and removed method + const auto sc = + AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace::SomeClass"); + QVERIFY(sc); + QCOMPARE(sc->functions().size(), 2); // default constructor and removed method const auto removedFunc = sc->functions().constLast(); QVERIFY(removedFunc->isModifiedRemoved()); } @@ -95,11 +79,11 @@ void TestNestedTypes::testNestedTypesModifications() void TestNestedTypes::testDuplicationOfNestedTypes() { - const char* cppCode ="\ + const char cppCode[] = "\ namespace Namespace {\n\ class SomeClass {};\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <namespace-type name='Namespace'>\n\ <value-type name='SomeClass'>\n\ @@ -109,22 +93,22 @@ void TestNestedTypes::testDuplicationOfNestedTypes() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 2); - const AbstractMetaClass *nspace = AbstractMetaClass::findClass(classes, QLatin1String("Namespace")); + QCOMPARE(classes.size(), 2); + const auto nspace = AbstractMetaClass::findClass(classes, "Namespace"); QVERIFY(nspace); - const AbstractMetaClass *cls1 = AbstractMetaClass::findClass(classes, QLatin1String("SomeClass")); + const auto cls1 = AbstractMetaClass::findClass(classes, "SomeClass"); QVERIFY(cls1); - const AbstractMetaClass *cls2 = AbstractMetaClass::findClass(classes, QLatin1String("Namespace::SomeClass")); + const auto cls2 = AbstractMetaClass::findClass(classes, "Namespace::SomeClass"); QVERIFY(cls2); QCOMPARE(cls1, cls2); - QCOMPARE(cls1->name(), QLatin1String("SomeClass")); - QCOMPARE(cls1->qualifiedCppName(), QLatin1String("Namespace::SomeClass")); + QCOMPARE(cls1->name(), u"SomeClass"); + QCOMPARE(cls1->qualifiedCppName(), u"Namespace::SomeClass"); - TypeEntry* t1 = TypeDatabase::instance()->findType(QLatin1String("Namespace::SomeClass")); + auto t1 = TypeDatabase::instance()->findType(u"Namespace::SomeClass"_s); QVERIFY(t1); - TypeEntry* t2 = TypeDatabase::instance()->findType(QLatin1String("SomeClass")); + auto t2 = TypeDatabase::instance()->findType(u"SomeClass"_s); QVERIFY(!t2); } diff --git a/sources/shiboken6/ApiExtractor/tests/testnestedtypes.h b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.h index a870511ff..544ea05ab 100644 --- a/sources/shiboken6/ApiExtractor/tests/testnestedtypes.h +++ b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.h @@ -1,34 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTNESTEDTYPES_H #define TESTNESTEDTYPES_H -#include <QObject> + +#include <QtCore/QObject> class TestNestedTypes : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp index de2f30135..9eef7ec47 100644 --- a/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp @@ -1,45 +1,22 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testnumericaltypedef.h" #include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> +#include <abstractmetatype.h> #include <typesystem.h> void TestNumericalTypedef::testNumericalTypedef() { - const char* cppCode ="\ + const char cppCode[] = "\ typedef double real;\n\ void funcDouble(double);\n\ void funcReal(real);\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='double'/>\n\ <primitive-type name='real'/>\n\ @@ -47,37 +24,37 @@ void TestNumericalTypedef::testNumericalTypedef() <function signature='funcReal(real)'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); QCOMPARE(builder->globalFunctions().size(), 2); auto funcDouble = builder->globalFunctions().constFirst(); auto funcReal = builder->globalFunctions().constLast(); QVERIFY(funcReal); - if (funcDouble->name() == QLatin1String("funcReal")) + if (funcDouble->name() == u"funcReal") std::swap(funcDouble, funcReal); - QCOMPARE(funcDouble->minimalSignature(), QLatin1String("funcDouble(double)")); - QCOMPARE(funcReal->minimalSignature(), QLatin1String("funcReal(real)")); + QCOMPARE(funcDouble->minimalSignature(), u"funcDouble(double)"); + QCOMPARE(funcReal->minimalSignature(), u"funcReal(real)"); const AbstractMetaType doubleType = funcDouble->arguments().constFirst().type(); - QCOMPARE(doubleType.cppSignature(), QLatin1String("double")); + QCOMPARE(doubleType.cppSignature(), u"double"); QVERIFY(doubleType.isPrimitive()); - QVERIFY(doubleType.typeEntry()->isCppPrimitive()); + QVERIFY(isCppPrimitive(doubleType.typeEntry())); const AbstractMetaType realType = funcReal->arguments().constFirst().type(); - QCOMPARE(realType.cppSignature(), QLatin1String("real")); + QCOMPARE(realType.cppSignature(), u"real"); QVERIFY(realType.isPrimitive()); - QVERIFY(realType.typeEntry()->isCppPrimitive()); + QVERIFY(isCppPrimitive(realType.typeEntry())); } void TestNumericalTypedef::testUnsignedNumericalTypedef() { - const char* cppCode ="\ + const char cppCode[] = "\ typedef unsigned short custom_ushort;\n\ void funcUnsignedShort(unsigned short);\n\ void funcUShort(custom_ushort);\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='short'/>\n\ <primitive-type name='unsigned short'/>\n\ @@ -86,27 +63,27 @@ void TestNumericalTypedef::testUnsignedNumericalTypedef() <function signature='funcUShort(custom_ushort)'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); QCOMPARE(builder->globalFunctions().size(), 2); auto funcUnsignedShort = builder->globalFunctions().constFirst(); auto funcUShort = builder->globalFunctions().constLast(); - if (funcUnsignedShort->name() == QLatin1String("funcUShort")) + if (funcUnsignedShort->name() == u"funcUShort") std::swap(funcUnsignedShort, funcUShort); - QCOMPARE(funcUnsignedShort->minimalSignature(), QLatin1String("funcUnsignedShort(unsigned short)")); - QCOMPARE(funcUShort->minimalSignature(), QLatin1String("funcUShort(custom_ushort)")); + QCOMPARE(funcUnsignedShort->minimalSignature(), u"funcUnsignedShort(unsigned short)"); + QCOMPARE(funcUShort->minimalSignature(), u"funcUShort(custom_ushort)"); const AbstractMetaType unsignedShortType = funcUnsignedShort->arguments().constFirst().type(); - QCOMPARE(unsignedShortType.cppSignature(), QLatin1String("unsigned short")); + QCOMPARE(unsignedShortType.cppSignature(), u"unsigned short"); QVERIFY(unsignedShortType.isPrimitive()); - QVERIFY(unsignedShortType.typeEntry()->isCppPrimitive()); + QVERIFY(isCppPrimitive(unsignedShortType.typeEntry())); const AbstractMetaType ushortType = funcUShort->arguments().constFirst().type(); - QCOMPARE(ushortType.cppSignature(), QLatin1String("custom_ushort")); + QCOMPARE(ushortType.cppSignature(), u"custom_ushort"); QVERIFY(ushortType.isPrimitive()); - QVERIFY(ushortType.typeEntry()->isCppPrimitive()); + QVERIFY(isCppPrimitive(ushortType.typeEntry())); } QTEST_APPLESS_MAIN(TestNumericalTypedef) diff --git a/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h index e4e051077..32f549836 100644 --- a/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h +++ b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTNUMERICALTYPEDEF_H #define TESTNUMERICALTYPEDEF_H -#include <QObject> +#include <QtCore/QObject> class TestNumericalTypedef : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp index e78f9f274..99cced09d 100644 --- a/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp @@ -1,59 +1,39 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testprimitivetypetag.h" -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetalang.h> -#include <typesystem.h> +#include <primitivetypeentry.h> + +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; void TestPrimitiveTypeTag::testPrimitiveTypeDefaultConstructor() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {};\n\ struct B {};\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <primitive-type name='A' default-constructor='A()'/>\n\ <object-type name='B'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 1); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QCOMPARE(classes.size(), 1); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classB); - PrimitiveTypeEntry* typeEntry = TypeDatabase::instance()->findPrimitiveType(QLatin1String("A")); + auto typeEntry = TypeDatabase::instance()->findPrimitiveType(u"A"_s); QVERIFY(typeEntry); QVERIFY(typeEntry->hasDefaultConstructor()); - QCOMPARE(typeEntry->defaultConstructor(), QLatin1String("A()")); + QCOMPARE(typeEntry->defaultConstructor(), u"A()"); } QTEST_APPLESS_MAIN(TestPrimitiveTypeTag) diff --git a/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h index ee5f5159f..3a0e05138 100644 --- a/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h +++ b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTPRIMITIVETYPETAG_H #define TESTPRIMITIVETYPETAG_H -#include <QObject> +#include <QtCore/QObject> class TestPrimitiveTypeTag : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp index f3ffd0edf..f2e261624 100644 --- a/sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp @@ -1,46 +1,26 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testrefcounttag.h" -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetafunction.h> #include <abstractmetalang.h> #include <modifications.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestRefCountTag::testReferenceCountTag() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {};\n\ struct B {\n\ void keepObject(B* b);\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <object-type name='A'/>\n\ <object-type name='B'>\n\ @@ -52,11 +32,11 @@ void TestRefCountTag::testReferenceCountTag() </object-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); - const auto func = classB->findFunction(QLatin1String("keepObject")); - QVERIFY(!func.isNull()); + const auto classB = AbstractMetaClass::findClass(classes, "B"); + const auto func = classB->findFunction("keepObject"); + QVERIFY(func); const auto refCount = func->modifications().constFirst().argument_mods().constFirst().referenceCounts().constFirst(); QCOMPARE(refCount.action, ReferenceCount::Add); @@ -64,12 +44,12 @@ void TestRefCountTag::testReferenceCountTag() void TestRefCountTag::testWithApiVersion() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {};\n\ struct B {\n\ void keepObject(B*, B*);\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <object-type name='A'/>\n\ <object-type name='B'>\n\ @@ -85,12 +65,12 @@ void TestRefCountTag::testWithApiVersion() </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, - false, QLatin1String("0.1"))); - QVERIFY(!builder.isNull()); + false, u"0.1"_s)); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); - const auto func = classB->findFunction(QLatin1String("keepObject")); - QVERIFY(!func.isNull()); + const auto classB = AbstractMetaClass::findClass(classes, "B"); + const auto func = classB->findFunction("keepObject"); + QVERIFY(func); const auto refCount = func->modifications().constFirst().argument_mods().constFirst().referenceCounts().constFirst(); QCOMPARE(refCount.action, ReferenceCount::Add); diff --git a/sources/shiboken6/ApiExtractor/tests/testrefcounttag.h b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.h index 4acbddcfc..6093c6f7b 100644 --- a/sources/shiboken6/ApiExtractor/tests/testrefcounttag.h +++ b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTREFCOUNTTAG_H #define TESTREFCOUNTTAG_H -#include <QObject> +#include <QtCore/QObject> class TestRefCountTag : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp index b929ebd66..ae85c5a86 100644 --- a/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp @@ -1,58 +1,35 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testreferencetopointer.h" #include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> +#include <abstractmetatype.h> #include <typesystem.h> void TestReferenceToPointer::testReferenceToPointerArgument() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {};\n\ struct B {\n\ void dummy(A*&);\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <object-type name='A'/>\n\ <object-type name='B'/>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classB); - const auto func = classB->findFunction(QLatin1String("dummy")); - QVERIFY(!func.isNull()); - QCOMPARE(func->arguments().constFirst().type().minimalSignature(), QLatin1String("A*&")); + const auto func = classB->findFunction("dummy"); + QVERIFY(func); + QCOMPARE(func->arguments().constFirst().type().minimalSignature(), u"A*&"); } QTEST_APPLESS_MAIN(TestReferenceToPointer) diff --git a/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h index 0f717b55d..2a7b34807 100644 --- a/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h +++ b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTREFERENCETOPOINTER_H #define TESTREFERENCETOPOINTER_H -#include <QObject> +#include <QtCore/QObject> class TestReferenceToPointer : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testremovefield.cpp b/sources/shiboken6/ApiExtractor/tests/testremovefield.cpp index 5fb2ff687..2cc82071b 100644 --- a/sources/shiboken6/ApiExtractor/tests/testremovefield.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testremovefield.cpp @@ -1,46 +1,26 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testremovefield.h" #include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetafield.h> +#include <abstractmetafunction.h> +#include <abstractmetatype.h> #include <abstractmetalang.h> #include <typesystem.h> +using namespace Qt::StringLiterals; + void TestRemoveField::testRemoveField() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {\n\ int fieldA;\n\ int fieldB;\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <primitive-type name='int'/>\n\ <value-type name='A'>\n\ @@ -48,13 +28,47 @@ void TestRemoveField::testRemoveField() </value-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); QCOMPARE(classA->fields().size(), 1); const AbstractMetaField &fieldA = classA->fields().constFirst(); - QCOMPARE(fieldA.name(), QLatin1String("fieldA")); + QCOMPARE(fieldA.name(), u"fieldA"); +} + +// Verify that 'static constexpr' fields are seen as static/const and +// appear fully qualified for function parameter default values. +void TestRemoveField::testConstExprField() +{ + const char cppCode[] = R"( +struct A { + static constexpr int constExprField = 44; + + void f(int iParam=constExprField); +}; +)"; + + const char xmlCode[] = R"( +<typesystem package="Foo"> + <value-type name='A'/> +</typesystem> +)"; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(builder); + AbstractMetaClassList classes = builder->classes(); + const auto classA = AbstractMetaClass::findClass(classes, "A"); + QVERIFY(classA); + const auto &fields = classA->fields(); + QCOMPARE(fields.size(), 1); + QVERIFY(fields.constFirst().isStatic()); + QVERIFY(fields.constFirst().type().isConstant()); + const auto function = classA->findFunction("f"_L1); + QVERIFY(function); + const auto &arguments = function->arguments(); + QCOMPARE(arguments.size(), 1); + QCOMPARE(arguments.constFirst().defaultValueExpression(), "A::constExprField"_L1); } QTEST_APPLESS_MAIN(TestRemoveField) diff --git a/sources/shiboken6/ApiExtractor/tests/testremovefield.h b/sources/shiboken6/ApiExtractor/tests/testremovefield.h index 8b52cc32f..05912d99e 100644 --- a/sources/shiboken6/ApiExtractor/tests/testremovefield.h +++ b/sources/shiboken6/ApiExtractor/tests/testremovefield.h @@ -1,41 +1,17 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTREMOVEFIELD_H #define TESTREMOVEFIELD_H -#include <QObject> +#include <QtCore/QObject> class TestRemoveField : public QObject { Q_OBJECT private slots: void testRemoveField(); + void testConstExprField(); }; #endif diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp index 41103c24e..87e318e95 100644 --- a/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp @@ -1,50 +1,27 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testremoveimplconv.h" #include "testutil.h" #include <QtTest/QTest> +#include <abstractmetaargument.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> -#include <typesystem.h> +#include <abstractmetatype.h> +#include <complextypeentry.h> // When a constructor able to trigger implicity conversions is removed // it should not appear in the implicity conversion list. void TestRemoveImplConv::testRemoveImplConv() { - const char* cppCode ="\ + const char cppCode[] = "\ struct A {};\n\ struct B {};\n\ struct C {\n\ C(const A&);\n\ C(const B&);\n\ };\n"; - const char* xmlCode = "\ + const char xmlCode[] = "\ <typesystem package=\"Foo\">\n\ <value-type name='A'/>\n\ <value-type name='B'/>\n\ @@ -53,17 +30,17 @@ void TestRemoveImplConv::testRemoveImplConv() </value-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 3); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + QCOMPARE(classes.size(), 3); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classB); - const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C")); + const auto classC = AbstractMetaClass::findClass(classes, "C"); QVERIFY(classC); const auto implConv = classC->implicitConversions(); - QCOMPARE(implConv.count(), 1); + QCOMPARE(implConv.size(), 1); QCOMPARE(implConv.constFirst()->arguments().constFirst().type().typeEntry(), classB->typeEntry()); } diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h index 9e96dc2e9..d11d30633 100644 --- a/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h +++ b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTREMOVEIMPLCONV_H #define TESTREMOVEIMPLCONV_H -#include <QObject> +#include <QtCore/QObject> class TestRemoveImplConv : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp index 9824d1bf0..17a069b5e 100644 --- a/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp @@ -1,63 +1,44 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testremoveoperatormethod.h" -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetafunction.h> #include <abstractmetalang.h> #include <typesystem.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestRemoveOperatorMethod::testRemoveOperatorMethod() { - const char* cppCode ="\ - #include <stdint.h>\n\ - \n\ - struct Char {};\n\ - struct ByteArray {};\n\ - struct String {};\n\ - \n\ - struct A {\n\ - A& operator>>(char&);\n\ - A& operator>>(char*);\n\ - A& operator>>(short&);\n\ - A& operator>>(unsigned short&);\n\ - A& operator>>(int&);\n\ - A& operator>>(unsigned int&);\n\ - A& operator>>(int64_t&);\n\ - A& operator>>(uint64_t&);\n\ - A& operator>>(float&);\n\ - A& operator>>(double&);\n\ - A& operator>>(Char&);\n\ - A& operator>>(ByteArray&);\n\ - A& operator>>(String&);\n\ - };\n"; - const char* xmlCode = "\ + const char cppCode[] = R"(#include <cstdint> + +struct Char {}; +struct ByteArray {}; +struct String {}; + +struct A { + A& operator>>(char&); + A& operator>>(char*); + A& operator>>(short&); + A& operator>>(unsigned short&); + A& operator>>(int&); + A& operator>>(unsigned int&); + A& operator>>(int64_t&); + A& operator>>(uint64_t&); + A& operator>>(float&); + A& operator>>(double&); + A& operator>>(Char&); + A& operator>>(ByteArray&); + A& operator>>(String&); +}; +)"; + + const char xmlCode[] = "\ <typesystem package='Foo'>\n\ <primitive-type name='char'/>\n\ <primitive-type name='short'/>\n\ @@ -87,25 +68,25 @@ void TestRemoveOperatorMethod::testRemoveOperatorMethod() </object-type>\n\ </typesystem>\n"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); QCOMPARE(classA->functions().size(), 14); QStringList removedSignatures; - removedSignatures.append(QLatin1String("operator>>(char&)")); - removedSignatures.append(QLatin1String("operator>>(char*)")); - removedSignatures.append(QLatin1String("operator>>(short&)")); - removedSignatures.append(QLatin1String("operator>>(unsigned short&)")); - removedSignatures.append(QLatin1String("operator>>(int&)")); - removedSignatures.append(QLatin1String("operator>>(unsigned int&)")); - removedSignatures.append(QLatin1String("operator>>(int64_t&)")); - removedSignatures.append(QLatin1String("operator>>(uint64_t&)")); - removedSignatures.append(QLatin1String("operator>>(float&)")); - removedSignatures.append(QLatin1String("operator>>(double&)")); - removedSignatures.append(QLatin1String("operator>>(Char&)")); - removedSignatures.append(QLatin1String("operator>>(String&)")); - int notRemoved = classA->functions().size(); + removedSignatures.append(u"operator>>(char&)"_s); + removedSignatures.append(u"operator>>(char*)"_s); + removedSignatures.append(u"operator>>(short&)"_s); + removedSignatures.append(u"operator>>(unsigned short&)"_s); + removedSignatures.append(u"operator>>(int&)"_s); + removedSignatures.append(u"operator>>(unsigned int&)"_s); + removedSignatures.append(u"operator>>(int64_t&)"_s); + removedSignatures.append(u"operator>>(uint64_t&)"_s); + removedSignatures.append(u"operator>>(float&)"_s); + removedSignatures.append(u"operator>>(double&)"_s); + removedSignatures.append(u"operator>>(Char&)"_s); + removedSignatures.append(u"operator>>(String&)"_s); + auto notRemoved = classA->functions().size(); for (const auto &f : classA->functions()) { QCOMPARE(f->isModifiedRemoved(), bool(removedSignatures.contains(f->minimalSignature()))); notRemoved -= int(f->isModifiedRemoved()); diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h index 23c3e5144..6ec335e0c 100644 --- a/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h +++ b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTREMOVEOPERATORMETHOD_H #define TESTREMOVEOPERATORMETHOD_H -#include <QObject> +#include <QtCore/QObject> class TestRemoveOperatorMethod : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp b/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp index 4c2930234..67ebcc606 100644 --- a/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp @@ -1,40 +1,33 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testresolvetype.h" -#include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> +#include <abstractmetaenum.h> +#include <abstractmetafunction.h> #include <abstractmetalang.h> -#include <typesystem.h> +#include <abstractmetatype.h> +#include <complextypeentry.h> +#include <enumtypeentry.h> +#include <primitivetypeentry.h> +#include <typedatabase.h> + +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + +void TestResolveType::initTestCase() +{ + // For enum lookup in testFixDefaultArguments() + AbstractMetaBuilder::setCodeModelTestMode(true); +} void TestResolveType::testResolveReturnTypeFromParentScope() { - const char* cppCode = "\n\ + const char cppCode[] = "\n\ namespace A {\n\ struct B {\n\ struct C {};\n\ @@ -44,7 +37,7 @@ void TestResolveType::testResolveReturnTypeFromParentScope() C* method();\n\ };\n\ };"; - const char* xmlCode = R"XML( + const char xmlCode[] = R"XML( <typesystem package='Foo'> <namespace-type name='A'> <value-type name='B'> @@ -54,14 +47,235 @@ void TestResolveType::testResolveReturnTypeFromParentScope() </namespace-type> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classD = AbstractMetaClass::findClass(classes, QLatin1String("A::D")); + const auto classD = AbstractMetaClass::findClass(classes, "A::D"); QVERIFY(classD); - const auto meth = classD->findFunction(QLatin1String("method")); - QVERIFY(!meth.isNull()); + const auto meth = classD->findFunction("method"); + QVERIFY(meth); QVERIFY(meth); } -QTEST_APPLESS_MAIN(TestResolveType) +// Helper classes and functions for testing default value fixing. +// Put the AbstractMetaBuilder into test fixture struct to avoid having +// to re-parse for each data row. + +struct DefaultValuesFixture +{ + std::shared_ptr<AbstractMetaBuilder> builder; + + AbstractMetaType intType; + AbstractMetaType stringType; + AbstractMetaType classType; + AbstractMetaType listType; + AbstractMetaType enumType; + AbstractMetaClassCPtr klass{}; +}; + +Q_DECLARE_METATYPE(DefaultValuesFixture) +Q_DECLARE_METATYPE(AbstractMetaType) + +static int populateDefaultValuesFixture(DefaultValuesFixture *fixture) +{ + static const char cppCode[] =R"( +#include <string> +#include <list> + +namespace Namespace { +class Test +{ +public: + enum Enum { enumValue1, enumValue2 }; + + explicit Test(int x = INT_FIELD_1); + explicit Test(const std::string &t = std::string(CHAR_FIELD_1)); + + static void listFunc(std::list<Test> list = std::list<Test>()); + + static const int INT_FIELD_1 = 42; + static const char *CHAR_FIELD_1; + static const Enum DefaultValue = enumValue1; +}; +} // Namespace +)"; + static const char xmlCode[] = R"( +<typesystem package="Foo"> + <namespace-type name='Namespace'> + <value-type name='Test'> + <enum-type name='Enum'/> + </value-type> + </namespace-type> + <container-type name="std::list" type="list"/> +</typesystem> +)"; + + fixture->builder.reset(TestUtil::parse(cppCode, xmlCode, false)); + if (!fixture->builder) + return -1; + + for (const auto &klass : fixture->builder->classes()) { + if (klass->name() == u"Test") { + fixture->klass = klass; + break; + } + } + if (!fixture->klass) + return -2; + + fixture->classType = AbstractMetaType(fixture->klass->typeEntry()); + fixture->classType.decideUsagePattern(); + + for (const auto &f : fixture->klass->findFunctions("Test")) { + if (f->functionType() == AbstractMetaFunction::ConstructorFunction + && f->arguments().size() == 1) { + const auto type = f->arguments().constFirst().type(); + if (type.name() == u"int") + fixture->intType = type; + else + fixture->stringType = type; + } + } + if (fixture->intType.isVoid() || fixture->stringType.isVoid()) + return -3; + + auto listFunc = fixture->klass->findFunction("listFunc"); + if (!listFunc || listFunc->arguments().size() != 1) + return -3; + fixture->listType = listFunc->arguments().constFirst().type(); + + fixture->enumType = AbstractMetaType(fixture->klass->enums().constFirst().typeEntry()); + fixture->enumType.decideUsagePattern(); + return 0; +} + +void TestResolveType::testFixDefaultArguments_data() +{ + DefaultValuesFixture fixture; + const int setupOk = populateDefaultValuesFixture(&fixture); + + QTest::addColumn<DefaultValuesFixture>("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"); + + QTest::newRow("int") << fixture << setupOk + << fixture.intType << "1" << "1"; + QTest::newRow("int-macro") << fixture << setupOk + << fixture.intType << "GL_MACRO" << "GL_MACRO"; + QTest::newRow("int-enum") << fixture << setupOk + << fixture.intType << "enumValue1" << "Namespace::Test::Enum::enumValue1"; + + // Test expansion of container types + QString expected = u"std::list<Namespace::Test>()"_s; + QTest::newRow("list") + << fixture << setupOk << fixture.listType + << expected << expected; + QTest::newRow("partially qualified list") + << fixture << setupOk << fixture.listType + << "std::list<Test>()" << expected; + + // Test field expansion + expected = u"Namespace::Test::INT_FIELD_1"_s; + QTest::newRow("qualified class field") + << fixture << setupOk << fixture.intType + << expected << expected; + QTest::newRow("partially qualified class field") + << fixture << setupOk << fixture.intType + << "Test::INT_FIELD_1" << expected; + QTest::newRow("unqualified class field") + << fixture << setupOk << fixture.intType + << "INT_FIELD_1" << expected; + + // Test field expansion when constructing some class + expected = u"QLatin1String(Namespace::Test::CHAR_FIELD_1)"_s; + QTest::newRow("class from qualified class field") + << fixture << setupOk << fixture.classType + << expected << expected; + QTest::newRow("class from partially qualified class field") + << fixture << setupOk << fixture.classType + << "QLatin1String(Test::CHAR_FIELD_1)" << expected; + QTest::newRow("class from unqualified class field") + << fixture << setupOk << fixture.classType + << "QLatin1String(CHAR_FIELD_1)" << expected; + + // Test field expansion when constructing class itself + expected = u"Namespace::Test(Namespace::Test::CHAR_FIELD_1)"_s; + QTest::newRow("self from qualified class field") + << fixture << setupOk << fixture.classType + << expected << expected; + QTest::newRow("self from partially qualified class field") + << fixture << setupOk << fixture.classType + << "Test(Test::CHAR_FIELD_1)" << expected; + QTest::newRow("self from unqualified class field") + << fixture << setupOk << fixture.classType + << "Test(CHAR_FIELD_1)" << expected; + + // Test enum expansion when constructing class itself + expected = u"Namespace::Test(Namespace::Test::Enum::enumValue1)"_s; + QTest::newRow("self from qualified enum") + << fixture << setupOk << fixture.classType + << expected << expected; + QTest::newRow("self from enum") + << fixture << setupOk << fixture.classType + << "Test(enumValue1)" << expected; + + // Don't qualify fields to "Test::Enum::DefaultValue" + QTest::newRow("enum from static field") + << fixture << setupOk << fixture.enumType + << "DefaultValue" << u"Namespace::Test::DefaultValue"_s; +} + +void TestResolveType::testFixDefaultArguments() +{ + QFETCH(DefaultValuesFixture, fixture); + QFETCH(int, setupOk); + QFETCH(AbstractMetaType, metaType); + QFETCH(QString, input); + QFETCH(QString, expected); + QCOMPARE(setupOk, 0); + const QString actual = fixture.builder->fixDefaultValue(input, metaType, fixture.klass); + QCOMPARE(actual, expected); +} + +// Verify that the typedefs of the C++ 11 integer types (int32_t, ...) +// are seen by the C++ parser, otherwise they are handled as unknown +// primitive types, causing invalid code to be generated. +// (see BuilderPrivate::visitHeader(), +// sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp). +void TestResolveType::testCppTypes() +{ + static const char cppCode[] =R"( +#include <cstdint> + +class Test +{ +public: + explicit Test(int32_t v); +}; +)"; + static const char xmlCode[] = R"( +<typesystem package="Foo"> + <value-type name='Test'/> + <primitive-type name='int32_t'/> +</typesystem> +)"; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(builder); + AbstractMetaClassList classes = builder->classes(); + const auto testClass = AbstractMetaClass::findClass(classes, "Test"); + QVERIFY(testClass); + + auto *tdb = TypeDatabase::instance(); + auto int32TEntry = tdb->findType(u"int32_t"_s); + QVERIFY2(int32TEntry, "int32_t not found"); + QVERIFY(int32TEntry->isPrimitive()); + auto int32T = std::static_pointer_cast<const PrimitiveTypeEntry>(int32TEntry); + auto basicType = basicReferencedTypeEntry(int32T); + QVERIFY2(basicType != int32T, + "Typedef for int32_t not found. Check the system include paths."); +} + +QTEST_APPLESS_MAIN(TestResolveType) diff --git a/sources/shiboken6/ApiExtractor/tests/testresolvetype.h b/sources/shiboken6/ApiExtractor/tests/testresolvetype.h index 62c08bcd7..a07855eab 100644 --- a/sources/shiboken6/ApiExtractor/tests/testresolvetype.h +++ b/sources/shiboken6/ApiExtractor/tests/testresolvetype.h @@ -1,41 +1,21 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTRESOLVETYPE_H #define TESTRESOLVETYPE_H -#include <QObject> +#include <QtCore/QObject> class TestResolveType : public QObject { Q_OBJECT private slots: + void initTestCase(); + void testResolveReturnTypeFromParentScope(); + void testFixDefaultArguments_data(); + void testFixDefaultArguments(); + void testCppTypes(); }; #endif diff --git a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp index 3ad77c86f..f4eecff2c 100644 --- a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp @@ -1,37 +1,16 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testreverseoperators.h" #include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> #include <typesystem.h> +#include <clangparser/compilersupport.h> + +#include <algorithm> void TestReverseOperators::testReverseSum() { @@ -46,16 +25,16 @@ void TestReverseOperators::testReverseSum() </typesystem>"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - QCOMPARE(classA->functions().count(), 4); + QCOMPARE(classA->functions().size(), 4); AbstractMetaFunctionCPtr reverseOp; AbstractMetaFunctionCPtr normalOp; for (const auto &func : classA->functions()) { - if (func->name() == QLatin1String("operator+")) { + if (func->name() == u"operator+") { if (func->isReverseOperator()) reverseOp = func; else @@ -63,12 +42,12 @@ void TestReverseOperators::testReverseSum() } } - QVERIFY(!normalOp.isNull()); + QVERIFY(normalOp); QVERIFY(!normalOp->isReverseOperator()); - QCOMPARE(normalOp->arguments().count(), 1); - QVERIFY(!reverseOp.isNull()); + QCOMPARE(normalOp->arguments().size(), 1); + QVERIFY(reverseOp); QVERIFY(reverseOp->isReverseOperator()); - QCOMPARE(reverseOp->arguments().count(), 1); + QCOMPARE(reverseOp->arguments().size(), 1); } void TestReverseOperators::testReverseSumWithAmbiguity() @@ -88,37 +67,63 @@ void TestReverseOperators::testReverseSumWithAmbiguity() </typesystem>"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - QCOMPARE(classA->functions().count(), 4); + QCOMPARE(classA->functions().size(), 4); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classB); - QCOMPARE(classB->functions().count(), 4); + QCOMPARE(classB->functions().size(), 4); AbstractMetaFunctionCPtr reverseOp; AbstractMetaFunctionCPtr normalOp; for (const auto &func : classB->functions()) { - if (func->name() == QLatin1String("operator+")) { + if (func->name() == u"operator+") { if (func->isReverseOperator()) reverseOp = func; else normalOp = func; } } - QVERIFY(!normalOp.isNull()); + QVERIFY(normalOp); QVERIFY(!normalOp->isReverseOperator()); - QCOMPARE(normalOp->arguments().count(), 1); - QCOMPARE(normalOp->minimalSignature(), QLatin1String("operator+(B,A)")); - QVERIFY(!reverseOp.isNull()); + QCOMPARE(normalOp->arguments().size(), 1); + QCOMPARE(normalOp->minimalSignature(), u"operator+(B,A)"); + QVERIFY(reverseOp); QVERIFY(reverseOp->isReverseOperator()); - QCOMPARE(reverseOp->arguments().count(), 1); - QCOMPARE(reverseOp->minimalSignature(), QLatin1String("operator+(A,B)")); + QCOMPARE(reverseOp->arguments().size(), 1); + QCOMPARE(reverseOp->minimalSignature(), u"operator+(A,B)"); } - +void TestReverseOperators::testSpaceshipOperator() +{ + const char cppCode[] = R"( + class Test { + public: + explicit Test(int v); + int operator<=>(const Test &rhs) const = default; + };)"; + const char xmlCode[] = R"( + <typesystem package="Foo"> + <value-type name='Test'/> + </typesystem>)"; + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, + {}, {}, LanguageLevel::Cpp20)); + QVERIFY(builder); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.size(), 1); + const auto testClass = AbstractMetaClass::findClass(classes, "Test"); + QVERIFY(testClass); + const auto &functions = testClass->functions(); + // 6 operators should be synthesized + const auto count = std::count_if(functions.cbegin(), functions.cend(), + [](const AbstractMetaFunctionCPtr &f) { + return f->isComparisonOperator(); + }); + QCOMPARE(count, 6); +} QTEST_APPLESS_MAIN(TestReverseOperators) diff --git a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h index ba3b43cfb..fb8d97c97 100644 --- a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h +++ b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTREVERSEOPERATORS_H #define TESTREVERSEOPERATORS_H -#include <QObject> +#include <QtCore/QObject> class TestReverseOperators : public QObject { @@ -36,6 +11,7 @@ class TestReverseOperators : public QObject private slots: void testReverseSum(); void testReverseSumWithAmbiguity(); + void testSpaceshipOperator(); }; #endif diff --git a/sources/shiboken6/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken6/ApiExtractor/tests/testtemplates.cpp index aa1d0414c..ea37c6255 100644 --- a/sources/shiboken6/ApiExtractor/tests/testtemplates.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testtemplates.cpp @@ -1,40 +1,23 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testtemplates.h" -#include <QtTest/QTest> -#include <QtCore/QTextStream> -#include <QTemporaryFile> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetafield.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> -#include <typesystem.h> +#include <abstractmetatype.h> +#include <complextypeentry.h> +#include <containertypeentry.h> + +#include <qtcompat.h> + +#include <QtCore/QTemporaryFile> +#include <QtCore/QTextStream> +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; void TestTemplates::testTemplateWithNamespace() { @@ -72,16 +55,16 @@ namespace Internet { </typesystem>)XML").arg(file.fileName()); QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, qPrintable(xmlCode1), false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("Bookmarks")); + const auto classB = AbstractMetaClass::findClass(classes, "Bookmarks"); QVERIFY(classB); - const auto func = classB->findFunction(QLatin1String("list")); - QVERIFY(!func.isNull()); + const auto func = classB->findFunction("list"); + QVERIFY(func); AbstractMetaType funcType = func->type(); QVERIFY(!funcType.isVoid()); - QCOMPARE(funcType.cppSignature(), QLatin1String("QList<Internet::Url >")); + QCOMPARE(funcType.cppSignature(), u"QList<Internet::Url>"); } void TestTemplates::testTemplateOnContainers() @@ -110,26 +93,26 @@ namespace Namespace { </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classB); QVERIFY(!classB->baseClass()); QVERIFY(classB->baseClassName().isEmpty()); - const auto func = classB->findFunction(QLatin1String("foo")); - QVERIFY(!func.isNull()); + const auto func = classB->findFunction("foo"); + QVERIFY(func); AbstractMetaType argType = func->arguments().constFirst().type(); - QCOMPARE(argType.instantiations().count(), 1); - QCOMPARE(argType.typeEntry()->qualifiedCppName(), QLatin1String("QList")); + QCOMPARE(argType.instantiations().size(), 1); + QCOMPARE(argType.typeEntry()->qualifiedCppName(), u"QList"); const AbstractMetaType &instance1 = argType.instantiations().constFirst(); - QCOMPARE(instance1.instantiations().count(), 1); - QCOMPARE(instance1.typeEntry()->qualifiedCppName(), QLatin1String("Namespace::A")); + QCOMPARE(instance1.instantiations().size(), 1); + QCOMPARE(instance1.typeEntry()->qualifiedCppName(), u"Namespace::A"); const AbstractMetaType &instance2 = instance1.instantiations().constFirst(); - QCOMPARE(instance2.instantiations().count(), 0); - QCOMPARE(instance2.typeEntry()->qualifiedCppName(), QLatin1String("Namespace::E1")); + QCOMPARE(instance2.instantiations().size(), 0); + QCOMPARE(instance2.typeEntry()->qualifiedCppName(), u"Namespace::E1"); } void TestTemplates::testTemplateValueAsArgument() @@ -147,14 +130,14 @@ void func(List<int> arg) {} </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); const auto globalFuncs = builder->globalFunctions(); - QCOMPARE(globalFuncs.count(), 1); + QCOMPARE(globalFuncs.size(), 1); const auto func = globalFuncs.constFirst(); - QCOMPARE(func->minimalSignature(), QLatin1String("func(List<int>)")); + QCOMPARE(func->minimalSignature(), u"func(List<int>)"); QCOMPARE(func->arguments().constFirst().type().cppSignature(), - QLatin1String("List<int >")); + u"List<int>"); } void TestTemplates::testTemplatePointerAsArgument() @@ -172,14 +155,14 @@ void func(List<int>* arg) {} </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaFunctionCList globalFuncs = builder->globalFunctions(); - QCOMPARE(globalFuncs.count(), 1); + QCOMPARE(globalFuncs.size(), 1); const auto func = globalFuncs.constFirst(); - QCOMPARE(func->minimalSignature(), QLatin1String("func(List<int>*)")); + QCOMPARE(func->minimalSignature(), u"func(List<int>*)"); QCOMPARE(func->arguments().constFirst().type().cppSignature(), - QLatin1String("List<int > *")); + u"List<int> *"); } void TestTemplates::testTemplateReferenceAsArgument() @@ -197,14 +180,14 @@ void func(List<int>& arg) {} </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); const auto globalFuncs = builder->globalFunctions(); - QCOMPARE(globalFuncs.count(), 1); + QCOMPARE(globalFuncs.size(), 1); const auto func = globalFuncs.constFirst(); - QCOMPARE(func->minimalSignature(), QLatin1String("func(List<int>&)")); + QCOMPARE(func->minimalSignature(), u"func(List<int>&)"); QCOMPARE(func->arguments().constFirst().type().cppSignature(), - QLatin1String("List<int > &")); + u"List<int> &"); } void TestTemplates::testTemplateParameterFixup() @@ -226,22 +209,21 @@ struct List { </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); const AbstractMetaClassList templates = builder->templates(); - QCOMPARE(templates.count(), 1); - const AbstractMetaClass *list = templates.constFirst(); - // Verify that the parameter of "void append(List l)" gets fixed to "List<T >" - const auto append = list->findFunction(QStringLiteral("append")); - QVERIFY(!append.isNull()); + QCOMPARE(templates.size(), 1); + AbstractMetaClassCPtr list = templates.constFirst(); + // Verify that the parameter of "void append(List l)" gets fixed to "List<T>" + const auto append = list->findFunction("append"); + QVERIFY(append); QCOMPARE(append->arguments().size(), 1); - QCOMPARE(append->arguments().at(0).type().cppSignature(), QLatin1String("List<T >")); + QCOMPARE(append->arguments().at(0).type().cppSignature(), u"List<T>"); // Verify that the parameter of "void erase(Iterator)" is not modified - const auto erase = list->findFunction(QStringLiteral("erase")); - QVERIFY(!erase.isNull()); + const auto erase = list->findFunction("erase"); + QVERIFY(erase); QCOMPARE(erase->arguments().size(), 1); - QEXPECT_FAIL("", "Clang: Some other code changes the parameter type", Abort); - QCOMPARE(erase->arguments().at(0).type().cppSignature(), QLatin1String("List::Iterator")); + QCOMPARE(erase->arguments().at(0).type().cppSignature(), u"List::Iterator"); } void TestTemplates::testInheritanceFromContainterTemplate() @@ -267,17 +249,17 @@ struct FooBars : public ListContainer<FooBar> {}; </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); AbstractMetaClassList templates = builder->templates(); - QCOMPARE(classes.count(), 2); - QCOMPARE(templates.count(), 1); + QCOMPARE(classes.size(), 2); + QCOMPARE(templates.size(), 1); - const AbstractMetaClass* foobars = AbstractMetaClass::findClass(classes, QLatin1String("FooBars")); - QCOMPARE(foobars->functions().count(), 4); + const auto foobars = AbstractMetaClass::findClass(classes, "FooBars"); + QCOMPARE(foobars->functions().size(), 4); - const AbstractMetaClass *lc = templates.constFirst(); - QCOMPARE(lc->functions().count(), 2); + AbstractMetaClassCPtr lc = templates.constFirst(); + QCOMPARE(lc->functions().size(), 2); } void TestTemplates::testTemplateInheritanceMixedWithForwardDeclaration() @@ -304,15 +286,15 @@ template<SomeEnum type> struct Future {}; </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classB); QVERIFY(!classB->baseClass()); QVERIFY(classB->baseClassName().isEmpty()); // 3 functions: simple constructor, copy constructor and "method()". - QCOMPARE(classB->functions().count(), 3); + QCOMPARE(classB->functions().size(), 3); } void TestTemplates::testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration() @@ -343,15 +325,15 @@ template<SomeEnum type> struct Future {}; </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("Namespace::B")); + const auto classB = AbstractMetaClass::findClass(classes, "Namespace::B"); QVERIFY(classB); QVERIFY(!classB->baseClass()); QVERIFY(classB->baseClassName().isEmpty()); // 3 functions: simple constructor, copy constructor and "method()". - QCOMPARE(classB->functions().count(), 3); + QCOMPARE(classB->functions().size(), 3); } void TestTemplates::testTypedefOfInstantiationOfTemplateClass() @@ -363,7 +345,7 @@ enum ClassType { }; template<ClassType CLASS_TYPE> struct BaseTemplateClass { - inline ClassType getClassType() const { CLASS_TYPE; } + inline ClassType getClassType() const { return CLASS_TYPE; } }; typedef BaseTemplateClass<TypeOne> TypeOneClass; } @@ -379,30 +361,30 @@ typedef BaseTemplateClass<TypeOne> TypeOneClass; </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 3); + QCOMPARE(classes.size(), 3); - const AbstractMetaClass* base = AbstractMetaClass::findClass(classes, QLatin1String("BaseTemplateClass")); + const auto base = AbstractMetaClass::findClass(classes, "BaseTemplateClass"); QVERIFY(base); - const AbstractMetaClass* one = AbstractMetaClass::findClass(classes, QLatin1String("TypeOneClass")); + const auto one = AbstractMetaClass::findClass(classes, "TypeOneClass"); QVERIFY(one); QCOMPARE(one->templateBaseClass(), base); - QCOMPARE(one->functions().count(), base->functions().count()); + QCOMPARE(one->functions().size(), base->functions().size()); QVERIFY(one->isTypeDef()); - const ComplexTypeEntry* oneType = one->typeEntry(); - const ComplexTypeEntry* baseType = base->typeEntry(); + auto oneType = one->typeEntry(); + auto baseType = base->typeEntry(); QCOMPARE(oneType->baseContainerType(), baseType); - QCOMPARE(one->baseClassNames(), QStringList(QLatin1String("BaseTemplateClass<TypeOne>"))); + QCOMPARE(one->baseClassNames(), QStringList(u"NSpace::BaseTemplateClass<NSpace::TypeOne>"_s)); QVERIFY(one->hasTemplateBaseClassInstantiations()); AbstractMetaTypeList instantiations = one->templateBaseClassInstantiations(); - QCOMPARE(instantiations.count(), 1); + QCOMPARE(instantiations.size(), 1); const AbstractMetaType &inst = instantiations.constFirst(); QVERIFY(!inst.isEnum()); QVERIFY(!inst.typeEntry()->isEnum()); QVERIFY(inst.typeEntry()->isEnumValue()); - QCOMPARE(inst.cppSignature(), QLatin1String("NSpace::TypeOne")); + QCOMPARE(inst.cppSignature(), u"NSpace::TypeOne"); } void TestTemplates::testContainerTypeIncompleteArgument() @@ -428,27 +410,27 @@ typedef Vector<int> IntVector; </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - QCOMPARE(classes.count(), 1); + QCOMPARE(classes.size(), 1); - AbstractMetaClass* vector = AbstractMetaClass::findClass(classes, QLatin1String("IntVector")); + const auto vector = AbstractMetaClass::findClass(classes, "IntVector"); QVERIFY(vector); auto baseContainer = vector->typeEntry()->baseContainerType(); QVERIFY(baseContainer); - QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(baseContainer)->containerKind(), + QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(baseContainer.get())->containerKind(), ContainerTypeEntry::ListContainer); - QCOMPARE(vector->functions().count(), 4); + QCOMPARE(vector->functions().size(), 4); - const auto method = vector->findFunction(QLatin1String("method")); - QVERIFY(!method.isNull()); - QCOMPARE(method->signature(), QLatin1String("method(const Vector<int > & vector)")); + const auto method = vector->findFunction("method"); + QVERIFY(method); + QCOMPARE(method->signature(), u"method(const Vector<int> & vector)"); - const auto otherMethod = vector->findFunction(QLatin1String("otherMethod")); - QVERIFY(!otherMethod.isNull()); - QCOMPARE(otherMethod->signature(), QLatin1String("otherMethod()")); + const auto otherMethod = vector->findFunction("otherMethod"); + QVERIFY(otherMethod); + QCOMPARE(otherMethod->signature(), u"otherMethod()"); QVERIFY(!otherMethod->type().isVoid()); - QCOMPARE(otherMethod->type().cppSignature(), QLatin1String("Vector<int >")); + QCOMPARE(otherMethod->type().cppSignature(), u"Vector<int>"); } void TestTemplates::testNonTypeTemplates() @@ -472,12 +454,12 @@ Array<int, 2> foo(); </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); auto functions = builder->globalFunctions(); - QCOMPARE(functions.count(), 1); + QCOMPARE(functions.size(), 1); auto foo = functions.constFirst(); - QCOMPARE(foo->name(), QLatin1String("foo")); - QCOMPARE(foo->type().name(), QLatin1String("Array")); + QCOMPARE(foo->name(), u"foo"); + QCOMPARE(foo->type().name(), u"Array"); } // Perform checks on template inheritance; a typedef of a template class @@ -555,44 +537,42 @@ void TestTemplates::testTemplateTypeDefs() const QByteArray cppBa = cpp.toLocal8Bit(); const QByteArray xmlBa = xml.toLocal8Bit(); QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppBa.constData(), xmlBa.constData(), true)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *optional = AbstractMetaClass::findClass(classes, QLatin1String("Optional")); + const auto optional = AbstractMetaClass::findClass(classes, "Optional"); QVERIFY(optional); // Find the typedef'ed class - const AbstractMetaClass *optionalInt = - AbstractMetaClass::findClass(classes, QLatin1String("IntOptional")); + const auto optionalInt = AbstractMetaClass::findClass(classes, "IntOptional"); QVERIFY(optionalInt); QCOMPARE(optionalInt->templateBaseClass(), optional); // Find the class typedef'ed in the typesystem XML - const AbstractMetaClass *xmlOptionalInt = - AbstractMetaClass::findClass(classes, QLatin1String("XmlIntOptional")); + const auto xmlOptionalInt = AbstractMetaClass::findClass(classes, "XmlIntOptional"); QVERIFY(xmlOptionalInt); QCOMPARE(xmlOptionalInt->templateBaseClass(), optional); // Check whether the value() method now has an 'int' return - const auto valueMethod = optionalInt->findFunction(QLatin1String("value")); - QVERIFY(!valueMethod.isNull()); - QCOMPARE(valueMethod->type().cppSignature(), QLatin1String("int")); + const auto valueMethod = optionalInt->findFunction("value"); + QVERIFY(valueMethod); + QCOMPARE(valueMethod->type().cppSignature(), u"int"); // ditto for typesystem XML - const auto xmlValueMethod = xmlOptionalInt->findFunction(QLatin1String("value")); - QVERIFY(!xmlValueMethod.isNull()); - QCOMPARE(xmlValueMethod->type().cppSignature(), QLatin1String("int")); + const auto xmlValueMethod = xmlOptionalInt->findFunction("value"); + QVERIFY(xmlValueMethod); + QCOMPARE(xmlValueMethod->type().cppSignature(), u"int"); // Check whether the m_value field is of type 'int' - const auto valueField = optionalInt->findField(QLatin1String("m_value")); + const auto valueField = optionalInt->findField(u"m_value"); QVERIFY(valueField.has_value()); - QCOMPARE(valueField->type().cppSignature(), QLatin1String("int")); + QCOMPARE(valueField->type().cppSignature(), u"int"); // ditto for typesystem XML const auto xmlValueField = - xmlOptionalInt->findField(QLatin1String("m_value")); + xmlOptionalInt->findField(u"m_value"); QVERIFY(xmlValueField.has_value()); - QCOMPARE(xmlValueField->type().cppSignature(), QLatin1String("int")); + QCOMPARE(xmlValueField->type().cppSignature(), u"int"); } void TestTemplates::testTemplateTypeAliases() @@ -626,22 +606,23 @@ public: </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - auto testClass = AbstractMetaClass::findClass(classes, QLatin1String("Test")); + const auto testClass = AbstractMetaClass::findClass(classes, "Test"); QVERIFY(testClass); auto fields = testClass->fields(); - QCOMPARE(fields.count(), 1); + QCOMPARE(fields.size(), 1); auto fieldType = testClass->fields().at(0).type(); - QCOMPARE(fieldType.name(), QLatin1String("Container1")); + QCOMPARE(fieldType.name(), u"Container1"); QCOMPARE(fieldType.instantiations().size(), 1); - auto derived = AbstractMetaClass::findClass(classes, QLatin1String("Derived")); + const auto derived = AbstractMetaClass::findClass(classes, "Derived"); QVERIFY(derived); auto base = derived->templateBaseClass(); - QCOMPARE(base->name(), QLatin1String("Container1")); + QVERIFY(base); + QCOMPARE(base->name(), u"Container1"); } QTEST_APPLESS_MAIN(TestTemplates) diff --git a/sources/shiboken6/ApiExtractor/tests/testtemplates.h b/sources/shiboken6/ApiExtractor/tests/testtemplates.h index c96e7fe4a..36800f723 100644 --- a/sources/shiboken6/ApiExtractor/tests/testtemplates.h +++ b/sources/shiboken6/ApiExtractor/tests/testtemplates.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTTEMPLATES_H #define TESTTEMPLATES_H -#include <QObject> +#include <QtCore/QObject> class TestTemplates : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testtoposort.cpp b/sources/shiboken6/ApiExtractor/tests/testtoposort.cpp index 6126c2b42..50cefcfe9 100644 --- a/sources/shiboken6/ApiExtractor/tests/testtoposort.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testtoposort.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testtoposort.h" #include "graph.h" diff --git a/sources/shiboken6/ApiExtractor/tests/testtoposort.h b/sources/shiboken6/ApiExtractor/tests/testtoposort.h index 012156dc9..4271d6a0e 100644 --- a/sources/shiboken6/ApiExtractor/tests/testtoposort.h +++ b/sources/shiboken6/ApiExtractor/tests/testtoposort.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTTOPOSORT_H #define TESTTOPOSORT_H -#include <QObject> +#include <QtCore/QObject> class TestTopoSort : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp b/sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp index d8170f5e8..72dae8cc5 100644 --- a/sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp @@ -1,45 +1,27 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testtyperevision.h" -#include <QtTest/QTest> #include "testutil.h" #include <abstractmetaenum.h> #include <abstractmetalang.h> -#include <typesystem.h> +#include <complextypeentry.h> +#include <enumtypeentry.h> +#include <flagstypeentry.h> #include <typedatabase.h> +#include <qtcompat.h> + +#include <QtTest/QTest> + +using namespace Qt::StringLiterals; + void TestTypeRevision::testRevisionAttr() { - const char* cppCode = "class Rev_0 {};" + const char cppCode[] = "class Rev_0 {};" "class Rev_1 {};" "class Rev_2 { public: enum Rev_3 { X }; enum Rev_5 { Y }; };"; - const char* xmlCode = "<typesystem package=\"Foo\">" + const char xmlCode[] = "<typesystem package=\"Foo\">" "<value-type name=\"Rev_0\"/>" "<value-type name=\"Rev_1\" revision=\"1\"/>" "<object-type name=\"Rev_2\" revision=\"2\">" @@ -48,25 +30,25 @@ void TestTypeRevision::testRevisionAttr() "</object-type>" "</typesystem>"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *rev0 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_0")); + const auto rev0 = AbstractMetaClass::findClass(classes, "Rev_0"); QCOMPARE(rev0->typeEntry()->revision(), 0); - const AbstractMetaClass *rev1 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_1")); + const auto rev1 = AbstractMetaClass::findClass(classes, "Rev_1"); QCOMPARE(rev1->typeEntry()->revision(), 1); - AbstractMetaClass *rev2 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_2")); + const auto rev2 = AbstractMetaClass::findClass(classes, "Rev_2"); QCOMPARE(rev2->typeEntry()->revision(), 2); - auto rev3 = rev2->findEnum(QLatin1String("Rev_3")); + auto rev3 = rev2->findEnum(u"Rev_3"_s); QVERIFY(rev3.has_value()); QCOMPARE(rev3->typeEntry()->revision(), 3); - FlagsTypeEntry* rev4 = rev3->typeEntry()->flags(); + auto rev4 = rev3->typeEntry()->flags(); QCOMPARE(rev4->revision(), 4); - auto rev5 = rev2->findEnum(QLatin1String("Rev_5")); + auto rev5 = rev2->findEnum(u"Rev_5"_s); QVERIFY(rev5.has_value()); - const EnumTypeEntry *revEnumTypeEntry = rev5->typeEntry(); + EnumTypeEntryCPtr revEnumTypeEntry = rev5->typeEntry(); QCOMPARE(revEnumTypeEntry->revision(), 5); QCOMPARE(revEnumTypeEntry->flags()->revision(), 5); } @@ -100,7 +82,7 @@ class Bar20 {}; )XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, version)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); QCOMPARE(builder->classes().size(), expectedClassCount); } diff --git a/sources/shiboken6/ApiExtractor/tests/testtyperevision.h b/sources/shiboken6/ApiExtractor/tests/testtyperevision.h index 3832c3883..84af839d2 100644 --- a/sources/shiboken6/ApiExtractor/tests/testtyperevision.h +++ b/sources/shiboken6/ApiExtractor/tests/testtyperevision.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTTYPEREVISION_H #define TESTTYPEREVISION_H -#include <QObject> +#include <QtCore/QObject> class TestTypeRevision : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testutil.h b/sources/shiboken6/ApiExtractor/tests/testutil.h index 56ce8a72e..dc4e3b2da 100644 --- a/sources/shiboken6/ApiExtractor/tests/testutil.h +++ b/sources/shiboken6/ApiExtractor/tests/testutil.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTUTIL_H #define TESTUTIL_H @@ -43,27 +18,28 @@ namespace TestUtil { static AbstractMetaBuilder *parse(const char *cppCode, const char *xmlCode, bool silent = true, - const QString &apiVersion = QString(), - const QStringList &dropTypeEntries = QStringList()) + const QString &apiVersion = {}, + const QStringList &dropTypeEntries = {}, + LanguageLevel languageLevel = LanguageLevel::Default) { ReportHandler::setSilent(silent); ReportHandler::startTimer(); - TypeDatabase* td = TypeDatabase::instance(true); + auto *td = TypeDatabase::instance(true); if (apiVersion.isEmpty()) TypeDatabase::clearApiVersions(); - else if (!TypeDatabase::setApiVersion(QLatin1String("*"), apiVersion)) + else if (!TypeDatabase::setApiVersion(QLatin1StringView("*"), apiVersion)) return nullptr; td->setDropTypeEntries(dropTypeEntries); QBuffer buffer; // parse typesystem buffer.setData(xmlCode); if (!buffer.open(QIODevice::ReadOnly)) - return Q_NULLPTR; + return nullptr; if (!td->parseFile(&buffer)) return nullptr; buffer.close(); // parse C++ code - QTemporaryFile tempSource(QDir::tempPath() + QLatin1String("/st_XXXXXX_main.cpp")); + QTemporaryFile tempSource(QDir::tempPath() + QLatin1StringView("/st_XXXXXX_main.cpp")); if (!tempSource.open()) { qWarning().noquote().nospace() << "Creation of temporary file failed: " << tempSource.errorString(); @@ -76,7 +52,7 @@ namespace TestUtil auto builder = std::make_unique<AbstractMetaBuilder>(); try { - if (!builder->build(arguments)) + if (!builder->build(arguments, {}, true, languageLevel)) return nullptr; } catch (const std::exception &e) { qWarning("%s", e.what()); diff --git a/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp index 1850025d6..98e30eac2 100644 --- a/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp @@ -1,62 +1,37 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testvaluetypedefaultctortag.h" #include <QtTest/QTest> #include "testutil.h" #include <abstractmetalang.h> -#include <typesystem.h> +#include <complextypeentry.h> void TestValueTypeDefaultCtorTag::testValueTypeDefaultCtorTagArgument() { - const char* cppCode ="\n\ + const char cppCode[] = "\n\ struct A {\n\ A(int,int);\n\ };\n\ struct B {};\n\ "; - const char* xmlCode = "\n\ + const char xmlCode[] = "\n\ <typesystem package='Foo'>\n\ <primitive-type name='int' />\n\ <value-type name='A' default-constructor='A(0, 0)' />\n\ <value-type name='B' />\n\ </typesystem>"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); QVERIFY(classA->typeEntry()->hasDefaultConstructor()); - QCOMPARE(classA->typeEntry()->defaultConstructor(), QLatin1String("A(0, 0)")); + QCOMPARE(classA->typeEntry()->defaultConstructor(), u"A(0, 0)"); - const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + const auto classB = AbstractMetaClass::findClass(classes, "B"); QVERIFY(classB); QVERIFY(!classB->typeEntry()->hasDefaultConstructor()); } diff --git a/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h index 244181707..192c07c1d 100644 --- a/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h +++ b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTVALUETYPEDEFAULTCTORTAG_H #define TESTVALUETYPEDEFAULTCTORTAG_H -#include <QObject> +#include <QtCore/QObject> class TestValueTypeDefaultCtorTag : public QObject { diff --git a/sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp b/sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp index 6d155dacc..a600181a5 100644 --- a/sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp +++ b/sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp @@ -1,34 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "testvoidarg.h" #include <QtTest/QTest> #include "testutil.h" +#include <abstractmetaargument.h> #include <abstractmetafunction.h> #include <abstractmetalang.h> #include <typesystem.h> @@ -41,13 +17,13 @@ void TestVoidArg::testVoidParsedFunction() <value-type name='A'/>\n\ </typesystem>"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const auto addedFunc = classA->findFunction(QLatin1String("a")); - QVERIFY(!addedFunc.isNull()); - QCOMPARE(addedFunc->arguments().count(), 0); + const auto addedFunc = classA->findFunction("a"); + QVERIFY(addedFunc); + QCOMPARE(addedFunc->arguments().size(), 0); } void TestVoidArg::testVoidAddedFunction() @@ -60,13 +36,13 @@ void TestVoidArg::testVoidAddedFunction() </value-type>\n\ </typesystem>"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const auto addedFunc = classA->findFunction(QLatin1String("a")); - QVERIFY(!addedFunc.isNull()); - QCOMPARE(addedFunc->arguments().count(), 0); + const auto addedFunc = classA->findFunction("a"); + QVERIFY(addedFunc); + QCOMPARE(addedFunc->arguments().size(), 0); } @@ -78,13 +54,13 @@ void TestVoidArg::testVoidPointerParsedFunction() <value-type name='A' />\n\ </typesystem>"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); - QVERIFY(!builder.isNull()); + QVERIFY(builder); AbstractMetaClassList classes = builder->classes(); - const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); + const auto classA = AbstractMetaClass::findClass(classes, "A"); QVERIFY(classA); - const auto addedFunc = classA->findFunction(QLatin1String("a")); - QVERIFY(!addedFunc.isNull()); - QCOMPARE(addedFunc->arguments().count(), 1); + const auto addedFunc = classA->findFunction("a"); + QVERIFY(addedFunc); + QCOMPARE(addedFunc->arguments().size(), 1); } diff --git a/sources/shiboken6/ApiExtractor/tests/testvoidarg.h b/sources/shiboken6/ApiExtractor/tests/testvoidarg.h index 44d90d075..191b9cfb2 100644 --- a/sources/shiboken6/ApiExtractor/tests/testvoidarg.h +++ b/sources/shiboken6/ApiExtractor/tests/testvoidarg.h @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TESTVOIDARG_H #define TESTVOIDARG_H -#include <QObject> +#include <QtCore/QObject> class TestVoidArg : public QObject { diff --git a/sources/shiboken6/ApiExtractor/textstream.cpp b/sources/shiboken6/ApiExtractor/textstream.cpp index 364634f2d..83d981b2b 100644 --- a/sources/shiboken6/ApiExtractor/textstream.cpp +++ b/sources/shiboken6/ApiExtractor/textstream.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "textstream.h" @@ -75,6 +50,12 @@ qint64 TextStream::pos() const return m_str.pos(); } +void TextStream::setString(QString *string, QIODeviceBase::OpenMode openMode) +{ + m_str.setString(string, openMode); + m_rstFormattingEnd = false; +} + void TextStream::putRepetitiveChars(char c, int count) { if (count > 0) { @@ -87,6 +68,11 @@ void TextStream::putRepetitiveChars(char c, int count) } } +void TextStream::_setRstFormattingEnd() +{ + m_rstFormattingEnd = true; +} + void TextStream::setLastCharClass(CharClass c) { m_lastCharClass = c; @@ -110,6 +96,11 @@ static TextStream::CharClass charClassHelper(Char c) return TextStream::CharClass::NewLine; case '#': return TextStream::CharClass::Hash; + case ' ': + case '\t': + return TextStream::CharClass::Space; + case '\\': + return TextStream::CharClass::BackSlash; default: break; } @@ -124,6 +115,13 @@ static inline TextStream::CharClass charClass(QChar c) void TextStream::checkIndent(CharClass upComingCharClass) { + if (m_rstFormattingEnd) { + if (upComingCharClass != CharClass::Space && upComingCharClass != CharClass::NewLine + && upComingCharClass != CharClass::BackSlash) { + m_str << '\\'; + } + m_rstFormattingEnd = false; + } if (m_indentationEnabled && m_lastCharClass == CharClass::NewLine && (upComingCharClass != CharClass::NewLine && (m_language != Language::Cpp || upComingCharClass != CharClass::Hash))) { @@ -135,7 +133,8 @@ void TextStream::checkIndent(CharClass upComingCharClass) template <class Char> void TextStream::putCharHelper(Char c) { - checkIndent(charClass(c)); + const auto klass = charClass(c); + checkIndent(klass); m_str << c; } @@ -150,7 +149,8 @@ void TextStream::putString(QStringView v) // If there is no newline, write as a blob. This is important to make // field formatting (alignment/width) working, else each char will be // considered a field. - checkIndent(charClass(*v.cbegin())); + const auto klass = charClass(*v.cbegin()); + checkIndent(klass); m_str << v; m_lastCharClass = CharClass::Other; } @@ -225,6 +225,39 @@ void disableIndent(TextStream &s) void ensureEndl(TextStream &s) { - if (s.lastChar() != QLatin1Char('\n')) + if (s.lastChar() != u'\n') s << '\n'; } + +void rstBold(TextStream &s) +{ + s.putRawString("**"); +} + +void rstBoldOff(TextStream &s) +{ + s.putRawString("**"); + s._setRstFormattingEnd(); +} + +void rstItalic(TextStream &s) +{ + s.putRawChar('*'); +} + +void rstItalicOff(TextStream &s) +{ + s.putRawChar('*'); + s._setRstFormattingEnd(); +} + +void rstCode(TextStream &s) +{ + s.putRawString("``"); +} + +void rstCodeOff(TextStream &s) +{ + s.putRawString("``"); + s._setRstFormattingEnd(); +} diff --git a/sources/shiboken6/ApiExtractor/textstream.h b/sources/shiboken6/ApiExtractor/textstream.h index dff79b939..228f36405 100644 --- a/sources/shiboken6/ApiExtractor/textstream.h +++ b/sources/shiboken6/ApiExtractor/textstream.h @@ -1,35 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TEXTSTREAM_H #define TEXTSTREAM_H #include <QtCore/QTextStream> +#include <QtCore/QString> /// A text stream based on QTextStream with built-in indent. class TextStream @@ -46,7 +22,7 @@ public: enum class CharClass { - Other, NewLine, Hash + Other, NewLine, Space, Hash, BackSlash }; explicit TextStream(QIODevice *device, Language l = Language::None); @@ -55,7 +31,7 @@ public: virtual ~TextStream(); Language language() const { return m_language; } - void setLanguage(const Language &language) { m_language = language; } + void setLanguage(Language language) { m_language = language; } bool isIndentationEnabled() const { return m_indentationEnabled; } void setIndentationEnabled(bool m) @@ -79,8 +55,7 @@ public: { return m_str.fieldAlignment(); } void setFieldAlignment(QTextStream::FieldAlignment al) { m_str.setFieldAlignment(al); } - void setString(QString *string, QIODeviceBase::OpenMode openMode = QIODeviceBase::ReadWrite) - { m_str.setString(string, openMode); } + void setString(QString *string, QIODeviceBase::OpenMode openMode = QIODeviceBase::ReadWrite); QString *string() const { return m_str.string(); } void flush() { m_str.flush(); } void setDevice(QIODevice *device) { m_str.setDevice(device); } @@ -98,7 +73,14 @@ public: void putInt(int t); void putSizeType(qsizetype t); + void putRawString(const char *s) { m_str << s; } + void putRawChar(char c) { m_str << c; } + TextStream &operator<<(QStringView v) { putString(v); return *this; } + TextStream &operator<<(const QString &qs) { putString(QStringView{qs}); return *this; } + TextStream &operator<<(QLatin1StringView lv) { putString(lv.constData()); return *this; } + TextStream &operator<<(QUtf8StringView uv) { putString(uv.data()); return *this; } + TextStream &operator<<(const QByteArray &ba) { putString(ba.constData()); return *this; } TextStream &operator<<(QChar c) { putChar(c); return *this; } TextStream &operator<<(const char *s) { putString(s); return *this; } TextStream &operator<<(char c) { putChar(c); return *this; } @@ -107,11 +89,13 @@ public: TextStream &operator<<(qsizetype t) { putSizeType(t); return *this; } #endif - inline TextStream &operator<<(QTextStreamManipulator m) { m_str << m; return *this; } + inline TextStream &operator<<(const QTextStreamManipulator &m) { m_str << m; return *this; } inline TextStream &operator<<(ManipulatorFunc f) { f(*this); return *this; } void putRepetitiveChars(char c, int count); + void _setRstFormattingEnd(); + protected: void setLastCharClass(CharClass c); @@ -126,6 +110,7 @@ private: int m_tabWidth = 4; int m_indentation = 0; bool m_indentationEnabled = true; + bool m_rstFormattingEnd = false; // just past some **bla** where '\' needs to be enforced Language m_language; }; @@ -152,6 +137,19 @@ void disableIndent(TextStream &s); // Works only for streams on strings void ensureEndl(TextStream &s); +void rstBold(TextStream &s); +void rstBoldOff(TextStream &s); +void rstCode(TextStream &s); +void rstCodeOff(TextStream &s); +void rstItalic(TextStream &s); +void rstItalicOff(TextStream &s); + +inline TextStream &operator<<(TextStream &str, QAnyStringView asv) +{ + asv.visit([&str](auto s) { str << s; }); + return str; +} + /// Format an aligned field template <class T> class AlignedField @@ -191,6 +189,28 @@ TextStream &operator<<(TextStream &str, const AlignedField<T> &fa) return str; } +class Pad +{ +public: + explicit Pad(char c, int count) : m_char(c), m_count(count) {} + + void write(TextStream &str) const + { + for (int i = 0; i < m_count; ++i) + str << m_char; + } + +private: + const char m_char; + const int m_count; +}; + +inline TextStream &operator<<(TextStream &str, const Pad &pad) +{ + pad.write(str); + return str; +} + class Indentation { public: diff --git a/sources/shiboken6/ApiExtractor/typedatabase.cpp b/sources/shiboken6/ApiExtractor/typedatabase.cpp index 8a4e6d2f1..749c4baa3 100644 --- a/sources/shiboken6/ApiExtractor/typedatabase.cpp +++ b/sources/shiboken6/ApiExtractor/typedatabase.cpp @@ -1,71 +1,317 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "typedatabase.h" -#include "typesystem.h" -#include "typesystemparser.h" +#include "abstractmetatype.h" +#include "addedfunction.h" +#include "messages.h" +#include "typesystemparser_p.h" +#include "complextypeentry.h" +#include "constantvaluetypeentry.h" +#include "containertypeentry.h" +#include "customtypenentry.h" +#include "debughelpers_p.h" +#include "exception.h" +#include "flagstypeentry.h" +#include "functiontypeentry.h" +#include "namespacetypeentry.h" +#include "objecttypeentry.h" +#include "primitivetypeentry.h" +#include "optionsparser.h" +#include "pythontypeentry.h" +#include "smartpointertypeentry.h" +#include "typedefentry.h" +#include "typesystemtypeentry.h" +#include "varargstypeentry.h" +#include "voidtypeentry.h" #include "conditionalstreamreader.h" +#include "predefined_templates.h" +#include "clangparser/compilersupport.h" +#include "modifications.h" +#include "qtcompat.h" + +#include <QtCore/QBuffer> #include <QtCore/QFile> #include <QtCore/QDebug> #include <QtCore/QDir> -#include <QtCore/QPair> #include <QtCore/QList> #include <QtCore/QRegularExpression> #include <QtCore/QVersionNumber> #include <QtCore/QXmlStreamReader> #include "reporthandler.h" -// #include <tr1/tuple> + #include <algorithm> +#include <utility> + +using namespace Qt::StringLiterals; + +using TypeDatabaseParserContextPtr = std::shared_ptr<TypeDatabaseParserContext>; // package -> api-version static QString wildcardToRegExp(QString w) { - w.replace(QLatin1Char('?'), QLatin1Char('.')); - w.replace(QLatin1Char('*'), QStringLiteral(".*")); + w.replace(u'?', u'.'); + w.replace(u'*', ".*"_L1); return w; } -using ApiVersion =QPair<QRegularExpression, QVersionNumber>; +using ApiVersion = std::pair<QRegularExpression, QVersionNumber>; using ApiVersions = QList<ApiVersion>; Q_GLOBAL_STATIC(ApiVersions, apiVersions) -TypeDatabase::TypeDatabase() +struct PythonType +{ + QString name; + QString checkFunction; + TypeSystem::CPythonType type; +}; + +using PythonTypes = QList<PythonType>; + +static const PythonTypes &builtinPythonTypes() +{ + static const PythonTypes result{ + // "Traditional" custom types + // numpy + {u"PyArrayObject"_s, u"PyArray_Check"_s, TypeSystem::CPythonType::Other}, + {u"PyBuffer"_s, u"Shiboken::Buffer::checkType"_s, TypeSystem::CPythonType::Other}, + {u"PyByteArray"_s, u"PyByteArray_Check"_s, TypeSystem::CPythonType::Other}, + {u"PyBytes"_s, u"PyBytes_Check"_s, TypeSystem::CPythonType::Other}, + {u"PyCallable"_s, u"PyCallable_Check"_s, TypeSystem::CPythonType::Other}, + {u"PyDate"_s, u"PyDate_Check"_s, TypeSystem::CPythonType::Other}, + {u"PyDateTime"_s, u"PyDateTime_Check_Check"_s, TypeSystem::CPythonType::Other}, + {u"PyDict"_s, u"PyDict_Check"_s, TypeSystem::CPythonType::Other}, + // Convenience macro in sbkconverter.h + {u"PyObject"_s, u"true"_s, TypeSystem::CPythonType::Other}, + // shiboken-specific + {u"PyPathLike"_s, u"Shiboken::String::checkPath"_s, TypeSystem::CPythonType::Other}, + {u"PySequence"_s, u"Shiboken::String::checkIterable"_s, TypeSystem::CPythonType::Other}, + {u"PyUnicode"_s, u"PyUnicode_Check"_s, TypeSystem::CPythonType::String}, + {u"PyTypeObject"_s, u"PyType_Check"_s, TypeSystem::CPythonType::Other}, + {u"str"_s, u"Shiboken::String::check"_s, TypeSystem::CPythonType::String}, + // Types used as target lang API types for primitive types + {u"PyBool"_s, u"PyBool_Check"_s, TypeSystem::CPythonType::Bool}, + {u"PyComplex"_s, u"PyComplex_Check"_s, TypeSystem::CPythonType::Other}, + {u"PyLong"_s, u"PyLong_Check"_s, TypeSystem::CPythonType::Integer}, + {u"PyFloat"_s, u"PyFloat_Check"_s, TypeSystem::CPythonType::Float}, + // Single character strings to match C++ char types + {u"SbkChar"_s, u"SbkChar_Check"_s, TypeSystem::CPythonType::String} + }; + return result; +} + +struct SuppressedWarning +{ + QRegularExpression pattern; + QString rawText; + bool generate; // Current type system + mutable bool matched = false; +}; + +QList<OptionDescription> TypeDatabase::options() +{ + return { + {u"api-version=<\"package mask\">,<\"version\">"_s, + u"Specify the supported api version used to generate the bindings"_s}, + {u"drop-type-entries=\"<TypeEntry0>[;TypeEntry1;...]\""_s, + u"Semicolon separated list of type system entries (classes, namespaces,\n" + "global functions and enums) to be dropped from generation."_s}, + {u"-T<path>"_s, {} }, + {u"typesystem-paths="_s + OptionsParser::pathSyntax(), + u"Paths used when searching for typesystems"_s}, + {u"force-process-system-include-paths="_s + OptionsParser::pathSyntax(), + u"Include paths that are considered as system headers by the C++ parser, but should still " + "be processed to extract types (e.g. Qt include paths in a yocto sysroot)"_s}, + {u"keywords=keyword1[,keyword2,...]"_s, + u"A comma-separated list of keywords for conditional typesystem parsing"_s}, + }; +} + +struct TypeDatabaseOptions +{ + QStringList m_dropTypeEntries; + QStringList m_forceProcessSystemIncludes; + QStringList m_typesystemKeywords; + QStringList m_typesystemPaths; + bool m_suppressWarnings = true; +}; + +class TypeDatabaseOptionsParser : public OptionsParser +{ +public: + explicit TypeDatabaseOptionsParser(TypeDatabaseOptions *o) : m_options(o) {} + + bool handleBoolOption(const QString &key, OptionSource source) override; + bool handleOption(const QString &key, const QString &value, OptionSource source) override; + +private: + TypeDatabaseOptions *m_options; +}; + +bool TypeDatabaseOptionsParser::handleBoolOption(const QString &key, OptionSource source) +{ + switch (source) { + case OptionSource::CommandLine: + case OptionSource::ProjectFile: + if (key == u"no-suppress-warnings") { + m_options->m_suppressWarnings = false; + return true; + } + break; + case OptionSource::CommandLineSingleDash: + if (key.startsWith(u'T')) { // "-T/path" ends up a bool option + m_options->m_typesystemPaths += key.sliced(1).split(QDir::listSeparator(), + Qt::SkipEmptyParts); + return true; + } + break; + } + return false; +} + +bool TypeDatabaseOptionsParser::handleOption(const QString &key, const QString &value, + OptionSource source) +{ + if (source == OptionSource::CommandLineSingleDash) + return false; + if (key == u"api-version") { + const auto fullVersions = QStringView{value}.split(u'|'); + for (const auto &fullVersion : fullVersions) { + const auto parts = fullVersion.split(u','); + const QString package = parts.size() == 1 + ? u"*"_s : parts.constFirst().toString(); + const QString version = parts.constLast().toString(); + if (!TypeDatabase::setApiVersion(package, version)) + throw Exception(msgInvalidVersion(package, version)); + } + return true; + } + + if (key == u"drop-type-entries") { + m_options->m_dropTypeEntries = value.split(u';'); + m_options->m_dropTypeEntries.sort(); + return true; + } + + if (key == u"keywords") { + m_options->m_typesystemKeywords = value.split(u','); + return true; + } + + if (key == u"typesystem-paths") { + m_options->m_typesystemPaths += value.split(QDir::listSeparator(), + Qt::SkipEmptyParts); + return true; + } + + if (key == u"force-process-system-include-paths") { + m_options->m_forceProcessSystemIncludes += value.split(QDir::listSeparator(), + Qt::SkipEmptyParts); + return true; + } + + if (source == OptionSource::ProjectFile) { + if (key == u"typesystem-path") { + m_options->m_typesystemPaths += value; + return true; + } + } + + return false; +} + +struct TypeDatabasePrivate : public TypeDatabaseOptions +{ + TypeSystemTypeEntryCPtr defaultTypeSystemType() const; + TypeEntryPtr findType(const QString &name) const; + TypeEntryCList findCppTypes(const QString &name) const; + bool addType(TypeEntryPtr e, QString *errorMessage = nullptr); + bool parseFile(QIODevice *device, TypeDatabase *db, bool generate = true); + static bool parseFile(const TypeDatabaseParserContextPtr &context, + QIODevice *device, bool generate = true); + bool parseFile(const TypeDatabaseParserContextPtr &context, + const QString &filename, const QString ¤tPath, bool generate); + bool prepareParsing(QFile &file, const QString &origFileName, + const QString ¤tPath = {}); + + QString modifiedTypesystemFilepath(const QString& tsFile, + const QString ¤tPath) const; + void addBuiltInType(const TypeEntryPtr &e); + PrimitiveTypeEntryPtr addBuiltInPrimitiveType(const QString &name, + const TypeSystemTypeEntryCPtr &root, + const QString &rootPackage, + const CustomTypeEntryPtr &targetLang); + void addBuiltInCppStringPrimitiveType(const QString &name, + const QString &viewName, + const TypeSystemTypeEntryCPtr &root, + const QString &rootPackage, + const CustomTypeEntryPtr &targetLang); + void addBuiltInPrimitiveTypes(); + void addBuiltInContainerTypes(const TypeDatabaseParserContextPtr &context); + bool addOpaqueContainers(const TypeDatabaseParserContextPtr &context); + TypeEntryMultiMapConstIteratorRange findTypeRange(const QString &name) const; + template <class Predicate> + TypeEntryCList findTypesHelper(const QString &name, Predicate pred) const; + template <class Type, class Predicate> + QList<std::shared_ptr<const Type> > findTypesByTypeHelper(Predicate pred) const; + TypeEntryPtr resolveTypeDefEntry(const TypedefEntryPtr &typedefEntry, QString *errorMessage); + template <class String> + bool isSuppressedWarningHelper(const String &s) const; + bool resolveSmartPointerInstantiations(const TypeDatabaseParserContextPtr &context); + void formatDebug(QDebug &d) const; + void formatBuiltinTypes(QDebug &d) const; + + TypeEntryMultiMap m_entries; // Contains duplicate entries (cf addInlineNamespaceLookups). + TypeEntryMap m_flagsEntries; + TypedefEntryMap m_typedefEntries; + TemplateEntryMap m_templates; + QList<SuppressedWarning> m_suppressedWarnings; + QList<TypeSystemTypeEntryCPtr > m_typeSystemEntries; // maintain order, default is first. + + AddedFunctionList m_globalUserFunctions; + FunctionModificationList m_functionMods; + + QStringList m_requiredTargetImports; + + QHash<QString, bool> m_parsedTypesystemFiles; + + QList<TypeRejection> m_rejections; +}; + +static const char ENV_TYPESYSTEMPATH[] = "TYPESYSTEMPATH"; + +TypeDatabase::TypeDatabase() : d(new TypeDatabasePrivate) +{ + // Environment TYPESYSTEMPATH + if (qEnvironmentVariableIsSet(ENV_TYPESYSTEMPATH)) { + d->m_typesystemPaths + += qEnvironmentVariable(ENV_TYPESYSTEMPATH).split(QDir::listSeparator(), + Qt::SkipEmptyParts); + } + + d->addBuiltInType(TypeEntryPtr(new VoidTypeEntry())); + d->addBuiltInType(TypeEntryPtr(new VarargsTypeEntry())); + for (const auto &pt : builtinPythonTypes()) + d->addBuiltInType(TypeEntryPtr(new PythonTypeEntry(pt.name, pt.checkFunction, pt.type))); + + for (const auto &p : predefinedTemplates()) + addTemplate(p.name, p.content); +} + +TypeDatabase::~TypeDatabase() { - addType(new VoidTypeEntry()); - addType(new VarargsTypeEntry()); + delete d; } -TypeDatabase::~TypeDatabase() = default; +std::shared_ptr<OptionsParser> TypeDatabase::createOptionsParser() +{ + return std::make_shared<TypeDatabaseOptionsParser>(d); +} -TypeDatabase* TypeDatabase::instance(bool newInstance) +TypeDatabase *TypeDatabase::instance(bool newInstance) { static TypeDatabase *db = nullptr; if (!db || newInstance) { @@ -91,12 +337,11 @@ static const IntTypeNormalizationEntries &intTypeNormalizationEntries() static bool firstTime = true; if (firstTime) { firstTime = false; - for (auto t : {"char", "short", "int", "long"}) { - const QString intType = QLatin1String(t); - if (!TypeDatabase::instance()->findType(QLatin1Char('u') + intType)) { + for (const auto &intType : {"char"_L1, "short"_L1, "int"_L1, "long"_L1}) { + if (!TypeDatabase::instance()->findType(u'u' + intType)) { IntTypeNormalizationEntry entry; - entry.replacement = QStringLiteral("unsigned ") + intType; - entry.regex.setPattern(QStringLiteral("\\bu") + intType + QStringLiteral("\\b")); + entry.replacement = "unsigned "_L1 + intType; + entry.regex.setPattern("\\bu"_L1 + intType + "\\b"_L1); Q_ASSERT(entry.regex.isValid()); result.append(entry); } @@ -105,11 +350,64 @@ static const IntTypeNormalizationEntries &intTypeNormalizationEntries() return result; } +// Normalization helpers +enum CharCategory { Space, Identifier, Other }; + +static CharCategory charCategory(QChar c) +{ + if (c.isSpace()) + return Space; + if (c.isLetterOrNumber() || c == u'_') + return Identifier; + return Other; +} + +// Normalize a C++ function signature: +// Drop space except between identifiers ("unsigned int", "const int") +static QString normalizeCppFunctionSignature(const QString &signatureIn) +{ + const QString signature = signatureIn.simplified(); + QString result; + result.reserve(signature.size()); + + CharCategory lastNonSpaceCategory = Other; + bool pendingSpace = false; + for (QChar c : signature) { + if (c.isSpace()) { + pendingSpace = true; + } else { + const auto category = charCategory(c); + if (pendingSpace) { + if (lastNonSpaceCategory == Identifier && category == Identifier) + result.append(u' '); + pendingSpace = false; + } + lastNonSpaceCategory = category; + result.append(c); + } + } + return result; +} + +// Normalize a signature for <add-function> by removing spaces +QString TypeDatabase::normalizedAddedFunctionSignature(const QString &signature) +{ + return normalizeCppFunctionSignature(signature); +} + +// Normalize a signature for matching by <modify-function>/<function> +// by removing spaces and changing const-ref to value. +// FIXME: PYSIDE7: Check whether the above simple normalization can be used +// here as well. Note though that const-ref would then have to be spelled out +// in typeystem XML. QString TypeDatabase::normalizedSignature(const QString &signature) { - QString normalized = QLatin1String(QMetaObject::normalizedSignature(signature.toUtf8().constData())); + // QMetaObject::normalizedSignature() changes const-ref to value and + // changes "unsigned int" to "uint" which is undone by the below code + QByteArray normalizedB = QMetaObject::normalizedSignature(signature.toUtf8().constData()); + QString normalized = QLatin1StringView(normalizedB); - if (instance() && signature.contains(QLatin1String("unsigned"))) { + if (instance() && signature.contains(u"unsigned")) { const IntTypeNormalizationEntries &entries = intTypeNormalizationEntries(); for (const auto &entry : entries) normalized.replace(entry.regex, entry.replacement); @@ -120,141 +418,185 @@ QString TypeDatabase::normalizedSignature(const QString &signature) QStringList TypeDatabase::requiredTargetImports() const { - return m_requiredTargetImports; + return d->m_requiredTargetImports; } void TypeDatabase::addRequiredTargetImport(const QString& moduleName) { - if (!m_requiredTargetImports.contains(moduleName)) - m_requiredTargetImports << moduleName; -} - -void TypeDatabase::addTypesystemPath(const QString& typesystem_paths) -{ - #if defined(Q_OS_WIN32) - const char path_splitter = ';'; - #else - const char path_splitter = ':'; - #endif - m_typesystemPaths += typesystem_paths.split(QLatin1Char(path_splitter)); + if (!d->m_requiredTargetImports.contains(moduleName)) + d->m_requiredTargetImports << moduleName; } QStringList TypeDatabase::typesystemKeywords() const { - QStringList result = m_typesystemKeywords; - for (const auto &d : m_dropTypeEntries) - result.append(QStringLiteral("no_") + d); + QStringList result = d->m_typesystemKeywords; + for (const auto &d : d->m_dropTypeEntries) + result.append("no_"_L1 + d); + + switch (clang::emulatedCompilerLanguageLevel()) { + case LanguageLevel::Cpp11: + result.append(u"c++11"_s); + break; + case LanguageLevel::Cpp14: + result.append(u"c++14"_s); + break; + case LanguageLevel::Cpp17: + result.append(u"c++17"_s); + break; + case LanguageLevel::Cpp20: + result.append(u"c++20"_s); + break; + default: + break; + } return result; } IncludeList TypeDatabase::extraIncludes(const QString& className) const { - ComplexTypeEntry* typeEntry = findComplexType(className); - return typeEntry ? typeEntry->extraIncludes() : IncludeList(); + auto typeEntry = findComplexType(className); + return typeEntry ? typeEntry->extraIncludes() : IncludeList(); } -void TypeDatabase::addSystemInclude(const QString &name) +const QStringList &TypeDatabase::forceProcessSystemIncludes() const { - m_systemIncludes.append(name.toUtf8()); + return d->m_forceProcessSystemIncludes; +} + +void TypeDatabase::addForceProcessSystemInclude(const QString &name) +{ + d->m_forceProcessSystemIncludes.append(name); } // Add a lookup for the short name excluding inline namespaces // so that "std::shared_ptr" finds "std::__1::shared_ptr" as well. -// Note: This inserts duplicate TypeEntry * into m_entries. -void TypeDatabase::addInlineNamespaceLookups(const NamespaceTypeEntry *n) +// Note: This inserts duplicate TypeEntryPtr into m_entries. +void TypeDatabase::addInlineNamespaceLookups(const NamespaceTypeEntryCPtr &n) { TypeEntryList additionalEntries; // Store before modifying the hash - for (TypeEntry *entry : qAsConst(m_entries)) { + for (const auto &entry : std::as_const(d->m_entries)) { if (entry->isChildOf(n)) additionalEntries.append(entry); } - for (const auto &ae : qAsConst(additionalEntries)) - m_entries.insert(ae->shortName(), ae); + for (const auto &ae : std::as_const(additionalEntries)) + d->m_entries.insert(ae->shortName(), ae); } -ContainerTypeEntry* TypeDatabase::findContainerType(const QString &name) const +ContainerTypeEntryPtr TypeDatabase::findContainerType(const QString &name) const { QString template_name = name; - int pos = name.indexOf(QLatin1Char('<')); + const auto pos = name.indexOf(u'<'); if (pos > 0) template_name = name.left(pos); - TypeEntry* type_entry = findType(template_name); + auto type_entry = findType(template_name); if (type_entry && type_entry->isContainer()) - return static_cast<ContainerTypeEntry*>(type_entry); - return nullptr; + return std::static_pointer_cast<ContainerTypeEntry>(type_entry); + return {}; } -static bool inline useType(const TypeEntry *t) +static bool inline useType(const TypeEntryCPtr &t) { return !t->isPrimitive() - || static_cast<const PrimitiveTypeEntry *>(t)->preferredTargetLangType(); + || std::static_pointer_cast<const PrimitiveTypeEntry>(t)->preferredTargetLangType(); } -FunctionTypeEntry* TypeDatabase::findFunctionType(const QString& name) const +FunctionTypeEntryPtr TypeDatabase::findFunctionType(const QString &name) const { - const auto entries = findTypeRange(name); - for (TypeEntry *entry : entries) { + const auto entries = d->findTypeRange(name); + for (const TypeEntryPtr &entry : entries) { if (entry->type() == TypeEntry::FunctionType && useType(entry)) - return static_cast<FunctionTypeEntry*>(entry); + return std::static_pointer_cast<FunctionTypeEntry>(entry); } - return nullptr; + return {}; } -void TypeDatabase::addTypeSystemType(const TypeSystemTypeEntry *e) +void TypeDatabase::addTypeSystemType(const TypeSystemTypeEntryCPtr &e) { - m_typeSystemEntries.append(e); + d->m_typeSystemEntries.append(e); } -const TypeSystemTypeEntry *TypeDatabase::findTypeSystemType(const QString &name) const +TypeSystemTypeEntryCPtr TypeDatabase::findTypeSystemType(const QString &name) const { - for (auto entry : m_typeSystemEntries) { + for (auto entry : d->m_typeSystemEntries) { if (entry->name() == name) return entry; } - return nullptr; + return {}; +} + +TypeSystemTypeEntryCPtr TypeDatabase::defaultTypeSystemType() const +{ + return d->defaultTypeSystemType(); +} + +QString TypeDatabase::loadedTypeSystemNames() const +{ + QString result; + for (const auto &entry : d->m_typeSystemEntries) { + if (!result.isEmpty()) + result += u", "_s; + result += entry->name(); + } + return result; } -const TypeSystemTypeEntry *TypeDatabase::defaultTypeSystemType() const +TypeSystemTypeEntryCPtr TypeDatabasePrivate::defaultTypeSystemType() const { return m_typeSystemEntries.value(0, nullptr); } QString TypeDatabase::defaultPackageName() const { - Q_ASSERT(!m_typeSystemEntries.isEmpty()); - return m_typeSystemEntries.constFirst()->name(); + Q_ASSERT(!d->m_typeSystemEntries.isEmpty()); + return d->m_typeSystemEntries.constFirst()->name(); } -TypeEntry* TypeDatabase::findType(const QString& name) const +TypeEntryPtr TypeDatabase::findType(const QString& name) const +{ + return d->findType(name); +} + +TypeEntryPtr TypeDatabasePrivate::findType(const QString& name) const { const auto entries = findTypeRange(name); - for (TypeEntry *entry : entries) { + for (const auto &entry : entries) { if (useType(entry)) return entry; } - return nullptr; + return {}; } template <class Predicate> -TypeEntries TypeDatabase::findTypesHelper(const QString &name, Predicate pred) const +TypeEntryCList TypeDatabasePrivate::findTypesHelper(const QString &name, Predicate pred) const { - TypeEntries result; + TypeEntryCList result; const auto entries = findTypeRange(name); - for (TypeEntry *entry : entries) { + for (const auto &entry : entries) { if (pred(entry)) result.append(entry); } return result; } -TypeEntries TypeDatabase::findTypes(const QString &name) const +template<class Type, class Predicate> +QList<std::shared_ptr<const Type> > TypeDatabasePrivate::findTypesByTypeHelper(Predicate pred) const +{ + QList<std::shared_ptr<const Type> > result; + for (const auto &entry : m_entries) { + if (pred(entry)) + result.append(std::static_pointer_cast<const Type>(entry)); + } + return result; +} + +TypeEntryCList TypeDatabase::findTypes(const QString &name) const { - return findTypesHelper(name, useType); + return d->findTypesHelper(name, useType); } -static bool useCppType(const TypeEntry *t) +static bool useCppType(const TypeEntryCPtr &t) { bool result = false; switch (t->type()) { @@ -278,37 +620,48 @@ static bool useCppType(const TypeEntry *t) return result; } -TypeEntries TypeDatabase::findCppTypes(const QString &name) const +TypeEntryCList TypeDatabase::findCppTypes(const QString &name) const +{ + return d->findCppTypes(name); +} + +TypeEntryCList TypeDatabasePrivate::findCppTypes(const QString &name) const { return findTypesHelper(name, useCppType); } -TypeEntryMultiMapConstIteratorRange TypeDatabase::findTypeRange(const QString &name) const +const TypeEntryMultiMap &TypeDatabase::entries() const +{ + return d->m_entries; +} + +const TypedefEntryMap &TypeDatabase::typedefEntries() const +{ + return d->m_typedefEntries; +} + +TypeEntryMultiMapConstIteratorRange TypeDatabasePrivate::findTypeRange(const QString &name) const { const auto range = m_entries.equal_range(name); return {range.first, range.second}; } -PrimitiveTypeEntryList TypeDatabase::primitiveTypes() const +PrimitiveTypeEntryCList TypeDatabase::primitiveTypes() const { - PrimitiveTypeEntryList returned; - for (auto it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it) { - TypeEntry *typeEntry = it.value(); - if (typeEntry->isPrimitive()) - returned.append(static_cast<PrimitiveTypeEntry *>(typeEntry)); - } - return returned; + auto pred = [](const TypeEntryCPtr &t) { return t->isPrimitive(); }; + return d->findTypesByTypeHelper<PrimitiveTypeEntry>(pred); } -ContainerTypeEntryList TypeDatabase::containerTypes() const +ContainerTypeEntryCList TypeDatabase::containerTypes() const { - ContainerTypeEntryList returned; - for (auto it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it) { - TypeEntry *typeEntry = it.value(); - if (typeEntry->isContainer()) - returned.append(static_cast<ContainerTypeEntry *>(typeEntry)); - } - return returned; + auto pred = [](const TypeEntryCPtr &t) { return t->isContainer(); }; + return d->findTypesByTypeHelper<ContainerTypeEntry>(pred); +} + +SmartPointerTypeEntryList TypeDatabase::smartPointerTypes() const +{ + auto pred = [](const TypeEntryCPtr &t) { return t->isSmartPointer(); }; + return d->findTypesByTypeHelper<SmartPointerTypeEntry>(pred); } #ifndef QT_NO_DEBUG_STREAM @@ -325,36 +678,15 @@ QDebug operator<<(QDebug d, const TypeRejection &r) void TypeDatabase::addRejection(const TypeRejection &r) { - m_rejections << r; -} - -static inline QString msgRejectReason(const TypeRejection &r, const QString &needle = QString()) -{ - QString result; - QTextStream str(&result); - switch (r.matchType) { - case TypeRejection::ExcludeClass: - str << " matches class exclusion \"" << r.className.pattern() << '"'; - break; - case TypeRejection::Function: - case TypeRejection::Field: - case TypeRejection::Enum: - str << " matches class \"" << r.className.pattern() << "\" and \"" << r.pattern.pattern() << '"'; - break; - case TypeRejection::ArgumentType: - case TypeRejection::ReturnType: - str << " matches class \"" << r.className.pattern() << "\" and \"" << needle - << "\" matches \"" << r.pattern.pattern() << '"'; - break; - } - return result; + d->m_rejections << r; } // Match class name only bool TypeDatabase::isClassRejected(const QString& className, QString *reason) const { - for (const TypeRejection& r : m_rejections) { + for (const TypeRejection& r : d->m_rejections) { if (r.matchType == TypeRejection::ExcludeClass && r.className.match(className).hasMatch()) { + r.matched = true; if (reason) *reason = msgRejectReason(r); return true; @@ -373,6 +705,7 @@ static bool findRejection(const QList<TypeRejection> &rejections, for (const TypeRejection& r : rejections) { if (r.matchType == matchType && r.pattern.match(name).hasMatch() && r.className.match(className).hasMatch()) { + r.matched = true; if (reason) *reason = msgRejectReason(r, name); return true; @@ -383,24 +716,24 @@ static bool findRejection(const QList<TypeRejection> &rejections, bool TypeDatabase::isEnumRejected(const QString& className, const QString& enumName, QString *reason) const { - return findRejection(m_rejections, TypeRejection::Enum, className, enumName, reason); + return findRejection(d->m_rejections, TypeRejection::Enum, className, enumName, reason); } -TypeEntry *TypeDatabase::resolveTypeDefEntry(TypedefEntry *typedefEntry, +TypeEntryPtr TypeDatabasePrivate::resolveTypeDefEntry(const TypedefEntryPtr &typedefEntry, QString *errorMessage) { QString sourceName = typedefEntry->sourceType(); - const int lessThanPos = sourceName.indexOf(QLatin1Char('<')); + const auto lessThanPos = sourceName.indexOf(u'<'); if (lessThanPos != -1) sourceName.truncate(lessThanPos); - ComplexTypeEntry *source = nullptr; - for (TypeEntry *e : findTypeRange(sourceName)) { + ComplexTypeEntryPtr source; + for (const auto &e : findTypeRange(sourceName)) { switch (e->type()) { case TypeEntry::BasicValueType: case TypeEntry::ContainerType: case TypeEntry::ObjectType: case TypeEntry::SmartPointerType: - source = dynamic_cast<ComplexTypeEntry *>(e); + source = std::dynamic_pointer_cast<ComplexTypeEntry>(e); Q_ASSERT(source); break; default: @@ -409,23 +742,34 @@ TypeEntry *TypeDatabase::resolveTypeDefEntry(TypedefEntry *typedefEntry, } if (!source) { if (errorMessage) - *errorMessage = QLatin1String("Unable to resolve typedef \"") - + typedefEntry->sourceType() + QLatin1Char('"'); + *errorMessage = msgUnableToResolveTypedef(typedefEntry->sourceType(), sourceName); return nullptr; } - auto *result = static_cast<ComplexTypeEntry *>(source->clone()); + m_typedefEntries.insert(typedefEntry->qualifiedCppName(), typedefEntry); + return TypeDatabase::initializeTypeDefEntry(typedefEntry, source); +} + +ComplexTypeEntryPtr + TypeDatabase::initializeTypeDefEntry(const TypedefEntryPtr &typedefEntry, + const ComplexTypeEntryCPtr &source) +{ + ComplexTypeEntryPtr result(static_cast<ComplexTypeEntry *>(source->clone())); result->useAsTypedef(typedefEntry); typedefEntry->setSource(source); typedefEntry->setTarget(result); - m_typedefEntries.insert(typedefEntry->qualifiedCppName(), typedefEntry); return result; } -bool TypeDatabase::addType(TypeEntry *e, QString *errorMessage) +bool TypeDatabase::addType(const TypeEntryPtr &e, QString *errorMessage) +{ + return d->addType(e, errorMessage); +} + +bool TypeDatabasePrivate::addType(TypeEntryPtr e, QString *errorMessage) { if (e->type() == TypeEntry::TypedefType) { - e = resolveTypeDefEntry(static_cast<TypedefEntry *>(e), errorMessage); + e = resolveTypeDefEntry(std::static_pointer_cast<TypedefEntry>(e), errorMessage); if (Q_UNLIKELY(!e)) return false; } @@ -434,11 +778,11 @@ bool TypeDatabase::addType(TypeEntry *e, QString *errorMessage) } // Add a dummy value entry for non-type template parameters -ConstantValueTypeEntry * +ConstantValueTypeEntryPtr TypeDatabase::addConstantValueTypeEntry(const QString &value, - const TypeEntry *parent) + const TypeEntryCPtr &parent) { - auto result = new ConstantValueTypeEntry(value, parent); + auto result = std::make_shared<ConstantValueTypeEntry>(value, parent); result->setCodeGeneration(TypeEntry::GenerateNothing); addType(result); return result; @@ -447,35 +791,36 @@ ConstantValueTypeEntry * bool TypeDatabase::isFunctionRejected(const QString& className, const QString& functionName, QString *reason) const { - return findRejection(m_rejections, TypeRejection::Function, className, functionName, reason); + return findRejection(d->m_rejections, TypeRejection::Function, className, functionName, reason); } bool TypeDatabase::isFieldRejected(const QString& className, const QString& fieldName, QString *reason) const { - return findRejection(m_rejections, TypeRejection::Field, className, fieldName, reason); + return findRejection(d->m_rejections, TypeRejection::Field, className, fieldName, reason); } bool TypeDatabase::isArgumentTypeRejected(const QString& className, const QString& typeName, QString *reason) const { - return findRejection(m_rejections, TypeRejection::ArgumentType, className, typeName, reason); + return findRejection(d->m_rejections, TypeRejection::ArgumentType, className, typeName, reason); } bool TypeDatabase::isReturnTypeRejected(const QString& className, const QString& typeName, QString *reason) const { - return findRejection(m_rejections, TypeRejection::ReturnType, className, typeName, reason); + return findRejection(d->m_rejections, TypeRejection::ReturnType, className, typeName, reason); } -FlagsTypeEntry* TypeDatabase::findFlagsType(const QString &name) const +FlagsTypeEntryPtr TypeDatabase::findFlagsType(const QString &name) const { - TypeEntry *fte = findType(name); + TypeEntryPtr fte = findType(name); if (!fte) { - fte = m_flagsEntries.value(name); + fte = d->m_flagsEntries.value(name); if (!fte) { //last hope, search for flag without scope inside of flags hash - for (auto it = m_flagsEntries.cbegin(), end = m_flagsEntries.cend(); it != end; ++it) { + const auto end = d->m_flagsEntries.cend(); + for (auto it = d->m_flagsEntries.cbegin(); it != end; ++it) { if (it.key().endsWith(name)) { fte = it.value(); break; @@ -483,28 +828,45 @@ FlagsTypeEntry* TypeDatabase::findFlagsType(const QString &name) const } } } - return static_cast<FlagsTypeEntry *>(fte); + return std::static_pointer_cast<FlagsTypeEntry>(fte); +} + +void TypeDatabase::addFlagsType(const FlagsTypeEntryPtr &fte) +{ + d->m_flagsEntries[fte->originalName()] = fte; } -void TypeDatabase::addFlagsType(FlagsTypeEntry *fte) +TemplateEntryPtr TypeDatabase::findTemplate(const QString &name) const { - m_flagsEntries[fte->originalName()] = fte; + return d->m_templates[name]; } -void TypeDatabase::addTemplate(TemplateEntry *t) +void TypeDatabase::addTemplate(const TemplateEntryPtr &t) { - m_templates[t->name()] = t; + d->m_templates[t->name()] = t; +} + +void TypeDatabase::addTemplate(const QString &name, const QString &code) +{ + auto te = std::make_shared<TemplateEntry>(name); + te->addCode(code); + addTemplate(te); +} + +AddedFunctionList TypeDatabase::globalUserFunctions() const +{ + return d->m_globalUserFunctions; } void TypeDatabase::addGlobalUserFunctions(const AddedFunctionList &functions) { - m_globalUserFunctions << functions; + d->m_globalUserFunctions << functions; } AddedFunctionList TypeDatabase::findGlobalUserFunctions(const QString& name) const { AddedFunctionList addedFunctions; - for (const AddedFunctionPtr &func : m_globalUserFunctions) { + for (const AddedFunctionPtr &func : d->m_globalUserFunctions) { if (func->name() == name) addedFunctions.append(func); } @@ -513,151 +875,384 @@ AddedFunctionList TypeDatabase::findGlobalUserFunctions(const QString& name) con void TypeDatabase::addGlobalUserFunctionModifications(const FunctionModificationList &functionModifications) { - m_functionMods << functionModifications; + d->m_functionMods << functionModifications; } -QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/) +QString TypeDatabase::globalNamespaceClassName(const TypeEntryCPtr & /*entry*/) { - return QLatin1String("Global"); + return u"Global"_s; } -FunctionModificationList TypeDatabase::functionModifications(const QString& signature) const +FunctionModificationList + TypeDatabase::globalFunctionModifications(const QStringList &signatures) const { FunctionModificationList lst; - for (int i = 0; i < m_functionMods.count(); ++i) { - const FunctionModification& mod = m_functionMods.at(i); - if (mod.matches(signature)) + for (const auto &mod : d->m_functionMods) { + if (mod.matches(signatures)) lst << mod; } return lst; } -bool TypeDatabase::addSuppressedWarning(const QString &warning, QString *errorMessage) +bool TypeDatabase::addSuppressedWarning(const QString &warning, bool generate, + QString *errorMessage) { QString pattern; - if (warning.startsWith(QLatin1Char('^')) && warning.endsWith(QLatin1Char('$'))) { + if (warning.startsWith(u'^') && warning.endsWith(u'$')) { pattern = warning; } else { // Legacy syntax: Use wildcards '*' (unless escaped by '\') - QList<int> asteriskPositions; - const int warningSize = warning.size(); - for (int i = 0; i < warningSize; ++i) { - if (warning.at(i) == QLatin1Char('\\')) + QList<qsizetype> asteriskPositions; + const auto warningSize = warning.size(); + for (qsizetype i = 0, warningSize = warning.size(); i < warningSize; ++i) { + if (warning.at(i) == u'\\') ++i; - else if (warning.at(i) == QLatin1Char('*')) + else if (warning.at(i) == u'*') asteriskPositions.append(i); } asteriskPositions.append(warningSize); - pattern.append(QLatin1Char('^')); - int lastPos = 0; - for (int a = 0, aSize = asteriskPositions.size(); a < aSize; ++a) { + pattern.append(u'^'); + qsizetype lastPos = 0; + for (qsizetype a = 0, aSize = asteriskPositions.size(); a < aSize; ++a) { if (a) - pattern.append(QStringLiteral(".*")); - const int nextPos = asteriskPositions.at(a); + pattern.append(".*"_L1); + const auto nextPos = asteriskPositions.at(a); if (nextPos > lastPos) pattern.append(QRegularExpression::escape(warning.mid(lastPos, nextPos - lastPos))); lastPos = nextPos + 1; } - pattern.append(QLatin1Char('$')); + pattern.append(u'$'); } QRegularExpression expression(pattern); if (!expression.isValid()) { - *errorMessage = QLatin1String("Invalid message pattern \"") + warning - + QLatin1String("\": ") + expression.errorString(); + *errorMessage = u"Invalid message pattern \""_s + warning + + u"\": "_s + expression.errorString(); return false; } expression.setPatternOptions(expression.patternOptions() | QRegularExpression::MultilineOption); - m_suppressedWarnings.append(expression); + d->m_suppressedWarnings.append({expression, warning, generate}); return true; } bool TypeDatabase::isSuppressedWarning(QStringView s) const { - if (!m_suppressWarnings) + if (!d->m_suppressWarnings) return false; - return std::any_of(m_suppressedWarnings.cbegin(), m_suppressedWarnings.end(), - [&s] (const QRegularExpression &e) { - return e.match(s).hasMatch(); - }); + auto wit = std::find_if(d->m_suppressedWarnings.cbegin(), d->m_suppressedWarnings.cend(), + [&s] (const SuppressedWarning &e) { + return e.pattern.matchView(s).hasMatch(); + }); + const bool found = wit != d->m_suppressedWarnings.cend(); + if (found) + wit->matched = true; + return found; } QString TypeDatabase::modifiedTypesystemFilepath(const QString& tsFile, const QString ¤tPath) const { + return d->modifiedTypesystemFilepath(tsFile, currentPath); +} + +void TypeDatabase::logUnmatched() const +{ + for (auto &sw : d->m_suppressedWarnings) { + if (sw.generate && !sw.matched) + qWarning("Unmatched suppressed warning: \"%s\"", qPrintable(sw.rawText)); + } + + for (auto &tr : d->m_rejections) { + if (tr.generate && !tr.matched) { + QDebug d = qWarning(); + d.noquote(); + d.nospace(); + d << "Unmatched rejection: " << tr.matchType; + if (!tr.className.pattern().isEmpty()) + d << " class " << tr.className.pattern(); + if (!tr.pattern.pattern().isEmpty()) + d << " \"" << tr.pattern.pattern() << '"'; + } + } +} + +QString TypeDatabasePrivate::modifiedTypesystemFilepath(const QString& tsFile, + const QString ¤tPath) const +{ const QFileInfo tsFi(tsFile); if (tsFi.isAbsolute()) // No point in further lookups return tsFi.absoluteFilePath(); if (tsFi.isFile()) // Make path absolute return tsFi.absoluteFilePath(); if (!currentPath.isEmpty()) { - const QFileInfo fi(currentPath + QLatin1Char('/') + tsFile); + const QFileInfo fi(currentPath + u'/' + tsFile); if (fi.isFile()) return fi.absoluteFilePath(); } for (const QString &path : m_typesystemPaths) { - const QFileInfo fi(path + QLatin1Char('/') + tsFile); + const QFileInfo fi(path + u'/' + tsFile); if (fi.isFile()) return fi.absoluteFilePath(); } return tsFile; } -bool TypeDatabase::parseFile(const QString &filename, bool generate) -{ - return parseFile(filename, QString(), generate); +void TypeDatabasePrivate::addBuiltInContainerTypes(const TypeDatabaseParserContextPtr &context) +{ + // Unless the user has added the standard containers (potentially with + // some opaque types), add them by default. + const bool hasStdArray = findType(u"std::array"_s) != nullptr; + const bool hasStdPair = findType(u"std::pair"_s) != nullptr; + const bool hasStdList = findType(u"std::list"_s) != nullptr; + const bool hasStdVector = findType(u"std::vector"_s) != nullptr; + const bool hasStdMap = findType(u"std::map"_s) != nullptr; + const bool hasStdUnorderedMap = findType(u"std::unordered_map"_s) != nullptr; + const bool hasStdSpan = findType(u"std::span"_s) != nullptr; + + if (hasStdPair && hasStdList && hasStdVector && hasStdMap && hasStdUnorderedMap) + return; + + QByteArray ts = R"(<?xml version="1.0" encoding="UTF-8"?><typesystem>)"; + if (!hasStdArray) { + ts += containerTypeSystemSnippet( + "std::array", "list", "array", + "shiboken_conversion_cppsequence_to_pylist", + "PySequence", + "shiboken_conversion_pyiterable_to_cpparray"); + } + if (!hasStdPair) { + ts += containerTypeSystemSnippet( + "std::pair", "pair", "utility", + "shiboken_conversion_cpppair_to_pytuple", + "PySequence", "shiboken_conversion_pysequence_to_cpppair"); + } + if (!hasStdList) { + ts += containerTypeSystemSnippet( + "std::list", "list", "list", + "shiboken_conversion_cppsequence_to_pylist", + "PySequence", + "shiboken_conversion_pyiterable_to_cppsequentialcontainer"); + } + if (!hasStdVector) { + ts += containerTypeSystemSnippet( + "std::vector", "list", "vector", + "shiboken_conversion_cppsequence_to_pylist", + "PySequence", + "shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve"); + } + if (!hasStdMap) { + ts += containerTypeSystemSnippet( + "std::map", "map", "map", + "shiboken_conversion_stdmap_to_pydict", + "PyDict", "shiboken_conversion_pydict_to_stdmap"); + } + if (!hasStdUnorderedMap) { + ts += containerTypeSystemSnippet( + "std::unordered_map", "map", "unordered_map", + "shiboken_conversion_stdmap_to_pydict", + "PyDict", "shiboken_conversion_pydict_to_stdmap"); + } + if (!hasStdSpan + && clang::emulatedCompilerLanguageLevel() >= LanguageLevel::Cpp20) { + auto spanSnip = containerTypeSystemSnippet( + "std::span", "span", "span", + "shiboken_conversion_cppsequence_to_pylist"); + auto pos = spanSnip.indexOf('>'); + spanSnip.insert(pos, R"( view-on="std::vector")"); + ts += spanSnip; + } + + ts += "</typesystem>"; + QBuffer buffer(&ts); + buffer.open(QIODevice::ReadOnly); + const bool ok = parseFile(context, &buffer, true); + Q_ASSERT(ok); } -bool TypeDatabase::parseFile(const QString &filename, const QString ¤tPath, bool generate) +bool TypeDatabasePrivate::addOpaqueContainers(const TypeDatabaseParserContextPtr &context) { + const auto &och = context->opaqueContainerHash; + for (auto it = och.cbegin(), end = och.cend(); it != end; ++it) { + const QString &name = it.key(); + auto te = findType(name); + if (!te || !te->isContainer()) { + qCWarning(lcShiboken, "No container \"%s\" found.", qPrintable(name)); + return false; + } + auto cte = std::static_pointer_cast<ContainerTypeEntry>(te); + cte->appendOpaqueContainers(it.value()); + } + return true; +} - QString filepath = modifiedTypesystemFilepath(filename, currentPath); - if (m_parsedTypesystemFiles.contains(filepath)) - return m_parsedTypesystemFiles[filepath]; +bool TypeDatabase::parseFile(const QString &filename, bool generate) +{ + QString filepath = modifiedTypesystemFilepath(filename, {}); + QFile file(filepath); + return d->prepareParsing(file, filename) && d->parseFile(&file, this, generate); +} - m_parsedTypesystemFiles[filepath] = true; // Prevent recursion when including self. +bool TypeDatabase::parseFile(const TypeDatabaseParserContextPtr &context, + const QString &filename, const QString ¤tPath, + bool generate) +{ + return d->parseFile(context, filename, currentPath, generate); +} - QFile file(filepath); +bool TypeDatabasePrivate::prepareParsing(QFile &file, const QString &origFileName, + const QString ¤tPath) +{ + const QString &filepath = file.fileName(); if (!file.exists()) { m_parsedTypesystemFiles[filepath] = false; - QString message = QLatin1String("Can't find ") + filename; + QString message = u"Can't find "_s + origFileName; if (!currentPath.isEmpty()) - message += QLatin1String(", current path: ") + currentPath; - message += QLatin1String(", typesystem paths: ") + m_typesystemPaths.join(QLatin1String(", ")); - qCWarning(lcShiboken).noquote().nospace() << message; + message += u", current path: "_s + currentPath; + message += u", typesystem paths: "_s + m_typesystemPaths.join(u", "_s); + qCWarning(lcShiboken, "%s", qPrintable(message)); return false; } if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { m_parsedTypesystemFiles[filepath] = false; - qCWarning(lcShiboken).noquote().nospace() - << "Can't open " << QDir::toNativeSeparators(filename) << ": " << file.errorString(); + qCWarning(lcShiboken, "%s", qPrintable(msgCannotOpenForReading(file))); return false; } - bool ok = parseFile(&file, generate); + m_parsedTypesystemFiles[filepath] = true; + return true; +} + +bool TypeDatabasePrivate::parseFile(const TypeDatabaseParserContextPtr &context, + const QString &filename, const QString ¤tPath, + bool generate) +{ + // Prevent recursion when including self. + QString filepath = modifiedTypesystemFilepath(filename, currentPath); + const auto it = m_parsedTypesystemFiles.constFind(filepath); + if (it != m_parsedTypesystemFiles.cend()) + return it.value(); + + QFile file(filepath); + if (!prepareParsing(file, filename, currentPath)) + return false; + + const bool ok = parseFile(context, &file, generate); m_parsedTypesystemFiles[filepath] = ok; return ok; } -bool TypeDatabase::parseFile(QIODevice* device, bool generate) +bool TypeDatabase::parseFile(QIODevice *device, bool generate) +{ + return d->parseFile(device, this, generate); +} + +bool TypeDatabasePrivate::parseFile(QIODevice *device, TypeDatabase *db, bool generate) +{ + const auto context = std::make_shared<TypeDatabaseParserContext>(); + context->db = db; + + if (!parseFile(context, device, generate)) + return false; + + addBuiltInPrimitiveTypes(); + addBuiltInContainerTypes(context); + return addOpaqueContainers(context) + && resolveSmartPointerInstantiations(context); +} + +bool TypeDatabase::parseFile(const TypeDatabaseParserContextPtr &context, + QIODevice *device, bool generate) +{ + return d->parseFile(context, device, generate); +} + +bool TypeDatabasePrivate::parseFile(const TypeDatabaseParserContextPtr &context, + QIODevice *device, bool generate) { ConditionalStreamReader reader(device); - reader.setConditions(TypeDatabase::instance()->typesystemKeywords()); - TypeSystemParser handler(this, generate); + reader.setConditions(context->db->typesystemKeywords()); + TypeSystemParser handler(context, generate); const bool result = handler.parse(reader); - if (!result) + if (!result) { qCWarning(lcShiboken, "%s", qPrintable(handler.errorString())); + return false; + } return result; } -PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString& name) const +// Split a type list potentially with template types +// "A<B,C>,D" -> ("A<B,C>", "D") +static QStringList splitTypeList(const QString &s) { - const auto entries = findTypeRange(name); - for (TypeEntry *entry : entries) { + QStringList result; + int templateDepth = 0; + qsizetype lastPos = 0; + const auto size = s.size(); + for (qsizetype i = 0; i < size; ++i) { + switch (s.at(i).toLatin1()) { + case '<': + ++templateDepth; + break; + case '>': + --templateDepth; + break; + case ',': + if (templateDepth == 0) { + result.append(s.mid(lastPos, i - lastPos).trimmed()); + lastPos = i + 1; + } + break; + } + } + if (lastPos < size) + result.append(s.mid(lastPos, size - lastPos).trimmed()); + return result; +} + +bool TypeDatabasePrivate::resolveSmartPointerInstantiations(const TypeDatabaseParserContextPtr &context) +{ + const auto &instantiations = context->smartPointerInstantiations; + for (auto it = instantiations.cbegin(), end = instantiations.cend(); it != end; ++it) { + auto smartPointerEntry = it.key(); + const auto instantiationNames = splitTypeList(it.value()); + SmartPointerTypeEntry::Instantiations instantiations; + instantiations.reserve(instantiationNames.size()); + for (const auto &instantiation : instantiationNames) { + QString name; + QString type = instantiation; + const auto equalsPos = instantiation.indexOf(u'='); + if (equalsPos != -1) { + type.truncate(equalsPos); + name = instantiation.mid(equalsPos + 1); + } + + const auto typeEntries = findCppTypes(type); + if (typeEntries.isEmpty()) { + const QString m = msgCannotFindTypeEntryForSmartPointer(type, + smartPointerEntry->name()); + qCWarning(lcShiboken, "%s", qPrintable(m)); + return false; + } + if (typeEntries.size() > 1) { + const QString m = msgAmbiguousTypesFound(type, typeEntries); + qCWarning(lcShiboken, "%s", qPrintable(m)); + return false; + } + instantiations.append({name, typeEntries.constFirst()}); + } + smartPointerEntry->setInstantiations(instantiations); + } + return true; +} + +PrimitiveTypeEntryPtr TypeDatabase::findPrimitiveType(const QString& name) const +{ + const auto entries = d->findTypeRange(name); + for (const auto &entry : entries) { if (entry->isPrimitive()) { - auto *pe = static_cast<PrimitiveTypeEntry *>(entry); + auto pe = std::static_pointer_cast<PrimitiveTypeEntry>(entry); if (pe->preferredTargetLangType()) return pe; } @@ -666,22 +1261,22 @@ PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString& name) const return nullptr; } -ComplexTypeEntry* TypeDatabase::findComplexType(const QString& name) const +ComplexTypeEntryPtr TypeDatabase::findComplexType(const QString& name) const { - const auto entries = findTypeRange(name); - for (TypeEntry *entry : entries) { + const auto entries = d->findTypeRange(name); + for (const auto &entry : entries) { if (entry->isComplex() && useType(entry)) - return static_cast<ComplexTypeEntry*>(entry); + return std::static_pointer_cast<ComplexTypeEntry>(entry); } return nullptr; } -ObjectTypeEntry* TypeDatabase::findObjectType(const QString& name) const +ObjectTypeEntryPtr TypeDatabase::findObjectType(const QString& name) const { - const auto entries = findTypeRange(name); - for (TypeEntry *entry : entries) { + const auto entries = d->findTypeRange(name); + for (const auto &entry : entries) { if (entry && entry->isObject() && useType(entry)) - return static_cast<ObjectTypeEntry*>(entry); + return std::static_pointer_cast<ObjectTypeEntry>(entry); } return nullptr; } @@ -689,26 +1284,26 @@ ObjectTypeEntry* TypeDatabase::findObjectType(const QString& name) const NamespaceTypeEntryList TypeDatabase::findNamespaceTypes(const QString& name) const { NamespaceTypeEntryList result; - const auto entries = findTypeRange(name); - for (TypeEntry *entry : entries) { + const auto entries = d->findTypeRange(name); + for (const auto &entry : entries) { if (entry->isNamespace()) - result.append(static_cast<NamespaceTypeEntry*>(entry)); + result.append(std::static_pointer_cast<NamespaceTypeEntry>(entry)); } return result; } -NamespaceTypeEntry *TypeDatabase::findNamespaceType(const QString& name, +NamespaceTypeEntryPtr TypeDatabase::findNamespaceType(const QString& name, const QString &fileName) const { const auto entries = findNamespaceTypes(name); // Preferably check on matching file name first, if a pattern was given. if (!fileName.isEmpty()) { - for (NamespaceTypeEntry *entry : entries) { + for (const auto &entry : entries) { if (entry->hasPattern() && entry->matchesFile(fileName)) return entry; } } - for (NamespaceTypeEntry *entry : entries) { + for (const auto &entry : entries) { if (!entry->hasPattern()) return entry; } @@ -717,19 +1312,19 @@ NamespaceTypeEntry *TypeDatabase::findNamespaceType(const QString& name, bool TypeDatabase::shouldDropTypeEntry(const QString& fullTypeName) const { - return m_dropTypeEntries.contains(fullTypeName); + return d->m_dropTypeEntries.contains(fullTypeName); } -void TypeDatabase::setDropTypeEntries(QStringList dropTypeEntries) +void TypeDatabase::setDropTypeEntries(const QStringList &dropTypeEntries) { - m_dropTypeEntries = dropTypeEntries; - m_dropTypeEntries.sort(); + d->m_dropTypeEntries = dropTypeEntries; + d->m_dropTypeEntries.sort(); } static bool computeTypeIndexes = true; static int maxTypeIndex; -static bool typeEntryLessThan(const TypeEntry* t1, const TypeEntry* t2) +static bool typeEntryLessThan(const TypeEntryCPtr &t1, const TypeEntryCPtr &t2) { if (t1->revision() < t2->revision()) return true; @@ -739,7 +1334,7 @@ static bool typeEntryLessThan(const TypeEntry* t1, const TypeEntry* t2) static void _computeTypeIndexes() { - TypeDatabase* tdb = TypeDatabase::instance(); + auto *tdb = TypeDatabase::instance(); TypeEntryList list; @@ -747,7 +1342,7 @@ static void _computeTypeIndexes() const auto &allEntries = tdb->entries(); list.reserve(allEntries.size()); for (auto tit = allEntries.cbegin(), end = allEntries.cend(); tit != end; ++tit) { - TypeEntry *entry = tit.value(); + const TypeEntryPtr &entry = tit.value(); if (entry->isPrimitive() || entry->isContainer() || entry->isFunction() @@ -766,7 +1361,7 @@ static void _computeTypeIndexes() std::sort(list.begin(), list.end(), typeEntryLessThan); maxTypeIndex = 0; - for (TypeEntry *e : qAsConst(list)) + for (const TypeEntryPtr &e : std::as_const(list)) e->setSbkIndex(maxTypeIndex++); computeTypeIndexes = false; } @@ -803,7 +1398,7 @@ bool TypeDatabase::setApiVersion(const QString& packageWildcardPattern, const QS if (versionNumber.isNull()) return false; ApiVersions &versions = *apiVersions(); - for (int i = 0, size = versions.size(); i < size; ++i) { + for (qsizetype i = 0, size = versions.size(); i < size; ++i) { if (versions.at(i).first.pattern() == packagePattern) { versions[i].second = versionNumber; return true; @@ -812,7 +1407,7 @@ bool TypeDatabase::setApiVersion(const QString& packageWildcardPattern, const QS const QRegularExpression packageRegex(packagePattern); if (!packageRegex.isValid()) return false; - versions.append(qMakePair(packageRegex, versionNumber)); + versions.append(std::make_pair(packageRegex, versionNumber)); return true; } @@ -822,7 +1417,7 @@ bool TypeDatabase::checkApiVersion(const QString &package, const ApiVersions &versions = *apiVersions(); if (versions.isEmpty()) // Nothing specified: use latest. return true; - for (int i = 0, size = versions.size(); i < size; ++i) { + for (qsizetype i = 0, size = versions.size(); i < size; ++i) { if (versions.at(i).first.match(package).hasMatch()) return versions.at(i).second >= vr.since && versions.at(i).second <= vr.until; @@ -830,23 +1425,18 @@ bool TypeDatabase::checkApiVersion(const QString &package, return false; } -#ifndef QT_NO_DEBUG_STREAM +bool TypeDatabase::hasDroppedTypeEntries() const +{ + return !d->m_dropTypeEntries.isEmpty(); +} -template <class Container, class Separator> -static void formatList(QDebug &d, const char *name, const Container &c, Separator sep) +#ifndef QT_NO_DEBUG_STREAM +void TypeDatabase::formatDebug(QDebug &debug) const { - if (const int size = c.size()) { - d << ", " << name << '[' << size << "]=("; - for (int i = 0; i < size; ++i) { - if (i) - d << sep; - d << c.at(i); - } - d << ')'; - } + d->formatDebug(debug); } -void TypeDatabase::formatDebug(QDebug &d) const +void TypeDatabasePrivate::formatDebug(QDebug &d) const { d << "TypeDatabase(" << "entries[" << m_entries.size() << "]="; @@ -883,10 +1473,182 @@ void TypeDatabase::formatDebug(QDebug &d) const d << ")\n"; } d <<"\nglobalUserFunctions=" << m_globalUserFunctions << '\n'; - formatList(d, "globalFunctionMods", m_functionMods, '\n'); + formatList(d, "globalFunctionMods", m_functionMods, "\n"); d << ')'; } +// Helpers for dumping out primitive type info + +struct formatPrimitiveEntry +{ + explicit formatPrimitiveEntry(const PrimitiveTypeEntryCPtr &e) : m_pe(e) {} + + PrimitiveTypeEntryCPtr m_pe; +}; + +QDebug operator<<(QDebug debug, const formatPrimitiveEntry &fe) +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + const QString &name = fe.m_pe->name(); + const QString &targetLangName = fe.m_pe->targetLangApiName(); + debug << '"' << name << '"'; + if (name != targetLangName) + debug << " (\"" << targetLangName << "\")"; + if (fe.m_pe->isBuiltIn()) + debug << " [builtin]"; + if (isExtendedCppPrimitive(fe.m_pe)) { + debug << " ["; + if (!isCppPrimitive(fe.m_pe)) + debug << "extended "; + debug << "C++]"; + } + return debug; +} + +// Sort primitive types for displaying; base type and typedef'ed types +struct PrimitiveFormatListEntry +{ + PrimitiveTypeEntryCPtr baseType; + PrimitiveTypeEntryCList typedefs; +}; + +static bool operator<(const PrimitiveFormatListEntry &e1, const PrimitiveFormatListEntry &e2) +{ + return e1.baseType->name() < e2.baseType->name(); +} + +using PrimitiveFormatListEntries = QList<PrimitiveFormatListEntry>; + +static qsizetype indexOf(const PrimitiveFormatListEntries &e, const PrimitiveTypeEntryCPtr &needle) +{ + for (qsizetype i = 0, size = e.size(); i < size; ++i) { + if (e.at(i).baseType == needle) + return i; + } + return -1; +} + +void TypeDatabase::formatBuiltinTypes(QDebug debug) const +{ + QDebugStateSaver saver(debug); + debug.noquote(); + debug.nospace(); + + // Determine base types and their typedef'ed types + QList<PrimitiveFormatListEntry> primitiveEntries; + for (const auto &e : std::as_const(d->m_entries)) { + if (e->isPrimitive()) { + auto pe = std::static_pointer_cast<const PrimitiveTypeEntry>(e); + auto basic = basicReferencedTypeEntry(pe); + if (basic != pe) { + const auto idx = indexOf(primitiveEntries, basic); + if (idx != -1) + primitiveEntries[idx].typedefs.append(pe); + else + primitiveEntries.append(PrimitiveFormatListEntry{basic, {pe}}); + } else { + primitiveEntries.append(PrimitiveFormatListEntry{pe, {}}); + } + } + } + + std::sort(primitiveEntries.begin(), primitiveEntries.end()); + + for (const auto &e : std::as_const(primitiveEntries)) { + debug << "Primitive: " << formatPrimitiveEntry(e.baseType) << '\n'; + for (const auto &pe : e.typedefs) + debug << " " << formatPrimitiveEntry(pe) << '\n'; + } +} + +void TypeDatabasePrivate::addBuiltInType(const TypeEntryPtr &e) +{ + e->setBuiltIn(true); + addType(e); +} + +PrimitiveTypeEntryPtr + TypeDatabasePrivate::addBuiltInPrimitiveType(const QString &name, + const TypeSystemTypeEntryCPtr &root, + const QString &rootPackage, + const CustomTypeEntryPtr &targetLang) +{ + auto result = std::make_shared<PrimitiveTypeEntry>(name, QVersionNumber{}, root); + result->setTargetLangApiType(targetLang); + result->setTargetLangPackage(rootPackage); + addBuiltInType(result); + return result; +} + +void TypeDatabasePrivate::addBuiltInCppStringPrimitiveType(const QString &name, + const QString &viewName, + const TypeSystemTypeEntryCPtr &root, + const QString &rootPackage, + const CustomTypeEntryPtr &targetLang) + +{ + auto stringType = addBuiltInPrimitiveType(name, root, rootPackage, + targetLang); + auto viewType = addBuiltInPrimitiveType(viewName, root, rootPackage, + nullptr); + viewType->setViewOn(stringType); +} + +void TypeDatabasePrivate::addBuiltInPrimitiveTypes() +{ + auto root = defaultTypeSystemType(); + const QString &rootPackage = root->name(); + + // C++ primitive types + auto pyLongEntry = findType(u"PyLong"_s); + Q_ASSERT(pyLongEntry && pyLongEntry->isCustom()); + auto pyLongCustomEntry = std::static_pointer_cast<CustomTypeEntry>(pyLongEntry); + auto pyBoolEntry = findType(u"PyBool"_s); + Q_ASSERT(pyBoolEntry && pyBoolEntry->isCustom()); + auto sbkCharEntry = findType(u"SbkChar"_s); + Q_ASSERT(sbkCharEntry && sbkCharEntry->isCustom()); + auto sbkCharCustomEntry = std::static_pointer_cast<CustomTypeEntry>(sbkCharEntry); + + auto pyBoolCustomEntry = std::static_pointer_cast<CustomTypeEntry>(pyBoolEntry); + for (const auto &t : AbstractMetaType::cppIntegralTypes()) { + if (!m_entries.contains(t)) { + CustomTypeEntryPtr targetLangApi = pyLongCustomEntry; + if (t == u"bool") + targetLangApi = pyBoolCustomEntry; + else if (AbstractMetaType::cppCharTypes().contains(t)) + targetLangApi = sbkCharCustomEntry; + addBuiltInPrimitiveType(t, root, rootPackage, targetLangApi); + } + } + + auto pyFloatEntry = findType(u"PyFloat"_s); + Q_ASSERT(pyFloatEntry && pyFloatEntry->isCustom()); + auto pyFloatCustomEntry = std::static_pointer_cast<CustomTypeEntry>(pyFloatEntry); + for (const auto &t : AbstractMetaType::cppFloatTypes()) { + if (!m_entries.contains(t)) + addBuiltInPrimitiveType(t, root, rootPackage, pyFloatCustomEntry); + } + + auto pyUnicodeEntry = findType(u"PyUnicode"_s); + Q_ASSERT(pyUnicodeEntry && pyUnicodeEntry->isCustom()); + auto pyUnicodeCustomEntry = std::static_pointer_cast<CustomTypeEntry>(pyUnicodeEntry); + + constexpr auto stdString = "std::string"_L1; + if (!m_entries.contains(stdString)) { + addBuiltInCppStringPrimitiveType(stdString, u"std::string_view"_s, + root, rootPackage, + pyUnicodeCustomEntry); + } + constexpr auto stdWString = "std::wstring"_L1; + if (!m_entries.contains(stdWString)) { + addBuiltInCppStringPrimitiveType(stdWString, u"std::wstring_view"_s, + root, rootPackage, + pyUnicodeCustomEntry); + } +} + QDebug operator<<(QDebug d, const TypeDatabase &db) { QDebugStateSaver saver(d); diff --git a/sources/shiboken6/ApiExtractor/typedatabase.h b/sources/shiboken6/ApiExtractor/typedatabase.h index 082d833b5..d5adca324 100644 --- a/sources/shiboken6/ApiExtractor/typedatabase.h +++ b/sources/shiboken6/ApiExtractor/typedatabase.h @@ -1,64 +1,30 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TYPEDATABASE_H #define TYPEDATABASE_H #include "include.h" +#include "modifications_typedefs.h" #include "typedatabase_typedefs.h" -#include "typesystem_enums.h" -#include "typesystem_typedefs.h" #include <QtCore/QRegularExpression> #include <QtCore/QStringList> #include <QtCore/QVersionNumber> -QT_FORWARD_DECLARE_CLASS(QIODevice) +#include <memory> -class ComplexTypeEntry; -class ContainerTypeEntry; -class FlagsTypeEntry; -class FunctionTypeEntry; -class NamespaceTypeEntry; -class ObjectTypeEntry; -class TemplateEntry; -class TypeEntry; +QT_FORWARD_DECLARE_CLASS(QIODevice) -struct TypeRejection; +struct OptionDescription; +class OptionsParser; +struct TypeDatabasePrivate; +struct TypeDatabaseParserContext; QT_FORWARD_DECLARE_CLASS(QDebug) int getMaxTypeIndex(); -class ContainerTypeEntry; -class PrimitiveTypeEntry; -class TypeSystemTypeEntry; - struct VersionRange { bool isNull() const @@ -85,7 +51,9 @@ struct TypeRejection QRegularExpression className; QRegularExpression pattern; - MatchType matchType; + MatchType matchType = ExcludeClass; + bool generate; // Current type system + mutable bool matched = false; }; #ifndef QT_NO_DEBUG_STREAM @@ -95,10 +63,14 @@ QDebug operator<<(QDebug d, const TypeRejection &r); class TypeDatabase { TypeDatabase(); - Q_DISABLE_COPY(TypeDatabase) public: + Q_DISABLE_COPY_MOVE(TypeDatabase) + ~TypeDatabase(); + static QList<OptionDescription> options(); + std::shared_ptr<OptionsParser> createOptionsParser(); + /** * Return the type system instance. * \param newInstance This parameter is useful just for unit testing, because singletons causes @@ -107,44 +79,45 @@ public: static TypeDatabase *instance(bool newInstance = false); static QString normalizedSignature(const QString &signature); + static QString normalizedAddedFunctionSignature(const QString &signature); QStringList requiredTargetImports() const; void addRequiredTargetImport(const QString &moduleName); - void addTypesystemPath(const QString &typesystem_paths); - - void setTypesystemKeywords(const QStringList &keywords) { m_typesystemKeywords = keywords; } QStringList typesystemKeywords() const; IncludeList extraIncludes(const QString &className) const; - const QByteArrayList &systemIncludes() const { return m_systemIncludes; } - void addSystemInclude(const QString &name); + const QStringList &forceProcessSystemIncludes() const; + void addForceProcessSystemInclude(const QString &name); - void addInlineNamespaceLookups(const NamespaceTypeEntry *n); + void addInlineNamespaceLookups(const NamespaceTypeEntryCPtr &n); - PrimitiveTypeEntry *findPrimitiveType(const QString &name) const; - ComplexTypeEntry *findComplexType(const QString &name) const; - ObjectTypeEntry *findObjectType(const QString &name) const; + PrimitiveTypeEntryPtr findPrimitiveType(const QString &name) const; + ComplexTypeEntryPtr findComplexType(const QString &name) const; + ObjectTypeEntryPtr findObjectType(const QString &name) const; NamespaceTypeEntryList findNamespaceTypes(const QString &name) const; - NamespaceTypeEntry *findNamespaceType(const QString &name, const QString &fileName = QString()) const; - ContainerTypeEntry *findContainerType(const QString &name) const; - FunctionTypeEntry *findFunctionType(const QString &name) const; - const TypeSystemTypeEntry *findTypeSystemType(const QString &name) const; - const TypeSystemTypeEntry *defaultTypeSystemType() const; + NamespaceTypeEntryPtr findNamespaceType(const QString &name, const QString &fileName = QString()) const; + ContainerTypeEntryPtr findContainerType(const QString &name) const; + FunctionTypeEntryPtr findFunctionType(const QString &name) const; + TypeSystemTypeEntryCPtr findTypeSystemType(const QString &name) const; + TypeSystemTypeEntryCPtr defaultTypeSystemType() const; + QString loadedTypeSystemNames() const; QString defaultPackageName() const; - TypeEntry *findType(const QString &name) const; - TypeEntries findTypes(const QString &name) const; - TypeEntries findCppTypes(const QString &name) const; + TypeEntryPtr findType(const QString &name) const; + TypeEntryCList findTypes(const QString &name) const; + TypeEntryCList findCppTypes(const QString &name) const; - const TypeEntryMultiMap &entries() const { return m_entries; } - const TypedefEntryMap &typedefEntries() const { return m_typedefEntries; } + const TypeEntryMultiMap &entries() const; + const TypedefEntryMap &typedefEntries() const; - PrimitiveTypeEntryList primitiveTypes() const; + PrimitiveTypeEntryCList primitiveTypes() const; - ContainerTypeEntryList containerTypes() const; + ContainerTypeEntryCList containerTypes() const; + + SmartPointerTypeEntryList smartPointerTypes() const; void addRejection(const TypeRejection &); bool isClassRejected(const QString &className, QString *reason = nullptr) const; @@ -159,19 +132,24 @@ public: bool isReturnTypeRejected(const QString &className, const QString &typeName, QString *reason = nullptr) const; - bool addType(TypeEntry *e, QString *errorMessage = nullptr); - ConstantValueTypeEntry *addConstantValueTypeEntry(const QString &value, - const TypeEntry *parent); - void addTypeSystemType(const TypeSystemTypeEntry *e); + bool addType(const TypeEntryPtr &e, QString *errorMessage = nullptr); + ConstantValueTypeEntryPtr addConstantValueTypeEntry(const QString &value, + const TypeEntryCPtr &parent); + void addTypeSystemType(const TypeSystemTypeEntryCPtr &e); + + static ComplexTypeEntryPtr + initializeTypeDefEntry(const TypedefEntryPtr &typedefEntry, + const ComplexTypeEntryCPtr &source); - FlagsTypeEntry *findFlagsType(const QString &name) const; - void addFlagsType(FlagsTypeEntry *fte); + FlagsTypeEntryPtr findFlagsType(const QString &name) const; + void addFlagsType(const FlagsTypeEntryPtr &fte); - TemplateEntry *findTemplate(const QString &name) const { return m_templates[name]; } + TemplateEntryPtr findTemplate(const QString &name) const; - void addTemplate(TemplateEntry *t); + void addTemplate(const TemplateEntryPtr &t); + void addTemplate(const QString &name, const QString &code); - AddedFunctionList globalUserFunctions() const { return m_globalUserFunctions; } + AddedFunctionList globalUserFunctions() const; void addGlobalUserFunctions(const AddedFunctionList &functions); @@ -179,69 +157,51 @@ public: void addGlobalUserFunctionModifications(const FunctionModificationList &functionModifications); - FunctionModificationList functionModifications(const QString &signature) const; - - void setSuppressWarnings(bool on) { m_suppressWarnings = on; } + FunctionModificationList + globalFunctionModifications(const QStringList &signatures) const; - bool addSuppressedWarning(const QString &warning, QString *errorMessage); + bool addSuppressedWarning(const QString &warning, bool generate, QString *errorMessage); bool isSuppressedWarning(QStringView s) const; - static QString globalNamespaceClassName(const TypeEntry *te); + static QString globalNamespaceClassName(const TypeEntryCPtr &te); + // Top level file parsing bool parseFile(const QString &filename, bool generate = true); - bool parseFile(const QString &filename, const QString ¤tPath, bool generate); + bool parseFile(const std::shared_ptr<TypeDatabaseParserContext> &context, + const QString &filename, const QString ¤tPath, bool generate); + // Top level QIODevice parsing for tests. bool parseFile(QIODevice *device, bool generate = true); + bool parseFile(const std::shared_ptr<TypeDatabaseParserContext> &context, + QIODevice *device, bool generate = true); static bool setApiVersion(const QString &package, const QString &version); static void clearApiVersions(); static bool checkApiVersion(const QString &package, const VersionRange &vr); - bool hasDroppedTypeEntries() const { return !m_dropTypeEntries.isEmpty(); } + bool hasDroppedTypeEntries() const; bool shouldDropTypeEntry(const QString &fullTypeName) const; - void setDropTypeEntries(QStringList dropTypeEntries); + void setDropTypeEntries(const QStringList &dropTypeEntries); QString modifiedTypesystemFilepath(const QString &tsFile, const QString ¤tPath = QString()) const; + void logUnmatched() const; + #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const; #endif + void formatBuiltinTypes(QDebug debug) const; + private: - TypeEntryMultiMapConstIteratorRange findTypeRange(const QString &name) const; - template <class Predicate> - TypeEntries findTypesHelper(const QString &name, Predicate pred) const; - TypeEntry *resolveTypeDefEntry(TypedefEntry *typedefEntry, QString *errorMessage); - template <class String> - bool isSuppressedWarningHelper(const String &s) const; - - bool m_suppressWarnings = true; - TypeEntryMultiMap m_entries; // Contains duplicate entries (cf addInlineNamespaceLookups). - TypeEntryMap m_flagsEntries; - TypedefEntryMap m_typedefEntries; - TemplateEntryMap m_templates; - QList<QRegularExpression> m_suppressedWarnings; - QList<const TypeSystemTypeEntry *> m_typeSystemEntries; // maintain order, default is first. - - AddedFunctionList m_globalUserFunctions; - FunctionModificationList m_functionMods; - - QStringList m_requiredTargetImports; - - QStringList m_typesystemPaths; - QStringList m_typesystemKeywords; - QHash<QString, bool> m_parsedTypesystemFiles; - - QList<TypeRejection> m_rejections; - - QStringList m_dropTypeEntries; - QByteArrayList m_systemIncludes; + TypeDatabasePrivate *d; }; #ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const TypeEntryCPtr &te); QDebug operator<<(QDebug d, const TypeEntry *te); QDebug operator<<(QDebug d, const TypeDatabase &db); #endif diff --git a/sources/shiboken6/ApiExtractor/typedatabase_p.h b/sources/shiboken6/ApiExtractor/typedatabase_p.h new file mode 100644 index 000000000..fc56c7961 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/typedatabase_p.h @@ -0,0 +1,25 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef TYPEDATABASE_P_H +#define TYPEDATABASE_P_H + +#include "typesystem_typedefs.h" +#include "containertypeentry.h" + +#include <QtCore/QHash> +#include <QtCore/QString> + +class TypeDatabase; + +struct TypeDatabaseParserContext +{ + using SmartPointerInstantiations = QHash<SmartPointerTypeEntryPtr, QString>; + using OpaqueContainerHash = QHash<QString, OpaqueContainers>; + + TypeDatabase *db; + SmartPointerInstantiations smartPointerInstantiations; + OpaqueContainerHash opaqueContainerHash; +}; + +#endif // TYPEDATABASE_P_H diff --git a/sources/shiboken6/ApiExtractor/typedatabase_typedefs.h b/sources/shiboken6/ApiExtractor/typedatabase_typedefs.h index 03ad90463..f00c61570 100644 --- a/sources/shiboken6/ApiExtractor/typedatabase_typedefs.h +++ b/sources/shiboken6/ApiExtractor/typedatabase_typedefs.h @@ -1,48 +1,16 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TYPEDATABASE_TYPEDEFS_H #define TYPEDATABASE_TYPEDEFS_H +#include "typesystem_typedefs.h" + #include <QtCore/QMultiMap> #include <QtCore/QString> #include <QtCore/QList> -class ConstantValueTypeEntry; -class ContainerTypeEntry; -class NamespaceTypeEntry; -class PrimitiveTypeEntry; -class TemplateEntry; -class TypeEntry; -class TypedefEntry; - -using TypeEntryList = QList<TypeEntry *>; -using TemplateEntryMap =QMap<QString, TemplateEntry *>; +using TemplateEntryMap =QMap<QString, TemplateEntryPtr>; template <class Key, class Value> struct QMultiMapConstIteratorRange // A range of iterator for a range-based for loop @@ -56,14 +24,10 @@ struct QMultiMapConstIteratorRange // A range of iterator for a range-based for ConstIterator m_end; }; -using TypeEntryMultiMap = QMultiMap<QString, TypeEntry *>; -using TypeEntryMultiMapConstIteratorRange = QMultiMapConstIteratorRange<QString, TypeEntry *>; - -using TypeEntryMap = QMap<QString, TypeEntry *>; -using TypedefEntryMap = QMap<QString, TypedefEntry *>; +using TypeEntryMultiMap = QMultiMap<QString, TypeEntryPtr>; +using TypeEntryMultiMapConstIteratorRange = QMultiMapConstIteratorRange<QString, TypeEntryPtr>; -using ContainerTypeEntryList = QList<const ContainerTypeEntry *>; -using NamespaceTypeEntryList = QList<NamespaceTypeEntry *>; -using PrimitiveTypeEntryList = QList<const PrimitiveTypeEntry *>; +using TypeEntryMap = QMap<QString, TypeEntryPtr>; +using TypedefEntryMap = QMap<QString, TypedefEntryPtr>; #endif // TYPEDATABASE_TYPEDEFS_H diff --git a/sources/shiboken6/ApiExtractor/typedefentry.h b/sources/shiboken6/ApiExtractor/typedefentry.h new file mode 100644 index 000000000..44646972c --- /dev/null +++ b/sources/shiboken6/ApiExtractor/typedefentry.h @@ -0,0 +1,37 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef TYPEDEFENTRY_H +#define TYPEDEFENTRY_H + +#include "complextypeentry.h" + +class TypedefEntryPrivate; + +class TypedefEntry : public ComplexTypeEntry +{ +public: + explicit TypedefEntry(const QString &entryName, + const QString &sourceType, + const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + QString sourceType() const; + void setSourceType(const QString &s); + + TypeEntry *clone() const override; + + ComplexTypeEntryCPtr source() const; + void setSource(const ComplexTypeEntryCPtr &source); + + ComplexTypeEntryPtr target() const; + void setTarget(ComplexTypeEntryPtr target); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif +protected: + explicit TypedefEntry(TypedefEntryPrivate *d); +}; + +#endif // TYPEDEFENTRY_H diff --git a/sources/shiboken6/ApiExtractor/typeparser.cpp b/sources/shiboken6/ApiExtractor/typeparser.cpp index 38c556d41..11d7bf641 100644 --- a/sources/shiboken6/ApiExtractor/typeparser.cpp +++ b/sources/shiboken6/ApiExtractor/typeparser.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "typeparser.h" #include <typeinfo.h> @@ -33,6 +8,8 @@ #include <QtCore/QStack> #include <QtCore/QTextStream> +using namespace Qt::StringLiterals; + class Scanner { public: @@ -60,7 +37,7 @@ public: { } - Token nextToken(QString *errorMessage = Q_NULLPTR); + Token nextToken(QString *errorMessage = nullptr); QString identifier() const; QString msgParseError(const QString &why) const; @@ -82,7 +59,7 @@ Scanner::Token Scanner::nextToken(QString *errorMessage) Token tok = NoToken; // remove whitespace - while (m_pos < m_length && m_chars[m_pos] == QLatin1Char(' ')) + while (m_pos < m_length && m_chars[m_pos] == u' ') ++m_pos; m_tokenStart = m_pos; @@ -108,7 +85,7 @@ Scanner::Token Scanner::nextToken(QString *errorMessage) ++m_pos; break; default: - if (c.isLetterOrNumber() || c == QLatin1Char('_')) { + if (c.isLetterOrNumber() || c == u'_') { tok = Identifier; } else { QString message; @@ -131,7 +108,7 @@ Scanner::Token Scanner::nextToken(QString *errorMessage) } if (tok == Identifier) { - if (c.isLetterOrNumber() || c == QLatin1Char('_')) + if (c.isLetterOrNumber() || c == u'_') ++m_pos; else break; @@ -141,23 +118,23 @@ Scanner::Token Scanner::nextToken(QString *errorMessage) if (tok == Identifier) { switch (m_pos - m_tokenStart) { case 5: - if (m_chars[m_tokenStart] == QLatin1Char('c') - && m_chars[m_tokenStart + 1] == QLatin1Char('o') - && m_chars[m_tokenStart + 2] == QLatin1Char('n') - && m_chars[m_tokenStart + 3] == QLatin1Char('s') - && m_chars[m_tokenStart + 4] == QLatin1Char('t')) { + if (m_chars[m_tokenStart] == u'c' + && m_chars[m_tokenStart + 1] == u'o' + && m_chars[m_tokenStart + 2] == u'n' + && m_chars[m_tokenStart + 3] == u's' + && m_chars[m_tokenStart + 4] == u't') { tok = ConstToken; } break; case 8: - if (m_chars[m_tokenStart] == QLatin1Char('v') - && m_chars[m_tokenStart + 1] == QLatin1Char('o') - && m_chars[m_tokenStart + 2] == QLatin1Char('l') - && m_chars[m_tokenStart + 3] == QLatin1Char('a') - && m_chars[m_tokenStart + 4] == QLatin1Char('t') - && m_chars[m_tokenStart + 5] == QLatin1Char('i') - && m_chars[m_tokenStart + 6] == QLatin1Char('l') - && m_chars[m_tokenStart + 7] == QLatin1Char('e')) { + if (m_chars[m_tokenStart] == u'v' + && m_chars[m_tokenStart + 1] == u'o' + && m_chars[m_tokenStart + 2] == u'l' + && m_chars[m_tokenStart + 3] == u'a' + && m_chars[m_tokenStart + 4] == u't' + && m_chars[m_tokenStart + 5] == u'i' + && m_chars[m_tokenStart + 6] == u'l' + && m_chars[m_tokenStart + 7] == u'e') { tok = VolatileToken; } break; @@ -170,8 +147,8 @@ Scanner::Token Scanner::nextToken(QString *errorMessage) QString Scanner::msgParseError(const QString &why) const { - return QStringLiteral("TypeParser: Unable to parse \"") - + QString(m_chars, m_length) + QStringLiteral("\": ") + why; + return "TypeParser: Unable to parse \""_L1 + + QString(m_chars, m_length) + "\": "_L1 + why; } TypeInfo TypeParser::parse(const QString &str, QString *errorMessage) @@ -189,7 +166,7 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage) Scanner::Token tok = scanner.nextToken(errorMessage); while (tok != Scanner::NoToken) { if (tok == Scanner::InvalidToken) - return TypeInfo(); + return {}; // switch (tok) { // case Scanner::StarToken: printf(" - *\n"); break; @@ -222,12 +199,12 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage) stack.top().setReferenceType(RValueReference); break; case RValueReference: - const QString message = scanner.msgParseError(QStringLiteral("Too many '&' qualifiers")); + const QString message = scanner.msgParseError("Too many '&' qualifiers"_L1); if (errorMessage) *errorMessage = message; else qWarning().noquote().nospace() << message; - return TypeInfo(); + return {}; } break; case Scanner::LessThanToken: @@ -269,12 +246,12 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage) case Scanner::OpenParenToken: // function pointers not supported case Scanner::CloseParenToken: { - const QString message = scanner.msgParseError(QStringLiteral("Function pointers are not supported")); + const QString message = scanner.msgParseError("Function pointers are not supported"_L1); if (errorMessage) *errorMessage = message; else qWarning().noquote().nospace() << message; - return TypeInfo(); + return {}; } case Scanner::Identifier: @@ -285,7 +262,7 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage) colon_prefix = false; } else { QStringList qualifiedName = stack.top().qualifiedName(); - qualifiedName.last().append(QLatin1Char(' ') + scanner.identifier()); + qualifiedName.last().append(u' ' + scanner.identifier()); stack.top().setQualifiedName(qualifiedName); } break; @@ -304,9 +281,12 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage) break; } - tok = scanner.nextToken(); + tok = scanner.nextToken(errorMessage); } - Q_ASSERT(!stack.isEmpty()); + if (stack.isEmpty() || stack.constFirst().qualifiedName().isEmpty()) { + *errorMessage = u"Unable to parse type \""_s + str + u"\"."_s; + return {}; + } return stack.constFirst(); } diff --git a/sources/shiboken6/ApiExtractor/typeparser.h b/sources/shiboken6/ApiExtractor/typeparser.h index 2359da7b2..97634b5db 100644 --- a/sources/shiboken6/ApiExtractor/typeparser.h +++ b/sources/shiboken6/ApiExtractor/typeparser.h @@ -1,36 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TYPEPARSER_H #define TYPEPARSER_H -#include "parser/codemodel_enums.h" - #include <QtCore/QString> class TypeInfo; diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp index d445febfa..99d42b668 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.cpp +++ b/sources/shiboken6/ApiExtractor/typesystem.cpp @@ -1,103 +1,92 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "typesystem.h" +#include "arraytypeentry.h" +#include "codesnip.h" +#include "complextypeentry.h" +#include "configurabletypeentry.h" +#include "constantvaluetypeentry.h" +#include "containertypeentry.h" +#include "customtypenentry.h" +#include "debughelpers_p.h" +#include "enumtypeentry.h" +#include "enumvaluetypeentry.h" +#include "flagstypeentry.h" +#include "functiontypeentry.h" +#include "include.h" +#include "namespacetypeentry.h" +#include "objecttypeentry.h" +#include "primitivetypeentry.h" +#include "pythontypeentry.h" +#include "smartpointertypeentry.h" +#include "templateargumententry.h" +#include "typedefentry.h" +#include "typesystemtypeentry.h" +#include "valuetypeentry.h" +#include "varargstypeentry.h" +#include "voidtypeentry.h" +#include "abstractmetatype.h" #include "typedatabase.h" #include "modifications.h" -#include "messages.h" #include "sourcelocation.h" +#include "qtcompat.h" + #include <QtCore/QDebug> #include <QtCore/QRegularExpression> #include <QtCore/QSet> +#include <QtCore/QVarLengthArray> + +using namespace Qt::StringLiterals; -static QString buildName(const QString &entryName, const TypeEntry *parent) +static QString buildName(const QString &entryName, const TypeEntryCPtr &parent) { return parent == nullptr || parent->type() == TypeEntry::TypeSystemType - ? entryName : parent->name() + QLatin1String("::") + entryName; + ? entryName : parent->name() + u"::"_s + entryName; } // Access private class as 'd', cf macro Q_D() #define S_D(Class) auto d = static_cast<Class##Private *>(d_func()) -static const QSet<QString> &primitiveCppTypes() -{ - static QSet<QString> result; - if (result.isEmpty()) { - static const char *cppTypes[] = { - "bool", "char", "double", "float", "int", - "long", "long long", "short", - "wchar_t" - }; - for (const char *cppType : cppTypes) - result.insert(QLatin1String(cppType)); - } - return result; -} - class TypeEntryPrivate { public: + TypeEntryPrivate(const TypeEntryPrivate &) = default; // Enable copy for cloning. + TypeEntryPrivate &operator=(const TypeEntryPrivate &) = delete; + TypeEntryPrivate(TypeEntryPrivate &&) = delete; + TypeEntryPrivate &operator=(TypeEntryPrivate &&) = delete; + explicit TypeEntryPrivate(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr, - const TypeEntry *parent); - virtual ~TypeEntryPrivate(); + const TypeEntryCPtr &parent); + virtual ~TypeEntryPrivate() = default; QString shortName() const; - const TypeEntry *m_parent; + TypeEntryCPtr m_parent; QString m_name; // C++ fully qualified - QString m_targetLangApiName; mutable QString m_cachedShortName; // C++ excluding inline namespaces QString m_entryName; QString m_targetLangPackage; mutable QString m_cachedTargetLangName; // "Foo.Bar" mutable QString m_cachedTargetLangEntryName; // "Bar" - CustomFunction m_customConstructor; - CustomFunction m_customDestructor; - CodeSnipList m_codeSnips; - DocModificationList m_docModifications; IncludeList m_extraIncludes; Include m_include; - QString m_targetConversionRule; QVersionNumber m_version; - CustomConversion *m_customConversion = nullptr; SourceLocation m_sourceLocation; // XML file TypeEntry::CodeGeneration m_codeGeneration = TypeEntry::GenerateCode; - TypeEntry *m_viewOn = nullptr; + TypeEntryPtr m_viewOn; + CustomTypeEntryPtr m_targetLangApiType; int m_revision = 0; int m_sbkIndex = 0; TypeEntry::Type m_type; bool m_stream = false; bool m_private = false; + bool m_builtin = false; }; TypeEntryPrivate::TypeEntryPrivate(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : m_parent(parent), m_name(buildName(entryName, parent)), m_entryName(entryName), @@ -106,13 +95,8 @@ TypeEntryPrivate::TypeEntryPrivate(const QString &entryName, TypeEntry::Type t, { } -TypeEntryPrivate::~TypeEntryPrivate() -{ - delete m_customConversion; -} - TypeEntry::TypeEntry(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : TypeEntry(new TypeEntryPrivate(entryName, t, vr, parent)) { } @@ -123,31 +107,6 @@ TypeEntry::TypeEntry(TypeEntryPrivate *d) : m_d(d) TypeEntry::~TypeEntry() = default; -CodeSnipList TypeEntry::codeSnips() const -{ - return m_d->m_codeSnips; -} - -void TypeEntry::setCodeSnips(const CodeSnipList &codeSnips) -{ - m_d->m_codeSnips = codeSnips; -} - -void TypeEntry::addCodeSnip(const CodeSnip &codeSnip) -{ - m_d->m_codeSnips << codeSnip; -} - -void TypeEntry::setDocModification(const DocModificationList &docMods) -{ - m_d->m_docModifications << docMods; -} - -DocModificationList TypeEntry::docModifications() const -{ - return m_d->m_docModifications; -} - const IncludeList &TypeEntry::extraIncludes() const { return m_d->m_extraIncludes; @@ -174,47 +133,31 @@ void TypeEntry::setInclude(const Include &inc) // This is a workaround for preventing double inclusion of the QSharedPointer implementation // header, which does not use header guards. In the previous parser this was not a problem // because the Q_QDOC define was set, and the implementation header was never included. - if (inc.name().endsWith(QLatin1String("qsharedpointer_impl.h"))) { + if (inc.name().endsWith(u"qsharedpointer_impl.h")) { QString path = inc.name(); - path.remove(QLatin1String("_impl")); + path.remove(u"_impl"_s); m_d->m_include = Include(inc.type(), path); } else { m_d->m_include = inc; } } -void TypeEntry::setTargetConversionRule(const QString &conversionRule) -{ - m_d->m_targetConversionRule = conversionRule; -} - -QString TypeEntry::targetConversionRule() const -{ - return m_d->m_targetConversionRule; -} - QVersionNumber TypeEntry::version() const { return m_d->m_version; } -bool TypeEntry::hasTargetConversionRule() const -{ - return !m_d->m_targetConversionRule.isEmpty(); -} - -bool TypeEntry::isCppPrimitive() const +bool isCppPrimitive(const TypeEntryCPtr &e) { - if (!isPrimitive()) + if (!e->isPrimitive()) return false; - if (m_d->m_type == VoidType) + if (e->type() == TypeEntry::VoidType) return true; - const PrimitiveTypeEntry *referencedType = - static_cast<const PrimitiveTypeEntry *>(this)->basicReferencedTypeEntry(); - const QString &typeName = referencedType ? referencedType->name() : m_d->m_name; - return typeName.contains(QLatin1Char(' ')) || primitiveCppTypes().contains(typeName); + PrimitiveTypeEntryCPtr referencedType = basicReferencedTypeEntry(e); + const QString &typeName = referencedType->name(); + return AbstractMetaType::cppPrimitiveTypes().contains(typeName); } TypeEntry::Type TypeEntry::type() const @@ -222,17 +165,17 @@ TypeEntry::Type TypeEntry::type() const return m_d->m_type; } -const TypeEntry *TypeEntry::parent() const +TypeEntryCPtr TypeEntry::parent() const { return m_d->m_parent; } -void TypeEntry::setParent(const TypeEntry *p) +void TypeEntry::setParent(const TypeEntryCPtr &p) { m_d->m_parent = p; } -bool TypeEntry::isChildOf(const TypeEntry *p) const +bool TypeEntry::isChildOf(const TypeEntryCPtr &p) const { for (auto e = m_d->m_parent; e; e = e->parent()) { if (e == p) @@ -241,18 +184,18 @@ bool TypeEntry::isChildOf(const TypeEntry *p) const return false; } -const TypeSystemTypeEntry *TypeEntry::typeSystemTypeEntry() const +TypeSystemTypeEntryCPtr typeSystemTypeEntry(TypeEntryCPtr e) { - for (auto e = this; e; e = e->parent()) { + for (; e; e = e->parent()) { if (e->type() == TypeEntry::TypeSystemType) - return static_cast<const TypeSystemTypeEntry *>(e); + return std::static_pointer_cast<const TypeSystemTypeEntry>(e); } - return nullptr; + return {}; } -const TypeEntry *TypeEntry::targetLangEnclosingEntry() const +TypeEntryCPtr targetLangEnclosingEntry(const TypeEntryCPtr &e) { - auto result = m_d->m_parent; + auto result = e->parent(); while (result && result->type() != TypeEntry::TypeSystemType && !NamespaceTypeEntry::isVisibleScope(result)) { result = result->parent(); @@ -295,6 +238,14 @@ bool TypeEntry::isSmartPointer() const return m_d->m_type == SmartPointerType; } +bool TypeEntry::isUniquePointer() const +{ + if (m_d->m_type != SmartPointerType) + return false; + auto *ste = static_cast<const SmartPointerTypeEntry *>(this); + return ste->smartPointerType() == TypeSystem::SmartPointerType::Unique; +} + bool TypeEntry::isArray() const { return m_d->m_type == ArrayType; @@ -317,7 +268,7 @@ bool TypeEntry::isVarargs() const bool TypeEntry::isCustom() const { - return m_d->m_type == CustomType; + return m_d->m_type == CustomType || m_d->m_type == PythonType; } bool TypeEntry::isTypeSystem() const @@ -345,6 +296,16 @@ void TypeEntry::setStream(bool b) m_d->m_stream = b; } +bool TypeEntry::isBuiltIn() const +{ + return m_d->m_builtin; +} + +void TypeEntry::setBuiltIn(bool b) +{ + m_d->m_builtin = b; +} + bool TypeEntry::isPrivate() const { return m_d->m_private; @@ -365,11 +326,11 @@ QString TypeEntry::name() const QString TypeEntryPrivate::shortName() const { if (m_cachedShortName.isEmpty()) { - QVarLengthArray<const TypeEntry *> parents; + QVarLengthArray<TypeEntryCPtr > parents; bool foundInlineNamespace = false; for (auto p = m_parent; p != nullptr && p->type() != TypeEntry::TypeSystemType; p = p->parent()) { if (p->type() == TypeEntry::NamespaceType - && static_cast<const NamespaceTypeEntry *>(p)->isInlineNamespace()) { + && std::static_pointer_cast<const NamespaceTypeEntry>(p)->isInlineNamespace()) { foundInlineNamespace = true; } else { parents.append(p); @@ -377,9 +338,9 @@ QString TypeEntryPrivate::shortName() const } if (foundInlineNamespace) { m_cachedShortName.reserve(m_name.size()); - for (int i = parents.size() - 1; i >= 0; --i) { + for (auto i = parents.size() - 1; i >= 0; --i) { m_cachedShortName.append(parents.at(i)->entryName()); - m_cachedShortName.append(QLatin1String("::")); + m_cachedShortName.append(u"::"_s); } m_cachedShortName.append(m_entryName); } else { @@ -414,6 +375,11 @@ bool TypeEntry::generateCode() const return m_d->m_codeGeneration == GenerateCode; } +bool TypeEntry::shouldGenerate() const +{ + return generateCode() && NamespaceTypeEntry::isVisibleScope(this); +} + int TypeEntry::revision() const { return m_d->m_revision; @@ -429,15 +395,25 @@ QString TypeEntry::qualifiedCppName() const return m_d->m_name; } -QString TypeEntry::targetLangApiName() const +CustomTypeEntryCPtr TypeEntry::targetLangApiType() const { - return m_d->m_targetLangApiName.isEmpty() - ? m_d->m_name : m_d->m_targetLangApiName; + return m_d->m_targetLangApiType; } -void TypeEntry::setTargetLangApiName(const QString &t) +bool TypeEntry::hasTargetLangApiType() const { - m_d->m_targetLangApiName = t; + return m_d->m_targetLangApiType != nullptr; +} + +void TypeEntry::setTargetLangApiType(const CustomTypeEntryPtr &cte) +{ + m_d->m_targetLangApiType = cte; +} + +QString TypeEntry::targetLangApiName() const +{ + return m_d->m_targetLangApiType != nullptr + ? m_d->m_targetLangApiType->name() : m_d->m_name; } QString TypeEntry::targetLangName() const @@ -458,9 +434,9 @@ QString TypeEntry::buildTargetLangName() const for (auto p = parent(); p && p->type() != TypeEntry::TypeSystemType; p = p->parent()) { if (NamespaceTypeEntry::isVisibleScope(p)) { if (!result.isEmpty()) - result.prepend(QLatin1Char('.')); + result.prepend(u'.'); QString n = p->m_d->m_entryName; - n.replace(QLatin1String("::"), QLatin1String(".")); // Primitive types may have "std::" + n.replace(u"::"_s, u"."_s); // Primitive types may have "std::" result.prepend(n); } } @@ -489,15 +465,13 @@ void TypeEntry::setSourceLocation(const SourceLocation &sourceLocation) m_d->m_sourceLocation = sourceLocation; } -bool TypeEntry::isUserPrimitive() const +bool isUserPrimitive(const TypeEntryCPtr &e) { - if (!isPrimitive()) + if (!e->isPrimitive()) return false; - const auto *trueType = static_cast<const PrimitiveTypeEntry *>(this); - if (trueType->basicReferencedTypeEntry()) - trueType = trueType->basicReferencedTypeEntry(); - return trueType->isPrimitive() && !trueType->isCppPrimitive() - && trueType->qualifiedCppName() != u"std::string"; + const auto type = basicReferencedTypeEntry(e); + return !isCppPrimitive(type) + && type->qualifiedCppName() != u"std::string"; } bool TypeEntry::isWrapperType() const @@ -505,29 +479,23 @@ bool TypeEntry::isWrapperType() const return isObject() || isValue() || isSmartPointer(); } -bool TypeEntry::isCppIntegralPrimitive() const +bool isCppIntegralPrimitive(const TypeEntryCPtr &e) { - if (!isCppPrimitive()) + if (!isCppPrimitive(e)) return false; - const auto *trueType = static_cast<const PrimitiveTypeEntry *>(this); - if (trueType->basicReferencedTypeEntry()) - trueType = trueType->basicReferencedTypeEntry(); - QString typeName = trueType->qualifiedCppName(); - return !typeName.contains(u"double") - && !typeName.contains(u"float") - && !typeName.contains(u"wchar"); + const auto type = basicReferencedTypeEntry(e); + return AbstractMetaType::cppIntegralTypes().contains(type->qualifiedCppName()); } -bool TypeEntry::isExtendedCppPrimitive() const +bool isExtendedCppPrimitive(const TypeEntryCPtr &e) { - if (isCppPrimitive()) + if (isCppPrimitive(e)) return true; - if (!isPrimitive()) + if (!e->isPrimitive()) return false; - const auto *trueType = static_cast<const PrimitiveTypeEntry *>(this); - if (trueType->basicReferencedTypeEntry()) - trueType = trueType->basicReferencedTypeEntry(); - return trueType->qualifiedCppName() == u"std::string"; + const auto type = basicReferencedTypeEntry(e); + const QString &name = type->qualifiedCppName(); + return name == u"std::string" || name == u"std::wstring"; } const TypeEntryPrivate *TypeEntry::d_func() const @@ -544,7 +512,7 @@ QString TypeEntry::targetLangEntryName() const { if (m_d->m_cachedTargetLangEntryName.isEmpty()) { m_d->m_cachedTargetLangEntryName = targetLangName(); - const int lastDot = m_d->m_cachedTargetLangEntryName.lastIndexOf(QLatin1Char('.')); + const int lastDot = m_d->m_cachedTargetLangEntryName.lastIndexOf(u'.'); if (lastDot != -1) m_d->m_cachedTargetLangEntryName.remove(0, lastDot + 1); } @@ -563,27 +531,7 @@ void TypeEntry::setTargetLangPackage(const QString &p) QString TypeEntry::qualifiedTargetLangName() const { - return targetLangPackage() + QLatin1Char('.') + targetLangName(); -} - -void TypeEntry::setCustomConstructor(const CustomFunction &func) -{ - m_d->m_customConstructor = func; -} - -CustomFunction TypeEntry::customConstructor() const -{ - return m_d->m_customConstructor; -} - -void TypeEntry::setCustomDestructor(const CustomFunction &func) -{ - m_d->m_customDestructor = func; -} - -CustomFunction TypeEntry::customDestructor() const -{ - return m_d->m_customDestructor; + return targetLangPackage() + u'.' + targetLangName(); } bool TypeEntry::isValue() const @@ -596,27 +544,12 @@ bool TypeEntry::isComplex() const return false; } -bool TypeEntry::hasCustomConversion() const -{ - return m_d->m_customConversion != nullptr; -} - -void TypeEntry::setCustomConversion(CustomConversion* customConversion) -{ - m_d->m_customConversion = customConversion; -} - -CustomConversion* TypeEntry::customConversion() const -{ - return m_d->m_customConversion; -} - -TypeEntry *TypeEntry::viewOn() const +TypeEntryPtr TypeEntry::viewOn() const { return m_d->m_viewOn; } -void TypeEntry::setViewOn(TypeEntry *v) +void TypeEntry::setViewOn(const TypeEntryPtr &v) { m_d->m_viewOn = v; } @@ -627,13 +560,15 @@ TypeEntry *TypeEntry::clone() const } // Take over parameters relevant for typedefs -void TypeEntry::useAsTypedef(const TypeEntry *source) +void TypeEntry::useAsTypedef(const TypeEntryCPtr &source) { // XML Typedefs are in the global namespace for now. - m_d->m_parent = source->typeSystemTypeEntry(); + m_d->m_parent = typeSystemTypeEntry(source); m_d->m_entryName = source->m_d->m_entryName; m_d->m_name = source->m_d->m_name; m_d->m_targetLangPackage = source->m_d->m_targetLangPackage; + m_d->m_cachedTargetLangName.clear(); // Clear cached names. + m_d->m_cachedTargetLangEntryName.clear(); m_d->m_codeGeneration = source->m_d->m_codeGeneration; m_d->m_version = source->m_d->m_version; } @@ -648,7 +583,7 @@ public: }; CustomTypeEntry::CustomTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : TypeEntry(new CustomTypeEntryPrivate(entryName, CustomType, vr, parent)) { } @@ -664,6 +599,12 @@ TypeEntry *CustomTypeEntry::clone() const return new CustomTypeEntry(new CustomTypeEntryPrivate(*d)); } +bool CustomTypeEntry::hasCheckFunction() const +{ + S_D(const CustomTypeEntry); + return !d->m_checkFunction.isEmpty(); +} + QString CustomTypeEntry::checkFunction() const { S_D(const CustomTypeEntry); @@ -676,17 +617,62 @@ void CustomTypeEntry::setCheckFunction(const QString &f) d->m_checkFunction = f; } +// ----------------- PythonTypeEntry +class PythonTypeEntryPrivate : public CustomTypeEntryPrivate +{ +public: + using CustomTypeEntryPrivate::CustomTypeEntryPrivate; + explicit PythonTypeEntryPrivate(const QString &entryName, + const QString &checkFunction, + TypeSystem::CPythonType type) : + CustomTypeEntryPrivate(entryName, TypeEntry::PythonType, {}, {}), + m_cPythonType(type) + { + m_checkFunction = checkFunction; + } + + TypeSystem::CPythonType m_cPythonType; +}; + +PythonTypeEntry::PythonTypeEntry(const QString &entryName, + const QString &checkFunction, + TypeSystem::CPythonType type) : + CustomTypeEntry(new PythonTypeEntryPrivate(entryName, checkFunction, type)) +{ +} + +TypeEntry *PythonTypeEntry::clone() const +{ + S_D(const PythonTypeEntry); + return new PythonTypeEntry(new PythonTypeEntryPrivate(*d)); +} + +TypeSystem::CPythonType PythonTypeEntry::cPythonType() const +{ + S_D(const PythonTypeEntry); + return d->m_cPythonType; +} + +PythonTypeEntry::PythonTypeEntry(TypeEntryPrivate *d) : + CustomTypeEntry(d) +{ +} + // ----------------- TypeSystemTypeEntry class TypeSystemTypeEntryPrivate : public TypeEntryPrivate { public: using TypeEntryPrivate::TypeEntryPrivate; + CodeSnipList m_codeSnips; TypeSystem::SnakeCase m_snakeCase = TypeSystem::SnakeCase::Disabled; + QString m_subModuleOf; + QString m_namespaceBegin; + QString m_namespaceEnd; }; TypeSystemTypeEntry::TypeSystemTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : TypeEntry(new TypeSystemTypeEntryPrivate(entryName, TypeSystemType, vr, parent)) { } @@ -702,6 +688,60 @@ TypeEntry *TypeSystemTypeEntry::clone() const return new TypeSystemTypeEntry(new TypeSystemTypeEntryPrivate(*d)); } +const CodeSnipList &TypeSystemTypeEntry::codeSnips() const +{ + S_D(const TypeSystemTypeEntry); + return d->m_codeSnips; +} + +CodeSnipList &TypeSystemTypeEntry::codeSnips() +{ + S_D(TypeSystemTypeEntry); + return d->m_codeSnips; +} + +void TypeSystemTypeEntry::addCodeSnip(const CodeSnip &codeSnip) +{ + S_D(TypeSystemTypeEntry); + d->m_codeSnips.append(codeSnip); +} + +QString TypeSystemTypeEntry::subModuleOf() const +{ + S_D(const TypeSystemTypeEntry); + return d->m_subModuleOf; +} + +void TypeSystemTypeEntry::setSubModule(const QString &s) +{ + S_D(TypeSystemTypeEntry); + d->m_subModuleOf = s; +} + +const QString &TypeSystemTypeEntry::namespaceBegin() const +{ + S_D(const TypeSystemTypeEntry); + return d->m_namespaceBegin; +} + +void TypeSystemTypeEntry::setNamespaceBegin(const QString &p) +{ + S_D(TypeSystemTypeEntry); + d->m_namespaceBegin = p; +} + +const QString &TypeSystemTypeEntry::namespaceEnd() const +{ + S_D(const TypeSystemTypeEntry); + return d->m_namespaceEnd; +} + +void TypeSystemTypeEntry::setNamespaceEnd(const QString &n) +{ + S_D(TypeSystemTypeEntry); + d->m_namespaceEnd = n; +} + TypeSystem::SnakeCase TypeSystemTypeEntry::snakeCase() const { S_D(const TypeSystemTypeEntry); @@ -716,7 +756,7 @@ void TypeSystemTypeEntry::setSnakeCase(TypeSystem::SnakeCase sc) // ----------------- VoidTypeEntry VoidTypeEntry::VoidTypeEntry() : - TypeEntry(QLatin1String("void"), VoidType, QVersionNumber(0, 0), nullptr) + TypeEntry(u"void"_s, VoidType, QVersionNumber(0, 0), nullptr) { } @@ -731,7 +771,7 @@ TypeEntry *VoidTypeEntry::clone() const } VarargsTypeEntry::VarargsTypeEntry() : - TypeEntry(QLatin1String("..."), VarargsType, QVersionNumber(0, 0), nullptr) + TypeEntry(u"..."_s, VarargsType, QVersionNumber(0, 0), nullptr) { } @@ -756,7 +796,7 @@ public: }; TemplateArgumentEntry::TemplateArgumentEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : TypeEntry(new TemplateArgumentEntryPrivate(entryName, TemplateArgumentType, vr, parent)) { } @@ -788,30 +828,30 @@ TemplateArgumentEntry::TemplateArgumentEntry(TemplateArgumentEntryPrivate *d) : class ArrayTypeEntryPrivate : public TypeEntryPrivate { public: - explicit ArrayTypeEntryPrivate(const TypeEntry *nested_type, const QVersionNumber &vr, - const TypeEntry *parent) : - TypeEntryPrivate(QLatin1String("Array"), TypeEntry::ArrayType, vr, parent), + explicit ArrayTypeEntryPrivate(const TypeEntryCPtr &nested_type, const QVersionNumber &vr, + const TypeEntryCPtr &parent) : + TypeEntryPrivate(u"Array"_s, TypeEntry::ArrayType, vr, parent), m_nestedType(nested_type) { } - const TypeEntry *m_nestedType; + TypeEntryCPtr m_nestedType; }; -ArrayTypeEntry::ArrayTypeEntry(const TypeEntry *nested_type, const QVersionNumber &vr, - const TypeEntry *parent) : +ArrayTypeEntry::ArrayTypeEntry(const TypeEntryCPtr &nested_type, const QVersionNumber &vr, + const TypeEntryCPtr &parent) : TypeEntry(new ArrayTypeEntryPrivate(nested_type, vr, parent)) { Q_ASSERT(nested_type); } -void ArrayTypeEntry::setNestedTypeEntry(TypeEntry *nested) +void ArrayTypeEntry::setNestedTypeEntry(const TypeEntryPtr &nested) { S_D(ArrayTypeEntry); d->m_nestedType = nested; } -const TypeEntry *ArrayTypeEntry::nestedTypeEntry() const +TypeEntryCPtr ArrayTypeEntry::nestedTypeEntry() const { S_D(const ArrayTypeEntry); return d->m_nestedType; @@ -820,7 +860,7 @@ const TypeEntry *ArrayTypeEntry::nestedTypeEntry() const QString ArrayTypeEntry::buildTargetLangName() const { S_D(const ArrayTypeEntry); - return d->m_nestedType->targetLangName() + QLatin1String("[]"); + return d->m_nestedType->targetLangName() + u"[]"_s; } TypeEntry *ArrayTypeEntry::clone() const @@ -839,19 +879,20 @@ class PrimitiveTypeEntryPrivate : public TypeEntryPrivate { public: PrimitiveTypeEntryPrivate(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : TypeEntryPrivate(entryName, TypeEntry::PrimitiveType, vr, parent), m_preferredTargetLangType(true) { } QString m_defaultConstructor; + CustomConversionPtr m_customConversion; + PrimitiveTypeEntryPtr m_referencedTypeEntry; uint m_preferredTargetLangType : 1; - PrimitiveTypeEntry* m_referencedTypeEntry = nullptr; }; PrimitiveTypeEntry::PrimitiveTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : TypeEntry(new PrimitiveTypeEntryPrivate(entryName, vr, parent)) { } @@ -874,26 +915,46 @@ bool PrimitiveTypeEntry::hasDefaultConstructor() const return !d->m_defaultConstructor.isEmpty(); } -PrimitiveTypeEntry *PrimitiveTypeEntry::referencedTypeEntry() const +PrimitiveTypeEntryPtr PrimitiveTypeEntry::referencedTypeEntry() const { S_D(const PrimitiveTypeEntry); return d->m_referencedTypeEntry; } -void PrimitiveTypeEntry::setReferencedTypeEntry(PrimitiveTypeEntry *referencedTypeEntry) +void PrimitiveTypeEntry::setReferencedTypeEntry(PrimitiveTypeEntryPtr referencedTypeEntry) { S_D(PrimitiveTypeEntry); d->m_referencedTypeEntry = referencedTypeEntry; } -PrimitiveTypeEntry *PrimitiveTypeEntry::basicReferencedTypeEntry() const +PrimitiveTypeEntryCPtr basicReferencedTypeEntry(const PrimitiveTypeEntryCPtr &e) { - S_D(const PrimitiveTypeEntry); - if (!d->m_referencedTypeEntry) - return nullptr; + auto result = e; + while (auto referenced = result->referencedTypeEntry()) + result = referenced; + return result; +} - PrimitiveTypeEntry *baseReferencedTypeEntry = d->m_referencedTypeEntry->basicReferencedTypeEntry(); - return baseReferencedTypeEntry ? baseReferencedTypeEntry : d->m_referencedTypeEntry; +PrimitiveTypeEntryCPtr basicReferencedTypeEntry(const TypeEntryCPtr &e) +{ + Q_ASSERT(e->isPrimitive()); + return basicReferencedTypeEntry(std::static_pointer_cast<const PrimitiveTypeEntry>(e)); +} + +PrimitiveTypeEntryCPtr basicReferencedNonBuiltinTypeEntry(const PrimitiveTypeEntryCPtr &e) +{ + auto result = e; + for (; result->referencedTypeEntry() ; result = result->referencedTypeEntry()) { + if (!result->isBuiltIn()) + break; + } + return result; +} + +bool PrimitiveTypeEntry::referencesType() const +{ + S_D(const PrimitiveTypeEntry); + return d->m_referencedTypeEntry != nullptr; } bool PrimitiveTypeEntry::preferredTargetLangType() const @@ -908,6 +969,24 @@ void PrimitiveTypeEntry::setPreferredTargetLangType(bool b) d->m_preferredTargetLangType = b; } +bool PrimitiveTypeEntry::hasCustomConversion() const +{ + S_D(const PrimitiveTypeEntry); + return bool(d->m_customConversion); +} + +void PrimitiveTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion) +{ + S_D(PrimitiveTypeEntry); + d->m_customConversion = customConversion; +} + +CustomConversionPtr PrimitiveTypeEntry::customConversion() const +{ + S_D(const PrimitiveTypeEntry); + return d->m_customConversion; +} + TypeEntry *PrimitiveTypeEntry::clone() const { S_D(const PrimitiveTypeEntry); @@ -919,22 +998,85 @@ PrimitiveTypeEntry::PrimitiveTypeEntry(PrimitiveTypeEntryPrivate *d) { } -// ----------------- EnumTypeEntry -class EnumTypeEntryPrivate : public TypeEntryPrivate +// ----------------- ConfigurableTypeEntry + +class ConfigurableTypeEntryPrivate : public TypeEntryPrivate { public: using TypeEntryPrivate::TypeEntryPrivate; - const EnumValueTypeEntry *m_nullValue = nullptr; + QString m_configCondition; +}; + +ConfigurableTypeEntry::ConfigurableTypeEntry(const QString &entryName, Type t, + const QVersionNumber &vr, + const TypeEntryCPtr &parent) : + TypeEntry(new ConfigurableTypeEntryPrivate(entryName, t, vr, parent)) +{ +} + +ConfigurableTypeEntry::ConfigurableTypeEntry(ConfigurableTypeEntryPrivate *d) : + TypeEntry(d) +{ +} + +TypeEntry *ConfigurableTypeEntry::clone() const +{ + S_D(const ConfigurableTypeEntry); + return new ConfigurableTypeEntry(new ConfigurableTypeEntryPrivate(*d)); +} + +QString ConfigurableTypeEntry::configCondition() const +{ + S_D(const ConfigurableTypeEntry); + return d->m_configCondition; +} + +void ConfigurableTypeEntry::setConfigCondition(const QString &c) +{ + S_D(ConfigurableTypeEntry); + d->m_configCondition = c; + if (!d->m_configCondition.startsWith(u'#')) + d->m_configCondition.prepend(u"#if "); +} + +bool ConfigurableTypeEntry::hasConfigCondition() const +{ + S_D(const ConfigurableTypeEntry); + return !d->m_configCondition.isEmpty(); +} + +// ----------------- EnumTypeEntry +class EnumTypeEntryPrivate : public ConfigurableTypeEntryPrivate +{ +public: + using ConfigurableTypeEntryPrivate::ConfigurableTypeEntryPrivate; + + EnumValueTypeEntryCPtr m_nullValue; QStringList m_rejectedEnums; - FlagsTypeEntry *m_flags = nullptr; + FlagsTypeEntryPtr m_flags; + QString m_cppType; + QString m_docFile; + TypeSystem::PythonEnumType m_pythonEnumType = TypeSystem::PythonEnumType::Unspecified; }; EnumTypeEntry::EnumTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent) : - TypeEntry(new EnumTypeEntryPrivate(entryName, EnumType, vr, parent)) + const TypeEntryCPtr &parent) : + ConfigurableTypeEntry(new EnumTypeEntryPrivate(entryName, EnumType, vr, parent)) +{ +} + +TypeSystem::PythonEnumType EnumTypeEntry::pythonEnumType() const +{ + S_D(const EnumTypeEntry); + return d->m_pythonEnumType; +} + +void EnumTypeEntry::setPythonEnumType(TypeSystem::PythonEnumType t) { + S_D(EnumTypeEntry); + d->m_pythonEnumType = t; } QString EnumTypeEntry::targetLangQualifier() const @@ -954,30 +1096,42 @@ QString EnumTypeEntry::qualifier() const parentEntry->name() : QString(); } -const EnumValueTypeEntry *EnumTypeEntry::nullValue() const +EnumValueTypeEntryCPtr EnumTypeEntry::nullValue() const { S_D(const EnumTypeEntry); return d->m_nullValue; } -void EnumTypeEntry::setNullValue(const EnumValueTypeEntry *n) +void EnumTypeEntry::setNullValue(const EnumValueTypeEntryCPtr &n) { S_D(EnumTypeEntry); d->m_nullValue = n; } -void EnumTypeEntry::setFlags(FlagsTypeEntry *flags) +void EnumTypeEntry::setFlags(const FlagsTypeEntryPtr &flags) { S_D(EnumTypeEntry); d->m_flags = flags; } -FlagsTypeEntry *EnumTypeEntry::flags() const +FlagsTypeEntryPtr EnumTypeEntry::flags() const { S_D(const EnumTypeEntry); return d->m_flags; } +QString EnumTypeEntry::cppType() const +{ + S_D(const EnumTypeEntry); + return d->m_cppType; +} + +void EnumTypeEntry::setCppType(const QString &t) +{ + S_D(EnumTypeEntry); + d->m_cppType = t; +} + bool EnumTypeEntry::isEnumValueRejected(const QString &name) const { S_D(const EnumTypeEntry); @@ -996,6 +1150,18 @@ QStringList EnumTypeEntry::enumValueRejections() const return d->m_rejectedEnums; } +QString EnumTypeEntry::docFile() const +{ + S_D(const EnumTypeEntry); + return d->m_docFile; +} + +void EnumTypeEntry::setDocFile(const QString &df) +{ + S_D(EnumTypeEntry); + d->m_docFile = df; +} + TypeEntry *EnumTypeEntry::clone() const { S_D(const EnumTypeEntry); @@ -1003,7 +1169,7 @@ TypeEntry *EnumTypeEntry::clone() const } EnumTypeEntry::EnumTypeEntry(EnumTypeEntryPrivate *d) : - TypeEntry(d) + ConfigurableTypeEntry(d) { } @@ -1012,7 +1178,7 @@ class EnumValueTypeEntryPrivate : public TypeEntryPrivate { public: EnumValueTypeEntryPrivate(const QString &name, const QString &value, - const EnumTypeEntry *enclosingEnum, + const EnumTypeEntryCPtr &enclosingEnum, bool isScopedEnum, const QVersionNumber &vr) : TypeEntryPrivate(name, TypeEntry::EnumValue, vr, @@ -1023,11 +1189,11 @@ public: } QString m_value; - const EnumTypeEntry *m_enclosingEnum; + EnumTypeEntryCPtr m_enclosingEnum; }; EnumValueTypeEntry::EnumValueTypeEntry(const QString &name, const QString &value, - const EnumTypeEntry *enclosingEnum, + const EnumTypeEntryCPtr &enclosingEnum, bool isScopedEnum, const QVersionNumber &vr) : TypeEntry(new EnumValueTypeEntryPrivate(name, value, enclosingEnum, isScopedEnum, vr)) @@ -1040,7 +1206,7 @@ QString EnumValueTypeEntry::value() const return d->m_value; } -const EnumTypeEntry *EnumValueTypeEntry::enclosingEnum() const +EnumTypeEntryCPtr EnumValueTypeEntry::enclosingEnum() const { S_D(const EnumValueTypeEntry); return d->m_enclosingEnum; @@ -1065,11 +1231,11 @@ public: QString m_originalName; QString m_flagsName; - EnumTypeEntry *m_enum = nullptr; + EnumTypeEntryPtr m_enum; }; FlagsTypeEntry::FlagsTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : TypeEntry(new FlagsTypeEntryPrivate(entryName, FlagsType, vr, parent)) { } @@ -1078,7 +1244,7 @@ QString FlagsTypeEntry::buildTargetLangName() const { S_D(const FlagsTypeEntry); QString on = d->m_originalName; - on.replace(QLatin1String("::"), QLatin1String(".")); + on.replace(u"::"_s, u"."_s); return on; } @@ -1111,13 +1277,13 @@ void FlagsTypeEntry::setFlagsName(const QString &name) d->m_flagsName = name; } -EnumTypeEntry *FlagsTypeEntry::originator() const +EnumTypeEntryPtr FlagsTypeEntry::originator() const { S_D(const FlagsTypeEntry); return d->m_enum; } -void FlagsTypeEntry::setOriginator(EnumTypeEntry *e) +void FlagsTypeEntry::setOriginator(const EnumTypeEntryPtr &e) { S_D(FlagsTypeEntry); d->m_enum = e; @@ -1131,7 +1297,7 @@ TypeEntry *FlagsTypeEntry::clone() const // ----------------- ConstantValueTypeEntry ConstantValueTypeEntry::ConstantValueTypeEntry(const QString& name, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : TypeEntry(name, ConstantValueType, QVersionNumber(0, 0), parent) { } @@ -1142,13 +1308,13 @@ ConstantValueTypeEntry::ConstantValueTypeEntry(TypeEntryPrivate *d) : } // ----------------- ComplexTypeEntry -class ComplexTypeEntryPrivate : public TypeEntryPrivate +class ComplexTypeEntryPrivate : public ConfigurableTypeEntryPrivate { public: ComplexTypeEntryPrivate(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr, - const TypeEntry *parent) : - TypeEntryPrivate(entryName, t, vr, parent), + const TypeEntryCPtr &parent) : + ConfigurableTypeEntryPrivate(entryName, t, vr, parent), m_qualifiedCppName(buildName(entryName, parent)), m_polymorphicBase(false), m_genericClass(false), @@ -1158,8 +1324,14 @@ public: AddedFunctionList m_addedFunctions; FunctionModificationList m_functionMods; + CodeSnipList m_codeSnips; + DocModificationList m_docModifications; + DocModificationList m_functionDocModifications; + IncludeList m_argumentIncludes; + QSet<QString> m_generateFunctions; FieldModificationList m_fieldMods; QList<TypeSystemProperty> m_properties; + QList<TypeSystemPyMethodDefEntry> m_PyMethodDefEntrys; QString m_defaultConstructor; QString m_defaultSuperclass; QString m_qualifiedCppName; @@ -1169,24 +1341,29 @@ public: uint m_deleteInMainThread : 1; QString m_polymorphicIdValue; + QString m_polymorphicNameFunction; QString m_targetType; ComplexTypeEntry::TypeFlags m_typeFlags; ComplexTypeEntry::CopyableFlag m_copyableFlag = ComplexTypeEntry::Unknown; QString m_hashFunction; - const ComplexTypeEntry* m_baseContainerType = nullptr; + ComplexTypeEntryCPtr m_baseContainerType; // For class functions TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; TypeSystem::AllowThread m_allowThread = TypeSystem::AllowThread::Unspecified; TypeSystem::SnakeCase m_snakeCase = TypeSystem::SnakeCase::Unspecified; TypeSystem::BoolCast m_operatorBoolMode = TypeSystem::BoolCast::Unspecified; TypeSystem::BoolCast m_isNullMode = TypeSystem::BoolCast::Unspecified; + TypeSystem::QtMetaTypeRegistration m_qtMetaTypeRegistration = + TypeSystem::QtMetaTypeRegistration::Unspecified; + // Determined by AbstractMetaBuilder from the code model. + bool m_isValueTypeWithCopyConstructorOnly = false; }; ComplexTypeEntry::ComplexTypeEntry(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr, - const TypeEntry *parent) : - TypeEntry(new ComplexTypeEntryPrivate(entryName, t, vr, parent)) + const TypeEntryCPtr &parent) : + ConfigurableTypeEntry(new ComplexTypeEntryPrivate(entryName, t, vr, parent)) { } @@ -1249,18 +1426,77 @@ void ComplexTypeEntry::addFunctionModification(const FunctionModification &funct d->m_functionMods << functionModification; } -FunctionModificationList ComplexTypeEntry::functionModifications(const QString &signature) const +FunctionModificationList + ComplexTypeEntry::functionModifications(const QStringList &signatures) const { S_D(const ComplexTypeEntry); FunctionModificationList lst; - for (int i = 0; i < d->m_functionMods.count(); ++i) { - const FunctionModification &mod = d->m_functionMods.at(i); - if (mod.matches(signature)) + for (const auto &mod : std::as_const(d->m_functionMods)) { + if (mod.matches(signatures)) lst << mod; } return lst; } +const CodeSnipList &ComplexTypeEntry::codeSnips() const +{ + S_D(const ComplexTypeEntry); + return d->m_codeSnips; +} + +CodeSnipList &ComplexTypeEntry::codeSnips() +{ + S_D(ComplexTypeEntry); + return d->m_codeSnips; +} + +void ComplexTypeEntry::setCodeSnips(const CodeSnipList &codeSnips) +{ + S_D(ComplexTypeEntry); + d->m_codeSnips = codeSnips; +} + +void ComplexTypeEntry::addCodeSnip(const CodeSnip &codeSnip) +{ + S_D(ComplexTypeEntry); + d->m_codeSnips << codeSnip; +} + +void ComplexTypeEntry::setDocModification(const DocModificationList &docMods) +{ + S_D(ComplexTypeEntry); + for (const auto &m : docMods) { + if (m.signature().isEmpty()) + d->m_docModifications << m; + else + d->m_functionDocModifications << m; + } +} + +DocModificationList ComplexTypeEntry::docModifications() const +{ + S_D(const ComplexTypeEntry); + return d->m_docModifications; +} + +DocModificationList ComplexTypeEntry::functionDocModifications() const +{ + S_D(const ComplexTypeEntry); + return d->m_functionDocModifications; +} + +const IncludeList &ComplexTypeEntry::argumentIncludes() const +{ + S_D(const ComplexTypeEntry); + return d->m_argumentIncludes; +} + +void ComplexTypeEntry::addArgumentInclude(const Include &newInclude) +{ + S_D(ComplexTypeEntry); + IncludeGroup::appendInclude(newInclude, &d->m_argumentIncludes); +} + AddedFunctionList ComplexTypeEntry::addedFunctions() const { S_D(const ComplexTypeEntry); @@ -1279,6 +1515,30 @@ void ComplexTypeEntry::addNewFunction(const AddedFunctionPtr &addedFunction) d->m_addedFunctions << addedFunction; } +const QList<TypeSystemPyMethodDefEntry> &ComplexTypeEntry::addedPyMethodDefEntrys() const +{ + S_D(const ComplexTypeEntry); + return d->m_PyMethodDefEntrys; +} + +void ComplexTypeEntry::addPyMethodDef(const TypeSystemPyMethodDefEntry &p) +{ + S_D(ComplexTypeEntry); + d->m_PyMethodDefEntrys.append(p); +} + +const QSet<QString> &ComplexTypeEntry::generateFunctions() const +{ + S_D(const ComplexTypeEntry); + return d->m_generateFunctions; +} + +void ComplexTypeEntry::setGenerateFunctions(const QSet<QString> &f) +{ + S_D(ComplexTypeEntry); + d->m_generateFunctions = f; +} + void ComplexTypeEntry::setFieldModifications(const FieldModificationList &mods) { S_D(ComplexTypeEntry); @@ -1345,6 +1605,18 @@ QString ComplexTypeEntry::polymorphicIdValue() const return d->m_polymorphicIdValue; } +QString ComplexTypeEntry::polymorphicNameFunction() const +{ + S_D(const ComplexTypeEntry); + return d->m_polymorphicNameFunction; +} + +void ComplexTypeEntry::setPolymorphicNameFunction(const QString &n) +{ + S_D(ComplexTypeEntry); + d->m_polymorphicNameFunction = n; +} + QString ComplexTypeEntry::targetType() const { S_D(const ComplexTypeEntry); @@ -1393,6 +1665,18 @@ void ComplexTypeEntry::setCopyable(ComplexTypeEntry::CopyableFlag flag) d->m_copyableFlag = flag; } +TypeSystem::QtMetaTypeRegistration ComplexTypeEntry::qtMetaTypeRegistration() const +{ + S_D(const ComplexTypeEntry); + return d->m_qtMetaTypeRegistration; +} + +void ComplexTypeEntry::setQtMetaTypeRegistration(TypeSystem::QtMetaTypeRegistration r) +{ + S_D(ComplexTypeEntry); + d->m_qtMetaTypeRegistration = r; +} + QString ComplexTypeEntry::hashFunction() const { S_D(const ComplexTypeEntry); @@ -1405,13 +1689,13 @@ void ComplexTypeEntry::setHashFunction(const QString &hashFunction) d->m_hashFunction = hashFunction; } -void ComplexTypeEntry::setBaseContainerType(const ComplexTypeEntry *baseContainer) +void ComplexTypeEntry::setBaseContainerType(const ComplexTypeEntryCPtr &baseContainer) { S_D(ComplexTypeEntry); d->m_baseContainerType = baseContainer; } -const ComplexTypeEntry *ComplexTypeEntry::baseContainerType() const +ComplexTypeEntryCPtr ComplexTypeEntry::baseContainerType() const { S_D(const ComplexTypeEntry); return d->m_baseContainerType; @@ -1471,6 +1755,31 @@ void ComplexTypeEntry::setSnakeCase(TypeSystem::SnakeCase sc) d->m_snakeCase = sc; } +bool ComplexTypeEntry::isValueTypeWithCopyConstructorOnly() const +{ + S_D(const ComplexTypeEntry); + return d->m_isValueTypeWithCopyConstructorOnly; +} + +void ComplexTypeEntry::setValueTypeWithCopyConstructorOnly(bool v) +{ + S_D(ComplexTypeEntry); + d->m_isValueTypeWithCopyConstructorOnly = v; +} + +// FIXME PYSIDE 7: Remove this and make "true" the default +static bool parentManagementEnabled = false; + +bool ComplexTypeEntry::isParentManagementEnabled() +{ + return parentManagementEnabled; +} + +void ComplexTypeEntry::setParentManagementEnabled(bool e) +{ + parentManagementEnabled = e; +} + TypeEntry *ComplexTypeEntry::clone() const { S_D(const ComplexTypeEntry); @@ -1478,16 +1787,17 @@ TypeEntry *ComplexTypeEntry::clone() const } // Take over parameters relevant for typedefs -void ComplexTypeEntry::useAsTypedef(const ComplexTypeEntry *source) +void ComplexTypeEntry::useAsTypedef(const ComplexTypeEntryCPtr &source) { S_D(ComplexTypeEntry); TypeEntry::useAsTypedef(source); d->m_qualifiedCppName = source->qualifiedCppName(); d->m_targetType = source->targetType(); + d->m_typeFlags.setFlag(ComplexTypeEntry::Typedef); } ComplexTypeEntry::ComplexTypeEntry(ComplexTypeEntryPrivate *d) : - TypeEntry(d) + ConfigurableTypeEntry(d) { } @@ -1506,7 +1816,7 @@ public: TypedefEntryPrivate(const QString &entryName, const QString &sourceType, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : ComplexTypeEntryPrivate(entryName, TypeEntry::TypedefType, vr, parent), m_sourceType(sourceType) @@ -1514,12 +1824,12 @@ public: } QString m_sourceType; - ComplexTypeEntry *m_source = nullptr; - ComplexTypeEntry *m_target = nullptr; + ComplexTypeEntryCPtr m_source; + ComplexTypeEntryPtr m_target; }; TypedefEntry::TypedefEntry(const QString &entryName, const QString &sourceType, - const QVersionNumber &vr, const TypeEntry *parent) : + const QVersionNumber &vr, const TypeEntryCPtr &parent) : ComplexTypeEntry(new TypedefEntryPrivate(entryName, sourceType, vr, parent)) { } @@ -1542,25 +1852,25 @@ TypeEntry *TypedefEntry::clone() const return new TypedefEntry(new TypedefEntryPrivate(*d)); } -ComplexTypeEntry *TypedefEntry::source() const +ComplexTypeEntryCPtr TypedefEntry::source() const { S_D(const TypedefEntry); return d->m_source; } -void TypedefEntry::setSource(ComplexTypeEntry *source) +void TypedefEntry::setSource(const ComplexTypeEntryCPtr &source) { S_D(TypedefEntry); d->m_source = source; } -ComplexTypeEntry *TypedefEntry::target() const +ComplexTypeEntryPtr TypedefEntry::target() const { S_D(const TypedefEntry); return d->m_target; } -void TypedefEntry::setTarget(ComplexTypeEntry *target) +void TypedefEntry::setTarget(ComplexTypeEntryPtr target) { S_D(TypedefEntry); d->m_target = target; @@ -1578,18 +1888,41 @@ public: ContainerTypeEntryPrivate(const QString &entryName, ContainerTypeEntry::ContainerKind containerKind, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : ComplexTypeEntryPrivate(entryName, TypeEntry::ContainerType, vr, parent), m_containerKind(containerKind) { } + OpaqueContainers::const_iterator findOpaqueContainer(const QStringList &instantiations) const + { + return std::find_if(m_opaqueContainers.cbegin(), m_opaqueContainers.cend(), + [&instantiations](const OpaqueContainer &r) { + return r.instantiations == instantiations; + }); + } + + OpaqueContainers m_opaqueContainers; + CustomConversionPtr m_customConversion; ContainerTypeEntry::ContainerKind m_containerKind; }; +QString OpaqueContainer::templateParameters() const +{ + QString result; + result += u'<'; + for (qsizetype i = 0, size = instantiations.size(); i < size; ++i) { + if (i) + result += u','; + result += instantiations.at(i); + } + result += u'>'; + return result; +} + ContainerTypeEntry::ContainerTypeEntry(const QString &entryName, ContainerKind containerKind, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : ComplexTypeEntry(new ContainerTypeEntryPrivate(entryName, containerKind, vr, parent)) { setCodeGeneration(GenerateForSubclass); @@ -1601,6 +1934,67 @@ ContainerTypeEntry::ContainerKind ContainerTypeEntry::containerKind() const return d->m_containerKind; } +qsizetype ContainerTypeEntry::templateParameterCount() const +{ + S_D(const ContainerTypeEntry); + qsizetype result = 1; + switch (d->m_containerKind) { + case MapContainer: + case MultiMapContainer: + case PairContainer: + case SpanContainer: + result = 2; + break; + case ListContainer: + case SetContainer: + break; + } + return result; +} + +const OpaqueContainers &ContainerTypeEntry::opaqueContainers() const +{ + S_D(const ContainerTypeEntry); + return d->m_opaqueContainers; +} + +void ContainerTypeEntry::appendOpaqueContainers(const OpaqueContainers &l) +{ + S_D(ContainerTypeEntry); + d->m_opaqueContainers.append(l); +} + +bool ContainerTypeEntry::generateOpaqueContainer(const QStringList &instantiations) const +{ + S_D(const ContainerTypeEntry); + return d->findOpaqueContainer(instantiations) != d->m_opaqueContainers.cend(); +} + +QString ContainerTypeEntry::opaqueContainerName(const QStringList &instantiations) const +{ + S_D(const ContainerTypeEntry); + const auto it = d->findOpaqueContainer(instantiations); + return it != d->m_opaqueContainers.cend() ? it->name : QString{}; +} + +bool ContainerTypeEntry::hasCustomConversion() const +{ + S_D(const ContainerTypeEntry); + return bool(d->m_customConversion); +} + +void ContainerTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion) +{ + S_D(ContainerTypeEntry); + d->m_customConversion = customConversion; +} + +CustomConversionPtr ContainerTypeEntry::customConversion() const +{ + S_D(const ContainerTypeEntry); + return d->m_customConversion; +} + TypeEntry *ContainerTypeEntry::clone() const { S_D(const ContainerTypeEntry); @@ -1618,32 +2012,53 @@ class SmartPointerTypeEntryPrivate : public ComplexTypeEntryPrivate public: SmartPointerTypeEntryPrivate(const QString &entryName, const QString &getterName, - const QString &smartPointerType, + TypeSystem::SmartPointerType type, const QString &refCountMethodName, - const QVersionNumber &vr, const TypeEntry *parent) : + const QVersionNumber &vr, const TypeEntryCPtr &parent) : ComplexTypeEntryPrivate(entryName, TypeEntry::SmartPointerType, vr, parent), m_getterName(getterName), - m_smartPointerType(smartPointerType), - m_refCountMethodName(refCountMethodName) + m_refCountMethodName(refCountMethodName), + m_smartPointerType(type) { } + qsizetype instantiationIndex(const TypeEntryCPtr &t) const; + QString m_getterName; - QString m_smartPointerType; QString m_refCountMethodName; + QString m_valueCheckMethod; + QString m_nullCheckMethod; + QString m_resetMethod; SmartPointerTypeEntry::Instantiations m_instantiations; + TypeSystem::SmartPointerType m_smartPointerType; }; +qsizetype SmartPointerTypeEntryPrivate::instantiationIndex(const TypeEntryCPtr &t) const +{ + for (qsizetype i = 0, size = m_instantiations.size(); i < size; ++i) { + if (m_instantiations.at(i).typeEntry == t) + return i; + } + return -1; +} + SmartPointerTypeEntry::SmartPointerTypeEntry(const QString &entryName, const QString &getterName, - const QString &smartPointerType, + TypeSystem::SmartPointerType smartPointerType, const QString &refCountMethodName, - const QVersionNumber &vr, const TypeEntry *parent) : + const QVersionNumber &vr, + const TypeEntryCPtr &parent) : ComplexTypeEntry(new SmartPointerTypeEntryPrivate(entryName, getterName, smartPointerType, refCountMethodName, vr, parent)) { } +TypeSystem::SmartPointerType SmartPointerTypeEntry::smartPointerType() const +{ + S_D(const SmartPointerTypeEntry); + return d->m_smartPointerType; +} + QString SmartPointerTypeEntry::getter() const { S_D(const SmartPointerTypeEntry); @@ -1656,13 +2071,49 @@ QString SmartPointerTypeEntry::refCountMethodName() const return d->m_refCountMethodName; } +QString SmartPointerTypeEntry::valueCheckMethod() const +{ + S_D(const SmartPointerTypeEntry); + return d->m_valueCheckMethod; +} + +void SmartPointerTypeEntry::setValueCheckMethod(const QString &m) +{ + S_D(SmartPointerTypeEntry); + d->m_valueCheckMethod = m; +} + +QString SmartPointerTypeEntry::nullCheckMethod() const +{ + S_D(const SmartPointerTypeEntry); + return d->m_nullCheckMethod; +} + +void SmartPointerTypeEntry::setNullCheckMethod(const QString &f) +{ + S_D(SmartPointerTypeEntry); + d->m_nullCheckMethod = f; +} + +QString SmartPointerTypeEntry::resetMethod() const +{ + S_D(const SmartPointerTypeEntry); + return d->m_resetMethod; +} + +void SmartPointerTypeEntry::setResetMethod(const QString &f) +{ + S_D(SmartPointerTypeEntry); + d->m_resetMethod = f; +} + TypeEntry *SmartPointerTypeEntry::clone() const { S_D(const SmartPointerTypeEntry); return new SmartPointerTypeEntry(new SmartPointerTypeEntryPrivate(*d)); } -SmartPointerTypeEntry::Instantiations SmartPointerTypeEntry::instantiations() const +const SmartPointerTypeEntry::Instantiations &SmartPointerTypeEntry::instantiations() const { S_D(const SmartPointerTypeEntry); return d->m_instantiations; @@ -1679,10 +2130,38 @@ SmartPointerTypeEntry::SmartPointerTypeEntry(SmartPointerTypeEntryPrivate *d) : { } -bool SmartPointerTypeEntry::matchesInstantiation(const TypeEntry *e) const +bool SmartPointerTypeEntry::matchesInstantiation(const TypeEntryCPtr &e) const +{ + S_D(const SmartPointerTypeEntry); + // No instantiations specified, or match + return d->m_instantiations.isEmpty() || d->instantiationIndex(e) != -1; +} + +static QString fixSmartPointerName(QString name) +{ + name.replace(u"::"_s, u"_"_s); + name.replace(u'<', u'_'); + name.remove(u'>'); + name.remove(u' '); + return name; +} + +QString SmartPointerTypeEntry::getTargetName(const AbstractMetaType &metaType) const { S_D(const SmartPointerTypeEntry); - return d->m_instantiations.isEmpty() || d->m_instantiations.contains(e); + auto instantiatedTe = metaType.instantiations().constFirst().typeEntry(); + const auto index = d->instantiationIndex(instantiatedTe); + if (index != -1 && !d->m_instantiations.at(index).name.isEmpty()) + return d->m_instantiations.at(index).name; + + QString name = metaType.cppSignature(); + const auto templatePos = name.indexOf(u'<'); + if (templatePos != -1) { // "std::shared_ptr<A::B>" -> "shared_ptr<A::B>" + const auto colonPos = name.lastIndexOf(u"::"_s, templatePos); + if (colonPos != -1) + name.remove(0, colonPos + 2); + } + return fixSmartPointerName(name); } // ----------------- NamespaceTypeEntry @@ -1692,7 +2171,7 @@ public: using ComplexTypeEntryPrivate::ComplexTypeEntryPrivate; QRegularExpression m_filePattern; - const NamespaceTypeEntry *m_extends = nullptr; + NamespaceTypeEntryCPtr m_extends; TypeSystem::Visibility m_visibility = TypeSystem::Visibility::Auto; bool m_hasPattern = false; bool m_inlineNamespace = false; @@ -1700,7 +2179,7 @@ public: }; NamespaceTypeEntry::NamespaceTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : ComplexTypeEntry(new NamespaceTypeEntryPrivate(entryName, NamespaceType, vr, parent)) { } @@ -1711,13 +2190,13 @@ TypeEntry *NamespaceTypeEntry::clone() const return new NamespaceTypeEntry(new NamespaceTypeEntryPrivate(*d)); } -const NamespaceTypeEntry *NamespaceTypeEntry::extends() const +NamespaceTypeEntryCPtr NamespaceTypeEntry::extends() const { S_D(const NamespaceTypeEntry); return d->m_extends; } -void NamespaceTypeEntry::setExtends(const NamespaceTypeEntry *e) +void NamespaceTypeEntry::setExtends(const NamespaceTypeEntryCPtr &e) { S_D(NamespaceTypeEntry); d->m_extends = e; @@ -1780,6 +2259,11 @@ void NamespaceTypeEntry::setInlineNamespace(bool i) d->m_inlineNamespace = i; } +bool NamespaceTypeEntry::isVisibleScope(const TypeEntryCPtr &e) +{ + return isVisibleScope(e.get()); +} + bool NamespaceTypeEntry::isVisibleScope(const TypeEntry *e) { return e->type() != TypeEntry::NamespaceType @@ -1799,167 +2283,78 @@ void NamespaceTypeEntry::setGenerateUsing(bool generateUsing) } // ----------------- ValueTypeEntry -ValueTypeEntry::ValueTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent) : - ComplexTypeEntry(entryName, BasicValueType, vr, parent) -{ -} - -bool ValueTypeEntry::isValue() const -{ - return true; -} - -TypeEntry *ValueTypeEntry::clone() const -{ - S_D(const ComplexTypeEntry); - return new ValueTypeEntry(new ComplexTypeEntryPrivate(*d)); -} -ValueTypeEntry::ValueTypeEntry(ComplexTypeEntryPrivate *d) : - ComplexTypeEntry(d) -{ -} - -ValueTypeEntry::ValueTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, - const TypeEntry *parent) : - ComplexTypeEntry(entryName, t, vr, parent) -{ -} - -// ----------------- CustomConversion -struct CustomConversion::CustomConversionPrivate +class ValueTypeEntryPrivate : public ComplexTypeEntryPrivate { - CustomConversionPrivate(const TypeEntry* ownerType) - : ownerType(ownerType), replaceOriginalTargetToNativeConversions(false) - { - } - const TypeEntry* ownerType; - QString nativeToTargetConversion; - bool replaceOriginalTargetToNativeConversions; - TargetToNativeConversions targetToNativeConversions; -}; +public: + using ComplexTypeEntryPrivate::ComplexTypeEntryPrivate; -struct CustomConversion::TargetToNativeConversion::TargetToNativeConversionPrivate -{ - TargetToNativeConversionPrivate() - : sourceType(nullptr) - { - } - const TypeEntry* sourceType; - QString sourceTypeName; - QString sourceTypeCheck; - QString conversion; + QString m_targetConversionRule; + CustomConversionPtr m_customConversion; }; -CustomConversion::CustomConversion(TypeEntry* ownerType) -{ - m_d = new CustomConversionPrivate(ownerType); - if (ownerType) - ownerType->setCustomConversion(this); -} - -CustomConversion::~CustomConversion() -{ - qDeleteAll(m_d->targetToNativeConversions); - delete m_d; -} - -const TypeEntry* CustomConversion::ownerType() const -{ - return m_d->ownerType; -} - -QString CustomConversion::nativeToTargetConversion() const -{ - return m_d->nativeToTargetConversion; -} - -void CustomConversion::setNativeToTargetConversion(const QString& nativeToTargetConversion) -{ - m_d->nativeToTargetConversion = nativeToTargetConversion; -} - -bool CustomConversion::replaceOriginalTargetToNativeConversions() const -{ - return m_d->replaceOriginalTargetToNativeConversions; -} - -void CustomConversion::setReplaceOriginalTargetToNativeConversions(bool replaceOriginalTargetToNativeConversions) -{ - m_d->replaceOriginalTargetToNativeConversions = replaceOriginalTargetToNativeConversions; -} - -bool CustomConversion::hasTargetToNativeConversions() const -{ - return !(m_d->targetToNativeConversions.isEmpty()); -} - -CustomConversion::TargetToNativeConversions& CustomConversion::targetToNativeConversions() -{ - return m_d->targetToNativeConversions; -} - -const CustomConversion::TargetToNativeConversions& CustomConversion::targetToNativeConversions() const +ValueTypeEntry::ValueTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntryCPtr &parent) : + ComplexTypeEntry(new ValueTypeEntryPrivate(entryName, BasicValueType, vr, parent)) { - return m_d->targetToNativeConversions; } -void CustomConversion::addTargetToNativeConversion(const QString& sourceTypeName, - const QString& sourceTypeCheck, - const QString& conversion) +bool ValueTypeEntry::hasCustomConversion() const { - m_d->targetToNativeConversions.append(new TargetToNativeConversion(sourceTypeName, sourceTypeCheck, conversion)); + S_D(const ValueTypeEntry); + return bool(d->m_customConversion); } -CustomConversion::TargetToNativeConversion::TargetToNativeConversion(const QString& sourceTypeName, - const QString& sourceTypeCheck, - const QString& conversion) +void ValueTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion) { - m_d = new TargetToNativeConversionPrivate; - m_d->sourceTypeName = sourceTypeName; - m_d->sourceTypeCheck = sourceTypeCheck; - m_d->conversion = conversion; + S_D(ValueTypeEntry); + d->m_customConversion = customConversion; } -CustomConversion::TargetToNativeConversion::~TargetToNativeConversion() +CustomConversionPtr ValueTypeEntry::customConversion() const { - delete m_d; + S_D(const ValueTypeEntry); + return d->m_customConversion; } -const TypeEntry* CustomConversion::TargetToNativeConversion::sourceType() const +void ValueTypeEntry::setTargetConversionRule(const QString &conversionRule) { - return m_d->sourceType; + S_D(ValueTypeEntry); + d->m_targetConversionRule = conversionRule; } -void CustomConversion::TargetToNativeConversion::setSourceType(const TypeEntry* sourceType) +QString ValueTypeEntry::targetConversionRule() const { - m_d->sourceType = sourceType; + S_D(const ValueTypeEntry); + return d->m_targetConversionRule; } -bool CustomConversion::TargetToNativeConversion::isCustomType() const +bool ValueTypeEntry::hasTargetConversionRule() const { - return !(m_d->sourceType); + S_D(const ValueTypeEntry); + return !d->m_targetConversionRule.isEmpty(); } -QString CustomConversion::TargetToNativeConversion::sourceTypeName() const +bool ValueTypeEntry::isValue() const { - return m_d->sourceTypeName; + return true; } -QString CustomConversion::TargetToNativeConversion::sourceTypeCheck() const +TypeEntry *ValueTypeEntry::clone() const { - return m_d->sourceTypeCheck; + S_D(const ValueTypeEntry); + return new ValueTypeEntry(new ValueTypeEntryPrivate(*d)); } -QString CustomConversion::TargetToNativeConversion::conversion() const +ValueTypeEntry::ValueTypeEntry(ComplexTypeEntryPrivate *d) : + ComplexTypeEntry(d) { - return m_d->conversion; } -void CustomConversion::TargetToNativeConversion::setConversion(const QString& conversion) +ValueTypeEntry::ValueTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, + const TypeEntryCPtr &parent) : + ComplexTypeEntry(entryName, t, vr, parent) { - m_d->conversion = conversion; } // ----------------- FunctionTypeEntry @@ -1968,19 +2363,19 @@ class FunctionTypeEntryPrivate : public TypeEntryPrivate public: FunctionTypeEntryPrivate(const QString &entryName, const QString &signature, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : TypeEntryPrivate(entryName, TypeEntry::FunctionType, vr, parent), m_signatures(signature) { } QStringList m_signatures; - TypeSystem::SnakeCase m_snakeCase = TypeSystem::SnakeCase::Unspecified; + QString m_docFile; }; FunctionTypeEntry::FunctionTypeEntry(const QString &entryName, const QString &signature, const QVersionNumber &vr, - const TypeEntry *parent) : + const TypeEntryCPtr &parent) : TypeEntry(new FunctionTypeEntryPrivate(entryName, signature, vr, parent)) { } @@ -2003,16 +2398,16 @@ bool FunctionTypeEntry::hasSignature(const QString &signature) const return d->m_signatures.contains(signature); } -TypeSystem::SnakeCase FunctionTypeEntry::snakeCase() const +QString FunctionTypeEntry::docFile() const { S_D(const FunctionTypeEntry); - return d->m_snakeCase; + return d->m_docFile; } -void FunctionTypeEntry::setSnakeCase(TypeSystem::SnakeCase sc) +void FunctionTypeEntry::setDocFile(const QString &df) { S_D(FunctionTypeEntry); - d->m_snakeCase = sc; + d->m_docFile = df; } TypeEntry *FunctionTypeEntry::clone() const @@ -2028,7 +2423,7 @@ FunctionTypeEntry::FunctionTypeEntry(FunctionTypeEntryPrivate *d) : // ----------------- ObjectTypeEntry ObjectTypeEntry::ObjectTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent) + const TypeEntryCPtr &parent) : ComplexTypeEntry(entryName, ObjectType, vr, parent) { } @@ -2058,20 +2453,6 @@ ObjectTypeEntry::ObjectTypeEntry(ComplexTypeEntryPrivate *d) : if (!var.isEmpty()) \ debug << ", " << var.size() << ' ' << name; -template <class Container, class Separator> -static void formatList(QDebug &d, const char *name, const Container &c, Separator sep) -{ - if (const int size = c.size()) { - d << ", " << name << '[' << size << "]=("; - for (int i = 0; i < size; ++i) { - if (i) - d << sep; - d << c.at(i); - } - d << ')'; - } -} - void TypeEntry::formatDebug(QDebug &debug) const { const QString cppName = qualifiedCppName(); @@ -2079,11 +2460,13 @@ void TypeEntry::formatDebug(QDebug &debug) const if (m_d->m_name != cppName) debug << "\", cppName=\"" << cppName << '"'; debug << ", type=" << m_d->m_type << ", codeGeneration=" - << m_d->m_codeGeneration << ", target=\"" << targetLangName() << '"'; + << m_d->m_codeGeneration; + const QString &targetName = targetLangName(); + if (m_d->m_name != targetName) + debug << ", target=\"" << targetLangName() << '"'; FORMAT_NONEMPTY_STRING("package", m_d->m_targetLangPackage) FORMAT_BOOL("stream", m_d->m_stream) - FORMAT_LIST_SIZE("codeSnips", m_d->m_codeSnips) - FORMAT_NONEMPTY_STRING("targetConversionRule", m_d->m_targetConversionRule) + FORMAT_BOOL("built-in", m_d->m_builtin) if (m_d->m_viewOn) debug << ", views=" << m_d->m_viewOn->name(); if (!m_d->m_version.isNull() && m_d->m_version > QVersionNumber(0, 0)) @@ -2099,6 +2482,16 @@ void TypeEntry::formatDebug(QDebug &debug) const formatList(debug, "extraIncludes", m_d->m_extraIncludes, ", "); } +void PrimitiveTypeEntry::formatDebug(QDebug &debug) const +{ + TypeEntry::formatDebug(debug); + if (auto e = referencedTypeEntry()) { + debug << ", references"; + for (; e ; e = e->referencedTypeEntry()) + debug << ":\"" << e->qualifiedCppName() <<'"'; + } +} + void ComplexTypeEntry::formatDebug(QDebug &debug) const { S_D(const ComplexTypeEntry); @@ -2118,16 +2511,31 @@ void ComplexTypeEntry::formatDebug(QDebug &debug) const FORMAT_NONEMPTY_STRING("hash", d->m_hashFunction) FORMAT_LIST_SIZE("addedFunctions", d->m_addedFunctions) formatList(debug, "functionMods", d->m_functionMods, ", "); + FORMAT_LIST_SIZE("codeSnips", d->m_codeSnips) FORMAT_LIST_SIZE("fieldMods", d->m_fieldMods) } +void CustomTypeEntry::formatDebug(QDebug &debug) const +{ + S_D(const CustomTypeEntry); + TypeEntry::formatDebug(debug); + debug << ", checkFunction=" << d->m_checkFunction; +} + +void PythonTypeEntry::formatDebug(QDebug &debug) const +{ + S_D(const PythonTypeEntry); + + CustomTypeEntry::formatDebug(debug); + debug << ", type=" << int(d->m_cPythonType); +} + void FunctionTypeEntry::formatDebug(QDebug &debug) const { S_D(const FunctionTypeEntry); TypeEntry::formatDebug(debug); - debug << "signatures=" << d->m_signatures - << ", snakeCase=" << int(d->m_snakeCase); + debug << "signatures=" << d->m_signatures; } void TypedefEntry::formatDebug(QDebug &debug) const @@ -2144,6 +2552,8 @@ void EnumTypeEntry::formatDebug(QDebug &debug) const S_D(const EnumTypeEntry); TypeEntry::formatDebug(debug); + if (d->m_pythonEnumType != TypeSystem::PythonEnumType::Unspecified) + debug << ", python-type=" << int(d->m_pythonEnumType); if (d->m_flags) debug << ", flags=(" << d->m_flags << ')'; } @@ -2160,12 +2570,23 @@ void NamespaceTypeEntry::formatDebug(QDebug &debug) const debug << "[inline]"; } +QDebug operator<<(QDebug d, const OpaqueContainer &oc) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "OpaqueContainer(\"" << oc.name << "\": " << oc.templateParameters() << ')'; + return d; +} + void ContainerTypeEntry::formatDebug(QDebug &debug) const { S_D(const ContainerTypeEntry); ComplexTypeEntry::formatDebug(debug); debug << ", type=" << d->m_containerKind << '"'; + if (!d->m_opaqueContainers.isEmpty()) + debug << ", opaque-containers=[" << d->m_opaqueContainers << ']'; } void SmartPointerTypeEntry::formatDebug(QDebug &debug) const @@ -2174,9 +2595,13 @@ void SmartPointerTypeEntry::formatDebug(QDebug &debug) const ComplexTypeEntry::formatDebug(debug); if (!d->m_instantiations.isEmpty()) { - debug << ", instantiations[" << d->m_instantiations.size() << "]=("; - for (auto i : d->m_instantiations) - debug << i->name() << ','; + debug << "type=" << d->m_type << ", instantiations[" + << d->m_instantiations.size() << "]=("; + for (const auto &i : d->m_instantiations) { + debug << i.typeEntry->name() << ','; + if (!i.name.isEmpty()) + debug << "=\"" << i.name << '"'; + } debug << ')'; } } @@ -2195,6 +2620,12 @@ QDebug operator<<(QDebug d, const TypeEntry *te) return d; } +QDebug operator<<(QDebug d, const TypeEntryCPtr &te) +{ + d << te.get(); + return d; +} + QDebug operator<<(QDebug d, const TemplateEntry *te) { QDebugStateSaver saver(d); @@ -2209,4 +2640,10 @@ QDebug operator<<(QDebug d, const TemplateEntry *te) d << ')'; return d; } + +QDebug operator<<(QDebug d, const TemplateEntryCPtr &te) +{ + d << te.get(); + return d; +} #endif // QT_NO_DEBUG_STREAM diff --git a/sources/shiboken6/ApiExtractor/typesystem.h b/sources/shiboken6/ApiExtractor/typesystem.h index fada1fea3..a2e4debc8 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.h +++ b/sources/shiboken6/ApiExtractor/typesystem.h @@ -1,84 +1,29 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TYPESYSTEM_H #define TYPESYSTEM_H -#include "typesystem_enums.h" -#include "typesystem_typedefs.h" #include "include.h" +#include "typesystem_typedefs.h" -#include <QtCore/QStringList> +#include <QtCore/qobjectdefs.h> +#include <QtCore/QString> #include <QtCore/QScopedPointer> -class CustomFunction; -class CustomConversion; -class EnumValueTypeEntry; -class FlagsTypeEntry; +class AbstractMetaType; +class CustomTypeEntry; +class PrimitiveTypeEntry; class SourceLocation; class TypeSystemTypeEntry; class TypeEntryPrivate; -class TemplateArgumentEntryPrivate; -class ArrayTypeEntryPrivate; -class PrimitiveTypeEntryPrivate; -class EnumTypeEntryPrivate; -class EnumValueTypeEntryPrivate; -class FlagsTypeEntryPrivate; -class ComplexTypeEntryPrivate; -class TypedefEntryPrivate; -class ContainerTypeEntryPrivate; -class SmartPointerTypeEntryPrivate; -class NamespaceTypeEntryPrivate; -class FunctionTypeEntryPrivate; -struct TargetToNativeConversionPrivate; QT_BEGIN_NAMESPACE class QDebug; -class QRegularExpression; -class QTextStream; class QVersionNumber; QT_END_NAMESPACE -struct TypeSystemProperty -{ - bool isValid() const { return !name.isEmpty() && !read.isEmpty() && !type.isEmpty(); } - - QString type; - QString name; - QString read; - QString write; - QString reset; - QString designable; - // Indicates whether actual code is generated instead of relying on libpyside. - bool generateGetSetDef = false; -}; - class TypeEntry { Q_GADGET @@ -101,6 +46,7 @@ public: ArrayType, TypeSystemType, CustomType, + PythonType, FunctionType, SmartPointerType, TypedefType @@ -116,17 +62,14 @@ public: Q_ENUM(CodeGeneration) explicit TypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, - const TypeEntry *parent); + const TypeEntryCPtr &parent); virtual ~TypeEntry(); Type type() const; - const TypeEntry *parent() const; - void setParent(const TypeEntry *p); - bool isChildOf(const TypeEntry *p) const; - const TypeSystemTypeEntry *typeSystemTypeEntry() const; - // cf AbstractMetaClass::targetLangEnclosingClass() - const TypeEntry *targetLangEnclosingEntry() const; + TypeEntryCPtr parent() const; + void setParent(const TypeEntryCPtr &); + bool isChildOf(const TypeEntryCPtr &p) const; bool isPrimitive() const; bool isEnum() const; @@ -135,6 +78,7 @@ public: bool isNamespace() const; bool isContainer() const; bool isSmartPointer() const; + bool isUniquePointer() const; bool isArray() const; bool isTemplateArgument() const; bool isVoid() const; @@ -147,6 +91,9 @@ public: bool stream() const; void setStream(bool b); + bool isBuiltIn() const; + void setBuiltIn(bool b); + bool isPrivate() const; void setPrivate(bool b); @@ -167,6 +114,9 @@ public: // on 'load-typesystem' tag bool generateCode() const; + /// Returns whether the C++ generators should generate this entry + bool shouldGenerate() const; + int revision() const; void setRevision(int r); // see typedatabase.cpp int sbkIndex() const; // see typedatabase.cpp @@ -180,8 +130,10 @@ public: /// be a JNI name, for Python it should represent the CPython type name. /// \return string representing the target language API name /// Currently used only for PrimitiveTypeEntry (attribute "target"). + CustomTypeEntryCPtr targetLangApiType() const; + bool hasTargetLangApiType() const; + void setTargetLangApiType(const CustomTypeEntryPtr &cte); QString targetLangApiName() const; - void setTargetLangApiName(const QString &t); // The type's name in TargetLang QString targetLangName() const; // "Foo.Bar" @@ -194,22 +146,9 @@ public: QString qualifiedTargetLangName() const; - void setCustomConstructor(const CustomFunction &func); - CustomFunction customConstructor() const; - - void setCustomDestructor(const CustomFunction &func); - CustomFunction customDestructor() const; - virtual bool isValue() const; virtual bool isComplex() const; - CodeSnipList codeSnips() const; - void setCodeSnips(const CodeSnipList &codeSnips); - void addCodeSnip(const CodeSnip &codeSnip); - - void setDocModification(const DocModificationList& docMods); - DocModificationList docModifications() const; - const IncludeList &extraIncludes() const; void setExtraIncludes(const IncludeList &includes); void addExtraInclude(const Include &newInclude); @@ -217,49 +156,25 @@ public: Include include() const; void setInclude(const Include &inc); - // FIXME PYSIDE7: Remove - /// Set the target type conversion rule - void setTargetConversionRule(const QString& conversionRule); - - /// Returns the target type conversion rule - QString targetConversionRule() const; - QVersionNumber version() const; - /// TODO-CONVERTER: mark as deprecated - bool hasTargetConversionRule() const; - - bool isCppPrimitive() const; - - bool hasCustomConversion() const; - void setCustomConversion(CustomConversion* customConversion); - CustomConversion* customConversion() const; - // View on: Type to use for function argument conversion, fex // std::string_view -> std::string for foo(std::string_view). // cf AbstractMetaType::viewOn() - TypeEntry *viewOn() const; - void setViewOn(TypeEntry *v); + TypeEntryPtr viewOn() const; + void setViewOn(const TypeEntryPtr &v); virtual TypeEntry *clone() const; - void useAsTypedef(const TypeEntry *source); + void useAsTypedef(const TypeEntryCPtr &source); SourceLocation sourceLocation() const; void setSourceLocation(const SourceLocation &sourceLocation); // Query functions for generators - /// Returns true if the type is a primitive but not a C++ primitive. - bool isUserPrimitive() const; /// Returns true if the type passed has a Python wrapper for it. /// Although namespace has a Python wrapper, it's not considered a type. bool isWrapperType() const; - /// Returns true if the type is a C++ integral primitive, - /// i.e. bool, char, int, long, and their unsigned counterparts. - bool isCppIntegralPrimitive() const; - /// Returns true if the type is an extended C++ primitive, a void*, - /// a const char*, or a std::string (cf isCppPrimitive()). - bool isExtendedCppPrimitive() const; #ifndef QT_NO_DEBUG_STREAM virtual void formatDebug(QDebug &d) const; @@ -279,539 +194,22 @@ private: QScopedPointer<TypeEntryPrivate> m_d; }; -class CustomTypeEntry : public TypeEntry -{ -public: - explicit CustomTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent); - - TypeEntry *clone() const override; - - QString checkFunction() const; - void setCheckFunction(const QString &f); - -protected: - explicit CustomTypeEntry(TypeEntryPrivate *d); -}; - -class TypeSystemTypeEntry : public TypeEntry -{ -public: - explicit TypeSystemTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent); - - TypeEntry *clone() const override; - - TypeSystem::SnakeCase snakeCase() const; - void setSnakeCase(TypeSystem::SnakeCase sc); - -protected: - explicit TypeSystemTypeEntry(TypeEntryPrivate *d); -}; - -class VoidTypeEntry : public TypeEntry -{ -public: - VoidTypeEntry(); - - TypeEntry *clone() const override; - -protected: - explicit VoidTypeEntry(TypeEntryPrivate *d); -}; - -class VarargsTypeEntry : public TypeEntry -{ -public: - VarargsTypeEntry(); - - TypeEntry *clone() const override; - -protected: - explicit VarargsTypeEntry(TypeEntryPrivate *d); -}; - -class TemplateArgumentEntry : public TypeEntry -{ -public: - explicit TemplateArgumentEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent); - - int ordinal() const; - void setOrdinal(int o); - - TypeEntry *clone() const override; - -protected: - explicit TemplateArgumentEntry(TemplateArgumentEntryPrivate *d); -}; - -class ArrayTypeEntry : public TypeEntry -{ -public: - explicit ArrayTypeEntry(const TypeEntry *nested_type, const QVersionNumber &vr, - const TypeEntry *parent); - - void setNestedTypeEntry(TypeEntry *nested); - const TypeEntry *nestedTypeEntry() const; - - TypeEntry *clone() const override; - -protected: - explicit ArrayTypeEntry(ArrayTypeEntryPrivate *d); - - QString buildTargetLangName() const override; -}; - -class PrimitiveTypeEntry : public TypeEntry -{ -public: - explicit PrimitiveTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent); - - QString defaultConstructor() const; - void setDefaultConstructor(const QString& defaultConstructor); - bool hasDefaultConstructor() const; - - /** - * The PrimitiveTypeEntry pointed by this type entry if it - * represents a typedef). - * /return the type referenced by the typedef, or a null pointer - * if the current object is not an typedef - */ - PrimitiveTypeEntry *referencedTypeEntry() const; - - /** - * Defines type referenced by this entry. - * /param referencedTypeEntry type referenced by this entry - */ - void setReferencedTypeEntry(PrimitiveTypeEntry* referencedTypeEntry); - - /** - * Finds the most basic primitive type that the typedef represents, - * i.e. a type that is not an typedef'ed. - * /return the most basic non-typedef'ed primitive type represented - * by this typedef - */ - PrimitiveTypeEntry* basicReferencedTypeEntry() const; - - bool preferredTargetLangType() const; - void setPreferredTargetLangType(bool b); - - TypeEntry *clone() const override; - -protected: - explicit PrimitiveTypeEntry(PrimitiveTypeEntryPrivate *d); -}; - -class EnumTypeEntry : public TypeEntry -{ -public: - explicit EnumTypeEntry(const QString &entryName, - const QVersionNumber &vr, - const TypeEntry *parent); - - QString targetLangQualifier() const; - - QString qualifier() const; - - const EnumValueTypeEntry *nullValue() const; - void setNullValue(const EnumValueTypeEntry *n); - - void setFlags(FlagsTypeEntry *flags); - FlagsTypeEntry *flags() const; - - bool isEnumValueRejected(const QString &name) const; - void addEnumValueRejection(const QString &name); - QStringList enumValueRejections() const; - - TypeEntry *clone() const override; -#ifndef QT_NO_DEBUG_STREAM - void formatDebug(QDebug &d) const override; -#endif -protected: - explicit EnumTypeEntry(EnumTypeEntryPrivate *d); -}; - -// EnumValueTypeEntry is used for resolving integer type templates -// like array<EnumValue>. Note: Dummy entries for integer values will -// be created for non-type template parameters, where m_enclosingEnum==nullptr. -class EnumValueTypeEntry : public TypeEntry -{ -public: - explicit EnumValueTypeEntry(const QString& name, const QString& value, - const EnumTypeEntry* enclosingEnum, - bool isScopedEnum, const QVersionNumber &vr); - - QString value() const; - const EnumTypeEntry* enclosingEnum() const; - - TypeEntry *clone() const override; - -protected: - explicit EnumValueTypeEntry(EnumValueTypeEntryPrivate *d); -}; - -class FlagsTypeEntry : public TypeEntry -{ -public: - explicit FlagsTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent); - - QString originalName() const; - void setOriginalName(const QString &s); - - QString flagsName() const; - void setFlagsName(const QString &name); - - EnumTypeEntry *originator() const; - void setOriginator(EnumTypeEntry *e); - - TypeEntry *clone() const override; - -protected: - explicit FlagsTypeEntry(FlagsTypeEntryPrivate *d); - - QString buildTargetLangName() const override; -}; - -// For primitive values, typically to provide a dummy type for -// example the '2' in non-type template 'Array<2>'. -class ConstantValueTypeEntry : public TypeEntry -{ -public: - explicit ConstantValueTypeEntry(const QString& name, - const TypeEntry *parent); - - TypeEntry *clone() const override; - -protected: - explicit ConstantValueTypeEntry(TypeEntryPrivate *d); -}; - -class ComplexTypeEntry : public TypeEntry -{ -public: - enum TypeFlag { - DisableWrapper = 0x1, - Deprecated = 0x4, - ForceAbstract = 0x8 - }; - Q_DECLARE_FLAGS(TypeFlags, TypeFlag) - - enum CopyableFlag { - CopyableSet, - NonCopyableSet, - Unknown - }; - - explicit ComplexTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, - const TypeEntry *parent); - - bool isComplex() const override; +TypeSystemTypeEntryCPtr typeSystemTypeEntry(TypeEntryCPtr e); - TypeFlags typeFlags() const; - void setTypeFlags(TypeFlags flags); +// cf AbstractMetaClass::targetLangEnclosingClass() +TypeEntryCPtr targetLangEnclosingEntry(const TypeEntryCPtr &e); - // Override command line options to generate nb_bool from - // operator bool or method isNull(). - TypeSystem::BoolCast operatorBoolMode() const; - void setOperatorBoolMode(TypeSystem::BoolCast b); - TypeSystem::BoolCast isNullMode() const; - void setIsNullMode(TypeSystem::BoolCast b); +bool isCppPrimitive(const TypeEntryCPtr &e); - FunctionModificationList functionModifications() const; - void setFunctionModifications(const FunctionModificationList &functionModifications); - void addFunctionModification(const FunctionModification &functionModification); - FunctionModificationList functionModifications(const QString &signature) const; +/// Returns true if the type is a primitive but not a C++ primitive. +bool isUserPrimitive(const TypeEntryCPtr &e); - AddedFunctionList addedFunctions() const; - void setAddedFunctions(const AddedFunctionList &addedFunctions); - void addNewFunction(const AddedFunctionPtr &addedFunction); +/// Returns true if the type is a C++ integral primitive, +/// i.e. bool, char, int, long, and their unsigned counterparts. +bool isCppIntegralPrimitive(const TypeEntryCPtr &e); - void setFieldModifications(const FieldModificationList &mods); - FieldModificationList fieldModifications() const; - - const QList<TypeSystemProperty> &properties() const; - void addProperty(const TypeSystemProperty &p); - - QString defaultSuperclass() const; - void setDefaultSuperclass(const QString &sc); - - QString qualifiedCppName() const override; - - void setIsPolymorphicBase(bool on); - bool isPolymorphicBase() const; - - void setPolymorphicIdValue(const QString &value); - QString polymorphicIdValue() const; - - QString targetType() const; - void setTargetType(const QString &code); - - bool isGenericClass() const; - void setGenericClass(bool isGeneric); - - bool deleteInMainThread() const; - void setDeleteInMainThread(bool d); - - CopyableFlag copyable() const; - void setCopyable(CopyableFlag flag); - - QString hashFunction() const; - void setHashFunction(const QString &hashFunction); - - void setBaseContainerType(const ComplexTypeEntry *baseContainer); - - const ComplexTypeEntry *baseContainerType() const; - - TypeSystem::ExceptionHandling exceptionHandling() const; - void setExceptionHandling(TypeSystem::ExceptionHandling e); - - TypeSystem::AllowThread allowThread() const; - void setAllowThread(TypeSystem::AllowThread allowThread); - - QString defaultConstructor() const; - void setDefaultConstructor(const QString& defaultConstructor); - bool hasDefaultConstructor() const; - - TypeEntry *clone() const override; - - void useAsTypedef(const ComplexTypeEntry *source); - - TypeSystem::SnakeCase snakeCase() const; - void setSnakeCase(TypeSystem::SnakeCase sc); - -#ifndef QT_NO_DEBUG_STREAM - void formatDebug(QDebug &debug) const override; -#endif -protected: - explicit ComplexTypeEntry(ComplexTypeEntryPrivate *d); -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(ComplexTypeEntry::TypeFlags) - -class TypedefEntry : public ComplexTypeEntry -{ -public: - explicit TypedefEntry(const QString &entryName, - const QString &sourceType, - const QVersionNumber &vr, - const TypeEntry *parent); - - QString sourceType() const; - void setSourceType(const QString &s); - - TypeEntry *clone() const override; - - ComplexTypeEntry *source() const; - void setSource(ComplexTypeEntry *source); - - ComplexTypeEntry *target() const; - void setTarget(ComplexTypeEntry *target); - -#ifndef QT_NO_DEBUG_STREAM - void formatDebug(QDebug &d) const override; -#endif -protected: - explicit TypedefEntry(TypedefEntryPrivate *d); -}; - -class ContainerTypeEntry : public ComplexTypeEntry -{ - Q_GADGET -public: - enum ContainerKind { - ListContainer, - SetContainer, - MapContainer, - MultiMapContainer, - PairContainer, - }; - Q_ENUM(ContainerKind) - - explicit ContainerTypeEntry(const QString &entryName, ContainerKind containerKind, - const QVersionNumber &vr, const TypeEntry *parent); - - ContainerKind containerKind() const; - - TypeEntry *clone() const override; - -#ifndef QT_NO_DEBUG_STREAM - void formatDebug(QDebug &d) const override; -#endif -protected: - explicit ContainerTypeEntry(ContainerTypeEntryPrivate *d); -}; - -class SmartPointerTypeEntry : public ComplexTypeEntry -{ -public: - using Instantiations = QList<const TypeEntry *>; - - explicit SmartPointerTypeEntry(const QString &entryName, - const QString &getterName, - const QString &smartPointerType, - const QString &refCountMethodName, - const QVersionNumber &vr, - const TypeEntry *parent); - - QString getter() const; - - QString refCountMethodName() const; - - TypeEntry *clone() const override; - - Instantiations instantiations() const; - void setInstantiations(const Instantiations &i); - bool matchesInstantiation(const TypeEntry *e) const; - -#ifndef QT_NO_DEBUG_STREAM - void formatDebug(QDebug &d) const override; -#endif -protected: - SmartPointerTypeEntry(SmartPointerTypeEntryPrivate *d); -}; - -class NamespaceTypeEntry : public ComplexTypeEntry -{ -public: - explicit NamespaceTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent); - - TypeEntry *clone() const override; - - const NamespaceTypeEntry *extends() const; - void setExtends(const NamespaceTypeEntry *e); - - const QRegularExpression &filePattern() const; // restrict files - void setFilePattern(const QRegularExpression &r); - - bool hasPattern() const; - - bool matchesFile(const QString &needle) const; - - bool isVisible() const; - void setVisibility(TypeSystem::Visibility v); - - // C++ 11 inline namespace, from code model - bool isInlineNamespace() const; - void setInlineNamespace(bool i); - - static bool isVisibleScope(const TypeEntry *e); - -#ifndef QT_NO_DEBUG_STREAM - void formatDebug(QDebug &d) const override; -#endif - - // Whether to generate "using namespace" into wrapper - bool generateUsing() const; - void setGenerateUsing(bool generateUsing); - -protected: - explicit NamespaceTypeEntry(NamespaceTypeEntryPrivate *d); -}; - -class ValueTypeEntry : public ComplexTypeEntry -{ -public: - explicit ValueTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent); - - bool isValue() const override; - - TypeEntry *clone() const override; - -protected: - explicit ValueTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, - const TypeEntry *parent); - explicit ValueTypeEntry(ComplexTypeEntryPrivate *d); -}; - -class FunctionTypeEntry : public TypeEntry -{ -public: - explicit FunctionTypeEntry(const QString& name, const QString& signature, - const QVersionNumber &vr, - const TypeEntry *parent); - - const QStringList &signatures() const; - bool hasSignature(const QString& signature) const; - void addSignature(const QString& signature); - - TypeSystem::SnakeCase snakeCase() const; - void setSnakeCase(TypeSystem::SnakeCase sc); - - TypeEntry *clone() const override; - -#ifndef QT_NO_DEBUG_STREAM - void formatDebug(QDebug &d) const override; -#endif - -protected: - explicit FunctionTypeEntry(FunctionTypeEntryPrivate *d); -}; - -class ObjectTypeEntry : public ComplexTypeEntry -{ -public: - explicit ObjectTypeEntry(const QString &entryName, const QVersionNumber &vr, - const TypeEntry *parent); - - TypeEntry *clone() const override; - -protected: - explicit ObjectTypeEntry(ComplexTypeEntryPrivate *d); -}; - -class CustomConversion -{ -public: - CustomConversion(TypeEntry* ownerType); - ~CustomConversion(); - - const TypeEntry* ownerType() const; - QString nativeToTargetConversion() const; - void setNativeToTargetConversion(const QString& nativeToTargetConversion); - - class TargetToNativeConversion - { - public: - TargetToNativeConversion(const QString& sourceTypeName, - const QString& sourceTypeCheck, - const QString& conversion = QString()); - ~TargetToNativeConversion(); - - const TypeEntry* sourceType() const; - void setSourceType(const TypeEntry* sourceType); - bool isCustomType() const; - QString sourceTypeName() const; - QString sourceTypeCheck() const; - QString conversion() const; - void setConversion(const QString& conversion); - private: - struct TargetToNativeConversionPrivate; - TargetToNativeConversionPrivate* m_d; - }; - - /** - * Returns true if the target to C++ custom conversions should - * replace the original existing ones, and false if the custom - * conversions should be added to the original. - */ - bool replaceOriginalTargetToNativeConversions() const; - void setReplaceOriginalTargetToNativeConversions(bool replaceOriginalTargetToNativeConversions); - - using TargetToNativeConversions = QList<TargetToNativeConversion *>; - bool hasTargetToNativeConversions() const; - TargetToNativeConversions& targetToNativeConversions(); - const TargetToNativeConversions& targetToNativeConversions() const; - void addTargetToNativeConversion(const QString& sourceTypeName, - const QString& sourceTypeCheck, - const QString& conversion = QString()); -private: - struct CustomConversionPrivate; - CustomConversionPrivate* m_d; -}; +/// Returns true if the type is an extended C++ primitive, a void*, +/// a const char*, or a std::string (cf isCppPrimitive()). +bool isExtendedCppPrimitive(const TypeEntryCPtr &e); #endif // TYPESYSTEM_H diff --git a/sources/shiboken6/ApiExtractor/typesystem_enums.h b/sources/shiboken6/ApiExtractor/typesystem_enums.h index 1a972ec1f..9ecbb08a1 100644 --- a/sources/shiboken6/ApiExtractor/typesystem_enums.h +++ b/sources/shiboken6/ApiExtractor/typesystem_enums.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TYPESYSTEM_ENUMS_H #define TYPESYSTEM_ENUMS_H @@ -43,10 +18,10 @@ enum Language { }; enum class AllowThread { + Unspecified, Allow, Disallow, - Auto, - Unspecified + Auto }; enum Ownership { @@ -60,6 +35,7 @@ enum CodeSnipPosition { CodeSnipPositionBeginning, CodeSnipPositionEnd, CodeSnipPositionDeclaration, + CodeSnipPositionPyOverride, CodeSnipPositionAny }; @@ -98,6 +74,38 @@ enum class BoolCast { // Generate nb_bool (overriding command line) Enabled }; +enum class CPythonType +{ + Bool, + Float, + Integer, + String, + Other +}; + +enum class QtMetaTypeRegistration +{ + Unspecified, + Enabled, + BaseEnabled, // Registration only for the base class of a hierarchy + Disabled +}; + +enum class SmartPointerType { + Shared, + Unique, + Handle, + ValueHandle +}; + +enum class PythonEnumType { + Unspecified, + Enum, + IntEnum, + Flag, + IntFlag +}; + enum : int { OverloadNumberUnset = -1, OverloadNumberDefault = 99999 }; } // namespace TypeSystem diff --git a/sources/shiboken6/ApiExtractor/typesystem_typedefs.h b/sources/shiboken6/ApiExtractor/typesystem_typedefs.h index e7a72aa46..5a4e12ff2 100644 --- a/sources/shiboken6/ApiExtractor/typesystem_typedefs.h +++ b/sources/shiboken6/ApiExtractor/typesystem_typedefs.h @@ -1,53 +1,79 @@ -/**************************************************************************** -** -** Copyright (C) 2017 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$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TYPESYSTEM_TYPEDEFS_H #define TYPESYSTEM_TYPEDEFS_H -#include <QtCore/QHash> -#include <QtCore/QList> -#include <QtCore/QSharedPointer> #include <QtCore/QList> -class CodeSnip; -class DocModification; +#include <memory> -struct AddedFunction; -class FieldModification; -class FunctionModification; +class ArrayTypeEntry; +class ComplexTypeEntry; +class ConfigurableTypeEntry; +class ConstantValueTypeEntry; +class ContainerTypeEntry; +class CustomTypeEntry; +class EnumTypeEntry; +class EnumValueTypeEntry; +class FlagsTypeEntry; +class FunctionTypeEntry; +class NamespaceTypeEntry; +class ObjectTypeEntry; +class PrimitiveTypeEntry; +class SmartPointerTypeEntry; +class TemplateEntry; class TypeEntry; +class TypedefEntry; +class TypeSystemTypeEntry; +class ValueTypeEntry; + +using ArrayTypeEntryPtr = std::shared_ptr<ArrayTypeEntry>; +using ComplexTypeEntryPtr = std::shared_ptr<ComplexTypeEntry>; +using ConfigurableTypeEntryPtr = std::shared_ptr<ConfigurableTypeEntry>; +using ConstantValueTypeEntryPtr = std::shared_ptr<ConstantValueTypeEntry>; +using ContainerTypeEntryPtr = std::shared_ptr<ContainerTypeEntry>; +using CustomTypeEntryPtr = std::shared_ptr<CustomTypeEntry>; +using EnumTypeEntryPtr = std::shared_ptr<EnumTypeEntry>; +using EnumValueTypeEntryPtr = std::shared_ptr<EnumValueTypeEntry>; +using FlagsTypeEntryPtr = std::shared_ptr<FlagsTypeEntry>; +using FunctionTypeEntryPtr = std::shared_ptr<FunctionTypeEntry>; +using NamespaceTypeEntryPtr = std::shared_ptr<NamespaceTypeEntry>; +using ObjectTypeEntryPtr = std::shared_ptr<ObjectTypeEntry>; +using PrimitiveTypeEntryPtr = std::shared_ptr<PrimitiveTypeEntry>; +using SmartPointerTypeEntryPtr = std::shared_ptr<SmartPointerTypeEntry>; +using TemplateEntryPtr = std::shared_ptr<TemplateEntry>; +using TypeEntryPtr = std::shared_ptr<TypeEntry>; +using TypedefEntryPtr = std::shared_ptr<TypedefEntry>; +using TypeSystemTypeEntryPtr = std::shared_ptr<TypeSystemTypeEntry>; +using ValueTypeEntryPtr = std::shared_ptr<ValueTypeEntry>; + +using ArrayTypeEntryCPtr = std::shared_ptr<const ArrayTypeEntry>; +using ComplexTypeEntryCPtr = std::shared_ptr<const ComplexTypeEntry>; +using ConstantValueTypeEntryCPtr = std::shared_ptr<const ConstantValueTypeEntry>; +using ConfigurableTypeEntryCPtr = std::shared_ptr<const ConfigurableTypeEntry>; +using ContainerTypeEntryCPtr = std::shared_ptr<const ContainerTypeEntry>; +using CustomTypeEntryCPtr = std::shared_ptr<const CustomTypeEntry>; +using EnumTypeEntryCPtr = std::shared_ptr<const EnumTypeEntry>; +using EnumValueTypeEntryCPtr = std::shared_ptr<const EnumValueTypeEntry>; +using FlagsTypeEntryCPtr = std::shared_ptr<const FlagsTypeEntry>; +using FunctionTypeEntryCPtr = std::shared_ptr<const FunctionTypeEntry>; +using NamespaceTypeEntryCPtr = std::shared_ptr<const NamespaceTypeEntry>; +using ObjectTypeEntryCPtr = std::shared_ptr<const ObjectTypeEntry>; +using PrimitiveTypeEntryCPtr = std::shared_ptr<const PrimitiveTypeEntry>; +using SmartPointerTypeEntryCPtr = std::shared_ptr<const SmartPointerTypeEntry>; +using TemplateEntryCPtr = std::shared_ptr<const TemplateEntry>; +using TypeEntryCPtr = std::shared_ptr<const TypeEntry>; +using TypedefEntryCPtr = std::shared_ptr<const TypedefEntry>; +using TypeSystemTypeEntryCPtr = std::shared_ptr<const TypeSystemTypeEntry>; +using ValueTypeEntryCPtr = std::shared_ptr<const ValueTypeEntry>; -using AddedFunctionPtr = QSharedPointer<AddedFunction>; -using AddedFunctionList = QList<AddedFunctionPtr>; -using CodeSnipList = QList<CodeSnip>; -using DocModificationList = QList<DocModification>; -using FieldModificationList = QList<FieldModification>; -using FunctionModificationList = QList<FunctionModification>; -using TypeEntries = QList<const TypeEntry *>; +using ComplexTypeEntryCList = QList<ComplexTypeEntryCPtr>; +using ContainerTypeEntryCList = QList<ContainerTypeEntryCPtr>; +using NamespaceTypeEntryList = QList<NamespaceTypeEntryPtr>; +using PrimitiveTypeEntryCList = QList<PrimitiveTypeEntryCPtr>; +using SmartPointerTypeEntryList = QList<SmartPointerTypeEntryCPtr>; +using TypeEntryList = QList<TypeEntryPtr>; +using TypeEntryCList = QList<TypeEntryCPtr>; #endif // TYPESYSTEM_TYPEDEFS_H diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp index ea07b752e..2b686e997 100644 --- a/sources/shiboken6/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp @@ -1,38 +1,33 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 "typesystemparser.h" +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "typesystemparser_p.h" +#include "anystringview_helpers.h" +#include "addedfunction.h" +#include "codesnip.h" +#include "enumtypeentry.h" +#include "containertypeentry.h" +#include "customconversion.h" +#include "customtypenentry.h" +#include "flagstypeentry.h" +#include "functiontypeentry.h" +#include "namespacetypeentry.h" +#include "objecttypeentry.h" +#include "primitivetypeentry.h" +#include "smartpointertypeentry.h" +#include "typedefentry.h" +#include "typesystemtypeentry.h" +#include "valuetypeentry.h" +#include "modifications.h" #include "typedatabase.h" #include "messages.h" #include "reporthandler.h" #include "sourcelocation.h" #include "conditionalstreamreader.h" +#include "qtcompat.h" + +#include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFile> #include <QtCore/QFileInfo> @@ -49,74 +44,103 @@ #include <optional> #include <memory> -static inline QString allowThreadAttribute() { return QStringLiteral("allow-thread"); } -static inline QString colonColon() { return QStringLiteral("::"); } -static inline QString checkFunctionAttribute() { return QStringLiteral("check-function"); } -static inline QString copyableAttribute() { return QStringLiteral("copyable"); } -static inline QString accessAttribute() { return QStringLiteral("access"); } -static inline QString actionAttribute() { return QStringLiteral("action"); } -static inline QString quoteAfterLineAttribute() { return QStringLiteral("quote-after-line"); } -static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote-before-line"); } -static inline QString textAttribute() { return QStringLiteral("text"); } -static inline QString nameAttribute() { return QStringLiteral("name"); } -static inline QString sinceAttribute() { return QStringLiteral("since"); } -static inline QString untilAttribute() { return QStringLiteral("until"); } -static inline QString defaultSuperclassAttribute() { return QStringLiteral("default-superclass"); } -static inline QString deleteInMainThreadAttribute() { return QStringLiteral("delete-in-main-thread"); } -static inline QString deprecatedAttribute() { return QStringLiteral("deprecated"); } -static inline QString disableWrapperAttribute() { return QStringLiteral("disable-wrapper"); } -static inline QString exceptionHandlingAttribute() { return QStringLiteral("exception-handling"); } -static inline QString extensibleAttribute() { return QStringLiteral("extensible"); } -static inline QString fileNameAttribute() { return QStringLiteral("file-name"); } -static inline QString flagsAttribute() { return QStringLiteral("flags"); } -static inline QString forceAbstractAttribute() { return QStringLiteral("force-abstract"); } -static inline QString forceIntegerAttribute() { return QStringLiteral("force-integer"); } -static inline QString formatAttribute() { return QStringLiteral("format"); } -static inline QString generateUsingAttribute() { return QStringLiteral("generate-using"); } -static inline QString classAttribute() { return QStringLiteral("class"); } -static inline QString generateAttribute() { return QStringLiteral("generate"); } -static inline QString generateGetSetDefAttribute() { return QStringLiteral("generate-getsetdef"); } -static inline QString genericClassAttribute() { return QStringLiteral("generic-class"); } -static inline QString indexAttribute() { return QStringLiteral("index"); } -static inline QString invalidateAfterUseAttribute() { return QStringLiteral("invalidate-after-use"); } -static inline QString isNullAttribute() { return QStringLiteral("isNull"); } -static inline QString locationAttribute() { return QStringLiteral("location"); } -static inline QString modifiedTypeAttribute() { return QStringLiteral("modified-type"); } -static inline QString operatorBoolAttribute() { return QStringLiteral("operator-bool"); } -static inline QString pyiTypeAttribute() { return QStringLiteral("pyi-type"); } -static inline QString overloadNumberAttribute() { return QStringLiteral("overload-number"); } -static inline QString ownershipAttribute() { return QStringLiteral("owner"); } -static inline QString packageAttribute() { return QStringLiteral("package"); } -static inline QString positionAttribute() { return QStringLiteral("position"); } -static inline QString preferredConversionAttribute() { return QStringLiteral("preferred-conversion"); } -static inline QString preferredTargetLangTypeAttribute() { return QStringLiteral("preferred-target-lang-type"); } -static inline QString removeAttribute() { return QStringLiteral("remove"); } -static inline QString renameAttribute() { return QStringLiteral("rename"); } -static inline QString readAttribute() { return QStringLiteral("read"); } -static inline QString targetLangNameAttribute() { return QStringLiteral("target-lang-name"); } -static inline QString writeAttribute() { return QStringLiteral("write"); } -static inline QString replaceAttribute() { return QStringLiteral("replace"); } -static inline QString toAttribute() { return QStringLiteral("to"); } -static inline QString signatureAttribute() { return QStringLiteral("signature"); } -static inline QString snippetAttribute() { return QStringLiteral("snippet"); } -static inline QString snakeCaseAttribute() { return QStringLiteral("snake-case"); } -static inline QString staticAttribute() { return QStringLiteral("static"); } -static inline QString classmethodAttribute() { return QStringLiteral("classmethod"); } -static inline QString threadAttribute() { return QStringLiteral("thread"); } -static inline QString sourceAttribute() { return QStringLiteral("source"); } -static inline QString streamAttribute() { return QStringLiteral("stream"); } -static inline QString privateAttribute() { return QStringLiteral("private"); } -static inline QString xPathAttribute() { return QStringLiteral("xpath"); } -static inline QString virtualSlotAttribute() { return QStringLiteral("virtual-slot"); } -static inline QString visibleAttribute() { return QStringLiteral("visible"); } -static inline QString enumIdentifiedByValueAttribute() { return QStringLiteral("identified-by-value"); } - -static inline QString noAttributeValue() { return QStringLiteral("no"); } -static inline QString yesAttributeValue() { return QStringLiteral("yes"); } -static inline QString trueAttributeValue() { return QStringLiteral("true"); } -static inline QString falseAttributeValue() { return QStringLiteral("false"); } - -static QList<CustomConversion *> customConversionsForReview; +using namespace Qt::StringLiterals; + +constexpr auto allowThreadAttribute = "allow-thread"_L1; +constexpr auto checkFunctionAttribute = "check-function"_L1; +constexpr auto copyableAttribute = "copyable"_L1; +constexpr auto accessAttribute = "access"_L1; +constexpr auto actionAttribute = "action"_L1; +constexpr auto quoteAfterLineAttribute = "quote-after-line"_L1; +constexpr auto quoteBeforeLineAttribute = "quote-before-line"_L1; +constexpr auto textAttribute = "text"_L1; +constexpr auto nameAttribute = "name"_L1; +constexpr auto sinceAttribute = "since"_L1; +constexpr auto untilAttribute = "until"_L1; +constexpr auto defaultSuperclassAttribute = "default-superclass"_L1; +constexpr auto deleteInMainThreadAttribute = "delete-in-main-thread"_L1; +constexpr auto deprecatedAttribute = "deprecated"_L1; +constexpr auto disableWrapperAttribute = "disable-wrapper"_L1; +constexpr auto docFileAttribute = "doc-file"_L1; +constexpr auto exceptionHandlingAttribute = "exception-handling"_L1; +constexpr auto extensibleAttribute = "extensible"_L1; +constexpr auto fileNameAttribute = "file-name"_L1; +constexpr auto fileAttribute = "file"_L1; +constexpr auto flagsAttribute = "flags"_L1; +constexpr auto forceAbstractAttribute = "force-abstract"_L1; +constexpr auto forceIntegerAttribute = "force-integer"_L1; +constexpr auto formatAttribute = "format"_L1; +constexpr auto generateUsingAttribute = "generate-using"_L1; +constexpr auto generateFunctionsAttribute = "generate-functions"_L1; +constexpr auto classAttribute = "class"_L1; +constexpr auto generateAttribute = "generate"_L1; +constexpr auto generateGetSetDefAttribute = "generate-getsetdef"_L1; +constexpr auto genericClassAttribute = "generic-class"_L1; +constexpr auto indexAttribute = "index"_L1; +constexpr auto invalidateAfterUseAttribute = "invalidate-after-use"_L1; +constexpr auto isNullAttribute = "isNull"_L1; +constexpr auto locationAttribute = "location"_L1; +constexpr auto modifiedTypeAttribute = "modified-type"_L1; +constexpr auto opaqueContainerAttribute = "opaque-containers"_L1; +constexpr auto operatorBoolAttribute = "operator-bool"_L1; +constexpr auto parentManagementAttribute = "parent-management"_L1; +constexpr auto pyiTypeAttribute = "pyi-type"_L1; +constexpr auto overloadNumberAttribute = "overload-number"_L1; +constexpr auto ownershipAttribute = "owner"_L1; +constexpr auto packageAttribute = "package"_L1; +constexpr auto polymorphicBaseAttribute = "polymorphic-base"_L1; +constexpr auto positionAttribute = "position"_L1; +constexpr auto preferredConversionAttribute = "preferred-conversion"_L1; +constexpr auto preferredTargetLangTypeAttribute = "preferred-target-lang-type"_L1; +constexpr auto pythonEnumTypeAttribute = "python-type"_L1; +constexpr auto pythonOverrideAttribute = "python-override"_L1; +constexpr auto cppEnumTypeAttribute = "cpp-type"_L1; +constexpr auto qtMetaObjectFunctionsAttribute = "qt-metaobject"_L1; +constexpr auto qtMetaTypeAttribute = "qt-register-metatype"_L1; +constexpr auto removeAttribute = "remove"_L1; +constexpr auto renameAttribute = "rename"_L1; +constexpr auto readAttribute = "read"_L1; +constexpr auto targetLangNameAttribute = "target-lang-name"_L1; +constexpr auto writeAttribute = "write"_L1; +constexpr auto opaqueContainerFieldAttribute = "opaque-container"_L1; +constexpr auto replaceAttribute = "replace"_L1; +constexpr auto toAttribute = "to"_L1; +constexpr auto signatureAttribute = "signature"_L1; +constexpr auto snippetAttribute = "snippet"_L1; +constexpr auto snakeCaseAttribute = "snake-case"_L1; +constexpr auto staticAttribute = "static"_L1; +constexpr auto classmethodAttribute = "classmethod"_L1; +constexpr auto threadAttribute = "thread"_L1; +constexpr auto sourceAttribute = "source"_L1; +constexpr auto streamAttribute = "stream"_L1; +constexpr auto privateAttribute = "private"_L1; +constexpr auto xPathAttribute = "xpath"_L1; +constexpr auto virtualSlotAttribute = "virtual-slot"_L1; +constexpr auto visibleAttribute = "visible"_L1; +constexpr auto enumIdentifiedByValueAttribute = "identified-by-value"_L1; +constexpr auto subModuleOfAttribute = "submodule-of"_L1; + +constexpr auto noAttributeValue = "no"_L1; +constexpr auto yesAttributeValue = "yes"_L1; +constexpr auto trueAttributeValue = "true"_L1; +constexpr auto falseAttributeValue = "false"_L1; + +static bool isTypeEntry(StackElement el) +{ + return el >= StackElement::FirstTypeEntry && el <= StackElement::LastTypeEntry; +} + +static bool isComplexTypeEntry(StackElement el) +{ + return el >= StackElement::FirstTypeEntry && el <= StackElement::LastComplexTypeEntry; +} + +static bool isDocumentation(StackElement el) +{ + return el >= StackElement::FirstDocumentation && el <= StackElement::LastDocumentation; +} + +static QList<CustomConversionPtr> customConversionsForReview; // Set a regular expression for rejection from text. By legacy, those are fixed // strings, except for '*' meaning 'match all'. Enclosing in "^..$" @@ -126,12 +150,12 @@ static bool setRejectionRegularExpression(const QString &patternIn, QString *errorMessage) { QString pattern; - if (patternIn.startsWith(QLatin1Char('^')) && patternIn.endsWith(QLatin1Char('$'))) + if (patternIn.startsWith(u'^') && patternIn.endsWith(u'$')) pattern = patternIn; - else if (patternIn == QLatin1String("*")) - pattern = QStringLiteral("^.*$"); + else if (patternIn == u"*") + pattern = "^.*$"_L1; else - pattern = QLatin1Char('^') + QRegularExpression::escape(patternIn) + QLatin1Char('$'); + pattern = u'^' + QRegularExpression::escape(patternIn) + u'$'; re->setPattern(pattern); if (!re->isValid()) { *errorMessage = msgInvalidRegularExpression(patternIn, re->errorString()); @@ -140,78 +164,66 @@ static bool setRejectionRegularExpression(const QString &patternIn, return true; } +static inline bool hasFileSnippetAttributes(const QXmlStreamAttributes *attributes) +{ + return attributes->hasAttribute(fileAttribute); +} + // Extract a snippet from a file within annotation "// @snippet label". std::optional<QString> extractSnippet(const QString &code, const QString &snippetLabel) { if (snippetLabel.isEmpty()) return code; - const QString pattern = QStringLiteral(R"(^\s*//\s*@snippet\s+)") + const QString pattern = R"(^\s*//\s*@snippet\s+)"_L1 + QRegularExpression::escape(snippetLabel) - + QStringLiteral(R"(\s*$)"); + + R"(\s*$)"_L1; const QRegularExpression snippetRe(pattern); Q_ASSERT(snippetRe.isValid()); bool useLine = false; bool foundLabel = false; QString result; - const auto lines = QStringView{code}.split(QLatin1Char('\n')); + const auto lines = QStringView{code}.split(u'\n'); for (const auto &line : lines) { - if (snippetRe.match(line).hasMatch()) { + if (snippetRe.matchView(line).hasMatch()) { foundLabel = true; useLine = !useLine; if (!useLine) break; // End of snippet reached } else if (useLine) - result += line.toString() + QLatin1Char('\n'); + result += line.toString() + u'\n'; } if (!foundLabel) return {}; return CodeSnipAbstract::fixSpaces(result); } -template <class EnumType, Qt::CaseSensitivity cs = Qt::CaseInsensitive> +template <class EnumType> struct EnumLookup { QStringView name; EnumType value; }; -template <class EnumType, Qt::CaseSensitivity cs> -bool operator==(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2) -{ - return e1.name.compare(e2.name, cs) == 0; -} - -template <class EnumType, Qt::CaseSensitivity cs> -bool operator<(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2) -{ - return e1.name.compare(e2.name, cs) < 0; -} - // Helper macros to define lookup functions that take a QStringView needle // and an optional default return value. #define ENUM_LOOKUP_BEGIN(EnumType, caseSensitivity, functionName) \ static std::optional<EnumType> functionName(QStringView needle) \ { \ - using HaystackEntry = EnumLookup<EnumType, caseSensitivity>; \ - static const HaystackEntry haystack[] = - -#define ENUM_LOOKUP_LINEAR_SEARCH() \ - const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \ - const auto it = std::find(haystack, end, HaystackEntry{needle, {} }); \ + using HaystackEntry = EnumLookup<EnumType>; \ + constexpr auto cs = caseSensitivity; \ + static constexpr HaystackEntry haystack[] = + +#define ENUM_LOOKUP_LINEAR_SEARCH \ + auto pred = [cs, needle](const HaystackEntry &he) { \ + return he.name.compare(needle, cs) == 0; \ + }; \ + auto end = std::cend(haystack); \ + auto it = std::find_if(std::cbegin(haystack), end, pred); \ if (it != end) \ return it->value; \ - return {}; \ -} - -#define ENUM_LOOKUP_BINARY_SEARCH() \ - const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \ - const HaystackEntry needleEntry{needle, {} }; \ - const auto lb = std::lower_bound(haystack, end, needleEntry); \ - if (lb != end && *lb == needleEntry) \ - return lb->value; \ - return {}; \ + return std::nullopt; \ } ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive, @@ -223,7 +235,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive, {u"no", TypeSystem::AllowThread::Disallow}, {u"false", TypeSystem::AllowThread::Disallow}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::BoolCast, Qt::CaseInsensitive, @@ -234,7 +246,28 @@ ENUM_LOOKUP_BEGIN(TypeSystem::BoolCast, Qt::CaseInsensitive, {u"no", TypeSystem::BoolCast::Disabled}, {u"false", TypeSystem::BoolCast::Disabled}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH + +ENUM_LOOKUP_BEGIN(TypeSystem::PythonEnumType, Qt::CaseSensitive, + pythonEnumTypeFromAttribute) + { + {u"Enum", TypeSystem::PythonEnumType::Enum}, + {u"IntEnum", TypeSystem::PythonEnumType::IntEnum}, + {u"Flag", TypeSystem::PythonEnumType::Flag}, + {u"IntFlag", TypeSystem::PythonEnumType::IntFlag}, + }; +ENUM_LOOKUP_LINEAR_SEARCH + +ENUM_LOOKUP_BEGIN(TypeSystem::QtMetaTypeRegistration, Qt::CaseSensitive, + qtMetaTypeFromAttribute) + { + {u"yes", TypeSystem::QtMetaTypeRegistration::Enabled}, + {u"true", TypeSystem::QtMetaTypeRegistration::Enabled}, + {u"base", TypeSystem::QtMetaTypeRegistration::BaseEnabled}, + {u"no", TypeSystem::QtMetaTypeRegistration::Disabled}, + {u"false", TypeSystem::QtMetaTypeRegistration::Disabled}, + }; +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive, languageFromAttribute) @@ -244,7 +277,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive, {u"shell", TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe {u"target", TypeSystem::TargetLangCode} // em algum lugar do cpp }; -ENUM_LOOKUP_BINARY_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive, ownershipFromFromAttribute) @@ -253,7 +286,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive, {u"c++", TypeSystem::CppOwnership}, {u"default", TypeSystem::DefaultOwnership} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive, addedFunctionAccessFromAttribute) @@ -261,7 +294,7 @@ ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive, {u"public", AddedFunction::Public}, {u"protected", AddedFunction::Protected}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(FunctionModification::ModifierFlag, Qt::CaseSensitive, modifierFromAttribute) @@ -269,12 +302,11 @@ ENUM_LOOKUP_BEGIN(FunctionModification::ModifierFlag, Qt::CaseSensitive, {u"private", FunctionModification::Private}, {u"public", FunctionModification::Public}, {u"protected", FunctionModification::Protected}, - {u"friendly", FunctionModification::Friendly}, {u"rename", FunctionModification::Rename}, {u"final", FunctionModification::Final}, {u"non-final", FunctionModification::NonFinal} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive, referenceCountFromAttribute) @@ -285,7 +317,7 @@ ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive, {u"set", ReferenceCount::Set}, {u"ignore", ReferenceCount::Ignore} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive, argumentOwnerActionFromAttribute) @@ -293,16 +325,17 @@ ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive, {u"add", ArgumentOwner::Add}, {u"remove", ArgumentOwner::Remove} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::CodeSnipPosition, Qt::CaseInsensitive, codeSnipPositionFromAttribute) { {u"beginning", TypeSystem::CodeSnipPositionBeginning}, {u"end", TypeSystem::CodeSnipPositionEnd}, - {u"declaration", TypeSystem::CodeSnipPositionDeclaration} + {u"declaration", TypeSystem::CodeSnipPositionDeclaration}, + {u"override", TypeSystem::CodeSnipPositionPyOverride} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive, locationFromAttribute) @@ -311,7 +344,7 @@ ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive, {u"local", Include::LocalPath}, {u"target", Include::TargetLangImport} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive, docModificationFromAttribute) @@ -320,7 +353,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive, {u"prepend", TypeSystem::DocModificationPrepend}, {u"replace", TypeSystem::DocModificationReplace} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(ContainerTypeEntry::ContainerKind, Qt::CaseSensitive, containerTypeFromAttribute) @@ -336,9 +369,10 @@ ENUM_LOOKUP_BEGIN(ContainerTypeEntry::ContainerKind, Qt::CaseSensitive, {u"multi-map", ContainerTypeEntry::MultiMapContainer}, {u"hash", ContainerTypeEntry::MapContainer}, {u"multi-hash", ContainerTypeEntry::MultiMapContainer}, - {u"pair", ContainerTypeEntry::PairContainer} + {u"pair", ContainerTypeEntry::PairContainer}, + {u"span", ContainerTypeEntry::SpanContainer} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive, typeRejectionFromAttribute) @@ -350,7 +384,7 @@ ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive, {u"argument-type", TypeRejection::ArgumentType}, {u"return-type", TypeRejection::ReturnType} }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive, exceptionHandlingFromAttribute) @@ -362,28 +396,61 @@ ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive, {u"yes", TypeSystem::ExceptionHandling::On}, {u"true", TypeSystem::ExceptionHandling::On}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH -ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive, - elementFromTag) - { - {u"add-conversion", StackElement::AddConversion}, // sorted! +ENUM_LOOKUP_BEGIN(TypeSystem::SmartPointerType, Qt::CaseSensitive, + smartPointerTypeFromAttribute) +{ + {u"handle", TypeSystem::SmartPointerType::Handle}, + {u"unique", TypeSystem::SmartPointerType::Unique}, + {u"value-handle", TypeSystem::SmartPointerType::ValueHandle}, + {u"shared", TypeSystem::SmartPointerType::Shared} +}; +ENUM_LOOKUP_LINEAR_SEARCH + +template <class EnumType> +static std::optional<EnumType> + lookupHashElement(const QHash<QStringView, EnumType> &hash, + QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) +{ + auto end = hash.cend(); + auto it = hash.constFind(needle); + if (it != end) + return it.value(); + if (cs == Qt::CaseInsensitive) { // brute force search for the unlikely case mismatch + for (it = hash.cbegin(); it != end; ++it) { + if (it.key().compare(needle, cs) == 0) + return it.value(); + } + } + return std::nullopt; +} + +using StackElementHash = QHash<QStringView, StackElement>; + +static const StackElementHash &stackElementHash() +{ + static const StackElementHash result{ + {u"add-conversion", StackElement::AddConversion}, {u"add-function", StackElement::AddFunction}, + {u"add-pymethoddef", StackElement::AddPyMethodDef}, {u"array", StackElement::Array}, + {u"configuration", StackElement::Configuration}, {u"container-type", StackElement::ContainerTypeEntry}, {u"conversion-rule", StackElement::ConversionRule}, - {u"custom-constructor", StackElement::CustomMetaConstructor}, - {u"custom-destructor", StackElement::CustomMetaDestructor}, + {u"custom-constructor", StackElement::Unimplemented}, + {u"custom-destructor", StackElement::Unimplemented}, {u"custom-type", StackElement::CustomTypeEntry}, {u"declare-function", StackElement::DeclareFunction}, {u"define-ownership", StackElement::DefineOwnership}, {u"enum-type", StackElement::EnumTypeEntry}, {u"extra-includes", StackElement::ExtraIncludes}, {u"function", StackElement::FunctionTypeEntry}, + {u"import-file", StackElement::ImportFile}, {u"include", StackElement::Include}, {u"inject-code", StackElement::InjectCode}, {u"inject-documentation", StackElement::InjectDocumentation}, - {u"insert-template", StackElement::TemplateInstanceEnum}, + {u"insert-template", StackElement::InsertTemplate}, {u"interface-type", StackElement::InterfaceTypeEntry}, {u"load-typesystem", StackElement::LoadTypesystem}, {u"modify-argument", StackElement::ModifyArgument}, @@ -394,6 +461,7 @@ ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive, {u"native-to-target", StackElement::NativeToTarget}, {u"no-null-pointer", StackElement::NoNullPointers}, {u"object-type", StackElement::ObjectTypeEntry}, + {u"opaque-container", StackElement::OpaqueContainer}, {u"parent", StackElement::ParentOwner}, {u"primitive-type", StackElement::PrimitiveTypeEntry}, {u"property", StackElement::Property}, @@ -415,8 +483,30 @@ ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive, {u"typesystem", StackElement::Root}, {u"value-type", StackElement::ValueTypeEntry}, }; -ENUM_LOOKUP_BINARY_SEARCH() + return result; +} + +static std::optional<StackElement> elementFromTag(QStringView needle) +{ + return lookupHashElement(stackElementHash(), needle, + Qt::CaseInsensitive); // FIXME PYSIDE-7: case sensitive +} + +static QStringView tagFromElement(StackElement st) +{ + return stackElementHash().key(st); +} +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, StackElement st) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << tagFromElement(st); + return d; +} +#endif // QT_NO_DEBUG_STREAM ENUM_LOOKUP_BEGIN(TypeSystem::SnakeCase, Qt::CaseSensitive, snakeCaseFromAttribute) @@ -427,7 +517,7 @@ ENUM_LOOKUP_BEGIN(TypeSystem::SnakeCase, Qt::CaseSensitive, {u"true", TypeSystem::SnakeCase::Enabled}, {u"both", TypeSystem::SnakeCase::Both}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH ENUM_LOOKUP_BEGIN(TypeSystem::Visibility, Qt::CaseSensitive, visibilityFromAttribute) @@ -438,12 +528,12 @@ ENUM_LOOKUP_BEGIN(TypeSystem::Visibility, Qt::CaseSensitive, {u"yes", TypeSystem::Visibility::Visible}, {u"true", TypeSystem::Visibility::Visible}, }; -ENUM_LOOKUP_LINEAR_SEARCH() +ENUM_LOOKUP_LINEAR_SEARCH static int indexOfAttribute(const QXmlStreamAttributes &atts, - QStringView name) + QAnyStringView name) { - for (int i = 0, size = atts.size(); i < size; ++i) { + for (qsizetype i = 0, size = atts.size(); i < size; ++i) { if (atts.at(i).qualifiedName() == name) return i; } @@ -452,8 +542,8 @@ static int indexOfAttribute(const QXmlStreamAttributes &atts, static QString msgMissingAttribute(const QString &a) { - return QLatin1String("Required attribute '") + a - + QLatin1String("' missing."); + return u"Required attribute '"_s + a + + u"' missing."_s; } QTextStream &operator<<(QTextStream &str, const QXmlStreamAttribute &attribute) @@ -474,7 +564,7 @@ static QString msgUnusedAttributes(QStringView tag, const QXmlStreamAttributes & QString result; QTextStream str(&result); str << attributes.size() << " attributes(s) unused on <" << tag << ">: "; - for (int i = 0, size = attributes.size(); i < size; ++i) { + for (qsizetype i = 0, size = attributes.size(); i < size; ++i) { if (i) str << ", "; str << attributes.at(i); @@ -496,31 +586,30 @@ private: QString readFile(const QString &entityName, QString *errorMessage) const; const QString m_currentPath; - QHash<QString, QString> m_cache; }; QString TypeSystemEntityResolver::readFile(const QString &entityName, QString *errorMessage) const { QString fileName = entityName; - if (!fileName.contains(QLatin1Char('.'))) - fileName += QLatin1String(".xml"); + if (!fileName.contains(u'.')) + fileName += u".xml"_s; QString path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath); if (!QFileInfo::exists(path)) // PySide6-specific hack - fileName.prepend(QLatin1String("typesystem_")); + fileName.prepend(u"typesystem_"_s); path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath); if (!QFileInfo::exists(path)) { - *errorMessage = QLatin1String("Unable to resolve: ") + entityName; - return QString(); + *errorMessage = u"Unable to resolve: "_s + entityName; + return {}; } QFile file(path); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { *errorMessage = msgCannotOpenForReading(file); - return QString(); + return {}; } QString result = QString::fromUtf8(file.readAll()).trimmed(); // Remove license header comments on which QXmlStreamReader chokes - if (result.startsWith(QLatin1String("<!--"))) { - const int commentEnd = result.indexOf(QLatin1String("-->")); + if (result.startsWith(u"<!--")) { + const auto commentEnd = result.indexOf(u"-->"); if (commentEnd != -1) { result.remove(0, commentEnd + 3); result = result.trimmed(); @@ -531,20 +620,33 @@ QString TypeSystemEntityResolver::readFile(const QString &entityName, QString *e QString TypeSystemEntityResolver::resolveUndeclaredEntity(const QString &name) { - auto it = m_cache.find(name); - if (it == m_cache.end()) { - QString errorMessage; - it = m_cache.insert(name, readFile(name, &errorMessage)); - if (it.value().isEmpty()) { // The parser will fail and display the line number. - qCWarning(lcShiboken, "%s", - qPrintable(msgCannotResolveEntity(name, errorMessage))); - } + QString errorMessage; + const QString result = readFile(name, &errorMessage); + if (result.isEmpty()) { // The parser will fail and display the line number. + qCWarning(lcShiboken, "%s", + qPrintable(msgCannotResolveEntity(name, errorMessage))); } - return it.value(); + return result; } -TypeSystemParser::TypeSystemParser(TypeDatabase *database, bool generate) : - m_database(database), +// State depending on element stack +enum class ParserState +{ + None, + PrimitiveTypeNativeToTargetConversion, + PrimitiveTypeTargetToNativeConversion, + ArgumentConversion, // Argument conversion rule with class attribute + ArgumentNativeToTargetConversion, + ArgumentTargetToNativeConversion, + FunctionCodeInjection, + TypeEntryCodeInjection, + TypeSystemCodeInjection, + Template +}; + +TypeSystemParser::TypeSystemParser(const std::shared_ptr<TypeDatabaseParserContext> &context, + bool generate) : + m_context(context), m_generate(generate ? TypeEntry::GenerateCode : TypeEntry::GenerateForSubclass) { } @@ -585,7 +687,7 @@ static QString msgReaderError(const ConditionalStreamReader &reader, const QStri } static QString msgUnimplementedElementWarning(const ConditionalStreamReader &reader, - QStringView name) + QAnyStringView name) { QString message; QTextStream(&message) << "The element \"" << name @@ -610,7 +712,7 @@ static inline QString msgUnimplementedAttributeWarning(const ConditionalStreamRe static QString msgUnimplementedAttributeValueWarning(const ConditionalStreamReader &reader, - QStringView name, QStringView value) + QAnyStringView name, QAnyStringView value) { QString message; QTextStream(&message) << "The value \"" << value @@ -627,21 +729,22 @@ static inline attribute.value()); } -static bool addRejection(TypeDatabase *database, QXmlStreamAttributes *attributes, +static bool addRejection(TypeDatabase *database, bool generate, QXmlStreamAttributes *attributes, QString *errorMessage) { - const int classIndex = indexOfAttribute(*attributes, classAttribute()); + const auto classIndex = indexOfAttribute(*attributes, classAttribute); if (classIndex == -1) { - *errorMessage = msgMissingAttribute(classAttribute()); + *errorMessage = msgMissingAttribute(classAttribute); return false; } TypeRejection rejection; + rejection.generate = generate; const QString className = attributes->takeAt(classIndex).value().toString(); if (!setRejectionRegularExpression(className, &rejection.className, errorMessage)) return false; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto &attribute = attributes->at(i); const auto name = attribute.qualifiedName(); const auto typeOpt = typeRejectionFromAttribute(name); @@ -668,9 +771,9 @@ static bool addRejection(TypeDatabase *database, QXmlStreamAttributes *attribute } // Special case: When all fields except class are empty, completely exclude class - if (className == QLatin1String("*")) { - *errorMessage = QLatin1String("bad reject entry, neither 'class', 'function-name'" - " nor 'field' specified"); + if (className == u"*") { + *errorMessage = u"bad reject entry, neither 'class', 'function-name'" + " nor 'field' specified"_s; return false; } rejection.matchType = TypeRejection::ExcludeClass; @@ -683,10 +786,7 @@ bool TypeSystemParser::parse(ConditionalStreamReader &reader) m_error.clear(); m_currentPath.clear(); m_currentFile.clear(); - m_smartPointerInstantiations.clear(); - const bool result = parseXml(reader) && setupSmartPointerInstantiations(); - m_smartPointerInstantiations.clear(); - return result; + return parseXml(reader); } bool TypeSystemParser::parseXml(ConditionalStreamReader &reader) @@ -706,18 +806,25 @@ bool TypeSystemParser::parseXml(ConditionalStreamReader &reader) case QXmlStreamReader::Invalid: m_error = msgReaderError(reader, reader.errorString()); return false; - case QXmlStreamReader::StartElement: - if (!startElement(reader)) { + case QXmlStreamReader::StartElement: { + const auto elementTypeOpt = elementFromTag(reader.name()); + if (!elementTypeOpt.has_value()) { + m_error = u"Unknown tag name: '"_s + reader.name().toString() + u'\''; + return false; + } + m_stack.push(elementTypeOpt.value()); + if (!startElement(reader, m_stack.top())) { m_error = msgReaderError(reader, m_error); return false; } - + } break; case QXmlStreamReader::EndElement: - if (!endElement(reader.name())) { + if (!endElement(m_stack.top())) { m_error = msgReaderError(reader, m_error); return false; } + m_stack.pop(); break; case QXmlStreamReader::Characters: if (!characters(reader.text())) { @@ -737,315 +844,302 @@ bool TypeSystemParser::parseXml(ConditionalStreamReader &reader) return true; } -// Split a type list potentially with template types -// "A<B,C>,D" -> ("A<B,C>", "D") -static QStringList splitTypeList(const QString &s) -{ - QStringList result; - int templateDepth = 0; - int lastPos = 0; - const int size = s.size(); - for (int i = 0; i < size; ++i) { - switch (s.at(i).toLatin1()) { - case '<': - ++templateDepth; - break; - case '>': - --templateDepth; - break; - case ',': - if (templateDepth == 0) { - result.append(s.mid(lastPos, i - lastPos).trimmed()); - lastPos = i + 1; - } - break; - } - } - if (lastPos < size) - result.append(s.mid(lastPos, size - lastPos).trimmed()); - return result; -} - -bool TypeSystemParser::setupSmartPointerInstantiations() -{ - for (auto it = m_smartPointerInstantiations.cbegin(), - end = m_smartPointerInstantiations.cend(); it != end; ++it) { - auto smartPointerEntry = it.key(); - const auto instantiationNames = splitTypeList(it.value()); - SmartPointerTypeEntry::Instantiations instantiations; - instantiations.reserve(instantiationNames.size()); - for (const auto &instantiationName : instantiationNames) { - const auto types = m_database->findCppTypes(instantiationName); - if (types.isEmpty()) { - m_error = - msgCannotFindTypeEntryForSmartPointer(instantiationName, - smartPointerEntry->name()); - return false; - } - if (types.size() > 1) { - m_error = msgAmbiguousTypesFound(instantiationName, types); - return false; - } - instantiations.append(types.constFirst()); - } - smartPointerEntry->setInstantiations(instantiations); - } - return true; -} - -bool TypeSystemParser::endElement(QStringView localName) +bool TypeSystemParser::endElement(StackElement element) { if (m_ignoreDepth) { --m_ignoreDepth; return true; } - if (m_currentDroppedEntry) { - if (m_currentDroppedEntryDepth == 1) { - m_current = m_currentDroppedEntry->parent; - delete m_currentDroppedEntry; - m_currentDroppedEntry = nullptr; - m_currentDroppedEntryDepth = 0; - } else { - --m_currentDroppedEntryDepth; - } + if (m_currentDroppedEntryDepth != 0) { + --m_currentDroppedEntryDepth; return true; } - if (!localName.compare(QLatin1String("import-file"), Qt::CaseInsensitive)) + if (element == StackElement::ImportFile) return true; - if (!m_current) + if (m_contextStack.isEmpty()) return true; - switch (m_current->type) { + const auto &top = m_contextStack.top(); + + switch (element) { + case StackElement::Unimplemented: + return true; case StackElement::Root: if (m_generate == TypeEntry::GenerateCode) { - TypeDatabase::instance()->addGlobalUserFunctions(m_contextStack.top()->addedFunctions); - TypeDatabase::instance()->addGlobalUserFunctionModifications(m_contextStack.top()->functionMods); - for (CustomConversion *customConversion : qAsConst(customConversionsForReview)) { - const CustomConversion::TargetToNativeConversions &toNatives = customConversion->targetToNativeConversions(); - for (CustomConversion::TargetToNativeConversion *toNative : toNatives) - toNative->setSourceType(m_database->findType(toNative->sourceTypeName())); + TypeDatabase::instance()->addGlobalUserFunctions(top->addedFunctions); + TypeDatabase::instance()->addGlobalUserFunctionModifications(top->functionMods); + for (const auto &customConversion : std::as_const(customConversionsForReview)) { + TargetToNativeConversions &toNatives = + customConversion->targetToNativeConversions(); + for (auto &toNative : toNatives) + toNative.setSourceType(m_context->db->findType(toNative.sourceTypeName())); } } + purgeEmptyCodeSnips(&std::static_pointer_cast<TypeSystemTypeEntry>(top->entry)->codeSnips()); + break; + case StackElement::FunctionTypeEntry: + TypeDatabase::instance()->addGlobalUserFunctionModifications(top->functionMods); break; case StackElement::ObjectTypeEntry: case StackElement::ValueTypeEntry: case StackElement::InterfaceTypeEntry: case StackElement::ContainerTypeEntry: case StackElement::NamespaceTypeEntry: { - auto *centry = static_cast<ComplexTypeEntry *>(m_current->entry); - auto top = m_contextStack.top(); + Q_ASSERT(top->entry); + Q_ASSERT(top->entry->isComplex()); + auto centry = std::static_pointer_cast<ComplexTypeEntry>(top->entry); + purgeEmptyCodeSnips(¢ry->codeSnips()); centry->setAddedFunctions(top->addedFunctions); centry->setFunctionModifications(top->functionMods); centry->setFieldModifications(top->fieldMods); - centry->setCodeSnips(top->codeSnips); centry->setDocModification(top->docModifications); } break; case StackElement::TypedefTypeEntry: { - auto *centry = static_cast<TypedefEntry *>(m_current->entry)->target(); - auto top = m_contextStack.top(); + auto centry = std::static_pointer_cast<TypedefEntry>(top->entry)->target(); centry->setAddedFunctions(centry->addedFunctions() + top->addedFunctions); centry->setFunctionModifications(centry->functionModifications() + top->functionMods); centry->setFieldModifications(centry->fieldModifications() + top->fieldMods); - centry->setCodeSnips(centry->codeSnips() + top->codeSnips); centry->setDocModification(centry->docModifications() + top->docModifications); + if (top->entry->isComplex()) { + auto cte = std::static_pointer_cast<const ComplexTypeEntry>(top->entry); + centry->setCodeSnips(centry->codeSnips() + cte->codeSnips()); + } } break; - case StackElement::AddFunction: { + case StackElement::AddFunction: + case StackElement::DeclareFunction: { // Leaving add-function: Assign all modifications to the added function - StackElementContext *top = m_contextStack.top(); const int modIndex = top->addedFunctionModificationIndex; top->addedFunctionModificationIndex = -1; Q_ASSERT(modIndex >= 0); Q_ASSERT(!top->addedFunctions.isEmpty()); while (modIndex < top->functionMods.size()) - top->addedFunctions.last()->modifications.append(top->functionMods.takeAt(modIndex)); + top->addedFunctions.last()->modifications().append(top->functionMods.takeAt(modIndex)); } - break; + break; case StackElement::NativeToTarget: - case StackElement::AddConversion: { - CustomConversion* customConversion = static_cast<TypeEntry*>(m_current->entry)->customConversion(); - if (!customConversion) { - m_error = QLatin1String("CustomConversion object is missing."); - return false; - } - - QString code = m_contextStack.top()->codeSnips.takeLast().code(); - if (m_current->type == StackElement::AddConversion) { - if (customConversion->targetToNativeConversions().isEmpty()) { - m_error = QLatin1String("CustomConversion's target to native conversions missing."); + case StackElement::AddConversion: + switch (parserState()) { + case ParserState::PrimitiveTypeNativeToTargetConversion: + case ParserState::PrimitiveTypeTargetToNativeConversion: { + auto customConversion = CustomConversion::getCustomConversion(top->entry); + if (!customConversion) { + m_error = msgMissingCustomConversion(top->entry); return false; } - customConversion->targetToNativeConversions().last()->setConversion(code); - } else { - customConversion->setNativeToTargetConversion(code); - } - } - break; - case StackElement::CustomMetaConstructor: { - m_current->entry->setCustomConstructor(*m_current->value.customFunction); - delete m_current->value.customFunction; - } - break; - case StackElement::CustomMetaDestructor: { - m_current->entry->setCustomDestructor(*m_current->value.customFunction); - delete m_current->value.customFunction; - } - break; - case StackElement::EnumTypeEntry: - m_current->entry->setDocModification(m_contextStack.top()->docModifications); - m_contextStack.top()->docModifications = DocModificationList(); - m_currentEnum = nullptr; - break; - case StackElement::Template: - m_database->addTemplate(m_current->value.templateEntry); - break; - case StackElement::TemplateInstanceEnum: - switch (m_current->parent->type) { - case StackElement::InjectCode: - if (m_current->parent->parent->type == StackElement::Root) { - CodeSnipList snips = m_current->parent->entry->codeSnips(); - CodeSnip snip = snips.takeLast(); - snip.addTemplateInstance(m_current->value.templateInstance); - snips.append(snip); - m_current->parent->entry->setCodeSnips(snips); - break; + QString code = top->conversionCodeSnips.constLast().code(); + if (element == StackElement::AddConversion) { + if (customConversion->targetToNativeConversions().isEmpty()) { + m_error = u"CustomConversion's target to native conversions missing."_s; + return false; + } + customConversion->targetToNativeConversions().last().setConversion(code); + } else { + customConversion->setNativeToTargetConversion(code); } - Q_FALLTHROUGH(); - case StackElement::NativeToTarget: - case StackElement::AddConversion: - m_contextStack.top()->codeSnips.last().addTemplateInstance(m_current->value.templateInstance); - break; - case StackElement::Template: - m_current->parent->value.templateEntry->addTemplateInstance(m_current->value.templateInstance); - break; - case StackElement::CustomMetaConstructor: - case StackElement::CustomMetaDestructor: - m_current->parent->value.customFunction->addTemplateInstance(m_current->value.templateInstance); + } break; - case StackElement::ConversionRule: - m_contextStack.top()->functionMods.last().argument_mods().last().conversionRules().last().addTemplateInstance(m_current->value.templateInstance); + + case ParserState::ArgumentNativeToTargetConversion: { + top->conversionCodeSnips.last().language = TypeSystem::TargetLangCode; + auto &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods().last(); + lastArgMod.conversionRules().append(top->conversionCodeSnips.constLast()); + } break; - case StackElement::InjectCodeInFunction: - m_contextStack.top()->functionMods.last().snips().last().addTemplateInstance(m_current->value.templateInstance); + case ParserState::ArgumentTargetToNativeConversion: { + top->conversionCodeSnips.last().language = TypeSystem::NativeCode; + auto &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods().last(); + lastArgMod.conversionRules().append(top->conversionCodeSnips.constLast()); + } break; default: - break; // nada + break; } + top->conversionCodeSnips.clear(); break; + + case StackElement::EnumTypeEntry: + m_currentEnum = nullptr; + break; + case StackElement::Template: + m_context->db->addTemplate(m_templateEntry); + m_templateEntry = nullptr; + break; + case StackElement::InsertTemplate: + if (auto *snip = injectCodeTarget(1)) + snip->addTemplateInstance(m_templateInstance); + m_templateInstance.reset(); + break; + + case StackElement::ModifyArgument: + purgeEmptyCodeSnips(&top->functionMods.last().argument_mods().last().conversionRules()); + break; + default: break; } - switch (m_current->type) { - case StackElement::Root: - case StackElement::NamespaceTypeEntry: - case StackElement::InterfaceTypeEntry: - case StackElement::ObjectTypeEntry: - case StackElement::ValueTypeEntry: - case StackElement::PrimitiveTypeEntry: - case StackElement::TypedefTypeEntry: - case StackElement::ContainerTypeEntry: - delete m_contextStack.pop(); + if (isTypeEntry(element) || element == StackElement::Root) + m_contextStack.pop(); + + return true; +} + +ParserState TypeSystemParser::parserState(qsizetype offset) const +{ + const auto stackSize = m_stack.size() - offset; + if (stackSize <= 0 || m_contextStack.isEmpty()) + return ParserState::None; + + const auto last = stackSize - 1; + + switch (m_stack.at(last)) { + // Primitive entry with conversion rule + case StackElement::NativeToTarget: // <conversion-rule><native-to-target> + if (stackSize > 2 && m_stack.at(last - 2) == StackElement::ModifyArgument) + return ParserState::ArgumentNativeToTargetConversion; + return ParserState::PrimitiveTypeNativeToTargetConversion; + + case StackElement::AddConversion: // <conversion-rule><target-to-native><add-conversion> + if (stackSize > 3 && m_stack.at(last - 3) == StackElement::ModifyArgument) + return ParserState::ArgumentTargetToNativeConversion; + return ParserState::PrimitiveTypeTargetToNativeConversion; + + case StackElement::ConversionRule: + if (stackSize > 1 && m_stack.at(last - 1) == StackElement::ModifyArgument) + return ParserState::ArgumentConversion; break; + + case StackElement::InjectCode: + switch (m_stack.value(last - 1, StackElement::None)) { + case StackElement::Root: + return ParserState::TypeSystemCodeInjection; + case StackElement::ModifyFunction: + case StackElement::AddFunction: + return ParserState::FunctionCodeInjection; + case StackElement::NamespaceTypeEntry: + case StackElement::ObjectTypeEntry: + case StackElement::ValueTypeEntry: + case StackElement::InterfaceTypeEntry: + return ParserState::TypeEntryCodeInjection; + default: + break; + } + break; + + case StackElement::Template: + return ParserState::Template; + default: break; } - StackElement *child = m_current; - m_current = m_current->parent; - delete(child); + return ParserState::None; +} - return true; +// Return where to add injected code depending on elements. +CodeSnipAbstract *TypeSystemParser::injectCodeTarget(qsizetype offset) const +{ + const auto state = parserState(offset); + if (state == ParserState::None) + return nullptr; + + const auto &top = m_contextStack.top(); + switch (state) { + case ParserState::PrimitiveTypeNativeToTargetConversion: + case ParserState::PrimitiveTypeTargetToNativeConversion: + case ParserState::ArgumentNativeToTargetConversion: + case ParserState::ArgumentTargetToNativeConversion: + return &top->conversionCodeSnips.last(); + case ParserState::ArgumentConversion: + return &top->functionMods.last().argument_mods().last().conversionRules().last(); + case ParserState::FunctionCodeInjection: { + auto &funcMod = top->functionMods.last(); + funcMod.setModifierFlag(FunctionModification::CodeInjection); + return &funcMod.snips().last(); + } + case ParserState::TypeEntryCodeInjection: + Q_ASSERT(top->entry->isComplex()); + return &std::static_pointer_cast<ComplexTypeEntry>(top->entry)->codeSnips().last(); + case ParserState::TypeSystemCodeInjection: + Q_ASSERT(top->entry->isTypeSystem()); + return &std::static_pointer_cast<TypeSystemTypeEntry>(top->entry)->codeSnips().last(); + case ParserState::Template: + return m_templateEntry.get(); + default: + break; + } + + return nullptr; } template <class String> // QString/QStringRef bool TypeSystemParser::characters(const String &ch) { - if (m_currentDroppedEntry || m_ignoreDepth) - return true; - - if (m_current->type == StackElement::Template) { - m_current->value.templateEntry->addCode(ch); + const auto stackSize = m_stack.size(); + if (m_currentDroppedEntryDepth != 0 || m_ignoreDepth != 0 + || stackSize == 0 || m_stack.top() == StackElement::Unimplemented) { return true; } - if (m_current->type == StackElement::CustomMetaConstructor || m_current->type == StackElement::CustomMetaDestructor) { - m_current->value.customFunction->addCode(ch); - return true; - } + const StackElement type = m_stack.top(); - if (m_current->type == StackElement::ConversionRule - && m_current->parent->type == StackElement::ModifyArgument) { - m_contextStack.top()->functionMods.last().argument_mods().last().conversionRules().last().addCode(ch); + if (type == StackElement::Template) { + m_templateEntry->addCode(ch); return true; } - if (m_current->type == StackElement::NativeToTarget || m_current->type == StackElement::AddConversion) { - m_contextStack.top()->codeSnips.last().addCode(ch); - return true; + if (m_contextStack.isEmpty()) { + m_error = msgNoRootTypeSystemEntry(); + return false; } - if (m_current->parent) { - if ((m_current->type & StackElement::CodeSnipMask)) { - CodeSnipList snips; - switch (m_current->parent->type) { - case StackElement::Root: - snips = m_current->parent->entry->codeSnips(); - snips.last().addCode(ch); - m_current->parent->entry->setCodeSnips(snips); - break; - case StackElement::ModifyFunction: - case StackElement::AddFunction: - m_contextStack.top()->functionMods.last().snips().last().addCode(ch); - m_contextStack.top()->functionMods.last().setModifierFlag(FunctionModification::CodeInjection); - break; - case StackElement::NamespaceTypeEntry: - case StackElement::ObjectTypeEntry: - case StackElement::ValueTypeEntry: - case StackElement::InterfaceTypeEntry: - m_contextStack.top()->codeSnips.last().addCode(ch); - break; - default: - Q_ASSERT(false); - } - return true; - } + if (auto *snip = injectCodeTarget()) { + snip->addCode(ch); + return true; } - if (m_current->type & StackElement::DocumentationMask) - m_contextStack.top()->docModifications.last().setCode(ch); + if (isDocumentation(type)) { + const bool isAddedFunction = m_stack.value(m_stack.size() - 2, StackElement::None) + == StackElement::AddFunction; + const auto &top = m_contextStack.top(); + auto &docModifications = isAddedFunction + ? top->addedFunctions.last()->docModifications() + : top->docModifications; + docModifications.last().setCode(ch); + } return true; } bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts) { - const QString fileName = atts.value(nameAttribute()).toString(); + const QString fileName = atts.value(nameAttribute).toString(); if (fileName.isEmpty()) { - m_error = QLatin1String("Required attribute 'name' missing for include-file tag."); + m_error = u"Required attribute 'name' missing for include-file tag."_s; return false; } QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - file.setFileName(QLatin1String(":/trolltech/generator/") + fileName); + file.setFileName(u":/trolltech/generator/"_s + fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { m_error = msgCannotOpenForReading(file); return false; } } - const auto quoteFrom = atts.value(quoteAfterLineAttribute()); + const auto quoteFrom = atts.value(quoteAfterLineAttribute); bool foundFromOk = quoteFrom.isEmpty(); bool from = quoteFrom.isEmpty(); - const auto quoteTo = atts.value(quoteBeforeLineAttribute()); + const auto quoteTo = atts.value(quoteBeforeLineAttribute); bool foundToOk = quoteTo.isEmpty(); bool to = true; @@ -1058,69 +1152,67 @@ bool TypeSystemParser::importFileElement(const QXmlStreamAttributes &atts) break; } if (from && to) - characters(line + QLatin1Char('\n')); + characters(line + u'\n'); if (!from && line.contains(quoteFrom)) { from = true; foundFromOk = true; } } if (!foundFromOk || !foundToOk) { - QString fromError = QStringLiteral("Could not find quote-after-line='%1' in file '%2'.") - .arg(quoteFrom.toString(), fileName); - QString toError = QStringLiteral("Could not find quote-before-line='%1' in file '%2'.") - .arg(quoteTo.toString(), fileName); + QString fromError = QString::fromLatin1("Could not find quote-after-line='%1' in file '%2'.") + .arg(quoteFrom.toString(), fileName); + QString toError = QString::fromLatin1("Could not find quote-before-line='%1' in file '%2'.") + .arg(quoteTo.toString(), fileName); if (!foundToOk) m_error = toError; if (!foundFromOk) m_error = fromError; if (!foundFromOk && !foundToOk) - m_error = fromError + QLatin1Char(' ') + toError; + m_error = fromError + u' ' + toError; return false; } return true; } -static bool convertBoolean(QStringView value, const QString &attributeName, bool defaultValue) +static bool convertBoolean(QStringView value, QAnyStringView attributeName, bool defaultValue) { - if (value.compare(trueAttributeValue(), Qt::CaseInsensitive) == 0 - || value.compare(yesAttributeValue(), Qt::CaseInsensitive) == 0) { + if (value.compare(trueAttributeValue, Qt::CaseInsensitive) == 0 + || value.compare(yesAttributeValue, Qt::CaseInsensitive) == 0) { return true; } - if (value.compare(falseAttributeValue(), Qt::CaseInsensitive) == 0 - || value.compare(noAttributeValue(), Qt::CaseInsensitive) == 0) { + if (value.compare(falseAttributeValue, Qt::CaseInsensitive) == 0 + || value.compare(noAttributeValue, Qt::CaseInsensitive) == 0) { return false; } - const QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.") - .arg(value) - .arg(attributeName, - defaultValue ? yesAttributeValue() : noAttributeValue()); - - qCWarning(lcShiboken).noquote().nospace() << warn; + qCWarning(lcShiboken).noquote().nospace() << "Boolean value '" << value + << "' not supported in attribute '" << attributeName + << "'. Use 'yes' or 'no'. Defaulting to '" + << (defaultValue ? yesAttributeValue : noAttributeValue) << "'."; return defaultValue; } static bool convertRemovalAttribute(QStringView value) { return value == u"all" // Legacy - || convertBoolean(value, removeAttribute(), false); + || convertBoolean(value, removeAttribute, false); } // Check whether an entry should be dropped, allowing for dropping the module // name (match 'Class' and 'Module.Class'). static bool shouldDropTypeEntry(const TypeDatabase *db, - const StackElement *element, + const TypeSystemParser::ContextStack &stack , QString name) { - for (auto e = element->parent; e ; e = e->parent) { - if (e->entry) { - if (e->entry->type() == TypeEntry::TypeSystemType) { + for (auto i = stack.size() - 1; i >= 0; --i) { + if (auto entry = stack.at(i)->entry) { + if (entry->type() == TypeEntry::TypeSystemType) { if (db->shouldDropTypeEntry(name)) // Unqualified return true; } - name.prepend(QLatin1Char('.')); - name.prepend(e->entry->name()); + name.prepend(u'.'); + name.prepend(entry->name()); } } return db->shouldDropTypeEntry(name); @@ -1129,10 +1221,10 @@ static bool shouldDropTypeEntry(const TypeDatabase *db, // Returns empty string if there's no error. static QString checkSignatureError(const QString& signature, const QString& tag) { - QString funcName = signature.left(signature.indexOf(QLatin1Char('('))).trimmed(); - static const QRegularExpression whiteSpace(QStringLiteral("\\s")); + QString funcName = signature.left(signature.indexOf(u'(')).trimmed(); + static const QRegularExpression whiteSpace("\\s"_L1); Q_ASSERT(whiteSpace.isValid()); - if (!funcName.startsWith(QLatin1String("operator ")) && funcName.contains(whiteSpace)) { + if (!funcName.startsWith(u"operator ") && funcName.contains(whiteSpace)) { return QString::fromLatin1("Error in <%1> tag signature attribute '%2'.\n" "White spaces aren't allowed in function names, " "and return types should not be part of the signature.") @@ -1141,20 +1233,24 @@ static QString checkSignatureError(const QString& signature, const QString& tag) return QString(); } -inline const TypeEntry *TypeSystemParser::currentParentTypeEntry() const +inline TypeEntryCPtr TypeSystemParser::currentParentTypeEntry() const { - return m_current ? m_current->entry : nullptr; + const auto size = m_contextStack.size(); + return size > 1 ? m_contextStack.at(size - 2)->entry : nullptr; } bool TypeSystemParser::checkRootElement() { - const bool ok = currentParentTypeEntry() != nullptr; - if (!ok) - m_error = msgNoRootTypeSystemEntry(); - return ok; + for (auto i = m_contextStack.size() - 1; i >= 0; --i) { + auto e = m_contextStack.at(i)->entry; + if (e && e->isTypeSystem()) + return true; + } + m_error = msgNoRootTypeSystemEntry(); + return false; } -static TypeEntry *findViewedType(const QString &name) +static TypeEntryPtr findViewedType(const QString &name) { const auto range = TypeDatabase::instance()->entries().equal_range(name); for (auto i = range.first; i != range.second; ++i) { @@ -1171,20 +1267,21 @@ static TypeEntry *findViewedType(const QString &name) return nullptr; } -bool TypeSystemParser::applyCommonAttributes(const ConditionalStreamReader &reader, TypeEntry *type, +bool TypeSystemParser::applyCommonAttributes(const ConditionalStreamReader &reader, + const TypeEntryPtr &type, QXmlStreamAttributes *attributes) { type->setSourceLocation(SourceLocation(m_currentFile, reader.lineNumber())); type->setCodeGeneration(m_generate); - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); if (name == u"revision") { type->setRevision(attributes->takeAt(i).value().toInt()); } else if (name == u"view-on") { const QString name = attributes->takeAt(i).value().toString(); - TypeEntry *views = findViewedType(name); - if (views == nullptr) { + TypeEntryPtr views = findViewedType(name); + if (!views) { m_error = msgCannotFindView(name, type->name()); return false; } @@ -1194,61 +1291,62 @@ bool TypeSystemParser::applyCommonAttributes(const ConditionalStreamReader &read return true; } -CustomTypeEntry *TypeSystemParser::parseCustomTypeEntry(const ConditionalStreamReader &, +CustomTypeEntryPtr TypeSystemParser::parseCustomTypeEntry(const ConditionalStreamReader &, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - auto *result = new CustomTypeEntry(name, since, m_current->entry); - for (int i = attributes->size() - 1; i >= 0; --i) { + auto result = std::make_shared<CustomTypeEntry>(name, since, m_contextStack.top()->entry); + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == checkFunctionAttribute()) + if (name == checkFunctionAttribute) result->setCheckFunction(attributes->takeAt(i).value().toString()); } return result; } -FlagsTypeEntry * +FlagsTypeEntryPtr TypeSystemParser::parseFlagsEntry(const ConditionalStreamReader &reader, - EnumTypeEntry *enumEntry, QString flagName, + const EnumTypeEntryPtr &enumEntry, QString flagName, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - auto ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + enumEntry->name() + QLatin1Char('>'), - since, - currentParentTypeEntry()->typeSystemTypeEntry()); + auto ftype = std::make_shared<FlagsTypeEntry>(u"QFlags<"_s + enumEntry->name() + u'>', + since, + typeSystemTypeEntry(currentParentTypeEntry())); ftype->setOriginator(enumEntry); ftype->setTargetLangPackage(enumEntry->targetLangPackage()); // Try toenumEntry get the guess the qualified flag name - if (!flagName.contains(colonColon())) { + if (!flagName.contains(u"::"_s)) { auto eq = enumEntry->qualifier(); if (!eq.isEmpty()) - flagName.prepend(eq + colonColon()); + flagName.prepend(eq + u"::"_s); } ftype->setOriginalName(flagName); if (!applyCommonAttributes(reader, ftype, attributes)) return nullptr; - QStringList lst = flagName.split(colonColon()); - const QString targetLangFlagName = QStringList(lst.mid(0, lst.size() - 1)).join(QLatin1Char('.')); + QStringList lst = flagName.split(u"::"_s); + const QString name = lst.takeLast(); + const QString targetLangFlagName = lst.join(u'.'); const QString &targetLangQualifier = enumEntry->targetLangQualifier(); if (targetLangFlagName != targetLangQualifier) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("enum %1 and flags %2 (%3) differ in qualifiers") - .arg(targetLangQualifier, lst.constFirst(), targetLangFlagName); + qCWarning(lcShiboken, "enum %s and flags %s (%s) differ in qualifiers", + qPrintable(targetLangQualifier), qPrintable(lst.value(0)), + qPrintable(targetLangFlagName)); } - ftype->setFlagsName(lst.constLast()); + ftype->setFlagsName(name); enumEntry->setFlags(ftype); - m_database->addFlagsType(ftype); - m_database->addType(ftype); + m_context->db->addFlagsType(ftype); + m_context->db->addType(ftype); const int revisionIndex = indexOfAttribute(*attributes, u"flags-revision"); @@ -1258,159 +1356,259 @@ FlagsTypeEntry * return ftype; } -SmartPointerTypeEntry * +SmartPointerTypeEntryPtr TypeSystemParser::parseSmartPointerEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - QString smartPointerType; + TypeSystem::SmartPointerType smartPointerType = TypeSystem::SmartPointerType::Shared; QString getter; QString refCountMethodName; + QString valueCheckMethod; + QString nullCheckMethod; + QString resetMethod; QString instantiations; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("type")) { - smartPointerType = attributes->takeAt(i).value().toString(); - } else if (name == QLatin1String("getter")) { + if (name == u"type") { + const auto attribute = attributes->takeAt(i); + const auto typeOpt = smartPointerTypeFromAttribute(attribute.value()); + if (!typeOpt.has_value()) { + m_error = msgInvalidAttributeValue(attribute); + return nullptr; + } + smartPointerType = typeOpt.value(); + } else if (name == u"getter") { getter = attributes->takeAt(i).value().toString(); - } else if (name == QLatin1String("ref-count-method")) { + } else if (name == u"ref-count-method") { refCountMethodName = attributes->takeAt(i).value().toString(); - } else if (name == QLatin1String("instantiations")) { + } else if (name == u"instantiations") { instantiations = attributes->takeAt(i).value().toString(); + } else if (name == u"value-check-method") { + valueCheckMethod = attributes->takeAt(i).value().toString(); + } else if (name == u"null-check-method") { + nullCheckMethod = attributes->takeAt(i).value().toString(); + } else if (name == u"reset-method") { + resetMethod = attributes->takeAt(i).value().toString(); } } - if (smartPointerType.isEmpty()) { - m_error = QLatin1String("No type specified for the smart pointer. Currently supported types: 'shared',"); - return nullptr; - } - if (smartPointerType != QLatin1String("shared")) { - m_error = QLatin1String("Currently only the 'shared' type is supported."); - return nullptr; - } - if (getter.isEmpty()) { - m_error = QLatin1String("No function getter name specified for getting the raw pointer held by the smart pointer."); + m_error = u"No function getter name specified for getting the raw pointer held by the smart pointer."_s; return nullptr; } - QString signature = getter + QLatin1String("()"); + QString signature = getter + u"()"_s; signature = TypeDatabase::normalizedSignature(signature); if (signature.isEmpty()) { - m_error = QLatin1String("No signature for the smart pointer getter found."); + m_error = u"No signature for the smart pointer getter found."_s; return nullptr; } QString errorString = checkSignatureError(signature, - QLatin1String("smart-pointer-type")); + u"smart-pointer-type"_s); if (!errorString.isEmpty()) { m_error = errorString; return nullptr; } - auto *type = new SmartPointerTypeEntry(name, getter, smartPointerType, - refCountMethodName, since, currentParentTypeEntry()); + if (smartPointerType == TypeSystem::SmartPointerType::Unique && resetMethod.isEmpty()) { + m_error = u"Unique pointers require a reset() method."_s; + return nullptr; + } + + auto type = std::make_shared<SmartPointerTypeEntry>(name, getter, smartPointerType, + refCountMethodName, since, + currentParentTypeEntry()); if (!applyCommonAttributes(reader, type, attributes)) return nullptr; - m_smartPointerInstantiations.insert(type, instantiations); + applyComplexTypeAttributes(reader, type, attributes); + type->setNullCheckMethod(nullCheckMethod); + type->setValueCheckMethod(valueCheckMethod); + type->setResetMethod(resetMethod); + m_context->smartPointerInstantiations.insert(type, instantiations); return type; } -PrimitiveTypeEntry * +PrimitiveTypeEntryPtr TypeSystemParser::parsePrimitiveTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - auto *type = new PrimitiveTypeEntry(name, since, currentParentTypeEntry()); + auto type = std::make_shared<PrimitiveTypeEntry>(name, since, currentParentTypeEntry()); + QString targetLangApiName; if (!applyCommonAttributes(reader, type, attributes)) return nullptr; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == targetLangNameAttribute()) { + if (name == targetLangNameAttribute) { type->setTargetLangName(attributes->takeAt(i).value().toString()); - } else if (name == QLatin1String("target-lang-api-name")) { - type->setTargetLangApiName(attributes->takeAt(i).value().toString()); - } else if (name == preferredConversionAttribute()) { + } else if (name == u"target-lang-api-name") { + targetLangApiName = attributes->takeAt(i).value().toString(); + } else if (name == preferredConversionAttribute) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - } else if (name == preferredTargetLangTypeAttribute()) { + } else if (name == preferredTargetLangTypeAttribute) { const bool v = convertBoolean(attributes->takeAt(i).value(), - preferredTargetLangTypeAttribute(), true); + preferredTargetLangTypeAttribute, true); type->setPreferredTargetLangType(v); - } else if (name == QLatin1String("default-constructor")) { + } else if (name == u"default-constructor") { type->setDefaultConstructor(attributes->takeAt(i).value().toString()); } } - if (type->targetLangApiName().isEmpty()) - type->setTargetLangApiName(type->name()); + if (!targetLangApiName.isEmpty()) { + auto e = m_context->db->findType(targetLangApiName); + if (!e || !e->isCustom()) { + m_error = msgInvalidTargetLanguageApiName(targetLangApiName); + return nullptr; + } + type->setTargetLangApiType(std::static_pointer_cast<CustomTypeEntry>(e)); + } type->setTargetLangPackage(m_defaultPackage); return type; } -ContainerTypeEntry * +// "int:QList_int;QString:QList_QString" +bool TypeSystemParser::parseOpaqueContainers(QStringView s, OpaqueContainers *result) +{ + const auto entries = s.split(u';'); + for (const auto &entry : entries) { + const auto values = entry.split(u':'); + if (values.size() != 2) { + m_error = u"Error parsing the opaque container attribute: \""_s + + s.toString() + u"\"."_s; + return false; + } + OpaqueContainer oc; + oc.name = values.at(1).trimmed().toString(); + const auto instantiations = values.at(0).split(u',', Qt::SkipEmptyParts); + for (const auto &instantiationV : instantiations) { + QString instantiation = instantiationV.trimmed().toString(); + // Fix to match AbstractMetaType::signature() which is used for matching + // "Foo*" -> "Foo *" + const auto asteriskPos = instantiation.indexOf(u'*'); + if (asteriskPos > 0 && !instantiation.at(asteriskPos - 1).isSpace()) + instantiation.insert(asteriskPos, u' '); + oc.instantiations.append(instantiation); + } + result->append(oc); + } + return true; +} + +ContainerTypeEntryPtr TypeSystemParser::parseContainerTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - const int typeIndex = indexOfAttribute(*attributes, u"type"); + const auto typeIndex = indexOfAttribute(*attributes, u"type"); if (typeIndex == -1) { - m_error = QLatin1String("no 'type' attribute specified"); + m_error = u"no 'type' attribute specified"_s; return nullptr; } - const auto typeName = attributes->takeAt(typeIndex).value(); + const auto typeName = attributes->at(typeIndex).value(); const auto containerTypeOpt = containerTypeFromAttribute(typeName); if (!containerTypeOpt.has_value()) { - m_error = QLatin1String("there is no container of type ") + typeName.toString(); + m_error = u"there is no container of type "_s + typeName.toString(); return nullptr; } - auto *type = new ContainerTypeEntry(name, containerTypeOpt.value(), - since, currentParentTypeEntry()); + attributes->removeAt(typeIndex); + auto type = std::make_shared<ContainerTypeEntry>(name, containerTypeOpt.value(), + since, currentParentTypeEntry()); if (!applyCommonAttributes(reader, type, attributes)) return nullptr; + applyComplexTypeAttributes(reader, type, attributes); + + for (auto i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == opaqueContainerAttribute) { + const auto attribute = attributes->takeAt(i); + OpaqueContainers oc; + if (!parseOpaqueContainers(attribute.value(), &oc)) + return nullptr; + type->appendOpaqueContainers(oc); + } + } + return type; } -EnumTypeEntry * +bool TypeSystemParser::parseOpaqueContainerElement(QXmlStreamAttributes *attributes) +{ + QString containerName; + OpaqueContainers oc; + for (auto i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == nameAttribute) { + containerName = attributes->takeAt(i).value().toString(); + } else if (name == opaqueContainerAttribute) { + const auto attribute = attributes->takeAt(i); + if (!parseOpaqueContainers(attribute.value(), &oc)) + return false; + } + } + if (containerName.isEmpty()) { + m_error = msgMissingAttribute(nameAttribute); + return false; + } + m_context->opaqueContainerHash[containerName].append(oc); + return true; +} + +EnumTypeEntryPtr TypeSystemParser::parseEnumTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - auto *entry = new EnumTypeEntry(name, since, currentParentTypeEntry()); + auto entry = std::make_shared<EnumTypeEntry>(name, since, currentParentTypeEntry()); applyCommonAttributes(reader, entry, attributes); entry->setTargetLangPackage(m_defaultPackage); QString flagNames; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("upper-bound")) { + if (name == u"upper-bound") { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - } else if (name == QLatin1String("lower-bound")) { + } else if (name == u"lower-bound") { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - } else if (name == forceIntegerAttribute()) { + } else if (name == docFileAttribute) { + entry->setDocFile(attributes->takeAt(i).value().toString()); + } else if (name == forceIntegerAttribute) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - } else if (name == extensibleAttribute()) { + } else if (name == pythonEnumTypeAttribute) { + const auto attribute = attributes->takeAt(i); + const auto typeOpt = pythonEnumTypeFromAttribute(attribute.value()); + if (typeOpt.has_value()) { + entry->setPythonEnumType(typeOpt.value()); + } else { + qCWarning(lcShiboken, "%s", + qPrintable(msgInvalidAttributeValue(attribute))); + } + } else if (name == cppEnumTypeAttribute) { + entry->setCppType(attributes->takeAt(i).value().toString()); + } else if (name == extensibleAttribute) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - } else if (name == flagsAttribute()) { + } else if (name == flagsAttribute) { flagNames = attributes->takeAt(i).value().toString(); } } // put in the flags parallel... if (!flagNames.isEmpty()) { - const QStringList &flagNameList = flagNames.split(QLatin1Char(',')); + const QStringList &flagNameList = flagNames.split(u','); for (const QString &flagName : flagNameList) parseFlagsEntry(reader, entry, flagName.trimmed(), since, attributes); } @@ -1418,19 +1616,19 @@ EnumTypeEntry * } -NamespaceTypeEntry * +NamespaceTypeEntryPtr TypeSystemParser::parseNamespaceTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - std::unique_ptr<NamespaceTypeEntry> result(new NamespaceTypeEntry(name, since, currentParentTypeEntry())); + auto result = std::make_shared<NamespaceTypeEntry>(name, since, currentParentTypeEntry()); auto visibility = TypeSystem::Visibility::Unspecified; - applyCommonAttributes(reader, result.get(), attributes); - for (int i = attributes->size() - 1; i >= 0; --i) { + applyCommonAttributes(reader, result, attributes); + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto attributeName = attributes->at(i).qualifiedName(); - if (attributeName == QLatin1String("files")) { + if (attributeName == u"files") { const QString pattern = attributes->takeAt(i).value().toString(); QRegularExpression re(pattern); if (!re.isValid()) { @@ -1438,11 +1636,11 @@ NamespaceTypeEntry * return nullptr; } result->setFilePattern(re); - } else if (attributeName == QLatin1String("extends")) { - const auto extendsPackageName = attributes->takeAt(i).value(); + } else if (attributeName == u"extends") { + const auto extendsPackageName = attributes->at(i).value(); auto allEntries = TypeDatabase::instance()->findNamespaceTypes(name); auto extendsIt = std::find_if(allEntries.cbegin(), allEntries.cend(), - [extendsPackageName] (const NamespaceTypeEntry *e) { + [extendsPackageName] (const NamespaceTypeEntryCPtr &e) { return e->targetLangPackage() == extendsPackageName; }); if (extendsIt == allEntries.cend()) { @@ -1450,7 +1648,8 @@ NamespaceTypeEntry * return nullptr; } result->setExtends(*extendsIt); - } else if (attributeName == visibleAttribute()) { + attributes->removeAt(i); + } else if (attributeName == visibleAttribute) { const auto attribute = attributes->takeAt(i); const auto visibilityOpt = visibilityFromAttribute(attribute.value()); if (!visibilityOpt.has_value()) { @@ -1458,36 +1657,39 @@ NamespaceTypeEntry * return nullptr; } visibility = visibilityOpt.value(); - } else if (attributeName == generateAttribute()) { - if (!convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true)) + } else if (attributeName == generateAttribute) { + if (!convertBoolean(attributes->takeAt(i).value(), generateAttribute, true)) visibility = TypeSystem::Visibility::Invisible; - } else if (attributeName == generateUsingAttribute()) { - result->setGenerateUsing(convertBoolean(attributes->takeAt(i).value(), generateUsingAttribute(), true)); + } else if (attributeName == generateUsingAttribute) { + result->setGenerateUsing(convertBoolean(attributes->takeAt(i).value(), + generateUsingAttribute, true)); } } if (visibility != TypeSystem::Visibility::Unspecified) result->setVisibility(visibility); // Handle legacy "generate" before the common handling - applyComplexTypeAttributes(reader, result.get(), attributes); + applyComplexTypeAttributes(reader, result, attributes); if (result->extends() && !result->hasPattern()) { m_error = msgExtendingNamespaceRequiresPattern(name); - return nullptr; + return {}; } - return result.release(); + return result; } -ValueTypeEntry * +ValueTypeEntryPtr TypeSystemParser::parseValueTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - auto *typeEntry = new ValueTypeEntry(name, since, currentParentTypeEntry()); - applyCommonAttributes(reader, typeEntry, attributes); + auto typeEntry = std::make_shared<ValueTypeEntry>(name, since, currentParentTypeEntry()); + if (!applyCommonAttributes(reader, typeEntry, attributes)) + return nullptr; + applyComplexTypeAttributes(reader, typeEntry, attributes); const int defaultCtIndex = indexOfAttribute(*attributes, u"default-constructor"); if (defaultCtIndex != -1) @@ -1495,7 +1697,7 @@ ValueTypeEntry * return typeEntry; } -FunctionTypeEntry * +FunctionTypeEntryPtr TypeSystemParser::parseFunctionTypeEntry(const ConditionalStreamReader &reader, const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) @@ -1503,75 +1705,84 @@ FunctionTypeEntry * if (!checkRootElement()) return nullptr; - QString signature; - TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Disabled; + FunctionModification mod; + const auto oldAttributesSize = attributes->size(); + if (!parseModifyFunctionAttributes(attributes, &mod)) + return nullptr; + const bool hasModification = attributes->size() < oldAttributesSize; - for (int i = attributes->size() - 1; i >= 0; --i) { + QString originalSignature; + QString docFile; + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == signatureAttribute()) { - signature = TypeDatabase::normalizedSignature(attributes->takeAt(i).value().toString()); - } else if (name == snakeCaseAttribute()) { - const auto attribute = attributes->takeAt(i); - const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); - if (!snakeCaseOpt.has_value()) { - m_error = msgInvalidAttributeValue(attribute); - return nullptr; - } - snakeCase = snakeCaseOpt.value(); - } + if (name == signatureAttribute) + originalSignature = attributes->takeAt(i).value().toString().simplified(); + else if (name == docFileAttribute) + docFile = attributes->takeAt(i).value().toString(); } + const QString signature = TypeDatabase::normalizedSignature(originalSignature); if (signature.isEmpty()) { - m_error = msgMissingAttribute(signatureAttribute()); + m_error = msgMissingAttribute(signatureAttribute); return nullptr; } - TypeEntry *existingType = m_database->findType(name); + if (hasModification) { + mod.setOriginalSignature(originalSignature); + mod.setSignature(signature); + m_contextStack.top()->functionMods << mod; + } + + TypeEntryPtr existingType = m_context->db->findType(name); if (!existingType) { - auto *result = new FunctionTypeEntry(name, signature, since, currentParentTypeEntry()); - result->setSnakeCase(snakeCase); + auto result = std::make_shared<FunctionTypeEntry>(name, signature, since, + currentParentTypeEntry()); + result->setTargetLangPackage(m_defaultPackage); + result->setDocFile(docFile); applyCommonAttributes(reader, result, attributes); return result; } if (existingType->type() != TypeEntry::FunctionType) { - m_error = QStringLiteral("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.") - .arg(name); + m_error = name + " expected to be a function, but isn't! Maybe it was already declared as a class or something else."_L1; return nullptr; } - auto *result = reinterpret_cast<FunctionTypeEntry *>(existingType); + auto result = std::static_pointer_cast<FunctionTypeEntry>(existingType); result->addSignature(signature); return result; } -TypedefEntry * +TypedefEntryPtr TypeSystemParser::parseTypedefEntry(const ConditionalStreamReader &reader, - const QString &name, + const QString &name, StackElement topElement, const QVersionNumber &since, QXmlStreamAttributes *attributes) { if (!checkRootElement()) return nullptr; - if (m_current && m_current->type != StackElement::Root - && m_current->type != StackElement::NamespaceTypeEntry) { - m_error = QLatin1String("typedef entries must be nested in namespaces or type system."); + if (topElement != StackElement::Root + && topElement != StackElement::NamespaceTypeEntry) { + m_error = u"typedef entries must be nested in namespaces or type system."_s; return nullptr; } - const int sourceIndex = indexOfAttribute(*attributes, sourceAttribute()); + const auto sourceIndex = indexOfAttribute(*attributes, sourceAttribute); if (sourceIndex == -1) { - m_error = msgMissingAttribute(sourceAttribute()); + m_error = msgMissingAttribute(sourceAttribute); return nullptr; } const QString sourceType = attributes->takeAt(sourceIndex).value().toString(); - auto result = new TypedefEntry(name, sourceType, since, currentParentTypeEntry()); - applyCommonAttributes(reader, result, attributes); + auto result = std::make_shared<TypedefEntry>(name, sourceType, since, + currentParentTypeEntry()); + if (!applyCommonAttributes(reader, result, attributes)) + return nullptr; + applyComplexTypeAttributes(reader, result, attributes); return result; } void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader &reader, - ComplexTypeEntry *ctype, + const ComplexTypeEntryPtr &ctype, QXmlStreamAttributes *attributes) const { bool generate = true; @@ -1580,34 +1791,40 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader auto allowThread = m_allowThread; QString package = m_defaultPackage; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == streamAttribute()) { - ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute(), false)); - } else if (name == privateAttribute()) { + if (name == streamAttribute) { + ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute, false)); + } else if (name == privateAttribute) { ctype->setPrivate(convertBoolean(attributes->takeAt(i).value(), - privateAttribute(), false)); - } else if (name == generateAttribute()) { - generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true); - } else if (name ==packageAttribute()) { + privateAttribute, false)); + } else if (name == generateAttribute) { + generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute, true); + } else if (name ==packageAttribute) { package = attributes->takeAt(i).value().toString(); - } else if (name == defaultSuperclassAttribute()) { + } else if (name == defaultSuperclassAttribute) { ctype->setDefaultSuperclass(attributes->takeAt(i).value().toString()); - } else if (name == genericClassAttribute()) { + } else if (name == genericClassAttribute) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - const bool v = convertBoolean(attributes->takeAt(i).value(), genericClassAttribute(), false); + const bool v = convertBoolean(attributes->takeAt(i).value(), + genericClassAttribute, false); ctype->setGenericClass(v); - } else if (name == targetLangNameAttribute()) { + } else if (name == targetLangNameAttribute) { ctype->setTargetLangName(attributes->takeAt(i).value().toString()); - } else if (name == QLatin1String("polymorphic-base")) { - ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString()); - } else if (name == QLatin1String("polymorphic-id-expression")) { + } else if (name == polymorphicBaseAttribute) { + const bool v = convertBoolean(attributes->takeAt(i).value(), + polymorphicBaseAttribute, false); + ctype->setIsPolymorphicBase(v); + } else if (name == u"polymorphic-name-function") { + ctype->setPolymorphicNameFunction(attributes->takeAt(i).value().toString()); + } else if (name == u"polymorphic-id-expression") { ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString()); - } else if (name == copyableAttribute()) { - const bool v = convertBoolean(attributes->takeAt(i).value(), copyableAttribute(), false); + } else if (name == copyableAttribute) { + const bool v = convertBoolean(attributes->takeAt(i).value(), + copyableAttribute, false); ctype->setCopyable(v ? ComplexTypeEntry::CopyableSet : ComplexTypeEntry::NonCopyableSet); - } else if (name == exceptionHandlingAttribute()) { + } else if (name == exceptionHandlingAttribute) { const auto attribute = attributes->takeAt(i); const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value()); if (exceptionOpt.has_value()) { @@ -1616,7 +1833,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == allowThreadAttribute()) { + } else if (name == allowThreadAttribute) { const auto attribute = attributes->takeAt(i); const auto allowThreadOpt = allowThreadFromAttribute(attribute.value()); if (allowThreadOpt.has_value()) { @@ -1625,26 +1842,39 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == QLatin1String("held-type")) { + } else if (name == u"held-type") { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); - } else if (name == QLatin1String("hash-function")) { + } else if (name == u"hash-function") { ctype->setHashFunction(attributes->takeAt(i).value().toString()); - } else if (name == forceAbstractAttribute()) { - if (convertBoolean(attributes->takeAt(i).value(), forceAbstractAttribute(), false)) + } else if (name == forceAbstractAttribute) { + if (convertBoolean(attributes->takeAt(i).value(), forceAbstractAttribute, false)) ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract); - } else if (name == deprecatedAttribute()) { - if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute(), false)) + } else if (name == deprecatedAttribute) { + if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute, false)) ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated); - } else if (name == disableWrapperAttribute()) { - if (convertBoolean(attributes->takeAt(i).value(), disableWrapperAttribute(), false)) + } else if (name == disableWrapperAttribute) { + if (convertBoolean(attributes->takeAt(i).value(), disableWrapperAttribute, false)) ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DisableWrapper); - } else if (name == deleteInMainThreadAttribute()) { - if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute(), false)) + } else if (name == deleteInMainThreadAttribute) { + if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute, false)) ctype->setDeleteInMainThread(true); - } else if (name == QLatin1String("target-type")) { + } else if (name == qtMetaObjectFunctionsAttribute) { + if (!convertBoolean(attributes->takeAt(i).value(), + qtMetaObjectFunctionsAttribute, true)) { + ctype->setTypeFlags(ctype->typeFlags() + | ComplexTypeEntry::DisableQtMetaObjectFunctions); + } + } else if (name == generateFunctionsAttribute) { + const auto names = attributes->takeAt(i).value(); + const auto nameList = names.split(u';', Qt::SkipEmptyParts); + QSet<QString> nameSet; + for (const auto &name : nameList) + nameSet.insert(name.trimmed().toString()); + ctype->setGenerateFunctions(nameSet); + } else if (name == u"target-type") { ctype->setTargetType(attributes->takeAt(i).value().toString()); - } else if (name == snakeCaseAttribute()) { + } else if (name == snakeCaseAttribute) { const auto attribute = attributes->takeAt(i); const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); if (snakeCaseOpt.has_value()) { @@ -1653,7 +1883,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == isNullAttribute()) { + } else if (name == isNullAttribute) { const auto attribute = attributes->takeAt(i); const auto boolCastOpt = boolCastFromAttribute(attribute.value()); if (boolCastOpt.has_value()) { @@ -1662,7 +1892,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == operatorBoolAttribute()) { + } else if (name == operatorBoolAttribute) { const auto attribute = attributes->takeAt(i); const auto boolCastOpt = boolCastFromAttribute(attribute.value()); if (boolCastOpt.has_value()) { @@ -1671,6 +1901,20 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } + } else if (name == qtMetaTypeAttribute) { + const auto attribute = attributes->takeAt(i); + const auto qtMetaTypeOpt = qtMetaTypeFromAttribute(attribute.value()); + if (qtMetaTypeOpt.has_value()) { + ctype->setQtMetaTypeRegistration(qtMetaTypeOpt.value()); + } else { + qCWarning(lcShiboken, "%s", + qPrintable(msgInvalidAttributeValue(attribute))); + } + } else if (name == parentManagementAttribute) { + const auto attribute = attributes->takeAt(i); + if (convertBoolean(attribute.value(), parentManagementAttribute, false)) + ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ParentManagement); + ComplexTypeEntry::setParentManagementEnabled(true); } } @@ -1689,40 +1933,66 @@ void TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader ctype->setCodeGeneration(TypeEntry::GenerationDisabled); } +bool TypeSystemParser::parseConfiguration(StackElement topElement, + QXmlStreamAttributes *attributes) +{ + if (!isComplexTypeEntry(topElement) + && topElement != StackElement::EnumTypeEntry) { + m_error = u"<configuration> must be nested into a complex or enum type entry."_s; + return false; + } + QString condition; + for (auto i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == u"condition") { + condition = attributes->takeAt(i).value().toString(); + } + } + if (condition.isEmpty()) { + m_error = u"<configuration> requires a \"condition\" attribute."_s; + return false; + } + const auto topEntry = m_contextStack.top()->entry; + const auto configurableEntry = std::dynamic_pointer_cast<ConfigurableTypeEntry>(topEntry); + Q_ASSERT(configurableEntry); + configurableEntry->setConfigCondition(condition); + return true; +} + bool TypeSystemParser::parseRenameFunction(const ConditionalStreamReader &, QString *name, QXmlStreamAttributes *attributes) { QString signature; QString rename; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == signatureAttribute()) { + if (name == signatureAttribute) { // Do not remove as it is needed for the type entry later on - signature = attributes->at(i).value().toString(); - } else if (name == renameAttribute()) { + signature = attributes->at(i).value().toString().simplified(); + } else if (name == renameAttribute) { rename = attributes->takeAt(i).value().toString(); } } if (signature.isEmpty()) { - m_error = msgMissingAttribute(signatureAttribute()); + m_error = msgMissingAttribute(signatureAttribute); return false; } - *name = signature.left(signature.indexOf(QLatin1Char('('))).trimmed(); + *name = signature.left(signature.indexOf(u'(')).trimmed(); - QString errorString = checkSignatureError(signature, QLatin1String("function")); + QString errorString = checkSignatureError(signature, u"function"_s); if (!errorString.isEmpty()) { m_error = errorString; return false; } if (!rename.isEmpty()) { - static const QRegularExpression functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$")); + static const QRegularExpression functionNameRegExp(u"^[a-zA-Z_][a-zA-Z0-9_]*$"_s); Q_ASSERT(functionNameRegExp.isValid()); if (!functionNameRegExp.match(rename).hasMatch()) { - m_error = QLatin1String("can not rename '") + signature + QLatin1String("', '") - + rename + QLatin1String("' is not a valid function name"); + m_error = u"can not rename '"_s + signature + u"', '"_s + + rename + u"' is not a valid function name"_s; return false; } FunctionModification mod; @@ -1735,23 +2005,25 @@ bool TypeSystemParser::parseRenameFunction(const ConditionalStreamReader &, return true; } -bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &, +bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &, StackElement topElement, QXmlStreamAttributes *attributes) { - const int validParent = StackElement::TypeEntryMask - | StackElement::ModifyFunction - | StackElement::ModifyField; - if (!m_current->parent || (m_current->parent->type & validParent) == 0) { - m_error = QLatin1String("inject-documentation must be inside modify-function, " - "modify-field or other tags that creates a type"); + const bool isAddFunction = topElement == StackElement::AddFunction; + const bool validParent = isTypeEntry(topElement) + || topElement == StackElement::ModifyFunction + || topElement == StackElement::ModifyField + || isAddFunction; + if (!validParent) { + m_error = u"inject-documentation must be inside modify-function, add-function" + "modify-field or other tags that creates a type"_s; return false; } TypeSystem::DocModificationMode mode = TypeSystem::DocModificationReplace; TypeSystem::Language lang = TypeSystem::NativeCode; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("mode")) { + if (name == u"mode") { const auto attribute = attributes->takeAt(i); const auto modeOpt = docModificationFromAttribute(attribute.value()); if (!modeOpt.has_value()) { @@ -1759,7 +2031,7 @@ bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &, return false; } mode = modeOpt.value(); - } else if (name == formatAttribute()) { + } else if (name == formatAttribute) { const auto attribute = attributes->takeAt(i); const auto langOpt = languageFromAttribute(attribute.value()); if (!langOpt.has_value()) { @@ -1770,53 +2042,66 @@ bool TypeSystemParser::parseInjectDocumentation(const ConditionalStreamReader &, } } - QString signature = m_current->type & StackElement::TypeEntryMask - ? QString() : m_currentSignature; + QString signature = isTypeEntry(topElement) ? QString() : m_currentSignature; DocModification mod(mode, signature); mod.setFormat(lang); - m_contextStack.top()->docModifications << mod; + if (hasFileSnippetAttributes(attributes)) { + const auto snippetOptional = readFileSnippet(attributes); + if (!snippetOptional.has_value()) + return false; + mod.setCode(snippetOptional.value().content); + } + auto &top = m_contextStack.top(); + if (isAddFunction) + top->addedFunctions.last()->addDocModification(mod); + else + top->docModifications << mod; return true; } bool TypeSystemParser::parseModifyDocumentation(const ConditionalStreamReader &, + StackElement topElement, QXmlStreamAttributes *attributes) { - const int validParent = StackElement::TypeEntryMask - | StackElement::ModifyFunction - | StackElement::ModifyField; - if (!m_current->parent || (m_current->parent->type & validParent) == 0) { - m_error = QLatin1String("modify-documentation must be inside modify-function, " - "modify-field or other tags that creates a type"); + const bool validParent = isTypeEntry(topElement) + || topElement == StackElement::ModifyFunction + || topElement == StackElement::ModifyField; + if (!validParent) { + m_error = u"modify-documentation must be inside modify-function, " + "modify-field or other tags that creates a type"_s; return false; } - const int xpathIndex = indexOfAttribute(*attributes, xPathAttribute()); + const auto xpathIndex = indexOfAttribute(*attributes, xPathAttribute); if (xpathIndex == -1) { - m_error = msgMissingAttribute(xPathAttribute()); + m_error = msgMissingAttribute(xPathAttribute); return false; } const QString xpath = attributes->takeAt(xpathIndex).value().toString(); - QString signature = (m_current->type & StackElement::TypeEntryMask) ? QString() : m_currentSignature; + QString signature = isTypeEntry(topElement) ? QString() : m_currentSignature; m_contextStack.top()->docModifications << DocModification(xpath, signature); return true; } // m_exceptionHandling -TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const ConditionalStreamReader &, +TypeSystemTypeEntryPtr TypeSystemParser::parseRootElement(const ConditionalStreamReader &, const QVersionNumber &since, QXmlStreamAttributes *attributes) { TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified; + QString subModuleOf; + QString namespaceBegin; + QString namespaceEnd; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == packageAttribute()) { + if (name == packageAttribute) { m_defaultPackage = attributes->takeAt(i).value().toString(); - } else if (name == defaultSuperclassAttribute()) { + } else if (name == defaultSuperclassAttribute) { m_defaultSuperclass = attributes->takeAt(i).value().toString(); - } else if (name == exceptionHandlingAttribute()) { + } else if (name == exceptionHandlingAttribute) { const auto attribute = attributes->takeAt(i); const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value()); if (exceptionOpt.has_value()) { @@ -1825,7 +2110,7 @@ TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const ConditionalStreamR qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == allowThreadAttribute()) { + } else if (name == allowThreadAttribute) { const auto attribute = attributes->takeAt(i); const auto allowThreadOpt = allowThreadFromAttribute(attribute.value()); if (allowThreadOpt.has_value()) { @@ -1834,7 +2119,7 @@ TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const ConditionalStreamR qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } - } else if (name == snakeCaseAttribute()) { + } else if (name == snakeCaseAttribute) { const auto attribute = attributes->takeAt(i); const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); if (snakeCaseOpt.has_value()) { @@ -1843,25 +2128,43 @@ TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const ConditionalStreamR qCWarning(lcShiboken, "%s", qPrintable(msgInvalidAttributeValue(attribute))); } + } else if (name == subModuleOfAttribute) { + subModuleOf = attributes->takeAt(i).value().toString(); + } else if (name == "namespace-begin"_L1) { + namespaceBegin = attributes->takeAt(i).value().toString(); + } else if (name == "namespace-end"_L1) { + namespaceEnd = attributes->takeAt(i).value().toString(); } } - auto *moduleEntry = - const_cast<TypeSystemTypeEntry *>(m_database->findTypeSystemType(m_defaultPackage)); - const bool add = moduleEntry == nullptr; + if (m_defaultPackage.isEmpty()) { // Extending default, see addBuiltInContainerTypes() + auto moduleEntry = std::const_pointer_cast<TypeSystemTypeEntry>(m_context->db->defaultTypeSystemType()); + Q_ASSERT(moduleEntry); + m_defaultPackage = moduleEntry->name(); + return moduleEntry; + } + + auto moduleEntry = + std::const_pointer_cast<TypeSystemTypeEntry>(m_context->db->findTypeSystemType(m_defaultPackage)); + const bool add = !moduleEntry; if (add) { - moduleEntry = new TypeSystemTypeEntry(m_defaultPackage, since, - currentParentTypeEntry()); + moduleEntry.reset(new TypeSystemTypeEntry(m_defaultPackage, since, + currentParentTypeEntry())); + moduleEntry->setSubModule(subModuleOf); } moduleEntry->setCodeGeneration(m_generate); moduleEntry->setSnakeCase(snakeCase); + if (!namespaceBegin.isEmpty()) + moduleEntry->setNamespaceBegin(namespaceBegin); + if (!namespaceEnd.isEmpty()) + moduleEntry->setNamespaceEnd(namespaceEnd); if ((m_generate == TypeEntry::GenerateForSubclass || m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty()) TypeDatabase::instance()->addRequiredTargetImport(m_defaultPackage); if (add) - m_database->addTypeSystemType(moduleEntry); + m_context->db->addTypeSystemType(moduleEntry); return moduleEntry; } @@ -1870,22 +2173,22 @@ bool TypeSystemParser::loadTypesystem(const ConditionalStreamReader &, { QString typeSystemName; bool generateChild = true; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == nameAttribute()) + if (name == nameAttribute) typeSystemName = attributes->takeAt(i).value().toString(); - else if (name == generateAttribute()) - generateChild = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true); + else if (name == generateAttribute) + generateChild = convertBoolean(attributes->takeAt(i).value(), generateAttribute, true); } if (typeSystemName.isEmpty()) { - m_error = QLatin1String("No typesystem name specified"); + m_error = u"No typesystem name specified"_s; return false; } const bool result = - m_database->parseFile(typeSystemName, m_currentPath, generateChild - && m_generate == TypeEntry::GenerateCode); + m_context->db->parseFile(m_context, typeSystemName, m_currentPath, + generateChild && m_generate == TypeEntry::GenerateCode); if (!result) - m_error = QStringLiteral("Failed to parse: '%1'").arg(typeSystemName); + m_error = u"Failed to parse: '"_s + typeSystemName + u'\''; return result; } @@ -1893,12 +2196,12 @@ bool TypeSystemParser::parseRejectEnumValue(const ConditionalStreamReader &, QXmlStreamAttributes *attributes) { if (!m_currentEnum) { - m_error = QLatin1String("<reject-enum-value> node must be used inside a <enum-type> node"); + m_error = u"<reject-enum-value> node must be used inside a <enum-type> node"_s; return false; } - const int nameIndex = indexOfAttribute(*attributes, nameAttribute()); + const auto nameIndex = indexOfAttribute(*attributes, nameAttribute); if (nameIndex == -1) { - m_error = msgMissingAttribute(nameAttribute()); + m_error = msgMissingAttribute(nameAttribute); return false; } m_currentEnum->addEnumValueRejection(attributes->takeAt(nameIndex).value().toString()); @@ -1906,16 +2209,16 @@ bool TypeSystemParser::parseRejectEnumValue(const ConditionalStreamReader &, } bool TypeSystemParser::parseReplaceArgumentType(const ConditionalStreamReader &, - const StackElement &topElement, + StackElement topElement, QXmlStreamAttributes *attributes) { - if (topElement.type != StackElement::ModifyArgument) { - m_error = QLatin1String("Type replacement can only be specified for argument modifications"); + if (topElement != StackElement::ModifyArgument) { + m_error = u"Type replacement can only be specified for argument modifications"_s; return false; } - const int modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute()); + const auto modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute); if (modifiedTypeIndex == -1) { - m_error = QLatin1String("Type replacement requires 'modified-type' attribute"); + m_error = u"Type replacement requires 'modified-type' attribute"_s; return false; } m_contextStack.top()->functionMods.last().argument_mods().last().setModifiedType( @@ -1924,24 +2227,24 @@ bool TypeSystemParser::parseReplaceArgumentType(const ConditionalStreamReader &, } bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, - const StackElement &topElement, + StackElement topElement, QXmlStreamAttributes *attributes) { - if (topElement.type != StackElement::ModifyArgument - && topElement.type != StackElement::ValueTypeEntry - && topElement.type != StackElement::PrimitiveTypeEntry - && topElement.type != StackElement::ContainerTypeEntry) { - m_error = QLatin1String("Conversion rules can only be specified for argument modification, " - "value-type, primitive-type or container-type conversion."); + if (topElement != StackElement::ModifyArgument + && topElement != StackElement::ValueTypeEntry + && topElement != StackElement::PrimitiveTypeEntry + && topElement != StackElement::ContainerTypeEntry) { + m_error = u"Conversion rules can only be specified for argument modification, " + "value-type, primitive-type or container-type conversion."_s; return false; } QString sourceFile; QString snippetLabel; TypeSystem::Language lang = TypeSystem::NativeCode; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == classAttribute()) { + if (name == classAttribute) { const auto languageAttribute = attributes->takeAt(i); const auto langOpt = languageFromAttribute(languageAttribute.value()); if (!langOpt.has_value()) { @@ -1949,28 +2252,33 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, return false; } lang = langOpt.value(); - } else if (name == QLatin1String("file")) { + } else if (name == u"file") { sourceFile = attributes->takeAt(i).value().toString(); - } else if (name == snippetAttribute()) { + } else if (name == snippetAttribute) { snippetLabel = attributes->takeAt(i).value().toString(); } } - if (topElement.type == StackElement::ModifyArgument) { + const auto &top = m_contextStack.top(); + if (topElement == StackElement::ModifyArgument) { CodeSnip snip; snip.language = lang; - m_contextStack.top()->functionMods.last().argument_mods().last().conversionRules().append(snip); + top->functionMods.last().argument_mods().last().conversionRules().append(snip); return true; } - if (topElement.entry->hasTargetConversionRule() || topElement.entry->hasCustomConversion()) { - m_error = QLatin1String("Types can have only one conversion rule"); - return false; + ValueTypeEntryPtr valueTypeEntry; + if (top->entry->isValue()) { + valueTypeEntry = std::static_pointer_cast<ValueTypeEntry>(top->entry); + if (valueTypeEntry->hasTargetConversionRule() || valueTypeEntry->hasCustomConversion()) { + m_error = u"Types can have only one conversion rule"_s; + return false; + } } // The old conversion rule tag that uses a file containing the conversion // will be kept temporarily for compatibility reasons. FIXME PYSIDE7: Remove - if (!sourceFile.isEmpty()) { + if (valueTypeEntry != nullptr && !sourceFile.isEmpty()) { if (m_generate != TypeEntry::GenerateForSubclass && m_generate != TypeEntry::GenerateNothing) { qWarning(lcShiboken, "Specifying conversion rules by \"file\" is deprecated."); @@ -1988,57 +2296,75 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, m_error = msgCannotFindSnippet(sourceFile, snippetLabel); return false; } - topElement.entry->setTargetConversionRule(conversionRuleOptional.value()); + valueTypeEntry->setTargetConversionRule(conversionRuleOptional.value()); } return true; } - auto *customConversion = new CustomConversion(m_current->entry); + auto customConversion = std::make_shared<CustomConversion>(top->entry); + if (top->entry->isPrimitive()) + std::static_pointer_cast<PrimitiveTypeEntry>(top->entry)->setCustomConversion(customConversion); + else if (top->entry->isContainer()) + std::static_pointer_cast<ContainerTypeEntry>(top->entry)->setCustomConversion(customConversion); + else if (top->entry->isValue()) + std::static_pointer_cast<ValueTypeEntry>(top->entry)->setCustomConversion(customConversion); customConversionsForReview.append(customConversion); return true; } bool TypeSystemParser::parseNativeToTarget(const ConditionalStreamReader &, - const StackElement &topElement, + StackElement topElement, QXmlStreamAttributes *attributes) { - if (topElement.type != StackElement::ConversionRule) { - m_error = QLatin1String("Native to Target conversion code can only be specified for custom conversion rules."); + if (topElement != StackElement::ConversionRule) { + m_error = u"Native to Target conversion code can only be specified for custom conversion rules."_s; return false; } CodeSnip snip; - if (!readFileSnippet(attributes, &snip)) + if (!readCodeSnippet(attributes, &snip)) return false; - m_contextStack.top()->codeSnips.append(snip); + m_contextStack.top()->conversionCodeSnips.append(snip); return true; } bool TypeSystemParser::parseAddConversion(const ConditionalStreamReader &, - const StackElement &topElement, + StackElement topElement, QXmlStreamAttributes *attributes) { - if (topElement.type != StackElement::TargetToNative) { - m_error = QLatin1String("Target to Native conversions can only be added inside 'target-to-native' tags."); + if (topElement != StackElement::TargetToNative) { + m_error = u"Target to Native conversions can only be added inside 'target-to-native' tags."_s; return false; } QString sourceTypeName; QString typeCheck; CodeSnip snip; - if (!readFileSnippet(attributes, &snip)) + if (!readCodeSnippet(attributes, &snip)) return false; - for (int i = attributes->size() - 1; i >= 0; --i) { + + const auto &top = m_contextStack.top(); + top->conversionCodeSnips.append(snip); + + if (parserState() == ParserState::ArgumentTargetToNativeConversion) + return true; + + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("type")) + if (name == u"type") sourceTypeName = attributes->takeAt(i).value().toString(); - else if (name == QLatin1String("check")) + else if (name == u"check") typeCheck = attributes->takeAt(i).value().toString(); } + if (sourceTypeName.isEmpty()) { - m_error = QLatin1String("Target to Native conversions must specify the input type with the 'type' attribute."); + m_error = u"Target to Native conversions must specify the input type with the 'type' attribute."_s; + return false; + } + auto customConversion = CustomConversion::getCustomConversion(top->entry); + if (!customConversion) { + m_error = msgMissingCustomConversion(top->entry); return false; } - m_current->entry->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck); - m_contextStack.top()->codeSnips.append(snip); + customConversion->addTargetToNativeConversion(sourceTypeName, typeCheck); return true; } @@ -2047,17 +2373,17 @@ static bool parseIndex(const QString &index, int *result, QString *errorMessage) bool ok = false; *result = index.toInt(&ok); if (!ok) - *errorMessage = QStringLiteral("Cannot convert '%1' to integer").arg(index); + *errorMessage = QString::fromLatin1("Cannot convert '%1' to integer").arg(index); return ok; } static bool parseArgumentIndex(const QString &index, int *result, QString *errorMessage) { - if (index == QLatin1String("return")) { + if (index == u"return") { *result = 0; return true; } - if (index == QLatin1String("this")) { + if (index == u"this") { *result = -1; return true; } @@ -2065,13 +2391,14 @@ static bool parseArgumentIndex(const QString &index, int *result, QString *error } bool TypeSystemParser::parseModifyArgument(const ConditionalStreamReader &, - const StackElement &topElement, QXmlStreamAttributes *attributes) -{ - if (topElement.type != StackElement::ModifyFunction - && topElement.type != StackElement::AddFunction) { - m_error = QString::fromLatin1("argument modification requires function" - " modification as parent, was %1") - .arg(topElement.type, 0, 16); + StackElement topElement, QXmlStreamAttributes *attributes) +{ + if (topElement != StackElement::ModifyFunction + && topElement != StackElement::AddFunction + && topElement != StackElement::DeclareFunction) { + m_error = u"Argument modification requires <modify-function>," + " <add-function> or <declare-function> as parent, was "_s + + tagFromElement(topElement).toString(); return false; } @@ -2079,22 +2406,22 @@ bool TypeSystemParser::parseModifyArgument(const ConditionalStreamReader &, QString renameTo; QString pyiType; bool resetAfterUse = false; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == indexAttribute()) { + if (name == indexAttribute) { index = attributes->takeAt(i).value().toString(); - } else if (name == invalidateAfterUseAttribute()) { + } else if (name == invalidateAfterUseAttribute) { resetAfterUse = convertBoolean(attributes->takeAt(i).value(), - invalidateAfterUseAttribute(), false); - } else if (name == renameAttribute()) { + invalidateAfterUseAttribute, false); + } else if (name == renameAttribute) { renameTo = attributes->takeAt(i).value().toString(); - } else if (name == pyiTypeAttribute()) { + } else if (name == pyiTypeAttribute) { pyiType = attributes->takeAt(i).value().toString(); } } if (index.isEmpty()) { - m_error = msgMissingAttribute(indexAttribute()); + m_error = msgMissingAttribute(indexAttribute); return false; } @@ -2111,10 +2438,10 @@ bool TypeSystemParser::parseModifyArgument(const ConditionalStreamReader &, } bool TypeSystemParser::parseNoNullPointer(const ConditionalStreamReader &reader, - const StackElement &topElement, QXmlStreamAttributes *attributes) + StackElement topElement, QXmlStreamAttributes *attributes) { - if (topElement.type != StackElement::ModifyArgument) { - m_error = QLatin1String("no-null-pointer requires argument modification as parent"); + if (topElement != StackElement::ModifyArgument) { + m_error = u"no-null-pointer requires argument modification as parent"_s; return false; } @@ -2132,19 +2459,19 @@ bool TypeSystemParser::parseNoNullPointer(const ConditionalStreamReader &reader, } bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &, - const StackElement &topElement, + StackElement topElement, QXmlStreamAttributes *attributes) { - if (topElement.type != StackElement::ModifyArgument) { - m_error = QLatin1String("define-ownership requires argument modification as parent"); + if (topElement != StackElement::ModifyArgument) { + m_error = u"define-ownership requires argument modification as parent"_s; return false; } TypeSystem::Language lang = TypeSystem::TargetLangCode; std::optional<TypeSystem::Ownership> ownershipOpt; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == classAttribute()) { + if (name == classAttribute) { const auto classAttribute = attributes->takeAt(i); const auto langOpt = languageFromAttribute(classAttribute.value()); if (!langOpt.has_value() || langOpt.value() == TypeSystem::ShellCode) { @@ -2152,7 +2479,7 @@ bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &, return false; } lang = langOpt.value(); - } else if (name == ownershipAttribute()) { + } else if (name == ownershipAttribute) { const auto attribute = attributes->takeAt(i); ownershipOpt = ownershipFromFromAttribute(attribute.value()); if (!ownershipOpt.has_value()) { @@ -2163,7 +2490,7 @@ bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &, } if (!ownershipOpt.has_value()) { - m_error = QStringLiteral("unspecified ownership"); + m_error = "unspecified ownership"_L1; return false; } auto &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods().last(); @@ -2182,17 +2509,17 @@ bool TypeSystemParser::parseDefineOwnership(const ConditionalStreamReader &, // ### fixme PySide7: remove (replaced by attribute). bool TypeSystemParser::parseRename(const ConditionalStreamReader &, - const StackElement &topElement, + StackElement topElement, QXmlStreamAttributes *attributes) { - if (topElement.type != StackElement::ModifyArgument) { - m_error = QLatin1String("Argument modification parent required"); + if (topElement != StackElement::ModifyArgument) { + m_error = u"Argument modification parent required"_s; return false; } - const int toIndex = indexOfAttribute(*attributes, toAttribute()); + const auto toIndex = indexOfAttribute(*attributes, toAttribute); if (toIndex == -1) { - m_error = msgMissingAttribute(toAttribute()); + m_error = msgMissingAttribute(toAttribute); return false; } const QString renamed_to = attributes->takeAt(toIndex).value().toString(); @@ -2204,19 +2531,22 @@ bool TypeSystemParser::parseModifyField(const ConditionalStreamReader &, QXmlStreamAttributes *attributes) { FieldModification fm; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == nameAttribute()) { + if (name == nameAttribute) { fm.setName(attributes->takeAt(i).value().toString()); - } else if (name == removeAttribute()) { + } else if (name == removeAttribute) { fm.setRemoved(convertRemovalAttribute(attributes->takeAt(i).value())); - } else if (name == readAttribute()) { - fm.setReadable(convertBoolean(attributes->takeAt(i).value(), readAttribute(), true)); - } else if (name == writeAttribute()) { - fm.setWritable(convertBoolean(attributes->takeAt(i).value(), writeAttribute(), true)); - } else if (name == renameAttribute()) { + } else if (name == opaqueContainerFieldAttribute) { + fm.setOpaqueContainer(convertBoolean(attributes->takeAt(i).value(), + opaqueContainerFieldAttribute, false)); + } else if (name == readAttribute) { + fm.setReadable(convertBoolean(attributes->takeAt(i).value(), readAttribute, true)); + } else if (name == writeAttribute) { + fm.setWritable(convertBoolean(attributes->takeAt(i).value(), writeAttribute, true)); + } else if (name == renameAttribute) { fm.setRenamedToName(attributes->takeAt(i).value().toString()); - } else if (name == snakeCaseAttribute()) { + } else if (name == snakeCaseAttribute) { const auto attribute = attributes->takeAt(i); const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); if (snakeCaseOpt.has_value()) { @@ -2228,7 +2558,7 @@ bool TypeSystemParser::parseModifyField(const ConditionalStreamReader &, } } if (fm.name().isEmpty()) { - m_error = msgMissingAttribute(nameAttribute()); + m_error = msgMissingAttribute(nameAttribute); return false; } m_contextStack.top()->fieldMods << fm; @@ -2248,70 +2578,85 @@ static bool parseOverloadNumber(const QXmlStreamAttribute &attribute, int *overl } bool TypeSystemParser::parseAddFunction(const ConditionalStreamReader &, - const StackElement &topElement, - StackElement::ElementType t, + StackElement topElement, + StackElement t, QXmlStreamAttributes *attributes) { - if (!(topElement.type - & (StackElement::ComplexTypeEntryMask | StackElement::Root | StackElement::ContainerTypeEntry))) { + const bool validParent = isComplexTypeEntry(topElement) + || topElement == StackElement::Root + || topElement == StackElement::ContainerTypeEntry; + if (!validParent) { m_error = QString::fromLatin1("Add/Declare function requires a complex/container type or a root tag as parent" - ", was=%1").arg(topElement.type, 0, 16); + ", was=%1").arg(tagFromElement(topElement)); + return false; + } + + FunctionModification mod; + if (!(t == StackElement::AddFunction + ? parseBasicModifyFunctionAttributes(attributes, &mod) + : parseModifyFunctionAttributes(attributes, &mod))) { return false; } + QString originalSignature; QString returnType; bool staticFunction = false; bool classMethod = false; + bool pythonOverride = false; QString access; - int overloadNumber = TypeSystem::OverloadNumberUnset; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("signature")) { - originalSignature = attributes->takeAt(i).value().toString(); - } else if (name == QLatin1String("return-type")) { + if (name == signatureAttribute) { + originalSignature = attributes->takeAt(i).value().toString().simplified(); + } else if (name == u"return-type") { returnType = attributes->takeAt(i).value().toString(); - } else if (name == staticAttribute()) { + } else if (name == staticAttribute) { staticFunction = convertBoolean(attributes->takeAt(i).value(), - staticAttribute(), false); - } else if (name == classmethodAttribute()) { + staticAttribute, false); + } else if (name == classmethodAttribute) { classMethod = convertBoolean(attributes->takeAt(i).value(), - classmethodAttribute(), false); - } else if (name == accessAttribute()) { + classmethodAttribute, false); + } else if (name == accessAttribute) { access = attributes->takeAt(i).value().toString(); - } else if (name == overloadNumberAttribute()) { - if (!parseOverloadNumber(attributes->takeAt(i), &overloadNumber, &m_error)) - return false; + } else if (name == pythonOverrideAttribute) { + pythonOverride = convertBoolean(attributes->takeAt(i).value(), + pythonOverrideAttribute, false); } } - QString signature = TypeDatabase::normalizedSignature(originalSignature); + QString signature = TypeDatabase::normalizedAddedFunctionSignature(originalSignature); if (signature.isEmpty()) { - m_error = QLatin1String("No signature for the added function"); + m_error = u"No signature for the added function"_s; return false; } - QString errorString = checkSignatureError(signature, QLatin1String("add-function")); + QString errorString = checkSignatureError(signature, u"add-function"_s); if (!errorString.isEmpty()) { m_error = errorString; return false; } AddedFunctionPtr func = AddedFunction::createAddedFunction(signature, returnType, &errorString); - if (func.isNull()) { + if (!func) { m_error = errorString; return false; } func->setStatic(staticFunction); func->setClassMethod(classMethod); - if (!signature.contains(QLatin1Char('('))) - signature += QLatin1String("()"); + func->setPythonOverride(pythonOverride); + func->setTargetLangPackage(m_defaultPackage); + + // Create signature for matching modifications + signature = TypeDatabase::normalizedSignature(originalSignature); + if (!signature.contains(u'(')) + signature += u"()"_s; m_currentSignature = signature; if (!access.isEmpty()) { const auto acessOpt = addedFunctionAccessFromAttribute(access); if (!acessOpt.has_value()) { - m_error = QString::fromLatin1("Bad access type '%1'").arg(access); + m_error = u"Bad access type '"_s + access + u'\''; return false; } func->setAccess(acessOpt.value()); @@ -2322,8 +2667,6 @@ bool TypeSystemParser::parseAddFunction(const ConditionalStreamReader &, m_contextStack.top()->addedFunctionModificationIndex = m_contextStack.top()->functionMods.size(); - FunctionModification mod; - mod.setOverloadNumber(overloadNumber); if (!mod.setSignature(m_currentSignature, &m_error)) return false; mod.setOriginalSignature(originalSignature); @@ -2331,156 +2674,217 @@ bool TypeSystemParser::parseAddFunction(const ConditionalStreamReader &, return true; } -bool TypeSystemParser::parseProperty(const ConditionalStreamReader &, const StackElement &topElement, +bool TypeSystemParser::parseAddPyMethodDef(const ConditionalStreamReader &, + StackElement topElement, + QXmlStreamAttributes *attributes) +{ + if (!isComplexTypeEntry(topElement)) { + m_error = u"add-pymethoddef requires a complex type as parent, was="_s + + tagFromElement(topElement).toString(); + return false; + } + + TypeSystemPyMethodDefEntry def; + for (auto i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == nameAttribute) { + def.name = attributes->takeAt(i).value().toString(); + } else if (name == u"doc") { + def.doc = attributes->takeAt(i).value().toString(); + } else if (name == u"function") { + def.function = attributes->takeAt(i).value().toString(); + } else if (name == u"flags") { + auto attribute = attributes->takeAt(i); + const auto flags = attribute.value().split(u'|', Qt::SkipEmptyParts); + for (const auto &flag : flags) + def.methFlags.append(flag.toString().toUtf8()); + } else if (name == u"signatures") { + auto attribute = attributes->takeAt(i); + const auto signatures = attribute.value().split(u';', Qt::SkipEmptyParts); + for (const auto &signature : signatures) + def.signatures.append(signature.toString()); + } + } + + if (def.name.isEmpty() || def.function.isEmpty()) { + m_error = u"add-pymethoddef requires at least a name and a function attribute"_s; + return false; + } + std::static_pointer_cast<ComplexTypeEntry>(m_contextStack.top()->entry)->addPyMethodDef(def); + return true; +} + +bool TypeSystemParser::parseProperty(const ConditionalStreamReader &, StackElement topElement, QXmlStreamAttributes *attributes) { - if ((topElement.type & StackElement::ComplexTypeEntryMask) == 0) { + if (!isComplexTypeEntry(topElement)) { m_error = QString::fromLatin1("Add property requires a complex type as parent" - ", was=%1").arg(topElement.type, 0, 16); + ", was=%1").arg(tagFromElement(topElement)); return false; } TypeSystemProperty property; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == nameAttribute()) { + if (name == nameAttribute) { property.name = attributes->takeAt(i).value().toString(); - } else if (name == QLatin1String("get")) { + } else if (name == u"get") { property.read = attributes->takeAt(i).value().toString(); - } else if (name == QLatin1String("type")) { + } else if (name == u"type") { property.type = attributes->takeAt(i).value().toString(); - } else if (name == QLatin1String("set")) { + } else if (name == u"set") { property.write = attributes->takeAt(i).value().toString(); - } else if (name == generateGetSetDefAttribute()) { + } else if (name == generateGetSetDefAttribute) { property.generateGetSetDef = convertBoolean(attributes->takeAt(i).value(), - generateGetSetDefAttribute(), false); + generateGetSetDefAttribute, false); } } if (!property.isValid()) { - m_error = QLatin1String("<property> element is missing required attibutes (name/type/get)."); + m_error = u"<property> element is missing required attibutes (name/type/get)."_s; return false; } - static_cast<ComplexTypeEntry *>(topElement.entry)->addProperty(property); + std::static_pointer_cast<ComplexTypeEntry>(m_contextStack.top()->entry)->addProperty(property); return true; } -bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader, - const StackElement &topElement, - QXmlStreamAttributes *attributes) +// Parse basic attributes applicable to <add-function>/<declare-function>/<function> +// and <modify-function> (all that is not done by injected code). +bool TypeSystemParser::parseBasicModifyFunctionAttributes(QXmlStreamAttributes *attributes, + FunctionModification *mod) { - if (!(topElement.type & StackElement::ComplexTypeEntryMask)) { - m_error = QString::fromLatin1("Modify function requires complex type as parent" - ", was=%1").arg(topElement.type, 0, 16); - return false; + for (auto i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == overloadNumberAttribute) { + int overloadNumber = TypeSystem::OverloadNumberUnset; + if (!parseOverloadNumber(attributes->takeAt(i), &overloadNumber, &m_error)) + return false; + mod->setOverloadNumber(overloadNumber); + } } + return true; +} - QString originalSignature; - QString access; - bool removed = false; - QString rename; - bool deprecated = false; - bool isThread = false; - int overloadNumber = TypeSystem::OverloadNumberUnset; - TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; - TypeSystem::AllowThread allowThread = TypeSystem::AllowThread::Unspecified; - TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified; - for (int i = attributes->size() - 1; i >= 0; --i) { +// Parse attributes applicable to <declare-function>/<function> +// and <modify-function>. +bool TypeSystemParser::parseModifyFunctionAttributes(QXmlStreamAttributes *attributes, + FunctionModification *mod) +{ + if (!parseBasicModifyFunctionAttributes(attributes, mod)) + return false; + + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("signature")) { - originalSignature = attributes->takeAt(i).value().toString(); - } else if (name == accessAttribute()) { - access = attributes->takeAt(i).value().toString(); - } else if (name == renameAttribute()) { - rename = attributes->takeAt(i).value().toString(); - } else if (name == removeAttribute()) { - removed = convertRemovalAttribute(attributes->takeAt(i).value()); - } else if (name == deprecatedAttribute()) { - deprecated = convertBoolean(attributes->takeAt(i).value(), - deprecatedAttribute(), false); - } else if (name == threadAttribute()) { - isThread = convertBoolean(attributes->takeAt(i).value(), - threadAttribute(), false); - } else if (name == allowThreadAttribute()) { + if (name == allowThreadAttribute) { const QXmlStreamAttribute attribute = attributes->takeAt(i); const auto allowThreadOpt = allowThreadFromAttribute(attribute.value()); if (!allowThreadOpt.has_value()) { m_error = msgInvalidAttributeValue(attribute); return false; } - allowThread = allowThreadOpt.value(); - } else if (name == exceptionHandlingAttribute()) { + mod->setAllowThread(allowThreadOpt.value()); + } else if (name == exceptionHandlingAttribute) { const auto attribute = attributes->takeAt(i); const auto exceptionOpt = exceptionHandlingFromAttribute(attribute.value()); - if (exceptionOpt.has_value()) { - exceptionHandling = exceptionOpt.value(); - } else { - qCWarning(lcShiboken, "%s", - qPrintable(msgInvalidAttributeValue(attribute))); - } - } else if (name == overloadNumberAttribute()) { - if (!parseOverloadNumber(attributes->takeAt(i), &overloadNumber, &m_error)) + if (!exceptionOpt.has_value()) { + m_error = msgInvalidAttributeValue(attribute); return false; - } else if (name == snakeCaseAttribute()) { + } + mod->setExceptionHandling(exceptionOpt.value()); + } else if (name == snakeCaseAttribute) { const auto attribute = attributes->takeAt(i); const auto snakeCaseOpt = snakeCaseFromAttribute(attribute.value()); - if (snakeCaseOpt.has_value()) { - snakeCase = snakeCaseOpt.value(); - } else { - qCWarning(lcShiboken, "%s", - qPrintable(msgInvalidAttributeValue(attribute))); + if (!snakeCaseOpt.has_value()) { + m_error = msgInvalidAttributeValue(attribute); + return false; } - } else if (name == virtualSlotAttribute()) { + mod->setSnakeCase(snakeCaseOpt.value()); + } else if (name == deprecatedAttribute) { + const bool deprecated = convertBoolean(attributes->takeAt(i).value(), + deprecatedAttribute, false); + mod->setModifierFlag(deprecated ? FunctionModification::Deprecated + : FunctionModification::Undeprecated); + } + } + return true; +} + +bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader, + StackElement topElement, + QXmlStreamAttributes *attributes) +{ + const bool validParent = isComplexTypeEntry(topElement) + || topElement == StackElement::TypedefTypeEntry + || topElement == StackElement::FunctionTypeEntry; + if (!validParent) { + m_error = QString::fromLatin1("Modify function requires complex type as parent" + ", was=%1").arg(tagFromElement(topElement)); + return false; + } + + QString originalSignature; + FunctionModification mod; + if (!parseModifyFunctionAttributes(attributes, &mod)) + return false; + + QString access; + bool removed = false; + QString rename; + for (auto i = attributes->size() - 1; i >= 0; --i) { + const auto name = attributes->at(i).qualifiedName(); + if (name == signatureAttribute) { + originalSignature = attributes->takeAt(i).value().toString().simplified(); + } else if (name == accessAttribute) { + access = attributes->takeAt(i).value().toString(); + } else if (name == renameAttribute) { + rename = attributes->takeAt(i).value().toString(); + } else if (name == removeAttribute) { + removed = convertRemovalAttribute(attributes->takeAt(i).value()); + } else if (name == virtualSlotAttribute || name == threadAttribute) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeWarning(reader, name))); } } // Child of global <function> - if (originalSignature.isEmpty() && topElement.entry->isFunction()) { - auto f = static_cast<const FunctionTypeEntry *>(topElement.entry); + const auto &top = m_contextStack.top(); + if (originalSignature.isEmpty() && top->entry->isFunction()) { + auto f = std::static_pointer_cast<const FunctionTypeEntry>(top->entry); originalSignature = f->signatures().value(0); } const QString signature = TypeDatabase::normalizedSignature(originalSignature); if (signature.isEmpty()) { - m_error = QLatin1String("No signature for modified function"); + m_error = u"No signature for modified function"_s; return false; } - QString errorString = checkSignatureError(signature, QLatin1String("modify-function")); + QString errorString = checkSignatureError(signature, u"modify-function"_s); if (!errorString.isEmpty()) { m_error = errorString; return false; } - FunctionModification mod; if (!mod.setSignature(signature, &m_error)) return false; mod.setOriginalSignature(originalSignature); - mod.setExceptionHandling(exceptionHandling); - mod.setOverloadNumber(overloadNumber); - mod.setSnakeCase(snakeCase); m_currentSignature = signature; if (!access.isEmpty()) { const auto modifierFlagOpt = modifierFromAttribute(access); if (!modifierFlagOpt.has_value()) { - m_error = QString::fromLatin1("Bad access type '%1'").arg(access); + m_error = u"Bad access type '"_s + access + u'\''; return false; } const FunctionModification::ModifierFlag m = modifierFlagOpt.value(); - if (m == FunctionModification::Final || m == FunctionModification::NonFinal) { + if (m == FunctionModification::NonFinal) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedAttributeValueWarning(reader, - accessAttribute(), access))); + accessAttribute, access))); } mod.setModifierFlag(m); } - if (deprecated) - mod.setModifierFlag(FunctionModification::Deprecated); - mod.setRemoved(removed); if (!rename.isEmpty()) { @@ -2488,25 +2892,21 @@ bool TypeSystemParser::parseModifyFunction(const ConditionalStreamReader &reader mod.setModifierFlag(FunctionModification::Rename); } - mod.setIsThread(isThread); - if (allowThread != TypeSystem::AllowThread::Unspecified) - mod.setAllowThread(allowThread); - - m_contextStack.top()->functionMods << mod; + top->functionMods << mod; return true; } bool TypeSystemParser::parseReplaceDefaultExpression(const ConditionalStreamReader &, - const StackElement &topElement, + StackElement topElement, QXmlStreamAttributes *attributes) { - if (!(topElement.type & StackElement::ModifyArgument)) { - m_error = QLatin1String("Replace default expression only allowed as child of argument modification"); + if (!(topElement & StackElement::ModifyArgument)) { + m_error = u"Replace default expression only allowed as child of argument modification"_s; return false; } - const int withIndex = indexOfAttribute(*attributes, u"with"); + const auto withIndex = indexOfAttribute(*attributes, u"with"); if (withIndex == -1 || attributes->at(withIndex).value().isEmpty()) { - m_error = QLatin1String("Default expression replaced with empty string. Use remove-default-expression instead."); + m_error = u"Default expression replaced with empty string. Use remove-default-expression instead."_s; return false; } @@ -2515,41 +2915,19 @@ bool TypeSystemParser::parseReplaceDefaultExpression(const ConditionalStreamRead return true; } -CustomFunction * - TypeSystemParser::parseCustomMetaConstructor(const ConditionalStreamReader &, - StackElement::ElementType type, - const StackElement &topElement, - QXmlStreamAttributes *attributes) -{ - QString functionName = topElement.entry->name().toLower() - + (type == StackElement::CustomMetaConstructor - ? QLatin1String("_create") : QLatin1String("_delete")); - QString paramName = QLatin1String("copy"); - for (int i = attributes->size() - 1; i >= 0; --i) { - const auto name = attributes->at(i).qualifiedName(); - if (name == nameAttribute()) - functionName = attributes->takeAt(i).value().toString(); - else if (name == QLatin1String("param-name")) - paramName = attributes->takeAt(i).value().toString(); - } - auto *func = new CustomFunction(functionName); - func->paramName = paramName; - return func; -} - bool TypeSystemParser::parseReferenceCount(const ConditionalStreamReader &reader, - const StackElement &topElement, + StackElement topElement, QXmlStreamAttributes *attributes) { - if (topElement.type != StackElement::ModifyArgument) { - m_error = QLatin1String("reference-count must be child of modify-argument"); + if (topElement != StackElement::ModifyArgument) { + m_error = u"reference-count must be child of modify-argument"_s; return false; } ReferenceCount rc; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == actionAttribute()) { + if (name == actionAttribute) { const QXmlStreamAttribute attribute = attributes->takeAt(i); const auto actionOpt = referenceCountFromAttribute(attribute.value()); if (!actionOpt.has_value()) { @@ -2566,7 +2944,7 @@ bool TypeSystemParser::parseReferenceCount(const ConditionalStreamReader &reader default: break; } - } else if (name == QLatin1String("variable-name")) { + } else if (name == u"variable-name") { rc.varName = attributes->takeAt(i).value().toString(); } } @@ -2576,21 +2954,21 @@ bool TypeSystemParser::parseReferenceCount(const ConditionalStreamReader &reader } bool TypeSystemParser::parseParentOwner(const ConditionalStreamReader &, - const StackElement &topElement, + StackElement topElement, QXmlStreamAttributes *attributes) { - if (topElement.type != StackElement::ModifyArgument) { - m_error = QLatin1String("parent-policy must be child of modify-argument"); + if (topElement != StackElement::ModifyArgument) { + m_error = u"parent-policy must be child of modify-argument"_s; return false; } ArgumentOwner ao; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == indexAttribute()) { + if (name == indexAttribute) { const QString index = attributes->takeAt(i).value().toString(); if (!parseArgumentIndex(index, &ao.index, &m_error)) return false; - } else if (name == actionAttribute()) { + } else if (name == actionAttribute) { const auto action = attributes->takeAt(i); const auto actionOpt = argumentOwnerActionFromAttribute(action.value()); if (!actionOpt.has_value()) { @@ -2604,46 +2982,62 @@ bool TypeSystemParser::parseParentOwner(const ConditionalStreamReader &, return true; } -bool TypeSystemParser::readFileSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip) +std::optional<TypeSystemParser::Snippet> + TypeSystemParser::readFileSnippet(QXmlStreamAttributes *attributes) { - QString fileName; - QString snippetLabel; - for (int i = attributes->size() - 1; i >= 0; --i) { + Snippet result; + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("file")) { - fileName = attributes->takeAt(i).value().toString(); - } else if (name == snippetAttribute()) { - snippetLabel = attributes->takeAt(i).value().toString(); + if (name == fileAttribute) { + result.fileName = attributes->takeAt(i).value().toString(); + } else if (name == snippetAttribute) { + result.snippetLabel = attributes->takeAt(i).value().toString(); } } - if (fileName.isEmpty()) - return true; - const QString resolved = m_database->modifiedTypesystemFilepath(fileName, m_currentPath); + if (result.fileName.isEmpty()) { + m_error = "Snippet missing file name"_L1; + return std::nullopt; + } + const QString resolved = m_context->db->modifiedTypesystemFilepath(result.fileName, + m_currentPath); if (!QFile::exists(resolved)) { - m_error = QLatin1String("File for inject code not exist: ") - + QDir::toNativeSeparators(fileName); - return false; + m_error = u"File for inject code not exist: "_s + + QDir::toNativeSeparators(result.fileName); + return std::nullopt; } QFile codeFile(resolved); if (!codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) { m_error = msgCannotOpenForReading(codeFile); - return false; + return std::nullopt; } - const auto codeOptional = extractSnippet(QString::fromUtf8(codeFile.readAll()), snippetLabel); + const auto contentOptional = extractSnippet(QString::fromUtf8(codeFile.readAll()), + result.snippetLabel); codeFile.close(); - if (!codeOptional.has_value()) { - m_error = msgCannotFindSnippet(resolved, snippetLabel); - return false; + if (!contentOptional.has_value()) { + m_error = msgCannotFindSnippet(resolved, result.snippetLabel); + return std::nullopt; } + result.content = contentOptional.value(); + return result; +} - QString source = fileName; - if (!snippetLabel.isEmpty()) - source += QLatin1String(" (") + snippetLabel + QLatin1Char(')'); +bool TypeSystemParser::readCodeSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip) +{ + if (!hasFileSnippetAttributes(attributes)) + return true; // Expecting inline content. + const auto snippetOptional = readFileSnippet(attributes); + if (!snippetOptional.has_value()) + return false; + const auto snippet = snippetOptional.value(); + + QString source = snippet.fileName; + if (!snippet.snippetLabel.isEmpty()) + source += " ("_L1 + snippet.snippetLabel + u')'; QString content; QTextStream str(&content); str << "// ========================================================================\n" "// START of custom code block [file: " - << source << "]\n" << codeOptional.value() + << source << "]\n" << snippet.content << "// END of custom code block [file: " << source << "]\n// ========================================================================\n"; snip->addCode(content); @@ -2651,25 +3045,25 @@ bool TypeSystemParser::readFileSnippet(QXmlStreamAttributes *attributes, CodeSni } bool TypeSystemParser::parseInjectCode(const ConditionalStreamReader &, - const StackElement &topElement, - StackElement* element, QXmlStreamAttributes *attributes) -{ - if (!(topElement.type & StackElement::ComplexTypeEntryMask) - && (topElement.type != StackElement::AddFunction) - && (topElement.type != StackElement::ModifyFunction) - && (topElement.type != StackElement::Root)) { - m_error = QLatin1String("wrong parent type for code injection"); + StackElement topElement, + QXmlStreamAttributes *attributes) +{ + if (!isComplexTypeEntry(topElement) + && (topElement != StackElement::AddFunction) + && (topElement != StackElement::ModifyFunction) + && (topElement != StackElement::Root)) { + m_error = u"wrong parent type for code injection"_s; return false; } TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionBeginning; TypeSystem::Language lang = TypeSystem::TargetLangCode; CodeSnip snip; - if (!readFileSnippet(attributes, &snip)) + if (!readCodeSnippet(attributes, &snip)) return false; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == classAttribute()) { + if (name == classAttribute) { const auto attribute = attributes->takeAt(i); const auto langOpt = languageFromAttribute(attribute.value()); if (!langOpt.has_value()) { @@ -2677,7 +3071,7 @@ bool TypeSystemParser::parseInjectCode(const ConditionalStreamReader &, return false; } lang = langOpt.value(); - } else if (name == positionAttribute()) { + } else if (name == positionAttribute) { const auto attribute = attributes->takeAt(i); const auto positionOpt = codeSnipPositionFromAttribute(attribute.value()); if (!positionOpt.has_value()) { @@ -2691,32 +3085,36 @@ bool TypeSystemParser::parseInjectCode(const ConditionalStreamReader &, snip.position = position; snip.language = lang; - if (topElement.type == StackElement::ModifyFunction - || topElement.type == StackElement::AddFunction) { + switch (topElement) { + case StackElement::ModifyFunction: + case StackElement::AddFunction: { FunctionModification &mod = m_contextStack.top()->functionMods.last(); mod.appendSnip(snip); if (!snip.code().isEmpty()) mod.setModifierFlag(FunctionModification::CodeInjection); - element->type = StackElement::InjectCodeInFunction; - } else if (topElement.type == StackElement::Root) { - element->entry->addCodeSnip(snip); - } else if (topElement.type != StackElement::Root) { - m_contextStack.top()->codeSnips << snip; + } + break; + case StackElement::Root: + std::static_pointer_cast<TypeSystemTypeEntry>(m_contextStack.top()->entry)->addCodeSnip(snip); + break; + default: + std::static_pointer_cast<ComplexTypeEntry>(m_contextStack.top()->entry)->addCodeSnip(snip); + break; } return true; } bool TypeSystemParser::parseInclude(const ConditionalStreamReader &, - const StackElement &topElement, - TypeEntry *entry, QXmlStreamAttributes *attributes) + StackElement topElement, + const TypeEntryPtr &entry, QXmlStreamAttributes *attributes) { QString fileName; Include::IncludeType location = Include::IncludePath; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == fileNameAttribute()) { + if (name == fileNameAttribute) { fileName = attributes->takeAt(i).value().toString(); - } else if (name == locationAttribute()) { + } else if (name == locationAttribute) { const auto attribute = attributes->takeAt(i); const auto locationOpt = locationFromAttribute(attribute.value()); if (!locationOpt.has_value()) { @@ -2728,13 +3126,16 @@ bool TypeSystemParser::parseInclude(const ConditionalStreamReader &, } Include inc(location, fileName); - if (topElement.type - & (StackElement::ComplexTypeEntryMask | StackElement::PrimitiveTypeEntry)) { + if (isComplexTypeEntry(topElement) + || topElement == StackElement::PrimitiveTypeEntry + || topElement == StackElement::ContainerTypeEntry + || topElement == StackElement::SmartPointerTypeEntry + || topElement == StackElement::TypedefTypeEntry) { entry->setInclude(inc); - } else if (topElement.type == StackElement::ExtraIncludes) { + } else if (topElement == StackElement::ExtraIncludes) { entry->addExtraInclude(inc); } else { - m_error = QLatin1String("Only supported parent tags are primitive-type, complex types or extra-includes"); + m_error = u"Only supported parent tags are primitive-type, complex types or extra-includes"_s; return false; } return true; @@ -2743,57 +3144,79 @@ bool TypeSystemParser::parseInclude(const ConditionalStreamReader &, bool TypeSystemParser::parseSystemInclude(const ConditionalStreamReader &, QXmlStreamAttributes *attributes) { - const int index = indexOfAttribute(*attributes, fileNameAttribute()); + const auto index = indexOfAttribute(*attributes, fileNameAttribute); if (index == -1) { - m_error = msgMissingAttribute(fileNameAttribute()); + m_error = msgMissingAttribute(fileNameAttribute); return false; } - TypeDatabase::instance()->addSystemInclude(attributes->takeAt(index).value().toString()); + TypeDatabase::instance()->addForceProcessSystemInclude(attributes->takeAt(index).value().toString()); return true; } TemplateInstance * - TypeSystemParser::parseTemplateInstanceEnum(const ConditionalStreamReader &, - const StackElement &topElement, - QXmlStreamAttributes *attributes) + TypeSystemParser::parseInsertTemplate(const ConditionalStreamReader &, + StackElement topElement, + QXmlStreamAttributes *attributes) { - if (!(topElement.type & StackElement::CodeSnipMask) && - (topElement.type != StackElement::Template) && - (topElement.type != StackElement::CustomMetaConstructor) && - (topElement.type != StackElement::CustomMetaDestructor) && - (topElement.type != StackElement::NativeToTarget) && - (topElement.type != StackElement::AddConversion) && - (topElement.type != StackElement::ConversionRule)) { - m_error = QLatin1String("Can only insert templates into code snippets, templates, custom-constructors, "\ - "custom-destructors, conversion-rule, native-to-target or add-conversion tags."); + if ((topElement != StackElement::InjectCode) && + (topElement != StackElement::Template) && + (topElement != StackElement::NativeToTarget) && + (topElement != StackElement::AddConversion) && + (topElement != StackElement::ConversionRule)) { + m_error = u"Can only insert templates into code snippets, templates, "\ + "conversion-rule, native-to-target or add-conversion tags."_s; return nullptr; } - const int nameIndex = indexOfAttribute(*attributes, nameAttribute()); + const auto nameIndex = indexOfAttribute(*attributes, nameAttribute); if (nameIndex == -1) { - m_error = msgMissingAttribute(nameAttribute()); + m_error = msgMissingAttribute(nameAttribute); return nullptr; } return new TemplateInstance(attributes->takeAt(nameIndex).value().toString()); } bool TypeSystemParser::parseReplace(const ConditionalStreamReader &, - const StackElement &topElement, - StackElement *element, QXmlStreamAttributes *attributes) + StackElement topElement, QXmlStreamAttributes *attributes) { - if (topElement.type != StackElement::TemplateInstanceEnum) { - m_error = QLatin1String("Can only insert replace rules into insert-template."); + if (topElement != StackElement::InsertTemplate) { + m_error = u"Can only insert replace rules into insert-template."_s; return false; } QString from; QString to; - for (int i = attributes->size() - 1; i >= 0; --i) { + for (auto i = attributes->size() - 1; i >= 0; --i) { const auto name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("from")) + if (name == u"from") from = attributes->takeAt(i).value().toString(); - else if (name == toAttribute()) + else if (name == toAttribute) to = attributes->takeAt(i).value().toString(); } - element->parent->value.templateInstance->addReplaceRule(from, to); + m_templateInstance->addReplaceRule(from, to); + return true; +} + +// Check for a duplicated type entry and return whether to add the new one. +// We need to be able to have duplicate primitive type entries, +// or it's not possible to cover all primitive target language +// types (which we need to do in order to support fake meta objects) +bool TypeSystemParser::checkDuplicatedTypeEntry(const ConditionalStreamReader &reader, + StackElement t, + const QString &name) const +{ + if (t == StackElement::PrimitiveTypeEntry || t == StackElement::FunctionTypeEntry) + return true; + const auto duplicated = m_context->db->findType(name); + if (!duplicated || duplicated->isNamespace()) + return true; + if (duplicated->isBuiltIn()) { + qCWarning(lcShiboken, "%s", + qPrintable(msgReaderMessage(reader, "Warning", + msgDuplicateBuiltInTypeEntry(name)))); + return false; + } + qCWarning(lcShiboken, "%s", + qPrintable(msgReaderMessage(reader, "Warning", + msgDuplicateTypeEntry(name)))); return true; } @@ -2808,7 +3231,7 @@ static bool parseVersion(const QString &versionSpec, const QString &package, return true; } -bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) +bool TypeSystemParser::startElement(const ConditionalStreamReader &reader, StackElement element) { if (m_ignoreDepth) { ++m_ignoreDepth; @@ -2819,14 +3242,14 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) QXmlStreamAttributes attributes = reader.attributes(); VersionRange versionRange; - for (int i = attributes.size() - 1; i >= 0; --i) { + for (auto i = attributes.size() - 1; i >= 0; --i) { const auto name = attributes.at(i).qualifiedName(); - if (name == sinceAttribute()) { + if (name == sinceAttribute) { if (!parseVersion(attributes.takeAt(i).value().toString(), m_defaultPackage, &versionRange.since, &m_error)) { return false; } - } else if (name == untilAttribute()) { + } else if (name == untilAttribute) { if (!parseVersion(attributes.takeAt(i).value().toString(), m_defaultPackage, &versionRange.until, &m_error)) { return false; @@ -2835,89 +3258,76 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) } if (!m_defaultPackage.isEmpty() && !versionRange.isNull()) { - TypeDatabase* td = TypeDatabase::instance(); + auto *td = TypeDatabase::instance(); if (!td->checkApiVersion(m_defaultPackage, versionRange)) { ++m_ignoreDepth; return true; } } - if (tagName.compare(QLatin1String("import-file"), Qt::CaseInsensitive) == 0) + if (element == StackElement::ImportFile) return importFileElement(attributes); - const auto elementTypeOpt = elementFromTag(tagName); - if (!elementTypeOpt.has_value()) { - m_error = QStringLiteral("Unknown tag name: '%1'").arg(tagName); - return false; - } - - if (m_currentDroppedEntry) { + if (m_currentDroppedEntryDepth) { ++m_currentDroppedEntryDepth; return true; } - std::unique_ptr<StackElement> element(new StackElement(m_current)); - element->type = elementTypeOpt.value(); - - if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateCode) + if (element == StackElement::Root && m_generate == TypeEntry::GenerateCode) customConversionsForReview.clear(); - if (element->type == StackElement::CustomMetaConstructor - || element->type == StackElement::CustomMetaDestructor) { + if (element == StackElement::Unimplemented) { qCWarning(lcShiboken, "%s", qPrintable(msgUnimplementedElementWarning(reader, tagName))); + return true; } - switch (element->type) { - case StackElement::Root: - case StackElement::NamespaceTypeEntry: - case StackElement::InterfaceTypeEntry: - case StackElement::ObjectTypeEntry: - case StackElement::ValueTypeEntry: - case StackElement::PrimitiveTypeEntry: - case StackElement::TypedefTypeEntry: - case StackElement::ContainerTypeEntry: - m_contextStack.push(new StackElementContext()); - break; - default: - break; + if (isTypeEntry(element) || element == StackElement::Root) + m_contextStack.push(std::make_shared<StackElementContext>()); + + if (m_contextStack.isEmpty()) { + m_error = msgNoRootTypeSystemEntry(); + return false; } - if (element->type & StackElement::TypeEntryMask) { + const auto &top = m_contextStack.top(); + const StackElement topElement = m_stack.value(m_stack.size() - 2, StackElement::None); + + if (isTypeEntry(element)) { QString name; - if (element->type != StackElement::FunctionTypeEntry) { - const int nameIndex = indexOfAttribute(attributes, nameAttribute()); + if (element != StackElement::FunctionTypeEntry) { + const auto nameIndex = indexOfAttribute(attributes, nameAttribute); if (nameIndex != -1) { name = attributes.takeAt(nameIndex).value().toString(); - } else if (element->type != StackElement::EnumTypeEntry) { // anonymous enum? - m_error = msgMissingAttribute(nameAttribute()); + } else if (element != StackElement::EnumTypeEntry) { // anonymous enum? + m_error = msgMissingAttribute(nameAttribute); return false; } } // Allow for primitive and/or std:: types only, else require proper nesting. - if (element->type != StackElement::PrimitiveTypeEntry && name.contains(QLatin1Char(':')) - && !name.contains(QLatin1String("std::"))) { + if (element != StackElement::PrimitiveTypeEntry && name.contains(u':') + && !name.contains(u"std::")) { m_error = msgIncorrectlyNestedName(name); return false; } - if (m_database->hasDroppedTypeEntries()) { - const QString identifier = element->type == StackElement::FunctionTypeEntry - ? attributes.value(signatureAttribute()).toString() : name; - if (shouldDropTypeEntry(m_database, element.get(), identifier)) { - m_currentDroppedEntry = element.release(); + if (m_context->db->hasDroppedTypeEntries()) { + const QString identifier = element == StackElement::FunctionTypeEntry + ? attributes.value(signatureAttribute).toString().simplified() : name; + if (shouldDropTypeEntry(m_context->db, m_contextStack, identifier)) { m_currentDroppedEntryDepth = 1; if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { qCInfo(lcShiboken, "Type system entry '%s' was intentionally dropped from generation.", qPrintable(identifier)); } + m_contextStack.pop(); return true; } } // The top level tag 'function' has only the 'signature' tag // and we should extract the 'name' value from it. - if (element->type == StackElement::FunctionTypeEntry + if (element == StackElement::FunctionTypeEntry && !parseRenameFunction(reader, &name, &attributes)) { return false; } @@ -2925,144 +3335,134 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) // We need to be able to have duplicate primitive type entries, // or it's not possible to cover all primitive target language // types (which we need to do in order to support fake meta objects) - if (element->type != StackElement::PrimitiveTypeEntry - && element->type != StackElement::FunctionTypeEntry) { - TypeEntry *tmp = m_database->findType(name); + if (element != StackElement::PrimitiveTypeEntry + && element != StackElement::FunctionTypeEntry) { + TypeEntryPtr tmp = m_context->db->findType(name); if (tmp && !tmp->isNamespace()) qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("Duplicate type entry: '%1'").arg(name); + << "Duplicate type entry: '" << name << '\''; } - if (element->type == StackElement::EnumTypeEntry) { - const int enumIdentifiedByIndex = indexOfAttribute(attributes, enumIdentifiedByValueAttribute()); + if (element == StackElement::EnumTypeEntry) { + const auto enumIdentifiedByIndex = + indexOfAttribute(attributes, enumIdentifiedByValueAttribute); const QString identifiedByValue = enumIdentifiedByIndex != -1 ? attributes.takeAt(enumIdentifiedByIndex).value().toString() : QString(); if (name.isEmpty()) { name = identifiedByValue; } else if (!identifiedByValue.isEmpty()) { - m_error = QLatin1String("can't specify both 'name' and 'identified-by-value' attributes"); + m_error = u"can't specify both 'name' and 'identified-by-value' attributes"_s; return false; } } if (name.isEmpty()) { - m_error = QLatin1String("no 'name' attribute specified"); + m_error = u"no 'name' attribute specified"_s; return false; } - switch (element->type) { + switch (element) { case StackElement::CustomTypeEntry: - element->entry = - parseCustomTypeEntry(reader, name, versionRange.since, &attributes); - if (Q_UNLIKELY(!element->entry)) + top->entry = parseCustomTypeEntry(reader, name, versionRange.since, &attributes); + if (Q_UNLIKELY(!top->entry)) return false; break; case StackElement::PrimitiveTypeEntry: - element->entry = parsePrimitiveTypeEntry(reader, name, versionRange.since, &attributes); - if (Q_UNLIKELY(!element->entry)) + top->entry = parsePrimitiveTypeEntry(reader, name, versionRange.since, &attributes); + if (Q_UNLIKELY(!top->entry)) return false; break; case StackElement::ContainerTypeEntry: - if (ContainerTypeEntry *ce = parseContainerTypeEntry(reader, name, versionRange.since, &attributes)) { - applyComplexTypeAttributes(reader, ce, &attributes); - element->entry = ce; - } else { + top->entry = parseContainerTypeEntry(reader, name, versionRange.since, &attributes); + if (top->entry == nullptr) return false; - } break; case StackElement::SmartPointerTypeEntry: - if (SmartPointerTypeEntry *se = parseSmartPointerEntry(reader, name, versionRange.since, &attributes)) { - applyComplexTypeAttributes(reader, se, &attributes); - element->entry = se; - } else { + top->entry = parseSmartPointerEntry(reader, name, versionRange.since, &attributes); + if (top->entry == nullptr) return false; - } break; case StackElement::EnumTypeEntry: m_currentEnum = parseEnumTypeEntry(reader, name, versionRange.since, &attributes); if (Q_UNLIKELY(!m_currentEnum)) return false; - element->entry = m_currentEnum; + top->entry = m_currentEnum; break; case StackElement::ValueTypeEntry: - if (ValueTypeEntry *ve = parseValueTypeEntry(reader, name, versionRange.since, &attributes)) { - applyComplexTypeAttributes(reader, ve, &attributes); - element->entry = ve; - } else { + top->entry = parseValueTypeEntry(reader, name, versionRange.since, &attributes); + if (top->entry == nullptr) return false; - } break; case StackElement::NamespaceTypeEntry: - if (auto entry = parseNamespaceTypeEntry(reader, name, versionRange.since, &attributes)) - element->entry = entry; - else + top->entry = parseNamespaceTypeEntry(reader, name, versionRange.since, &attributes); + if (top->entry == nullptr) return false; break; case StackElement::ObjectTypeEntry: - case StackElement::InterfaceTypeEntry: + case StackElement::InterfaceTypeEntry: { if (!checkRootElement()) return false; - element->entry = new ObjectTypeEntry(name, versionRange.since, currentParentTypeEntry()); - applyCommonAttributes(reader, element->entry, &attributes); - applyComplexTypeAttributes(reader, static_cast<ComplexTypeEntry *>(element->entry), &attributes); + auto ce = std::make_shared<ObjectTypeEntry>(name, versionRange.since, currentParentTypeEntry()); + top->entry = ce; + applyCommonAttributes(reader, top->entry, &attributes); + applyComplexTypeAttributes(reader, ce, &attributes); + } break; case StackElement::FunctionTypeEntry: - element->entry = parseFunctionTypeEntry(reader, name, versionRange.since, &attributes); - if (Q_UNLIKELY(!element->entry)) + top->entry = parseFunctionTypeEntry(reader, name, versionRange.since, &attributes); + if (Q_UNLIKELY(!top->entry)) return false; break; case StackElement::TypedefTypeEntry: - if (TypedefEntry *te = parseTypedefEntry(reader, name, versionRange.since, &attributes)) { - applyComplexTypeAttributes(reader, te, &attributes); - element->entry = te; - } else { + top->entry = parseTypedefEntry(reader, name, topElement, + versionRange.since, &attributes); + if (top->entry == nullptr) return false; - } break; default: Q_ASSERT(false); } - if (element->entry) { - if (!m_database->addType(element->entry, &m_error)) + if (top->entry) { + if (checkDuplicatedTypeEntry(reader, element, top->entry->name()) + && !m_context->db->addType(top->entry, &m_error)) { return false; + } } else { qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("Type: %1 was rejected by typesystem").arg(name); + << u"Type: "_s + name + u" was rejected by typesystem"_s; } - } else if (element->type == StackElement::InjectDocumentation) { - if (!parseInjectDocumentation(reader, &attributes)) + } else if (element == StackElement::InjectDocumentation) { + if (!parseInjectDocumentation(reader, topElement, &attributes)) return false; - } else if (element->type == StackElement::ModifyDocumentation) { - if (!parseModifyDocumentation(reader, &attributes)) + } else if (element == StackElement::ModifyDocumentation) { + if (!parseModifyDocumentation(reader, topElement, &attributes)) return false; - } else if (element->type != StackElement::None) { - bool topLevel = element->type == StackElement::Root - || element->type == StackElement::SuppressedWarning - || element->type == StackElement::Rejection - || element->type == StackElement::LoadTypesystem - || element->type == StackElement::InjectCode - || element->type == StackElement::ExtraIncludes - || element->type == StackElement::SystemInclude - || element->type == StackElement::ConversionRule - || element->type == StackElement::AddFunction - || element->type == StackElement::Template; - - if (!topLevel && m_current->type == StackElement::Root) { - m_error = QStringLiteral("Tag requires parent: '%1'").arg(tagName); + } else if (element != StackElement::None) { + bool topLevel = element == StackElement::Root + || element == StackElement::SuppressedWarning + || element == StackElement::Rejection + || element == StackElement::LoadTypesystem + || element == StackElement::InjectCode + || element == StackElement::ExtraIncludes + || element == StackElement::SystemInclude + || element == StackElement::ConversionRule + || element == StackElement::AddFunction + || element == StackElement::DeclareFunction + || element == StackElement::Template + || element == StackElement::OpaqueContainer; + + if (!topLevel && m_stack.at(m_stack.size() - 2) == StackElement::Root) { + m_error = u"Tag requires parent: '"_s + tagName.toString() + u'\''; return false; } - StackElement topElement = !m_current ? StackElement(nullptr) : *m_current; - element->entry = topElement.entry; - - switch (element->type) { + switch (element) { case StackElement::Root: - element->entry = parseRootElement(reader, versionRange.since, &attributes); - element->type = StackElement::Root; + top->entry = parseRootElement(reader, versionRange.since, &attributes); break; case StackElement::LoadTypesystem: if (!loadTypesystem(reader, &attributes)) @@ -3085,15 +3485,24 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) return false; break; case StackElement::TargetToNative: { - if (topElement.type != StackElement::ConversionRule) { - m_error = QLatin1String("Target to Native conversions can only be specified for custom conversion rules."); + if (topElement != StackElement::ConversionRule) { + m_error = u"Target to Native conversions can only be specified for custom conversion rules."_s; return false; } - const int replaceIndex = indexOfAttribute(attributes, replaceAttribute()); - const bool replace = replaceIndex == -1 - || convertBoolean(attributes.takeAt(replaceIndex).value(), - replaceAttribute(), true); - m_current->entry->customConversion()->setReplaceOriginalTargetToNativeConversions(replace); + + const auto topParent = m_stack.value(m_stack.size() - 3, StackElement::None); + if (isTypeEntry(topParent)) { + const auto replaceIndex = indexOfAttribute(attributes, replaceAttribute); + const bool replace = replaceIndex == -1 + || convertBoolean(attributes.takeAt(replaceIndex).value(), + replaceAttribute, true); + auto customConversion = CustomConversion::getCustomConversion(top->entry); + if (!customConversion) { + m_error = msgMissingCustomConversion(top->entry); + return false; + } + customConversion->setReplaceOriginalTargetToNativeConversions(replace); + } } break; case StackElement::AddConversion: @@ -3113,14 +3522,17 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) return false; break; case StackElement::SuppressedWarning: { - const int textIndex = indexOfAttribute(attributes, textAttribute()); + const auto textIndex = indexOfAttribute(attributes, textAttribute); if (textIndex == -1) { qCWarning(lcShiboken) << "Suppressed warning with no text specified"; } else { const QString suppressedWarning = attributes.takeAt(textIndex).value().toString(); - if (!m_database->addSuppressedWarning(suppressedWarning, &m_error)) + if (!m_context->db->addSuppressedWarning(suppressedWarning, + m_generate == TypeEntry::GenerateCode, + &m_error)) { return false; + } } } break; @@ -3129,12 +3541,12 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) return false; break; case StackElement::RemoveArgument: - if (topElement.type != StackElement::ModifyArgument) { - m_error = QLatin1String("Removing argument requires argument modification as parent"); + if (topElement != StackElement::ModifyArgument) { + m_error = u"Removing argument requires argument modification as parent"_s; return false; } - m_contextStack.top()->functionMods.last().argument_mods().last().setRemoved(true); + top->functionMods.last().argument_mods().last().setRemoved(true); break; case StackElement::ModifyField: @@ -3143,7 +3555,11 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) break; case StackElement::DeclareFunction: case StackElement::AddFunction: - if (!parseAddFunction(reader, topElement, element->type, &attributes)) + if (!parseAddFunction(reader, topElement, element, &attributes)) + return false; + break; + case StackElement::AddPyMethodDef: + if (!parseAddPyMethodDef(reader, topElement, &attributes)) return false; break; case StackElement::Property: @@ -3159,12 +3575,7 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) return false; break; case StackElement::RemoveDefaultExpression: - m_contextStack.top()->functionMods.last().argument_mods().last().setRemovedDefaultExpression(true); - break; - case StackElement::CustomMetaConstructor: - case StackElement::CustomMetaDestructor: - element->value.customFunction = - parseCustomMetaConstructor(reader, element->type, topElement, &attributes); + top->functionMods.last().argument_mods().last().setRemovedDefaultExpression(true); break; case StackElement::ReferenceCount: if (!parseReferenceCount(reader, topElement, &attributes)) @@ -3175,46 +3586,52 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) return false; break; case StackElement::Array: - if (topElement.type != StackElement::ModifyArgument) { - m_error = QLatin1String("array must be child of modify-argument"); + if (topElement != StackElement::ModifyArgument) { + m_error = u"array must be child of modify-argument"_s; return false; } - m_contextStack.top()->functionMods.last().argument_mods().last().setArray(true); + top->functionMods.last().argument_mods().last().setArray(true); break; case StackElement::InjectCode: - if (!parseInjectCode(reader, topElement, element.get(), &attributes)) + if (!parseInjectCode(reader, topElement, &attributes)) return false; break; case StackElement::Include: - if (!parseInclude(reader, topElement, element->entry, &attributes)) + if (!parseInclude(reader, topElement, top->entry, &attributes)) return false; break; case StackElement::Rejection: - if (!addRejection(m_database, &attributes, &m_error)) + if (!addRejection(m_context->db, m_generate == TypeEntry::GenerateCode, + &attributes, &m_error)) { return false; + } break; case StackElement::SystemInclude: if (!parseSystemInclude(reader, &attributes)) return false; break; case StackElement::Template: { - const int nameIndex = indexOfAttribute(attributes, nameAttribute()); + const auto nameIndex = indexOfAttribute(attributes, nameAttribute); if (nameIndex == -1) { - m_error = msgMissingAttribute(nameAttribute()); + m_error = msgMissingAttribute(nameAttribute); return false; } - element->value.templateEntry = - new TemplateEntry(attributes.takeAt(nameIndex).value().toString()); + m_templateEntry.reset(new TemplateEntry(attributes.takeAt(nameIndex).value().toString())); } break; - case StackElement::TemplateInstanceEnum: - element->value.templateInstance = - parseTemplateInstanceEnum(reader, topElement, &attributes); - if (!element->value.templateInstance) + case StackElement::InsertTemplate: + m_templateInstance.reset(parseInsertTemplate(reader, topElement, &attributes)); + if (!m_templateInstance) return false; break; case StackElement::Replace: - if (!parseReplace(reader, topElement, element.get(), &attributes)) + if (!parseReplace(reader, topElement, &attributes)) + return false; + break; + case StackElement::OpaqueContainer: + if (!parseOpaqueContainerElement(&attributes)) + case StackElement::Configuration: + if (!parseConfiguration(topElement, &attributes)) return false; break; default: @@ -3227,6 +3644,5 @@ bool TypeSystemParser::startElement(const ConditionalStreamReader &reader) qCWarning(lcShiboken, "%s", qPrintable(msgReaderWarning(reader, message))); } - m_current = element.release(); return true; } diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.h b/sources/shiboken6/ApiExtractor/typesystemparser.h deleted file mode 100644 index f1e11d661..000000000 --- a/sources/shiboken6/ApiExtractor/typesystemparser.h +++ /dev/null @@ -1,285 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ -#ifndef TYPESYSTEMPARSER_H -#define TYPESYSTEMPARSER_H - -#include "typesystem.h" -#include "modifications.h" - -#include <QtCore/QStack> -#include <QtCore/QHash> -#include <QtCore/QScopedPointer> - -QT_FORWARD_DECLARE_CLASS(QVersionNumber) -QT_FORWARD_DECLARE_CLASS(QXmlStreamAttributes) -QT_FORWARD_DECLARE_CLASS(QXmlStreamReader) - -class ConditionalStreamReader; - -class TypeSystemEntityResolver; -class TypeDatabase; -class StackElement -{ - public: - enum ElementType { - None = 0x0, - - // Type tags (0x1, ... , 0xff) - ObjectTypeEntry = 0x1, - ValueTypeEntry = 0x2, - InterfaceTypeEntry = 0x3, - NamespaceTypeEntry = 0x4, - ComplexTypeEntryMask = 0x7, - - // Non-complex type tags (0x8, 0x9, ... , 0xf) - PrimitiveTypeEntry = 0x8, - EnumTypeEntry = 0x9, - ContainerTypeEntry = 0xa, - FunctionTypeEntry = 0xb, - CustomTypeEntry = 0xc, - SmartPointerTypeEntry = 0xd, - TypedefTypeEntry = 0xe, - TypeEntryMask = 0xf, - - // Documentation tags - InjectDocumentation = 0x10, - ModifyDocumentation = 0x20, - DocumentationMask = 0xf0, - - // Simple tags (0x100, 0x200, ... , 0xf00) - ExtraIncludes = 0x0100, - Include = 0x0200, - ModifyFunction = 0x0300, - ModifyField = 0x0400, - Root = 0x0500, - CustomMetaConstructor = 0x0600, - CustomMetaDestructor = 0x0700, - SuppressedWarning = 0x0900, - Rejection = 0x0a00, - LoadTypesystem = 0x0b00, - RejectEnumValue = 0x0c00, - Template = 0x0d00, - TemplateInstanceEnum = 0x0e00, - Replace = 0x0f00, - AddFunction = 0x1000, - DeclareFunction = 0x1100, - NativeToTarget = 0x1200, - TargetToNative = 0x1300, - AddConversion = 0x1400, - SystemInclude = 0x1500, - Property = 0x1600, - SimpleMask = 0x3f00, - - // Code snip tags (0x1000, 0x2000, ... , 0xf000) - InjectCode = 0x4000, - InjectCodeInFunction = 0x8000, - CodeSnipMask = 0xc000, - - // Function modifier tags (0x010000, 0x020000, ... , 0xf00000) - Rename = 0x040000, // (modify-argument) - ModifyArgument = 0x080000, - Thread = 0x100000, - FunctionModifiers = 0xff0000, - - // Argument modifier tags (0x01000000 ... 0xf0000000) - ConversionRule = 0x01000000, - ReplaceType = 0x02000000, - ReplaceDefaultExpression = 0x04000000, - RemoveArgument = 0x08000000, - DefineOwnership = 0x10000000, - RemoveDefaultExpression = 0x20000000, - NoNullPointers = 0x40000000, - ReferenceCount = 0x80000000, - ParentOwner = 0x90000000, - Array = 0xA0000000, - ArgumentModifiers = 0xff000000 - }; - - StackElement(StackElement *p) : entry(nullptr), type(None), parent(p) { } - - TypeEntry* entry; - ElementType type; - StackElement *parent; - - union { - TemplateInstance* templateInstance; - TemplateEntry* templateEntry; - CustomFunction* customFunction; - } value; -}; - -struct StackElementContext -{ - CodeSnipList codeSnips; - AddedFunctionList addedFunctions; - FunctionModificationList functionMods; - FieldModificationList fieldMods; - DocModificationList docModifications; - int addedFunctionModificationIndex = -1; -}; - -class TypeSystemParser -{ -public: - Q_DISABLE_COPY(TypeSystemParser) - - TypeSystemParser(TypeDatabase* database, bool generate); - ~TypeSystemParser(); - - bool parse(ConditionalStreamReader &reader); - - QString errorString() const { return m_error; } - -private: - bool parseXml(ConditionalStreamReader &reader); - bool setupSmartPointerInstantiations(); - bool startElement(const ConditionalStreamReader &reader); - SmartPointerTypeEntry *parseSmartPointerEntry(const ConditionalStreamReader &, - const QString &name, - const QVersionNumber &since, - QXmlStreamAttributes *attributes); - bool endElement(QStringView localName); - template <class String> // QString/QStringRef - bool characters(const String &ch); - - bool importFileElement(const QXmlStreamAttributes &atts); - - const TypeEntry *currentParentTypeEntry() const; - bool checkRootElement(); - bool applyCommonAttributes(const ConditionalStreamReader &reader, TypeEntry *type, - QXmlStreamAttributes *attributes); - PrimitiveTypeEntry * - parsePrimitiveTypeEntry(const ConditionalStreamReader &, const QString &name, - const QVersionNumber &since, QXmlStreamAttributes *); - CustomTypeEntry * - parseCustomTypeEntry(const ConditionalStreamReader &, const QString &name, - const QVersionNumber &since, QXmlStreamAttributes *); - ContainerTypeEntry * - parseContainerTypeEntry(const ConditionalStreamReader &, const QString &name, - const QVersionNumber &since, QXmlStreamAttributes *); - EnumTypeEntry * - parseEnumTypeEntry(const ConditionalStreamReader &, const QString &name, - const QVersionNumber &since, QXmlStreamAttributes *); - FlagsTypeEntry * - parseFlagsEntry(const ConditionalStreamReader &, EnumTypeEntry *enumEntry, - QString flagName, const QVersionNumber &since, - QXmlStreamAttributes *); - - NamespaceTypeEntry * - parseNamespaceTypeEntry(const ConditionalStreamReader &, - const QString &name, const QVersionNumber &since, - QXmlStreamAttributes *attributes); - - ValueTypeEntry * - parseValueTypeEntry(const ConditionalStreamReader &, const QString &name, - const QVersionNumber &since, QXmlStreamAttributes *); - FunctionTypeEntry * - parseFunctionTypeEntry(const ConditionalStreamReader &, const QString &name, - const QVersionNumber &since, QXmlStreamAttributes *); - TypedefEntry * - parseTypedefEntry(const ConditionalStreamReader &, const QString &name, - const QVersionNumber &since, QXmlStreamAttributes *); - void applyComplexTypeAttributes(const ConditionalStreamReader &, ComplexTypeEntry *ctype, - QXmlStreamAttributes *) const; - bool parseRenameFunction(const ConditionalStreamReader &, QString *name, - QXmlStreamAttributes *); - bool parseInjectDocumentation(const ConditionalStreamReader &, QXmlStreamAttributes *); - bool parseModifyDocumentation(const ConditionalStreamReader &, QXmlStreamAttributes *); - TypeSystemTypeEntry * - parseRootElement(const ConditionalStreamReader &, const QVersionNumber &since, - QXmlStreamAttributes *); - bool loadTypesystem(const ConditionalStreamReader &, QXmlStreamAttributes *); - bool parseRejectEnumValue(const ConditionalStreamReader &, QXmlStreamAttributes *); - bool parseReplaceArgumentType(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *); - bool parseCustomConversion(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *); - bool parseAddConversion(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *); - bool parseNativeToTarget(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *attributes); - bool parseModifyArgument(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *attributes); - bool parseNoNullPointer(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *attributes); - bool parseDefineOwnership(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *); - bool parseRename(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *); - bool parseModifyField(const ConditionalStreamReader &, QXmlStreamAttributes *); - bool parseAddFunction(const ConditionalStreamReader &, const StackElement &topElement, - StackElement::ElementType t, QXmlStreamAttributes *); - bool parseProperty(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *); - bool parseModifyFunction(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *); - bool parseReplaceDefaultExpression(const ConditionalStreamReader &, - const StackElement &topElement, QXmlStreamAttributes *); - static CustomFunction * - parseCustomMetaConstructor(const ConditionalStreamReader &, - StackElement::ElementType type, - const StackElement &topElement, QXmlStreamAttributes *); - bool parseReferenceCount(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *); - bool parseParentOwner(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *); - bool readFileSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip); - bool parseInjectCode(const ConditionalStreamReader &, const StackElement &topElement, - StackElement* element, QXmlStreamAttributes *); - bool parseInclude(const ConditionalStreamReader &, const StackElement &topElement, - TypeEntry *entry, QXmlStreamAttributes *); - bool parseSystemInclude(const ConditionalStreamReader &, QXmlStreamAttributes *); - TemplateInstance - *parseTemplateInstanceEnum(const ConditionalStreamReader &, const StackElement &topElement, - QXmlStreamAttributes *); - bool parseReplace(const ConditionalStreamReader &, const StackElement &topElement, - StackElement *element, QXmlStreamAttributes *); - - TypeDatabase* m_database; - StackElement* m_current = nullptr; - StackElement* m_currentDroppedEntry = nullptr; - int m_currentDroppedEntryDepth = 0; - int m_ignoreDepth = 0; - QString m_defaultPackage; - QString m_defaultSuperclass; - TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; - TypeSystem::AllowThread m_allowThread = TypeSystem::AllowThread::Unspecified; - QString m_error; - const TypeEntry::CodeGeneration m_generate; - - EnumTypeEntry* m_currentEnum = nullptr; - QStack<StackElementContext*> m_contextStack; - - QString m_currentSignature; - QString m_currentPath; - QString m_currentFile; - QScopedPointer<TypeSystemEntityResolver> m_entityResolver; - QHash<SmartPointerTypeEntry *, QString> m_smartPointerInstantiations; -}; - -#endif // TYPESYSTEMPARSER_H diff --git a/sources/shiboken6/ApiExtractor/typesystemparser_p.h b/sources/shiboken6/ApiExtractor/typesystemparser_p.h new file mode 100644 index 000000000..4d9d4fd92 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/typesystemparser_p.h @@ -0,0 +1,297 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#ifndef TYPESYSTEMPARSER_H +#define TYPESYSTEMPARSER_H + +#include "typesystem.h" +#include "containertypeentry.h" +#include "typedatabase.h" +#include "typedatabase_p.h" +#include "typesystem_typedefs.h" +#include "codesnip.h" + +#include <QtCore/QStack> +#include <QtCore/QHash> +#include <QtCore/QScopedPointer> + +#include <memory> +#include <optional> + +QT_FORWARD_DECLARE_CLASS(QVersionNumber) +QT_FORWARD_DECLARE_CLASS(QXmlStreamAttributes) +QT_FORWARD_DECLARE_CLASS(QXmlStreamReader) + +class ConditionalStreamReader; + +class TypeSystemEntityResolver; +class TypeDatabase; + +class FlagsTypeEntry; +class TypeSystemTypeEntry; +class ValueTypeEntry; +class EnumTypeEntry; + +enum class ParserState; + +enum class StackElement { + None, + + // Type tags + ObjectTypeEntry, + FirstTypeEntry = ObjectTypeEntry, + ValueTypeEntry, + InterfaceTypeEntry, + NamespaceTypeEntry, + LastComplexTypeEntry = NamespaceTypeEntry, + + // Non-complex type tags + PrimitiveTypeEntry, + EnumTypeEntry, + ContainerTypeEntry, + FunctionTypeEntry, + CustomTypeEntry, + SmartPointerTypeEntry, + TypedefTypeEntry, + LastTypeEntry = TypedefTypeEntry, + + // Documentation tags + InjectDocumentation, + FirstDocumentation = InjectDocumentation, + ModifyDocumentation, + LastDocumentation = ModifyDocumentation, + + // Simple tags + ExtraIncludes, + Include, + ModifyFunction, + ModifyField, + Root, + SuppressedWarning, + Rejection, + LoadTypesystem, + RejectEnumValue, + Template, + InsertTemplate, + Replace, + AddFunction, + AddPyMethodDef, + DeclareFunction, + NativeToTarget, + TargetToNative, + AddConversion, + SystemInclude, + Property, + + // Code snip tags + InjectCode, + + // Function modifier tags + Rename, // (modify-argument) + ModifyArgument, + Thread, + + // Argument modifier tags + ConversionRule, + ReplaceType, + ReplaceDefaultExpression, + RemoveArgument, + DefineOwnership, + RemoveDefaultExpression, + NoNullPointers, + ReferenceCount, + ParentOwner, + Array, + ArgumentModifiers, + + ImportFile, + OpaqueContainer, + Configuration, + Unimplemented +}; + +inline uint64_t operator&(StackElement s1, StackElement s2) +{ + return uint64_t(s1) & uint64_t(s2); +} + +inline StackElement operator|(StackElement s1, StackElement s2) +{ + return StackElement(uint64_t(s1) | uint64_t(s2)); +} + +struct StackElementContext +{ + CodeSnipList conversionCodeSnips; + AddedFunctionList addedFunctions; + FunctionModificationList functionMods; + FieldModificationList fieldMods; + DocModificationList docModifications; + TypeEntryPtr entry; + int addedFunctionModificationIndex = -1; +}; + +class TypeSystemParser +{ +public: + Q_DISABLE_COPY_MOVE(TypeSystemParser) + + using StackElementContextPtr = std::shared_ptr<StackElementContext>; + using ContextStack = QStack<StackElementContextPtr>; + + explicit TypeSystemParser(const std::shared_ptr<TypeDatabaseParserContext> &context, + bool generate); + ~TypeSystemParser(); + + bool parse(ConditionalStreamReader &reader); + + QString errorString() const { return m_error; } + +private: + struct Snippet + { + QString content; + QString fileName; + QString snippetLabel; + }; + + bool parseXml(ConditionalStreamReader &reader); + bool setupSmartPointerInstantiations(); + bool startElement(const ConditionalStreamReader &reader, StackElement element); + SmartPointerTypeEntryPtr parseSmartPointerEntry(const ConditionalStreamReader &, + const QString &name, + const QVersionNumber &since, + QXmlStreamAttributes *attributes); + bool endElement(StackElement element); + template <class String> // QString/QStringRef + bool characters(const String &ch); + + bool importFileElement(const QXmlStreamAttributes &atts); + + TypeEntryCPtr currentParentTypeEntry() const; + bool checkRootElement(); + bool applyCommonAttributes(const ConditionalStreamReader &reader, + const TypeEntryPtr &type, + QXmlStreamAttributes *attributes); + PrimitiveTypeEntryPtr + parsePrimitiveTypeEntry(const ConditionalStreamReader &, const QString &name, + const QVersionNumber &since, QXmlStreamAttributes *); + CustomTypeEntryPtr + parseCustomTypeEntry(const ConditionalStreamReader &, const QString &name, + const QVersionNumber &since, QXmlStreamAttributes *); + bool parseOpaqueContainers(QStringView s, OpaqueContainers *result); + ContainerTypeEntryPtr + parseContainerTypeEntry(const ConditionalStreamReader &, const QString &name, + const QVersionNumber &since, QXmlStreamAttributes *); + bool parseOpaqueContainerElement(QXmlStreamAttributes *attributes); + EnumTypeEntryPtr + parseEnumTypeEntry(const ConditionalStreamReader &, const QString &name, + const QVersionNumber &since, QXmlStreamAttributes *); + FlagsTypeEntryPtr + parseFlagsEntry(const ConditionalStreamReader &, const EnumTypeEntryPtr &enumEntry, + QString flagName, const QVersionNumber &since, + QXmlStreamAttributes *); + + NamespaceTypeEntryPtr + parseNamespaceTypeEntry(const ConditionalStreamReader &, + const QString &name, const QVersionNumber &since, + QXmlStreamAttributes *attributes); + + ValueTypeEntryPtr + parseValueTypeEntry(const ConditionalStreamReader &, const QString &name, + const QVersionNumber &since, QXmlStreamAttributes *); + FunctionTypeEntryPtr + parseFunctionTypeEntry(const ConditionalStreamReader &, const QString &name, + const QVersionNumber &since, QXmlStreamAttributes *); + TypedefEntryPtr + parseTypedefEntry(const ConditionalStreamReader &, const QString &name, + StackElement topElement, + const QVersionNumber &since, QXmlStreamAttributes *); + void applyComplexTypeAttributes(const ConditionalStreamReader &, const ComplexTypeEntryPtr &ctype, + QXmlStreamAttributes *) const; + bool parseConfiguration(StackElement topElement, + QXmlStreamAttributes *attributes); + bool parseRenameFunction(const ConditionalStreamReader &, QString *name, + QXmlStreamAttributes *); + bool parseInjectDocumentation(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool parseModifyDocumentation(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + TypeSystemTypeEntryPtr + parseRootElement(const ConditionalStreamReader &, const QVersionNumber &since, + QXmlStreamAttributes *); + bool loadTypesystem(const ConditionalStreamReader &, QXmlStreamAttributes *); + bool parseRejectEnumValue(const ConditionalStreamReader &, QXmlStreamAttributes *); + bool parseReplaceArgumentType(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool parseCustomConversion(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool parseAddConversion(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool parseNativeToTarget(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *attributes); + bool parseModifyArgument(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *attributes); + bool parseNoNullPointer(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *attributes); + bool parseDefineOwnership(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool parseRename(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool parseModifyField(const ConditionalStreamReader &, QXmlStreamAttributes *); + bool parseAddFunction(const ConditionalStreamReader &, StackElement topElement, + StackElement t, QXmlStreamAttributes *); + bool parseAddPyMethodDef(const ConditionalStreamReader &, + StackElement topElement, QXmlStreamAttributes *attributes); + bool parseProperty(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool parseBasicModifyFunctionAttributes(QXmlStreamAttributes *, + FunctionModification *mod); + bool parseModifyFunctionAttributes(QXmlStreamAttributes *, + FunctionModification *mod); + bool parseModifyFunction(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool parseReplaceDefaultExpression(const ConditionalStreamReader &, + StackElement topElement, QXmlStreamAttributes *); + bool parseReferenceCount(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool parseParentOwner(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + std::optional<Snippet> readFileSnippet(QXmlStreamAttributes *attributes); + bool readCodeSnippet(QXmlStreamAttributes *attributes, CodeSnip *snip); + bool parseInjectCode(const ConditionalStreamReader &, StackElement topElement, QXmlStreamAttributes *); + bool parseInclude(const ConditionalStreamReader &, StackElement topElement, + const TypeEntryPtr &entry, QXmlStreamAttributes *); + bool parseSystemInclude(const ConditionalStreamReader &, QXmlStreamAttributes *); + TemplateInstance + *parseInsertTemplate(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool parseReplace(const ConditionalStreamReader &, StackElement topElement, + QXmlStreamAttributes *); + bool checkDuplicatedTypeEntry(const ConditionalStreamReader &reader, + StackElement t, const QString &name) const; + ParserState parserState(qsizetype offset = 0) const; + CodeSnipAbstract *injectCodeTarget(qsizetype offset = 0) const; + + std::shared_ptr<TypeDatabaseParserContext> m_context; + QStack<StackElement> m_stack; + int m_currentDroppedEntryDepth = 0; + int m_ignoreDepth = 0; + QString m_defaultPackage; + QString m_defaultSuperclass; + TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; + TypeSystem::AllowThread m_allowThread = TypeSystem::AllowThread::Unspecified; + QString m_error; + const TypeEntry::CodeGeneration m_generate; + + EnumTypeEntryPtr m_currentEnum; + TemplateInstancePtr m_templateInstance; + TemplateEntryPtr m_templateEntry; + ContextStack m_contextStack; + + QString m_currentSignature; + QString m_currentPath; + QString m_currentFile; + QScopedPointer<TypeSystemEntityResolver> m_entityResolver; +}; + +#endif // TYPESYSTEMPARSER_H diff --git a/sources/shiboken6/ApiExtractor/typesystemtypeentry.h b/sources/shiboken6/ApiExtractor/typesystemtypeentry.h new file mode 100644 index 000000000..9b9670696 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/typesystemtypeentry.h @@ -0,0 +1,40 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef TYPESYSTEMTYPEENTRY_H +#define TYPESYSTEMTYPEENTRY_H + +#include "typesystem.h" +#include "modifications_typedefs.h" +#include "typesystem_enums.h" +#include "typesystem_typedefs.h" + +class TypeSystemTypeEntry : public TypeEntry +{ +public: + explicit TypeSystemTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + TypeEntry *clone() const override; + + TypeSystem::SnakeCase snakeCase() const; + void setSnakeCase(TypeSystem::SnakeCase sc); + + const CodeSnipList &codeSnips() const; + CodeSnipList &codeSnips(); + void addCodeSnip(const CodeSnip &codeSnip); + + QString subModuleOf() const; + void setSubModule(const QString &); + + const QString &namespaceBegin() const; + void setNamespaceBegin(const QString &n); + + const QString &namespaceEnd() const; + void setNamespaceEnd(const QString &n); + +protected: + explicit TypeSystemTypeEntry(TypeEntryPrivate *d); +}; + +#endif // TYPESYSTEMTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/usingmember.h b/sources/shiboken6/ApiExtractor/usingmember.h index e3354f16d..346eab13c 100644 --- a/sources/shiboken6/ApiExtractor/usingmember.h +++ b/sources/shiboken6/ApiExtractor/usingmember.h @@ -1,43 +1,18 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef USINGMEMBER_H #define USINGMEMBER_H #include "abstractmetalang_typedefs.h" -#include "parser/codemodel.h" +#include "parser/codemodel_enums.h" QT_FORWARD_DECLARE_CLASS(QDebug) struct UsingMember // Introducing a base class member via 'using' directive { QString memberName; - const AbstractMetaClass *baseClass; + AbstractMetaClassCPtr baseClass; Access access; }; diff --git a/sources/shiboken6/ApiExtractor/valuetypeentry.h b/sources/shiboken6/ApiExtractor/valuetypeentry.h new file mode 100644 index 000000000..97bc26803 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/valuetypeentry.h @@ -0,0 +1,40 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef VALUETYPEENTRY_H +#define VALUETYPEENTRY_H + +#include "complextypeentry.h" +#include "customconversion_typedefs.h" + +class ValueTypeEntry : public ComplexTypeEntry +{ +public: + explicit ValueTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + + bool hasCustomConversion() const; + void setCustomConversion(const CustomConversionPtr &customConversion); + CustomConversionPtr customConversion() const; + + // FIXME PYSIDE7: Remove + /// Set the target type conversion rule + void setTargetConversionRule(const QString &conversionRule); + + /// Returns the target type conversion rule + QString targetConversionRule() const; + + /// TODO-CONVERTER: mark as deprecated + bool hasTargetConversionRule() const; + + bool isValue() const override; + + TypeEntry *clone() const override; + +protected: + explicit ValueTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, + const TypeEntryCPtr &parent); + explicit ValueTypeEntry(ComplexTypeEntryPrivate *d); +}; + +#endif // VALUETYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/varargstypeentry.h b/sources/shiboken6/ApiExtractor/varargstypeentry.h new file mode 100644 index 000000000..b2a4f4d30 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/varargstypeentry.h @@ -0,0 +1,20 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef VARARGSTYPEENTRY_H +#define VARARGSTYPEENTRY_H + +#include "typesystem.h" + +class VarargsTypeEntry : public TypeEntry +{ +public: + VarargsTypeEntry(); + + TypeEntry *clone() const override; + +protected: + explicit VarargsTypeEntry(TypeEntryPrivate *d); +}; + +#endif // VARARGSTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/voidtypeentry.h b/sources/shiboken6/ApiExtractor/voidtypeentry.h new file mode 100644 index 000000000..372c7c01f --- /dev/null +++ b/sources/shiboken6/ApiExtractor/voidtypeentry.h @@ -0,0 +1,20 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef VOIDTYPEENTRY_H +#define VOIDTYPEENTRY_H + +#include "typesystem.h" + +class VoidTypeEntry : public TypeEntry +{ +public: + VoidTypeEntry(); + + TypeEntry *clone() const override; + +protected: + explicit VoidTypeEntry(TypeEntryPrivate *d); +}; + +#endif // VOIDTYPEENTRY_H diff --git a/sources/shiboken6/ApiExtractor/xmlutils.cpp b/sources/shiboken6/ApiExtractor/xmlutils.cpp index 6edca2fa5..ccacd4ce7 100644 --- a/sources/shiboken6/ApiExtractor/xmlutils.cpp +++ b/sources/shiboken6/ApiExtractor/xmlutils.cpp @@ -1,35 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "xmlutils.h" #include "xmlutils_libxslt.h" +#include "qtcompat.h" + +using namespace Qt::StringLiterals; + XQuery::XQuery() = default; XQuery::~XQuery() = default; @@ -37,18 +16,18 @@ XQuery::~XQuery() = default; QString XQuery::evaluate(QString xPathExpression, QString *errorMessage) { // XQuery can't have invalid XML characters - xPathExpression.replace(QLatin1Char('&'), QLatin1String("&")); - xPathExpression.replace(QLatin1Char('<'), QLatin1String("<")); + xPathExpression.replace(u'&', u"&"_s); + xPathExpression.replace(u'<', u"<"_s); return doEvaluate(xPathExpression, errorMessage); } -QSharedPointer<XQuery> XQuery::create(const QString &focus, QString *errorMessage) +std::shared_ptr<XQuery> XQuery::create(const QString &focus, QString *errorMessage) { #if defined(HAVE_LIBXSLT) return libXml_createXQuery(focus, errorMessage); #else - *errorMessage = QLatin1String(__FUNCTION__) + QLatin1String(" is not implemented."); - return QSharedPointer<XQuery>(); + *errorMessage = QLatin1StringView(__FUNCTION__) + u" is not implemented."_s; + return std::shared_ptr<XQuery>(); #endif } @@ -57,7 +36,7 @@ QString xsl_transform(const QString &xml, const QString &xsl, QString *errorMess #if defined(HAVE_LIBXSLT) return libXslt_transform(xml, xsl, errorMessage); #else - *errorMessage = QLatin1String(__FUNCTION__) + QLatin1String(" is not implemented."); + *errorMessage = QLatin1StringView(__FUNCTION__) + u" is not implemented."_s; return xml; #endif } diff --git a/sources/shiboken6/ApiExtractor/xmlutils.h b/sources/shiboken6/ApiExtractor/xmlutils.h index 879b7757a..ac23c9c9c 100644 --- a/sources/shiboken6/ApiExtractor/xmlutils.h +++ b/sources/shiboken6/ApiExtractor/xmlutils.h @@ -1,46 +1,22 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef XMLUTILS_H #define XMLUTILS_H -#include <QtCore/QSharedPointer> #include <QtCore/QString> +#include <memory> + class XQuery { public: - Q_DISABLE_COPY(XQuery); + Q_DISABLE_COPY_MOVE(XQuery) virtual ~XQuery(); QString evaluate(QString xPathExpression, QString *errorMessage); - static QSharedPointer<XQuery> create(const QString &focus, QString *errorMessage); + static std::shared_ptr<XQuery> create(const QString &focus, QString *errorMessage); protected: XQuery(); diff --git a/sources/shiboken6/ApiExtractor/xmlutils_libxslt.cpp b/sources/shiboken6/ApiExtractor/xmlutils_libxslt.cpp index e1e185130..5a9a26913 100644 --- a/sources/shiboken6/ApiExtractor/xmlutils_libxslt.cpp +++ b/sources/shiboken6/ApiExtractor/xmlutils_libxslt.cpp @@ -1,34 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "xmlutils_libxslt.h" #include "xmlutils.h" +#include "qtcompat.h" + #include <QtCore/QByteArray> #include <QtCore/QCoreApplication> #include <QtCore/QDir> @@ -44,6 +21,8 @@ #include <cstdlib> #include <memory> +using namespace Qt::StringLiterals; + static void cleanup() { xsltCleanupGlobals(); @@ -61,8 +40,6 @@ static void ensureInitialized() } } -namespace { - // RAI Helpers for cleaning up libxml2/libxslt data struct XmlDocDeleter // for std::unique_ptr<xmlDoc> @@ -85,8 +62,6 @@ struct XmlXPathContextDeleter void operator()(xmlXPathContextPtr xPathContext) { xmlXPathFreeContext(xPathContext); } }; -} // namespace - using XmlDocUniquePtr = std::unique_ptr<xmlDoc, XmlDocDeleter>; using XmlPathObjectUniquePtr = std::unique_ptr<xmlXPathObject, XmlXPathObjectDeleter>; using XmlStyleSheetUniquePtr = std::unique_ptr<xsltStylesheet, XmlStyleSheetDeleter>; @@ -109,13 +84,13 @@ static QByteArray formatNode(xmlNodePtr node, QString *errorMessage) xmlSaveToIO(qbXmlOutputWriteCallback, qbXmlOutputCloseCallback, &result, "UTF-8", 0); if (!saveContext) { - *errorMessage = QLatin1String("xmlSaveToIO() failed."); + *errorMessage = u"xmlSaveToIO() failed."_s; return result; } const long saveResult = xmlSaveTree(saveContext, node); xmlSaveClose(saveContext); if (saveResult < 0) - *errorMessage = QLatin1String("xmlSaveTree() failed."); + *errorMessage = u"xmlSaveTree() failed."_s; return result; } @@ -144,8 +119,8 @@ QString LibXmlXQuery::doEvaluate(const QString &xPathExpression, QString *errorM XmlPathObjectUniquePtr xPathObject(xmlXPathEvalExpression(xPathExpressionX, m_xpathContext.get())); if (!xPathObject) { - *errorMessage = QLatin1String("xmlXPathEvalExpression() failed for \"") + xPathExpression - + QLatin1Char('"'); + *errorMessage = u"xmlXPathEvalExpression() failed for \""_s + xPathExpression + + u'"'; return QString(); } QString result; @@ -162,39 +137,42 @@ QString LibXmlXQuery::doEvaluate(const QString &xPathExpression, QString *errorM return result; } -QSharedPointer<XQuery> libXml_createXQuery(const QString &focus, QString *errorMessage) +std::shared_ptr<XQuery> libXml_createXQuery(const QString &focus, QString *errorMessage) { - XmlDocUniquePtr doc(xmlParseFile(QFile::encodeName(focus).constData())); + XmlDocUniquePtr doc(xmlReadFile(QFile::encodeName(focus).constData(), + "utf-8", XML_PARSE_NOENT)); if (!doc) { - *errorMessage = QLatin1String("libxml2: Cannot set focus to ") + QDir::toNativeSeparators(focus); + *errorMessage = u"libxml2: Cannot set focus to "_s + QDir::toNativeSeparators(focus); return {}; } XmlXPathContextUniquePtr xpathContext(xmlXPathNewContext(doc.get())); if (!xpathContext) { - *errorMessage = QLatin1String("libxml2: xmlXPathNewContext() failed"); + *errorMessage = u"libxml2: xmlXPathNewContext() failed"_s; return {}; } - return QSharedPointer<XQuery>(new LibXmlXQuery(doc, xpathContext)); + return std::shared_ptr<XQuery>(new LibXmlXQuery(doc, xpathContext)); } // XSLT transformation -static const char xsltPrefix[] = R"(<?xml version="1.0" encoding="UTF-8" ?> +static constexpr auto xsltPrefix = R"(<?xml version="1.0" encoding="UTF-8" ?> <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> -)"; +)"_L1; QString libXslt_transform(const QString &xml, QString xsl, QString *errorMessage) { ensureInitialized(); // Read XML data - if (!xsl.startsWith(QLatin1String("<?xml"))) { - xsl.prepend(QLatin1String(xsltPrefix)); - xsl.append(QLatin1String("</xsl:transform>")); + if (!xsl.startsWith(u"<?xml")) { + xsl.prepend(xsltPrefix); + xsl.append(u"</xsl:transform>"_s); } const QByteArray xmlData = xml.toUtf8(); - XmlDocUniquePtr xmlDoc(xmlParseMemory(xmlData.constData(), xmlData.size())); + + XmlDocUniquePtr xmlDoc(xmlReadMemory(xmlData.constData(), int(xmlData.size()), + "", "utf-8", XML_PARSE_NOENT)); if (!xmlDoc) { - *errorMessage = QLatin1String("xmlParseMemory() failed for XML."); + *errorMessage = u"xmlParseMemory() failed for XML."_s; return xml; } @@ -203,15 +181,14 @@ QString libXslt_transform(const QString &xml, QString xsl, QString *errorMessage // xsltFreeStylesheet will delete this pointer xmlDocPtr xslDoc = xmlParseMemory(xslData.constData(), xslData.size()); if (!xslDoc) { - *errorMessage = QLatin1String("xmlParseMemory() failed for XSL \"") - + xsl + QLatin1String("\"."); + *errorMessage = u"xmlParseMemory() failed for XSL \""_s + xsl + u"\"."_s; return xml; }; // Parse XSL data XmlStyleSheetUniquePtr xslt(xsltParseStylesheetDoc(xslDoc)); if (!xslt) { - *errorMessage = QLatin1String("xsltParseStylesheetDoc() failed."); + *errorMessage = u"xsltParseStylesheetDoc() failed."_s; return xml; } @@ -224,7 +201,7 @@ QString libXslt_transform(const QString &xml, QString xsl, QString *errorMessage result = QString::fromUtf8(reinterpret_cast<char*>(buffer), bufferSize); std::free(buffer); } else { - *errorMessage = QLatin1String("xsltSaveResultToString() failed."); + *errorMessage = u"xsltSaveResultToString() failed."_s; result = xml; } return result.trimmed(); diff --git a/sources/shiboken6/ApiExtractor/xmlutils_libxslt.h b/sources/shiboken6/ApiExtractor/xmlutils_libxslt.h index c32b3901d..0dd8eafcb 100644 --- a/sources/shiboken6/ApiExtractor/xmlutils_libxslt.h +++ b/sources/shiboken6/ApiExtractor/xmlutils_libxslt.h @@ -1,39 +1,15 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef XMLUTILS_LIBXSLT_H #define XMLUTILS_LIBXSLT_H #include <QtCore/QString> -#include <QtCore/QSharedPointer> + +#include <memory> class XQuery; -QSharedPointer<XQuery> libXml_createXQuery(const QString &focus, QString *errorMessage); +std::shared_ptr<XQuery> libXml_createXQuery(const QString &focus, QString *errorMessage); QString libXslt_transform(const QString &xml, QString xsl, QString *errorMessage); diff --git a/sources/shiboken6/ApiExtractor/xmlutils_qt.h b/sources/shiboken6/ApiExtractor/xmlutils_qt.h index a9c9adfa2..274827044 100644 --- a/sources/shiboken6/ApiExtractor/xmlutils_qt.h +++ b/sources/shiboken6/ApiExtractor/xmlutils_qt.h @@ -1,39 +1,15 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef XMLUTILS_QT_H #define XMLUTILS_QT_H #include <QtCore/QString> -#include <QtCore/QSharedPointer> + +#include <memory> class XQuery; -QSharedPointer<XQuery> qt_createXQuery(const QString &focus, QString *errorMessage); +std::shared_ptr<XQuery> qt_createXQuery(const QString &focus, QString *errorMessage); QString qt_xsl_transform(const QString &xml, QString xsl, QString *errorMessage); |