diff options
Diffstat (limited to 'sources/shiboken2')
38 files changed, 843 insertions, 902 deletions
diff --git a/sources/shiboken2/ApiExtractor/CMakeLists.txt b/sources/shiboken2/ApiExtractor/CMakeLists.txt index a3301a068..b67a352f0 100644 --- a/sources/shiboken2/ApiExtractor/CMakeLists.txt +++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt @@ -31,13 +31,6 @@ add_definitions(-DQT_PLUGIN) add_definitions(-DQT_SHARED) add_definitions(-DRXX_ALLOCATOR_INIT_0) -# Pass the path to the clang includes dir, so it headers like stdarg.h. -if(UNIX AND NOT APPLE) - add_definitions(-DCLANG_BUILTIN_INCLUDES_DIR="${CLANG_BUILTIN_INCLUDES_DIR}") -else() - add_definitions(-DCLANG_BUILTIN_INCLUDES_DIR="") -endif() - set(apiextractor_SRC apiextractor.cpp abstractmetabuilder.cpp diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index d76c788ec..c879727c3 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -32,6 +32,7 @@ #include <clangparser/clangbuilder.h> #include <clangparser/clangutils.h> +#include <clangparser/compilersupport.h> #include "parser/codemodel.h" @@ -158,18 +159,18 @@ AbstractMetaEnumList AbstractMetaBuilder::globalEnums() const return d->m_globalEnums; } -QSet<QString> AbstractMetaBuilder::qtMetaTypeDeclaredTypeNames() const -{ - return d->m_qmetatypeDeclaredTypenames; -} - -static QString msgNoFunctionForModification(const QString &signature, const QString &className, +static QString msgNoFunctionForModification(const QString &signature, + const QString &originalSignature, + const QString &className, const QStringList &possibleSignatures, const AbstractMetaFunctionList &allFunctions) { QString result; QTextStream str(&result); - str << "signature '" << signature << "' for function modification in '" + str << "signature '" << signature << '\''; + if (!originalSignature.isEmpty() && originalSignature != signature) + str << " (specified as '" << originalSignature << "')"; + str << " for function modification in '" << className << "' not found."; if (possibleSignatures.isEmpty()) { str << " No candidates were found. Member functions: "; @@ -231,7 +232,9 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() if (!found) { qCWarning(lcShiboken).noquote().nospace() - << msgNoFunctionForModification(signature, clazz->qualifiedCppName(), + << msgNoFunctionForModification(signature, + modification.originalSignature(), + clazz->qualifiedCppName(), possibleSignatures, functions); } } @@ -436,10 +439,15 @@ void AbstractMetaBuilderPrivate::sortLists() cls->sortFunctions(); } -FileModelItem AbstractMetaBuilderPrivate::buildDom(const QByteArrayList &arguments, +FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments, + LanguageLevel level, unsigned clangFlags) { clang::Builder builder; + if (level == LanguageLevel::Default) + level = clang::emulatedCompilerLanguageLevel(); + arguments.prepend(QByteArrayLiteral("-std=") + + clang::languageLevelOption(level)); FileModelItem result = clang::parse(arguments, clangFlags, builder) ? builder.dom() : FileModelItem(); const clang::BaseVisitor::Diagnostics &diagnostics = builder.diagnostics(); @@ -708,6 +716,10 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) const AddedFunctionList &globalUserFunctions = types->globalUserFunctions(); for (const AddedFunction &addedFunc : globalUserFunctions) { AbstractMetaFunction* metaFunc = traverseFunction(addedFunc); + if (Q_UNLIKELY(!metaFunc)) { + qFatal("Unable to traverse added global function \"%s\".", + qPrintable(addedFunc.name())); + } metaFunc->setFunctionType(AbstractMetaFunction::NormalFunction); m_globalFunctions << metaFunc; } @@ -715,9 +727,11 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) std::puts(""); } -bool AbstractMetaBuilder::build(const QByteArrayList &arguments, unsigned clangFlags) +bool AbstractMetaBuilder::build(const QByteArrayList &arguments, + LanguageLevel level, + unsigned clangFlags) { - const FileModelItem dom = d->buildDom(arguments, clangFlags); + const FileModelItem dom = d->buildDom(arguments, level, clangFlags); if (dom.isNull()) return false; if (ReportHandler::isDebug(ReportHandler::MediumDebug)) @@ -1027,16 +1041,6 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem ComplexTypeEntry* type = TypeDatabase::instance()->findComplexType(fullClassName); AbstractMetaBuilder::RejectReason reason = AbstractMetaBuilder::NoReason; - if (fullClassName == QLatin1String("QMetaTypeId")) { - // QtScript: record which types have been declared - int lpos = classItem->name().indexOf(QLatin1Char('<')); - int rpos = classItem->name().lastIndexOf(QLatin1Char('>')); - if ((lpos != -1) && (rpos != -1)) { - QString declaredTypename = classItem->name().mid(lpos + 1, rpos - lpos - 1); - m_qmetatypeDeclaredTypenames.insert(declaredTypename); - } - } - if (TypeDatabase::instance()->isClassRejected(fullClassName)) { reason = AbstractMetaBuilder::GenerationDisabled; } else if (!type) { @@ -1352,45 +1356,6 @@ static bool _compareAbstractMetaFunctions(const AbstractMetaFunction* func, cons return true; } -// Fix the arguments of template classes that take the class itself, for example: -// "QList(const QList &)" to "QList(const QList<T> &)". -static bool _fixFunctionModelItemTypes(FunctionModelItem& function, const AbstractMetaClass* metaClass) -{ - const QVector<TypeEntry *> &templateTypes = metaClass->templateArguments(); - if (templateTypes.isEmpty()) - return false; - - const QStringList classType = metaClass->typeEntry()->qualifiedCppName().split(colonColon()); - QStringList fixedClassType = classType; - fixedClassType.last().append(QLatin1Char('<')); - for (int i = 0, count = templateTypes.size(); i < count; ++i) { - if (i) - fixedClassType.last().append(QLatin1String(", ")); - fixedClassType.last().append(templateTypes.at(i)->qualifiedCppName()); - } - fixedClassType.last().append(QLatin1String(" >")); - - bool templateTypeFixed = false; - TypeInfo functionType = function->type(); - if (functionType.qualifiedName() == classType) { - templateTypeFixed = true; - functionType.setQualifiedName(fixedClassType); - function->setType(functionType); - } - - ArgumentList arguments = function->arguments(); - for (int i = 0; i < arguments.size(); ++i) { - ArgumentModelItem arg = arguments.at(i); - TypeInfo type = arg->type(); - if (type.qualifiedName() == classType) { - type.setQualifiedName(fixedClassType); - arg->setType(type); - templateTypeFixed = true; - } - } - return templateTypeFixed; -} - AbstractMetaFunctionList AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem, bool *constructorRejected) { @@ -1430,49 +1395,12 @@ private: const AbstractMetaFunction *m_function; }; -AbstractMetaFunctionList AbstractMetaBuilderPrivate::templateClassFunctionList(const ScopeModelItem &scopeItem, - AbstractMetaClass *metaClass, - bool *constructorRejected) -{ - AbstractMetaFunctionList result; - AbstractMetaFunctionList unchangedFunctions; - - *constructorRejected = false; - const FunctionList &scopeFunctionList = scopeItem->functions(); - result.reserve(scopeFunctionList.size()); - unchangedFunctions.reserve(scopeFunctionList.size()); - for (FunctionModelItem function : scopeFunctionList) { - // This fixes method's arguments and return types that are templates - // but the template variable wasn't declared in the C++ header. - const bool templateTypeFixed =_fixFunctionModelItemTypes(function, metaClass); - if (AbstractMetaFunction *metaFunction = traverseFunction(function)) { - result.append(metaFunction); - if (!templateTypeFixed) - unchangedFunctions.append(metaFunction); - } else if (function->functionType() == CodeModel::Constructor) { - *constructorRejected = true; - } - } - - const AbstractMetaFunctionList::ConstIterator unchangedBegin = unchangedFunctions.cbegin(); - const AbstractMetaFunctionList::ConstIterator unchangedEnd = unchangedFunctions.cend(); - for (int i = result.size() - 1; i >= 0; --i) { - AbstractMetaFunction *function = result.at(i); - if (!unchangedFunctions.contains(function) - && unchangedEnd != std::find_if(unchangedBegin, unchangedEnd, DuplicatingFunctionPredicate(function))) { - delete result.takeAt(i); - } - } - return result; -} - void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, AbstractMetaClass *metaClass) { bool constructorRejected = false; - const AbstractMetaFunctionList functions = metaClass->templateArguments().isEmpty() - ? classFunctionList(scopeItem, &constructorRejected) - : templateClassFunctionList(scopeItem, metaClass, &constructorRejected); + const AbstractMetaFunctionList functions = + classFunctionList(scopeItem, &constructorRejected); if (constructorRejected) *metaClass += AbstractMetaAttributes::HasRejectedConstructor; @@ -1564,8 +1492,12 @@ void AbstractMetaBuilderPrivate::fillAddedFunctions(AbstractMetaClass *metaClass { // Add the functions added by the typesystem const AddedFunctionList &addedFunctions = metaClass->typeEntry()->addedFunctions(); - for (const AddedFunction &addedFunc : addedFunctions) - traverseFunction(addedFunc, metaClass); + for (const AddedFunction &addedFunc : addedFunctions) { + if (!traverseFunction(addedFunc, metaClass)) { + qFatal("Unable to traverse function \"%s\" added to \"%s\".", + qPrintable(addedFunc.name()), qPrintable(metaClass->name())); + } + } } void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction *func) @@ -1612,7 +1544,7 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) // we only support our own containers and ONLY if there is only one baseclass if (baseClasses.size() == 1 && baseClasses.constFirst().contains(QLatin1Char('<'))) { - TypeParser::Info info; + TypeInfo info; ComplexTypeEntry* baseContainerType; AbstractMetaClass* templ = findTemplateClass(baseClasses.constFirst(), metaClass, &info, &baseContainerType); if (templ) { @@ -1746,6 +1678,13 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu AddedFunction::TypeInfo& typeInfo = args[i]; AbstractMetaArgument *metaArg = new AbstractMetaArgument; AbstractMetaType *type = translateType(typeInfo); + if (Q_UNLIKELY(!type)) { + qCWarning(lcShiboken, + "Unable to translate type \"%s\" of argument %d of added function \"%s\".", + qPrintable(typeInfo.name), i + 1, qPrintable(addedFunc.name())); + delete metaFunction; + return nullptr; + } type->decideUsagePattern(); metaArg->setType(type); metaArg->setArgumentIndex(i); @@ -2343,8 +2282,8 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ return nullptr; QString errorMessage; - TypeParser::Info typeInfo = TypeParser::parse(typei.toString(), &errorMessage); - if (typeInfo.is_busted) { + TypeInfo typeInfo = TypeParser::parse(typei.toString(), &errorMessage); + if (typeInfo.qualifiedName().isEmpty()) { qWarning().noquote().nospace() << "Unable to translate type \"" << _typei.toString() << "\": " << errorMessage; return 0; @@ -2354,43 +2293,43 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ // 2.1 Handle char arrays with unspecified size (aka "const char[]") as "const char*" with // NativePointerPattern usage. bool oneDimensionalArrayOfUnspecifiedSize = - typeInfo.arrays.size() == 1 - && typeInfo.arrays[0].isEmpty(); + typeInfo.arrayElements().size() == 1 + && typeInfo.arrayElements().at(0).isEmpty(); bool isConstCharStarCase = oneDimensionalArrayOfUnspecifiedSize - && typeInfo.qualified_name.size() == 1 - && typeInfo.qualified_name[0] == QStringLiteral("char") - && typeInfo.indirections == 0 - && typeInfo.is_constant == 1 - && typeInfo.is_busted == 0 - && typeInfo.referenceType == NoReference - && typeInfo.template_instantiations.size() == 0; + && typeInfo.qualifiedName().size() == 1 + && typeInfo.qualifiedName().at(0) == QStringLiteral("char") + && typeInfo.indirections() == 0 + && typeInfo.isConstant() + && typeInfo.referenceType() == NoReference + && typeInfo.arguments().isEmpty(); if (isConstCharStarCase) - typeInfo.indirections += typeInfo.arrays.size(); + typeInfo.setIndirections(typeInfo.indirections() + typeInfo.arrayElements().size()); // 2.2 Handle regular arrays. - if (typeInfo.arrays.size() > 0 && !isConstCharStarCase) { + if (!typeInfo.arrayElements().isEmpty() && !isConstCharStarCase) { TypeInfo newInfo; - //newInfo.setArguments(typei.arguments()); - newInfo.setIndirections(typei.indirections()); - newInfo.setConstant(typei.isConstant()); - newInfo.setFunctionPointer(typei.isFunctionPointer()); - newInfo.setQualifiedName(typei.qualifiedName()); - newInfo.setReferenceType(typei.referenceType()); - newInfo.setVolatile(typei.isVolatile()); + //newInfo.setArguments(typeInfo.arguments()); + newInfo.setIndirections(typeInfo.indirections()); + newInfo.setConstant(typeInfo.isConstant()); + newInfo.setFunctionPointer(typeInfo.isFunctionPointer()); + newInfo.setQualifiedName(typeInfo.qualifiedName()); + newInfo.setReferenceType(typeInfo.referenceType()); + newInfo.setVolatile(typeInfo.isVolatile()); AbstractMetaType *elementType = translateType(newInfo); if (!elementType) return nullptr; - for (int i = typeInfo.arrays.size() - 1; i >= 0; --i) { + for (int i = typeInfo.arrayElements().size() - 1; i >= 0; --i) { AbstractMetaType *arrayType = new AbstractMetaType; arrayType->setArrayElementType(elementType); - if (!typeInfo.arrays.at(i).isEmpty()) { + const QString &arrayElement = typeInfo.arrayElements().at(i); + if (!arrayElement.isEmpty()) { bool _ok; - const qint64 elems = findOutValueFromString(typeInfo.arrays.at(i), _ok); + const qint64 elems = findOutValueFromString(arrayElement, _ok); if (_ok) arrayType->setArrayElementCount(int(elems)); } @@ -2403,7 +2342,7 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ return elementType; } - QStringList qualifierList = typeInfo.qualified_name; + QStringList qualifierList = typeInfo.qualifiedName(); if (qualifierList.isEmpty()) { qCWarning(lcShiboken).noquote().nospace() << QStringLiteral("horribly broken type '%1'").arg(_typei.toString()); @@ -2468,21 +2407,16 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ AbstractMetaType *metaType = new AbstractMetaType; metaType->setTypeEntry(type); - metaType->setIndirections(typeInfo.indirections); - metaType->setReferenceType(typeInfo.referenceType); - metaType->setConstant(typeInfo.is_constant); + metaType->setIndirections(typeInfo.indirections()); + metaType->setReferenceType(typeInfo.referenceType()); + metaType->setConstant(typeInfo.isConstant()); metaType->setOriginalTypeDescription(_typei.toString()); - for (const TypeParser::Info &ta : qAsConst(typeInfo.template_instantiations)) { - TypeInfo info; - info.setConstant(ta.is_constant); - info.setReferenceType(ta.referenceType); - info.setIndirections(ta.indirections); - - info.setFunctionPointer(false); - info.setQualifiedName(ta.instantiationName().split(colonColon())); - - AbstractMetaType *targType = translateType(info); + const auto &templateArguments = typeInfo.arguments(); + for (int t = 0, size = templateArguments.size(); t < size; ++t) { + TypeInfo ti = templateArguments.at(t); + ti.setQualifiedName(ti.instantiationName()); + AbstractMetaType *targType = translateType(ti); if (!targType) { delete metaType; return nullptr; @@ -2671,13 +2605,9 @@ bool AbstractMetaBuilderPrivate::isEnum(const FileModelItem &dom, const QStringL AbstractMetaClass* AbstractMetaBuilderPrivate::findTemplateClass(const QString &name, const AbstractMetaClass *context, - TypeParser::Info *info, + TypeInfo *info, ComplexTypeEntry **baseContainerType) const { - TypeParser::Info localInfo; - if (!info) - info = &localInfo; - TypeDatabase* types = TypeDatabase::instance(); QStringList scope = context->typeEntry()->qualifiedCppName().split(colonColon()); @@ -2686,14 +2616,15 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::findTemplateClass(const QString & for (int i = scope.size(); i >= 0; --i) { QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(colonColon()) + colonColon() : QString(); QString completeName = prefix + name; - const TypeParser::Info parsed = TypeParser::parse(completeName, &errorMessage); - if (parsed.is_busted) { + const TypeInfo parsed = TypeParser::parse(completeName, &errorMessage); + QString qualifiedName = parsed.qualifiedName().join(colonColon()); + if (qualifiedName.isEmpty()) { qWarning().noquote().nospace() << "Unable to parse type \"" << completeName << "\" while looking for template \"" << name << "\": " << errorMessage; continue; } - *info = parsed; - QString qualifiedName = info->qualified_name.join(colonColon()); + if (info) + *info = parsed; AbstractMetaClass* templ = 0; for (AbstractMetaClass *c : qAsConst(m_templates)) { @@ -2795,9 +2726,9 @@ AbstractMetaType* AbstractMetaBuilderPrivate::inheritTemplateType(const QVector< bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, const AbstractMetaClass *templateClass, - const TypeParser::Info &info) + const TypeInfo &info) { - QVector<TypeParser::Info> targs = info.template_instantiations; + QVector<TypeInfo> targs = info.arguments(); QVector<AbstractMetaType *> templateTypes; if (subclass->isTypeDef()) { @@ -2810,8 +2741,8 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, subclass->setHasVirtualDestructor(templateClass->hasVirtualDestructor()); } - for (const TypeParser::Info &i : qAsConst(targs)) { - QString typeName = i.qualified_name.join(colonColon()); + for (const TypeInfo &i : qAsConst(targs)) { + QString typeName = i.qualifiedName().join(colonColon()); QStringList possibleNames; possibleNames << subclass->qualifiedCppName() + colonColon() + typeName; possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName; @@ -2831,9 +2762,9 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, if (t) { AbstractMetaType *temporaryType = new AbstractMetaType; temporaryType->setTypeEntry(t); - temporaryType->setConstant(i.is_constant); - temporaryType->setReferenceType(i.referenceType); - temporaryType->setIndirections(i.indirections); + temporaryType->setConstant(i.isConstant()); + temporaryType->setReferenceType(i.referenceType()); + temporaryType->setIndirections(i.indirections()); temporaryType->decideUsagePattern(); templateTypes << temporaryType; } else { @@ -3285,7 +3216,6 @@ static void debugFormatSequence(QDebug &d, const char *key, const Container& c, void AbstractMetaBuilder::formatDebug(QDebug &debug) const { debug << "m_globalHeader=" << d->m_globalHeader.absoluteFilePath(); - debugFormatSequence(debug, "qtMetaTypeDeclaredTypeNames", d->m_qmetatypeDeclaredTypenames); debugFormatSequence(debug, "globalEnums", d->m_globalEnums, "\n"); debugFormatSequence(debug, "globalFunctions", d->m_globalFunctions, "\n"); if (const int scopeCount = d->m_scopes.size()) { diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h index bd1236375..a0ca71b94 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h @@ -32,6 +32,8 @@ #include "abstractmetalang_typedefs.h" #include "dependency.h" +#include "clangparser/compilersupport.h" + QT_FORWARD_DECLARE_CLASS(QIODevice) class AbstractMetaBuilderPrivate; @@ -59,8 +61,6 @@ public: AbstractMetaClassList smartPointers() const; AbstractMetaFunctionList globalFunctions() const; AbstractMetaEnumList globalEnums() const; - // QtScript - QSet<QString> qtMetaTypeDeclaredTypeNames() const; /** * Sorts a list of classes topologically, if an AbstractMetaClass object @@ -71,7 +71,9 @@ public: AbstractMetaClassList classesTopologicalSorted(const AbstractMetaClass *cppClass = Q_NULLPTR, const Dependencies &additionalDependencies = Dependencies()) const; - bool build(const QByteArrayList &arguments, unsigned clangFlags = 0); + bool build(const QByteArrayList &arguments, + LanguageLevel level = LanguageLevel::Default, + unsigned clangFlags = 0); void setLogDirectory(const QString& logDir); /** diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h index 959734462..59e3cfc94 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h @@ -46,7 +46,9 @@ public: AbstractMetaBuilderPrivate(); ~AbstractMetaBuilderPrivate(); - static FileModelItem buildDom(const QByteArrayList &arguments, unsigned clangFlags); + static FileModelItem buildDom(QByteArrayList arguments, + LanguageLevel level, + unsigned clangFlags); void traverseDom(const FileModelItem &dom); void dumpLog() const; @@ -122,18 +124,17 @@ public: AbstractMetaType *translateType(const AddedFunction::TypeInfo &typeInfo); AbstractMetaType *translateType(const TypeInfo &type, bool resolveType = true); - qint64 findOutValueFromString(const QString &stringValue, bool &ok); AbstractMetaClass *findTemplateClass(const QString& name, const AbstractMetaClass *context, - TypeParser::Info *info = Q_NULLPTR, + TypeInfo *info = Q_NULLPTR, ComplexTypeEntry **baseContainerType = Q_NULLPTR) const; AbstractMetaClassList getBaseClasses(const AbstractMetaClass *metaClass) const; bool ancestorHasPrivateCopyConstructor(const AbstractMetaClass *metaClass) const; bool inheritTemplate(AbstractMetaClass *subclass, const AbstractMetaClass *templateClass, - const TypeParser::Info &info); + const TypeInfo &info); AbstractMetaType *inheritTemplateType(const QVector<AbstractMetaType *> &templateTypes, const AbstractMetaType *metaType, bool *ok = Q_NULLPTR); @@ -181,9 +182,6 @@ public: QSet<AbstractMetaClass *> m_setupInheritanceDone; - // QtScript - QSet<QString> m_qmetatypeDeclaredTypenames; - QString m_logDirectory; QFileInfo m_globalHeader; }; diff --git a/sources/shiboken2/ApiExtractor/apiextractor.cpp b/sources/shiboken2/ApiExtractor/apiextractor.cpp index 4c4eaff6c..171011cd4 100644 --- a/sources/shiboken2/ApiExtractor/apiextractor.cpp +++ b/sources/shiboken2/ApiExtractor/apiextractor.cpp @@ -159,12 +159,6 @@ ContainerTypeEntryList ApiExtractor::containerTypes() const return TypeDatabase::instance()->containerTypes(); } -QSet<QString> ApiExtractor::qtMetaTypeDeclaredTypeNames() const -{ - Q_ASSERT(m_builder); - return m_builder->qtMetaTypeDeclaredTypeNames(); -} - static const AbstractMetaEnum* findEnumOnClasses(AbstractMetaClassList metaClasses, const EnumTypeEntry* typeEntry) { const AbstractMetaEnum* result = 0; @@ -259,8 +253,9 @@ bool ApiExtractor::run() for (const HeaderPath &headerPath : qAsConst(m_includePaths)) arguments.append(HeaderPath::includeOption(headerPath)); arguments.append(QFile::encodeName(preprocessedCppFileName)); - qCDebug(lcShiboken) << __FUNCTION__ << arguments; - const bool result = m_builder->build(arguments); + qCDebug(lcShiboken) << __FUNCTION__ << arguments + << "level=" << int(m_languageLevel); + const bool result = m_builder->build(arguments, m_languageLevel); if (!result) autoRemove = false; if (!autoRemove) { @@ -270,6 +265,16 @@ bool ApiExtractor::run() return result; } +LanguageLevel ApiExtractor::languageLevel() const +{ + return m_languageLevel; +} + +void ApiExtractor::setLanguageLevel(const LanguageLevel languageLevel) +{ + m_languageLevel = languageLevel; +} + #ifndef QT_NO_DEBUG_STREAM template <class Container> static void debugFormatSequence(QDebug &d, const char *key, const Container& c) diff --git a/sources/shiboken2/ApiExtractor/apiextractor.h b/sources/shiboken2/ApiExtractor/apiextractor.h index 702d3994c..674e5a742 100644 --- a/sources/shiboken2/ApiExtractor/apiextractor.h +++ b/sources/shiboken2/ApiExtractor/apiextractor.h @@ -36,6 +36,7 @@ #include "header_paths.h" #include "typedatabase_typedefs.h" #include "typesystem_typedefs.h" +#include "clangparser/compilersupport.h" #include <QStringList> class AbstractMetaBuilder; @@ -75,6 +76,8 @@ public: void setLogDirectory(const QString& logDir); bool setApiVersion(const QString& package, const QString& version); void setDropTypeEntries(QString dropEntries); + LanguageLevel languageLevel() const; + void setLanguageLevel(const LanguageLevel languageLevel); AbstractMetaEnumList globalEnums() const; AbstractMetaFunctionList globalFunctions() const; @@ -83,7 +86,6 @@ public: AbstractMetaClassList classesTopologicalSorted(const Dependencies &additionalDependencies = Dependencies()) const; PrimitiveTypeEntryList primitiveTypes() const; ContainerTypeEntryList containerTypes() const; - QSet<QString> qtMetaTypeDeclaredTypeNames() const; const AbstractMetaEnum* findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const; const AbstractMetaEnum* findAbstractMetaEnum(const TypeEntry* typeEntry) const; @@ -99,6 +101,7 @@ private: HeaderPaths m_includePaths; AbstractMetaBuilder* m_builder; QString m_logDirectory; + LanguageLevel m_languageLevel = LanguageLevel::Default; // disable copy ApiExtractor(const ApiExtractor&); diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp index a6b6f2af3..5192e9e76 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp @@ -379,6 +379,27 @@ static QStringList parseArrayArgs(const CXType &type, QString *typeName) return result; } +// Create qualified name "std::list<std::string>" -> ("std", "list<std::string>") +static QStringList qualifiedName(const QString &t) +{ + QStringList result; + int end = t.indexOf(QLatin1Char('<')); + if (end == -1) + end = t.indexOf(QLatin1Char('(')); + if (end == -1) + end = t.size(); + int lastPos = 0; + while (true) { + const int nextPos = t.indexOf(colonColon(), lastPos); + if (nextPos < 0 || nextPos >= end) + break; + result.append(t.mid(lastPos, nextPos - lastPos)); + lastPos = nextPos + 2; + } + result.append(t.right(t.size() - lastPos)); + return result; +} + TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const { if (type.kind == CXType_Pointer) { // Check for function pointers, first. @@ -439,7 +460,7 @@ TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const typeName = typeName.trimmed(); - typeInfo.setQualifiedName(typeName.split(colonColon())); + typeInfo.setQualifiedName(qualifiedName(typeName)); // 3320:CINDEX_LINKAGE int clang_getNumArgTypes(CXType T); function ptr types? return typeInfo; } diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp index ddafcdb04..301b4211e 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp @@ -196,11 +196,6 @@ static CXTranslationUnit createTranslationUnit(CXIndex index, | CXTranslationUnit_Incomplete; static const QByteArrayList defaultArgs = { -#if defined(Q_CC_MSVC) && _MSC_VER > 1900 - "-std=c++1z", // Fixes constexpr errors in MSVC2017 library headers with Clang 4.1 -#else - "-std=c++14", // ! otherwise, t.h is parsed as "C" -#endif #ifndef Q_OS_WIN "-fPIC", #endif diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp index 655454898..820909713 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp @@ -29,17 +29,30 @@ #include "compilersupport.h" #include "header_paths.h" +#include <reporthandler.h> + #include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> #include <QtCore/QProcess> +#include <QtCore/QStandardPaths> #include <QtCore/QStringList> #include <QtCore/QVersionNumber> +#include <clang-c/Index.h> + #include <string.h> #include <algorithm> #include <iterator> namespace clang { +QVersionNumber libClangVersion() +{ + return QVersionNumber(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR); +} + static bool runProcess(const QString &program, const QStringList &arguments, QByteArray *stdOutIn = nullptr, QByteArray *stdErrIn = nullptr) { @@ -106,9 +119,9 @@ static HeaderPaths gppInternalIncludePaths(const QString &compiler) if (line.startsWith(QByteArrayLiteral("End of search list"))) { isIncludeDir = false; } else { - HeaderPath headerPath(line.trimmed()); + HeaderPath headerPath{line.trimmed(), HeaderType::System}; if (headerPath.path.endsWith(frameworkPath())) { - headerPath.m_isFramework = true; + headerPath.type = HeaderType::FrameworkSystem; headerPath.path.truncate(headerPath.path.size() - frameworkPath().size()); } result.append(headerPath); @@ -127,7 +140,8 @@ static void detectVulkan(HeaderPaths *headerPaths) static const char *vulkanVariables[] = {"VULKAN_SDK", "VK_SDK_PATH"}; for (const char *vulkanVariable : vulkanVariables) { if (qEnvironmentVariableIsSet(vulkanVariable)) { - headerPaths->append(HeaderPath(qgetenv(vulkanVariable) + QByteArrayLiteral("/include"))); + const QByteArray path = qgetenv(vulkanVariable) + QByteArrayLiteral("/include"); + headerPaths->append(HeaderPath{path, HeaderType::System}); break; } } @@ -154,6 +168,68 @@ static inline bool isRedHat74() 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 +// includes to prevent redefinition errors. The default toolchain includes +// should be picked up automatically by clang without specifying +// them implicitly. + +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) +# define NEED_CLANG_BUILTIN_INCLUDES 1 +#else +# define NEED_CLANG_BUILTIN_INCLUDES 0 +#endif + +#if NEED_CLANG_BUILTIN_INCLUDES +static QString findClang() +{ + for (const char *envVar : {"LLVM_INSTALL_DIR", "CLANG_INSTALL_DIR"}) { + if (qEnvironmentVariableIsSet(envVar)) { + const QString path = QFile::decodeName(qgetenv(envVar)); + if (QFileInfo::exists(path)) + return path; + } + } + const QString llvmConfig = + QStandardPaths::findExecutable(QLatin1String("llvm-config")); + if (!llvmConfig.isEmpty()) { + QByteArray stdOut; + if (runProcess(llvmConfig, QStringList{QLatin1String("--prefix")}, &stdOut)) { + const QString path = QFile::decodeName(stdOut.trimmed()); + if (QFileInfo::exists(path)) + return path; + } + } + return QString(); +} + +static QString findClangBuiltInIncludesDir() +{ + // Find the include directory of the highest version. + const QString clangPath = findClang(); + if (!clangPath.isEmpty()) { + QString candidate; + QVersionNumber lastVersionNumber(1, 0, 0); + QDir clangDir(clangPath + QLatin1String("/lib/clang")); + const QFileInfoList versionDirs = + clangDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QFileInfo &fi : versionDirs) { + const QString fileName = fi.fileName(); + if (fileName.at(0).isDigit()) { + const QVersionNumber versionNumber = QVersionNumber::fromString(fileName.at(0)); + if (!versionNumber.isNull() && versionNumber > lastVersionNumber) { + candidate = fi.absoluteFilePath(); + lastVersionNumber = versionNumber; + } + } + } + if (!candidate.isEmpty()) + return candidate + QStringLiteral("/include"); + } + return QString(); +} +#endif // NEED_CLANG_BUILTIN_INCLUDES + // Returns clang options needed for emulating the host compiler QByteArrayList emulatedCompilerOptions() { @@ -168,16 +244,21 @@ QByteArrayList emulatedCompilerOptions() #elif defined(Q_CC_GNU) HeaderPaths headerPaths; - // The clang builtin includes directory is used to find the definitions for intrinsic functions - // and builtin types. It is necessary to use the clang includes to prevent redefinition errors. - // The default toolchain includes should be picked up automatically by clang without specifying - // them implicitly. - QByteArray clangBuiltinIncludesDir(CLANG_BUILTIN_INCLUDES_DIR); - - if (!clangBuiltinIncludesDir.isEmpty()) { - result.append(QByteArrayLiteral("-isystem")); - result.append(clangBuiltinIncludesDir); +#if NEED_CLANG_BUILTIN_INCLUDES + const QString clangBuiltinIncludesDir = + QDir::toNativeSeparators(findClangBuiltInIncludesDir()); + if (clangBuiltinIncludesDir.isEmpty()) { + qCWarning(lcShiboken, "Unable to locate Clang's built-in include directory " + "(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", + qPrintable(clangBuiltinIncludesDir)); + headerPaths.append(HeaderPath{QFile::encodeName(clangBuiltinIncludesDir), + HeaderType::System}); } +#endif // NEED_CLANG_BUILTIN_INCLUDES + // Append the c++ include paths since Clang is unable to find <list> etc // on RHEL 7.4 with g++ 6.3. 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. @@ -193,10 +274,51 @@ QByteArrayList emulatedCompilerOptions() #endif detectVulkan(&headerPaths); std::transform(headerPaths.cbegin(), headerPaths.cend(), - std::back_inserter(result), [](const HeaderPath &p) { - return HeaderPath::includeOption(p, true); - }); + std::back_inserter(result), HeaderPath::includeOption); return result; } +LanguageLevel emulatedCompilerLanguageLevel() +{ +#if defined(Q_CC_MSVC) && _MSC_VER > 1900 + // Fixes constexpr errors in MSVC2017 library headers with Clang 4.1..5.X (0.45 == Clang 6). + if (libClangVersion() < QVersionNumber(0, 45)) + return LanguageLevel::Cpp1Z; +#endif // Q_CC_MSVC && _MSC_VER > 1900 + return LanguageLevel::Cpp14; // otherwise, t.h is parsed as "C" +} + +struct LanguageLevelMapping +{ + const char *option; + LanguageLevel level; +}; + +static const LanguageLevelMapping languageLevelMapping[] = +{ + {"c++11", LanguageLevel::Cpp11}, + {"c++14", LanguageLevel::Cpp14}, + {"c++17", LanguageLevel::Cpp17}, + {"c++20", LanguageLevel::Cpp20}, + {"c++1z", LanguageLevel::Cpp1Z} +}; + +const char *languageLevelOption(LanguageLevel l) +{ + for (const LanguageLevelMapping &m : languageLevelMapping) { + if (m.level == l) + return m.option; + } + return nullptr; +} + +LanguageLevel languageLevelFromOption(const char *o) +{ + for (const LanguageLevelMapping &m : languageLevelMapping) { + if (!strcmp(m.option, o)) + return m.level; + } + return LanguageLevel::Default; +} + } // namespace clang diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h index 68d09f6f5..d9e213e73 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h +++ b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h @@ -31,10 +31,25 @@ #include <QtCore/QByteArrayList> +QT_FORWARD_DECLARE_CLASS(QVersionNumber) + +enum class LanguageLevel { + Default, + Cpp11, + Cpp14, + Cpp17, + Cpp20, + Cpp1Z +}; + namespace clang { +QVersionNumber libClangVersion(); QByteArrayList emulatedCompilerOptions(); +LanguageLevel emulatedCompilerLanguageLevel(); +const char *languageLevelOption(LanguageLevel l); +LanguageLevel languageLevelFromOption(const char *); } // namespace clang #endif // COMPILERSUPPORT_H diff --git a/sources/shiboken2/ApiExtractor/header_paths.h b/sources/shiboken2/ApiExtractor/header_paths.h index 4681f14de..01d830921 100644 --- a/sources/shiboken2/ApiExtractor/header_paths.h +++ b/sources/shiboken2/ApiExtractor/header_paths.h @@ -33,30 +33,36 @@ #include <QList> #include <QString> +enum class HeaderType +{ + Standard, + System, // -isystem + Framework, // macOS framework path + FrameworkSystem // macOS framework system path +}; + class HeaderPath { public: - explicit HeaderPath(const QByteArray &p = QByteArray()) : path(p), m_isFramework(false) {} - explicit HeaderPath(const QString &s = QString(), bool isFramework = false) : - path(s.toLatin1()), m_isFramework(isFramework) {} - QByteArray path; - bool m_isFramework; // macOS framework path + HeaderType type; - static QByteArray includeOption(const HeaderPath &p, bool systemInclude = false) + static QByteArray includeOption(const HeaderPath &p) { QByteArray option; - - if (p.m_isFramework) { - if (systemInclude) - option = QByteArrayLiteral("-iframework"); - else - option = QByteArrayLiteral("-F"); - } else if (systemInclude) { - option = QByteArrayLiteral("-isystem"); - } else { + switch (p.type) { + case HeaderType::Standard: option = QByteArrayLiteral("-I"); + break; + case HeaderType::System: + option = QByteArrayLiteral("-isystem"); + break; + case HeaderType::Framework: + option = QByteArrayLiteral("-F"); + break; + case HeaderType::FrameworkSystem: + option = QByteArrayLiteral("-iframework"); + break; } - return option + p.path; } }; diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp index 0af4905f4..60a699337 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp @@ -238,6 +238,20 @@ QString TypeInfo::toString() const return tmp; } +QStringList TypeInfo::instantiationName() const +{ + QStringList result = m_qualifiedName; + if (const int argumentCount = m_arguments.size()) { + QString &last = result.last(); + for (int i = 0; i < argumentCount; ++i) { + last += i ? QLatin1String(", ") : QLatin1String("< "); + last += m_arguments.at(i).toString(); + } + last += QLatin1String(" >"); + } + return result; +} + bool TypeInfo::operator==(const TypeInfo &other) const { if (arrayElements().count() != other.arrayElements().count()) diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.h b/sources/shiboken2/ApiExtractor/parser/codemodel.h index d0d7b677c..d93aa10d9 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel.h +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h @@ -98,6 +98,7 @@ QDebug operator<<(QDebug d, const CodeModel *m); class TypeInfo { + friend class TypeParser; public: TypeInfo() : flags(0), m_referenceType(NoReference) {} @@ -184,6 +185,8 @@ public: QString toString() const; + QStringList instantiationName() const; + static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs); static TypeInfo resolveType(TypeInfo const &__type, CodeModelItem __scope); diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp index ea506f3b5..8d869e3f9 100644 --- a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp @@ -35,35 +35,37 @@ void TestTemplates::testTemplateWithNamespace() { - const char cppCode[] = "\n\ - template<typename T> struct QList {}; \n\ - struct Url {\n\ - void name();\n\ - };\n\ - namespace Internet {\n\ - struct Url{};\n\ - struct Bookmarks {\n\ - QList<Url> list();\n\ - };\n\ - }"; - const char xmlCode0[] = "\n\ - <typesystem package='Pakcage.Network'>\n\ - <value-type name='Url'/>\n\ - </typesystem>"; + const char cppCode[] = R"CPP( +template<typename T> struct QList {}; +struct Url { + void name(); +}; +namespace Internet { + struct Url{}; + struct Bookmarks { + QList<Url> list(); + }; +}; +)CPP"; + + const char xmlCode0[] = R"XML( +<typesystem package='Package.Network'> + <value-type name='Url'/> +</typesystem>)XML"; QTemporaryFile file; QVERIFY(file.open()); file.write(xmlCode0); file.close(); - QString xmlCode1 = QString::fromLatin1("\n\ - <typesystem package='Package.Internet'>\n\ - <load-typesystem name='%1' generate='no'/>\n\ - <container-type name='QList' type='list'/>\n\ - <namespace-type name='Internet' generate='no'/>\n\ - <value-type name='Internet::Url'/>\n\ - <value-type name='Internet::Bookmarks'/>\n\ - </typesystem>").arg(file.fileName()); + QString xmlCode1 = QString::fromLatin1(R"XML( +<typesystem package='Package.Internet'> + <load-typesystem name='%1' generate='no'/> + <container-type name='QList' type='list'/> + <namespace-type name='Internet' generate='no'/> + <value-type name='Internet::Url'/> + <value-type name='Internet::Bookmarks'/> +</typesystem>)XML").arg(file.fileName()); QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, qPrintable(xmlCode1), false)); QVERIFY(!builder.isNull()); @@ -79,26 +81,27 @@ void TestTemplates::testTemplateWithNamespace() void TestTemplates::testTemplateOnContainers() { - const char cppCode[] = "\n\ - struct Base {};\n\ - template<typename T> struct QList {}; \n\ - namespace Namespace {\n\ - enum SomeEnum { E1, E2 };\n\ - template<SomeEnum type> struct A {\n\ - A<type> foo(const QList<A<type> >& a);\n\ - };\n\ - typedef A<E1> B;\n\ - }\n\ - "; - const char xmlCode[] = "\n\ - <typesystem package=\"Package\">\n\ - <container-type name='QList' type='list'/>\n\ - <namespace-type name='Namespace'/>\n\ - <enum-type name='Namespace::SomeEnum'/>\n\ - <object-type name='Base'/>\n\ - <object-type name='Namespace::A' generate='no'/>\n\ - <object-type name='Namespace::B'/>\n\ - </typesystem>"; + const char cppCode[] = R"CPP( +struct Base {}; +template<typename T> struct QList {}; +namespace Namespace { + enum SomeEnum { E1, E2 }; + template<SomeEnum type> struct A { + A<type> foo(const QList<A<type> >& a); + }; + typedef A<E1> B; +} +)CPP"; + + const char xmlCode[] = R"XML( +<typesystem package="Package"> + <container-type name='QList' type='list'/> + <namespace-type name='Namespace'/> + <enum-type name='Namespace::SomeEnum'/> + <object-type name='Base'/> + <object-type name='Namespace::A' generate='no'/> + <object-type name='Namespace::B'/> +</typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); @@ -124,18 +127,17 @@ void TestTemplates::testTemplateOnContainers() void TestTemplates::testTemplateValueAsArgument() { - const char cppCode[] = "\n\ - template<typename T> struct List {};\n\ - void func(List<int> arg) {}\n\ - "; - - const char xmlCode[] = "\n\ - <typesystem package='Package'>\n\ - <primitive-type name='int'/>\n\ - <container-type name='List' type='list'/>\n\ - <function signature='func(List<int>)'/>\n\ - </typesystem>\n\ - "; + const char cppCode[] = R"CPP( +template<typename T> struct List {}; +void func(List<int> arg) {} +)CPP"; + + const char xmlCode[] = R"XML( +<typesystem package='Package'> + <primitive-type name='int'/> + <container-type name='List' type='list'/> + <function signature='func(List<int>)'/> +</typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); @@ -149,18 +151,17 @@ void TestTemplates::testTemplateValueAsArgument() void TestTemplates::testTemplatePointerAsArgument() { - const char cppCode[] = "\n\ - template<typename T> struct List {};\n\ - void func(List<int>* arg) {}\n\ - "; - - const char xmlCode[] = "\n\ - <typesystem package='Package'>\n\ - <primitive-type name='int'/>\n\ - <container-type name='List' type='list'/>\n\ - <function signature='func(List<int>*)'/>\n\ - </typesystem>\n\ - "; + const char cppCode[] = R"CPP( +template<typename T> struct List {}; +void func(List<int>* arg) {} +)CPP"; + + const char xmlCode[] = R"XML( + <typesystem package='Package'> + <primitive-type name='int'/> + <container-type name='List' type='list'/> + <function signature='func(List<int>*)'/> + </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); @@ -174,18 +175,17 @@ void TestTemplates::testTemplatePointerAsArgument() void TestTemplates::testTemplateReferenceAsArgument() { - const char cppCode[] = "\n\ - template<typename T> struct List {};\n\ - void func(List<int>& arg) {}\n\ - "; - - const char xmlCode[] = "\n\ - <typesystem package='Package'>\n\ - <primitive-type name='int'/>\n\ - <container-type name='List' type='list'/>\n\ - <function signature='func(List<int>&)'/>\n\ - </typesystem>\n\ - "; + const char cppCode[] = R"CPP( +template<typename T> struct List {}; +void func(List<int>& arg) {} + )CPP"; + + const char xmlCode[] = R"XML( +<typesystem package='Package'> + <primitive-type name='int'/> + <container-type name='List' type='list'/> + <function signature='func(List<int>&)'/> +</typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); @@ -199,19 +199,20 @@ void TestTemplates::testTemplateReferenceAsArgument() void TestTemplates::testTemplateParameterFixup() { - const char cppCode[] = "\n\ - template<typename T>\n\ - struct List {\n\ - struct Iterator {};\n\ - void append(List l);\n\ - void erase(List::Iterator it);\n\ - };\n"; - - const char xmlCode[] = "\n\ - <typesystem package='Package'>\n\ - <container-type name='List' type='list'/>\n\ - <value-type name='List::Iterator'/>\n\ - </typesystem>\n"; + const char cppCode[] = R"CPP( +template<typename T> +struct List { + struct Iterator {}; + void append(List l); + void erase(List::Iterator it); +}; +)CPP"; + + const char xmlCode[] = R"XML( + <typesystem package='Package'> + <container-type name='List' type='list'/> + <value-type name='List::Iterator'/> + </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); @@ -234,26 +235,25 @@ void TestTemplates::testTemplateParameterFixup() void TestTemplates::testInheritanceFromContainterTemplate() { - const char cppCode[] = "\n\ - template<typename T>\n\ - struct ListContainer {\n\ - inline void push_front(const T& t);\n\ - inline T& front();\n\ - };\n\ - struct FooBar {};\n\ - struct FooBars : public ListContainer<FooBar> {};\n\ - "; - - const char xmlCode[] = "\n\ - <typesystem package='Package'>\n\ - <container-type name='ListContainer' type='list'/>\n\ - <value-type name='FooBar'/>\n\ - <value-type name='FooBars'>\n\ - <modify-function signature='push_front(FooBar)' remove='all'/>\n\ - <modify-function signature='front()' remove='all'/>\n\ - </value-type>\n\ - </typesystem>\n\ - "; + const char cppCode[] = R"CPP( +template<typename T> +struct ListContainer { + inline void push_front(const T& t); + inline T& front(); +}; +struct FooBar {}; +struct FooBars : public ListContainer<FooBar> {}; +)CPP"; + + const char xmlCode[] = R"XML( +<typesystem package='Package'> + <container-type name='ListContainer' type='list'/> + <value-type name='FooBar'/> + <value-type name='FooBars'> + <modify-function signature='push_front(FooBar)' remove='all'/> + <modify-function signature='front()' remove='all'/> + </value-type> +</typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); @@ -271,25 +271,26 @@ void TestTemplates::testInheritanceFromContainterTemplate() void TestTemplates::testTemplateInheritanceMixedWithForwardDeclaration() { - const char cppCode[] = "\n\ - enum SomeEnum { E1, E2 };\n\ - template<SomeEnum type> struct Future;\n\ - template<SomeEnum type>\n\ - struct A {\n\ - A();\n\ - void method();\n\ - friend struct Future<type>;\n\ - };\n\ - typedef A<E1> B;\n\ - template<SomeEnum type> struct Future {};\n\ - "; - const char xmlCode[] = "\n\ - <typesystem package='Package'>\n\ - <enum-type name='SomeEnum'/>\n\ - <value-type name='A' generate='no'/>\n\ - <value-type name='B'/>\n\ - <value-type name='Future' generate='no'/>\n\ - </typesystem>"; + const char cppCode[] = R"CPP( +enum SomeEnum { E1, E2 }; +template<SomeEnum type> struct Future; +template<SomeEnum type> +struct A { + A(); + void method(); + friend struct Future<type>; +}; +typedef A<E1> B; +template<SomeEnum type> struct Future {}; +)CPP"; + + const char xmlCode[] = R"XML( +<typesystem package='Package'> + <enum-type name='SomeEnum'/> + <value-type name='A' generate='no'/> + <value-type name='B'/> + <value-type name='Future' generate='no'/> +</typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); @@ -305,28 +306,29 @@ void TestTemplates::testTemplateInheritanceMixedWithForwardDeclaration() void TestTemplates::testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration() { - const char cppCode[] = "\n\ - namespace Namespace {\n\ - enum SomeEnum { E1, E2 };\n\ - template<SomeEnum type> struct Future;\n\ - template<SomeEnum type>\n\ - struct A {\n\ - A();\n\ - void method();\n\ - friend struct Future<type>;\n\ - };\n\ - typedef A<E1> B;\n\ - template<SomeEnum type> struct Future {};\n\ - };\n\ - "; - const char xmlCode[] = "\n\ - <typesystem package='Package'>\n\ - <namespace-type name='Namespace'/>\n\ - <enum-type name='Namespace::SomeEnum'/>\n\ - <value-type name='Namespace::A' generate='no'/>\n\ - <value-type name='Namespace::B'/>\n\ - <value-type name='Namespace::Future' generate='no'/>\n\ - </typesystem>"; + const char cppCode[] = R"CPP( +namespace Namespace { +enum SomeEnum { E1, E2 }; +template<SomeEnum type> struct Future; +template<SomeEnum type> +struct A { + A(); + void method(); + friend struct Future<type>; +}; +typedef A<E1> B; +template<SomeEnum type> struct Future {}; +}; +)CPP"; + + const char xmlCode[] = R"XML( +<typesystem package='Package'> + <namespace-type name='Namespace'/> + <enum-type name='Namespace::SomeEnum'/> + <value-type name='Namespace::A' generate='no'/> + <value-type name='Namespace::B'/> + <value-type name='Namespace::Future' generate='no'/> +</typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); @@ -342,28 +344,27 @@ void TestTemplates::testTemplateInheritanceMixedWithNamespaceAndForwardDeclarati void TestTemplates::testTypedefOfInstantiationOfTemplateClass() { - const char cppCode[] = "\n\ - namespace NSpace {\n\ - enum ClassType {\n\ - TypeOne\n\ - };\n\ - template<ClassType CLASS_TYPE>\n\ - struct BaseTemplateClass {\n\ - inline ClassType getClassType() const { CLASS_TYPE; }\n\ - };\n\ - typedef BaseTemplateClass<TypeOne> TypeOneClass;\n\ - }\n\ - "; - - const char xmlCode[] = "\n\ - <typesystem package='Package'>\n\ - <namespace-type name='NSpace'>\n\ - <enum-type name='ClassType'/>\n\ - <object-type name='BaseTemplateClass' generate='no'/>\n\ - <object-type name='TypeOneClass'/>\n\ - </namespace-type>\n\ - </typesystem>\n\ - "; + const char cppCode[] = R"CPP( +namespace NSpace { +enum ClassType { + TypeOne +}; +template<ClassType CLASS_TYPE> +struct BaseTemplateClass { + inline ClassType getClassType() const { CLASS_TYPE; } +}; +typedef BaseTemplateClass<TypeOne> TypeOneClass; +} +)CPP"; + + const char xmlCode[] = R"XML( +<typesystem package='Package'> + <namespace-type name='NSpace'> + <enum-type name='ClassType'/> + <object-type name='BaseTemplateClass' generate='no'/> + <object-type name='TypeOneClass'/> + </namespace-type> +</typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); @@ -395,24 +396,25 @@ void TestTemplates::testTypedefOfInstantiationOfTemplateClass() void TestTemplates::testContainerTypeIncompleteArgument() { - const char* cppCode ="\n\ - template<typename T>\n\ - class Vector {\n\ - void method(const Vector& vector);\n\ - Vector otherMethod();\n\ - };\n\ - template <typename T>\n\ - void Vector<T>::method(const Vector<T>& vector) {}\n\ - template <typename T>\n\ - Vector<T> Vector<T>::otherMethod() { return Vector<T>(); }\n\ - typedef Vector<int> IntVector;\n\ - "; - const char* xmlCode = "\n\ - <typesystem package='Foo'>\n\ - <primitive-type name='int'/>\n\ - <container-type name='Vector' type='vector'/>\n\ - <value-type name='IntVector'/>\n\ - </typesystem>"; + const char cppCode[] = R"CPP( +template<typename T> +class Vector { + void method(const Vector& vector); + Vector otherMethod(); +}; +template <typename T> +void Vector<T>::method(const Vector<T>& vector) {} +template <typename T> +Vector<T> Vector<T>::otherMethod() { return Vector<T>(); } +typedef Vector<int> IntVector; +)CPP"; + + const char xmlCode[] = R"XML( +<typesystem package='Foo'> + <primitive-type name='int'/> + <container-type name='Vector' type='vector'/> + <value-type name='IntVector'/> +</typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true)); QVERIFY(!builder.isNull()); diff --git a/sources/shiboken2/ApiExtractor/tests/testutil.h b/sources/shiboken2/ApiExtractor/tests/testutil.h index 3d2dd19ea..6152793f5 100644 --- a/sources/shiboken2/ApiExtractor/tests/testutil.h +++ b/sources/shiboken2/ApiExtractor/tests/testutil.h @@ -67,7 +67,7 @@ namespace TestUtil tempSource.write(cppCode, qint64(strlen(cppCode))); tempSource.close(); AbstractMetaBuilder *builder = new AbstractMetaBuilder; - if (!builder->build(arguments, 0)) { + if (!builder->build(arguments)) { delete builder; return Q_NULLPTR; } diff --git a/sources/shiboken2/ApiExtractor/typeparser.cpp b/sources/shiboken2/ApiExtractor/typeparser.cpp index 9ef4be346..02c85421b 100644 --- a/sources/shiboken2/ApiExtractor/typeparser.cpp +++ b/sources/shiboken2/ApiExtractor/typeparser.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include "typeparser.h" +#include <codemodel.h> #include <QtCore/QDebug> #include <QtCore/QStack> @@ -155,19 +156,12 @@ QString Scanner::msgParseError(const QString &why) const + QString(m_chars, m_length) + QStringLiteral("\": ") + why; } -static TypeParser::Info invalidInfo() -{ - TypeParser::Info result; - result.is_busted = true; - return result; -} - -TypeParser::Info TypeParser::parse(const QString &str, QString *errorMessage) +TypeInfo TypeParser::parse(const QString &str, QString *errorMessage) { Scanner scanner(str); - Info info; - QStack<Info *> stack; + TypeInfo info; + QStack<TypeInfo *> stack; stack.push(&info); bool colon_prefix = false; @@ -177,7 +171,7 @@ TypeParser::Info TypeParser::parse(const QString &str, QString *errorMessage) Scanner::Token tok = scanner.nextToken(errorMessage); while (tok != Scanner::NoToken) { if (tok == Scanner::InvalidToken) - return invalidInfo(); + return TypeInfo(); // switch (tok) { // case Scanner::StarToken: printf(" - *\n"); break; @@ -197,16 +191,16 @@ TypeParser::Info TypeParser::parse(const QString &str, QString *errorMessage) switch (tok) { case Scanner::StarToken: - ++stack.top()->indirections; + ++stack.top()->m_indirections; break; case Scanner::AmpersandToken: - switch (stack.top()->referenceType) { + switch (stack.top()->referenceType()) { case NoReference: - stack.top()->referenceType = LValueReference; + stack.top()->setReferenceType(LValueReference); break; case LValueReference: - stack.top()->referenceType = RValueReference; + stack.top()->setReferenceType(RValueReference); break; case RValueReference: const QString message = scanner.msgParseError(QStringLiteral("Too many '&' qualifiers")); @@ -214,18 +208,18 @@ TypeParser::Info TypeParser::parse(const QString &str, QString *errorMessage) *errorMessage = message; else qWarning().noquote().nospace() << message; - return invalidInfo(); + return TypeInfo(); } break; case Scanner::LessThanToken: - stack.top()->template_instantiations << Info(); - stack.push(&stack.top()->template_instantiations.last()); + stack.top()->m_arguments << TypeInfo(); + stack.push(&stack.top()->m_arguments.last()); break; case Scanner::CommaToken: stack.pop(); - stack.top()->template_instantiations << Info(); - stack.push(&stack.top()->template_instantiations.last()); + stack.top()->m_arguments << TypeInfo(); + stack.push(&stack.top()->m_arguments.last()); break; case Scanner::GreaterThanToken: @@ -237,7 +231,7 @@ TypeParser::Info TypeParser::parse(const QString &str, QString *errorMessage) break; case Scanner::ConstToken: - stack.top()->is_constant = true; + stack.top()->m_constant = true; break; case Scanner::OpenParenToken: // function pointers not supported @@ -247,17 +241,17 @@ TypeParser::Info TypeParser::parse(const QString &str, QString *errorMessage) *errorMessage = message; else qWarning().noquote().nospace() << message; - return invalidInfo(); + return TypeInfo(); } case Scanner::Identifier: if (in_array) { array = scanner.identifier(); - } else if (colon_prefix || stack.top()->qualified_name.isEmpty()) { - stack.top()->qualified_name << scanner.identifier(); + } else if (colon_prefix || stack.top()->m_qualifiedName.isEmpty()) { + stack.top()->m_qualifiedName << scanner.identifier(); colon_prefix = false; } else { - stack.top()->qualified_name.last().append(QLatin1Char(' ') + scanner.identifier()); + stack.top()->m_qualifiedName.last().append(QLatin1Char(' ') + scanner.identifier()); } break; @@ -267,7 +261,7 @@ TypeParser::Info TypeParser::parse(const QString &str, QString *errorMessage) case Scanner::SquareEnd: in_array = false; - stack.top()->arrays += array; + stack.top()->m_arrayElements += array; break; @@ -280,83 +274,3 @@ TypeParser::Info TypeParser::parse(const QString &str, QString *errorMessage) return info; } - -QString TypeParser::Info::instantiationName() const -{ - QString s(qualified_name.join(QLatin1String("::"))); - if (!template_instantiations.isEmpty()) { - QStringList insts; - for (const Info &info : template_instantiations) - insts << info.toString(); - s += QLatin1String("< ") + insts.join(QLatin1String(", ")) + QLatin1String(" >"); - } - - return s; -} - -QString TypeParser::Info::toString() const -{ - QString s; - - if (is_constant) - s += QLatin1String("const "); - s += instantiationName(); - for (int i = 0; i < arrays.size(); ++i) - s += QLatin1Char('[') + arrays.at(i) + QLatin1Char(']'); - s += QString(indirections, QLatin1Char('*')); - switch (referenceType) { - case NoReference: - break; - case LValueReference: - s += QLatin1Char('&'); - break; - case RValueReference: - s += QLatin1String("&&"); - break; - } - return s; -} - -#ifndef QT_NO_DEBUG_STREAM - -static void formatTypeInfo(QDebug &d, const TypeParser::Info &i) -{ - if (i.is_busted) { - d << "busted"; - return; - } - - d << '"' << i.qualified_name << '"'; - if (!i.arrays.isEmpty()) { - d << ", arrays="; - for (const QString &a : i.arrays) - d << '[' << a << ']'; - } - if (!i.template_instantiations.isEmpty()) { - d << ", template_instantiations=["; - for (int t = 0, size = i.template_instantiations.size(); t < size; ++t) { - if (t) - d << ", "; - formatTypeInfo(d, i.template_instantiations.at(t)); - } - d << ']'; - } - if (i.referenceType != NoReference) - d << ", refType=" << i.referenceType; - if (i.is_constant) - d << ", [const]"; - if (i.indirections > 0) - d << ", indirections=" << i.indirections; -} - -QDebug operator<<(QDebug d, const TypeParser::Info &i) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "TypeParser::Info("; - formatTypeInfo(d, i); - d << ')'; - return d; -} -#endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken2/ApiExtractor/typeparser.h b/sources/shiboken2/ApiExtractor/typeparser.h index e51a2c21a..3b538017a 100644 --- a/sources/shiboken2/ApiExtractor/typeparser.h +++ b/sources/shiboken2/ApiExtractor/typeparser.h @@ -31,36 +31,15 @@ #include "parser/codemodel_enums.h" -#include <QtCore/QList> #include <QtCore/QString> -#include <QtCore/QStringList> #include <QtCore/QVector> -QT_FORWARD_DECLARE_CLASS(QDebug) +class TypeInfo; class TypeParser { public: - struct Info - { - Info() : referenceType(NoReference), is_constant(false), is_busted(false), indirections(0) { } - QStringList qualified_name; - QStringList arrays; - QVector<Info> template_instantiations; - ReferenceType referenceType; - uint is_constant : 1; - uint is_busted : 1; - uint indirections : 6; - - QString toString() const; - QString instantiationName() const; - }; - - static Info parse(const QString &str, QString *errorMessage = Q_NULLPTR); + static TypeInfo parse(const QString &str, QString *errorMessage = nullptr); }; -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const TypeParser::Info &); -#endif - #endif // TYPEPARSER_H diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp index 52f05ce5b..baaec6d30 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -1717,9 +1717,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts ", was=%1").arg(topElement.type, 0, 16); return false; } - QString signature = attributes[QLatin1String("signature")]; + const QString originalSignature = attributes[QLatin1String("signature")]; - signature = TypeDatabase::normalizedSignature(signature); + QString signature = TypeDatabase::normalizedSignature(originalSignature); if (signature.isEmpty()) { m_error = QLatin1String("No signature for the added function"); return false; @@ -1754,6 +1754,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts FunctionModification mod; if (!mod.setSignature(m_currentSignature, &m_error)) return false; + mod.setOriginalSignature(originalSignature); m_contextStack.top()->functionMods << mod; } break; @@ -1763,9 +1764,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts ", was=%1").arg(topElement.type, 0, 16); return false; } - QString signature = attributes[QLatin1String("signature")]; + const QString originalSignature = attributes[QLatin1String("signature")]; - signature = TypeDatabase::normalizedSignature(signature); + const QString signature = TypeDatabase::normalizedSignature(originalSignature); if (signature.isEmpty()) { m_error = QLatin1String("No signature for modified function"); return false; @@ -1780,6 +1781,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts FunctionModification mod; if (!mod.setSignature(signature, &m_error)) return false; + mod.setOriginalSignature(originalSignature); m_currentSignature = signature; QString access = attributes[QLatin1String("access")].toLower(); diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 79e60cd75..186c4b24d 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -356,6 +356,9 @@ struct FunctionModification: public Modification bool setSignature(const QString &s, QString *errorMessage = nullptr); QString signature() const { return m_signature.isEmpty() ? m_signaturePattern.pattern() : m_signature; } + void setOriginalSignature(const QString &s) { m_originalSignature = s; } + QString originalSignature() const { return m_originalSignature; } + QString toString() const; QString association; @@ -365,6 +368,7 @@ struct FunctionModification: public Modification private: QString m_signature; + QString m_originalSignature; QRegularExpression m_signaturePattern; bool m_thread = false; bool m_allowThread = false; diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt index 852e14c1a..1af84fca1 100644 --- a/sources/shiboken2/CMakeLists.txt +++ b/sources/shiboken2/CMakeLists.txt @@ -113,46 +113,6 @@ endif() message(STATUS "CLANG: ${CLANG_DIR}, ${CLANG_LIBRARY} detected by ${CLANG_DIR_SOURCE}") -# Find highest version clang builtin includes folder to pass along to shiboken. -set(CLANG_BUILTIN_INCLUDES_DIR_PREFIX ${CLANG_DIR}/lib/clang) -file(GLOB CLANG_BUILTIN_INCLUDES_DIR_CANDIDATES "${CLANG_BUILTIN_INCLUDES_DIR_PREFIX}/*") - -# Collect only directories, and not files, and only directories starting with a number. -set(CLANG_BUILTIN_INCLUDES_DIR_VERSIONS "") -foreach(candidate ${CLANG_BUILTIN_INCLUDES_DIR_CANDIDATES}) - get_filename_component(candidate_basename ${candidate} NAME) - if (IS_DIRECTORY ${candidate} AND ${candidate_basename} MATCHES "^[0-9]") # starts with number - list(APPEND CLANG_BUILTIN_INCLUDES_DIR_VERSIONS ${candidate}) - endif() -endforeach() - -# Sort in alphabetical order the list of version folders. -list(SORT CLANG_BUILTIN_INCLUDES_DIR_VERSIONS) - -# Reverse it so the first element is the highest version. -list(REVERSE CLANG_BUILTIN_INCLUDES_DIR_VERSIONS) - -message(STATUS - "Found the following CLANG builtins includes directories: ${CLANG_BUILTIN_INCLUDES_DIR_VERSIONS} \ - Considered the following directories: ${CLANG_BUILTIN_INCLUDES_DIR_CANDIDATES}") -if(CLANG_BUILTIN_INCLUDES_DIR_VERSIONS) - # Get highest version. - list(GET CLANG_BUILTIN_INCLUDES_DIR_VERSIONS 0 CLANG_BUILTIN_INCLUDES_DIR_HIGHEST_VERSION) - if (CLANG_BUILTIN_INCLUDES_DIR_HIGHEST_VERSION) - # Set the final variable to the full include path to pass along to shiboken. - set(CLANG_BUILTIN_INCLUDES_DIR "${CLANG_BUILTIN_INCLUDES_DIR_HIGHEST_VERSION}/include") - endif() -endif() - -message(STATUS "CLANG builtins includes directory chosen: ${CLANG_BUILTIN_INCLUDES_DIR}") - -# We don't exit with a hard error here, because it is uncertain whether all clang extra include -# paths follow the same layout across OSes and distros. -if (NOT CLANG_BUILTIN_INCLUDES_DIR) - message(WARNING "No CLANG builtins includes directory found. This may lead to shiboken \ - execution failure.") -endif() - set(CLANG_EXTRA_INCLUDES ${CLANG_DIR}/include) set(CLANG_EXTRA_LIBRARIES ${CLANG_LIBRARY}) diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp index ded504905..1e2f03932 100644 --- a/sources/shiboken2/generator/generator.cpp +++ b/sources/shiboken2/generator/generator.cpp @@ -46,7 +46,6 @@ struct Generator::GeneratorPrivate { // License comment QString licenseComment; QString packageName; - int numGenerated; QStringList instantiatedContainersNames; QStringList instantiatedSmartPointerNames; QVector<const AbstractMetaType *> instantiatedContainers; @@ -56,7 +55,6 @@ struct Generator::GeneratorPrivate { Generator::Generator() : m_d(new GeneratorPrivate) { - m_d->numGenerated = 0; } Generator::~Generator() @@ -249,11 +247,6 @@ const AbstractMetaEnum* Generator::findAbstractMetaEnum(const AbstractMetaType* return m_d->apiextractor->findAbstractMetaEnum(metaType); } -QSet< QString > Generator::qtMetaTypeDeclaredTypeNames() const -{ - return m_d->apiextractor->qtMetaTypeDeclaredTypeNames(); -} - QString Generator::licenseComment() const { return m_d->licenseComment; @@ -285,11 +278,6 @@ void Generator::setOutputDirectory(const QString &outDir) m_d->outDir = outDir; } -int Generator::numGenerated() const -{ - return m_d->numGenerated; -} - inline void touchFile(const QString &filePath) { QFile toucher(filePath); @@ -337,7 +325,6 @@ bool Generator::generateFileForContext(GeneratorContext &context) break; } - ++m_d->numGenerated; return true; } diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h index e48f86f6f..010ed868c 100644 --- a/sources/shiboken2/generator/generator.h +++ b/sources/shiboken2/generator/generator.h @@ -143,37 +143,21 @@ public: /// Optiosn used around the generator code enum Option { NoOption = 0x00000000, - BoxedPrimitive = 0x00000001, - ExcludeConst = 0x00000002, - ExcludeReference = 0x00000004, - UseNativeIds = 0x00000008, - - EnumAsInts = 0x00000010, - SkipName = 0x00000020, - NoCasts = 0x00000040, - SkipReturnType = 0x00000080, - OriginalName = 0x00000100, - ShowStatic = 0x00000200, - UnderscoreSpaces = 0x00000400, - ForceEnumCast = 0x00000800, - ArrayAsPointer = 0x00001000, - VirtualCall = 0x00002000, - SkipTemplateParameters = 0x00004000, - SkipAttributes = 0x00008000, - OriginalTypeDescription = 0x00010000, - SkipRemovedArguments = 0x00020000, - IncludeDefaultExpression = 0x00040000, - NoReturnStatement = 0x00080000, - NoBlockedSlot = 0x00100000, - - SuperCall = 0x00200000, - - GlobalRefJObject = 0x00100000, - - SkipDefaultValues = 0x00400000, - - WriteSelf = 0x00800000, - ExcludeMethodConst = 0x01000000, + ExcludeConst = 0x00000001, + ExcludeReference = 0x00000002, + + EnumAsInts = 0x00000004, + SkipName = 0x00000008, + SkipReturnType = 0x00000010, + OriginalName = 0x00000020, + VirtualCall = 0x00000040, + OriginalTypeDescription = 0x00000080, + SkipRemovedArguments = 0x00000100, + + SkipDefaultValues = 0x00000200, + + WriteSelf = 0x00000400, + ExcludeMethodConst = 0x00000800, ForceValueType = ExcludeReference | ExcludeConst }; @@ -241,9 +225,6 @@ public: QString getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType, const AbstractMetaClass *smartPointerClass) const; - /// Returns the number of generated items - int numGenerated() const; - /// Returns the generator's name. Used for cosmetic purposes. virtual const char* name() const = 0; @@ -284,9 +265,6 @@ public: void replaceTemplateVariables(QString &code, const AbstractMetaFunction *func); - // QtScript - QSet<QString> qtMetaTypeDeclaredTypeNames() const; - /** * Returns the license comment to be prepended to each source file generated. */ diff --git a/sources/shiboken2/generator/main.cpp b/sources/shiboken2/generator/main.cpp index 69f59a1b4..7ee43710e 100644 --- a/sources/shiboken2/generator/main.cpp +++ b/sources/shiboken2/generator/main.cpp @@ -46,8 +46,10 @@ #define PATH_SPLITTER ":" #endif +static inline QString languageLevelOption() { return QStringLiteral("language-level"); } static inline QString includePathOption() { return QStringLiteral("include-paths"); } static inline QString frameworkIncludePathOption() { return QStringLiteral("framework-include-paths"); } +static inline QString systemIncludePathOption() { return QStringLiteral("system-include-paths"); } static inline QString typesystemPathOption() { return QStringLiteral("typesystem-paths"); } static inline QString helpOption() { return QStringLiteral("help"); } static const char helpHint[] = "Note: use --help or -h for more information.\n"; @@ -171,8 +173,10 @@ static bool processProjectFile(QFile& projectFile, QMap<QString, QString>& args) QStringList includePaths; QStringList frameworkIncludePaths; + QStringList systemIncludePaths; QStringList typesystemPaths; QStringList apiVersions; + QString languageLevel; while (!projectFile.atEnd()) { line = projectFile.readLine().trimmed(); @@ -193,8 +197,12 @@ static bool processProjectFile(QFile& projectFile, QMap<QString, QString>& args) includePaths << QDir::toNativeSeparators(value); else if (key == "framework-include-path") frameworkIncludePaths << QDir::toNativeSeparators(value); + else if (key == "system-include-paths") + systemIncludePaths << QDir::toNativeSeparators(value); else if (key == "typesystem-path") typesystemPaths << QDir::toNativeSeparators(value); + else if (key == "language-level") + languageLevel = value; else if (key == "api-version") apiVersions << value; else if (key == "header-file") @@ -211,11 +219,17 @@ static bool processProjectFile(QFile& projectFile, QMap<QString, QString>& args) if (!frameworkIncludePaths.isEmpty()) args.insert(frameworkIncludePathOption(), frameworkIncludePaths.join(QLatin1String(PATH_SPLITTER))); + if (!systemIncludePaths.isEmpty()) { + args.insert(systemIncludePathOption(), + systemIncludePaths.join(QLatin1String(PATH_SPLITTER))); + } if (!typesystemPaths.isEmpty()) args.insert(typesystemPathOption(), typesystemPaths.join(QLatin1String(PATH_SPLITTER))); if (!apiVersions.isEmpty()) args.insert(QLatin1String("api-version"), apiVersions.join(QLatin1Char('|'))); + if (!languageLevel.isEmpty()) + args.insert(languageLevelOption(), languageLevel); return true; } @@ -284,7 +298,7 @@ static void getCommandLineArg(QString arg, int &argNum, QMap<QString, QString> & const QString option = arg.left(split); const QString value = arg.mid(split + 1).trimmed(); if (option == includePathOption() || option == frameworkIncludePathOption() - || option == typesystemPathOption()) { + || option == systemIncludePathOption() || option == typesystemPathOption()) { addPathOptionValue(option, value, args); } else { args.insert(option, value); @@ -297,10 +311,14 @@ static void getCommandLineArg(QString arg, int &argNum, QMap<QString, QString> & addPathOptionValue(includePathOption(), arg.mid(1), args); else if (arg.startsWith(QLatin1Char('F'))) addPathOptionValue(frameworkIncludePathOption(), arg.mid(1), args); + else if (arg.startsWith(QLatin1String("isystem"))) + addPathOptionValue(systemIncludePathOption(), arg.mid(7), args); else if (arg.startsWith(QLatin1Char('T'))) addPathOptionValue(typesystemPathOption(), arg.mid(1), args); else if (arg == QLatin1String("h")) args.insert(helpOption(), QString()); + else if (arg.startsWith(QLatin1String("std="))) + args.insert(languageLevelOption(), arg.mid(4)); else args.insert(arg, QString()); return; @@ -338,6 +356,13 @@ static inline Generators shibokenGenerators() return result; } +static inline QString languageLevelDescription() +{ + return QLatin1String("C++ Language level (c++11..c++17, default=") + + QLatin1String(clang::languageLevelOption(clang::emulatedCompilerLanguageLevel())) + + QLatin1Char(')'); +} + void printUsage() { QTextStream s(stdout); @@ -358,6 +383,9 @@ void printUsage() << qMakePair(QLatin1String("-F") + pathSyntax, QString()) << qMakePair(QLatin1String("framework-include-paths=") + pathSyntax, QLatin1String("Framework include paths used by the C++ parser")) + << qMakePair(QLatin1String("-isystem") + pathSyntax, QString()) + << qMakePair(QLatin1String("system-include-paths=") + pathSyntax, + QLatin1String("System include paths used by the C++ parser")) << qMakePair(QLatin1String("generator-set=<\"generator module\">"), QLatin1String("generator-set to be used. e.g. qtdoc")) << qMakePair(QLatin1String("-h"), QString()) @@ -366,6 +394,8 @@ void printUsage() << qMakePair(QLatin1String("-I") + pathSyntax, QString()) << qMakePair(QLatin1String("include-paths=") + pathSyntax, QLatin1String("Include paths used by the C++ parser")) + << qMakePair(languageLevelOption() + QLatin1String("=, -std=<level>"), + languageLevelDescription()) << qMakePair(QLatin1String("license-file=<license-file>"), QLatin1String("File used for copyright headers of generated files")) << qMakePair(QLatin1String("no-suppress-warnings"), @@ -414,6 +444,18 @@ static QString msgInvalidVersion(const QString &package, const QString &version) + QLatin1String("\" specified for package ") + package + QLatin1Char('.'); } +static void parseIncludePathOption(const QString &option, HeaderType headerType, + ArgsHandler &args, + ApiExtractor &extractor) +{ + const QString path = args.removeArg(option); + if (!path.isEmpty()) { + const QStringList includePathListList = path.split(QLatin1String(PATH_SPLITTER)); + for (const QString &s : includePathListList) + extractor.addIncludePath(HeaderPath{QFile::encodeName(s), headerType}); + } +} + int main(int argc, char *argv[]) { QElapsedTimer timer; @@ -525,23 +567,12 @@ int main(int argc, char *argv[]) if (!path.isEmpty()) extractor.addTypesystemSearchPath(path.split(QLatin1String(PATH_SPLITTER))); - path = argsHandler.removeArg(QLatin1String("include-paths")); - if (!path.isEmpty()) { - const QStringList includePathListList = path.split(QLatin1String(PATH_SPLITTER)); - for (const QString &s : qAsConst(includePathListList)) { - const bool isFramework = false; - extractor.addIncludePath(HeaderPath(s, isFramework)); - } - } - - path = argsHandler.removeArg(QLatin1String("framework-include-paths")); - if (!path.isEmpty()) { - const QStringList frameworkPathList = path.split(QLatin1String(PATH_SPLITTER)); - const bool isFramework = true; - for (const QString &s : qAsConst(frameworkPathList)) { - extractor.addIncludePath(HeaderPath(s, isFramework)); - } - } + parseIncludePathOption(includePathOption(), HeaderType::Standard, + argsHandler, extractor); + parseIncludePathOption(frameworkIncludePathOption(), HeaderType::Framework, + argsHandler, extractor); + parseIncludePathOption(systemIncludePathOption(), HeaderType::System, + argsHandler, extractor); QString cppFileName = argsHandler.removeArg(QLatin1String("arg-1")); const QFileInfo cppFileNameFi(cppFileName); @@ -574,6 +605,18 @@ int main(int argc, char *argv[]) argsHandler.removeArg(od.first); } + const QString languageLevel = argsHandler.removeArg(languageLevelOption()); + if (!languageLevel.isEmpty()) { + const QByteArray languageLevelBA = languageLevel.toLatin1(); + const LanguageLevel level = clang::languageLevelFromOption(languageLevelBA.constData()); + if (level == LanguageLevel::Default) { + std::cout << "Invalid argument for language level: \"" + << languageLevelBA.constData() << "\"\n" << helpHint; + return EXIT_FAILURE; + } + extractor.setLanguageLevel(level); + } + if (!argsHandler.noArgs()) { errorPrint(argsHandler.errorMessage()); std::cout << helpHint; @@ -587,6 +630,7 @@ int main(int argc, char *argv[]) extractor.setCppFileName(cppFileNameFi.absoluteFilePath()); extractor.setTypeSystem(typeSystemFileName); + if (!extractor.run()) { errorPrint(QLatin1String("Error running ApiExtractor.")); return EXIT_FAILURE; diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp index 489d498f9..3ed278871 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp @@ -521,7 +521,13 @@ QString QtXmlToSphinx::readFromLocations(const QStringList &locations, const QSt const QString &identifier, QString *errorMessage) { QString result; - const QString resolvedPath = resolveFile(locations, path); + QString resolvedPath; + if (path.endsWith(QLatin1String(".cpp"))) { + const QString pySnippet = path.left(path.size() - 3) + QLatin1String("py"); + resolvedPath = resolveFile(locations, pySnippet); + } + if (resolvedPath.isEmpty()) + resolvedPath = resolveFile(locations, path); if (resolvedPath.isEmpty()) { QTextStream(errorMessage) << "Could not resolve \"" << path << "\" in \"" << locations.join(QLatin1String("\", \"")); diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index bd654f17c..568b5fd27 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -1446,15 +1446,6 @@ void CppGenerator::writeCustomConverterRegister(QTextStream& s, const CustomConv } } -void CppGenerator::writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar) -{ - s << INDENT << "// Add user defined container conversion to type converter." << endl; - QString typeName = fixedCppTypeName(container); - QString toCpp = pythonToCppFunctionName(typeName, typeName); - QString isConv = convertibleToCppFunctionName(typeName, typeName); - writeAddPythonToCppConversion(s, converterVar, toCpp, isConv); -} - void CppGenerator::writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType) { writeCppToPythonFunction(s, containerType); @@ -1988,7 +1979,7 @@ void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData) QString strArg; AbstractMetaType* argType = arg->type(); if (isCString(argType)) { - strArg = QLatin1String("\" SBK_STR_NAME \""); + strArg = QLatin1String("\" SBK_BYTES_NAME \""); } else if (argType->isPrimitive()) { const PrimitiveTypeEntry* ptp = reinterpret_cast<const PrimitiveTypeEntry*>(argType->typeEntry()); while (ptp->referencedTypeEntry()) @@ -2025,7 +2016,9 @@ void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData) else if (strArg == QLatin1String("PyString")) strArg = QLatin1String("str"); else if (strArg == QLatin1String("PyBytes")) - strArg = QLatin1String("\" SBK_STR_NAME \""); + strArg = QLatin1String("\" SBK_BYTES_NAME \""); + else if (strArg == QLatin1String("PyByteArray")) + strArg = QLatin1String("bytearray"); else if (strArg == QLatin1String("PySequence")) strArg = QLatin1String("list"); else if (strArg == QLatin1String("PyTuple")) diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h index 4dbd31828..1b59bcda7 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.h +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h @@ -64,14 +64,12 @@ private: void writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass, GeneratorContext &classContext); void writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar); - void writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar); void writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType); void writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData, GeneratorContext &context); void writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, GeneratorContext &classContext); - void writeDestructorWrapper(QTextStream& s, const AbstractMetaClass* metaClass); void writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, GeneratorContext &classContext); void writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData); @@ -266,7 +264,6 @@ private: GeneratorContext &context); void writeRichCompareFunction(QTextStream &s, GeneratorContext &context); - void writeToPythonFunction(QTextStream& s, const AbstractMetaClass* metaClass); void writeEnumsInitialization(QTextStream& s, AbstractMetaEnumList& enums); void writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum); diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index 976b34141..80096cbf2 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -639,14 +639,6 @@ QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString arg + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))"); } -QString ShibokenGenerator::getFunctionReturnType(const AbstractMetaFunction* func, Options) const -{ - if (func->ownerClass() && func->isConstructor()) - return func->ownerClass()->qualifiedCppName() + QLatin1Char('*'); - - return translateTypeForWrapperMethod(func->type(), func->implementingClass()); -} - void ShibokenGenerator::writeToPythonConversion(QTextStream & s, const AbstractMetaType* type, const AbstractMetaClass * /* context */, const QString& argumentName) @@ -876,17 +868,6 @@ static QString msgUnknownOperator(const AbstractMetaFunction* func) static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); } -QString ShibokenGenerator::cpythonOperatorFunctionName(const AbstractMetaFunction* func) -{ - if (!func->isOperatorOverload()) - return QString(); - const QString pythonOp = pythonOperatorFunctionName(func->originalName()); - if (pythonOp == unknownOperator()) - qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func); - return QLatin1String("Sbk") + func->ownerClass()->name() - + QLatin1Char('_') + pythonOp; -} - QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative) { if (toNative->sourceType()) @@ -1014,12 +995,6 @@ bool ShibokenGenerator::isPyInt(const AbstractMetaType* type) return isPyInt(type->typeEntry()); } -bool ShibokenGenerator::isPairContainer(const AbstractMetaType* type) -{ - return type->isContainer() - && static_cast<const ContainerTypeEntry *>(type->typeEntry())->type() == ContainerTypeEntry::PairContainer; -} - bool ShibokenGenerator::isWrapperType(const TypeEntry* type) { if (type->isComplex()) @@ -1238,18 +1213,6 @@ QString ShibokenGenerator::guessCPythonCheckFunction(const QString& type, Abstra return type + QLatin1String("_Check"); } -QString ShibokenGenerator::guessCPythonIsConvertible(const QString& type) -{ - if (type == QLatin1String("PyTypeObject")) - return QLatin1String("PyType_Check"); - - AbstractMetaType* metaType = buildAbstractMetaTypeFromString(type); - if (metaType && !metaType->typeEntry()->isCustom()) - return cpythonIsConvertibleFunction(metaType); - - return type + QLatin1String("_Check"); -} - QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry* type, bool /* genericNumberType */, bool /* checkExact */) @@ -2096,16 +2059,6 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa code.replace(rep.first, rep.second); } -bool ShibokenGenerator::injectedCodeUsesCppSelf(const AbstractMetaFunction* func) -{ - CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode); - for (const CodeSnip &snip : qAsConst(snips)) { - if (snip.code().contains(QLatin1String("%CPPSELF"))) - return true; - } - return false; -} - bool ShibokenGenerator::injectedCodeUsesPySelf(const AbstractMetaFunction* func) { CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode); @@ -2296,20 +2249,6 @@ QString ShibokenGenerator::getModuleHeaderFileName(const QString& moduleName) co return result.toLower() + QLatin1String("_python.h"); } -QString ShibokenGenerator::extendedIsConvertibleFunctionName(const TypeEntry* targetType) const -{ - QString p = targetType->targetLangPackage(); - p.replace(QLatin1Char('.'), QLatin1Char('_')); - return QStringLiteral("ExtendedIsConvertible_%1_%2").arg(p, targetType->name()); -} - -QString ShibokenGenerator::extendedToCppFunctionName(const TypeEntry* targetType) const -{ - QString p = targetType->targetLangPackage(); - p.replace(QLatin1Char('.'), QLatin1Char('_')); - return QStringLiteral("ExtendedToCpp_%1_%2").arg(p, targetType->name()); -} - bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass) { @@ -2490,8 +2429,18 @@ QMap< QString, AbstractMetaFunctionList > ShibokenGenerator::getFunctionGroups(c QMap<QString, AbstractMetaFunctionList> results; for (AbstractMetaFunction *func : qAsConst(lst)) { - if (isGroupable(func)) - results[func->name()].append(func); + if (isGroupable(func)) { + AbstractMetaFunctionList &list = results[func->name()]; + // If there are virtuals methods in the mix (PYSIDE-570, + // QFileSystemModel::index(QString,int) and + // QFileSystemModel::index(int,int,QModelIndex)) override, make sure + // the overriding method of the most-derived class is seen first + // and inserted into the "seenSignatures" set. + if (func->isVirtual()) + list.prepend(func); + else + list.append(func); + } } return results; } @@ -2539,25 +2488,6 @@ AbstractMetaFunctionList ShibokenGenerator::getFunctionOverloads(const AbstractM return results; } -QPair< int, int > ShibokenGenerator::getMinMaxArguments(const AbstractMetaFunction* metaFunction) -{ - AbstractMetaFunctionList overloads = getFunctionOverloads(metaFunction->ownerClass(), metaFunction->name()); - - int minArgs = std::numeric_limits<int>::max(); - int maxArgs = 0; - for (const AbstractMetaFunction* func : qAsConst(overloads)) { - int numArgs = 0; - const AbstractMetaArgumentList &arguments = func->arguments(); - for (const AbstractMetaArgument *arg : arguments) { - if (!func->argumentRemoved(arg->argumentIndex() + 1)) - numArgs++; - } - maxArgs = std::max(maxArgs, numArgs); - minArgs = std::min(minArgs, numArgs); - } - return qMakePair(minArgs, maxArgs); -} - Generator::OptionDescriptions ShibokenGenerator::options() const { return OptionDescriptions() @@ -2759,23 +2689,6 @@ bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const OverloadD || overloadData.hasArgumentWithDefaultValue(); } -Generator::Options ShibokenGenerator::getConverterOptions(const AbstractMetaType* metaType) -{ - // exclude const on Objects - Options flags; - const TypeEntry* type = metaType->typeEntry(); - bool isCStr = isCString(metaType); - if (metaType->indirections() && !isCStr) { - flags = ExcludeConst; - } else if (metaType->isContainer() - || (type->isPrimitive() && !isCStr) - // const refs become just the value, but pure refs must remain pure. - || (type->isValue() && metaType->isConstant() && metaType->referenceType() == LValueReference)) { - flags = ExcludeConst | ExcludeReference; - } - return flags; -} - QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg) { if (!arg->defaultValueExpression().isEmpty()) diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h index 3271d741d..cb1bdd11f 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h @@ -106,11 +106,6 @@ public: */ AbstractMetaFunctionList getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName); /** - * Returns the minimun and maximun number of arguments which this function and all overloads - * can accept. Arguments removed by typesystem are considered as well. - */ - QPair<int, int> getMinMaxArguments(const AbstractMetaFunction* metaFunction); - /** * Write a function argument in the C++ in the text stream \p s. * This function just call \code s << argumentString(); \endcode * \param s text stream used to write the output. @@ -197,14 +192,6 @@ public: } /** - * Verifies if any of the function's code injections of the "target" - * type needs the type system variable "%CPPSELF". - * \param func the function to check - * \return true if the function's target code snippets use "%CPPSELF" - */ - bool injectedCodeUsesCppSelf(const AbstractMetaFunction* func); - - /** * Verifies if any of the function's code injections of the "native" * type needs the type system variable "%PYSELF". * \param func the function to check @@ -310,8 +297,6 @@ public: static QString pythonRichCompareOperatorId(QString cppOpFuncName); static QString pythonRichCompareOperatorId(const AbstractMetaFunction* func); - static QString cpythonOperatorFunctionName(const AbstractMetaFunction* func); - static QString fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative); static QString fixedCppTypeName(const AbstractMetaType* type); static QString fixedCppTypeName(const TypeEntry* type, QString typeName = QString()); @@ -321,7 +306,6 @@ public: static bool isNumber(const AbstractMetaType* type); static bool isPyInt(const TypeEntry* type); static bool isPyInt(const AbstractMetaType* type); - static bool isPairContainer(const AbstractMetaType* type); /** * Returns true if the type passed has a Python wrapper for it. @@ -391,7 +375,6 @@ public: QString cpythonIsConvertibleFunction(const TypeEntry* type, bool genericNumberType = false, bool checkExact = false); QString cpythonIsConvertibleFunction(const AbstractMetaType* metaType, bool genericNumberType = false); QString cpythonIsConvertibleFunction(const AbstractMetaArgument* metaArg, bool genericNumberType = false); - QString guessCPythonIsConvertible(const QString& type); QString cpythonToCppConversionFunction(const AbstractMetaClass* metaClass); QString cpythonToCppConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context = 0); @@ -425,15 +408,11 @@ public: /// Returns the special cast function name, the function used to proper cast class with multiple inheritance. QString cpythonSpecialCastFunctionName(const AbstractMetaClass* metaClass); - QString getFunctionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const; QString getFormatUnitString(const AbstractMetaFunction* func, bool incRef = false) const; /// Returns the file name for the module global header. If no module name is provided the current will be used. QString getModuleHeaderFileName(const QString& moduleName = QString()) const; - QString extendedIsConvertibleFunctionName(const TypeEntry* targetType) const; - QString extendedToCppFunctionName(const TypeEntry* targetType) const; - OptionDescriptions options() const override; /// Returns true if the user enabled the so called "parent constructor heuristic". @@ -479,12 +458,6 @@ public: void writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor = QString()); /** - * Helper function to return the flags to be used by a meta type when - * it needs to write some converter code. - */ - static Options getConverterOptions(const AbstractMetaType* metaType); - - /** * Helper function to find for argument default value */ static QString getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg); diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 0e2712ec8..ae6b2a68a 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -545,7 +545,7 @@ void init() PyEval_InitThreads(); //Init private data - Pep_Init(); + Pep384_Init(); Shiboken::ObjectType::initPrivateData(SbkObject_TypeF()); @@ -828,7 +828,14 @@ Py_hash_t hash(PyObject* pyObj) static void setSequenceOwnership(PyObject* pyObj, bool owner) { - if (PySequence_Check(pyObj)) { + + bool has_length = true; + if (PySequence_Size(pyObj) < 0) { + PyErr_Clear(); + has_length = false; + } + + if (PySequence_Check(pyObj) && has_length) { Py_ssize_t size = PySequence_Size(pyObj); if (size > 0) { std::list<SbkObject*> objs = splitPyObject(pyObj); diff --git a/sources/shiboken2/libshiboken/pep384_issue33738.cpp b/sources/shiboken2/libshiboken/pep384_issue33738.cpp new file mode 100644 index 000000000..ee085438e --- /dev/null +++ b/sources/shiboken2/libshiboken/pep384_issue33738.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// There is a bug in Python 3.6 that turned the Index_Check function +// into a macro without taking care of the limited API. +// This leads to the single problem that we don't have +// access to PyLong_Type's nb_index field which is no heap type. +// We cannot easily create this function by inheritance since it is +// not inherited. +// +// Simple solution: Create the structure and write such a function. +// Long term: Submit a patch to python.org . + +// Update: I did the long-term solution for python 3.7 in issue 33738. + +typedef struct { + /* Number implementations must check *both* + arguments for proper type and implement the necessary conversions + in the slot functions themselves. */ + + binaryfunc nb_add; + binaryfunc nb_subtract; + binaryfunc nb_multiply; + binaryfunc nb_remainder; + binaryfunc nb_divmod; + ternaryfunc nb_power; + unaryfunc nb_negative; + unaryfunc nb_positive; + unaryfunc nb_absolute; + inquiry nb_bool; + unaryfunc nb_invert; + binaryfunc nb_lshift; + binaryfunc nb_rshift; + binaryfunc nb_and; + binaryfunc nb_xor; + binaryfunc nb_or; + unaryfunc nb_int; + void *nb_reserved; /* the slot formerly known as nb_long */ + unaryfunc nb_float; + + binaryfunc nb_inplace_add; + binaryfunc nb_inplace_subtract; + binaryfunc nb_inplace_multiply; + binaryfunc nb_inplace_remainder; + ternaryfunc nb_inplace_power; + binaryfunc nb_inplace_lshift; + binaryfunc nb_inplace_rshift; + binaryfunc nb_inplace_and; + binaryfunc nb_inplace_xor; + binaryfunc nb_inplace_or; + + binaryfunc nb_floor_divide; + binaryfunc nb_true_divide; + binaryfunc nb_inplace_floor_divide; + binaryfunc nb_inplace_true_divide; + + unaryfunc nb_index; + + binaryfunc nb_matrix_multiply; + binaryfunc nb_inplace_matrix_multiply; +} PyNumberMethods; + +// temporary structure until we have a generator for the offsets +typedef struct _oldtypeobject { + PyVarObject ob_base; + void *X01; // const char *tp_name; + void *X02; // Py_ssize_t tp_basicsize; + void *X03; // Py_ssize_t tp_itemsize; + void *X04; // destructor tp_dealloc; + void *X05; // printfunc tp_print; + void *X06; // getattrfunc tp_getattr; + void *X07; // setattrfunc tp_setattr; + void *X08; // PyAsyncMethods *tp_as_async; + void *X09; // reprfunc tp_repr; + PyNumberMethods *tp_as_number; + +} PyOldTypeObject; + +int PyIndex_Check(PyObject *obj) +{ + PyOldTypeObject *type = reinterpret_cast<PyOldTypeObject*>(Py_TYPE(obj)); + return type->tp_as_number != NULL && + type->tp_as_number->nb_index != NULL; +} + diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index 2707d3716..dcd844ed6 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -449,94 +449,9 @@ check_PepTypeObject_valid(void) #ifdef Py_LIMITED_API -// This structure is only here because Python 3 has an error. -// I will fix that. - -typedef struct { - /* Number implementations must check *both* - arguments for proper type and implement the necessary conversions - in the slot functions themselves. */ - - binaryfunc nb_add; - binaryfunc nb_subtract; - binaryfunc nb_multiply; - binaryfunc nb_remainder; - binaryfunc nb_divmod; - ternaryfunc nb_power; - unaryfunc nb_negative; - unaryfunc nb_positive; - unaryfunc nb_absolute; - inquiry nb_bool; - unaryfunc nb_invert; - binaryfunc nb_lshift; - binaryfunc nb_rshift; - binaryfunc nb_and; - binaryfunc nb_xor; - binaryfunc nb_or; - unaryfunc nb_int; - void *nb_reserved; /* the slot formerly known as nb_long */ - unaryfunc nb_float; - - binaryfunc nb_inplace_add; - binaryfunc nb_inplace_subtract; - binaryfunc nb_inplace_multiply; - binaryfunc nb_inplace_remainder; - ternaryfunc nb_inplace_power; - binaryfunc nb_inplace_lshift; - binaryfunc nb_inplace_rshift; - binaryfunc nb_inplace_and; - binaryfunc nb_inplace_xor; - binaryfunc nb_inplace_or; - - binaryfunc nb_floor_divide; - binaryfunc nb_true_divide; - binaryfunc nb_inplace_floor_divide; - binaryfunc nb_inplace_true_divide; - - unaryfunc nb_index; - - binaryfunc nb_matrix_multiply; - binaryfunc nb_inplace_matrix_multiply; -} PyNumberMethods; - -// temporary structure until we have a generator for the offsets -typedef struct _oldtypeobject { - PyVarObject ob_base; - void *X01; // const char *tp_name; - void *X02; // Py_ssize_t tp_basicsize; - void *X03; // Py_ssize_t tp_itemsize; - void *X04; // destructor tp_dealloc; - void *X05; // printfunc tp_print; - void *X06; // getattrfunc tp_getattr; - void *X07; // setattrfunc tp_setattr; - void *X08; // PyAsyncMethods *tp_as_async; - void *X09; // reprfunc tp_repr; - PyNumberMethods *tp_as_number; - -} PyOldTypeObject; - -// There is a bug in Python 3.6 that turned the Index_Check function -// into a macro without taking care of the limited API. -// This leads to the single problem that we don't have -// access to PyLong_Type's nb_index field which is no heap type. -// We cannot easily create this function by inheritance since it is -// not inherited. -// -// Simple solution: Create the structure and write such a function. -// Long term: Submit a patch to python.org . - -unaryfunc -PepType_nb_index(PyTypeObject *type) -{ - return reinterpret_cast<PyOldTypeObject*>(type)->tp_as_number->nb_index; -} - -int PyIndex_Check(PyObject *obj) -{ - PyOldTypeObject *type = reinterpret_cast<PyOldTypeObject*>(Py_TYPE(obj)); - return type->tp_as_number != NULL && - type->tp_as_number->nb_index != NULL; -} +#if PY_VERSION_HEX < 0x03070000 +#include "pep384_issue33738.cpp" +#endif /***************************************************************************** * @@ -910,7 +825,7 @@ PepType_GetNameStr(PyTypeObject *type) */ void -Pep_Init() +Pep384_Init() { check_PepTypeObject_valid(); #ifdef Py_LIMITED_API diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h index fc0e3b40e..bfc603f69 100644 --- a/sources/shiboken2/libshiboken/pep384impl.h +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -133,11 +133,14 @@ typedef struct _peptypeobject { } PepTypeObject; -LIBSHIBOKEN_API unaryfunc PepType_nb_index(PyTypeObject *type); - +// This was a macro error in the limited API from the beginning. +// It was fixed in Python 3.7 . +// XXX The commit did go to master, but did not make it to 3.7, yet. +//#if PY_VERSION_HEX < 0x03070000 +#if PY_VERSION_HEX < 0x03080000 #undef PyIndex_Check - LIBSHIBOKEN_API int PyIndex_Check(PyObject *obj); +#endif #undef PyObject_IS_GC #define PyObject_IS_GC(o) (PyType_IS_GC(Py_TYPE(o)) && \ @@ -146,7 +149,6 @@ LIBSHIBOKEN_API int PyIndex_Check(PyObject *obj); #else #define PepTypeObject PyTypeObject -#define PepType_nb_index(o) (PepType(o)->nb_index) #endif // Py_LIMITED_API struct SbkObjectTypePrivate; @@ -309,7 +311,7 @@ typedef struct _methoddescr PyMethodDescrObject; #ifdef Py_LIMITED_API #define Py_TRASH_MIN_COMPATIBLE 0x03020400 -#define Py_TRASH_MAX_COMPATIBLE 0x030700A0 +#define Py_TRASH_MAX_COMPATIBLE 0x0307FFFF #if PY_VERSION_HEX >= Py_TRASH_MIN_COMPATIBLE && \ PY_VERSION_HEX <= Py_TRASH_MAX_COMPATIBLE @@ -383,7 +385,7 @@ LIBSHIBOKEN_API PyObject *PyRun_String(const char *, int, PyObject *, PyObject * // But this is no problem as we check it's validity for every version. #define PYTHON_BUFFER_VERSION_COMPATIBLE (PY_VERSION_HEX >= 0x03030000 && \ - PY_VERSION_HEX < 0X0306FFFF) + PY_VERSION_HEX < 0X0307FFFF) #if !PYTHON_BUFFER_VERSION_COMPATIBLE # error Please check the buffer compatibility for this python version! #endif @@ -564,7 +566,7 @@ extern LIBSHIBOKEN_API PyTypeObject *PepStaticMethod_TypePtr; * */ -LIBSHIBOKEN_API void Pep_Init(void); +LIBSHIBOKEN_API void Pep384_Init(void); } // extern "C" diff --git a/sources/shiboken2/libshiboken/sbkconverter.cpp b/sources/shiboken2/libshiboken/sbkconverter.cpp index d4d3ac899..f1be99a36 100644 --- a/sources/shiboken2/libshiboken/sbkconverter.cpp +++ b/sources/shiboken2/libshiboken/sbkconverter.cpp @@ -391,8 +391,11 @@ bool checkSequenceTypes(PyTypeObject* type, PyObject* pyIn) { assert(type); assert(pyIn); - if (!PySequence_Check(pyIn)) + if (PySequence_Size(pyIn) < 0) { + // clear the error if < 0 which means no length at all + PyErr_Clear(); return false; + } const Py_ssize_t size = PySequence_Size(pyIn); for (Py_ssize_t i = 0; i < size; ++i) { if (!PyObject_TypeCheck(AutoDecRef(PySequence_GetItem(pyIn, i)), type)) diff --git a/sources/shiboken2/libshiboken/sbkpython.h b/sources/shiboken2/libshiboken/sbkpython.h index 5fe364a29..a26c318d1 100644 --- a/sources/shiboken2/libshiboken/sbkpython.h +++ b/sources/shiboken2/libshiboken/sbkpython.h @@ -76,7 +76,6 @@ #define SbkNumber_Check(X) \ (PyNumber_Check(X) && (!PyInstance_Check(X) || PyObject_HasAttrString(X, "__trunc__"))) #define SBK_NB_BOOL(x) (x).nb_nonzero - #define SBK_STR_NAME "str" #define SBK_PyMethod_New(X, Y) PyMethod_New(X, Y, reinterpret_cast<PyObject *>(Py_TYPE(Y))) #define Py_hash_t long diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp index b92674383..6ca35f12e 100644 --- a/sources/shiboken2/libshiboken/sbkstring.cpp +++ b/sources/shiboken2/libshiboken/sbkstring.cpp @@ -99,18 +99,24 @@ const char* toCString(PyObject* str, Py_ssize_t* len) { if (str == Py_None) return NULL; -#ifdef IS_PY3K if (PyUnicode_Check(str)) { if (len) { // We need to encode the unicode string into utf8 to know the size of returned char*. Shiboken::AutoDecRef uniStr(PyUnicode_AsUTF8String(str)); *len = PyBytes_GET_SIZE(uniStr.object()); } +#ifdef IS_PY3K // Return unicode from str instead of uniStr, because the lifetime of the returned pointer // depends on the lifetime of str. return _PepUnicode_AsString(str); - } +#else + str = PyUnicode_AsUTF8String(str); + if (str == NULL) { + return NULL; + } + return PyString_AsString(str); #endif + } if (PyBytes_Check(str)) { if (len) *len = PyBytes_GET_SIZE(str); diff --git a/sources/shiboken2/libshiboken/sbkstring.h b/sources/shiboken2/libshiboken/sbkstring.h index d437f1c77..a6b5fbeed 100644 --- a/sources/shiboken2/libshiboken/sbkstring.h +++ b/sources/shiboken2/libshiboken/sbkstring.h @@ -44,9 +44,9 @@ #include "shibokenmacros.h" #if PY_MAJOR_VERSION >= 3 - #define SBK_STR_NAME "unicode" + #define SBK_BYTES_NAME "bytes" #else - #define SBK_STR_NAME "str" + #define SBK_BYTES_NAME "str" #endif namespace Shiboken diff --git a/sources/shiboken2/libshiboken/voidptr.cpp b/sources/shiboken2/libshiboken/voidptr.cpp index afb3f4040..94c667598 100644 --- a/sources/shiboken2/libshiboken/voidptr.cpp +++ b/sources/shiboken2/libshiboken/voidptr.cpp @@ -55,8 +55,13 @@ typedef struct { PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - SbkVoidPtrObject *self = - reinterpret_cast<SbkVoidPtrObject *>(PepType(type)->tp_alloc); + // PYSIDE-560: It is much safer to first call a function and then do a + // type cast than to do everything in one line. The bad construct looked + // like this, actual call forgotten: + // SbkVoidPtrObject *self = + // reinterpret_cast<SbkVoidPtrObject *>(PepType(type)->tp_alloc); + PyObject *ob = PepType(type)->tp_alloc(type, 0); + SbkVoidPtrObject *self = reinterpret_cast<SbkVoidPtrObject *>(ob); if (self != 0) { self->cptr = 0; diff --git a/sources/shiboken2/tests/dumpcodemodel/main.cpp b/sources/shiboken2/tests/dumpcodemodel/main.cpp index 997e13511..e132c97b3 100644 --- a/sources/shiboken2/tests/dumpcodemodel/main.cpp +++ b/sources/shiboken2/tests/dumpcodemodel/main.cpp @@ -28,6 +28,7 @@ #include <abstractmetabuilder_p.h> #include <parser/codemodel.h> +#include <clangparser/compilersupport.h> #include <QtCore/QCoreApplication> #include <QtCore/QCommandLineOption> @@ -40,6 +41,13 @@ #include <algorithm> #include <iterator> +static inline QString languageLevelDescription() +{ + return QLatin1String("C++ Language level (c++11..c++17, default=") + + QLatin1String(clang::languageLevelOption(clang::emulatedCompilerLanguageLevel())) + + QLatin1Char(')'); +} + int main(int argc, char **argv) { QCoreApplication app(argc, argv); @@ -52,6 +60,10 @@ int main(int argc, char **argv) QCommandLineOption verboseOption(QStringLiteral("d"), QStringLiteral("Display verbose output about types")); parser.addOption(verboseOption); + QCommandLineOption languageLevelOption(QStringLiteral("std"), + languageLevelDescription(), + QStringLiteral("level")); + parser.addOption(languageLevelOption); parser.addPositionalArgument(QStringLiteral("file"), QStringLiteral("C++ source file")); parser.process(app); @@ -62,7 +74,19 @@ int main(int argc, char **argv) QByteArrayList arguments; std::transform(positionalArguments.cbegin(), positionalArguments.cend(), std::back_inserter(arguments), QFile::encodeName); - const FileModelItem dom = AbstractMetaBuilderPrivate::buildDom(arguments, 0); + + LanguageLevel level = LanguageLevel::Default; + if (parser.isSet(languageLevelOption)) { + const QByteArray value = parser.value(languageLevelOption).toLatin1(); + level = clang::languageLevelFromOption(value.constData()); + if (level == LanguageLevel::Default) { + std::cerr << "Invalid value \"" << value.constData() + << "\" for language level option.\n"; + return -2; + } + } + + const FileModelItem dom = AbstractMetaBuilderPrivate::buildDom(arguments, level, 0); if (dom.isNull()) { QString message = QLatin1String("Unable to parse ") + positionalArguments.join(QLatin1Char(' ')); std::cerr << qPrintable(message) << '\n'; |