aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2')
-rw-r--r--sources/shiboken2/ApiExtractor/CMakeLists.txt1
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp698
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.h14
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h45
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp398
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h99
-rw-r--r--sources/shiboken2/ApiExtractor/apiextractor.cpp34
-rw-r--r--sources/shiboken2/ApiExtractor/apiextractor.h3
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp236
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp2
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp49
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangutils.h13
-rw-r--r--sources/shiboken2/ApiExtractor/doc/conf.py.in4
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst50
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst65
-rw-r--r--sources/shiboken2/ApiExtractor/docparser.cpp79
-rw-r--r--sources/shiboken2/ApiExtractor/docparser.h16
-rw-r--r--sources/shiboken2/ApiExtractor/doxygenparser.cpp30
-rw-r--r--sources/shiboken2/ApiExtractor/fileout.cpp180
-rw-r--r--sources/shiboken2/ApiExtractor/fileout.h15
-rw-r--r--sources/shiboken2/ApiExtractor/include.cpp5
-rw-r--r--sources/shiboken2/ApiExtractor/include.h3
-rw-r--r--sources/shiboken2/ApiExtractor/messages.cpp446
-rw-r--r--sources/shiboken2/ApiExtractor/messages.h142
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel.cpp222
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel.h54
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel_enums.h13
-rw-r--r--sources/shiboken2/ApiExtractor/parser/enumvalue.h1
-rw-r--r--sources/shiboken2/ApiExtractor/qtdocparser.cpp1
-rw-r--r--sources/shiboken2/ApiExtractor/tests/CMakeLists.txt17
-rw-r--r--sources/shiboken2/ApiExtractor/tests/injectedcode.txt5
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp37
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp3
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp45
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcodeinjection.h3
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcodeinjection.qrc6
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp6
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testenum.cpp3
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.qrc5
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp99
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp3
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtemplates.cpp119
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtemplates.h2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp49
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtyperevision.h2
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testutil.h11
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase.cpp379
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase.h28
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase_typedefs.h25
-rw-r--r--sources/shiboken2/ApiExtractor/typeparser.cpp57
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.cpp3764
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.h366
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem_enums.h21
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem_p.h112
-rw-r--r--sources/shiboken2/CMakeLists.txt5
-rw-r--r--sources/shiboken2/doc/commandlineoptions.rst110
-rw-r--r--sources/shiboken2/generator/CMakeLists.txt30
-rw-r--r--sources/shiboken2/generator/__init__.py.in2
-rw-r--r--sources/shiboken2/generator/_config.py.in9
-rw-r--r--sources/shiboken2/generator/generator.cpp408
-rw-r--r--sources/shiboken2/generator/generator.h182
-rw-r--r--sources/shiboken2/generator/main.cpp329
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp132
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.h6
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp670
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.h15
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.cpp145
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.h4
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.cpp18
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.h2
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp451
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.h284
-rw-r--r--sources/shiboken2/libshiboken/autodecref.h29
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp360
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.h8
-rw-r--r--sources/shiboken2/libshiboken/basewrapper_p.h106
-rw-r--r--sources/shiboken2/libshiboken/bindingmanager.cpp49
-rw-r--r--sources/shiboken2/libshiboken/bindingmanager.h13
-rw-r--r--sources/shiboken2/libshiboken/gilstate.h5
-rw-r--r--sources/shiboken2/libshiboken/helper.cpp26
-rw-r--r--sources/shiboken2/libshiboken/helper.h11
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.cpp27
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.h8
-rw-r--r--sources/shiboken2/libshiboken/sbkconverter.cpp8
-rw-r--r--sources/shiboken2/libshiboken/sbkconverter_p.h6
-rw-r--r--sources/shiboken2/libshiboken/sbkdbg.h5
-rw-r--r--sources/shiboken2/libshiboken/sbkenum.cpp36
-rw-r--r--sources/shiboken2/libshiboken/sbkpython.h58
-rw-r--r--sources/shiboken2/libshiboken/sbkstring.cpp5
-rw-r--r--sources/shiboken2/libshiboken/shibokenbuffer.cpp4
-rw-r--r--sources/shiboken2/libshiboken/signature.cpp291
-rw-r--r--sources/shiboken2/libshiboken/signature.h6
-rw-r--r--sources/shiboken2/libshiboken/threadstatesaver.h8
-rw-r--r--sources/shiboken2/libshiboken/typespec.cpp45
-rw-r--r--sources/shiboken2/libshiboken/typespec.h4
-rwxr-xr-xsources/shiboken2/shiboken_tool.py53
-rw-r--r--sources/shiboken2/shiboken_version.py14
-rw-r--r--sources/shiboken2/shibokenmodule/CMakeLists.txt27
-rw-r--r--sources/shiboken2/shibokenmodule/__init__.py.in4
-rw-r--r--sources/shiboken2/shibokenmodule/_config.py.in11
-rw-r--r--sources/shiboken2/tests/libsample/CMakeLists.txt1
-rw-r--r--sources/shiboken2/tests/libsample/exceptiontest.cpp64
-rw-r--r--sources/shiboken2/tests/libsample/exceptiontest.h48
-rw-r--r--sources/shiboken2/tests/libsample/mapuser.cpp5
-rw-r--r--sources/shiboken2/tests/libsample/mapuser.h2
-rw-r--r--sources/shiboken2/tests/libsample/nontypetemplate.h51
-rw-r--r--sources/shiboken2/tests/libsample/objecttype.cpp1
-rw-r--r--sources/shiboken2/tests/libsample/objecttype.h2
-rw-r--r--sources/shiboken2/tests/libsample/samplenamespace.cpp7
-rw-r--r--sources/shiboken2/tests/libsample/samplenamespace.h6
-rw-r--r--sources/shiboken2/tests/minimalbinding/CMakeLists.txt5
-rw-r--r--sources/shiboken2/tests/otherbinding/CMakeLists.txt5
-rw-r--r--sources/shiboken2/tests/samplebinding/CMakeLists.txt8
-rw-r--r--sources/shiboken2/tests/samplebinding/exception_test.py78
-rw-r--r--sources/shiboken2/tests/samplebinding/global.h2
-rw-r--r--sources/shiboken2/tests/samplebinding/nontypetemplate_test.py44
-rw-r--r--sources/shiboken2/tests/samplebinding/typesystem_sample.xml9
-rw-r--r--sources/shiboken2/tests/smartbinding/CMakeLists.txt5
121 files changed, 7948 insertions, 4515 deletions
diff --git a/sources/shiboken2/ApiExtractor/CMakeLists.txt b/sources/shiboken2/ApiExtractor/CMakeLists.txt
index b67a352f0..b4fd1cb99 100644
--- a/sources/shiboken2/ApiExtractor/CMakeLists.txt
+++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt
@@ -37,6 +37,7 @@ abstractmetabuilder.cpp
abstractmetalang.cpp
fileout.cpp
graph.cpp
+messages.cpp
reporthandler.cpp
typeparser.cpp
typesystem.cpp
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
index 84c116708..9653831cc 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
@@ -27,6 +27,7 @@
****************************************************************************/
#include "abstractmetabuilder_p.h"
+#include "messages.h"
#include "reporthandler.h"
#include "typedatabase.h"
@@ -159,38 +160,18 @@ AbstractMetaEnumList AbstractMetaBuilder::globalEnums() const
return d->m_globalEnums;
}
-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 << '\'';
- 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: ";
- for (int f = 0, size = allFunctions.size(); f < size; ++f) {
- if (f)
- str << ", ";
- str << allFunctions.at(f)->minimalSignature();
- }
- } else {
- str << " Possible candidates: " << possibleSignatures.join(QLatin1String(", "));
- }
- return result;
+AbstractMetaEnum *AbstractMetaBuilder::findEnum(const TypeEntry *typeEntry) const
+{
+ if (typeEntry && typeEntry->isFlags())
+ typeEntry = static_cast<const FlagsTypeEntry*>(typeEntry)->originator();
+ return d->m_enums.value(typeEntry);
}
void AbstractMetaBuilderPrivate::checkFunctionModifications()
{
- TypeDatabase *types = TypeDatabase::instance();
- const SingleTypeEntryHash entryHash = types->entries();
+ const auto &entries = TypeDatabase::instance()->entries();
- for (SingleTypeEntryHash::const_iterator it = entryHash.cbegin(), end = entryHash.cend(); it != end; ++it) {
+ for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
const TypeEntry *entry = it.value();
if (!entry)
continue;
@@ -241,7 +222,7 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications()
}
}
-AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(ArgumentModelItem argument)
+AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument)
{
AbstractMetaClass* returned = 0;
AbstractMetaType *type = translateType(argument->type());
@@ -256,7 +237,7 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(ArgumentModelItem
/**
* Checks the argument of a hash function and flags the type if it is a complex type
*/
-void AbstractMetaBuilderPrivate::registerHashFunction(FunctionModelItem function_item)
+void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &function_item)
{
ArgumentList arguments = function_item->arguments();
if (arguments.size() == 1) {
@@ -269,12 +250,12 @@ void AbstractMetaBuilderPrivate::registerHashFunction(FunctionModelItem function
* Check if a class has a debug stream operator that can be used as toString
*/
-void AbstractMetaBuilderPrivate::registerToStringCapability(FunctionModelItem function_item)
+void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelItem &function_item)
{
ArgumentList arguments = function_item->arguments();
if (arguments.size() == 2) {
if (arguments.at(0)->type().toString() == QLatin1String("QDebug")) {
- ArgumentModelItem arg = arguments.at(1);
+ const ArgumentModelItem &arg = arguments.at(1);
if (AbstractMetaClass *cls = argumentToClass(arg)) {
if (arg->type().indirections() < 2)
cls->setToStringCapability(true);
@@ -283,7 +264,7 @@ void AbstractMetaBuilderPrivate::registerToStringCapability(FunctionModelItem fu
}
}
-void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item)
+void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelItem &item)
{
if (item->accessPolicy() != CodeModel::Public)
return;
@@ -348,7 +329,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item
setupFunctionDefaults(metaFunction, baseoperandClass);
baseoperandClass->addFunction(metaFunction);
Q_ASSERT(!metaFunction->wasPrivate());
- } else if (metaFunction) {
+ } else {
delete metaFunction;
}
@@ -356,7 +337,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item
}
}
-void AbstractMetaBuilderPrivate::traverseStreamOperator(FunctionModelItem item)
+void AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem &item)
{
ArgumentList arguments = item->arguments();
if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) {
@@ -404,7 +385,7 @@ void AbstractMetaBuilderPrivate::traverseStreamOperator(FunctionModelItem item)
funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include());
m_currentClass = oldCurrentClass;
- } else if (streamFunction) {
+ } else {
delete streamFunction;
}
@@ -422,7 +403,7 @@ void AbstractMetaBuilderPrivate::fixQObjectForScope(const FileModelItem &dom,
TypeEntry* entry = types->findType(qualifiedName);
if (entry) {
if (isQObject(dom, qualifiedName) && entry->isComplex())
- ((ComplexTypeEntry*) entry)->setQObject(true);
+ static_cast<ComplexTypeEntry *>(entry)->setQObject(true);
}
}
@@ -475,19 +456,18 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
const ClassList &typeValues = dom->classes();
ReportHandler::setProgressReference(typeValues);
for (const ClassModelItem &item : typeValues) {
- ReportHandler::progress(QLatin1String("Generating class model..."));
- AbstractMetaClass *cls = traverseClass(dom, item);
- if (!cls)
- continue;
-
- addAbstractMetaClass(cls);
+ ReportHandler::progress(QStringLiteral("Generating class model (%1)...")
+ .arg(typeValues.size()));
+ if (AbstractMetaClass *cls = traverseClass(dom, item))
+ addAbstractMetaClass(cls);
}
// We need to know all global enums
const EnumList &enums = dom->enums();
ReportHandler::setProgressReference(enums);
for (const EnumModelItem &item : enums) {
- ReportHandler::progress(QLatin1String("Generating enum model..."));
+ ReportHandler::progress(QStringLiteral("Generating enum model (%1)...")
+ .arg(enums.size()));
AbstractMetaEnum *metaEnum = traverseEnum(item, 0, QSet<QString>());
if (metaEnum) {
if (metaEnum->typeEntry()->generateCode())
@@ -498,7 +478,8 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
const QSet<NamespaceModelItem> &namespaceTypeValues = dom->uniqueNamespaces();
ReportHandler::setProgressReference(namespaceTypeValues);
for (const NamespaceModelItem &item : namespaceTypeValues) {
- ReportHandler::progress(QLatin1String("Generating namespace model..."));
+ ReportHandler::progress(QStringLiteral("Generating namespace model (%1)...")
+ .arg(namespaceTypeValues.size()));
AbstractMetaClass *metaClass = traverseNamespace(dom, item);
if (metaClass)
m_metaClasses << metaClass;
@@ -509,11 +490,14 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
const TypeDefList typeDefs = dom->typeDefs();
ReportHandler::setProgressReference(typeDefs);
for (const TypeDefModelItem &typeDef : typeDefs) {
- ReportHandler::progress(QLatin1String("Resolving typedefs..."));
- AbstractMetaClass* cls = traverseTypeDef(dom, typeDef);
- addAbstractMetaClass(cls);
+ ReportHandler::progress(QStringLiteral("Resolving typedefs (%1)...")
+ .arg(typeDefs.size()));
+ if (AbstractMetaClass *cls = traverseTypeDef(dom, typeDef))
+ addAbstractMetaClass(cls);
}
+ traverseTypesystemTypedefs();
+
for (const ClassModelItem &item : typeValues)
traverseClassMembers(item);
@@ -580,13 +564,12 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
if (cls->isAbstract() && !cls->isInterface())
cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + QLatin1String("$ConcreteWrapper"));
}
- const TypeEntryHash allEntries = types->allEntries();
- ReportHandler::progress(QLatin1String("Detecting inconsistencies in typesystem..."));
- for (TypeEntryHash::const_iterator it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
- for (TypeEntry *entry : it.value()) {
- if (entry->isPrimitive())
- continue;
-
+ const auto &allEntries = types->entries();
+ ReportHandler::progress(QStringLiteral("Detecting inconsistencies in typesystem (%1)...")
+ .arg(allEntries.size()));
+ for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
+ TypeEntry *entry = it.value();
+ if (!entry->isPrimitive()) {
if ((entry->isValue() || entry->isObject())
&& !entry->isString()
&& !entry->isChar()
@@ -616,20 +599,13 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
}
}
} else if (entry->isEnum() && (entry->generateCode() & TypeEntry::GenerateTargetLang)) {
- const QString name = ((EnumTypeEntry*) entry)->targetLangQualifier();
+ const QString name = static_cast<const EnumTypeEntry *>(entry)->targetLangQualifier();
AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, name);
- bool enumFound = false;
- if (cls) {
- enumFound = cls->findEnum(entry->targetLangName());
- } else { // Global enum
- for (AbstractMetaEnum *metaEnum : qAsConst(m_enums)) {
- if (metaEnum->typeEntry() == entry) {
- enumFound = true;
- break;
- }
- }
- }
+ const bool enumFound = cls
+ ? cls->findEnum(entry->targetLangName()) != nullptr
+ : m_enums.contains(entry);
+
if (!enumFound) {
entry->setCodeGeneration(TypeEntry::GenerateNothing);
qCWarning(lcShiboken).noquote().nospace()
@@ -727,6 +703,15 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
std::puts("");
}
+static bool metaEnumLessThan(const AbstractMetaEnum *e1, const AbstractMetaEnum *e2)
+{ return e1->fullName() < e2->fullName(); }
+
+static bool metaClassLessThan(const AbstractMetaClass *c1, const AbstractMetaClass *c2)
+{ return c1->fullName() < c2->fullName(); }
+
+static bool metaFunctionLessThan(const AbstractMetaFunction *f1, const AbstractMetaFunction *f2)
+{ return f1->name() < f2->name(); }
+
bool AbstractMetaBuilder::build(const QByteArrayList &arguments,
LanguageLevel level,
unsigned clangFlags)
@@ -737,6 +722,14 @@ bool AbstractMetaBuilder::build(const QByteArrayList &arguments,
if (ReportHandler::isDebug(ReportHandler::MediumDebug))
qCDebug(lcShiboken) << dom.data();
d->traverseDom(dom);
+
+ // Ensure that indexes are in alphabetical order, roughly
+ std::sort(d->m_globalEnums.begin(), d->m_globalEnums.end(), metaEnumLessThan);
+ std::sort(d->m_metaClasses.begin(), d->m_metaClasses.end(), metaClassLessThan);
+ std::sort(d->m_templates.begin(), d->m_templates.end(), metaClassLessThan);
+ std::sort(d->m_smartPointers.begin(), d->m_smartPointers.end(), metaClassLessThan);
+ std::sort(d->m_globalFunctions.begin(), d->m_globalFunctions.end(), metaFunctionLessThan);
+
return true;
}
@@ -749,9 +742,6 @@ void AbstractMetaBuilder::setLogDirectory(const QString& logDir)
void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls)
{
- if (!cls)
- return;
-
cls->setOriginalAttributes(cls->attributes());
if (cls->typeEntry()->isContainer()) {
m_templates << cls;
@@ -848,7 +838,7 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel
return metaClass;
}
-AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumItem,
+AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem &enumItem,
AbstractMetaClass *enclosing,
const QSet<QString> &enumsDeclarations)
{
@@ -857,7 +847,7 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte
TypeEntry* typeEntry = 0;
if (enumItem->accessPolicy() == CodeModel::Private) {
QStringList names = enumItem->qualifiedName();
- QString enumName = names.constLast();
+ const QString &enumName = names.constLast();
QString nspace;
if (names.size() > 1)
nspace = QStringList(names.mid(0, names.size() - 1)).join(colonColon());
@@ -892,15 +882,23 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte
return 0;
}
- if ((!typeEntry || !typeEntry->isEnum())) {
- if (!m_currentClass ||
- (m_currentClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("enum '%1' does not have a type entry or is not an enum")
- .arg(qualifiedName);
+ const bool rejectionWarning = !m_currentClass
+ || (m_currentClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang);
+
+ if (!typeEntry) {
+ if (rejectionWarning)
+ qCWarning(lcShiboken, "%s", qPrintable(msgNoEnumTypeEntry(enumItem, className)));
+ m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem);
+ return nullptr;
+ }
+
+ if (!typeEntry->isEnum()) {
+ if (rejectionWarning) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgNoEnumTypeConflict(enumItem, className, typeEntry)));
}
m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem);
- return 0;
+ return nullptr;
}
AbstractMetaEnum *metaEnum = new AbstractMetaEnum;
@@ -946,15 +944,9 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte
qCDebug(lcShiboken) << " - " << metaEnumValue->name() << " = "
<< metaEnumValue->value() << " = " << metaEnumValue->value();
}
-
- // Add into global register...
- if (enclosing)
- m_enumValues[enclosing->name() + colonColon() + metaEnumValue->name()] = metaEnumValue;
- else
- m_enumValues[metaEnumValue->name()] = metaEnumValue;
}
- m_enums << metaEnum;
+ m_enums.insert(typeEntry, metaEnum);
if (!metaEnum->typeEntry()->include().isValid())
setInclude(metaEnum->typeEntry(), enumItem->fileName());
@@ -962,6 +954,15 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte
metaEnum->setOriginalAttributes(metaEnum->attributes());
// Register all enum values on Type database
+ QString prefix;
+ if (enclosing) {
+ prefix += enclosing->typeEntry()->qualifiedCppName();
+ prefix += colonColon();
+ }
+ if (enumItem->enumKind() == EnumClass) {
+ prefix += enumItem->name();
+ prefix += colonColon();
+ }
const EnumeratorList &enumerators = enumItem->enumerators();
for (const EnumeratorModelItem &e : enumerators) {
QString name;
@@ -969,11 +970,12 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte
name += enclosing->name();
name += colonColon();
}
- name += e->name();
EnumValueTypeEntry *enumValue =
- new EnumValueTypeEntry(name, e->stringValue(),
+ new EnumValueTypeEntry(prefix + e->name(), e->stringValue(),
enumTypeEntry, enumTypeEntry->version());
TypeDatabase::instance()->addType(enumValue);
+ if (e->value().isNullValue())
+ enumTypeEntry->setNullValue(enumValue);
}
return metaEnum;
@@ -1014,7 +1016,7 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelIt
AbstractMetaClass *metaClass = new AbstractMetaClass;
metaClass->setTypeDef(true);
metaClass->setTypeEntry(type);
- metaClass->setBaseClassNames(QStringList() << typeDef->type().qualifiedName().join(colonColon()));
+ metaClass->setBaseClassNames(QStringList(typeDef->type().toString()));
*metaClass += AbstractMetaAttributes::Public;
// Set the default include file name
@@ -1026,6 +1028,22 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelIt
return metaClass;
}
+// Add the typedef'ed classes
+void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs()
+{
+ const auto &entries = TypeDatabase::instance()->typedefEntries();
+ for (auto it = entries.begin(), end = entries.end(); it != end; ++it) {
+ TypedefEntry *te = it.value();
+ AbstractMetaClass *metaClass = new AbstractMetaClass;
+ metaClass->setTypeDef(true);
+ metaClass->setTypeEntry(te->target());
+ metaClass->setBaseClassNames(QStringList(te->sourceType()));
+ *metaClass += AbstractMetaAttributes::Public;
+ fillAddedFunctions(metaClass);
+ addAbstractMetaClass(metaClass);
+ }
+}
+
AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom,
const ClassModelItem &classItem)
{
@@ -1204,18 +1222,18 @@ void AbstractMetaBuilderPrivate::traverseNamespaceMembers(NamespaceModelItem ite
m_currentClass = oldCurrentClass;
}
-static inline QString fieldSignatureWithType(VariableModelItem field)
+static inline QString fieldSignatureWithType(const VariableModelItem &field)
{
return field->name() + QStringLiteral(" -> ") + field->type().toString();
}
static inline QString qualifiedFieldSignatureWithType(const QString &className,
- VariableModelItem field)
+ const VariableModelItem &field)
{
return className + colonColon() + fieldSignatureWithType(field);
}
-AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(VariableModelItem field,
+AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(const VariableModelItem &field,
const AbstractMetaClass *cls)
{
QString fieldName = field->name();
@@ -1272,7 +1290,7 @@ AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(VariableModelItem f
return metaField;
}
-void AbstractMetaBuilderPrivate::traverseFields(ScopeModelItem scope_item,
+void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item,
AbstractMetaClass *metaClass)
{
const VariableList &variables = scope_item->variables();
@@ -1327,14 +1345,8 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF
static bool _compareAbstractMetaTypes(const AbstractMetaType* type, const AbstractMetaType* other)
{
- if (!type && !other)
- return true;
- if (!type || !other)
- return false;
- return type->typeEntry() == other->typeEntry()
- && type->isConstant() == other->isConstant()
- && type->referenceType() == other->referenceType()
- && type->indirections() == other->indirections();
+ return (type != nullptr) == (other != nullptr)
+ && (type == nullptr || *type == *other);
}
static bool _compareAbstractMetaFunctions(const AbstractMetaFunction* func, const AbstractMetaFunction* other)
@@ -1426,7 +1438,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem,
}
} else if (QPropertySpec* reset = metaClass->propertySpecForReset(metaFunction->name())) {
// Property resetter must be in the form "void name()"
- if ((!metaFunction->type()) && (metaFunction->arguments().size() == 0)) {
+ if ((!metaFunction->type()) && metaFunction->arguments().isEmpty()) {
*metaFunction += AbstractMetaAttributes::PropertyResetter;
metaFunction->setPropertySpec(reset);
}
@@ -1635,7 +1647,7 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass)
return true;
}
-void AbstractMetaBuilderPrivate::traverseEnums(ScopeModelItem scopeItem,
+void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem,
AbstractMetaClass *metaClass,
const QStringList &enumsDeclarations)
{
@@ -1724,13 +1736,9 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu
replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1);
if (!replacedExpression.isEmpty()) {
- QString expr = replacedExpression;
if (!metaFunction->removedDefaultExpression(m_currentClass, i + 1)) {
- metaArg->setDefaultValueExpression(expr);
- metaArg->setOriginalDefaultValueExpression(expr);
-
- if (metaArg->type()->isEnum() || metaArg->type()->isFlags())
- m_enumDefaultArguments << QPair<AbstractMetaArgument*, AbstractMetaFunction*>(metaArg, metaFunction);
+ metaArg->setDefaultValueExpression(replacedExpression);
+ metaArg->setOriginalDefaultValueExpression(replacedExpression);
}
}
}
@@ -1784,7 +1792,7 @@ void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func, co
}
}
-static QString functionSignature(FunctionModelItem functionItem)
+static QString functionSignature(const FunctionModelItem &functionItem)
{
QStringList args;
const ArgumentList &arguments = functionItem->arguments();
@@ -1802,50 +1810,6 @@ static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem
result += functionSignature(functionItem);
return result;
}
-
-static inline QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n)
-{
- QString result;
- QTextStream str(&result);
- str << "unmatched type '" << arg->type().toString() << "' in parameter #"
- << (n + 1);
- if (!arg->name().isEmpty())
- str << " \"" << arg->name() << '"';
- return result;
-}
-
-static inline QString msgUnmatchedReturnType(const FunctionModelItem &functionItem)
-{
- return QLatin1String("unmatched return type '")
- + functionItem->type().toString() + QLatin1Char('\'');
-}
-
-static inline QString msgVoidParameterType(const ArgumentModelItem &arg, int n)
-{
- QString result;
- QTextStream str(&result);
- str << "'void' encountered at parameter #" << (n + 1);
- if (!arg->name().isEmpty())
- str << " \"" << arg->name() << '"';
- return result;
-}
-
-static QString msgSkippingFunction(const FunctionModelItem &functionItem,
- const QString &signature, const QString &why)
-{
- QString result;
- QTextStream str(&result);
- str << "skipping ";
- if (functionItem->isAbstract())
- str << "abstract ";
- str << "function '" << signature << "', " << why;
- if (functionItem->isAbstract()) {
- str << "\nThis will lead to compilation errors due to not "
- "being able to instantiate the wrapper.";
- }
- return result;
-}
-
static inline AbstractMetaFunction::FunctionType functionTypeFromCodeModel(CodeModel::FunctionType ft)
{
AbstractMetaFunction::FunctionType result = AbstractMetaFunction::NormalFunction;
@@ -1874,12 +1838,6 @@ static inline AbstractMetaFunction::FunctionType functionTypeFromCodeModel(CodeM
return result;
}
-static inline QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason)
-{
- return function + QLatin1String(": Cannot use parameter ") + QString::number(i + 1)
- + QLatin1String(" as an array: ") + reason;
-}
-
bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func,
const FunctionModelItem &functionItem,
int i)
@@ -1911,12 +1869,40 @@ bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func
return true;
}
-AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModelItem functionItem)
+static bool generateExceptionHandling(const AbstractMetaFunction *func,
+ ExceptionSpecification spec,
+ TypeSystem::ExceptionHandling handling)
+{
+ switch (func->functionType()) {
+ case AbstractMetaFunction::CopyConstructorFunction:
+ case AbstractMetaFunction::MoveConstructorFunction:
+ case AbstractMetaFunction::AssignmentOperatorFunction:
+ case AbstractMetaFunction::MoveAssignmentOperatorFunction:
+ case AbstractMetaFunction::DestructorFunction:
+ return false;
+ default:
+ break;
+ }
+ switch (handling) {
+ case TypeSystem::ExceptionHandling::On:
+ return true;
+ case TypeSystem::ExceptionHandling::AutoDefaultToOn:
+ return spec != ExceptionSpecification::NoExcept;
+ case TypeSystem::ExceptionHandling::AutoDefaultToOff:
+ return spec == ExceptionSpecification::Throws;
+ default:
+ break;
+ }
+ return false;
+}
+
+AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem)
{
if (functionItem->isDeleted() || !functionItem->templateParameters().isEmpty())
return nullptr;
QString functionName = functionItem->name();
QString className;
+ TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
if (m_currentClass) {
// Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT
// and overridden metaObject(), QGADGET helpers
@@ -1925,6 +1911,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
return nullptr;
}
className = m_currentClass->typeEntry()->qualifiedCppName();
+ exceptionHandling = m_currentClass->typeEntry()->exceptionHandling();
if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject"))
return nullptr;
}
@@ -1936,13 +1923,16 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
QString rejectReason;
if (TypeDatabase::instance()->isFunctionRejected(className, functionName, &rejectReason)) {
m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
- return 0;
- }
- else if (TypeDatabase::instance()->isFunctionRejected(className,
- functionSignature(functionItem), &rejectReason)) {
- m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
- return 0;
+ return nullptr;
}
+ const QString &signature = functionSignature(functionItem);
+ const bool rejected =
+ TypeDatabase::instance()->isFunctionRejected(className, signature, &rejectReason);
+ qCDebug(lcShiboken).nospace().noquote() << __FUNCTION__
+ << ": Checking rejection for signature \"" << signature << "\" for " << className
+ << ": " << rejected;
+ if (rejected)
+ return nullptr;
if (functionItem->isFriend())
return 0;
@@ -1951,6 +1941,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
// Additional check for assignment/move assignment down below
metaFunction->setFunctionType(functionTypeFromCodeModel(functionItem->functionType()));
metaFunction->setConstant(functionItem->isConstant());
+ metaFunction->setExceptionSpecification(functionItem->exceptionSpecification());
if (ReportHandler::isDebug(ReportHandler::MediumDebug))
qCDebug(lcShiboken).noquote().nospace() << " - " << functionName << "()";
@@ -1987,6 +1978,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
else
*metaFunction += AbstractMetaAttributes::Protected;
+ QString errorMessage;
switch (metaFunction->functionType()) {
case AbstractMetaFunction::DestructorFunction:
break;
@@ -2005,9 +1997,9 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
AbstractMetaType *type = nullptr;
if (!returnType.isVoid()) {
- type = translateType(returnType);
+ type = translateType(returnType, true, &errorMessage);
if (!type) {
- const QString reason = msgUnmatchedReturnType(functionItem);
+ const QString reason = msgUnmatchedReturnType(functionItem, errorMessage);
qCWarning(lcShiboken, "%s",
qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason)));
m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType);
@@ -2033,7 +2025,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
AbstractMetaArgumentList metaArguments;
for (int i = 0; i < arguments.size(); ++i) {
- ArgumentModelItem arg = arguments.at(i);
+ const ArgumentModelItem &arg = arguments.at(i);
if (TypeDatabase::instance()->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) {
m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
@@ -2041,7 +2033,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
return nullptr;
}
- AbstractMetaType *metaType = translateType(arg->type());
+ AbstractMetaType *metaType = translateType(arg->type(), true, &errorMessage);
if (!metaType) {
// If an invalid argument has a default value, simply remove it
if (arg->defaultValue()) {
@@ -2058,18 +2050,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
break;
}
Q_ASSERT(metaType == 0);
- const QString reason = msgUnmatchedParameterType(arg, i);
- qCWarning(lcShiboken, "%s",
- qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason)));
- const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn
- + QLatin1String(": ") + reason;
- m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType);
- delete metaFunction;
- return nullptr;
- }
-
- if (metaType == Q_NULLPTR) {
- const QString reason = msgVoidParameterType(arg, i);
+ const QString reason = msgUnmatchedParameterType(arg, i, errorMessage);
qCWarning(lcShiboken, "%s",
qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason)));
const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn
@@ -2089,9 +2070,22 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
metaFunction->setArguments(metaArguments);
+ const FunctionModificationList functionMods = metaFunction->modifications(m_currentClass);
+
+ for (const FunctionModification &mod : functionMods) {
+ if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) {
+ exceptionHandling = mod.exceptionHandling();
+ break;
+ }
+ }
+
+ metaFunction->setGenerateExceptionHandling(generateExceptionHandling(metaFunction,
+ functionItem->exceptionSpecification(),
+ exceptionHandling));
+
// Find the correct default values
for (int i = 0, size = metaArguments.size(); i < size; ++i) {
- ArgumentModelItem arg = arguments.at(i);
+ const ArgumentModelItem &arg = arguments.at(i);
AbstractMetaArgument* metaArg = metaArguments.at(i);
//use relace-default-expression for set default value
@@ -2099,9 +2093,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
if (m_currentClass) {
replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1);
} else {
- FunctionModificationList mods = TypeDatabase::instance()->functionModifications(metaFunction->minimalSignature());
- if (!mods.isEmpty()) {
- QVector<ArgumentModification> argMods = mods.constFirst().argument_mods;
+ if (!functionMods.isEmpty()) {
+ QVector<ArgumentModification> argMods = functionMods.constFirst().argument_mods;
if (!argMods.isEmpty())
replacedExpression = argMods.constFirst().replacedDefaultExpression;
}
@@ -2119,10 +2112,6 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
expr = replacedExpression;
}
metaArg->setDefaultValueExpression(expr);
-
- if (metaArg->type()->isEnum() || metaArg->type()->isFlags())
- m_enumDefaultArguments << QPair<AbstractMetaArgument *, AbstractMetaFunction *>(metaArg, metaFunction);
-
hasDefaultValue = !expr.isEmpty();
}
@@ -2140,9 +2129,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel
}
if (!metaArguments.isEmpty()) {
- const FunctionModificationList &mods = metaFunction->modifications(m_currentClass);
- fixArgumentNames(metaFunction, mods);
- for (const FunctionModification &mod : mods) {
+ fixArgumentNames(metaFunction, functionMods);
+ for (const FunctionModification &mod : functionMods) {
for (const ArgumentModification &argMod : mod.argument_mods) {
if (argMod.array)
setArrayArgumentType(metaFunction, functionItem, argMod.index - 1);
@@ -2202,8 +2190,8 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction:
if (!type) {
QStringList candidates;
- SingleTypeEntryHash entries = typeDb->entries();
- for (SingleTypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
+ const auto &entries = typeDb->entries();
+ for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
// Let's try to find the type in different scopes.
if (it.key().endsWith(colonColon() + typeName))
candidates.append(it.key());
@@ -2211,15 +2199,17 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction:
QString msg = QStringLiteral("Type '%1' wasn't found in the type database.\n").arg(typeName);
- if (candidates.isEmpty())
- qFatal(qPrintable(QString(msg + QLatin1String("Declare it in the type system using the proper <*-type> tag."))), NULL);
+ if (candidates.isEmpty()) {
+ qFatal("%sDeclare it in the type system using the proper <*-type> tag.",
+ qPrintable(msg));
+ }
msg += QLatin1String("Remember to inform the full qualified name for the type you want to use.\nCandidates are:\n");
candidates.sort();
for (const QString& candidate : qAsConst(candidates)) {
msg += QLatin1String(" ") + candidate + QLatin1Char('\n');
}
- qFatal(qPrintable(msg), NULL);
+ qFatal("%s", qPrintable(msg));
}
AbstractMetaType *metaType = new AbstractMetaType;
@@ -2243,7 +2233,7 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC
{
const TypeEntry* type = 0;
QStringList context = metaClass->qualifiedCppName().split(colonColon());
- while(!type && (context.size() > 0) ) {
+ while (!type && !context.isEmpty()) {
type = TypeDatabase::instance()->findType(context.join(colonColon()) + colonColon() + qualifiedName);
context.removeLast();
}
@@ -2251,43 +2241,48 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC
}
AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei,
- bool resolveType)
+ bool resolveType,
+ QString *errorMessage)
+{
+ return translateTypeStatic(_typei, m_currentClass, this, resolveType, errorMessage);
+}
+
+AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei,
+ AbstractMetaClass *currentClass,
+ AbstractMetaBuilderPrivate *d,
+ bool resolveType,
+ QString *errorMessageIn)
{
// 1. Test the type info without resolving typedefs in case this is present in the
// type system
- TypeInfo typei;
if (resolveType) {
- if (AbstractMetaType *resolved = translateType(_typei, false))
+ if (AbstractMetaType *resolved = translateTypeStatic(_typei, currentClass, d, false, errorMessageIn))
return resolved;
}
- if (!resolveType) {
- typei = _typei;
- } else {
+ TypeInfo typeInfo = _typei;
+ if (resolveType) {
// Go through all parts of the current scope (including global namespace)
// to resolve typedefs. The parser does not properly resolve typedefs in
// the global scope when they are referenced from inside a namespace.
// This is a work around to fix this bug since fixing it in resolveType
// seemed non-trivial
- int i = m_scopes.size() - 1;
+ int i = d ? d->m_scopes.size() - 1 : -1;
while (i >= 0) {
- typei = TypeInfo::resolveType(_typei, m_scopes.at(i--));
- if (typei.qualifiedName().join(colonColon()) != _typei.qualifiedName().join(colonColon()))
+ typeInfo = TypeInfo::resolveType(_typei, d->m_scopes.at(i--));
+ if (typeInfo.qualifiedName().join(colonColon()) != _typei.qualifiedName().join(colonColon()))
break;
}
}
- if (typei.isFunctionPointer())
+ if (typeInfo.isFunctionPointer()) {
+ if (errorMessageIn)
+ *errorMessageIn = msgUnableToTranslateType(_typei, QLatin1String("Unsupported function pointer."));
return nullptr;
+ }
QString errorMessage;
- TypeInfo typeInfo = TypeParser::parse(typei.toString(), &errorMessage);
- if (typeInfo.qualifiedName().isEmpty()) {
- qWarning().noquote().nospace() << "Unable to translate type \"" << _typei.toString()
- << "\": " << errorMessage;
- return 0;
- }
// 2. Handle arrays.
// 2.1 Handle char arrays with unspecified size (aka "const char[]") as "const char*" with
@@ -2312,16 +2307,22 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
if (!typeInfo.arrayElements().isEmpty() && !isConstCharStarCase) {
TypeInfo newInfo;
//newInfo.setArguments(typeInfo.arguments());
- newInfo.setIndirections(typeInfo.indirections());
+ newInfo.setIndirectionsV(typeInfo.indirectionsV());
newInfo.setConstant(typeInfo.isConstant());
+ newInfo.setVolatile(typeInfo.isVolatile());
newInfo.setFunctionPointer(typeInfo.isFunctionPointer());
newInfo.setQualifiedName(typeInfo.qualifiedName());
newInfo.setReferenceType(typeInfo.referenceType());
newInfo.setVolatile(typeInfo.isVolatile());
- AbstractMetaType *elementType = translateType(newInfo);
- if (!elementType)
+ AbstractMetaType *elementType = translateTypeStatic(newInfo, currentClass, d, true, &errorMessage);
+ if (!elementType) {
+ if (errorMessageIn) {
+ errorMessage.prepend(QLatin1String("Unable to translate array element: "));
+ *errorMessageIn = msgUnableToTranslateType(_typei, errorMessage);
+ }
return nullptr;
+ }
for (int i = typeInfo.arrayElements().size() - 1; i >= 0; --i) {
AbstractMetaType *arrayType = new AbstractMetaType;
@@ -2329,7 +2330,9 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
const QString &arrayElement = typeInfo.arrayElements().at(i);
if (!arrayElement.isEmpty()) {
bool _ok;
- const qint64 elems = findOutValueFromString(arrayElement, _ok);
+ const qint64 elems = d
+ ? d->findOutValueFromString(arrayElement, _ok)
+ : arrayElement.toLongLong(&_ok, 0);
if (_ok)
arrayType->setArrayElementCount(int(elems));
}
@@ -2344,8 +2347,11 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
QStringList qualifierList = typeInfo.qualifiedName();
if (qualifierList.isEmpty()) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("horribly broken type '%1'").arg(_typei.toString());
+ errorMessage = msgUnableToTranslateType(_typei, QLatin1String("horribly broken type"));
+ if (errorMessageIn)
+ *errorMessageIn = errorMessage;
+ else
+ qCWarning(lcShiboken,"%s", qPrintable(errorMessage));
return nullptr;
}
@@ -2353,19 +2359,21 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
QString name = qualifierList.takeLast();
// 4. Special case QFlags (include instantiation in name)
- if (qualifiedName == QLatin1String("QFlags"))
+ if (qualifiedName == QLatin1String("QFlags")) {
qualifiedName = typeInfo.toString();
+ typeInfo.clearInstantiations();
+ }
const TypeEntry *type = 0;
// 5. Try to find the type
// 5.1 - Try first using the current scope
- if (m_currentClass) {
- type = findTypeEntryUsingContext(m_currentClass, qualifiedName);
+ if (currentClass) {
+ type = findTypeEntryUsingContext(currentClass, qualifiedName);
// 5.1.1 - Try using the class parents' scopes
- if (!type && !m_currentClass->baseClassNames().isEmpty()) {
- const AbstractMetaClassList &baseClasses = getBaseClasses(m_currentClass);
+ if (!type && d && !currentClass->baseClassNames().isEmpty()) {
+ const AbstractMetaClassList &baseClasses = d->getBaseClasses(currentClass);
for (const AbstractMetaClass *cls : baseClasses) {
type = findTypeEntryUsingContext(cls, qualifiedName);
if (type)
@@ -2388,36 +2396,40 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
// 8. No? Check if the current class is a template and this type is one
// of the parameters.
- if (!type && m_currentClass) {
- const QVector<TypeEntry *> &template_args = m_currentClass->templateArguments();
+ if (!type && currentClass) {
+ const QVector<TypeEntry *> &template_args = currentClass->templateArguments();
for (TypeEntry *te : template_args) {
if (te->name() == qualifiedName)
type = te;
}
}
- if (!type)
+ if (!type) {
+ if (errorMessageIn) {
+ *errorMessageIn =
+ msgUnableToTranslateType(_typei, msgCannotFindTypeEntry(qualifiedName));
+ }
return nullptr;
-
- // Used to for diagnostics later...
- m_usedTypes << type;
+ }
// These are only implicit and should not appear in code...
Q_ASSERT(!type->isInterface());
AbstractMetaType *metaType = new AbstractMetaType;
metaType->setTypeEntry(type);
- metaType->setIndirections(typeInfo.indirections());
+ metaType->setIndirectionsV(typeInfo.indirectionsV());
metaType->setReferenceType(typeInfo.referenceType());
metaType->setConstant(typeInfo.isConstant());
+ metaType->setVolatile(typeInfo.isVolatile());
metaType->setOriginalTypeDescription(_typei.toString());
- const auto &templateArguments = typeInfo.arguments();
+ const auto &templateArguments = typeInfo.instantiations();
for (int t = 0, size = templateArguments.size(); t < size; ++t) {
- TypeInfo ti = templateArguments.at(t);
- ti.setQualifiedName(ti.instantiationName());
- AbstractMetaType *targType = translateType(ti);
+ const TypeInfo &ti = templateArguments.at(t);
+ AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, true, &errorMessage);
if (!targType) {
+ if (errorMessageIn)
+ *errorMessageIn = msgCannotTranslateTemplateArgument(t, ti, errorMessage);
delete metaType;
return nullptr;
}
@@ -2434,6 +2446,33 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ
return metaType;
}
+AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei,
+ AbstractMetaClass *currentClass,
+ bool resolveType,
+ QString *errorMessage)
+{
+ return AbstractMetaBuilderPrivate::translateTypeStatic(_typei, currentClass,
+ nullptr, resolveType,
+ errorMessage);
+}
+
+AbstractMetaType *AbstractMetaBuilder::translateType(const QString &t,
+ AbstractMetaClass *currentClass,
+ bool resolveType,
+ QString *errorMessageIn)
+{
+ QString errorMessage;
+ TypeInfo typeInfo = TypeParser::parse(t, &errorMessage);
+ if (typeInfo.qualifiedName().isEmpty()) {
+ errorMessage = msgUnableToTranslateType(t, errorMessage);
+ if (errorMessageIn)
+ *errorMessageIn = errorMessage;
+ else
+ qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
+ return nullptr;
+ }
+ return translateType(typeInfo, currentClass, resolveType, errorMessageIn);
+}
qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringValue, bool &ok)
{
@@ -2472,7 +2511,7 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV
return 0;
}
-QString AbstractMetaBuilderPrivate::fixDefaultValue(ArgumentModelItem item,
+QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &item,
AbstractMetaType *type,
AbstractMetaFunction *fnc,
AbstractMetaClass *implementingClass,
@@ -2676,59 +2715,55 @@ bool AbstractMetaBuilderPrivate::ancestorHasPrivateCopyConstructor(const Abstrac
return false;
}
-AbstractMetaType* AbstractMetaBuilderPrivate::inheritTemplateType(const QVector<AbstractMetaType *> &templateTypes,
- const AbstractMetaType *metaType,
- bool *ok)
+AbstractMetaType *
+ AbstractMetaBuilderPrivate::inheritTemplateType(const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaType *metaType)
{
- if (ok)
- *ok = true;
- if (!metaType || (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations()))
- return metaType ? metaType->copy() : 0;
+ Q_ASSERT(metaType);
+
+ QScopedPointer<AbstractMetaType> returned(metaType->copy());
- AbstractMetaType *returned = metaType->copy();
- returned->setOriginalTemplateType(metaType->copy());
+ if (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations())
+ return returned.take();
+
+ returned->setOriginalTemplateType(metaType);
if (returned->typeEntry()->isTemplateArgument()) {
const TemplateArgumentEntry* tae = static_cast<const TemplateArgumentEntry*>(returned->typeEntry());
// If the template is intantiated with void we special case this as rejecting the functions that use this
// parameter from the instantiation.
- if (templateTypes.size() <= tae->ordinal() || templateTypes.at(tae->ordinal())->typeEntry()->name() == QLatin1String("void")) {
- if (ok)
- *ok = false;
- return 0;
- }
+ const AbstractMetaType *templateType = templateTypes.value(tae->ordinal());
+ if (!templateType || templateType->typeEntry()->isVoid())
+ return nullptr;
AbstractMetaType* t = returned->copy();
- t->setTypeEntry(templateTypes.at(tae->ordinal())->typeEntry());
- t->setIndirections(templateTypes.at(tae->ordinal())->indirections() + t->indirections() ? 1 : 0);
+ t->setTypeEntry(templateType->typeEntry());
+ t->setIndirections(templateType->indirections() + t->indirections() ? 1 : 0);
t->decideUsagePattern();
- delete returned;
- returned = inheritTemplateType(templateTypes, t, ok);
- if (ok && !(*ok))
- return 0;
+ return inheritTemplateType(templateTypes, t);
}
if (returned->hasInstantiations()) {
AbstractMetaTypeList instantiations = returned->instantiations();
for (int i = 0; i < instantiations.count(); ++i) {
- AbstractMetaType *type = instantiations[i];
- instantiations[i] = inheritTemplateType(templateTypes, type, ok);
- if (ok && !(*ok))
- return 0;
+ instantiations[i] =
+ inheritTemplateType(templateTypes, instantiations.at(i));
+ if (!instantiations.at(i))
+ return nullptr;
}
returned->setInstantiations(instantiations, true);
}
- return returned;
+ return returned.take();
}
bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
const AbstractMetaClass *templateClass,
const TypeInfo &info)
{
- QVector<TypeInfo> targs = info.arguments();
+ QVector<TypeInfo> targs = info.instantiations();
QVector<AbstractMetaType *> templateTypes;
if (subclass->isTypeDef()) {
@@ -2743,20 +2778,35 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
for (const TypeInfo &i : qAsConst(targs)) {
QString typeName = i.qualifiedName().join(colonColon());
- QStringList possibleNames;
- possibleNames << subclass->qualifiedCppName() + colonColon() + typeName;
- possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName;
- if (subclass->enclosingClass())
- possibleNames << subclass->enclosingClass()->qualifiedCppName() + colonColon() + typeName;
- possibleNames << typeName;
-
- TypeDatabase* typeDb = TypeDatabase::instance();
- TypeEntry* t = 0;
- QString templateParamName;
- for (const QString &possibleName : qAsConst(possibleNames)) {
- t = typeDb->findType(possibleName);
- if (t)
- break;
+ TypeDatabase *typeDb = TypeDatabase::instance();
+ TypeEntry *t = nullptr;
+ // Check for a non-type template integer parameter, that is, for a base
+ // "template <int R, int C> Matrix<R, C>" and subclass
+ // "typedef Matrix<2,3> Matrix2x3;". If so, create dummy entries of
+ // EnumValueTypeEntry for the integer values encountered on the fly.
+ const bool isNumber = std::all_of(typeName.cbegin(), typeName.cend(),
+ [](QChar c) { return c.isDigit(); });
+ if (isNumber) {
+ t = typeDb->findType(typeName);
+ if (!t) {
+ t = new EnumValueTypeEntry(typeName, typeName, nullptr,
+ QVersionNumber(0, 0));
+ t->setCodeGeneration(0);
+ typeDb->addType(t);
+ }
+ } else {
+ QStringList possibleNames;
+ possibleNames << subclass->qualifiedCppName() + colonColon() + typeName;
+ possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName;
+ if (subclass->enclosingClass())
+ possibleNames << subclass->enclosingClass()->qualifiedCppName() + colonColon() + typeName;
+ possibleNames << typeName;
+
+ for (const QString &possibleName : qAsConst(possibleNames)) {
+ t = typeDb->findType(possibleName);
+ if (t)
+ break;
+ }
}
if (t) {
@@ -2764,48 +2814,48 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
temporaryType->setTypeEntry(t);
temporaryType->setConstant(i.isConstant());
temporaryType->setReferenceType(i.referenceType());
- temporaryType->setIndirections(i.indirections());
+ temporaryType->setIndirectionsV(i.indirectionsV());
temporaryType->decideUsagePattern();
templateTypes << temporaryType;
} else {
qCWarning(lcShiboken).noquote().nospace()
- << "Ignoring template parameter " << templateParamName << " from "
- << info.instantiationName() << ", because I don't know what it is.";
+ << "Ignoring template parameter " << typeName << " from "
+ << info.toString() << ". The corresponding type was not found in the typesystem.";
}
}
- AbstractMetaFunctionList funcs = subclass->functions();
+ const AbstractMetaFunctionList &subclassFuncs = subclass->functions();
const AbstractMetaFunctionList &templateClassFunctions = templateClass->functions();
for (const AbstractMetaFunction *function : templateClassFunctions) {
- if (function->isModifiedRemoved(TypeSystem::All))
+ // If the function is modified or the instantiation has an equally named
+ // function we have shadowing, so we need to skip it.
+ if (function->isModifiedRemoved(TypeSystem::All)
+ || AbstractMetaFunction::find(subclassFuncs, function->name()) != nullptr) {
continue;
+ }
- AbstractMetaFunction *f = function->copy();
+ QScopedPointer<AbstractMetaFunction> f(function->copy());
f->setArguments(AbstractMetaArgumentList());
- bool ok = true;
- AbstractMetaType *ftype = function->type();
- f->replaceType(inheritTemplateType(templateTypes, ftype, &ok));
- if (!ok) {
- delete f;
- continue;
+ if (function->type()) { // Non-void
+ AbstractMetaType *returnType = inheritTemplateType(templateTypes, function->type());
+ if (!returnType)
+ continue;
+ f->replaceType(returnType);
}
const AbstractMetaArgumentList &arguments = function->arguments();
for (AbstractMetaArgument *argument : arguments) {
- AbstractMetaType* atype = argument->type();
-
- AbstractMetaArgument *arg = argument->copy();
- arg->replaceType(inheritTemplateType(templateTypes, atype, &ok));
- if (!ok)
+ AbstractMetaType *argType = inheritTemplateType(templateTypes, argument->type());
+ if (!argType)
break;
+ AbstractMetaArgument *arg = argument->copy();
+ arg->replaceType(argType);
f->addArgument(arg);
}
- if (!ok) {
- delete f;
+ if (f->arguments().size() < function->arguments().size())
continue;
- }
// There is no base class in the target language to inherit from here, so
// the template instantiation is the class that implements the function.
@@ -2816,27 +2866,11 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
// on the inherited functions.
f->setDeclaringClass(subclass);
-
- if (f->isConstructor() && subclass->isTypeDef()) {
+ if (f->isConstructor()) {
+ if (!subclass->isTypeDef())
+ continue;
f->setName(subclass->name());
f->setOriginalName(subclass->name());
- } else if (f->isConstructor()) {
- delete f;
- continue;
- }
-
- // if the instantiation has a function named the same as an existing
- // function we have shadowing so we need to skip it.
- bool found = false;
- for (int i = 0; i < funcs.size(); ++i) {
- if (funcs.at(i)->name() == f->name()) {
- found = true;
- continue;
- }
- }
- if (found) {
- delete f;
- continue;
}
ComplexTypeEntry* te = subclass->typeEntry();
@@ -2863,7 +2897,27 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
te->addFunctionModification(mod);
}
- subclass->addFunction(f);
+ subclass->addFunction(f.take());
+ }
+
+ const AbstractMetaFieldList &subClassFields = subclass->fields();
+ const AbstractMetaFieldList &templateClassFields = templateClass->fields();
+ for (const AbstractMetaField *field : templateClassFields) {
+ // If the field is modified or the instantiation has a field named
+ // the same as an existing field we have shadowing, so we need to skip it.
+ if (field->isModifiedRemoved(TypeSystem::All)
+ || field->attributes().testFlag(AbstractMetaAttributes::Static)
+ || AbstractMetaField::find(subClassFields, field->name()) != nullptr) {
+ continue;
+ }
+
+ QScopedPointer<AbstractMetaField> f(field->copy());
+ f->setEnclosingClass(subclass);
+ AbstractMetaType *fieldType = inheritTemplateType(templateTypes, field->type());
+ if (!fieldType)
+ continue;
+ f->replaceType(fieldType);
+ subclass->addField(f.take());
}
subclass->setTemplateBaseClass(templateClass);
@@ -2878,9 +2932,9 @@ void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass,
const QStringList &declarations)
{
for (int i = 0; i < declarations.size(); ++i) {
- QString p = declarations.at(i);
+ const QString &p = declarations.at(i);
- QStringList l = p.split(QLatin1String(" "));
+ QStringList l = p.split(QLatin1Char(' '));
QStringList qualifiedScopeName = currentScope()->qualifiedName();
@@ -2925,8 +2979,8 @@ void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass,
static AbstractMetaFunction* findCopyCtor(AbstractMetaClass* cls)
{
- AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::Invisible);
- functions << cls->queryFunctions(AbstractMetaClass::Visible);
+
+ const auto &functions = cls->functions();
for (AbstractMetaFunction *f : qAsConst(functions)) {
const AbstractMetaFunction::FunctionType t = f->functionType();
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
index a0ca71b94..01806f6b4 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
@@ -38,7 +38,10 @@ QT_FORWARD_DECLARE_CLASS(QIODevice)
class AbstractMetaBuilderPrivate;
class AbstractMetaClass;
+class AbstractMetaType;
class AbstractMetaEnumValue;
+class TypeInfo;
+class TypeEntry;
class AbstractMetaBuilder
{
@@ -61,6 +64,7 @@ public:
AbstractMetaClassList smartPointers() const;
AbstractMetaFunctionList globalFunctions() const;
AbstractMetaEnumList globalEnums() const;
+ AbstractMetaEnum *findEnum(const TypeEntry *typeEntry) const;
/**
* Sorts a list of classes topologically, if an AbstractMetaClass object
@@ -83,6 +87,16 @@ public:
*/
void setGlobalHeader(const QString& globalHeader);
+ static AbstractMetaType *translateType(const TypeInfo &_typei,
+ AbstractMetaClass *currentClass = nullptr,
+ bool resolveType = true,
+ QString *errorMessage = nullptr);
+ static AbstractMetaType *translateType(const QString &t,
+ AbstractMetaClass *currentClass = nullptr,
+ bool resolveType = true,
+ QString *errorMessage = nullptr);
+
+
#ifndef QT_NO_DEBUG_STREAM
void formatDebug(QDebug &d) const;
#endif
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
index 59e3cfc94..ec55d1b47 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
@@ -60,11 +60,12 @@ public:
ScopeModelItem currentScope() const { return m_scopes.constLast(); }
- AbstractMetaClass *argumentToClass(ArgumentModelItem);
+ AbstractMetaClass *argumentToClass(const ArgumentModelItem &);
void addAbstractMetaClass(AbstractMetaClass *cls);
AbstractMetaClass *traverseTypeDef(const FileModelItem &dom,
const TypeDefModelItem &typeDef);
+ void traverseTypesystemTypedefs();
AbstractMetaClass *traverseClass(const FileModelItem &dom,
const ClassModelItem &item);
AbstractMetaClass *currentTraversedClass(ScopeModelItem item);
@@ -74,9 +75,9 @@ public:
bool setupInheritance(AbstractMetaClass *metaClass);
AbstractMetaClass *traverseNamespace(const FileModelItem &dom,
const NamespaceModelItem &item);
- AbstractMetaEnum *traverseEnum(EnumModelItem item, AbstractMetaClass *enclosing,
+ AbstractMetaEnum *traverseEnum(const EnumModelItem &item, AbstractMetaClass *enclosing,
const QSet<QString> &enumsDeclarations);
- void traverseEnums(ScopeModelItem item, AbstractMetaClass *parent,
+ void traverseEnums(const ScopeModelItem &item, AbstractMetaClass *parent,
const QStringList &enumsDeclarations);
AbstractMetaFunctionList classFunctionList(const ScopeModelItem &scopeItem,
bool *constructorRejected);
@@ -85,18 +86,18 @@ public:
bool *constructorRejected);
void traverseFunctions(ScopeModelItem item, AbstractMetaClass *parent);
void applyFunctionModifications(AbstractMetaFunction* func);
- void traverseFields(ScopeModelItem item, AbstractMetaClass *parent);
- void traverseStreamOperator(FunctionModelItem functionItem);
- void traverseOperatorFunction(FunctionModelItem item);
+ void traverseFields(const ScopeModelItem &item, AbstractMetaClass *parent);
+ void traverseStreamOperator(const FunctionModelItem &functionItem);
+ void traverseOperatorFunction(const FunctionModelItem &item);
AbstractMetaFunction* traverseFunction(const AddedFunction &addedFunc);
AbstractMetaFunction* traverseFunction(const AddedFunction &addedFunc,
AbstractMetaClass *metaClass);
- AbstractMetaFunction *traverseFunction(FunctionModelItem function);
- AbstractMetaField *traverseField(VariableModelItem field,
+ AbstractMetaFunction *traverseFunction(const FunctionModelItem &function);
+ AbstractMetaField *traverseField(const VariableModelItem &field,
const AbstractMetaClass *cls);
void checkFunctionModifications();
- void registerHashFunction(FunctionModelItem functionItem);
- void registerToStringCapability(FunctionModelItem functionItem);
+ void registerHashFunction(const FunctionModelItem &functionItem);
+ void registerToStringCapability(const FunctionModelItem &functionItem);
/**
* A conversion operator function should not have its owner class as
@@ -118,12 +119,19 @@ public:
void setupFunctionDefaults(AbstractMetaFunction *metaFunction,
AbstractMetaClass *metaClass);
- QString fixDefaultValue(ArgumentModelItem item, AbstractMetaType *type,
+ QString fixDefaultValue(const ArgumentModelItem &item, AbstractMetaType *type,
AbstractMetaFunction *fnc, AbstractMetaClass *,
int argumentIndex);
AbstractMetaType *translateType(const AddedFunction::TypeInfo &typeInfo);
AbstractMetaType *translateType(const TypeInfo &type,
- bool resolveType = true);
+ bool resolveType = true,
+ QString *errorMessage = nullptr);
+ static AbstractMetaType *translateTypeStatic(const TypeInfo &type,
+ AbstractMetaClass *current,
+ AbstractMetaBuilderPrivate *d = nullptr,
+ bool resolveType = true,
+ QString *errorMessageIn = nullptr);
+
qint64 findOutValueFromString(const QString &stringValue, bool &ok);
AbstractMetaClass *findTemplateClass(const QString& name, const AbstractMetaClass *context,
@@ -135,9 +143,8 @@ public:
bool inheritTemplate(AbstractMetaClass *subclass,
const AbstractMetaClass *templateClass,
const TypeInfo &info);
- AbstractMetaType *inheritTemplateType(const QVector<AbstractMetaType *> &templateTypes,
- const AbstractMetaType *metaType,
- bool *ok = Q_NULLPTR);
+ AbstractMetaType *inheritTemplateType(const AbstractMetaTypeList &templateTypes,
+ const AbstractMetaType *metaType);
bool isQObject(const FileModelItem &dom, const QString &qualifiedName);
bool isEnum(const FileModelItem &dom, const QStringList &qualifiedName);
@@ -161,8 +168,6 @@ public:
AbstractMetaFunctionList m_globalFunctions;
AbstractMetaEnumList m_globalEnums;
- QSet<const TypeEntry *> m_usedTypes;
-
typedef QMap<QString, AbstractMetaBuilder::RejectReason> RejectMap;
RejectMap m_rejectedClasses;
@@ -170,11 +175,7 @@ public:
RejectMap m_rejectedFunctions;
RejectMap m_rejectedFields;
- QList<AbstractMetaEnum *> m_enums;
-
- QList<QPair<AbstractMetaArgument *, AbstractMetaFunction *> > m_enumDefaultArguments;
-
- QHash<QString, AbstractMetaEnumValue *> m_enumValues;
+ QHash<const TypeEntry *, AbstractMetaEnum *> m_enums;
AbstractMetaClass *m_currentClass;
QList<ScopeModelItem> m_scopes;
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
index 5be7050bf..c65d7e0bd 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -27,10 +27,13 @@
****************************************************************************/
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "typedatabase.h"
#include "typesystem.h"
+#include <parser/codemodel.h>
+
#ifndef QT_NO_DEBUG_STREAM
# include <QtCore/QMetaEnum>
# include <QtCore/QMetaObject>
@@ -55,6 +58,16 @@ QDebug operator<<(QDebug d, const AbstractMetaAttributes *aa)
}
#endif // !QT_NO_DEBUG_STREAM
+template <class MetaClass>
+MetaClass *findByName(QVector<MetaClass *> haystack, QStringView needle)
+{
+ for (MetaClass *c : haystack) {
+ if (c->name() == needle)
+ return c;
+ }
+ return nullptr;
+}
+
/*******************************************************************************
* AbstractMetaVariable
*/
@@ -112,8 +125,8 @@ void AbstractMetaAttributes::assignMetaAttributes(const AbstractMetaAttributes &
AbstractMetaType::AbstractMetaType() :
m_constant(false),
+ m_volatile(false),
m_cppInstantiation(true),
- m_indirections(0),
m_reserved(0)
{
}
@@ -155,8 +168,9 @@ AbstractMetaType *AbstractMetaType::copy() const
cpy->setTypeUsagePattern(typeUsagePattern());
cpy->setConstant(isConstant());
+ cpy->setVolatile(isVolatile());
cpy->setReferenceType(referenceType());
- cpy->setIndirections(indirections());
+ cpy->setIndirectionsV(indirectionsV());
cpy->setInstantiations(instantiations());
cpy->setArrayElementCount(arrayElementCount());
cpy->setOriginalTypeDescription(originalTypeDescription());
@@ -278,6 +292,26 @@ bool AbstractMetaType::hasTemplateChildren() const
return false;
}
+bool AbstractMetaType::equals(const AbstractMetaType &rhs) const
+{
+ if (m_typeEntry != rhs.m_typeEntry || m_constant != rhs.m_constant
+ || m_referenceType != rhs.m_referenceType
+ || m_indirections != rhs.m_indirections
+ || m_instantiations.size() != rhs.m_instantiations.size()
+ || m_arrayElementCount != rhs.m_arrayElementCount) {
+ return false;
+ }
+ if ((m_arrayElementType != nullptr) != (rhs.m_arrayElementType != nullptr)
+ || (m_arrayElementType != nullptr && !m_arrayElementType->equals(*rhs.m_arrayElementType))) {
+ return false;
+ }
+ for (int i = 0, size = m_instantiations.size(); i < size; ++i) {
+ if (!m_instantiations.at(i)->equals(*rhs.m_instantiations.at(i)))
+ return false;
+ }
+ return true;
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const AbstractMetaType *at)
{
@@ -291,16 +325,32 @@ QDebug operator<<(QDebug d, const AbstractMetaType *at)
d << ", typeEntry=" << at->typeEntry() << ", signature=\""
<< at->cppSignature() << "\", pattern="
<< at->typeUsagePattern();
- if (at->indirections())
- d << ", indirections=" << at->indirections();
+ const auto indirections = at->indirectionsV();
+ if (!indirections.isEmpty()) {
+ d << ", indirections=";
+ for (auto i : indirections)
+ d << ' ' << TypeInfo::indirectionKeyword(i);
+ }
if (at->referenceType())
d << ", reftype=" << at->referenceType();
if (at->isConstant())
d << ", [const]";
+ if (at->isVolatile())
+ d << ", [volatile]";
if (at->isArray()) {
d << ", array of \"" << at->arrayElementType()->cppSignature()
<< "\", arrayElementCount=" << at->arrayElementCount();
}
+ const auto &instantiations = at->instantiations();
+ if (const int instantiationsSize = instantiations.size()) {
+ d << ", instantiations[" << instantiationsSize << "]=<";
+ for (int i = 0; i < instantiationsSize; ++i) {
+ if (i)
+ d << ", ";
+ d << instantiations.at(i);
+ }
+ }
+ d << '>';
}
} else {
d << '0';
@@ -357,7 +407,8 @@ AbstractMetaFunction::AbstractMetaFunction()
m_userAdded(false),
m_explicit(false),
m_pointerOperator(false),
- m_isCallOperator(false)
+ m_isCallOperator(false),
+ m_generateExceptionHandling(false)
{
}
@@ -475,6 +526,8 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const
if (type())
cpy->setType(type()->copy());
cpy->setConstant(isConstant());
+ cpy->setExceptionSpecification(m_exceptionSpecification);
+ cpy->setGenerateExceptionHandling(m_generateExceptionHandling);
for (AbstractMetaArgument *arg : m_arguments)
cpy->addArgument(arg->copy());
@@ -504,18 +557,17 @@ QStringList AbstractMetaFunction::introspectionCompatibleSignatures(const QStrin
if (arguments.size() == resolvedArguments.size()) {
QString signature = name() + QLatin1Char('(') + resolvedArguments.join(QLatin1Char(',')) + QLatin1Char(')');
return QStringList(TypeDatabase::normalizedSignature(signature));
- } else {
- QStringList returned;
-
- AbstractMetaArgument *argument = arguments.at(resolvedArguments.size());
- QStringList minimalTypeSignature = argument->type()->minimalSignature().split(QLatin1String("::"));
- for (int i = 0; i < minimalTypeSignature.size(); ++i) {
- returned += introspectionCompatibleSignatures(QStringList(resolvedArguments)
- << QStringList(minimalTypeSignature.mid(minimalTypeSignature.size() - i - 1)).join(QLatin1String("::")));
- }
+ }
+ QStringList returned;
- return returned;
+ AbstractMetaArgument *argument = arguments.at(resolvedArguments.size());
+ QStringList minimalTypeSignature = argument->type()->minimalSignature().split(QLatin1String("::"));
+ for (int i = 0; i < minimalTypeSignature.size(); ++i) {
+ returned += introspectionCompatibleSignatures(QStringList(resolvedArguments)
+ << QStringList(minimalTypeSignature.mid(minimalTypeSignature.size() - i - 1)).join(QLatin1String("::")));
}
+
+ return returned;
}
QString AbstractMetaFunction::signature() const
@@ -674,38 +726,54 @@ bool AbstractMetaFunction::argumentRemoved(int key) const
return false;
}
-bool AbstractMetaFunction::isVirtualSlot() const
+bool AbstractMetaFunction::isDeprecated() const
{
const FunctionModificationList &modifications = this->modifications(declaringClass());
for (const FunctionModification &modification : modifications) {
- if (modification.isVirtualSlot())
+ if (modification.isDeprecated())
return true;
}
-
return false;
}
-bool AbstractMetaFunction::isDeprecated() const
+// Auto-detect whether a function should be wrapped into
+// Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS, that is, temporarily release
+// the GIL (global interpreter lock). Doing so is required for any thread-wait
+// functions, anything that might call a virtual function (potentially
+// reimplemented in Python), and recommended for lengthy I/O or similar.
+// It has performance costs, though.
+bool AbstractMetaFunction::autoDetectAllowThread() const
{
- const FunctionModificationList &modifications = this->modifications(declaringClass());
- for (const FunctionModification &modification : modifications) {
- if (modification.isDeprecated())
- return true;
- }
- return false;
+ // Disallow for simple getter functions.
+ const bool maybeGetter = m_constant != 0 && m_type != nullptr
+ && m_arguments.isEmpty();
+ return !maybeGetter;
}
bool AbstractMetaFunction::allowThread() const
{
- const FunctionModificationList &modifications = this->modifications(declaringClass());
- for (const FunctionModification &modification : modifications) {
- if (modification.allowThread())
- return true;
+ using AllowThread = TypeSystem::AllowThread;
+
+ if (m_cachedAllowThread < 0) {
+ AllowThread allowThread = AllowThread::Auto;
+ // Find a modification that specifies allowThread
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ if (modification.allowThread() != AllowThread::Unspecified) {
+ allowThread = modification.allowThread();
+ break;
+ }
+ }
+
+ m_cachedAllowThread = allowThread == AllowThread::Allow
+ || (allowThread == AllowThread::Auto && autoDetectAllowThread()) ? 1 : 0;
+
+ if (m_cachedAllowThread == 0)
+ qCDebug(lcShiboken).noquote() << msgDisallowThread(this);
}
- return false;
+ return m_cachedAllowThread > 0;
}
-
TypeSystem::Ownership AbstractMetaFunction::ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int key) const
{
const FunctionModificationList &modifications = this->modifications(cls);
@@ -751,6 +819,18 @@ QString AbstractMetaFunction::typeReplaced(int key) const
return QString();
}
+bool AbstractMetaFunction::isModifiedToArray(int argumentIndex) const
+{
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == argumentIndex && argumentModification.array != 0)
+ return true;
+ }
+ }
+ return false;
+}
+
QString AbstractMetaFunction::minimalSignature() const
{
if (!m_cachedMinimalSignature.isEmpty())
@@ -809,8 +889,9 @@ FunctionModificationList AbstractMetaFunction::modifications(const AbstractMetaC
while (implementor) {
mods += implementor->typeEntry()->functionModifications(minimalSignature());
if ((implementor == implementor->baseClass()) ||
- (implementor == implementingClass() && (mods.size() > 0)))
+ (implementor == implementingClass() && !mods.isEmpty())) {
break;
+ }
const AbstractMetaClassList &interfaces = implementor->interfaces();
for (const AbstractMetaClass *interface : interfaces)
mods += this->modifications(interface);
@@ -873,14 +954,24 @@ bool AbstractMetaFunction::hasSignatureModifications() const
return false;
}
-bool AbstractMetaFunction::isConversionOperator(QString funcName)
+bool AbstractMetaFunction::isConversionOperator(const QString& funcName)
{
static const QRegularExpression opRegEx(QStringLiteral("^operator(?:\\s+(?:const|volatile))?\\s+(\\w+\\s*)&?$"));
Q_ASSERT(opRegEx.isValid());
return opRegEx.match(funcName).hasMatch();
}
-bool AbstractMetaFunction::isOperatorOverload(QString funcName)
+ExceptionSpecification AbstractMetaFunction::exceptionSpecification() const
+{
+ return m_exceptionSpecification;
+}
+
+void AbstractMetaFunction::setExceptionSpecification(ExceptionSpecification e)
+{
+ m_exceptionSpecification = e;
+}
+
+bool AbstractMetaFunction::isOperatorOverload(const QString& funcName)
{
if (isConversionOperator(funcName))
return true;
@@ -1038,6 +1129,13 @@ bool function_sorter(AbstractMetaFunction *a, AbstractMetaFunction *b)
return a->signature() < b->signature();
}
+AbstractMetaFunction *
+AbstractMetaFunction::find(const AbstractMetaFunctionList &haystack,
+ const QString &needle)
+{
+ return findByName(haystack, needle);
+}
+
#ifndef QT_NO_DEBUG_STREAM
static inline void formatMetaFunctionBrief(QDebug &d, const AbstractMetaFunction *af)
{
@@ -1046,7 +1144,20 @@ static inline void formatMetaFunctionBrief(QDebug &d, const AbstractMetaFunction
void AbstractMetaFunction::formatDebugVerbose(QDebug &d) const
{
- d << m_functionType << ' ' << m_type << ' ' << m_name << '(';
+ d << m_functionType << ' ' << m_type << ' ' << m_name;
+ switch (m_exceptionSpecification) {
+ case ExceptionSpecification::Unknown:
+ break;
+ case ExceptionSpecification::NoExcept:
+ d << " noexcept";
+ break;
+ case ExceptionSpecification::Throws:
+ d << " throw(...)";
+ break;
+ }
+ if (m_generateExceptionHandling)
+ d << "[generate-exception-handling]";
+ d << '(';
for (int i = 0, count = m_arguments.size(); i < count; ++i) {
if (i)
d << ", ";
@@ -1106,7 +1217,6 @@ AbstractMetaClass::AbstractMetaClass()
: m_hasVirtuals(false),
m_isPolymorphic(false),
m_hasNonpublic(false),
- m_hasVirtualSlots(false),
m_hasNonPrivateConstructor(false),
m_hasPrivateConstructor(false),
m_functionsFixed(false),
@@ -1330,11 +1440,8 @@ void AbstractMetaClass::setFunctions(const AbstractMetaFunctionList &functions)
for (AbstractMetaFunction *f : qAsConst(m_functions)) {
f->setOwnerClass(this);
-
- m_hasVirtualSlots = m_hasVirtualSlots || f->isVirtualSlot();
- m_hasVirtuals = m_hasVirtuals || f->isVirtualSlot() || hasVirtualDestructor();
- m_isPolymorphic = m_isPolymorphic || m_hasVirtuals;
- m_hasNonpublic = m_hasNonpublic || !f->isPublic();
+ if (!f->isPublic())
+ m_hasNonpublic = true;
}
}
@@ -1368,8 +1475,7 @@ void AbstractMetaClass::addFunction(AbstractMetaFunction *function)
else
Q_ASSERT(false); //memory leak
- m_hasVirtualSlots |= function->isVirtualSlot();
- m_hasVirtuals |= function->isVirtual() || function->isVirtualSlot() || hasVirtualDestructor();
+ m_hasVirtuals |= function->isVirtual() || hasVirtualDestructor();
m_isPolymorphic |= m_hasVirtuals;
m_hasNonpublic |= !function->isPublic();
}
@@ -1432,11 +1538,7 @@ bool AbstractMetaClass::hasFunction(const QString &str) const
const AbstractMetaFunction* AbstractMetaClass::findFunction(const QString& functionName) const
{
- for (const AbstractMetaFunction *f : m_functions) {
- if (f->name() == functionName)
- return f;
- }
- return 0;
+ return AbstractMetaFunction::find(m_functions, functionName);
}
bool AbstractMetaClass::hasProtectedFunctions() const
@@ -1511,6 +1613,13 @@ void AbstractMetaClass::setTemplateBaseClassInstantiations(AbstractMetaTypeList&
metaClassBaseTemplateInstantiations()->insert(this, instantiations);
}
+// Does any of the base classes require deletion in the main thread?
+bool AbstractMetaClass::deleteInMainThread() const
+{
+ return typeEntry()->deleteInMainThread()
+ || (m_baseClass && m_baseClass->deleteInMainThread());
+}
+
static bool functions_contains(const AbstractMetaFunctionList &l, const AbstractMetaFunction *func)
{
for (const AbstractMetaFunction *f : l) {
@@ -1537,6 +1646,11 @@ AbstractMetaField *AbstractMetaField::copy() const
return returned;
}
+AbstractMetaField *AbstractMetaField::find(const AbstractMetaFieldList &haystack,
+ const QString &needle)
+{
+ return findByName(haystack, needle);
+}
/*******************************************************************************
* Indicates that this field has a modification that removes it
*/
@@ -1723,27 +1837,22 @@ QDebug operator<<(QDebug d, const AbstractMetaEnum *ae)
bool AbstractMetaClass::hasConstructors() const
{
- return queryFunctions(Constructors).size();
+ return AbstractMetaClass::queryFirstFunction(m_functions, Constructors) != nullptr;
}
-bool AbstractMetaClass::hasCopyConstructor() const
+const AbstractMetaFunction *AbstractMetaClass::copyConstructor() const
{
- const AbstractMetaFunctionList &ctors = queryFunctions(Constructors);
- for (const AbstractMetaFunction* ctor : ctors) {
- if (ctor->functionType() == AbstractMetaFunction::CopyConstructorFunction)
- return true;
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->functionType() == AbstractMetaFunction::CopyConstructorFunction)
+ return f;
}
- return false;
+ return nullptr;
}
bool AbstractMetaClass::hasPrivateCopyConstructor() const
{
- const AbstractMetaFunctionList &ctors = queryFunctions(Constructors);
- for (const AbstractMetaFunction *ctor : ctors) {
- if (ctor->functionType() == AbstractMetaFunction::CopyConstructorFunction && ctor->isPrivate())
- return true;
- }
- return false;
+ const AbstractMetaFunction *copyCt = copyConstructor();
+ return copyCt && copyCt->isPrivate();
}
void AbstractMetaClass::addDefaultConstructor()
@@ -1801,85 +1910,122 @@ bool AbstractMetaClass::hasFunction(const AbstractMetaFunction *f) const
return functions_contains(m_functions, f);
}
+bool AbstractMetaClass::generateExceptionHandling() const
+{
+ return queryFirstFunction(m_functions, AbstractMetaClass::Visible
+ | AbstractMetaClass::GenerateExceptionHandling) != nullptr;
+}
/* Goes through the list of functions and returns a list of all
functions matching all of the criteria in \a query.
*/
-AbstractMetaFunctionList AbstractMetaClass::queryFunctions(FunctionQueryOptions query) const
+bool AbstractMetaClass::queryFunction(const AbstractMetaFunction *f, FunctionQueryOptions query)
{
- AbstractMetaFunctionList functions;
-
- for (AbstractMetaFunction *f : m_functions) {
- if ((query & NotRemovedFromTargetLang) && f->isRemovedFrom(f->implementingClass(), TypeSystem::TargetLangCode))
- continue;
+ if ((query & NotRemovedFromTargetLang)
+ && f->isRemovedFrom(f->implementingClass(), TypeSystem::TargetLangCode)) {
+ return false;
+ }
- if ((query & NotRemovedFromTargetLang) && f->isVirtual() && f->isRemovedFrom(f->declaringClass(), TypeSystem::TargetLangCode))
- continue;
+ if ((query & NotRemovedFromTargetLang) && f->isVirtual()
+ && f->isRemovedFrom(f->declaringClass(), TypeSystem::TargetLangCode)) {
+ return false;
+ }
- if ((query & Visible) && f->isPrivate())
- continue;
+ if ((query & Visible) && f->isPrivate())
+ return false;
- if ((query & VirtualInTargetLangFunctions) && f->isFinalInTargetLang())
- continue;
+ if ((query & VirtualInTargetLangFunctions) && f->isFinalInTargetLang())
+ return false;
- if ((query & Invisible) && !f->isPrivate())
- continue;
+ if ((query & Invisible) && !f->isPrivate())
+ return false;
- if ((query & Empty) && !f->isEmptyFunction())
- continue;
+ if ((query & Empty) && !f->isEmptyFunction())
+ return false;
- if ((query & WasPublic) && !f->wasPublic())
- continue;
+ if ((query & WasPublic) && !f->wasPublic())
+ return false;
- if ((query & ClassImplements) && f->ownerClass() != f->implementingClass())
- continue;
+ if ((query & ClassImplements) && f->ownerClass() != f->implementingClass())
+ return false;
- if ((query & FinalInTargetLangFunctions) && !f->isFinalInTargetLang())
- continue;
+ if ((query & FinalInTargetLangFunctions) && !f->isFinalInTargetLang())
+ return false;
- if ((query & VirtualInCppFunctions) && !f->isVirtual())
- continue;
+ if ((query & VirtualInCppFunctions) && !f->isVirtual())
+ return false;
- if ((query & Signals) && (!f->isSignal()))
- continue;
+ if ((query & Signals) && (!f->isSignal()))
+ return false;
- if ((query & Constructors) && (!f->isConstructor() || f->ownerClass() != f->implementingClass()))
- continue;
+ if ((query & Constructors) && (!f->isConstructor() || f->ownerClass() != f->implementingClass()))
+ return false;
- if (!(query & Constructors) && f->isConstructor())
- continue;
+ if (!(query & Constructors) && f->isConstructor())
+ return false;
- // Destructors are never included in the functions of a class currently
- /*
+ // Destructors are never included in the functions of a class currently
+ /*
if ((query & Destructors) && (!f->isDestructor()
|| f->ownerClass() != f->implementingClass())
|| f->isDestructor() && (query & Destructors) == 0) {
- continue;
+ return false;
}*/
- if ((query & StaticFunctions) && (!f->isStatic() || f->isSignal()))
- continue;
+ if ((query & StaticFunctions) && (!f->isStatic() || f->isSignal()))
+ return false;
- if ((query & NonStaticFunctions) && (f->isStatic()))
- continue;
+ if ((query & NonStaticFunctions) && (f->isStatic()))
+ return false;
- if ((query & NormalFunctions) && (f->isSignal()))
- continue;
+ if ((query & NormalFunctions) && (f->isSignal()))
+ return false;
- if ((query & OperatorOverloads) && !f->isOperatorOverload())
- continue;
+ if ((query & OperatorOverloads) && !f->isOperatorOverload())
+ return false;
+
+ if ((query & GenerateExceptionHandling) && !f->generateExceptionHandling())
+ return false;
+
+ return true;
+}
- functions << f;
+AbstractMetaFunctionList AbstractMetaClass::queryFunctionList(const AbstractMetaFunctionList &list,
+ FunctionQueryOptions query)
+{
+ AbstractMetaFunctionList result;
+ for (AbstractMetaFunction *f : list) {
+ if (queryFunction(f, query))
+ result.append(f);
+ }
+ return result;
+}
+
+const AbstractMetaFunction *AbstractMetaClass::queryFirstFunction(const AbstractMetaFunctionList &list,
+ FunctionQueryOptions query)
+{
+ AbstractMetaFunctionList result;
+ for (AbstractMetaFunction *f : list) {
+ if (queryFunction(f, query))
+ return f;
}
+ return nullptr;
+}
- return functions;
+AbstractMetaFunctionList AbstractMetaClass::queryFunctions(FunctionQueryOptions query) const
+{
+ return AbstractMetaClass::queryFunctionList(m_functions, query);
}
bool AbstractMetaClass::hasSignals() const
{
- return cppSignalFunctions().size() > 0;
+ return queryFirstFunction(m_functions, Signals | Visible | NotRemovedFromTargetLang) != nullptr;
}
+AbstractMetaFunctionList AbstractMetaClass::cppSignalFunctions() const
+{
+ return queryFunctions(Signals | Visible | NotRemovedFromTargetLang);
+}
/**
* Adds the specified interface to this class by adding all the
@@ -1932,13 +2078,15 @@ void AbstractMetaClass::setInterfaces(const AbstractMetaClassList &interfaces)
}
}
+AbstractMetaField *AbstractMetaClass::findField(const QString &name) const
+{
+ return AbstractMetaField::find(m_fields, name);
+}
AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName)
{
- for (AbstractMetaEnum *e : qAsConst(m_enums)) {
- if (e->name() == enumName)
- return e;
- }
+ if (AbstractMetaEnum *e = findByName(m_enums, enumName))
+ return e;
if (typeEntry()->designatedInterface())
return extractInterface()->findEnum(enumName);
@@ -2002,8 +2150,8 @@ void AbstractMetaClass::fixFunctions()
{
if (m_functionsFixed)
return;
- else
- m_functionsFixed = true;
+
+ m_functionsFixed = true;
AbstractMetaClass *superClass = baseClass();
AbstractMetaFunctionList funcs = functions();
@@ -2046,8 +2194,7 @@ void AbstractMetaClass::fixFunctions()
// we generally don't care about private functions, but we have to get the ones that are
// virtual in case they override abstract functions.
bool add = (sf->isNormal() || sf->isSignal() || sf->isEmptyFunction());
- for (int fi = 0; fi < funcs.size(); ++fi) {
- AbstractMetaFunction *f = funcs.at(fi);
+ for (AbstractMetaFunction *f : funcs) {
if (f->isRemovedFromAllLanguages(f->implementingClass()))
continue;
@@ -2114,7 +2261,8 @@ void AbstractMetaClass::fixFunctions()
if (mod.isNonFinal()) {
hasNonFinalModifier = true;
break;
- } else if (mod.isPrivate()) {
+ }
+ if (mod.isPrivate()) {
isBaseImplPrivate = true;
break;
}
@@ -2222,6 +2370,8 @@ QString AbstractMetaType::formatSignature(bool minimal) const
QString result;
if (isConstant())
result += QLatin1String("const ");
+ if (isVolatile())
+ result += QLatin1String("volatile ");
if (isArray()) {
// Build nested array dimensions a[2][3] in correct order
result += m_arrayElementType->minimalSignature();
@@ -2245,10 +2395,10 @@ QString AbstractMetaType::formatSignature(bool minimal) const
result += QLatin1String(" >");
}
- if (!minimal && (m_indirections != 0 || m_referenceType != NoReference))
+ if (!minimal && (!m_indirections.isEmpty() || m_referenceType != NoReference))
result += QLatin1Char(' ');
- if (m_indirections)
- result += QString(m_indirections, QLatin1Char('*'));
+ for (Indirection i : m_indirections)
+ result += TypeInfo::indirectionKeyword(i);
switch (referenceType()) {
case NoReference:
break;
@@ -2376,6 +2526,8 @@ QDebug operator<<(QDebug d, const AbstractMetaClass *ac)
d << " [final]";
if (ac->m_baseClass)
d << ", inherits \"" << ac->m_baseClass->name() << '"';
+ if (ac->m_templateBaseClass)
+ d << ", inherits template \"" << ac->m_templateBaseClass->name() << '"';
const AbstractMetaEnumList &enums = ac->enums();
if (!enums.isEmpty())
d << ", enums[" << enums.size() << "]=" << enums;
@@ -2406,6 +2558,18 @@ QDebug operator<<(QDebug d, const AbstractMetaClass *ac)
}
d << ')';
}
+ const auto &templateArguments = ac->templateArguments();
+ if (const int count = templateArguments.size()) {
+ d << ", templateArguments=[" << count << "](";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ d << ", ";
+ d << templateArguments.at(i);
+ }
+ d << ')';
+ }
+
+
} else {
d << '0';
}
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
index d1a0fbf88..aaefa32d5 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -288,6 +288,7 @@ class AbstractMetaType
{
Q_GADGET
public:
+ typedef QVector<Indirection> Indirections;
enum TypeUsagePattern {
InvalidPattern,
@@ -436,6 +437,9 @@ public:
m_constant = constant;
}
+ bool isVolatile() const { return m_volatile; }
+ void setVolatile(bool v) { m_volatile = v; }
+
bool isConstRef() const;
ReferenceType referenceType() const { return m_referenceType; }
@@ -443,16 +447,21 @@ public:
int actualIndirections() const
{
- return m_indirections + (m_referenceType == LValueReference ? 1 : 0);
- }
- int indirections() const
- {
- return m_indirections;
+ return m_indirections.size() + (m_referenceType == LValueReference ? 1 : 0);
}
+
+ Indirections indirectionsV() const { return m_indirections; }
+ void setIndirectionsV(const Indirections &i) { m_indirections = i; }
+ void clearIndirections() { m_indirections.clear(); }
+
+ // "Legacy"?
+ int indirections() const { return m_indirections.size(); }
void setIndirections(int indirections)
{
- m_indirections = indirections;
+ m_indirections = Indirections(indirections, Indirection::Pointer);
}
+ void addIndirection(Indirection i = Indirection::Pointer)
+ { m_indirections.append(i); }
void setArrayElementCount(int n)
{
@@ -527,6 +536,8 @@ public:
bool hasTemplateChildren() const;
+ bool equals(const AbstractMetaType &rhs) const;
+
private:
TypeUsagePattern determineUsagePattern() const;
QString formatSignature(bool minimal) const;
@@ -541,18 +552,25 @@ private:
int m_arrayElementCount = -1;
const AbstractMetaType *m_arrayElementType = nullptr;
const AbstractMetaType *m_originalTemplateType = nullptr;
+ Indirections m_indirections;
TypeUsagePattern m_pattern = InvalidPattern;
uint m_constant : 1;
+ uint m_volatile : 1;
uint m_cppInstantiation : 1;
- int m_indirections : 4;
- uint m_reserved : 26; // unused
+ uint m_reserved : 29; // unused
+
ReferenceType m_referenceType = NoReference;
AbstractMetaTypeList m_children;
Q_DISABLE_COPY(AbstractMetaType)
};
+inline bool operator==(const AbstractMetaType &t1, const AbstractMetaType &t2)
+{ return t1.equals(t2); }
+inline bool operator!=(const AbstractMetaType &t1, const AbstractMetaType &t2)
+{ return !t1.equals(t2); }
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const AbstractMetaType *at);
#endif
@@ -650,6 +668,13 @@ public:
m_originalExpression = expr;
}
+ bool hasDefaultValueExpression() const
+ { return !m_originalExpression.isEmpty() || !m_expression.isEmpty(); }
+ bool hasUnmodifiedDefaultValueExpression() const
+ { return !m_originalExpression.isEmpty() && m_originalExpression == m_expression; }
+ bool hasModifiedDefaultValueExpression() const
+ { return !m_expression.isEmpty() && m_originalExpression != m_expression; }
+
QString toString() const
{
return type()->name() + QLatin1Char(' ') + AbstractMetaVariable::name() +
@@ -709,6 +734,9 @@ public:
AbstractMetaField *copy() const;
+ static AbstractMetaField *
+ find(const AbstractMetaFieldList &haystack, const QString &needle);
+
private:
mutable AbstractMetaFunction *m_getter = nullptr;
mutable AbstractMetaFunction *m_setter = nullptr;
@@ -816,13 +844,20 @@ public:
return m_explicit;
}
- static bool isConversionOperator(QString funcName);
+ static bool isConversionOperator(const QString& funcName);
+
+ ExceptionSpecification exceptionSpecification() const;
+ void setExceptionSpecification(ExceptionSpecification e);
+
+ bool generateExceptionHandling() const { return m_generateExceptionHandling; }
+ void setGenerateExceptionHandling(bool g) { m_generateExceptionHandling = g; }
+
bool isConversionOperator() const
{
return isConversionOperator(originalName());
}
- static bool isOperatorOverload(QString funcName);
+ static bool isOperatorOverload(const QString& funcName);
bool isOperatorOverload() const
{
return isOperatorOverload(originalName());
@@ -1000,9 +1035,8 @@ public:
// Returns the ownership rules for the given argument in the given context
TypeSystem::Ownership ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int idx) const;
- bool isVirtualSlot() const;
-
QString typeReplaced(int argument_index) const;
+ bool isModifiedToArray(int argumentIndex) const;
bool isRemovedFromAllLanguages(const AbstractMetaClass *) const;
bool isRemovedFrom(const AbstractMetaClass *, TypeSystem::Language language) const;
bool argumentRemoved(int) const;
@@ -1057,11 +1091,16 @@ public:
bool isCallOperator() const;
+ static AbstractMetaFunction *
+ find(const AbstractMetaFunctionList &haystack, const QString &needle);
+
#ifndef QT_NO_DEBUG_STREAM
void formatDebugVerbose(QDebug &d) const;
#endif
private:
+ bool autoDetectAllowThread() const;
+
QString m_name;
QString m_originalName;
mutable QString m_cachedMinimalSignature;
@@ -1082,6 +1121,9 @@ private:
uint m_explicit : 1;
uint m_pointerOperator : 1;
uint m_isCallOperator : 1;
+ uint m_generateExceptionHandling: 1;
+ mutable int m_cachedAllowThread = -1;
+ ExceptionSpecification m_exceptionSpecification = ExceptionSpecification::Unknown;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::CompareResult)
@@ -1246,7 +1288,8 @@ public:
VirtualInCppFunctions = 0x0020000, // Only functions that are virtual in C++
VirtualInTargetLangFunctions = 0x0080000, // Only functions which are virtual in TargetLang
NotRemovedFromTargetLang = 0x0400000, // Only functions that have not been removed from TargetLang
- OperatorOverloads = 0x2000000 // Only functions that are operator overloads
+ OperatorOverloads = 0x2000000, // Only functions that are operator overloads
+ GenerateExceptionHandling = 0x4000000
};
Q_DECLARE_FLAGS(FunctionQueryOptions, FunctionQueryOption)
Q_FLAG(FunctionQueryOption)
@@ -1286,7 +1329,8 @@ public:
bool hasSignal(const AbstractMetaFunction *f) const;
bool hasConstructors() const;
- bool hasCopyConstructor() const;
+ const AbstractMetaFunction *copyConstructor() const;
+ bool hasCopyConstructor() const { return copyConstructor() != nullptr; }
bool hasPrivateCopyConstructor() const;
void addDefaultConstructor();
@@ -1347,10 +1391,18 @@ public:
return (hasNonPrivateConstructor() || !hasPrivateConstructor()) && !hasPrivateDestructor();
}
+ bool generateExceptionHandling() const;
+
AbstractMetaFunctionList queryFunctionsByName(const QString &name) const;
+ static bool queryFunction(const AbstractMetaFunction *f, FunctionQueryOptions query);
+ static AbstractMetaFunctionList queryFunctionList(const AbstractMetaFunctionList &list,
+ FunctionQueryOptions query);
+ static const AbstractMetaFunction *queryFirstFunction(const AbstractMetaFunctionList &list,
+ FunctionQueryOptions query);
+
AbstractMetaFunctionList queryFunctions(FunctionQueryOptions query) const;
AbstractMetaFunctionList functionsInTargetLang() const;
- inline AbstractMetaFunctionList cppSignalFunctions() const;
+ AbstractMetaFunctionList cppSignalFunctions() const;
AbstractMetaFunctionList implicitConversions() const;
/**
@@ -1383,6 +1435,8 @@ public:
m_fields << field;
}
+ AbstractMetaField *findField(const QString &name) const;
+
AbstractMetaEnumList enums() const
{
return m_enums;
@@ -1478,11 +1532,6 @@ public:
m_forceShellClass = on;
}
- bool hasVirtualSlots() const
- {
- return m_hasVirtualSlots;
- }
-
/**
* Says if the class that declares or inherits a virtual function.
* \return true if the class implements or inherits any virtual methods
@@ -1650,6 +1699,8 @@ public:
return m_hasToStringCapability;
}
+ bool deleteInMainThread() const;
+
static AbstractMetaClass *findClass(const AbstractMetaClassList &classes,
const QString &name);
static AbstractMetaClass *findClass(const AbstractMetaClassList &classes,
@@ -1666,7 +1717,6 @@ private:
uint m_hasVirtuals : 1;
uint m_isPolymorphic : 1;
uint m_hasNonpublic : 1;
- uint m_hasVirtualSlots : 1;
uint m_hasNonPrivateConstructor : 1;
uint m_hasPrivateConstructor : 1;
uint m_functionsFixed : 1;
@@ -1784,11 +1834,4 @@ private:
int m_index = -1;
};
-inline AbstractMetaFunctionList AbstractMetaClass::cppSignalFunctions() const
-{
- return queryFunctions(Signals
- | Visible
- | NotRemovedFromTargetLang);
-}
-
#endif // ABSTRACTMETALANG_H
diff --git a/sources/shiboken2/ApiExtractor/apiextractor.cpp b/sources/shiboken2/ApiExtractor/apiextractor.cpp
index 171011cd4..775485c81 100644
--- a/sources/shiboken2/ApiExtractor/apiextractor.cpp
+++ b/sources/shiboken2/ApiExtractor/apiextractor.cpp
@@ -177,41 +177,9 @@ static const AbstractMetaEnum* findEnumOnClasses(AbstractMetaClassList metaClass
return result;
}
-const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const
-{
- if (!typeEntry)
- return 0;
- const AbstractMetaEnumList &globalEnums = m_builder->globalEnums();
- for (AbstractMetaEnum* metaEnum : globalEnums) {
- if (metaEnum->typeEntry() == typeEntry)
- return metaEnum;
- }
- return findEnumOnClasses(m_builder->classes(), typeEntry);
-}
-
const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const TypeEntry* typeEntry) const
{
- if (!typeEntry)
- return 0;
- if (typeEntry->isFlags())
- return findAbstractMetaEnum(reinterpret_cast<const FlagsTypeEntry*>(typeEntry));
- if (typeEntry->isEnum())
- return findAbstractMetaEnum(reinterpret_cast<const EnumTypeEntry*>(typeEntry));
- return 0;
-}
-
-const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const
-{
- if (!typeEntry)
- return 0;
- return findAbstractMetaEnum(typeEntry->originator());
-}
-
-const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const AbstractMetaType* metaType) const
-{
- if (!metaType)
- return 0;
- return findAbstractMetaEnum(metaType->typeEntry());
+ return m_builder->findEnum(typeEntry);
}
int ApiExtractor::classCount() const
diff --git a/sources/shiboken2/ApiExtractor/apiextractor.h b/sources/shiboken2/ApiExtractor/apiextractor.h
index 674e5a742..ab520c9de 100644
--- a/sources/shiboken2/ApiExtractor/apiextractor.h
+++ b/sources/shiboken2/ApiExtractor/apiextractor.h
@@ -87,10 +87,7 @@ public:
PrimitiveTypeEntryList primitiveTypes() const;
ContainerTypeEntryList containerTypes() const;
- const AbstractMetaEnum* findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const;
const AbstractMetaEnum* findAbstractMetaEnum(const TypeEntry* typeEntry) const;
- const AbstractMetaEnum* findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const;
- const AbstractMetaEnum* findAbstractMetaEnum(const AbstractMetaType* metaType) const;
int classCount() const;
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
index af7f96068..40f915028 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
@@ -146,6 +146,7 @@ class BuilderPrivate {
public:
typedef QHash<CXCursor, ClassModelItem> CursorClassHash;
typedef QHash<CXCursor, TypeDefModelItem> CursorTypedefHash;
+ typedef QHash<CXType, TypeInfo> TypeInfoHash;
explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv), m_model(new CodeModel)
{
@@ -180,9 +181,16 @@ public:
CodeModel::FunctionType t = CodeModel::Normal) const;
FunctionModelItem createMemberFunction(const CXCursor &cursor) const;
void qualifyConstructor(const CXCursor &cursor);
+ TypeInfo createTypeInfoHelper(const CXType &type) const; // uncashed
TypeInfo createTypeInfo(const CXType &type) const;
TypeInfo createTypeInfo(const CXCursor &cursor) const
{ return createTypeInfo(clang_getCursorType(cursor)); }
+ void addTemplateInstantiations(const CXType &type,
+ QString *typeName,
+ TypeInfo *t) const;
+ bool addTemplateInstantiationsRecursion(const CXType &type, TypeInfo *t) const;
+
+ void addTypeDef(const CXCursor &cursor, const TypeInfo &ti);
TemplateParameterModelItem createTemplateParameter(const CXCursor &cursor) const;
TemplateParameterModelItem createNonTypeTemplateParameter(const CXCursor &cursor) const;
@@ -205,6 +213,8 @@ public:
CursorClassHash m_cursorClassHash;
CursorTypedefHash m_cursorTypedefHash;
+ mutable TypeInfoHash m_typeInfoHash; // Cache type information
+
ClassModelItem m_currentClass;
EnumModelItem m_currentEnum;
FunctionModelItem m_currentFunction;
@@ -247,6 +257,25 @@ bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t)
return true;
}
+static inline ExceptionSpecification exceptionSpecificationFromClang(int ce)
+{
+ switch (ce) {
+ case CXCursor_ExceptionSpecificationKind_BasicNoexcept:
+ case CXCursor_ExceptionSpecificationKind_ComputedNoexcept:
+ case CXCursor_ExceptionSpecificationKind_DynamicNone: // throw()
+ return ExceptionSpecification::NoExcept;
+ case CXCursor_ExceptionSpecificationKind_Dynamic: // throw(t1..)
+ case CXCursor_ExceptionSpecificationKind_MSAny: // throw(...)
+ return ExceptionSpecification::Throws;
+ default:
+ // CXCursor_ExceptionSpecificationKind_None,
+ // CXCursor_ExceptionSpecificationKind_Unevaluated,
+ // CXCursor_ExceptionSpecificationKind_Uninstantiated
+ break;
+ }
+ return ExceptionSpecification::Unknown;
+}
+
FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor,
CodeModel::FunctionType t) const
{
@@ -256,10 +285,11 @@ FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor,
name = fixTypeName(name);
FunctionModelItem result(new _FunctionModelItem(m_model, name));
setFileName(cursor, result.data());
- result->setType(createTypeInfo(clang_getCursorResultType(cursor)));
+ result->setType(createTypeInfoHelper(clang_getCursorResultType(cursor)));
result->setFunctionType(t);
result->setScope(m_scope);
result->setStatic(clang_Cursor_getStorageClass(cursor) == CX_SC_Static);
+ result->setExceptionSpecification(exceptionSpecificationFromClang(clang_getCursorExceptionSpecificationType(cursor)));
switch (clang_getCursorAvailability(cursor)) {
case CXAvailability_Available:
break;
@@ -335,7 +365,7 @@ TemplateParameterModelItem BuilderPrivate::createTemplateParameter(const CXCurso
TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const CXCursor &cursor) const
{
TemplateParameterModelItem result = createTemplateParameter(cursor);
- result->setType(createTypeInfo(cursor));
+ result->setType(createTypeInfoHelper(clang_getCursorType(cursor)));
return result;
}
@@ -359,38 +389,6 @@ struct ArrayDimensionResult
int position;
};
-static ArrayDimensionResult arrayDimensions(const QString &typeName)
-{
- ArrayDimensionResult result;
- result.position = typeName.indexOf(QLatin1Char('['));
- for (int openingPos = result.position; openingPos != -1; ) {
- const int closingPos = typeName.indexOf(QLatin1Char(']'), openingPos + 1);
- if (closingPos == -1)
- break;
- result.dimensions.append(typeName.midRef(openingPos + 1, closingPos - openingPos - 1));
- openingPos = typeName.indexOf(QLatin1Char('['), closingPos + 1);
- }
- return result;
-}
-
-// Array helpers: Parse "a[2][4]" into a list of dimensions or "" for none
-static QStringList parseArrayArgs(const CXType &type, QString *typeName)
-{
- const ArrayDimensionResult dimensions = arrayDimensions(*typeName);
- Q_ASSERT(!dimensions.dimensions.isEmpty());
-
- QStringList result;
- // get first dimension from clang, preferably.
- // "a[]" is seen as pointer by Clang, set special indicator ""
- const long long size = clang_getArraySize(type);
- result.append(size >= 0 ? QString::number(size) : QString());
- // Parse out remaining dimensions
- for (int i = 1, count = dimensions.dimensions.size(); i < count; ++i)
- result.append(dimensions.dimensions.at(i).toString());
- typeName->truncate(dimensions.position);
- return result;
-}
-
// Create qualified name "std::list<std::string>" -> ("std", "list<std::string>")
static QStringList qualifiedName(const QString &t)
{
@@ -412,71 +410,143 @@ static QStringList qualifiedName(const QString &t)
return result;
}
-TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const
+static bool isArrayType(CXTypeKind k)
+{
+ return k == CXType_ConstantArray || k == CXType_IncompleteArray
+ || k == CXType_VariableArray || k == CXType_DependentSizedArray;
+}
+
+static bool isPointerType(CXTypeKind k)
+{
+ return k == CXType_Pointer || k == CXType_LValueReference || k == CXType_RValueReference;
+}
+
+bool BuilderPrivate::addTemplateInstantiationsRecursion(const CXType &type, TypeInfo *t) const
+{
+ // Template arguments
+ switch (type.kind) {
+ case CXType_Elaborated:
+ case CXType_Record:
+ case CXType_Unexposed:
+ if (const int numTemplateArguments = qMax(0, clang_Type_getNumTemplateArguments(type))) {
+ for (unsigned tpl = 0; tpl < unsigned(numTemplateArguments); ++tpl) {
+ const CXType argType = clang_Type_getTemplateArgumentAsType(type, tpl);
+ // CXType_Invalid is returned when hitting on a specialization
+ // of a non-type template (template <int v>).
+ if (argType.kind == CXType_Invalid)
+ return false;
+ t->addInstantiation(createTypeInfoHelper(argType));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+static void dummyTemplateArgumentHandler(int, const QStringRef &) {}
+
+void BuilderPrivate::addTemplateInstantiations(const CXType &type,
+ QString *typeName,
+ TypeInfo *t) const
+{
+ // In most cases, for templates like "Vector<A>", Clang will give us the
+ // arguments by recursing down the type. However this will fail for example
+ // within template classes (for functions like the copy constructor):
+ // template <class T>
+ // class Vector {
+ // Vector(const Vector&);
+ // };
+ // In that case, have TypeInfo parse the list from the spelling.
+ // Finally, remove the list "<>" from the type name.
+ const bool parsed = addTemplateInstantiationsRecursion(type, t)
+ && !t->instantiations().isEmpty();
+ const QPair<int, int> pos = parsed
+ ? parseTemplateArgumentList(*typeName, dummyTemplateArgumentHandler)
+ : t->parseTemplateArgumentList(*typeName);
+ if (pos.first != -1 && pos.second != -1 && pos.second > pos.first)
+ typeName->remove(pos.first, pos.second - pos.first);
+}
+
+TypeInfo BuilderPrivate::createTypeInfoHelper(const CXType &type) const
{
if (type.kind == CXType_Pointer) { // Check for function pointers, first.
const CXType pointeeType = clang_getPointeeType(type);
const int argCount = clang_getNumArgTypes(pointeeType);
if (argCount >= 0) {
- TypeInfo result = createTypeInfo(clang_getResultType(pointeeType));
+ TypeInfo result = createTypeInfoHelper(clang_getResultType(pointeeType));
result.setFunctionPointer(true);
for (int a = 0; a < argCount; ++a)
- result.addArgument(createTypeInfo(clang_getArgType(pointeeType, unsigned(a))));
+ result.addArgument(createTypeInfoHelper(clang_getArgType(pointeeType, unsigned(a))));
return result;
}
}
TypeInfo typeInfo;
- QString typeName = fixTypeName(getTypeName(type));
- int indirections = 0;
- // "int **"
- for ( ; typeName.endsWith(QLatin1Char('*')) ; ++indirections)
- typeName.chop(1);
- typeInfo.setIndirections(indirections);
- // "int &&"
- if (typeName.endsWith(QLatin1String("&&"))) {
- typeName.chop(2);
- typeInfo.setReferenceType(RValueReference);
- } else if (typeName.endsWith(QLatin1Char('&'))) { // "int &"
- typeName.chop(1);
- typeInfo.setReferenceType(LValueReference);
+ CXType nestedType = type;
+ for (; isArrayType(nestedType.kind); nestedType = clang_getArrayElementType(nestedType)) {
+ const long long size = clang_getArraySize(nestedType);
+ typeInfo.addArrayElement(size >= 0 ? QString::number(size) : QString());
}
- // "int [3], int[]"
- if (type.kind == CXType_ConstantArray || type.kind == CXType_IncompleteArray
- || type.kind == CXType_VariableArray || type.kind == CXType_DependentSizedArray) {
- typeInfo.setArrayElements(parseArrayArgs(type, &typeName));
+ TypeInfo::Indirections indirections;
+ for (; isPointerType(nestedType.kind); nestedType = clang_getPointeeType(nestedType)) {
+ switch (nestedType.kind) {
+ case CXType_Pointer:
+ indirections.prepend(clang_isConstQualifiedType(nestedType) != 0
+ ? Indirection::ConstPointer : Indirection::Pointer);
+ break;
+ case CXType_LValueReference:
+ typeInfo.setReferenceType(LValueReference);
+ break;
+ case CXType_RValueReference:
+ typeInfo.setReferenceType(RValueReference);
+ break;
+ default:
+ break;
+ }
}
+ typeInfo.setIndirectionsV(indirections);
- bool isConstant = clang_isConstQualifiedType(type) != 0;
- // A "char *const" parameter, is considered to be const-qualified by Clang, but
- // not in the TypeInfo sense (corresponds to "char *" and not "const char *").
- if (type.kind == CXType_Pointer && isConstant && typeName.endsWith(QLatin1String("const"))) {
- typeName.chop(5);
- typeName = typeName.trimmed();
- isConstant = false;
- }
- // Clang has been observed to return false for "const int .."
- if (!isConstant && typeName.startsWith(QLatin1String("const "))) {
- typeName.remove(0, 6);
- isConstant = true;
- }
- typeInfo.setConstant(isConstant);
+ typeInfo.setConstant(clang_isConstQualifiedType(nestedType) != 0);
+ typeInfo.setVolatile(clang_isVolatileQualifiedType(nestedType) != 0);
- // clang_isVolatileQualifiedType() returns true for "volatile int", but not for "volatile int *"
- if (typeName.startsWith(QLatin1String("volatile "))) {
- typeName.remove(0, 9);
- typeInfo.setVolatile(true);
+ QString typeName = getTypeName(nestedType);
+ while (TypeInfo::stripLeadingConst(&typeName)
+ || TypeInfo::stripLeadingVolatile(&typeName)) {
}
- typeName = typeName.trimmed();
+ // Obtain template instantiations if the name has '<' (thus excluding
+ // typedefs like "std::string".
+ if (typeName.contains(QLatin1Char('<')))
+ addTemplateInstantiations(nestedType, &typeName, &typeInfo);
typeInfo.setQualifiedName(qualifiedName(typeName));
// 3320:CINDEX_LINKAGE int clang_getNumArgTypes(CXType T); function ptr types?
+ typeInfo.simplifyStdType();
return typeInfo;
}
+TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const
+{
+ TypeInfoHash::iterator it = m_typeInfoHash.find(type);
+ if (it == m_typeInfoHash.end())
+ it = m_typeInfoHash.insert(type, createTypeInfoHelper(type));
+ return it.value();
+}
+
+void BuilderPrivate::addTypeDef(const CXCursor &cursor, const TypeInfo &ti)
+{
+ TypeDefModelItem item(new _TypeDefModelItem(m_model, getCursorSpelling(cursor)));
+ setFileName(cursor, item.data());
+ item->setType(ti);
+ item->setScope(m_scope);
+ m_scopeStack.back()->addTypeDef(item);
+ m_cursorTypedefHash.insert(cursor, item);
+}
+
// extract an expression from the cursor via source
// CXCursor_EnumConstantDecl, ParmDecl (a = Flag1 | Flag2)
QString BuilderPrivate::cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor) const
@@ -795,9 +865,8 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
d->m_currentFunction = d->createMemberFunction(cursor);
d->m_scopeStack.back()->addFunction(d->m_currentFunction);
break;
- } else {
- return Skip; // inline member functions outside class
}
+ return Skip; // inline member functions outside class
}
}
Q_FALLTHROUGH(); // fall through to free template function.
@@ -868,17 +937,14 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
}
break;
case CXCursor_TypeAliasDecl:
- case CXCursor_TypeAliasTemplateDecl: // May contain nested CXCursor_TemplateTypeParameter
- return Skip;
- case CXCursor_TypedefDecl: {
- const QString name = getCursorSpelling(cursor);
- TypeDefModelItem item(new _TypeDefModelItem(d->m_model, name));
- setFileName(cursor, item.data());
- item->setType(d->createTypeInfo(clang_getTypedefDeclUnderlyingType(cursor)));
- item->setScope(d->m_scope);
- d->m_scopeStack.back()->addTypeDef(item);
- d->m_cursorTypedefHash.insert(cursor, item);
+ case CXCursor_TypeAliasTemplateDecl: { // May contain nested CXCursor_TemplateTypeParameter
+ const CXType type = clang_getCanonicalType(clang_getCursorType(cursor));
+ if (type.kind > CXType_Unexposed)
+ d->addTypeDef(cursor, d->createTypeInfo(type));
}
+ return Skip;
+ case CXCursor_TypedefDecl:
+ d->addTypeDef(cursor, d->createTypeInfo(clang_getTypedefDeclUnderlyingType(cursor)));
break;
case CXCursor_TypeRef:
if (!d->m_currentFunction.isNull()) {
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp
index ce0b6554d..e116f8b83 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp
@@ -166,7 +166,7 @@ static inline const char **byteArrayListToFlatArgV(const QByteArrayList &bl)
return result;
}
-static QByteArray msgCreateTranslationUnit(const QByteArrayList clangArgs, unsigned flags)
+static QByteArray msgCreateTranslationUnit(const QByteArrayList &clangArgs, unsigned flags)
{
QByteArray result = "clang_parseTranslationUnit2(0x";
result += QByteArray::number(flags, 16);
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
index 2ff18b23b..8bee28cdf 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
@@ -46,6 +46,18 @@ uint qHash(const CXCursor &c, uint seed)
^ qHash(c.data[1]) ^ qHash(c.data[2]) ^ seed;
}
+bool operator==(const CXType &t1, const CXType &t2)
+{
+ return t1.kind == t2.kind && t1.data[0] == t2.data[0]
+ && t1.data[1] == t2.data[1];
+}
+
+uint qHash(const CXType &ct, uint seed)
+{
+ return uint(ct.kind) ^ uint(0xFFFFFFFF & quintptr(ct.data[0]))
+ ^ uint(0xFFFFFFFF & quintptr(ct.data[1])) ^ seed;
+}
+
namespace clang {
SourceLocation getExpansionLocation(const CXSourceLocation &location)
@@ -160,6 +172,43 @@ QVector<Diagnostic> getDiagnostics(CXTranslationUnit tu)
return result;
}
+QPair<int, int> parseTemplateArgumentList(const QString &l,
+ const TemplateArgumentHandler &handler,
+ int from)
+{
+ const int ltPos = l.indexOf(QLatin1Char('<'), from);
+ if (ltPos == - 1)
+ return qMakePair(-1, -1);
+ int startPos = ltPos + 1;
+ int level = 1;
+ for (int p = startPos, end = l.size(); p < end; ) {
+ const char c = l.at(p).toLatin1();
+ switch (c) {
+ case ',':
+ case '>':
+ handler(level, l.midRef(startPos, p - startPos).trimmed());
+ ++p;
+ if (c == '>') {
+ if (--level == 0)
+ return qMakePair(ltPos, p);
+ // Skip over next ',': "a<b<c,d>,e>"
+ for (; p < end && (l.at(p).isSpace() || l.at(p) == QLatin1Char(',')); ++p) {}
+ }
+ startPos = p;
+ break;
+ case '<':
+ handler(level, l.midRef(startPos, p - startPos).trimmed());
+ ++level;
+ startPos = ++p;
+ break;
+ default:
+ ++p;
+ break;
+ }
+ }
+ return qMakePair(-1, -1);
+}
+
CXDiagnosticSeverity maxSeverity(const QVector<Diagnostic> &ds)
{
CXDiagnosticSeverity result = CXDiagnostic_Ignored;
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
index 98d0c9752..b290aac9a 100644
--- a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
@@ -34,11 +34,16 @@
#include <QtCore/QString>
#include <QtCore/QVector>
+#include <functional>
+
QT_FORWARD_DECLARE_CLASS(QDebug)
bool operator==(const CXCursor &c1, const CXCursor &c2);
uint qHash(const CXCursor &c, uint seed = 0);
+bool operator==(const CXType &t1, const CXType &t2);
+uint qHash(const CXType &ct, uint seed);
+
namespace clang {
QString getCursorKindName(CXCursorKind cursorKind);
@@ -92,6 +97,14 @@ struct Diagnostic {
QVector<Diagnostic> getDiagnostics(CXTranslationUnit tu);
CXDiagnosticSeverity maxSeverity(const QVector<Diagnostic> &ds);
+// Parse a template argument list "a<b<c,d>,e>" and invoke a handler
+// with each match (level and string). Return begin and end of the list.
+typedef std::function<void(int /*level*/, const QStringRef &)> TemplateArgumentHandler;
+
+QPair<int, int> parseTemplateArgumentList(const QString &l,
+ const TemplateArgumentHandler &handler,
+ int from = 0);
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug, const SourceLocation &);
QDebug operator<<(QDebug, const Diagnostic &);
diff --git a/sources/shiboken2/ApiExtractor/doc/conf.py.in b/sources/shiboken2/ApiExtractor/doc/conf.py.in
index 7251aaccd..609c4a363 100644
--- a/sources/shiboken2/ApiExtractor/doc/conf.py.in
+++ b/sources/shiboken2/ApiExtractor/doc/conf.py.in
@@ -132,10 +132,6 @@ html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_themes']
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-html_use_smartypants = True
-
# Custom sidebar templates, maps document names to template names.
#html_sidebars = { '' : ''}
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst
index ff6ea5317..12b866ad7 100644
--- a/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst
@@ -11,6 +11,9 @@ inject-code
given type or function, and it is a child of the :ref:`object-type`, :ref:`value-type`,
:ref:`modify-function` and :ref:`add-function` nodes.
+ The code can be embedded into XML (be careful to use the correct XML entities
+ for characters like '<', '>', '&'):
+
.. code-block:: xml
<value-type>
@@ -20,6 +23,18 @@ inject-code
</inject-code>
</value-type>
+ or obtained from an external file:
+
+ .. code-block:: xml
+
+ <value-type>
+ <inject-code class="native | target | target-declaration"
+ position="beginning | end" since="..."
+ file="external_source.cpp"
+ snippet="label"/>
+ </value-type>
+
+
The ``class`` attribute specifies which module of the generated code that
will be affected by the code injection. The ``class`` attribute accepts the
following values:
@@ -28,6 +43,8 @@ inject-code
* target: The binding code
* target-declaration: The code will be injected into the generated header
file containing the c++ wrapper class definition.
+ * file: The file name
+ * snippet: The snippet label (optional)
If the ``position`` attribute is set to *beginning* (the default), the code
is inserted at the beginning of the function. If it is set to *end*, the code
@@ -35,6 +52,16 @@ inject-code
The ``since`` attribute specify the API version where this code was injected.
+ If a ``snippet`` label is given, the code between annotations of the form
+
+ .. code-block:: c++
+
+ // @snippet label
+ ...
+ // @snippet label
+
+ will be extracted.
+
modify-field
^^^^^^^^^^^^
@@ -74,6 +101,8 @@ modify-function
since="..."
remove="all | c++"
access="public | private | protected"
+ allow-thread="true | auto | false"
+ exception-handling="off | auto-off | auto-on | on"
rename="..." />
</object-type>
@@ -82,6 +111,26 @@ modify-function
The ``since`` attribute specify the API version when this function was modified.
+ The ``allow-thread`` attribute specifies whether a function should be wrapped
+ into ``Py_BEGIN_ALLOW_THREADS`` and ``Py_END_ALLOW_THREADS``, that is,
+ temporarily release the GIL (global interpreter lock). Doing so is required
+ for any thread-related function (wait operations), functions that might call
+ a virtual function (potentially reimplemented in Python), and recommended for
+ lengthy I/O operations or similar. It has performance costs, though.
+ The value ``auto`` means that it will be turned off for functions for which
+ it is deemed to be safe, for example, simple getters.
+
+ The ``exception-handling`` attribute specifies whether to generate exception
+ handling code (nest the function call into try / catch statements). It accepts
+ the following values:
+
+ * no, false: Do not generate exception handling code
+ * auto-off: Generate exception handling code for functions
+ declaring a non-empty ``throw`` list
+ * auto-on: Generate exception handling code unless function
+ declares ``noexcept``
+ * yes, true: Always generate exception handling code
+
The ``remove``, ``access`` and ``rename`` attributes are *optional* attributes
for added convenience; they serve the same purpose as the deprecated tags :ref:`remove`, :ref:`access` and :ref:`rename`.
@@ -130,3 +179,4 @@ conversion-rule
.. note:: You can also use the conversion-rule node to specify :ref:`how the conversion of a single function argument should be done in a function <conversion-rule>`.
+ The ``file`` and ``snippet`` attributes are also supported (see :ref:`inject-code` nodes).
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
index 322f9bca6..c3180ae88 100644
--- a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
@@ -11,7 +11,7 @@ typesystem
.. code-block:: xml
- <typesystem package="..." default-superclass="...">
+ <typesystem package="..." default-superclass="..." exception-handling="...">
</typesystem>
The **package** attribute is a string describing the package to be used,
@@ -19,6 +19,9 @@ typesystem
The *optional* **default-superclass** attribute is the canonical C++ base class
name of all objects, e.g., "object".
+ The *optional* **exception-handling** attribute specifies the default exception
+ handling mode of all objects (see :ref:`modify-function`).
+
load-typesystem
^^^^^^^^^^^^^^^
@@ -216,6 +219,7 @@ value-type
<typesystem>
<value-type name="..." since="..."
copyable="yes | no"
+ exception-handling="..."
hash-function="..."
stream="yes | no"
default-constructor="..."
@@ -243,6 +247,9 @@ value-type
The **revision** attribute can be used to specify a revision for each type, easing the
production of ABI compatible bindings.
+ The *optional* **exception-handling** attribute specifies the default exception
+ handling mode of all functions (see :ref:`modify-function`).
+
.. _object-type:
object-type
@@ -258,6 +265,7 @@ object-type
<object-type name="..."
since="..."
copyable="yes | no"
+ exception-handling="..."
hash-function="..."
stream="yes | no"
revision="..." />
@@ -278,6 +286,9 @@ object-type
The **revision** attribute can be used to specify a revision for each type, easing the
production of ABI compatible bindings.
+ The *optional* **exception-handling** attribute specifies the default exception
+ handling mode of all functions (see :ref:`modify-function`).
+
interface-type
^^^^^^^^^^^^^^
@@ -329,6 +340,38 @@ container-type
The *optional* **since** value is used to specify the API version of this container.
+typedef-type
+^^^^^^^^^^^^
+
+ The typedef-type allows for specifying typedefs in the typesystem. They
+ are mostly equivalent to spelling out the typedef in the included header, which
+ is often complicated when trying to wrap libraries whose source code cannot be
+ easily extended.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <typedef-type name="..."
+ source="..."
+ since="..."
+ </typesystem>
+
+ The **source** attribute is the source. Example:
+
+ .. code-block:: xml
+
+ <namespace-type name='std'>
+ <value-type name='optional' generate='no'/>\n"
+ </namespace-type>
+ <typedef-type name="IntOptional" source="std::optional&lt;int&gt;"/>
+
+ is equivalent to
+
+ .. code-block:: c++
+
+ typedef std::optional<int> IntOptional;
+
+ The *optional* **since** value is used to specify the API version of this type.
.. _custom-type:
@@ -348,6 +391,26 @@ custom-type
The **name** attribute is the name of the custom type, e.g., "PyObject".
+.. _smart-pointer-type:
+
+smart-pointer-type
+^^^^^^^^^^^^^^^^^^
+
+ The smart pointer type node indicates that the given class is a smart pointer
+ and requires inserting calls to **getter** to access the pointeee.
+ Currently, only the **type** *shared* is supported and the usage is limited
+ to function return values.
+ **ref-count-method** specifies the name of the method used to do reference counting.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <smart-pointer-type name="..."
+ since="..."
+ type="..."
+ getter="..."
+ ref-count-method="..."/>
+ </typesystem>
.. _function:
diff --git a/sources/shiboken2/ApiExtractor/docparser.cpp b/sources/shiboken2/ApiExtractor/docparser.cpp
index 9305332ba..99921e7d3 100644
--- a/sources/shiboken2/ApiExtractor/docparser.cpp
+++ b/sources/shiboken2/ApiExtractor/docparser.cpp
@@ -27,6 +27,7 @@
****************************************************************************/
#include "docparser.h"
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "typesystem.h"
#include <QtCore/QDebug>
@@ -50,9 +51,7 @@ DocParser::DocParser()
#endif
}
-DocParser::~DocParser()
-{
-}
+DocParser::~DocParser() = default;
QString DocParser::getDocumentation(QXmlQuery& xquery, const QString& query,
const DocModificationList& mods) const
@@ -109,58 +108,21 @@ AbstractMetaFunctionList DocParser::documentableFunctions(const AbstractMetaClas
return result;
}
-QString DocParser::msgCannotFindDocumentation(const QString &fileName,
- const char *what, const QString &name,
- const QString &query)
-{
- QString result;
- QTextStream(&result) << "Cannot find documentation for " << what
- << ' ' << name << " in:\n " << QDir::toNativeSeparators(fileName)
- << "\n using query:\n " << query;
- return result;
-}
-
-QString DocParser::msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaFunction *function,
- const QString &query)
-{
- const QString name = metaClass->name() + QLatin1String("::")
- + function->minimalSignature();
- return msgCannotFindDocumentation(fileName, "function", name, query);
-}
-
-QString DocParser::msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaEnum *e,
- const QString &query)
-{
- return msgCannotFindDocumentation(fileName, "enum",
- metaClass->name() + QLatin1String("::") + e->name(),
- query);
-}
-
-QString DocParser::msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaField *f,
- const QString &query)
-{
- return msgCannotFindDocumentation(fileName, "field",
- metaClass->name() + QLatin1String("::") + f->name(),
- query);
-}
#ifdef HAVE_LIBXSLT
namespace
{
-struct XslResources
+class XslResources
{
- xmlDocPtr xmlDoc;
- xsltStylesheetPtr xslt;
- xmlDocPtr xslResult;
+ Q_DISABLE_COPY(XslResources)
+
+public:
+ xmlDocPtr xmlDoc = nullptr;
+ xsltStylesheetPtr xslt = nullptr;
+ xmlDocPtr xslResult = nullptr;
- XslResources() : xmlDoc(0), xslt(0), xslResult(0) {}
+ XslResources() = default;
~XslResources()
{
@@ -186,27 +148,6 @@ static inline bool isXpathDocModification(const DocModification &mod)
return mod.mode() == TypeSystem::DocModificationXPathReplace;
}
-QString msgXpathDocModificationError(const DocModificationList& mods,
- const QString &what)
-{
- QString result;
- QTextStream str(&result);
- str << "Error when applying modifications (";
- for (const DocModification &mod : mods) {
- if (isXpathDocModification(mod)) {
- str << '"' << mod.xpath() << "\" -> \"";
- const QString simplified = mod.code().simplified();
- if (simplified.size() > 20)
- str << simplified.leftRef(20) << "...";
- else
- str << simplified;
- str << '"';
- }
- }
- str << "): " << what;
- return result;
-}
-
QString DocParser::applyDocModifications(const DocModificationList& mods, const QString& xml) const
{
if (mods.isEmpty() || xml.isEmpty()
diff --git a/sources/shiboken2/ApiExtractor/docparser.h b/sources/shiboken2/ApiExtractor/docparser.h
index fff71a877..7cbbef28e 100644
--- a/sources/shiboken2/ApiExtractor/docparser.h
+++ b/sources/shiboken2/ApiExtractor/docparser.h
@@ -120,22 +120,6 @@ protected:
static AbstractMetaFunctionList documentableFunctions(const AbstractMetaClass *metaClass);
- static QString msgCannotFindDocumentation(const QString &fileName,
- const char *what, const QString &name,
- const QString &query);
- static QString msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaFunction *function,
- const QString &query);
- static QString msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaEnum *e,
- const QString &query);
- static QString msgCannotFindDocumentation(const QString &fileName,
- const AbstractMetaClass *metaClass,
- const AbstractMetaField *f,
- const QString &query);
-
private:
QString m_packageName;
QString m_docDataDir;
diff --git a/sources/shiboken2/ApiExtractor/doxygenparser.cpp b/sources/shiboken2/ApiExtractor/doxygenparser.cpp
index dfdb37a47..e238aa1f7 100644
--- a/sources/shiboken2/ApiExtractor/doxygenparser.cpp
+++ b/sources/shiboken2/ApiExtractor/doxygenparser.cpp
@@ -28,6 +28,7 @@
#include "doxygenparser.h"
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "typesystem.h"
@@ -35,23 +36,17 @@
#include <QtCore/QFile>
#include <QtCore/QDir>
-namespace
+static QString getSectionKindAttr(const AbstractMetaFunction *func)
{
-
-QString getSectionKindAttr(const AbstractMetaFunction* func)
-{
- if (func->isSignal()) {
+ if (func->isSignal())
return QLatin1String("signal");
- } else {
- QString kind = func->isPublic() ? QLatin1String("public") : QLatin1String("protected");
- if (func->isStatic())
- kind += QLatin1String("-static");
- else if (func->isSlot())
- kind += QLatin1String("-slot");
- return kind;
- }
-}
-
+ QString kind = func->isPublic()
+ ? QLatin1String("public") : QLatin1String("protected");
+ if (func->isStatic())
+ kind += QLatin1String("-static");
+ else if (func->isSlot())
+ kind += QLatin1String("-slot");
+ return kind;
}
Documentation DoxygenParser::retrieveModuleDocumentation()
@@ -73,13 +68,12 @@ void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass)
doxyFileSuffix += QLatin1String(".xml");
const char* prefixes[] = { "class", "struct", "namespace" };
- const int numPrefixes = sizeof(prefixes) / sizeof(const char*);
bool isProperty = false;
QString doxyFilePath;
- for (int i = 0; i < numPrefixes; ++i) {
+ for (const char *prefix : prefixes) {
doxyFilePath = documentationDataDirectory() + QLatin1Char('/')
- + QLatin1String(prefixes[i]) + doxyFileSuffix;
+ + QLatin1String(prefix) + doxyFileSuffix;
if (QFile::exists(doxyFilePath))
break;
doxyFilePath.clear();
diff --git a/sources/shiboken2/ApiExtractor/fileout.cpp b/sources/shiboken2/ApiExtractor/fileout.cpp
index e3c96d57b..10a8f6be8 100644
--- a/sources/shiboken2/ApiExtractor/fileout.cpp
+++ b/sources/shiboken2/ApiExtractor/fileout.cpp
@@ -27,11 +27,13 @@
****************************************************************************/
#include "fileout.h"
+#include "messages.h"
#include "reporthandler.h"
#include <QtCore/QTextCodec>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
+#include <QtCore/QDebug>
#include <cstdio>
@@ -50,24 +52,25 @@ static const char colorInfo[] = "";
static const char colorReset[] = "";
#endif
-FileOut::FileOut(QString n):
- name(n),
- stream(&tmp),
- isDone(false)
-{}
+FileOut::FileOut(QString n) :
+ name(std::move(n)),
+ stream(&tmp),
+ isDone(false)
+{
+}
+
+FileOut::~FileOut()
+{
+ if (!isDone)
+ done();
+}
-static int* lcsLength(QList<QByteArray> a, QList<QByteArray> b)
+static QVector<int> lcsLength(const QByteArrayList &a, const QByteArrayList &b)
{
const int height = a.size() + 1;
const int width = b.size() + 1;
- int *res = new int[width * height];
-
- for (int row = 0; row < height; row++)
- res[width * row] = 0;
-
- for (int col = 0; col < width; col++)
- res[col] = 0;
+ QVector<int> res(width * height, 0);
for (int row = 1; row < height; row++) {
for (int col = 1; col < width; col++) {
@@ -89,88 +92,84 @@ enum Type {
struct Unit
{
- Unit(Type type, int pos) :
- type(type),
- start(pos),
- end(pos) {}
-
Type type;
int start;
int end;
- void print(QList<QByteArray> a, QList<QByteArray> b)
- {
- if (type == Unchanged) {
- if ((end - start) > 9) {
- for (int i = start; i <= start + 2; i++)
- std::printf(" %s\n", a[i].data());
- std::printf("%s=\n= %d more lines\n=%s\n", colorInfo, end - start - 6, colorReset);
- for (int i = end - 2; i <= end; i++)
- std::printf(" %s\n", a[i].data());
- } else {
- for (int i = start; i <= end; i++)
- std::printf(" %s\n", a[i].data());
- }
- } else if (type == Add) {
- std::printf("%s", colorAdd);
- for (int i = start; i <= end; i++)
- std::printf("+ %s\n", b[i].data());
- std::printf("%s", colorReset);
- } else if (type == Delete) {
- std::printf("%s", colorDelete);
- for (int i = start; i <= end; i++)
- std::printf("- %s\n", a[i].data());
- std::printf("%s", colorReset);
- }
- }
+ void print(const QByteArrayList &a, const QByteArrayList &b) const;
};
-static QList<Unit*> *unitAppend(QList<Unit*> *res, Type type, int pos)
+void Unit::print(const QByteArrayList &a, const QByteArrayList &b) const
{
- if (!res) {
- res = new QList<Unit*>;
- res->append(new Unit(type, pos));
- return res;
+ switch (type) {
+ case Unchanged:
+ if ((end - start) > 9) {
+ for (int i = start; i <= start + 2; i++)
+ std::printf(" %s\n", a.at(i).constData());
+ std::printf("%s=\n= %d more lines\n=%s\n",
+ colorInfo, end - start - 6, colorReset);
+ for (int i = end - 2; i <= end; i++)
+ std::printf(" %s\n", a.at(i).constData());
+ } else {
+ for (int i = start; i <= end; i++)
+ std::printf(" %s\n", a.at(i).constData());
+ }
+ break;
+ case Add:
+ std::fputs(colorAdd, stdout);
+ for (int i = start; i <= end; i++)
+ std::printf("+ %s\n", b.at(i).constData());
+ std::fputs(colorReset, stdout);
+ break;
+ case Delete:
+ std::fputs(colorDelete, stdout);
+ for (int i = start; i <= end; i++)
+ std::printf("- %s\n", a.at(i).constData());
+ std::fputs(colorReset, stdout);
+ break;
}
+}
- Unit *last = res->last();
- if (last->type == type)
- last->end = pos;
+static void unitAppend(Type type, int pos, QVector<Unit> *units)
+{
+ if (!units->isEmpty() && units->last().type == type)
+ units->last().end = pos;
else
- res->append(new Unit(type, pos));
-
- return res;
+ units->append(Unit{type, pos, pos});
}
-static QList<Unit*> *diffHelper(int *lcs, QList<QByteArray> a, QList<QByteArray> b, int row, int col)
+static QVector<Unit> diffHelper(const QVector<int> &lcs,
+ const QByteArrayList &a, const QByteArrayList &b,
+ int row, int col)
{
- if (row > 0 && col > 0 && (a[row-1] == b[col-1])) {
- return unitAppend(diffHelper(lcs, a, b, row - 1, col - 1), Unchanged, row - 1);
- } else {
- int width = b.size() + 1;
- if ((col > 0)
- && (row == 0 || lcs[width * row + col-1] >= lcs[width *(row-1) + col])) {
- return unitAppend(diffHelper(lcs, a, b, row, col - 1), Add, col - 1);
- } else if ((row > 0)
- && (col == 0 || lcs[width * row + col-1] < lcs[width *(row-1) + col])) {
- return unitAppend(diffHelper(lcs, a, b, row - 1, col), Delete, row - 1);
- }
+ if (row > 0 && col > 0 && a.at(row - 1) == b.at(col - 1)) {
+ QVector<Unit> result = diffHelper(lcs, a, b, row - 1, col - 1);
+ unitAppend(Unchanged, row - 1, &result);
+ return result;
}
- delete lcs;
- return 0;
-}
-static void diff(QList<QByteArray> a, QList<QByteArray> b)
-{
- QList<Unit*> *res = diffHelper(lcsLength(a, b), a, b, a.size(), b.size());
- for (int i = 0; i < res->size(); i++) {
- Unit *unit = res->at(i);
- unit->print(a, b);
- delete(unit);
+ const int width = b.size() + 1;
+ if (col > 0
+ && (row == 0 || lcs.at(width * row + col -1 ) >= lcs.at(width * (row - 1) + col))) {
+ QVector<Unit> result = diffHelper(lcs, a, b, row, col - 1);
+ unitAppend(Add, col - 1, &result);
+ return result;
}
- delete(res);
+ if (row > 0
+ && (col == 0 || lcs.at(width * row + col-1) < lcs.at(width * (row - 1) + col))) {
+ QVector<Unit> result = diffHelper(lcs, a, b, row - 1, col);
+ unitAppend(Delete, row - 1, &result);
+ return result;
+ }
+ return QVector<Unit>{};
}
+static void diff(const QByteArrayList &a, const QByteArrayList &b)
+{
+ const QVector<Unit> res = diffHelper(lcsLength(a, b), a, b, a.size(), b.size());
+ for (const Unit &unit : res)
+ unit.print(a, b);
+}
FileOut::State FileOut::done()
{
@@ -181,18 +180,6 @@ FileOut::State FileOut::done()
return result;
}
-QString FileOut::msgCannotOpenForReading(const QFile &f)
-{
- return QStringLiteral("Failed to open file '%1' for reading: %2")
- .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
-}
-
-QString FileOut::msgCannotOpenForWriting(const QFile &f)
-{
- return QStringLiteral("Failed to open file '%1' for writing: %2")
- .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
-}
-
FileOut::State FileOut::done(QString *errorMessage)
{
Q_ASSERT(!isDone);
@@ -245,3 +232,18 @@ FileOut::State FileOut::done(QString *errorMessage)
return Success;
}
+
+void FileOut::touchFile(const QString &filePath)
+{
+ QFile toucher(filePath);
+ qint64 size = toucher.size();
+ if (!toucher.open(QIODevice::ReadWrite)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Failed to touch file '%1'")
+ .arg(QDir::toNativeSeparators(filePath));
+ return;
+ }
+ toucher.resize(size+1);
+ toucher.resize(size);
+ toucher.close();
+}
diff --git a/sources/shiboken2/ApiExtractor/fileout.h b/sources/shiboken2/ApiExtractor/fileout.h
index 539ae7a43..aace70131 100644
--- a/sources/shiboken2/ApiExtractor/fileout.h
+++ b/sources/shiboken2/ApiExtractor/fileout.h
@@ -43,18 +43,17 @@ private:
public:
enum State { Failure, Unchanged, Success };
- FileOut(QString name);
- ~FileOut()
- {
- if (!isDone)
- done();
- }
+ explicit FileOut(QString name);
+ ~FileOut();
+
+ QString filePath() const { return name; }
State done();
State done(QString *errorMessage);
- static QString msgCannotOpenForReading(const QFile &f);
- static QString msgCannotOpenForWriting(const QFile &f);
+ void touch() { touchFile(name); }
+
+ static void touchFile(const QString &filePath);
QTextStream stream;
diff --git a/sources/shiboken2/ApiExtractor/include.cpp b/sources/shiboken2/ApiExtractor/include.cpp
index 963999b9d..d6a451992 100644
--- a/sources/shiboken2/ApiExtractor/include.cpp
+++ b/sources/shiboken2/ApiExtractor/include.cpp
@@ -36,10 +36,9 @@ QString Include::toString() const
{
if (m_type == IncludePath)
return QLatin1String("#include <") + m_name + QLatin1Char('>');
- else if (m_type == LocalPath)
+ if (m_type == LocalPath)
return QLatin1String("#include \"") + m_name + QLatin1Char('"');
- else
- return QLatin1String("import ") + m_name + QLatin1Char(';');
+ return QLatin1String("import ") + m_name + QLatin1Char(';');
}
uint qHash(const Include& inc)
diff --git a/sources/shiboken2/ApiExtractor/include.h b/sources/shiboken2/ApiExtractor/include.h
index 16059876a..4890eea2c 100644
--- a/sources/shiboken2/ApiExtractor/include.h
+++ b/sources/shiboken2/ApiExtractor/include.h
@@ -42,7 +42,8 @@ public:
enum IncludeType {
IncludePath,
LocalPath,
- TargetLangImport
+ TargetLangImport,
+ InvalidInclude
};
Include() : m_type(IncludePath) {}
diff --git a/sources/shiboken2/ApiExtractor/messages.cpp b/sources/shiboken2/ApiExtractor/messages.cpp
new file mode 100644
index 000000000..fa4c75743
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/messages.cpp
@@ -0,0 +1,446 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "messages.h"
+#include "abstractmetalang.h"
+#include "typesystem.h"
+#include <codemodel.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QStringList>
+#include <QtCore/QXmlStreamReader>
+
+static inline QString colonColon() { return QStringLiteral("::"); }
+
+// abstractmetabuilder.cpp
+
+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 << '\'';
+ if (!originalSignature.isEmpty() && originalSignature != signature)
+ str << " (specified as '" << originalSignature << "')";
+ str << " for function modification in '"
+ << className << "' not found.";
+ if (!possibleSignatures.isEmpty()) {
+ str << "\n Possible candidates:\n";
+ for (const auto &s : possibleSignatures)
+ str << " " << s << '\n';
+ } else if (!allFunctions.isEmpty()) {
+ str << "\n No candidates were found. Member functions:\n";
+ const int maxCount = qMin(10, allFunctions.size());
+ for (int f = 0; f < maxCount; ++f)
+ str << " " << allFunctions.at(f)->minimalSignature() << '\n';
+ if (maxCount < allFunctions.size())
+ str << " ...\n";
+ }
+ return result;
+}
+
+template <class Stream>
+static void msgFormatEnumType(Stream &str,
+ const EnumModelItem &enumItem,
+ const QString &className)
+{
+ switch (enumItem->enumKind()) {
+ case CEnum:
+ str << "Enum '" << enumItem->qualifiedName().join(colonColon()) << '\'';
+ break;
+ case AnonymousEnum: {
+ const EnumeratorList &values = enumItem->enumerators();
+ str << "Anonymous enum (";
+ switch (values.size()) {
+ case 0:
+ break;
+ case 1:
+ str << values.constFirst()->name();
+ break;
+ case 2:
+ str << values.at(0)->name() << ", " << values.at(1)->name();
+ break;
+ default:
+ str << values.at(0)->name() << ", ... , "
+ << values.at(values.size() - 1)->name();
+ break;
+ }
+ str << ')';
+ }
+ break;
+ case EnumClass:
+ str << "Scoped enum '" << enumItem->qualifiedName().join(colonColon()) << '\'';
+ break;
+ }
+ if (!className.isEmpty())
+ str << " (class: " << className << ')';
+}
+
+QString msgNoEnumTypeEntry(const EnumModelItem &enumItem,
+ const QString &className)
+{
+ QString result;
+ QTextStream str(&result);
+ msgFormatEnumType(str, enumItem, className);
+ str << " does not have a type entry";
+ return result;
+}
+
+QString msgNoEnumTypeConflict(const EnumModelItem &enumItem,
+ const QString &className,
+ const TypeEntry *t)
+{
+ QString result;
+ QDebug debug(&result); // Use the debug operator for TypeEntry::Type
+ debug.noquote();
+ debug.nospace();
+ msgFormatEnumType(debug, enumItem, className);
+ debug << " is not an enum (type: " << t->type() << ')';
+ return result;
+}
+
+QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n,
+ const QString &why)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "unmatched type '" << arg->type().toString() << "' in parameter #"
+ << (n + 1);
+ if (!arg->name().isEmpty())
+ str << " \"" << arg->name() << '"';
+ str << ": " << why;
+ return result;
+}
+
+QString msgUnmatchedReturnType(const FunctionModelItem &functionItem,
+ const QString &why)
+{
+ return QLatin1String("unmatched return type '")
+ + functionItem->type().toString()
+ + QLatin1String("': ") + why;
+}
+
+QString msgSkippingFunction(const FunctionModelItem &functionItem,
+ const QString &signature, const QString &why)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "skipping ";
+ if (functionItem->isAbstract())
+ str << "abstract ";
+ str << "function '" << signature << "', " << why;
+ if (functionItem->isAbstract()) {
+ str << "\nThis will lead to compilation errors due to not "
+ "being able to instantiate the wrapper.";
+ }
+ return result;
+}
+
+QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason)
+{
+ return function + QLatin1String(": Cannot use parameter ")
+ + QString::number(i + 1) + QLatin1String(" as an array: ") + reason;
+}
+
+QString msgUnableToTranslateType(const QString &t, const QString &why)
+{
+ return QLatin1String("Unable to translate type \"")
+ + t + QLatin1String("\": ") + why;
+}
+
+QString msgUnableToTranslateType(const TypeInfo &typeInfo,
+ const QString &why)
+{
+ return msgUnableToTranslateType(typeInfo.toString(), why);
+}
+
+QString msgCannotFindTypeEntry(const QString &t)
+{
+ return QLatin1String("Cannot find type entry for \"") + t + QLatin1String("\".");
+}
+
+QString msgCannotTranslateTemplateArgument(int i,
+ const TypeInfo &typeInfo,
+ const QString &why)
+{
+ QString result;
+ QTextStream(&result) << "Unable to translate template argument "
+ << (i + 1) << typeInfo.toString() << ": " << why;
+ return result;
+}
+
+// abstractmetalang.cpp
+
+QString msgDisallowThread(const AbstractMetaFunction *f)
+{
+ QString result;
+ QTextStream str(&result);
+ str <<"Disallowing threads for ";
+ if (auto c = f->declaringClass())
+ str << c->name() << "::";
+ str << f->name() << "().";
+ return result;
+}
+
+// docparser.cpp
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const char *what, const QString &name,
+ const QString &query)
+{
+ QString result;
+ QTextStream(&result) << "Cannot find documentation for " << what
+ << ' ' << name << " in:\n " << QDir::toNativeSeparators(fileName)
+ << "\n using query:\n " << query;
+ return result;
+}
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaFunction *function,
+ const QString &query)
+{
+ const QString name = metaClass->name() + QLatin1String("::")
+ + function->minimalSignature();
+ return msgCannotFindDocumentation(fileName, "function", name, query);
+}
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaEnum *e,
+ const QString &query)
+{
+ return msgCannotFindDocumentation(fileName, "enum",
+ metaClass->name() + QLatin1String("::") + e->name(),
+ query);
+}
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaField *f,
+ const QString &query)
+{
+ return msgCannotFindDocumentation(fileName, "field",
+ metaClass->name() + QLatin1String("::") + f->name(),
+ query);
+}
+
+QString msgXpathDocModificationError(const DocModificationList& mods,
+ const QString &what)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Error when applying modifications (";
+ for (const DocModification &mod : mods) {
+ if (mod.mode() == TypeSystem::DocModificationXPathReplace) {
+ str << '"' << mod.xpath() << "\" -> \"";
+ const QString simplified = mod.code().simplified();
+ if (simplified.size() > 20)
+ str << simplified.leftRef(20) << "...";
+ else
+ str << simplified;
+ str << '"';
+ }
+ }
+ str << "): " << what;
+ return result;
+}
+
+// fileout.cpp
+
+QString msgCannotOpenForReading(const QFile &f)
+{
+ return QStringLiteral("Failed to open file '%1' for reading: %2")
+ .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
+}
+
+QString msgCannotOpenForWriting(const QFile &f)
+{
+ return QStringLiteral("Failed to open file '%1' for writing: %2")
+ .arg(QDir::toNativeSeparators(f.fileName()), f.errorString());
+}
+
+// generator.cpp
+
+QString msgCannotUseEnumAsInt(const QString &name)
+{
+ return QLatin1String("Cannot convert the protected scoped enum \"") + name
+ + QLatin1String("\" to type int when generating wrappers for the protected hack. "
+ "Compilation errors may occur when used as a function argument.");
+}
+
+// main.cpp
+
+QString msgLeftOverArguments(const QMap<QString, QString> &remainingArgs)
+{
+ QString message;
+ QTextStream str(&message);
+ str << "shiboken: Called with wrong arguments:";
+ for (auto it = remainingArgs.cbegin(), end = remainingArgs.cend(); it != end; ++it) {
+ str << ' ' << it.key();
+ if (!it.value().isEmpty())
+ str << ' ' << it.value();
+ }
+ str << "\nCommand line: " << QCoreApplication::arguments().join(QLatin1Char(' '));
+ return message;
+}
+
+QString msgInvalidVersion(const QString &package, const QString &version)
+{
+ return QLatin1String("Invalid version \"") + version
+ + QLatin1String("\" specified for package ") + package + QLatin1Char('.');
+}
+
+QString msgCyclicDependency(const QString &funcName, const QString &graphName,
+ const QVector<const AbstractMetaFunction *> &involvedConversions)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Cyclic dependency found on overloaddata for \"" << funcName
+ << "\" method! The graph boy saved the graph at \""
+ << QDir::toNativeSeparators(graphName) << "\".";
+ if (const int count = involvedConversions.size()) {
+ str << " Implicit conversions (" << count << "): ";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ str << ", \"";
+ str << involvedConversions.at(i)->signature() << '"';
+ if (const AbstractMetaClass *c = involvedConversions.at(i)->implementingClass())
+ str << '(' << c->name() << ')';
+ }
+ }
+ return result;
+}
+
+// shibokengenerator.cpp
+
+QString msgUnknownOperator(const AbstractMetaFunction* func)
+{
+ QString result = QLatin1String("Unknown operator: \"") + func->originalName()
+ + QLatin1Char('"');
+ if (const AbstractMetaClass *c = func->implementingClass())
+ result += QLatin1String(" in class: ") + c->name();
+ return result;
+}
+
+QString msgWrongIndex(const char *varName, const QString &capture,
+ const AbstractMetaFunction *func)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Wrong index for " << varName << " variable (" << capture << ") on ";
+ if (const AbstractMetaClass *c = func->implementingClass())
+ str << c->name() << "::";
+ str << func->signature();
+ return result;
+}
+
+QString msgCannotFindType(const QString &type, const QString &variable,
+ const QString &why)
+{
+ QString result;
+ QTextStream(&result) << "Could not find type '"
+ << type << "' for use in '" << variable << "' conversion: " << why
+ << "\nMake sure to use the full C++ name, e.g. 'Namespace::Class'.";
+ return result;
+}
+
+QString msgCannotBuildMetaType(const QString &s)
+{
+ return QLatin1String("Unable to build meta type for \"")
+ + s + QLatin1String("\": ");
+}
+
+QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type)
+{
+ return where + QLatin1String(": Could not find a minimal constructor for type '")
+ + type + QLatin1String("'. This will result in a compilation error.");
+}
+
+// typedatabase.cpp
+
+QString msgRejectReason(const TypeRejection &r, const QString &needle)
+{
+ QString result;
+ QTextStream str(&result);
+ switch (r.matchType) {
+ case TypeRejection::ExcludeClass:
+ str << " matches class exclusion \"" << r.className.pattern() << '"';
+ break;
+ case TypeRejection::Function:
+ case TypeRejection::Field:
+ case TypeRejection::Enum:
+ str << " matches class \"" << r.className.pattern() << "\" and \""
+ << r.pattern.pattern() << '"';
+ break;
+ case TypeRejection::ArgumentType:
+ case TypeRejection::ReturnType:
+ str << " matches class \"" << r.className.pattern() << "\" and \""
+ << needle << "\" matches \"" << r.pattern.pattern() << '"';
+ break;
+ case TypeRejection::Invalid:
+ break;
+ }
+ return result;
+}
+
+// qtdocgenerator.cpp
+
+QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &message)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "While handling <";
+ const QStringRef currentTag = reader.name();
+ if (currentTag.isEmpty())
+ str << tag;
+ else
+ str << currentTag;
+ str << "> in " << context << ", line "<< reader.lineNumber()
+ << ": " << message;
+ return result;
+}
+
+QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &location,
+ const QString &identifier, const QString &fallback)
+{
+ QString message = QLatin1String("Falling back to \"")
+ + QDir::toNativeSeparators(fallback) + QLatin1String("\" for \"")
+ + location + QLatin1Char('"');
+ if (!identifier.isEmpty())
+ message += QLatin1String(" [") + identifier + QLatin1Char(']');
+ return msgTagWarning(reader, context, tag, message);
+}
diff --git a/sources/shiboken2/ApiExtractor/messages.h b/sources/shiboken2/ApiExtractor/messages.h
new file mode 100644
index 000000000..539332aef
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/messages.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MESSAGES_H
+#define MESSAGES_H
+
+#include "abstractmetalang_typedefs.h"
+#include "parser/codemodel_fwd.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+class TypeEntry;
+class TypeInfo;
+struct TypeRejection;
+
+QT_FORWARD_DECLARE_CLASS(QDir)
+QT_FORWARD_DECLARE_CLASS(QFile)
+QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
+
+QString msgNoFunctionForModification(const QString &signature,
+ const QString &originalSignature,
+ const QString &className,
+ const QStringList &possibleSignatures,
+ const AbstractMetaFunctionList &allFunctions);
+
+QString msgNoEnumTypeEntry(const EnumModelItem &enumItem,
+ const QString &className);
+
+
+QString msgNoEnumTypeConflict(const EnumModelItem &enumItem,
+ const QString &className,
+ const TypeEntry *t);
+
+QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n,
+ const QString &why);
+
+QString msgUnmatchedReturnType(const FunctionModelItem &functionItem,
+ const QString &why);
+
+QString msgSkippingFunction(const FunctionModelItem &functionItem,
+ const QString &signature, const QString &why);
+
+QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason);
+
+QString msgUnableToTranslateType(const QString &t, const QString &why);
+
+QString msgUnableToTranslateType(const TypeInfo &typeInfo,
+ const QString &why);
+
+QString msgCannotFindTypeEntry(const QString &t);
+
+QString msgCannotTranslateTemplateArgument(int i,
+ const TypeInfo &typeInfo,
+ const QString &why);
+
+QString msgDisallowThread(const AbstractMetaFunction *f);
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const char *what, const QString &name,
+ const QString &query);
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaFunction *function,
+ const QString &query);
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaEnum *e,
+ const QString &query);
+
+QString msgCannotFindDocumentation(const QString &fileName,
+ const AbstractMetaClass *metaClass,
+ const AbstractMetaField *f,
+ const QString &query);
+
+QString msgXpathDocModificationError(const DocModificationList& mods,
+ const QString &what);
+
+QString msgCannotOpenForReading(const QFile &f);
+
+QString msgCannotOpenForWriting(const QFile &f);
+
+QString msgCannotUseEnumAsInt(const QString &name);
+
+QString msgLeftOverArguments(const QMap<QString, QString> &remainingArgs);
+
+QString msgInvalidVersion(const QString &package, const QString &version);
+
+QString msgCyclicDependency(const QString &funcName, const QString &graphName,
+ const QVector<const AbstractMetaFunction *> &involvedConversions);
+
+QString msgUnknownOperator(const AbstractMetaFunction* func);
+
+QString msgWrongIndex(const char *varName, const QString &capture,
+ const AbstractMetaFunction *func);
+
+QString msgCannotFindType(const QString &type, const QString &variable,
+ const QString &why);
+
+QString msgCannotBuildMetaType(const QString &s);
+
+QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type);
+
+QString msgRejectReason(const TypeRejection &r, const QString &needle = QString());
+
+QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &message);
+
+QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context,
+ const QString &tag, const QString &location,
+ const QString &identifier, const QString &fallback);
+
+#endif // MESSAGES_H
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp
index d862692dd..173f6dd23 100644
--- a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp
@@ -29,11 +29,15 @@
#include "codemodel.h"
+
+#include <clangparser/clangutils.h>
+
#include <algorithm>
#include <functional>
#include <iostream>
#include <QDebug>
#include <QDir>
+#include <QtCore/QStack>
// Predicate to find an item by name in a list of QSharedPointer<Item>
template <class T> class ModelItemNamePredicate : public std::unary_function<bool, QSharedPointer<T> >
@@ -140,16 +144,18 @@ TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs)
__result.setVolatile(__result.isVolatile() || __rhs.isVolatile());
if (__rhs.referenceType() > __result.referenceType())
__result.setReferenceType(__rhs.referenceType());
- __result.setIndirections(__result.indirections() + __rhs.indirections());
+ __result.m_indirections.append(__rhs.m_indirections);
__result.setArrayElements(__result.arrayElements() + __rhs.arrayElements());
+ __result.m_instantiations.append(__rhs.m_instantiations);
return __result;
}
bool TypeInfo::isVoid() const
{
- return m_indirections == 0 && m_referenceType == NoReference
+ return m_indirections.isEmpty() && m_referenceType == NoReference
&& m_arguments.isEmpty() && m_arrayElements.isEmpty()
+ && m_instantiations.isEmpty()
&& m_qualifiedName.size() == 1
&& m_qualifiedName.constFirst() == QLatin1String("void");
}
@@ -193,19 +199,76 @@ TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, Cod
return otherType;
}
+// Handler for clang::parseTemplateArgumentList() that populates
+// TypeInfo::m_instantiations
+class TypeInfoTemplateArgumentHandler :
+ public std::binary_function<void, int, const QStringRef &>
+{
+public:
+ explicit TypeInfoTemplateArgumentHandler(TypeInfo *t)
+ {
+ m_parseStack.append(t);
+ }
+
+ void operator()(int level, const QStringRef &name)
+ {
+ if (level > m_parseStack.size()) {
+ Q_ASSERT(!top()->m_instantiations.isEmpty());
+ m_parseStack.push(&top()->m_instantiations.back());
+ }
+ while (level < m_parseStack.size())
+ m_parseStack.pop();
+ TypeInfo instantiation;
+ instantiation.setQualifiedName(qualifiedName(name));
+ top()->addInstantiation(instantiation);
+ }
+
+private:
+ TypeInfo *top() const { return m_parseStack.back(); }
+
+ static QStringList qualifiedName(const QStringRef &name)
+ {
+ QStringList result;
+ const QVector<QStringRef> nameParts = name.split(QLatin1String("::"));
+ result.reserve(nameParts.size());
+ for (const QStringRef &p : nameParts)
+ result.append(p.toString());
+ return result;
+ }
+
+ QStack<TypeInfo *> m_parseStack;
+};
+
+QPair<int, int> TypeInfo::parseTemplateArgumentList(const QString &l, int from)
+{
+ return clang::parseTemplateArgumentList(l, clang::TemplateArgumentHandler(TypeInfoTemplateArgumentHandler(this)), from);
+}
+
QString TypeInfo::toString() const
{
QString tmp;
-
- tmp += m_qualifiedName.join(QLatin1String("::"));
if (isConstant())
- tmp += QLatin1String(" const");
+ tmp += QLatin1String("const ");
if (isVolatile())
- tmp += QLatin1String(" volatile");
+ tmp += QLatin1String("volatile ");
- if (indirections())
- tmp += QString(indirections(), QLatin1Char('*'));
+ tmp += m_qualifiedName.join(QLatin1String("::"));
+
+ if (const int instantiationCount = m_instantiations.size()) {
+ tmp += QLatin1Char('<');
+ for (int i = 0; i < instantiationCount; ++i) {
+ if (i)
+ tmp += QLatin1String(", ");
+ tmp += m_instantiations.at(i).toString();
+ }
+ if (tmp.endsWith(QLatin1Char('>')))
+ tmp += QLatin1Char(' ');
+ tmp += QLatin1Char('>');
+ }
+
+ for (Indirection i : m_indirections)
+ tmp.append(indirectionKeyword(i));
switch (referenceType()) {
case NoReference:
@@ -238,20 +301,6 @@ 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())
@@ -269,7 +318,73 @@ bool TypeInfo::operator==(const TypeInfo &other) const
return flags == other.flags
&& m_qualifiedName == other.m_qualifiedName
- && (!m_functionPointer || m_arguments == other.m_arguments);
+ && (!m_functionPointer || m_arguments == other.m_arguments)
+ && m_instantiations == other.m_instantiations;
+}
+
+QString TypeInfo::indirectionKeyword(Indirection i)
+{
+ return i == Indirection::Pointer
+ ? QStringLiteral("*") : QStringLiteral("*const");
+}
+
+static inline QString constQualifier() { return QStringLiteral("const"); }
+static inline QString volatileQualifier() { return QStringLiteral("volatile"); }
+
+bool TypeInfo::stripLeadingConst(QString *s)
+{
+ return stripLeadingQualifier(constQualifier(), s);
+}
+
+bool TypeInfo::stripLeadingVolatile(QString *s)
+{
+ return stripLeadingQualifier(volatileQualifier(), s);
+}
+
+bool TypeInfo::stripLeadingQualifier(const QString &qualifier, QString *s)
+{
+ // "const int x"
+ const int qualifierSize = qualifier.size();
+ if (s->size() < qualifierSize + 1 || !s->startsWith(qualifier)
+ || !s->at(qualifierSize).isSpace()) {
+ return false;
+ }
+ s->remove(0, qualifierSize + 1);
+ while (!s->isEmpty() && s->at(0).isSpace())
+ s->remove(0, 1);
+ return true;
+}
+
+// Helper functionality to simplify a raw standard type as returned by
+// clang_getCanonicalType() for g++ standard containers from
+// "std::__cxx11::list<int, std::allocator<int> >" or
+// "std::__1::list<int, std::allocator<int> >" -> "std::list<int>".
+
+bool TypeInfo::isStdType() const
+{
+ return m_qualifiedName.size() > 1
+ && m_qualifiedName.constFirst() == QLatin1String("std");
+}
+
+static inline bool discardStdType(const QString &name)
+{
+ return name == QLatin1String("allocator") || name == QLatin1String("less");
+}
+
+void TypeInfo::simplifyStdType()
+{
+ if (isStdType()) {
+ if (m_qualifiedName.at(1).startsWith(QLatin1String("__")))
+ m_qualifiedName.removeAt(1);
+ for (int t = m_instantiations.size() - 1; t >= 0; --t) {
+ if (m_instantiations.at(t).isStdType()) {
+ if (discardStdType(m_instantiations.at(t).m_qualifiedName.constLast()))
+ m_instantiations.removeAt(t);
+ else
+ m_instantiations[t].simplifyStdType();
+ }
+ }
+ }
}
#ifndef QT_NO_DEBUG_STREAM
@@ -292,8 +407,11 @@ void TypeInfo::formatDebug(QDebug &d) const
d << ", [const]";
if (m_volatile)
d << ", [volatile]";
- if (m_indirections)
- d << ", indirections=" << m_indirections;
+ if (!m_indirections.isEmpty()) {
+ d << ", indirections=";
+ for (auto i : m_indirections)
+ d << ' ' << TypeInfo::indirectionKeyword(i);
+ }
switch (m_referenceType) {
case NoReference:
break;
@@ -304,6 +422,11 @@ void TypeInfo::formatDebug(QDebug &d) const
d << ", [rvalref]";
break;
}
+ if (!m_instantiations.isEmpty()) {
+ d << ", template<";
+ formatSequence(d, m_instantiations.begin(), m_instantiations.end());
+ d << '>';
+ }
if (m_functionPointer) {
d << ", function ptr(";
formatSequence(d, m_arguments.begin(), m_arguments.end());
@@ -358,9 +481,7 @@ _CodeModelItem::_CodeModelItem(CodeModel *model, const QString &name, int kind)
{
}
-_CodeModelItem::~_CodeModelItem()
-{
-}
+_CodeModelItem::~_CodeModelItem() = default;
int _CodeModelItem::kind() const
{
@@ -532,9 +653,7 @@ QDebug operator<<(QDebug d, const _CodeModelItem *t)
#endif // !QT_NO_DEBUG_STREAM
// ---------------------------------------------------------------------------
-_ClassModelItem::~_ClassModelItem()
-{
-}
+_ClassModelItem::~_ClassModelItem() = default;
TemplateParameterList _ClassModelItem::templateParameters() const
{
@@ -624,9 +743,7 @@ FunctionModelItem _ScopeModelItem::declaredFunction(FunctionModelItem item)
return FunctionModelItem();
}
-_ScopeModelItem::~_ScopeModelItem()
-{
-}
+_ScopeModelItem::~_ScopeModelItem() = default;
void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration)
{
@@ -835,11 +952,9 @@ void _ArgumentModelItem::formatDebug(QDebug &d) const
}
#endif // !QT_NO_DEBUG_STREAM
// ---------------------------------------------------------------------------
-_FunctionModelItem::~_FunctionModelItem()
-{
-}
+_FunctionModelItem::~_FunctionModelItem() = default;
-bool _FunctionModelItem::isSimilar(FunctionModelItem other) const
+bool _FunctionModelItem::isSimilar(const FunctionModelItem &other) const
{
if (name() != other->name())
return false;
@@ -871,7 +986,7 @@ ArgumentList _FunctionModelItem::arguments() const
return m_arguments;
}
-void _FunctionModelItem::addArgument(ArgumentModelItem item)
+void _FunctionModelItem::addArgument(const ArgumentModelItem& item)
{
m_arguments.append(item);
}
@@ -896,6 +1011,21 @@ void _FunctionModelItem::setVariadics(bool isVariadics)
m_isVariadics = isVariadics;
}
+bool _FunctionModelItem::isNoExcept() const
+{
+ return m_exceptionSpecification == ExceptionSpecification::NoExcept;
+}
+
+ExceptionSpecification _FunctionModelItem::exceptionSpecification() const
+{
+ return m_exceptionSpecification;
+}
+
+void _FunctionModelItem::setExceptionSpecification(ExceptionSpecification e)
+{
+ m_exceptionSpecification = e;
+}
+
bool _FunctionModelItem::isDeleted() const
{
return m_isDeleted;
@@ -991,7 +1121,7 @@ void _FunctionModelItem::setInvokable(bool isInvokable)
void _FunctionModelItem::formatDebug(QDebug &d) const
{
_MemberModelItem::formatDebug(d);
- d << ", type=" << m_functionType;
+ d << ", type=" << m_functionType << ", exspec=" << int(m_exceptionSpecification);
if (m_isDeleted)
d << " [deleted!]";
if (m_isInline)
@@ -1091,9 +1221,7 @@ void _EnumModelItem::formatDebug(QDebug &d) const
#endif // !QT_NO_DEBUG_STREAM
// ---------------------------------------------------------------------------
-_EnumeratorModelItem::~_EnumeratorModelItem()
-{
-}
+_EnumeratorModelItem::~_EnumeratorModelItem() = default;
QString _EnumeratorModelItem::stringValue() const
{
@@ -1114,9 +1242,7 @@ void _EnumeratorModelItem::formatDebug(QDebug &d) const
#endif // !QT_NO_DEBUG_STREAM
// ---------------------------------------------------------------------------
-_TemplateParameterModelItem::~_TemplateParameterModelItem()
-{
-}
+_TemplateParameterModelItem::~_TemplateParameterModelItem() = default;
TypeInfo _TemplateParameterModelItem::type() const
{
@@ -1164,9 +1290,7 @@ CodeModel::AccessPolicy _MemberModelItem::accessPolicy() const
return m_accessPolicy;
}
-_MemberModelItem::~_MemberModelItem()
-{
-}
+_MemberModelItem::~_MemberModelItem() = default;
void _MemberModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy)
{
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.h b/sources/shiboken2/ApiExtractor/parser/codemodel.h
index ac1fe26c1..7bd82bd1d 100644
--- a/sources/shiboken2/ApiExtractor/parser/codemodel.h
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h
@@ -36,6 +36,7 @@
#include "enumvalue.h"
#include <QtCore/QHash>
+#include <QtCore/QPair>
#include <QtCore/QSet>
#include <QtCore/QString>
#include <QtCore/QStringList>
@@ -100,6 +101,8 @@ class TypeInfo
{
friend class TypeParser;
public:
+ typedef QVector<Indirection> Indirections;
+
TypeInfo() : flags(0), m_referenceType(NoReference) {}
QStringList qualifiedName() const
@@ -137,14 +140,16 @@ public:
ReferenceType referenceType() const { return m_referenceType; }
void setReferenceType(ReferenceType r) { m_referenceType = r; }
- int indirections() const
- {
- return m_indirections;
- }
+ Indirections indirectionsV() const { return m_indirections; }
+ void setIndirectionsV(const Indirections &i) { m_indirections = i; }
+ void addIndirection(Indirection i) { m_indirections.append(i); }
+
+ // "Legacy", rename?
+ int indirections() const { return m_indirections.size(); }
void setIndirections(int indirections)
{
- m_indirections = indirections;
+ m_indirections = Indirections(indirections, Indirection::Pointer);
}
bool isFunctionPointer() const
@@ -165,6 +170,8 @@ public:
m_arrayElements = arrayElements;
}
+ void addArrayElement(const QString &a) { m_arrayElements.append(a); }
+
QVector<TypeInfo> arguments() const { return m_arguments; }
void setArguments(const QVector<TypeInfo> &arguments);
@@ -174,6 +181,15 @@ public:
m_arguments.append(arg);
}
+ QVector<TypeInfo> instantiations() const { return m_instantiations; }
+ void setInstantiations(const QVector<TypeInfo> &i) { m_instantiations = i; }
+ void addInstantiation(const TypeInfo &i) { m_instantiations.append(i); }
+ void clearInstantiations() { m_instantiations.clear(); }
+
+ bool isStdType() const;
+
+ QPair<int, int> parseTemplateArgumentList(const QString &l, int from = 0);
+
bool operator==(const TypeInfo &other) const;
bool operator!=(const TypeInfo &other) const
@@ -185,8 +201,6 @@ public:
QString toString() const;
- QStringList instantiationName() const;
-
static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs);
static TypeInfo resolveType(TypeInfo const &__type, CodeModelItem __scope);
@@ -194,12 +208,24 @@ public:
void formatDebug(QDebug &d) const;
#endif
+ static QString indirectionKeyword(Indirection i);
+
+ static bool stripLeadingConst(QString *s);
+ static bool stripLeadingVolatile(QString *s);
+ static bool stripLeadingQualifier(const QString &qualifier, QString *s);
+
+ void simplifyStdType();
+
private:
+ friend class TypeInfoTemplateArgumentHandler;
+
static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, CodeModelItem __scope);
QStringList m_qualifiedName;
QStringList m_arrayElements;
QVector<TypeInfo> m_arguments;
+ QVector<TypeInfo> m_instantiations;
+ Indirections m_indirections;
union {
uint flags;
@@ -208,8 +234,7 @@ private:
uint m_constant: 1;
uint m_volatile: 1;
uint m_functionPointer: 1;
- uint m_indirections: 6;
- uint m_padding: 23;
+ uint m_padding: 29;
};
};
@@ -547,7 +572,7 @@ public:
ArgumentList arguments() const;
- void addArgument(ArgumentModelItem item);
+ void addArgument(const ArgumentModelItem& item);
CodeModel::FunctionType functionType() const;
void setFunctionType(CodeModel::FunctionType functionType);
@@ -582,7 +607,13 @@ public:
bool isVariadics() const;
void setVariadics(bool isVariadics);
- bool isSimilar(FunctionModelItem other) const;
+
+ bool isSimilar(const FunctionModelItem &other) const;
+
+ bool isNoExcept() const;
+
+ ExceptionSpecification exceptionSpecification() const;
+ void setExceptionSpecification(ExceptionSpecification e);
#ifndef QT_NO_DEBUG_STREAM
void formatDebug(QDebug &d) const override;
@@ -606,6 +637,7 @@ private:
};
uint m_flags;
};
+ ExceptionSpecification m_exceptionSpecification = ExceptionSpecification::Unknown;
};
class _VariableModelItem: public _MemberModelItem
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h
index b8a10ba93..1713ba42f 100644
--- a/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h
@@ -41,4 +41,17 @@ enum EnumKind {
EnumClass // C++ 11 : enum class Foo { value1, value2 }
};
+enum class Indirection
+{
+ Pointer, // int *
+ ConstPointer // int *const
+};
+
+enum class ExceptionSpecification
+{
+ Unknown,
+ NoExcept,
+ Throws
+};
+
#endif // CODEMODEL_ENUMS_H
diff --git a/sources/shiboken2/ApiExtractor/parser/enumvalue.h b/sources/shiboken2/ApiExtractor/parser/enumvalue.h
index 4905e89ba..ea30c39bb 100644
--- a/sources/shiboken2/ApiExtractor/parser/enumvalue.h
+++ b/sources/shiboken2/ApiExtractor/parser/enumvalue.h
@@ -49,6 +49,7 @@ public:
Type type() { return m_type; }
qint64 value() const { return m_value; }
quint64 unsignedValue() const { return m_unsignedValue; }
+ bool isNullValue() const { return m_type == Signed ? m_value == 0 : m_unsignedValue == 0u; }
void setValue(qint64 v);
void setUnsignedValue(quint64 v);
diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.cpp b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
index b0058d6ea..809760450 100644
--- a/sources/shiboken2/ApiExtractor/qtdocparser.cpp
+++ b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
@@ -28,6 +28,7 @@
#include "qtdocparser.h"
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "typesystem.h"
diff --git a/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt
index 860a37d9d..e100ef493 100644
--- a/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt
+++ b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt
@@ -4,13 +4,18 @@ find_package(Qt5Test)
find_package(Qt5Xml)
find_package(Qt5XmlPatterns)
+set(CMAKE_AUTORCC ON)
+
macro(declare_test testname)
# gone: qt4_automoc("${testname}.cpp")
- if (EXISTS "${testname}.h")
- add_executable(${testname} "${testname}.h ${testname}.cpp")
- else ()
- add_executable(${testname} "${testname}.cpp")
+ set(SOURCES "${testname}.cpp")
+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${testname}.h")
+ list(APPEND SOURCES "${testname}.h")
+ endif ()
+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${testname}.qrc")
+ list(APPEND SOURCES "${testname}.qrc")
endif ()
+ add_executable(${testname} ${SOURCES})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${apiextractor_SOURCE_DIR}
@@ -35,8 +40,6 @@ declare_test(testabstractmetatype)
declare_test(testaddfunction)
declare_test(testarrayargument)
declare_test(testcodeinjection)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/utf8code.txt"
- "${CMAKE_CURRENT_BINARY_DIR}/utf8code.txt" COPYONLY)
declare_test(testcontainer)
declare_test(testconversionoperator)
declare_test(testconversionruletag)
@@ -68,7 +71,5 @@ declare_test(testvoidarg)
declare_test(testtyperevision)
if (NOT DISABLE_DOCSTRINGS)
declare_test(testmodifydocumentation)
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/a.xml"
- "${CMAKE_CURRENT_BINARY_DIR}/a.xml" COPYONLY)
endif()
diff --git a/sources/shiboken2/ApiExtractor/tests/injectedcode.txt b/sources/shiboken2/ApiExtractor/tests/injectedcode.txt
new file mode 100644
index 000000000..872898810
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/injectedcode.txt
@@ -0,0 +1,5 @@
+// Bla
+// @snippet label
+code line
+// @snippet label
+// Bla
diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp
index 7f1361a7d..fc67ebba5 100644
--- a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp
@@ -31,6 +31,37 @@
#include "testutil.h"
#include <abstractmetalang.h>
#include <typesystem.h>
+#include <parser/codemodel.h>
+#include <typeparser.h>
+
+void TestAbstractMetaType::parsing_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("output");
+ QTest::newRow("primitive")
+ << QString::fromLatin1("int") << QString::fromLatin1("int");
+ QTest::newRow("ref")
+ << QString::fromLatin1("int &") << QString::fromLatin1("int&");
+ QTest::newRow("pointer")
+ << QString::fromLatin1("int **") << QString::fromLatin1("int**");
+ QTest::newRow("const ref")
+ << QString::fromLatin1("const int &") << QString::fromLatin1("const int&");
+ QTest::newRow("const pointer")
+ << QString::fromLatin1("const int **") << QString::fromLatin1("const int**");
+ QTest::newRow("const pointer const")
+ << QString::fromLatin1("const int *const*") << QString::fromLatin1("const int*const*");
+}
+
+void TestAbstractMetaType::parsing()
+{
+ QFETCH(QString, input);
+ QFETCH(QString, output);
+ QString errorMessage;
+ const TypeInfo ti = TypeParser::parse(input, &errorMessage);
+ QVERIFY2(errorMessage.isEmpty(), qPrintable(errorMessage));
+ const QString actual = ti.toString();
+ QCOMPARE(actual, output);
+}
void TestAbstractMetaType::testConstCharPtrType()
{
@@ -72,7 +103,8 @@ void TestAbstractMetaType::testApiVersionSupported()
<function signature='justAtest2()' since='1.1'/>\n\
<function signature='justAtest3()'/>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "1.0"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, QLatin1String("1.0")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
@@ -90,7 +122,8 @@ void TestAbstractMetaType::testApiVersionNotSupported()
const char* xmlCode = "<typesystem package='Foo'>\n\
<value-type name='object' since='0.1'/>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h
index b2aa7544f..b39a27a54 100644
--- a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h
+++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h
@@ -35,6 +35,8 @@ class TestAbstractMetaType : public QObject
{
Q_OBJECT
private slots:
+ void parsing_data();
+ void parsing();
void testConstCharPtrType();
void testCharType();
void testTypedef();
diff --git a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
index 2a953243e..db49942c9 100644
--- a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
@@ -366,7 +366,8 @@ void TestAddFunction::testAddFunctionWithApiVersion()
<inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
</add-function>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaFunctionList globalFuncs = builder->globalFunctions();
QCOMPARE(globalFuncs.count(), 1);
diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
index 7bbde3bd4..9f71b495a 100644
--- a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
@@ -34,19 +34,43 @@
#include <abstractmetalang.h>
#include <typesystem.h>
-void TestCodeInjections::testReadFileUtf8()
+void TestCodeInjections::testReadFile_data()
{
+ QTest::addColumn<QString>("filePath");
+ QTest::addColumn<QString>("snippet");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("utf8")
+ << QString::fromLatin1(":/utf8code.txt")
+ << QString()
+ << QString::fromUtf8("\xC3\xA1\xC3\xA9\xC3\xAD\xC3\xB3\xC3\xBA");
+
+ QTest::newRow("snippet")
+ << QString::fromLatin1(":/injectedcode.txt")
+ << QString::fromLatin1("label")
+ << QString::fromLatin1("code line");
+}
+
+void TestCodeInjections::testReadFile()
+{
+ QFETCH(QString, filePath);
+ QFETCH(QString, snippet);
+ QFETCH(QString, expected);
+
const char* cppCode ="struct A {};\n";
int argc = 0;
char *argv[] = {NULL};
QCoreApplication app(argc, argv);
- QString filePath = QDir::currentPath();
+
+ QString attribute = QLatin1String("file='") + filePath + QLatin1Char('\'');
+ if (!snippet.isEmpty())
+ attribute += QLatin1String(" snippet='") + snippet + QLatin1Char('\'');
+
QString xmlCode = QLatin1String("\
<typesystem package=\"Foo\">\n\
<value-type name='A'>\n\
- <conversion-rule file='") + filePath + QLatin1String("/utf8code.txt'/>\n\
- <inject-code class='target' file='") + filePath
- + QLatin1String("/utf8code.txt'/>\n\
+ <conversion-rule ") + attribute + QLatin1String("/>\n\
+ <inject-code class='target' ") + attribute + QLatin1String("/>\n\
</value-type>\n\
<value-type name='A::B'/>\n\
</typesystem>\n");
@@ -56,10 +80,9 @@ void TestCodeInjections::testReadFileUtf8()
const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
QCOMPARE(classA->typeEntry()->codeSnips().count(), 1);
QString code = classA->typeEntry()->codeSnips().first().code();
- QString utf8Data = QString::fromUtf8("\xC3\xA1\xC3\xA9\xC3\xAD\xC3\xB3\xC3\xBA");
- QVERIFY(code.indexOf(utf8Data) != -1);
+ QVERIFY(code.indexOf(expected) != -1);
code = classA->typeEntry()->conversionRule();
- QVERIFY(code.indexOf(utf8Data) != -1);
+ QVERIFY(code.indexOf(expected) != -1);
}
void TestCodeInjections::testInjectWithValidApiVersion()
@@ -74,7 +97,8 @@ void TestCodeInjections::testInjectWithValidApiVersion()
</value-type>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "1.0"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, QLatin1String("1.0")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
@@ -93,7 +117,8 @@ void TestCodeInjections::testInjectWithInvalidApiVersion()
</value-type>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h
index bd5e7ece1..1ac873970 100644
--- a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h
+++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h
@@ -37,7 +37,8 @@ class TestCodeInjections : public QObject
{
Q_OBJECT
private slots:
- void testReadFileUtf8();
+ void testReadFile_data();
+ void testReadFile();
void testInjectWithValidApiVersion();
void testInjectWithInvalidApiVersion();
};
diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.qrc b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.qrc
new file mode 100644
index 000000000..fd7616bd2
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource>
+ <file>utf8code.txt</file>
+ <file>injectedcode.txt</file>
+ </qresource>
+</RCC>
diff --git a/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp
index b46c23f56..6abebb922 100644
--- a/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp
@@ -70,7 +70,8 @@ void TestDropTypeEntries::testDropEntries()
droppedEntries << QLatin1String("Foo.ObjectB") << QLatin1String("Foo.NamespaceA.InnerClassA");
droppedEntries << QLatin1String("Foo.NamespaceB") << QLatin1String("Foo.EnumB") << QLatin1String("Foo.funcB()");
droppedEntries << QLatin1String("Foo.NamespaceA.InnerNamespaceA");
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, Q_NULLPTR, droppedEntries));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false,
+ QString(), droppedEntries));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
@@ -129,7 +130,8 @@ static const char* xmlCode2 = "\
void TestDropTypeEntries::testDropEntryWithChildTags()
{
QStringList droppedEntries(QLatin1String("Foo.ValueA"));
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false, Q_NULLPTR, droppedEntries));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false,
+ QString(), droppedEntries));
QVERIFY(!builder.isNull());
QVERIFY(!AbstractMetaClass::findClass(builder->classes(), QLatin1String("ValueA")));
}
diff --git a/sources/shiboken2/ApiExtractor/tests/testenum.cpp b/sources/shiboken2/ApiExtractor/tests/testenum.cpp
index 87f2608a1..ebdcf8d81 100644
--- a/sources/shiboken2/ApiExtractor/tests/testenum.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testenum.cpp
@@ -104,7 +104,8 @@ void TestEnum::testEnumWithApiVersion()
</value-type>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
QCOMPARE(classes.count(), 1);
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
index 7911a5eb1..f615befb4 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
@@ -60,7 +60,7 @@ R"(<typesystem package="Foo">
QCOMPARE(docMods[1].code().trimmed(), QLatin1String("<para>Some changed contents here</para>"));
QCOMPARE(docMods[1].signature(), QString());
QtDocParser docParser;
- docParser.setDocumentationDataDirectory(QDir::currentPath());
+ docParser.setDocumentationDataDirectory(QLatin1String(":"));
docParser.fillDocumentation(classA);
const QString actualDocSimplified = classA->documentation().value().simplified();
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.qrc b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.qrc
new file mode 100644
index 000000000..76b1bfc61
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource>
+ <file>a.xml</file>
+ </qresource>
+</RCC>
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
index d0a0c9c7a..af24689fe 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
@@ -136,7 +136,8 @@ void TestModifyFunction::invalidateAfterUse()
</object-type>\n\
<object-type name='E' />\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
@@ -208,7 +209,8 @@ void TestModifyFunction::testWithApiVersion()
</modify-function>\n\
</object-type>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
@@ -220,6 +222,61 @@ void TestModifyFunction::testWithApiVersion()
QVERIFY(func->ownership(func->ownerClass(), TypeSystem::TargetLangCode, 0) != TypeSystem::CppOwnership);
}
+void TestModifyFunction::testAllowThread()
+{
+ const char cppCode[] =R"CPP(\
+struct A {
+ void f1();
+ void f2();
+ void f3();
+ int getter1() const;
+ int getter2() const;
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='A'>
+ <modify-function signature='f2()' allow-thread='auto'/>
+ <modify-function signature='f3()' allow-thread='no'/>
+ <modify-function signature='getter2()const' allow-thread='yes'/>
+ </object-type>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, QLatin1String("0.1")));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+
+ // Nothing specified, true
+ const AbstractMetaFunction *f1 = classA->findFunction(QLatin1String("f1"));
+ QVERIFY(f1);
+ QVERIFY(f1->allowThread());
+
+ // 'auto' specified, should be true for nontrivial function
+ const AbstractMetaFunction *f2 = classA->findFunction(QLatin1String("f2"));
+ QVERIFY(f2);
+ QVERIFY(f2->allowThread());
+
+ // 'no' specified, should be false
+ const AbstractMetaFunction *f3 = classA->findFunction(QLatin1String("f3"));
+ QVERIFY(f3);
+ QVERIFY(!f3->allowThread());
+
+ // Nothing specified, should be false for simple getter
+ const AbstractMetaFunction *getter1 = classA->findFunction(QLatin1String("getter1"));
+ QVERIFY(getter1);
+ QVERIFY(!getter1->allowThread());
+
+ // Forced to true simple getter
+ const AbstractMetaFunction *getter2 = classA->findFunction(QLatin1String("getter2"));
+ QVERIFY(getter2);
+ QVERIFY(getter2->allowThread()); // Forced to true simple getter
+}
+
void TestModifyFunction::testGlobalFunctionModification()
{
const char* cppCode ="\
@@ -258,4 +315,42 @@ void TestModifyFunction::testGlobalFunctionModification()
QCOMPARE(arg->defaultValueExpression(), QLatin1String("A()"));
}
+void TestModifyFunction::testExceptionSpecification()
+{
+ const char cppCode[] = R"CPP(
+struct A {
+ void unspecified();
+ void nonThrowing() noexcept;
+ void throwing() throw(int);
+};
+)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <primitive-type name='int'/>
+ <object-type name='A'>
+ <modify-function signature='throwing()' exception-handling='auto-on'/>
+ </object-type>
+</typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A"));
+ QVERIFY(classA);
+
+ const AbstractMetaFunction *f = classA->findFunction(QStringLiteral("unspecified"));
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Unknown);
+ QVERIFY(!f->generateExceptionHandling());
+
+ f = classA->findFunction(QStringLiteral("nonThrowing"));
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::NoExcept);
+ QVERIFY(!f->generateExceptionHandling());
+
+ f = classA->findFunction(QStringLiteral("throwing"));
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Throws);
+ QVERIFY(f->generateExceptionHandling());
+}
+
QTEST_APPLESS_MAIN(TestModifyFunction)
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
index f116b5124..494f31991 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
@@ -37,10 +37,12 @@ class TestModifyFunction : public QObject
private slots:
void testOwnershipTransfer();
void testWithApiVersion();
+ void testAllowThread();
void testRenameArgument_data();
void testRenameArgument();
void invalidateAfterUse();
void testGlobalFunctionModification();
+ void testExceptionSpecification();
};
#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp
index 11cda3317..38099c455 100644
--- a/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp
@@ -82,7 +82,8 @@ void TestRefCountTag::testWithApiVersion()
</object-type>\n\
</typesystem>\n";
- QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "0.1"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, QLatin1String("0.1")));
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
index 8d869e3f9..b1b171bae 100644
--- a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
@@ -28,6 +28,7 @@
#include "testtemplates.h"
#include <QtTest/QTest>
+#include <QtCore/QTextStream>
#include <QTemporaryFile>
#include "testutil.h"
#include <abstractmetalang.h>
@@ -438,4 +439,122 @@ typedef Vector<int> IntVector;
QCOMPARE(otherMethod->type()->cppSignature(), QLatin1String("Vector<int >"));
}
+// Perform checks on template inheritance; a typedef of a template class
+// should result in rewritten types.
+void TestTemplates::testTemplateTypeDefs_data()
+{
+ QTest::addColumn<QString>("cpp");
+ QTest::addColumn<QString>("xml");
+
+ const char optionalClassDef[] = R"CPP(
+template<class T> // Some value type similar to std::optional
+class Optional {
+public:
+ T value() const { return m_value; }
+ operator bool() const { return m_success; }
+
+ T m_value;
+ bool m_success = false;
+};
+)CPP";
+
+ const char xmlPrefix[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <primitive-type name='bool'/>
+)XML";
+
+ const char xmlOptionalDecl[] = "<value-type name='Optional' generate='no'/>\n";
+ const char xmlOptionalIntDecl[] = "<value-type name='IntOptional'/>\n";
+ const char xmlPostFix[] = "</typesystem>\n";
+
+ // Flat, global namespace
+ QString cpp;
+ QTextStream(&cpp) << optionalClassDef
+ << "typedef Optional<int> IntOptional;\n";
+ QString xml;
+ QTextStream(&xml) << xmlPrefix << xmlOptionalDecl << xmlOptionalIntDecl
+ << "<typedef-type name='XmlIntOptional' source='Optional&lt;int&gt;'/>"
+ << xmlPostFix;
+ QTest::newRow("global-namespace")
+ << cpp << xml;
+
+ // Typedef from namespace Std
+ cpp.clear();
+ QTextStream(&cpp) << "namespace Std {\n" << optionalClassDef << "}\n"
+ << "typedef Std::Optional<int> IntOptional;\n";
+ xml.clear();
+ QTextStream(&xml) << xmlPrefix
+ << "<namespace-type name='Std'>\n" << xmlOptionalDecl
+ << "</namespace-type>\n" << xmlOptionalIntDecl
+ << "<typedef-type name='XmlIntOptional' source='Std::Optional&lt;int&gt;'/>"
+ << xmlPostFix;
+ QTest::newRow("namespace-Std")
+ << cpp << xml;
+
+ // Typedef from nested class
+ cpp.clear();
+ QTextStream(&cpp) << "class Outer {\npublic:\n" << optionalClassDef << "\n};\n"
+ << "typedef Outer::Optional<int> IntOptional;\n";
+ xml.clear();
+ QTextStream(&xml) << xmlPrefix
+ << "<object-type name='Outer'>\n" << xmlOptionalDecl
+ << "</object-type>\n" << xmlOptionalIntDecl
+ << "<typedef-type name='XmlIntOptional' source='Outer::Optional&lt;int&gt;'/>"
+ << xmlPostFix;
+ QTest::newRow("nested-class")
+ << cpp << xml;
+}
+
+void TestTemplates::testTemplateTypeDefs()
+{
+ QFETCH(QString, cpp);
+ QFETCH(QString, xml);
+
+ const QByteArray cppBa = cpp.toLocal8Bit();
+ const QByteArray xmlBa = xml.toLocal8Bit();
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppBa.constData(), xmlBa.constData(), true));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+
+ const AbstractMetaClass *optional = AbstractMetaClass::findClass(classes, QLatin1String("Optional"));
+ QVERIFY(optional);
+
+ // Find the typedef'ed class
+ const AbstractMetaClass *optionalInt =
+ AbstractMetaClass::findClass(classes, QLatin1String("IntOptional"));
+ QVERIFY(optionalInt);
+ QCOMPARE(optionalInt->templateBaseClass(), optional);
+
+ // Find the class typedef'ed in the typesystem XML
+ const AbstractMetaClass *xmlOptionalInt =
+ AbstractMetaClass::findClass(classes, QLatin1String("XmlIntOptional"));
+ QVERIFY(xmlOptionalInt);
+ QCOMPARE(xmlOptionalInt->templateBaseClass(), optional);
+
+ // Check whether the value() method now has an 'int' return
+ const AbstractMetaFunction *valueMethod =
+ optionalInt->findFunction(QLatin1String("value"));
+ QVERIFY(valueMethod);
+ QCOMPARE(valueMethod->type()->cppSignature(), QLatin1String("int"));
+
+ // ditto for typesystem XML
+ const AbstractMetaFunction *xmlValueMethod =
+ xmlOptionalInt->findFunction(QLatin1String("value"));
+ QVERIFY(xmlValueMethod);
+ QCOMPARE(xmlValueMethod->type()->cppSignature(), QLatin1String("int"));
+
+ // Check whether the m_value field is of type 'int'
+ const AbstractMetaField *valueField =
+ optionalInt->findField(QLatin1String("m_value"));
+ QVERIFY(valueField);
+ QCOMPARE(valueField->type()->cppSignature(), QLatin1String("int"));
+
+ // ditto for typesystem XML
+ const AbstractMetaField *xmlValueField =
+ xmlOptionalInt->findField(QLatin1String("m_value"));
+ QVERIFY(xmlValueField);
+ QCOMPARE(xmlValueField->type()->cppSignature(), QLatin1String("int"));
+}
+
QTEST_APPLESS_MAIN(TestTemplates)
diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.h b/sources/shiboken2/ApiExtractor/tests/testtemplates.h
index 3e1565933..df3de18b9 100644
--- a/sources/shiboken2/ApiExtractor/tests/testtemplates.h
+++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.h
@@ -46,6 +46,8 @@ private slots:
void testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration();
void testTypedefOfInstantiationOfTemplateClass();
void testContainerTypeIncompleteArgument();
+ void testTemplateTypeDefs_data();
+ void testTemplateTypeDefs();
};
#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp b/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp
index 1ec7ce025..a7e88e437 100644
--- a/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp
@@ -31,6 +31,7 @@
#include "testutil.h"
#include <abstractmetalang.h>
#include <typesystem.h>
+#include <typedatabase.h>
void TestTypeRevision::testRevisionAttr()
{
@@ -49,21 +50,55 @@ void TestTypeRevision::testRevisionAttr()
QVERIFY(!builder.isNull());
AbstractMetaClassList classes = builder->classes();
const AbstractMetaClass *rev0 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_0"));
- QCOMPARE(getTypeRevision(rev0->typeEntry()), 0);
+ QCOMPARE(rev0->typeEntry()->revision(), 0);
const AbstractMetaClass *rev1 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_1"));
- QCOMPARE(getTypeRevision(rev1->typeEntry()), 1);
+ QCOMPARE(rev1->typeEntry()->revision(), 1);
AbstractMetaClass *rev2 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_2"));
- QCOMPARE(getTypeRevision(rev2->typeEntry()), 2);
+ QCOMPARE(rev2->typeEntry()->revision(), 2);
AbstractMetaEnum* rev3 = rev2->findEnum(QLatin1String("Rev_3"));
- QCOMPARE(getTypeRevision(rev3->typeEntry()), 3);
+ QCOMPARE(rev3->typeEntry()->revision(), 3);
FlagsTypeEntry* rev4 = rev3->typeEntry()->flags();
- QCOMPARE(getTypeRevision(rev4), 4);
+ QCOMPARE(rev4->revision(), 4);
AbstractMetaEnum* rev5 = rev2->findEnum(QLatin1String("Rev_5"));
- QCOMPARE(getTypeRevision(rev5->typeEntry()), 5);
- QCOMPARE(getTypeRevision(rev5->typeEntry()->flags()), 5);
+ const EnumTypeEntry *revEnumTypeEntry = rev5->typeEntry();
+ QCOMPARE(revEnumTypeEntry->revision(), 5);
+ QCOMPARE(revEnumTypeEntry->flags()->revision(), 5);
+}
+
+
+void TestTypeRevision::testVersion_data()
+{
+ QTest::addColumn<QString>("version");
+ QTest::addColumn<int>("expectedClassCount");
+
+ QTest::newRow("none") << QString() << 2;
+ QTest::newRow("1.0") << QString::fromLatin1("1.0") << 1; // Bar20 excluded
+ QTest::newRow("2.0") << QString::fromLatin1("2.0") << 2;
+}
+
+void TestTypeRevision::testVersion()
+{
+ QFETCH(QString, version);
+ QFETCH(int, expectedClassCount);
+
+ const char cppCode[] = R"CPP(
+class Bar {};
+class Bar20 {};
+)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <value-type name="Bar"/>
+ <value-type name="Bar20" since="2.0"/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, version));
+ QVERIFY(!builder.isNull());
+
+ QCOMPARE(builder->classes().size(), expectedClassCount);
}
QTEST_APPLESS_MAIN(TestTypeRevision)
diff --git a/sources/shiboken2/ApiExtractor/tests/testtyperevision.h b/sources/shiboken2/ApiExtractor/tests/testtyperevision.h
index 4dfa241e3..3832c3883 100644
--- a/sources/shiboken2/ApiExtractor/tests/testtyperevision.h
+++ b/sources/shiboken2/ApiExtractor/tests/testtyperevision.h
@@ -37,6 +37,8 @@ class TestTypeRevision : public QObject
private slots:
void testRevisionAttr();
+ void testVersion_data();
+ void testVersion();
};
#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testutil.h b/sources/shiboken2/ApiExtractor/tests/testutil.h
index 6152793f5..c6ad19d7e 100644
--- a/sources/shiboken2/ApiExtractor/tests/testutil.h
+++ b/sources/shiboken2/ApiExtractor/tests/testutil.h
@@ -40,20 +40,23 @@ namespace TestUtil
{
static AbstractMetaBuilder *parse(const char *cppCode, const char *xmlCode,
bool silent = true,
- const char *apiVersion = Q_NULLPTR,
+ const QString &apiVersion = QString(),
const QStringList &dropTypeEntries = QStringList())
{
ReportHandler::setSilent(silent);
TypeDatabase* td = TypeDatabase::instance(true);
- if (apiVersion && !td->setApiVersion(QLatin1String("*"), QLatin1String(apiVersion)))
- return Q_NULLPTR;
+ if (apiVersion.isEmpty())
+ TypeDatabase::clearApiVersions();
+ else if (!td->setApiVersion(QLatin1String("*"), apiVersion))
+ return nullptr;
td->setDropTypeEntries(dropTypeEntries);
QBuffer buffer;
// parse typesystem
buffer.setData(xmlCode);
if (!buffer.open(QIODevice::ReadOnly))
return Q_NULLPTR;
- td->parseFile(&buffer);
+ if (!td->parseFile(&buffer))
+ return nullptr;
buffer.close();
// parse C++ code
QTemporaryFile tempSource(QDir::tempPath() + QLatin1String("/st_XXXXXX_main.cpp"));
diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp
index 9529de40a..4cb6cdd8a 100644
--- a/sources/shiboken2/ApiExtractor/typedatabase.cpp
+++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp
@@ -166,64 +166,66 @@ ContainerTypeEntry* TypeDatabase::findContainerType(const QString &name) const
return 0;
}
-FunctionTypeEntry* TypeDatabase::findFunctionType(const QString& name) const
+static bool inline useType(const TypeEntry *t)
{
- TypeEntry* entry = findType(name);
- if (entry && entry->type() == TypeEntry::FunctionType)
- return static_cast<FunctionTypeEntry*>(entry);
- return 0;
+ return !t->isPrimitive()
+ || static_cast<const PrimitiveTypeEntry *>(t)->preferredTargetLangType();
}
-TypeEntry* TypeDatabase::findType(const QString& name) const
+FunctionTypeEntry* TypeDatabase::findFunctionType(const QString& name) const
{
- const TypeEntryList &entries = findTypes(name);
+ const auto entries = findTypes(name);
for (TypeEntry *entry : entries) {
- if (entry &&
- (!entry->isPrimitive() || static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())) {
- return entry;
- }
+ if (entry->type() == TypeEntry::FunctionType && useType(entry))
+ return static_cast<FunctionTypeEntry*>(entry);
}
return 0;
}
-TypeEntryList TypeDatabase::findTypes(const QString &name) const
+const TypeSystemTypeEntry *TypeDatabase::findTypeSystemType(const QString &name) const
{
- return m_entries.value(name);
+ const auto entries = findTypes(name);
+ for (const TypeEntry *entry : entries) {
+ if (entry->type() == TypeEntry::TypeSystemType)
+ return static_cast<const TypeSystemTypeEntry *>(entry);
+ }
+ return nullptr;
}
-SingleTypeEntryHash TypeDatabase::entries() const
+TypeEntry* TypeDatabase::findType(const QString& name) const
{
- TypeEntryHash entries = allEntries();
-
- SingleTypeEntryHash returned;
- for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it)
- returned.insert(it.key(), findType(it.key()));
+ const auto entries = findTypes(name);
+ for (TypeEntry *entry : entries) {
+ if (useType(entry))
+ return entry;
+ }
+ return nullptr;
+}
- return returned;
+TypeEntryMultiMapConstIteratorRange TypeDatabase::findTypes(const QString &name) const
+{
+ const auto range = m_entries.equal_range(name);
+ return {range.first, range.second};
}
PrimitiveTypeEntryList TypeDatabase::primitiveTypes() const
{
- TypeEntryHash entries = allEntries();
PrimitiveTypeEntryList returned;
- for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
- for (TypeEntry *typeEntry : it.value()) {
- if (typeEntry->isPrimitive())
- returned.append(static_cast<PrimitiveTypeEntry *>(typeEntry));
- }
+ for (auto it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it) {
+ TypeEntry *typeEntry = it.value();
+ if (typeEntry->isPrimitive())
+ returned.append(static_cast<PrimitiveTypeEntry *>(typeEntry));
}
return returned;
}
ContainerTypeEntryList TypeDatabase::containerTypes() const
{
- TypeEntryHash entries = allEntries();
ContainerTypeEntryList returned;
- for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
- for (TypeEntry *typeEntry : it.value()) {
- if (typeEntry->isContainer())
- returned.append(static_cast<ContainerTypeEntry *>(typeEntry));
- }
+ for (auto it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it) {
+ TypeEntry *typeEntry = it.value();
+ if (typeEntry->isContainer())
+ returned.append(static_cast<ContainerTypeEntry *>(typeEntry));
}
return returned;
}
@@ -263,6 +265,8 @@ static inline QString msgRejectReason(const TypeRejection &r, const QString &nee
str << " matches class \"" << r.className.pattern() << "\" and \"" << needle
<< "\" matches \"" << r.pattern.pattern() << '"';
break;
+ case TypeRejection::Invalid:
+ break;
}
return result;
}
@@ -303,9 +307,52 @@ bool TypeDatabase::isEnumRejected(const QString& className, const QString& enumN
return findRejection(m_rejections, TypeRejection::Enum, className, enumName, reason);
}
-void TypeDatabase::addType(TypeEntry *e)
+TypeEntry *TypeDatabase::resolveTypeDefEntry(TypedefEntry *typedefEntry,
+ QString *errorMessage)
+{
+ QString sourceName = typedefEntry->sourceType();
+ const int lessThanPos = sourceName.indexOf(QLatin1Char('<'));
+ if (lessThanPos != -1)
+ sourceName.truncate(lessThanPos);
+ ComplexTypeEntry *source = nullptr;
+ for (TypeEntry *e : findTypes(sourceName)) {
+ switch (e->type()) {
+ case TypeEntry::BasicValueType:
+ case TypeEntry::ContainerType:
+ case TypeEntry::InterfaceType:
+ case TypeEntry::ObjectType:
+ case TypeEntry::SmartPointerType:
+ source = dynamic_cast<ComplexTypeEntry *>(e);
+ Q_ASSERT(source);
+ break;
+ default:
+ break;
+ }
+ }
+ if (!source) {
+ if (errorMessage)
+ *errorMessage = QLatin1String("Unable to resolve typedef \"")
+ + typedefEntry->sourceType() + QLatin1Char('"');
+ return nullptr;
+ }
+
+ ComplexTypeEntry *result = static_cast<ComplexTypeEntry *>(source->clone());
+ result->useAsTypedef(typedefEntry);
+ typedefEntry->setSource(source);
+ typedefEntry->setTarget(result);
+ m_typedefEntries.insert(typedefEntry->qualifiedCppName(), typedefEntry);
+ return result;
+}
+
+bool TypeDatabase::addType(TypeEntry *e, QString *errorMessage)
{
- m_entries[e->qualifiedCppName()].append(e);
+ if (e->type() == TypeEntry::TypedefType) {
+ e = resolveTypeDefEntry(static_cast<TypedefEntry *>(e), errorMessage);
+ if (Q_UNLIKELY(!e))
+ return false;
+ }
+ m_entries.insert(e->qualifiedCppName(), e);
+ return true;
}
bool TypeDatabase::isFunctionRejected(const QString& className, const QString& functionName,
@@ -339,7 +386,7 @@ FlagsTypeEntry* TypeDatabase::findFlagsType(const QString &name) const
fte = m_flagsEntries.value(name);
if (!fte) {
//last hope, search for flag without scope inside of flags hash
- for (SingleTypeEntryHash::const_iterator it = m_flagsEntries.cbegin(), end = m_flagsEntries.cend(); it != end; ++it) {
+ for (auto it = m_flagsEntries.cbegin(), end = m_flagsEntries.cend(); it != end; ++it) {
if (it.key().endsWith(name)) {
fte = it.value();
break;
@@ -427,12 +474,13 @@ bool TypeDatabase::addSuppressedWarning(const QString &warning, QString *errorMe
pattern.append(QLatin1Char('$'));
}
- const QRegularExpression expression(pattern);
+ QRegularExpression expression(pattern);
if (!expression.isValid()) {
*errorMessage = QLatin1String("Invalid message pattern \"") + warning
+ QLatin1String("\": ") + expression.errorString();
return false;
}
+ expression.setPatternOptions(expression.patternOptions() | QRegularExpression::MultilineOption);
m_suppressedWarnings.append(expression);
return true;
@@ -518,16 +566,21 @@ bool TypeDatabase::parseFile(QIODevice* device, bool generate)
{
QXmlStreamReader reader(device);
Handler handler(this, generate);
- return handler.parse(reader);
+ const bool result = handler.parse(reader);
+ if (!result)
+ qCWarning(lcShiboken, "%s", qPrintable(handler.errorString()));
+ return result;
}
PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString& name) const
{
- const TypeEntryList &entries = findTypes(name);
-
+ const auto entries = findTypes(name);
for (TypeEntry *entry : entries) {
- if (entry && entry->isPrimitive() && static_cast<PrimitiveTypeEntry*>(entry)->preferredTargetLangType())
- return static_cast<PrimitiveTypeEntry*>(entry);
+ if (entry->isPrimitive()) {
+ PrimitiveTypeEntry *pe = static_cast<PrimitiveTypeEntry *>(entry);
+ if (pe->preferredTargetLangType())
+ return pe;
+ }
}
return 0;
@@ -535,9 +588,9 @@ PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString& name) const
ComplexTypeEntry* TypeDatabase::findComplexType(const QString& name) const
{
- const TypeEntryList &entries = findTypes(name);
+ const auto entries = findTypes(name);
for (TypeEntry *entry : entries) {
- if (entry && entry->isComplex())
+ if (entry->isComplex() && useType(entry))
return static_cast<ComplexTypeEntry*>(entry);
}
return 0;
@@ -545,9 +598,9 @@ ComplexTypeEntry* TypeDatabase::findComplexType(const QString& name) const
ObjectTypeEntry* TypeDatabase::findObjectType(const QString& name) const
{
- const TypeEntryList &entries = findTypes(name);
+ const auto entries = findTypes(name);
for (TypeEntry *entry : entries) {
- if (entry && entry->isObject())
+ if (entry && entry->isObject() && useType(entry))
return static_cast<ObjectTypeEntry*>(entry);
}
return 0;
@@ -555,9 +608,9 @@ ObjectTypeEntry* TypeDatabase::findObjectType(const QString& name) const
NamespaceTypeEntry* TypeDatabase::findNamespaceType(const QString& name) const
{
- const TypeEntryList &entries = findTypes(name);
+ const auto entries = findTypes(name);
for (TypeEntry *entry : entries) {
- if (entry && entry->isNamespace())
+ if (entry->isNamespace() && useType(entry))
return static_cast<NamespaceTypeEntry*>(entry);
}
return 0;
@@ -574,75 +627,64 @@ void TypeDatabase::setDropTypeEntries(QStringList dropTypeEntries)
m_dropTypeEntries.sort();
}
-// Using std::pair to save some memory
-// the pair means (revision, typeIndex)
-// This global variable exists only because we can't break the ABI
-typedef QHash<const TypeEntry*, std::pair<int, int> > TypeRevisionMap;
-Q_GLOBAL_STATIC(TypeRevisionMap, typeEntryFields);
static bool computeTypeIndexes = true;
static int maxTypeIndex;
-int getTypeRevision(const TypeEntry* typeEntry)
+static bool typeEntryLessThan(const TypeEntry* t1, const TypeEntry* t2)
{
- return typeEntryFields()->value(typeEntry).first;
-}
-
-void setTypeRevision(TypeEntry* typeEntry, int revision)
-{
- (*typeEntryFields())[typeEntry].first = revision;
- computeTypeIndexes = true;
-}
-
-static bool compareTypeEntriesByName(const TypeEntry* t1, const TypeEntry* t2)
-{
- return t1->qualifiedCppName() < t2->qualifiedCppName();
+ if (t1->revision() < t2->revision())
+ return true;
+ return t1->revision() == t2->revision()
+ && t1->qualifiedCppName() < t2->qualifiedCppName();
}
static void _computeTypeIndexes()
{
TypeDatabase* tdb = TypeDatabase::instance();
- typedef QMap<int, TypeEntryList> GroupedTypeEntries;
- GroupedTypeEntries groupedEntries;
+
+ TypeEntryList list;
// Group type entries by revision numbers
- const TypeEntryHash &allEntries = tdb->allEntries();
- for (TypeEntryHash::const_iterator tit = allEntries.cbegin(), end = allEntries.cend(); tit != end; ++tit) {
- for (TypeEntry *entry : tit.value()) {
- if (entry->isPrimitive()
- || entry->isContainer()
- || entry->isFunction()
- || !entry->generateCode()
- || entry->isEnumValue()
- || entry->isVarargs()
- || entry->isTypeSystem()
- || entry->isVoid()
- || entry->isCustom())
- continue;
- groupedEntries[getTypeRevision(entry)] << entry;
- }
- }
+ const auto &allEntries = tdb->entries();
+ list.reserve(allEntries.size());
+ for (auto tit = allEntries.cbegin(), end = allEntries.cend(); tit != end; ++tit) {
+ TypeEntry *entry = tit.value();
+ if (entry->isPrimitive()
+ || entry->isContainer()
+ || entry->isFunction()
+ || !entry->generateCode()
+ || entry->isEnumValue()
+ || entry->isVarargs()
+ || entry->isTypeSystem()
+ || entry->isVoid()
+ || entry->isCustom())
+ continue;
+ if (!list.contains(entry)) // Remove duplicates
+ list.append(entry);
+ }
+
+ // Sort the type entries by revision, name
+ std::sort(list.begin(), list.end(), typeEntryLessThan);
maxTypeIndex = 0;
- GroupedTypeEntries::iterator it = groupedEntries.begin();
- for (; it != groupedEntries.end(); ++it) {
- // Remove duplicates
- TypeEntryList::iterator newEnd = std::unique(it.value().begin(), it.value().end());
- it.value().erase(newEnd, it.value().end());
- // Sort the type entries by name
- qSort(it.value().begin(), newEnd, compareTypeEntriesByName);
-
- for (TypeEntry *entry : qAsConst(it.value())) {
- (*typeEntryFields())[entry].second = maxTypeIndex++;
- }
- }
+ for (TypeEntry *e : qAsConst(list))
+ e->setSbkIndex(maxTypeIndex++);
computeTypeIndexes = false;
}
-int getTypeIndex(const TypeEntry* typeEntry)
+void TypeEntry::setRevision(int r)
+{
+ if (m_revision != r) {
+ m_revision = r;
+ computeTypeIndexes = true;
+ }
+}
+
+int TypeEntry::sbkIndex() const
{
if (computeTypeIndexes)
_computeTypeIndexes();
- return typeEntryFields()->value(typeEntry).second;
+ return m_sbkIndex;
}
int getMaxTypeIndex()
@@ -652,6 +694,11 @@ int getMaxTypeIndex()
return maxTypeIndex;
}
+void TypeDatabase::clearApiVersions()
+{
+ apiVersions()->clear();
+}
+
bool TypeDatabase::setApiVersion(const QString& packageWildcardPattern, const QString &version)
{
const QString packagePattern = wildcardToRegExp(packageWildcardPattern.trimmed());
@@ -673,9 +720,11 @@ bool TypeDatabase::setApiVersion(const QString& packageWildcardPattern, const QS
}
bool TypeDatabase::checkApiVersion(const QString &package,
- const QVersionNumber &versionNumber) const
+ const QVersionNumber &versionNumber)
{
const ApiVersions &versions = *apiVersions();
+ if (versions.isEmpty()) // Nothing specified: use latest.
+ return true;
for (int i = 0, size = versions.size(); i < size; ++i) {
if (versions.at(i).first.match(package).hasMatch())
return versions.at(i).second >= versionNumber;
@@ -684,33 +733,104 @@ bool TypeDatabase::checkApiVersion(const QString &package,
}
#ifndef QT_NO_DEBUG_STREAM
+
+#define FORMAT_BOOL(name, var) \
+ if (var) \
+ d << ", [" << name << ']';
+
+#define FORMAT_NONEMPTY_STRING(name, var) \
+ if (!var.isEmpty()) \
+ d << ", " << name << "=\"" << var << '"';
+
+#define FORMAT_LIST_SIZE(name, var) \
+ if (!var.isEmpty()) \
+ d << ", " << var.size() << ' ' << name;
+
+void TypeEntry::formatDebug(QDebug &d) const
+{
+ const QString cppName = qualifiedCppName();
+ d << '"' << m_name << '"';
+ if (m_name != cppName)
+ d << "\", cppName=\"" << cppName << '"';
+ d << ", type=" << m_type << ", codeGeneration=0x"
+ << hex << m_codeGeneration << dec;
+ FORMAT_NONEMPTY_STRING("package", m_targetLangPackage)
+ FORMAT_BOOL("stream", m_stream)
+ FORMAT_LIST_SIZE("codeSnips", m_codeSnips)
+ FORMAT_NONEMPTY_STRING("conversionRule", m_conversionRule)
+ if (!m_version.isNull() && m_version > QVersionNumber(0, 0))
+ d << ", version=" << m_version;
+ if (m_revision)
+ d << ", revision=" << m_revision;
+ if (m_sbkIndex)
+ d << ", sbkIndex=" << m_sbkIndex;
+ if (m_include.isValid())
+ d << ", include=" << m_include;
+ if (const int count = m_extraIncludes.size()) {
+ d << ", extraIncludes[" << count << "]=";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ d << ", ";
+ d << m_extraIncludes.at(i);
+ }
+ }
+}
+
+void ComplexTypeEntry::formatDebug(QDebug &d) const
+{
+ TypeEntry::formatDebug(d);
+ FORMAT_NONEMPTY_STRING("targetLangName", m_targetLangName)
+ FORMAT_BOOL("QObject", m_qobject)
+ FORMAT_BOOL("polymorphicBase", m_polymorphicBase)
+ FORMAT_BOOL("genericClass", m_genericClass)
+ FORMAT_BOOL("deleteInMainThread", m_deleteInMainThread)
+ if (m_typeFlags != 0)
+ d << ", typeFlags=" << m_typeFlags;
+ d << ", copyableFlag=" << m_copyableFlag
+ << ", except=" << int(m_exceptionHandling);
+ FORMAT_NONEMPTY_STRING("defaultSuperclass", m_defaultSuperclass)
+ FORMAT_NONEMPTY_STRING("polymorphicIdValue", m_polymorphicIdValue)
+ FORMAT_NONEMPTY_STRING("lookupName", m_lookupName)
+ FORMAT_NONEMPTY_STRING("targetType", m_targetType)
+ FORMAT_NONEMPTY_STRING("hash", m_hashFunction)
+ FORMAT_LIST_SIZE("addedFunctions", m_addedFunctions)
+ FORMAT_LIST_SIZE("functionMods", m_functionMods)
+ FORMAT_LIST_SIZE("fieldMods", m_fieldMods)
+}
+
+void TypedefEntry::formatDebug(QDebug &d) const
+{
+ ComplexTypeEntry::formatDebug(d);
+ d << ", sourceType=\"" << m_sourceType << '"'
+ << ", source=" << m_source << ", target=" << m_target;
+}
+
+void EnumTypeEntry::formatDebug(QDebug &d) const
+{
+ TypeEntry::formatDebug(d);
+ FORMAT_NONEMPTY_STRING("package", m_packageName)
+ FORMAT_NONEMPTY_STRING("qualifier", m_qualifier)
+ FORMAT_NONEMPTY_STRING("targetLangName", m_targetLangName)
+ if (m_flags)
+ d << ", flags=(" << m_flags << ')';
+}
+
+void ContainerTypeEntry::formatDebug(QDebug &d) const
+{
+ ComplexTypeEntry::formatDebug(d);
+ d << ", type=" << m_type << ",\"" << typeName() << '"';
+}
+
QDebug operator<<(QDebug d, const TypeEntry *te)
{
QDebugStateSaver saver(d);
d.noquote();
d.nospace();
d << "TypeEntry(";
- if (te) {
- const QString name = te->name();
- const QString cppName = te->qualifiedCppName();
- d << '"' << name << '"';
- if (name != cppName)
- d << "\", cppName=\"" << cppName << '"';
- d << ", type=" << te->type();
- if (te->include().isValid())
- d << ", include=" << te->include();
- const IncludeList &extraIncludes = te->extraIncludes();
- if (const int count = extraIncludes.size()) {
- d << ", extraIncludes[" << count << "]=";
- for (int i = 0; i < count; ++i) {
- if (i)
- d << ", ";
- d << extraIncludes.at(i);
- }
- }
- } else {
+ if (te)
+ te->formatDebug(d);
+ else
d << '0';
- }
d << ')';
return d;
}
@@ -732,25 +852,14 @@ QDebug operator<<(QDebug d, const TemplateEntry *te)
void TypeDatabase::formatDebug(QDebug &d) const
{
- typedef TypeEntryHash::ConstIterator Eit;
- typedef SingleTypeEntryHash::ConstIterator Sit;
- typedef TemplateEntryHash::ConstIterator TplIt;
d << "TypeDatabase("
<< "entries[" << m_entries.size() << "]=";
- for (Eit it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it) {
- const int count = it.value().size();
- d << '"' << it.key() << "\" [" << count << "]: (";
- for (int t = 0; t < count; ++t) {
- if (t)
- d << ", ";
- d << it.value().at(t);
- }
- d << ")\n";
- }
+ for (auto it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it)
+ d << " " << it.value() << '\n';
if (!m_templates.isEmpty()) {
d << "templates[" << m_templates.size() << "]=(";
- const TplIt begin = m_templates.cbegin();
- for (TplIt it = begin, end = m_templates.cend(); it != end; ++it) {
+ const auto begin = m_templates.cbegin();
+ for (auto it = begin, end = m_templates.cend(); it != end; ++it) {
if (it != begin)
d << ", ";
d << it.value();
@@ -759,8 +868,8 @@ void TypeDatabase::formatDebug(QDebug &d) const
}
if (!m_flagsEntries.isEmpty()) {
d << "flags[" << m_flagsEntries.size() << "]=(";
- const Sit begin = m_flagsEntries.cbegin();
- for (Sit it = begin, end = m_flagsEntries.cend(); it != end; ++it) {
+ const auto begin = m_flagsEntries.cbegin();
+ for (auto it = begin, end = m_flagsEntries.cend(); it != end; ++it) {
if (it != begin)
d << ", ";
d << it.value();
diff --git a/sources/shiboken2/ApiExtractor/typedatabase.h b/sources/shiboken2/ApiExtractor/typedatabase.h
index 2e7b009c2..247d74362 100644
--- a/sources/shiboken2/ApiExtractor/typedatabase.h
+++ b/sources/shiboken2/ApiExtractor/typedatabase.h
@@ -54,13 +54,12 @@ struct TypeRejection;
QT_FORWARD_DECLARE_CLASS(QDebug)
-void setTypeRevision(TypeEntry* typeEntry, int revision);
-int getTypeRevision(const TypeEntry* typeEntry);
-int getTypeIndex(const TypeEntry* typeEntry);
int getMaxTypeIndex();
class ContainerTypeEntry;
class PrimitiveTypeEntry;
+class TypeSystemTypeEntry;
+
class TypeDatabase
{
TypeDatabase();
@@ -91,12 +90,12 @@ public:
NamespaceTypeEntry* findNamespaceType(const QString& name) const;
ContainerTypeEntry* findContainerType(const QString& name) const;
FunctionTypeEntry* findFunctionType(const QString& name) const;
+ const TypeSystemTypeEntry *findTypeSystemType(const QString &name) const;
TypeEntry* findType(const QString& name) const;
- TypeEntryHash allEntries() const { return m_entries; }
-
- SingleTypeEntryHash entries() const;
+ const TypeEntryMultiMap &entries() const { return m_entries; }
+ const TypedefEntryMap &typedefEntries() const { return m_typedefEntries; }
PrimitiveTypeEntryList primitiveTypes() const;
@@ -115,7 +114,7 @@ public:
bool isReturnTypeRejected(const QString& className, const QString& typeName,
QString *reason = nullptr) const;
- void addType(TypeEntry* e);
+ bool addType(TypeEntry* e, QString *errorMessage = nullptr);
FlagsTypeEntry* findFlagsType(const QString& name) const;
void addFlagsType(FlagsTypeEntry* fte);
@@ -147,9 +146,10 @@ public:
bool parseFile(QIODevice* device, bool generate = true);
- bool setApiVersion(const QString& package, const QString& version);
+ static bool setApiVersion(const QString& package, const QString& version);
+ static void clearApiVersions();
- bool checkApiVersion(const QString &package, const QVersionNumber &version) const;
+ static bool checkApiVersion(const QString &package, const QVersionNumber &version);
bool hasDroppedTypeEntries() const { return !m_dropTypeEntries.isEmpty(); }
@@ -163,12 +163,14 @@ public:
void formatDebug(QDebug &d) const;
#endif
private:
- TypeEntryList findTypes(const QString &name) const;
+ TypeEntryMultiMapConstIteratorRange findTypes(const QString &name) const;
+ TypeEntry *resolveTypeDefEntry(TypedefEntry *typedefEntry, QString *errorMessage);
bool m_suppressWarnings;
- TypeEntryHash m_entries;
- SingleTypeEntryHash m_flagsEntries;
- TemplateEntryHash m_templates;
+ TypeEntryMultiMap m_entries;
+ TypeEntryMap m_flagsEntries;
+ TypedefEntryMap m_typedefEntries;
+ TemplateEntryMap m_templates;
QVector<QRegularExpression> m_suppressedWarnings;
AddedFunctionList m_globalUserFunctions;
diff --git a/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h b/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h
index 083602322..fbbbabe43 100644
--- a/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h
+++ b/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h
@@ -29,7 +29,7 @@
#ifndef TYPEDATABASE_TYPEDEFS_H
#define TYPEDATABASE_TYPEDEFS_H
-#include <QtCore/QHash>
+#include <QtCore/QMultiMap>
#include <QtCore/QString>
#include <QtCore/QVector>
@@ -37,11 +37,28 @@ class ContainerTypeEntry;
class PrimitiveTypeEntry;
class TemplateEntry;
class TypeEntry;
+class TypedefEntry;
typedef QVector<TypeEntry *> TypeEntryList;
-typedef QHash<QString, TypeEntryList> TypeEntryHash;
-typedef QHash<QString, TypeEntry *> SingleTypeEntryHash;
-typedef QHash<QString, TemplateEntry *> TemplateEntryHash;
+typedef QMap<QString, TemplateEntry *> TemplateEntryMap;
+
+template <class Key, class Value>
+struct QMultiMapConstIteratorRange // A range of iterator for a range-based for loop
+{
+ using ConstIterator = typename QMultiMap<Key, Value>::const_iterator;
+
+ ConstIterator begin() const { return m_begin; }
+ ConstIterator end() const { return m_end; }
+
+ ConstIterator m_begin;
+ ConstIterator m_end;
+};
+
+typedef QMultiMap<QString, TypeEntry *> TypeEntryMultiMap;
+typedef QMultiMapConstIteratorRange<QString, TypeEntry *> TypeEntryMultiMapConstIteratorRange;
+
+typedef QMap<QString, TypeEntry *> TypeEntryMap;
+typedef QMap<QString, TypedefEntry *> TypedefEntryMap;
typedef QVector<const ContainerTypeEntry *> ContainerTypeEntryList;
typedef QVector<const PrimitiveTypeEntry *> PrimitiveTypeEntryList;
diff --git a/sources/shiboken2/ApiExtractor/typeparser.cpp b/sources/shiboken2/ApiExtractor/typeparser.cpp
index 02c85421b..c440fb66d 100644
--- a/sources/shiboken2/ApiExtractor/typeparser.cpp
+++ b/sources/shiboken2/ApiExtractor/typeparser.cpp
@@ -49,13 +49,14 @@ public:
GreaterThanToken,
ConstToken,
+ VolatileToken,
Identifier,
NoToken,
InvalidToken
};
Scanner(const QString &s)
- : m_pos(0), m_length(s.length()), m_chars(s.constData())
+ : m_pos(0), m_length(s.length()), m_tokenStart(-1), m_chars(s.constData())
{
}
@@ -137,13 +138,30 @@ Scanner::Token Scanner::nextToken(QString *errorMessage)
}
}
- if (tok == Identifier && m_pos - m_tokenStart == 5) {
- if (m_chars[m_tokenStart] == QLatin1Char('c')
- && m_chars[m_tokenStart + 1] == QLatin1Char('o')
- && m_chars[m_tokenStart + 2] == QLatin1Char('n')
- && m_chars[m_tokenStart + 3] == QLatin1Char('s')
- && m_chars[m_tokenStart + 4] == QLatin1Char('t'))
- tok = ConstToken;
+ if (tok == Identifier) {
+ switch (m_pos - m_tokenStart) {
+ case 5:
+ if (m_chars[m_tokenStart] == QLatin1Char('c')
+ && m_chars[m_tokenStart + 1] == QLatin1Char('o')
+ && m_chars[m_tokenStart + 2] == QLatin1Char('n')
+ && m_chars[m_tokenStart + 3] == QLatin1Char('s')
+ && m_chars[m_tokenStart + 4] == QLatin1Char('t')) {
+ tok = ConstToken;
+ }
+ break;
+ case 8:
+ if (m_chars[m_tokenStart] == QLatin1Char('v')
+ && m_chars[m_tokenStart + 1] == QLatin1Char('o')
+ && m_chars[m_tokenStart + 2] == QLatin1Char('l')
+ && m_chars[m_tokenStart + 3] == QLatin1Char('a')
+ && m_chars[m_tokenStart + 4] == QLatin1Char('t')
+ && m_chars[m_tokenStart + 5] == QLatin1Char('i')
+ && m_chars[m_tokenStart + 6] == QLatin1Char('l')
+ && m_chars[m_tokenStart + 7] == QLatin1Char('e')) {
+ tok = VolatileToken;
+ }
+ break;
+ }
}
return tok;
@@ -167,6 +185,7 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
bool colon_prefix = false;
bool in_array = false;
QString array;
+ bool seenStar = false;
Scanner::Token tok = scanner.nextToken(errorMessage);
while (tok != Scanner::NoToken) {
@@ -191,7 +210,8 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
switch (tok) {
case Scanner::StarToken:
- ++stack.top()->m_indirections;
+ seenStar = true;
+ stack.top()->addIndirection(Indirection::Pointer);
break;
case Scanner::AmpersandToken:
@@ -212,14 +232,14 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
}
break;
case Scanner::LessThanToken:
- stack.top()->m_arguments << TypeInfo();
- stack.push(&stack.top()->m_arguments.last());
+ stack.top()->m_instantiations << TypeInfo();
+ stack.push(&stack.top()->m_instantiations.last());
break;
case Scanner::CommaToken:
stack.pop();
- stack.top()->m_arguments << TypeInfo();
- stack.push(&stack.top()->m_arguments.last());
+ stack.top()->m_instantiations << TypeInfo();
+ stack.push(&stack.top()->m_instantiations.last());
break;
case Scanner::GreaterThanToken:
@@ -231,7 +251,16 @@ TypeInfo TypeParser::parse(const QString &str, QString *errorMessage)
break;
case Scanner::ConstToken:
- stack.top()->m_constant = true;
+ if (seenStar) { // "int *const": Last indirection is const.
+ Q_ASSERT(!stack.top()->m_indirections.isEmpty());
+ *stack.top()->m_indirections.rbegin() = Indirection::ConstPointer;
+ } else {
+ stack.top()->m_constant = true;
+ }
+ break;
+
+ case Scanner::VolatileToken:
+ stack.top()->m_volatile = true;
break;
case Scanner::OpenParenToken: // function pointers not supported
diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp
index 8e0e4437a..2c7f5eeaa 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.cpp
+++ b/sources/shiboken2/ApiExtractor/typesystem.cpp
@@ -35,29 +35,68 @@
#include <QtCore/QFileInfo>
#include <QtCore/QRegularExpression>
#include <QtCore/QSet>
+#include <QtCore/QStringView>
+#include <QtCore/QStringAlgorithms>
#include <QtCore/QXmlStreamAttributes>
#include <QtCore/QXmlStreamReader>
+#include <algorithm>
+
+const char *TARGET_CONVERSION_RULE_FLAG = "0";
+const char *NATIVE_CONVERSION_RULE_FLAG = "1";
+
static QString strings_Object = QLatin1String("Object");
static QString strings_String = QLatin1String("String");
static QString strings_char = QLatin1String("char");
static QString strings_jchar = QLatin1String("jchar");
static QString strings_jobject = QLatin1String("jobject");
+static inline QString allowThreadAttribute() { return QStringLiteral("allow-thread"); }
static inline QString colonColon() { return QStringLiteral("::"); }
+static inline QString copyableAttribute() { return QStringLiteral("copyable"); }
+static inline QString accessAttribute() { return QStringLiteral("access"); }
+static inline QString actionAttribute() { return QStringLiteral("action"); }
static inline QString quoteAfterLineAttribute() { return QStringLiteral("quote-after-line"); }
static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote-before-line"); }
static inline QString textAttribute() { return QStringLiteral("text"); }
static inline QString nameAttribute() { return QStringLiteral("name"); }
static inline QString sinceAttribute() { return QStringLiteral("since"); }
+static inline QString defaultSuperclassAttribute() { return QStringLiteral("default-superclass"); }
+static inline QString deleteInMainThreadAttribute() { return QStringLiteral("delete-in-main-thread"); }
+static inline QString deprecatedAttribute() { return QStringLiteral("deprecated"); }
+static inline QString exceptionHandlingAttribute() { return QStringLiteral("exception-handling"); }
+static inline QString extensibleAttribute() { return QStringLiteral("extensible"); }
static inline QString flagsAttribute() { return QStringLiteral("flags"); }
+static inline QString forceAbstractAttribute() { return QStringLiteral("force-abstract"); }
+static inline QString forceIntegerAttribute() { return QStringLiteral("force-integer"); }
+static inline QString formatAttribute() { return QStringLiteral("format"); }
static inline QString classAttribute() { return QStringLiteral("class"); }
-static inline QString functionNameAttribute() { return QStringLiteral("function-name"); }
-static inline QString fieldNameAttribute() { return QStringLiteral("field-name"); }
-static inline QString enumNameAttribute() { return QStringLiteral("enum-name"); }
-static inline QString argumentTypeAttribute() { return QStringLiteral("argument-type"); }
-static inline QString returnTypeAttribute() { return QStringLiteral("return-type"); }
+static inline QString generateAttribute() { return QStringLiteral("generate"); }
+static inline QString genericClassAttribute() { return QStringLiteral("generic-class"); }
+static inline QString indexAttribute() { return QStringLiteral("index"); }
+static inline QString invalidateAfterUseAttribute() { return QStringLiteral("invalidate-after-use"); }
+static inline QString locationAttribute() { return QStringLiteral("location"); }
+static inline QString modifiedTypeAttribute() { return QStringLiteral("modified-type"); }
+static inline QString modifierAttribute() { return QStringLiteral("modifier"); }
+static inline QString ownershipAttribute() { return QStringLiteral("owner"); }
+static inline QString packageAttribute() { return QStringLiteral("package"); }
+static inline QString positionAttribute() { return QStringLiteral("position"); }
+static inline QString preferredConversionAttribute() { return QStringLiteral("preferred-conversion"); }
+static inline QString preferredTargetLangTypeAttribute() { return QStringLiteral("preferred-target-lang-type"); }
+static inline QString removeAttribute() { return QStringLiteral("remove"); }
+static inline QString renameAttribute() { return QStringLiteral("rename"); }
+static inline QString readAttribute() { return QStringLiteral("read"); }
+static inline QString writeAttribute() { return QStringLiteral("write"); }
+static inline QString replaceAttribute() { return QStringLiteral("replace"); }
+static inline QString toAttribute() { return QStringLiteral("to"); }
+static inline QString signatureAttribute() { return QStringLiteral("signature"); }
+static inline QString snippetAttribute() { return QStringLiteral("snippet"); }
+static inline QString staticAttribute() { return QStringLiteral("static"); }
+static inline QString threadAttribute() { return QStringLiteral("thread"); }
+static inline QString sourceAttribute() { return QStringLiteral("source"); }
+static inline QString streamAttribute() { return QStringLiteral("stream"); }
static inline QString xPathAttribute() { return QStringLiteral("xpath"); }
+static inline QString virtualSlotAttribute() { return QStringLiteral("virtual-slot"); }
static inline QString enumIdentifiedByValueAttribute() { return QStringLiteral("identified-by-value"); }
static inline QString noAttributeValue() { return QStringLiteral("no"); }
@@ -90,105 +129,317 @@ static bool setRejectionRegularExpression(const QString &patternIn,
return true;
}
-static bool addRejection(TypeDatabase *database, const QHash<QString, QString> &attributes,
- QString *errorMessage)
+// Extract a snippet from a file within annotation "// @snippet label".
+static QString extractSnippet(const QString &code, const QString &snippetLabel)
{
- typedef QPair<QString, TypeRejection::MatchType> AttributeMatchTypePair;
+ if (snippetLabel.isEmpty())
+ return code;
+ const QString pattern = QStringLiteral(R"(^\s*//\s*@snippet\s+)")
+ + QRegularExpression::escape(snippetLabel)
+ + QStringLiteral(R"(\s*$)");
+ const QRegularExpression snippetRe(pattern);
+ Q_ASSERT(snippetRe.isValid());
- TypeRejection rejection;
+ bool useLine = false;
+ QString result;
+ const auto lines = code.splitRef(QLatin1Char('\n'));
+ for (const QStringRef &line : lines) {
+ if (snippetRe.match(line).hasMatch()) {
+ useLine = !useLine;
+ if (!useLine)
+ break; // End of snippet reached
+ } else if (useLine)
+ result += line.toString() + QLatin1Char('\n');
+ }
+ return result;
+}
- const QString className = attributes.value(classAttribute());
- if (!setRejectionRegularExpression(className, &rejection.className, errorMessage))
- return false;
+template <class EnumType, Qt::CaseSensitivity cs = Qt::CaseInsensitive>
+struct EnumLookup
+{
+ QStringView name;
+ EnumType value;
+};
+
+template <class EnumType, Qt::CaseSensitivity cs>
+bool operator==(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2)
+{
+ return e1.name.compare(e2.name, cs) == 0;
+}
+
+template <class EnumType, Qt::CaseSensitivity cs>
+bool operator<(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2)
+{
+ return e1.name.compare(e2.name, cs) < 0;
+}
+
+// Helper macros to define lookup functions that take a QStringView needle
+// and an optional default return value.
+#define ENUM_LOOKUP_BEGIN(EnumType, caseSensitivity, functionName, defaultReturnValue) \
+static EnumType functionName(QStringView needle, EnumType defaultValue = defaultReturnValue) \
+{ \
+ typedef EnumLookup<EnumType, caseSensitivity> HaystackEntry; \
+ static const HaystackEntry haystack[] =
+
+#define ENUM_LOOKUP_LINEAR_SEARCH() \
+ const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \
+ const auto it = std::find(haystack, end, HaystackEntry{needle, defaultValue}); \
+ return it != end ? it->value : defaultValue; \
+}
- static const AttributeMatchTypePair attributeMatchTypeMapping[] =
- {{functionNameAttribute(), TypeRejection::Function},
- {fieldNameAttribute(), TypeRejection::Field},
- {enumNameAttribute(), TypeRejection::Enum},
- {argumentTypeAttribute(), TypeRejection::ArgumentType},
- {returnTypeAttribute(), TypeRejection::ReturnType}
+#define ENUM_LOOKUP_BINARY_SEARCH() \
+ const auto end = haystack + sizeof(haystack) / sizeof(haystack[0]); \
+ const HaystackEntry needleEntry{needle, defaultValue}; \
+ const auto lb = std::lower_bound(haystack, end, needleEntry); \
+ return lb != end && *lb == needleEntry ? lb->value : defaultValue; \
+}
+
+ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive,
+ allowThreadFromAttribute, TypeSystem::AllowThread::Unspecified)
+ {
+ {QStringViewLiteral("yes"), TypeSystem::AllowThread::Allow},
+ {QStringViewLiteral("true"), TypeSystem::AllowThread::Allow},
+ {QStringViewLiteral("auto"), TypeSystem::AllowThread::Auto},
+ {QStringViewLiteral("no"), TypeSystem::AllowThread::Disallow},
+ {QStringViewLiteral("false"), TypeSystem::AllowThread::Disallow},
};
+ENUM_LOOKUP_LINEAR_SEARCH()
- // Search for non-empty attribute (function, field, enum)
- const auto aend = attributes.cend();
- for (const AttributeMatchTypePair &mapping : attributeMatchTypeMapping) {
- const auto it = attributes.constFind(mapping.first);
- if (it != aend && !it.value().isEmpty()) {
- if (!setRejectionRegularExpression(it.value(), &rejection.pattern, errorMessage))
- return false;
- rejection.matchType = mapping.second;
- database->addRejection(rejection);
- return true;
- }
- }
+ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive,
+ languageFromAttribute, TypeSystem::NoLanguage)
+ {
+ {QStringViewLiteral("all"), TypeSystem::All}, // sorted!
+ {QStringViewLiteral("constructors"), TypeSystem::Constructors},
+ {QStringViewLiteral("destructor-function"), TypeSystem::DestructorFunction},
+ {QStringViewLiteral("interface"), TypeSystem::Interface},
+ {QStringViewLiteral("library-initializer"), TypeSystem::PackageInitializer},
+ {QStringViewLiteral("native"), TypeSystem::NativeCode}, // em algum lugar do cpp
+ {QStringViewLiteral("shell"), TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe
+ {QStringViewLiteral("shell-declaration"), TypeSystem::ShellDeclaration},
+ {QStringViewLiteral("target"), TypeSystem::TargetLangCode} // em algum lugar do cpp
+ };
+ENUM_LOOKUP_BINARY_SEARCH()
- // Special case: When all fields except class are empty, completely exclude class
- if (className == QLatin1String("*")) {
- *errorMessage = QLatin1String("bad reject entry, neither 'class', 'function-name'"
- " nor 'field' specified");
- return false;
+ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive,
+ ownershipFromFromAttribute, TypeSystem::InvalidOwnership)
+ {
+ {QStringViewLiteral("target"), TypeSystem::TargetLangOwnership},
+ {QStringViewLiteral("c++"), TypeSystem::CppOwnership},
+ {QStringViewLiteral("default"), TypeSystem::DefaultOwnership}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive,
+ addedFunctionAccessFromAttribute, AddedFunction::InvalidAccess)
+ {
+ {QStringViewLiteral("public"), AddedFunction::Public},
+ {QStringViewLiteral("protected"), AddedFunction::Protected},
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(Modification::Modifiers, Qt::CaseSensitive,
+ modifierFromAttribute, Modification::InvalidModifier)
+ {
+ {QStringViewLiteral("private"), Modification::Private},
+ {QStringViewLiteral("public"), Modification::Public},
+ {QStringViewLiteral("protected"), Modification::Protected},
+ {QStringViewLiteral("friendly"), Modification::Friendly},
+ {QStringViewLiteral("rename"), Modification::Rename},
+ {QStringViewLiteral("final"), Modification::Final},
+ {QStringViewLiteral("non-final"), Modification::NonFinal}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive,
+ referenceCountFromAttribute, ReferenceCount::Invalid)
+ {
+ {QStringViewLiteral("add"), ReferenceCount::Add},
+ {QStringViewLiteral("add-all"), ReferenceCount::AddAll},
+ {QStringViewLiteral("remove"), ReferenceCount::Remove},
+ {QStringViewLiteral("set"), ReferenceCount::Set},
+ {QStringViewLiteral("ignore"), ReferenceCount::Ignore}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive,
+ argumentOwnerActionFromAttribute, ArgumentOwner::Invalid)
+ {
+ {QStringViewLiteral("add"), ArgumentOwner::Add},
+ {QStringViewLiteral("remove"), ArgumentOwner::Remove}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::CodeSnipPosition, Qt::CaseInsensitive,
+ codeSnipPositionFromAttribute, TypeSystem::CodeSnipPositionInvalid)
+ {
+ {QStringViewLiteral("beginning"), TypeSystem::CodeSnipPositionBeginning},
+ {QStringViewLiteral("end"), TypeSystem::CodeSnipPositionEnd},
+ {QStringViewLiteral("declaration"), TypeSystem::CodeSnipPositionDeclaration},
+ {QStringViewLiteral("prototype-initialization"), TypeSystem::CodeSnipPositionPrototypeInitialization},
+ {QStringViewLiteral("constructor-initialization"), TypeSystem::CodeSnipPositionConstructorInitialization},
+ {QStringViewLiteral("constructor"), TypeSystem::CodeSnipPositionConstructor}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive,
+ locationFromAttribute, Include::InvalidInclude)
+ {
+ {QStringViewLiteral("global"), Include::IncludePath},
+ {QStringViewLiteral("local"), Include::LocalPath},
+ {QStringViewLiteral("target"), Include::TargetLangImport}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive,
+ docModificationFromAttribute, TypeSystem::DocModificationInvalid)
+ {
+ {QStringViewLiteral("append"), TypeSystem::DocModificationAppend},
+ {QStringViewLiteral("prepend"), TypeSystem::DocModificationPrepend},
+ {QStringViewLiteral("replace"), TypeSystem::DocModificationReplace}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(ContainerTypeEntry::Type, Qt::CaseSensitive,
+ containerTypeFromAttribute, ContainerTypeEntry::NoContainer)
+ {
+ {QStringViewLiteral("list"), ContainerTypeEntry::ListContainer},
+ {QStringViewLiteral("string-list"), ContainerTypeEntry::StringListContainer},
+ {QStringViewLiteral("linked-list"), ContainerTypeEntry::LinkedListContainer},
+ {QStringViewLiteral("vector"), ContainerTypeEntry::VectorContainer},
+ {QStringViewLiteral("stack"), ContainerTypeEntry::StackContainer},
+ {QStringViewLiteral("queue"), ContainerTypeEntry::QueueContainer},
+ {QStringViewLiteral("set"), ContainerTypeEntry::SetContainer},
+ {QStringViewLiteral("map"), ContainerTypeEntry::MapContainer},
+ {QStringViewLiteral("multi-map"), ContainerTypeEntry::MultiMapContainer},
+ {QStringViewLiteral("hash"), ContainerTypeEntry::HashContainer},
+ {QStringViewLiteral("multi-hash"), ContainerTypeEntry::MultiHashContainer},
+ {QStringViewLiteral("pair"), ContainerTypeEntry::PairContainer}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive,
+ typeRejectionFromAttribute, TypeRejection::Invalid)
+ {
+ {QStringViewLiteral("class"), TypeRejection::ExcludeClass},
+ {QStringViewLiteral("function-name"), TypeRejection::Function},
+ {QStringViewLiteral("field-name"), TypeRejection::Field},
+ {QStringViewLiteral("enum-name"), TypeRejection::Enum },
+ {QStringViewLiteral("argument-type"), TypeRejection::ArgumentType},
+ {QStringViewLiteral("return-type"), TypeRejection::ReturnType}
+ };
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive,
+ exceptionHandlingFromAttribute, TypeSystem::ExceptionHandling::Unspecified)
+{
+ {QStringViewLiteral("no"), TypeSystem::ExceptionHandling::Off},
+ {QStringViewLiteral("false"), TypeSystem::ExceptionHandling::Off},
+ {QStringViewLiteral("auto-off"), TypeSystem::ExceptionHandling::AutoDefaultToOff},
+ {QStringViewLiteral("auto-on"), TypeSystem::ExceptionHandling::AutoDefaultToOn},
+ {QStringViewLiteral("yes"), TypeSystem::ExceptionHandling::On},
+ {QStringViewLiteral("true"), TypeSystem::ExceptionHandling::On},
+};
+ENUM_LOOKUP_LINEAR_SEARCH()
+
+ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive,
+ elementFromTag, StackElement::None)
+ {
+ {QStringViewLiteral("access"), StackElement::Access}, // sorted!
+ {QStringViewLiteral("add-conversion"), StackElement::AddConversion},
+ {QStringViewLiteral("add-function"), StackElement::AddFunction},
+ {QStringViewLiteral("argument-map"), StackElement::ArgumentMap},
+ {QStringViewLiteral("array"), StackElement::Array},
+ {QStringViewLiteral("container-type"), StackElement::ContainerTypeEntry},
+ {QStringViewLiteral("conversion-rule"), StackElement::ConversionRule},
+ {QStringViewLiteral("custom-constructor"), StackElement::CustomMetaConstructor},
+ {QStringViewLiteral("custom-destructor"), StackElement::CustomMetaDestructor},
+ {QStringViewLiteral("custom-type"), StackElement::CustomTypeEntry},
+ {QStringViewLiteral("define-ownership"), StackElement::DefineOwnership},
+ {QStringViewLiteral("enum-type"), StackElement::EnumTypeEntry},
+ {QStringViewLiteral("extra-includes"), StackElement::ExtraIncludes},
+ {QStringViewLiteral("function"), StackElement::FunctionTypeEntry},
+ {QStringViewLiteral("include"), StackElement::Include},
+ {QStringViewLiteral("inject-code"), StackElement::InjectCode},
+ {QStringViewLiteral("inject-documentation"), StackElement::InjectDocumentation},
+ {QStringViewLiteral("insert-template"), StackElement::TemplateInstanceEnum},
+ {QStringViewLiteral("interface-type"), StackElement::InterfaceTypeEntry},
+ {QStringViewLiteral("load-typesystem"), StackElement::LoadTypesystem},
+ {QStringViewLiteral("modify-argument"), StackElement::ModifyArgument},
+ {QStringViewLiteral("modify-documentation"), StackElement::ModifyDocumentation},
+ {QStringViewLiteral("modify-field"), StackElement::ModifyField},
+ {QStringViewLiteral("modify-function"), StackElement::ModifyFunction},
+ {QStringViewLiteral("namespace-type"), StackElement::NamespaceTypeEntry},
+ {QStringViewLiteral("native-to-target"), StackElement::NativeToTarget},
+ {QStringViewLiteral("no-null-pointer"), StackElement::NoNullPointers},
+ {QStringViewLiteral("object-type"), StackElement::ObjectTypeEntry},
+ {QStringViewLiteral("parent"), StackElement::ParentOwner},
+ {QStringViewLiteral("primitive-type"), StackElement::PrimitiveTypeEntry},
+ {QStringViewLiteral("reference-count"), StackElement::ReferenceCount},
+ {QStringViewLiteral("reject-enum-value"), StackElement::RejectEnumValue},
+ {QStringViewLiteral("rejection"), StackElement::Rejection},
+ {QStringViewLiteral("remove"), StackElement::Removal},
+ {QStringViewLiteral("remove-argument"), StackElement::RemoveArgument},
+ {QStringViewLiteral("remove-default-expression"), StackElement::RemoveDefaultExpression},
+ {QStringViewLiteral("rename"), StackElement::Rename},
+ {QStringViewLiteral("replace"), StackElement::Replace},
+ {QStringViewLiteral("replace-default-expression"), StackElement::ReplaceDefaultExpression},
+ {QStringViewLiteral("replace-type"), StackElement::ReplaceType},
+ {QStringViewLiteral("smart-pointer-type"), StackElement::SmartPointerTypeEntry},
+ {QStringViewLiteral("suppress-warning"), StackElement::SuppressedWarning},
+ {QStringViewLiteral("target-to-native"), StackElement::TargetToNative},
+ {QStringViewLiteral("template"), StackElement::Template},
+ {QStringViewLiteral("typedef-type"), StackElement::TypedefTypeEntry},
+ {QStringViewLiteral("typesystem"), StackElement::Root},
+ {QStringViewLiteral("value-type"), StackElement::ValueTypeEntry},
+ };
+ENUM_LOOKUP_BINARY_SEARCH()
+
+static int indexOfAttribute(const QXmlStreamAttributes &atts,
+ QStringView name)
+{
+ for (int i = 0, size = atts.size(); i < size; ++i) {
+ if (atts.at(i).qualifiedName() == name)
+ return i;
}
- rejection.matchType = TypeRejection::ExcludeClass;
- database->addRejection(rejection);
- return true;
+ return -1;
+}
+
+static QString msgMissingAttribute(const QString &a)
+{
+ return QLatin1String("Required attribute '") + a
+ + QLatin1String("' missing.");
+}
+
+QTextStream &operator<<(QTextStream &str, const QXmlStreamAttribute &attribute)
+{
+ str << attribute.qualifiedName() << "=\"" << attribute.value() << '"';
+ return str;
+}
+
+static QString msgInvalidAttributeValue(const QXmlStreamAttribute &attribute)
+{
+ QString result;
+ QTextStream(&result) << "Invalid attribute value:" << attribute;
+ return result;
}
+static QString msgUnusedAttributes(const QStringRef &tag, const QXmlStreamAttributes &attributes)
+{
+ QString result;
+ QTextStream str(&result);
+ str << attributes.size() << " attributes(s) unused on <" << tag << ">: ";
+ for (int i = 0, size = attributes.size(); i < size; ++i) {
+ if (i)
+ str << ", ";
+ str << attributes.at(i);
+ }
+ return result;
+}
-Handler::Handler(TypeDatabase* database, bool generate)
- : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
-{
- m_currentEnum = 0;
- m_current = 0;
- m_currentDroppedEntry = 0;
- m_currentDroppedEntryDepth = 0;
- m_ignoreDepth = 0;
-
- tagNames.insert(QLatin1String("rejection"), StackElement::Rejection);
- tagNames.insert(QLatin1String("custom-type"), StackElement::CustomTypeEntry);
- tagNames.insert(QLatin1String("primitive-type"), StackElement::PrimitiveTypeEntry);
- tagNames.insert(QLatin1String("container-type"), StackElement::ContainerTypeEntry);
- tagNames.insert(QLatin1String("object-type"), StackElement::ObjectTypeEntry);
- tagNames.insert(QLatin1String("value-type"), StackElement::ValueTypeEntry);
- tagNames.insert(QLatin1String("interface-type"), StackElement::InterfaceTypeEntry);
- tagNames.insert(QLatin1String("namespace-type"), StackElement::NamespaceTypeEntry);
- tagNames.insert(QLatin1String("enum-type"), StackElement::EnumTypeEntry);
- tagNames.insert(QLatin1String("smart-pointer-type"), StackElement::SmartPointerTypeEntry);
- tagNames.insert(QLatin1String("function"), StackElement::FunctionTypeEntry);
- tagNames.insert(QLatin1String("extra-includes"), StackElement::ExtraIncludes);
- tagNames.insert(QLatin1String("include"), StackElement::Include);
- tagNames.insert(QLatin1String("inject-code"), StackElement::InjectCode);
- tagNames.insert(QLatin1String("modify-function"), StackElement::ModifyFunction);
- tagNames.insert(QLatin1String("modify-field"), StackElement::ModifyField);
- tagNames.insert(QLatin1String("access"), StackElement::Access);
- tagNames.insert(QLatin1String("remove"), StackElement::Removal);
- tagNames.insert(QLatin1String("rename"), StackElement::Rename);
- tagNames.insert(QLatin1String("typesystem"), StackElement::Root);
- tagNames.insert(QLatin1String("custom-constructor"), StackElement::CustomMetaConstructor);
- tagNames.insert(QLatin1String("custom-destructor"), StackElement::CustomMetaDestructor);
- tagNames.insert(QLatin1String("argument-map"), StackElement::ArgumentMap);
- tagNames.insert(QLatin1String("suppress-warning"), StackElement::SuppressedWarning);
- tagNames.insert(QLatin1String("load-typesystem"), StackElement::LoadTypesystem);
- tagNames.insert(QLatin1String("define-ownership"), StackElement::DefineOwnership);
- tagNames.insert(QLatin1String("replace-default-expression"), StackElement::ReplaceDefaultExpression);
- tagNames.insert(QLatin1String("reject-enum-value"), StackElement::RejectEnumValue);
- tagNames.insert(QLatin1String("replace-type"), StackElement::ReplaceType);
- tagNames.insert(QLatin1String("conversion-rule"), StackElement::ConversionRule);
- tagNames.insert(QLatin1String("native-to-target"), StackElement::NativeToTarget);
- tagNames.insert(QLatin1String("target-to-native"), StackElement::TargetToNative);
- tagNames.insert(QLatin1String("add-conversion"), StackElement::AddConversion);
- tagNames.insert(QLatin1String("modify-argument"), StackElement::ModifyArgument);
- tagNames.insert(QLatin1String("remove-argument"), StackElement::RemoveArgument);
- tagNames.insert(QLatin1String("remove-default-expression"), StackElement::RemoveDefaultExpression);
- tagNames.insert(QLatin1String("template"), StackElement::Template);
- tagNames.insert(QLatin1String("insert-template"), StackElement::TemplateInstanceEnum);
- tagNames.insert(QLatin1String("replace"), StackElement::Replace);
- tagNames.insert(QLatin1String("no-null-pointer"), StackElement::NoNullPointers);
- tagNames.insert(QLatin1String("reference-count"), StackElement::ReferenceCount);
- tagNames.insert(QLatin1String("parent"), StackElement::ParentOwner);
- tagNames.insert(QLatin1String("array"), StackElement::Array);
- tagNames.insert(QLatin1String("inject-documentation"), StackElement::InjectDocumentation);
- tagNames.insert(QLatin1String("modify-documentation"), StackElement::ModifyDocumentation);
- tagNames.insert(QLatin1String("add-function"), StackElement::AddFunction);
+Handler::Handler(TypeDatabase *database, bool generate) :
+ m_database(database),
+ m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
+{
}
static QString readerFileName(const QXmlStreamReader &reader)
@@ -197,22 +448,72 @@ static QString readerFileName(const QXmlStreamReader &reader)
return file != nullptr ? file->fileName() : QString();
}
-static QString msgReaderError(const QXmlStreamReader &reader, const QString &what)
+static QString msgReaderMessage(const QXmlStreamReader &reader,
+ const char *type,
+ const QString &what)
{
QString message;
QTextStream str(&message);
- str << "Error: ";
+ str << type << ": ";
const QString fileName = readerFileName(reader);
- if (!fileName.isEmpty())
- str << "file=" << QDir::toNativeSeparators(fileName) << ", ";
- str << "line=" << reader.lineNumber() << ", column=" << reader.columnNumber()
- << ", message=" << what;
+ if (fileName.isEmpty())
+ str << "<stdin>:";
+ else
+ str << QDir::toNativeSeparators(fileName) << ':';
+ str << reader.lineNumber() << ':' << reader.columnNumber()
+ << ": " << what;
return message;
}
-static QString msgReaderError(const QXmlStreamReader &reader)
+static QString msgReaderWarning(const QXmlStreamReader &reader, const QString &what)
{
- return msgReaderError(reader, reader.errorString());
+ return msgReaderMessage(reader, "Warning", what);
+}
+
+static QString msgReaderError(const QXmlStreamReader &reader, const QString &what)
+{
+ return msgReaderMessage(reader, "Error", what);
+}
+
+static QString msgUnimplementedElementWarning(const QXmlStreamReader &reader,
+ const QStringRef &name)
+{
+ const QString message = QLatin1String("The element \"") +
+ name + QLatin1String("\" is not implemented.");
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static QString msgUnimplementedAttributeWarning(const QXmlStreamReader &reader,
+ const QStringRef &name)
+{
+ const QString message = QLatin1String("The attribute \"") +
+ name + QLatin1String("\" is not implemented.");
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static inline QString msgUnimplementedAttributeWarning(const QXmlStreamReader &reader,
+ const QXmlStreamAttribute &attribute)
+{
+ return msgUnimplementedAttributeWarning(reader, attribute.qualifiedName());
+}
+
+static QString
+ msgUnimplementedAttributeValueWarning(const QXmlStreamReader &reader,
+ QStringView name, QStringView value)
+{
+ QString message;
+ QTextStream(&message) << "The value \"" << value
+ << "\" of the attribute \"" << name << "\" is not implemented.";
+ return msgReaderMessage(reader, "Warning", message);
+}
+
+static inline
+ QString msgUnimplementedAttributeValueWarning(const QXmlStreamReader &reader,
+ const QXmlStreamAttribute &attribute)
+{
+ return msgUnimplementedAttributeValueWarning(reader,
+ attribute.qualifiedName(),
+ attribute.value());
}
static QString msgInvalidVersion(const QStringRef &version, const QString &package = QString())
@@ -226,6 +527,53 @@ static QString msgInvalidVersion(const QStringRef &version, const QString &packa
return result;
}
+static bool addRejection(TypeDatabase *database, QXmlStreamAttributes *attributes,
+ QString *errorMessage)
+{
+ const int classIndex = indexOfAttribute(*attributes, classAttribute());
+ if (classIndex == -1) {
+ *errorMessage = msgMissingAttribute(classAttribute());
+ return false;
+ }
+
+ TypeRejection rejection;
+ const QString className = attributes->takeAt(classIndex).value().toString();
+ if (!setRejectionRegularExpression(className, &rejection.className, errorMessage))
+ return false;
+
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ const TypeRejection::MatchType type = typeRejectionFromAttribute(name);
+ switch (type) {
+ case TypeRejection::Function:
+ case TypeRejection::Field:
+ case TypeRejection::Enum:
+ case TypeRejection::ArgumentType:
+ case TypeRejection::ReturnType: {
+ const QString pattern = attributes->takeAt(i).value().toString();
+ if (!setRejectionRegularExpression(pattern, &rejection.pattern, errorMessage))
+ return false;
+ rejection.matchType = type;
+ database->addRejection(rejection);
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Special case: When all fields except class are empty, completely exclude class
+ if (className == QLatin1String("*")) {
+ *errorMessage = QLatin1String("bad reject entry, neither 'class', 'function-name'"
+ " nor 'field' specified");
+ return false;
+ }
+ rejection.matchType = TypeRejection::ExcludeClass;
+ database->addRejection(rejection);
+ return true;
+}
+
bool Handler::parse(QXmlStreamReader &reader)
{
m_error.clear();
@@ -238,10 +586,10 @@ bool Handler::parse(QXmlStreamReader &reader)
switch (reader.readNext()) {
case QXmlStreamReader::NoToken:
case QXmlStreamReader::Invalid:
- qCWarning(lcShiboken).noquote().nospace() << msgReaderError(reader);
+ m_error = msgReaderError(reader, reader.errorString());
return false;
case QXmlStreamReader::StartElement:
- if (!startElement(reader.name(), reader.attributes())) {
+ if (!startElement(reader)) {
m_error = msgReaderError(reader, m_error);
return false;
}
@@ -271,22 +619,6 @@ bool Handler::parse(QXmlStreamReader &reader)
return true;
}
-void Handler::fetchAttributeValues(const QString &name, const QXmlStreamAttributes &atts,
- QHash<QString, QString> *acceptedAttributes)
-{
- Q_ASSERT(acceptedAttributes);
-
- for (int i = 0; i < atts.length(); ++i) {
- const QString key = atts.at(i).name().toString().toLower();
- if (!acceptedAttributes->contains(key)) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("Unknown attribute for '%1': '%2'").arg(name, key);
- } else {
- acceptedAttributes->insert(key, atts.at(i).value().toString());
- }
- }
-}
-
bool Handler::endElement(const QStringRef &localName)
{
if (m_ignoreDepth) {
@@ -416,14 +748,18 @@ bool Handler::endElement(const QStringRef &localName)
break;
}
- if (m_current->type == StackElement::Root
- || m_current->type == StackElement::NamespaceTypeEntry
- || m_current->type == StackElement::InterfaceTypeEntry
- || m_current->type == StackElement::ObjectTypeEntry
- || m_current->type == StackElement::ValueTypeEntry
- || m_current->type == StackElement::PrimitiveTypeEntry) {
- StackElementContext* context = m_contextStack.pop();
- delete context;
+ switch (m_current->type) {
+ case StackElement::Root:
+ case StackElement::NamespaceTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::PrimitiveTypeEntry:
+ case StackElement::TypedefTypeEntry:
+ delete m_contextStack.pop();
+ break;
+ default:
+ break;
}
StackElement *child = m_current;
@@ -551,8 +887,9 @@ bool Handler::importFileElement(const QXmlStreamAttributes &atts)
return true;
}
-static bool convertBoolean(const QString &value, const QString &attributeName, bool defaultValue)
+static bool convertBoolean(QStringView value, const QString &attributeName, bool defaultValue)
{
+#ifdef QTBUG_69389_FIXED
if (value.compare(trueAttributeValue(), Qt::CaseInsensitive) == 0
|| value.compare(yesAttributeValue(), Qt::CaseInsensitive) == 0) {
return true;
@@ -561,28 +898,47 @@ static bool convertBoolean(const QString &value, const QString &attributeName, b
|| value.compare(noAttributeValue(), Qt::CaseInsensitive) == 0) {
return false;
}
+#else
+ if (QtPrivate::compareStrings(value, trueAttributeValue(), Qt::CaseInsensitive) == 0
+ || QtPrivate::compareStrings(value, yesAttributeValue(), Qt::CaseInsensitive) == 0) {
+ return true;
+ }
+ if (QtPrivate::compareStrings(value, falseAttributeValue(), Qt::CaseInsensitive) == 0
+ || QtPrivate::compareStrings(value, noAttributeValue(), Qt::CaseInsensitive) == 0) {
+ return false;
+ }
+#endif
const QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
- .arg(value, attributeName,
+ .arg(value)
+ .arg(attributeName,
defaultValue ? yesAttributeValue() : noAttributeValue());
qCWarning(lcShiboken).noquote().nospace() << warn;
return defaultValue;
}
-static bool convertRemovalAttribute(const QString& removalAttribute, Modification& mod, QString& errorMsg)
+static bool convertRemovalAttribute(QStringView remove, Modification& mod, QString& errorMsg)
{
- QString remove = removalAttribute.toLower();
- if (!remove.isEmpty()) {
- if (remove == QLatin1String("all")) {
- mod.removal = TypeSystem::All;
- } else if (remove == QLatin1String("target")) {
- mod.removal = TypeSystem::TargetLangAndNativeCode;
- } else {
- errorMsg = QString::fromLatin1("Bad removal type '%1'").arg(remove);
- return false;
- }
+ if (remove.isEmpty())
+ return true;
+#ifdef QTBUG_69389_FIXED
+ if (remove.compare(QStringViewLiteral("all"), Qt::CaseInsensitive) == 0) {
+#else
+ if (QtPrivate::compareStrings(remove, QStringViewLiteral("all"), Qt::CaseInsensitive) == 0) {
+#endif
+ mod.removal = TypeSystem::All;
+ return true;
}
- return true;
+#ifdef QTBUG_69389_FIXED
+ if (remove.compare(QStringViewLiteral("target"), Qt::CaseInsensitive) == 0) {
+#else
+ if (QtPrivate::compareStrings(remove, QStringViewLiteral("target"), Qt::CaseInsensitive) == 0) {
+#endif
+ mod.removal = TypeSystem::TargetLangAndNativeCode;
+ return true;
+ }
+ errorMsg = QString::fromLatin1("Bad removal type '%1'").arg(remove);
+ return false;
}
static void getNamePrefixRecursive(StackElement* element, QStringList& names)
@@ -615,98 +971,1439 @@ static QString checkSignatureError(const QString& signature, const QString& tag)
return QString();
}
-void Handler::addFlags(const QString &name, QString flagName,
- const QHash<QString, QString> &attributes,
- const QVersionNumber &since)
+void Handler::applyCommonAttributes(TypeEntry *type, QXmlStreamAttributes *attributes) const
+{
+ type->setCodeGeneration(m_generate);
+ const int revisionIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("revision"));
+ if (revisionIndex != -1)
+ type->setRevision(attributes->takeAt(revisionIndex).value().toInt());
+}
+
+FlagsTypeEntry *
+ Handler::parseFlagsEntry(const QXmlStreamReader &,
+ EnumTypeEntry *enumEntry,
+ const QString &name, QString flagName,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+
{
FlagsTypeEntry *ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + name + QLatin1Char('>'), since);
- ftype->setOriginator(m_currentEnum);
+ ftype->setOriginator(enumEntry);
+ ftype->setTargetLangPackage(enumEntry->targetLangPackage());
// Try to get the guess the qualified flag name
const int lastSepPos = name.lastIndexOf(colonColon());
if (lastSepPos >= 0 && !flagName.contains(colonColon()))
flagName.prepend(name.left(lastSepPos + 2));
ftype->setOriginalName(flagName);
- ftype->setCodeGeneration(m_generate);
+ applyCommonAttributes(ftype, attributes);
QString n = ftype->originalName();
QStringList lst = n.split(colonColon());
- if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != m_currentEnum->targetLangQualifier()) {
+ const QString &targetLangQualifier = enumEntry->targetLangQualifier();
+ if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != targetLangQualifier) {
qCWarning(lcShiboken).noquote().nospace()
<< QStringLiteral("enum %1 and flags %2 differ in qualifiers")
- .arg(m_currentEnum->targetLangQualifier(), lst.constFirst());
+ .arg(targetLangQualifier, lst.constFirst());
}
ftype->setFlagsName(lst.constLast());
- m_currentEnum->setFlags(ftype);
+ enumEntry->setFlags(ftype);
m_database->addFlagsType(ftype);
m_database->addType(ftype);
- QString revision = attributes.value(QLatin1String("flags-revision"));
- if (revision.isEmpty())
- revision = attributes.value(QLatin1String("revision"));
- setTypeRevision(ftype, revision.toInt());
-}
+ const int revisionIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("flags-revision"));
+ ftype->setRevision(revisionIndex != -1
+ ? attributes->takeAt(revisionIndex).value().toInt()
+ : enumEntry->revision());
+ return ftype;
+}
+
+SmartPointerTypeEntry *
+ Handler::parseSmartPointerEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ QString smartPointerType;
+ QString getter;
+ QString refCountMethodName;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("type")) {
+ smartPointerType = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("getter")) {
+ getter = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("ref-count-method")) {
+ refCountMethodName = attributes->takeAt(i).value().toString();
+ }
+ }
-bool Handler::handleSmartPointerEntry(StackElement *element,
- QHash<QString, QString> &attributes,
- const QString &name,
- const QVersionNumber &since)
-{
- QString smartPointerType = attributes[QLatin1String("type")];
if (smartPointerType.isEmpty()) {
m_error = QLatin1String("No type specified for the smart pointer. Currently supported types: 'shared',");
- return false;
+ return nullptr;
}
if (smartPointerType != QLatin1String("shared")) {
m_error = QLatin1String("Currently only the 'shared' type is supported.");
- return false;
+ return nullptr;
}
- QString getter = attributes[QLatin1String("getter")];
if (getter.isEmpty()) {
m_error = QLatin1String("No function getter name specified for getting the raw pointer held by the smart pointer.");
- return false;
+ return nullptr;
}
- QString refCountMethodName = attributes[QLatin1String("ref-count-method")];
QString signature = getter + QLatin1String("()");
-
signature = TypeDatabase::normalizedSignature(signature);
if (signature.isEmpty()) {
m_error = QLatin1String("No signature for the smart pointer getter found.");
- return false;
+ return nullptr;
}
QString errorString = checkSignatureError(signature,
QLatin1String("smart-pointer-type"));
if (!errorString.isEmpty()) {
m_error = errorString;
- return false;
+ return nullptr;
+ }
+
+ SmartPointerTypeEntry *type =
+ new SmartPointerTypeEntry(name, getter, smartPointerType, refCountMethodName, since);
+ applyCommonAttributes(type, attributes);
+ return type;
+}
+
+PrimitiveTypeEntry *
+ Handler::parsePrimitiveTypeEntry(const QXmlStreamReader &reader,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ PrimitiveTypeEntry *type = new PrimitiveTypeEntry(name, since);
+ applyCommonAttributes(type, attributes);
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("target-lang-name")) {
+ type->setTargetLangName(attributes->takeAt(i).value().toString());
+ } else if (name == QLatin1String("target-lang-api-name")) {
+ type->setTargetLangApiName(attributes->takeAt(i).value().toString());
+ } else if (name == preferredConversionAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == preferredTargetLangTypeAttribute()) {
+ const bool v = convertBoolean(attributes->takeAt(i).value(),
+ preferredTargetLangTypeAttribute(), true);
+ type->setPreferredTargetLangType(v);
+ } else if (name == QLatin1String("default-constructor")) {
+ type->setDefaultConstructor(attributes->takeAt(i).value().toString());
+ }
}
- SmartPointerTypeEntry *type = new SmartPointerTypeEntry(name,
- getter,
- smartPointerType,
- refCountMethodName,
- since);
+ if (type->targetLangName().isEmpty())
+ type->setTargetLangName(type->name());
+ if (type->targetLangApiName().isEmpty())
+ type->setTargetLangApiName(type->name());
type->setTargetLangPackage(m_defaultPackage);
- type->setCodeGeneration(m_generate);
- element->entry = type;
+ return type;
+}
+
+ContainerTypeEntry *
+ Handler::parseContainerTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ const int typeIndex = indexOfAttribute(*attributes, QStringViewLiteral("type"));
+ if (typeIndex == -1) {
+ m_error = QLatin1String("no 'type' attribute specified");
+ return nullptr;
+ }
+ const QStringRef typeName = attributes->takeAt(typeIndex).value();
+ ContainerTypeEntry::Type containerType = containerTypeFromAttribute(typeName);
+ if (containerType == ContainerTypeEntry::NoContainer) {
+ m_error = QLatin1String("there is no container of type ") + typeName.toString();
+ return nullptr;
+ }
+ ContainerTypeEntry *type = new ContainerTypeEntry(name, containerType, since);
+ applyCommonAttributes(type, attributes);
+ return type;
+}
+
+EnumTypeEntry *
+ Handler::parseEnumTypeEntry(const QXmlStreamReader &reader,
+ const QString &fullName, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ QString scope;
+ QString name = fullName;
+ const int sep = fullName.lastIndexOf(colonColon());
+ if (sep != -1) {
+ scope = fullName.left(sep);
+ name = fullName.right(fullName.size() - sep - 2);
+ }
+ EnumTypeEntry *entry = new EnumTypeEntry(scope, name, since);
+ applyCommonAttributes(entry, attributes);
+ entry->setTargetLangPackage(m_defaultPackage);
+
+ QString flagNames;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("upper-bound")) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == QLatin1String("lower-bound")) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == forceIntegerAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == extensibleAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == flagsAttribute()) {
+ flagNames = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ // put in the flags parallel...
+ if (!flagNames.isEmpty()) {
+ const QStringList &flagNameList = flagNames.split(QLatin1Char(','));
+ for (const QString &flagName : flagNameList)
+ parseFlagsEntry(reader, entry, fullName, flagName.trimmed(), since, attributes);
+ }
+ return entry;
+}
+
+ObjectTypeEntry *
+ Handler::parseInterfaceTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ ObjectTypeEntry *otype = new ObjectTypeEntry(name, since);
+ applyCommonAttributes(otype, attributes);
+ QString targetLangName = name;
+ bool generate = true;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("target-lang-name")) {
+ targetLangName = attributes->takeAt(i).value().toString();
+ } else if (name == generateAttribute()) {
+ generate = convertBoolean(attributes->takeAt(i).value(),
+ generateAttribute(), true);
+ }
+ }
+
+ InterfaceTypeEntry *itype =
+ new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName), since);
+
+ if (generate)
+ itype->setCodeGeneration(m_generate);
+ else
+ itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
+
+ otype->setDesignatedInterface(itype);
+ itype->setOrigin(otype);
+ return otype;
+}
+
+ValueTypeEntry *
+ Handler::parseValueTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ ValueTypeEntry *typeEntry = new ValueTypeEntry(name, since);
+ applyCommonAttributes(typeEntry, attributes);
+ const int defaultCtIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("default-constructor"));
+ if (defaultCtIndex != -1)
+ typeEntry->setDefaultConstructor(attributes->takeAt(defaultCtIndex).value().toString());
+ return typeEntry;
+}
+
+FunctionTypeEntry *
+ Handler::parseFunctionTypeEntry(const QXmlStreamReader &,
+ const QString &name, const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ const int signatureIndex = indexOfAttribute(*attributes, signatureAttribute());
+ if (signatureIndex == -1) {
+ m_error = msgMissingAttribute(signatureAttribute());
+ return nullptr;
+ }
+ const QString signature =
+ TypeDatabase::normalizedSignature(attributes->takeAt(signatureIndex).value().toString());
+
+ TypeEntry *existingType = m_database->findType(name);
+
+ if (!existingType) {
+ FunctionTypeEntry *result = new FunctionTypeEntry(name, signature, since);
+ applyCommonAttributes(result, attributes);
+ return result;
+ }
+
+ if (existingType->type() != TypeEntry::FunctionType) {
+ m_error = QStringLiteral("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.")
+ .arg(name);
+ return nullptr;
+ }
+
+ FunctionTypeEntry *result = reinterpret_cast<FunctionTypeEntry *>(existingType);
+ result->addSignature(signature);
+ return result;
+}
+
+TypedefEntry *
+ Handler::parseTypedefEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ if (m_current && m_current->type != StackElement::Root
+ && m_current->type != StackElement::NamespaceTypeEntry) {
+ m_error = QLatin1String("typedef entries must be nested in namespaces or type system.");
+ return nullptr;
+ }
+ const int sourceIndex = indexOfAttribute(*attributes, sourceAttribute());
+ if (sourceIndex == -1) {
+ m_error = msgMissingAttribute(sourceAttribute());
+ return nullptr;
+ }
+ const QString sourceType = attributes->takeAt(sourceIndex).value().toString();
+ auto result = new TypedefEntry(name, sourceType, since);
+ applyCommonAttributes(result, attributes);
+ return result;
+}
+
+void Handler::applyComplexTypeAttributes(const QXmlStreamReader &reader,
+ ComplexTypeEntry *ctype,
+ QXmlStreamAttributes *attributes) const
+{
+ bool generate = true;
+ ctype->setCopyable(ComplexTypeEntry::Unknown);
+ auto exceptionHandling = m_exceptionHandling;
+
+ QString package = m_defaultPackage;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == streamAttribute()) {
+ ctype->setStream(convertBoolean(attributes->takeAt(i).value(), streamAttribute(), false));
+ } else if (name == generateAttribute()) {
+ generate = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true);
+ } else if (name ==packageAttribute()) {
+ package = attributes->takeAt(i).value().toString();
+ } else if (name == defaultSuperclassAttribute()) {
+ ctype->setDefaultSuperclass(attributes->takeAt(i).value().toString());
+ } else if (name == genericClassAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ const bool v = convertBoolean(attributes->takeAt(i).value(), genericClassAttribute(), false);
+ ctype->setGenericClass(v);
+ } else if (name == QLatin1String("target-lang-name")) {
+ ctype->setTargetLangName(attributes->takeAt(i).value().toString());
+ } else if (name == QLatin1String("polymorphic-base")) {
+ ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString());
+ } else if (name == QLatin1String("polymorphic-id-expression")) {
+ ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString());
+ } else if (name == copyableAttribute()) {
+ const bool v = convertBoolean(attributes->takeAt(i).value(), copyableAttribute(), false);
+ ctype->setCopyable(v ? ComplexTypeEntry::CopyableSet : ComplexTypeEntry::NonCopyableSet);
+ } else if (name == exceptionHandlingAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ const auto v = exceptionHandlingFromAttribute(attribute.value());
+ if (v != TypeSystem::ExceptionHandling::Unspecified) {
+ exceptionHandling = v;
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == QLatin1String("held-type")) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == QLatin1String("hash-function")) {
+ ctype->setHashFunction(attributes->takeAt(i).value().toString());
+ } else if (name == forceAbstractAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == deprecatedAttribute()) {
+ if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute(), false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
+ } else if (name == deleteInMainThreadAttribute()) {
+ if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute(), false))
+ ctype->setDeleteInMainThread(true);
+ } else if (name == QLatin1String("target-type")) {
+ ctype->setTargetType(attributes->takeAt(i).value().toString());
+ }
+ }
+
+ if (exceptionHandling != TypeSystem::ExceptionHandling::Unspecified)
+ ctype->setExceptionHandling(exceptionHandling);
+
+ // The generator code relies on container's package being empty.
+ if (ctype->type() != TypeEntry::ContainerType)
+ ctype->setTargetLangPackage(package);
+
+ if (InterfaceTypeEntry *di = ctype->designatedInterface())
+ di->setTargetLangPackage(package);
+
+ if (generate)
+ ctype->setCodeGeneration(m_generate);
+ else
+ ctype->setCodeGeneration(TypeEntry::GenerateForSubclass);
+}
+
+bool Handler::parseRenameFunction(const QXmlStreamReader &,
+ QString *name, QXmlStreamAttributes *attributes)
+{
+ QString signature;
+ QString rename;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == signatureAttribute()) {
+ // Do not remove as it is needed for the type entry later on
+ signature = attributes->at(i).value().toString();
+ } else if (name == renameAttribute()) {
+ rename = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (signature.isEmpty()) {
+ m_error = msgMissingAttribute(signatureAttribute());
+ return false;
+ }
+
+ *name = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
+
+ QString errorString = checkSignatureError(signature, QLatin1String("function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ if (!rename.isEmpty()) {
+ static const QRegularExpression functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$"));
+ Q_ASSERT(functionNameRegExp.isValid());
+ if (!functionNameRegExp.match(rename).hasMatch()) {
+ m_error = QLatin1String("can not rename '") + signature + QLatin1String("', '")
+ + rename + QLatin1String("' is not a valid function name");
+ return false;
+ }
+ FunctionModification mod;
+ if (!mod.setSignature(signature, &m_error))
+ return false;
+ mod.renamedToName = rename;
+ mod.modifiers |= Modification::Rename;
+ m_contextStack.top()->functionMods << mod;
+ }
+ return true;
+}
+
+bool Handler::parseInjectDocumentation(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ const int validParent = StackElement::TypeEntryMask
+ | StackElement::ModifyFunction
+ | StackElement::ModifyField;
+ if (!m_current->parent || (m_current->parent->type & validParent) == 0) {
+ m_error = QLatin1String("inject-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type");
+ return false;
+ }
+
+ TypeSystem::DocModificationMode mode = TypeSystem::DocModificationReplace;
+ TypeSystem::Language lang = TypeSystem::NativeCode;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("mode")) {
+ const QStringRef modeName = attributes->takeAt(i).value();
+ mode = docModificationFromAttribute(modeName);
+ if (mode == TypeSystem::DocModificationInvalid) {
+ m_error = QLatin1String("Unknown documentation injection mode: ") + modeName;
+ return false;
+ }
+ } else if (name == formatAttribute()) {
+ const QStringRef format = attributes->takeAt(i).value();
+ lang = languageFromAttribute(format);
+ if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(format);
+ return false;
+ }
+ }
+ }
+
+ QString signature = m_current->type & StackElement::TypeEntryMask
+ ? QString() : m_currentSignature;
+ DocModification mod(mode, signature);
+ mod.setFormat(lang);
+ m_contextStack.top()->docModifications << mod;
+ return true;
+}
+
+bool Handler::parseModifyDocumentation(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ const int validParent = StackElement::TypeEntryMask
+ | StackElement::ModifyFunction
+ | StackElement::ModifyField;
+ if (!m_current->parent || (m_current->parent->type & validParent) == 0) {
+ m_error = QLatin1String("modify-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type");
+ return false;
+ }
+
+ const int xpathIndex = indexOfAttribute(*attributes, xPathAttribute());
+ if (xpathIndex == -1) {
+ m_error = msgMissingAttribute(xPathAttribute());
+ return false;
+ }
+
+ const QString xpath = attributes->takeAt(xpathIndex).value().toString();
+ QString signature = (m_current->type & StackElement::TypeEntryMask) ? QString() : m_currentSignature;
+ m_contextStack.top()->docModifications
+ << DocModification(xpath, signature);
+ return true;
+}
+
+// m_exceptionHandling
+TypeSystemTypeEntry *Handler::parseRootElement(const QXmlStreamReader &,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes)
+{
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == packageAttribute()) {
+ m_defaultPackage = attributes->takeAt(i).value().toString();
+ } else if (name == defaultSuperclassAttribute()) {
+ m_defaultSuperclass = attributes->takeAt(i).value().toString();
+ } else if (name == exceptionHandlingAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ const auto v = exceptionHandlingFromAttribute(attribute.value());
+ if (v != TypeSystem::ExceptionHandling::Unspecified) {
+ m_exceptionHandling = v;
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ }
+ }
+
+ TypeSystemTypeEntry *moduleEntry =
+ const_cast<TypeSystemTypeEntry *>(m_database->findTypeSystemType(m_defaultPackage));
+ if (!moduleEntry)
+ moduleEntry = new TypeSystemTypeEntry(m_defaultPackage, since);
+ moduleEntry->setCodeGeneration(m_generate);
+
+ if ((m_generate == TypeEntry::GenerateForSubclass ||
+ m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty())
+ TypeDatabase::instance()->addRequiredTargetImport(m_defaultPackage);
+
+ if (!moduleEntry->qualifiedCppName().isEmpty())
+ m_database->addType(moduleEntry);
+ return moduleEntry;
+}
+
+bool Handler::loadTypesystem(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ QString typeSystemName;
+ bool generateChild = true;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute())
+ typeSystemName = attributes->takeAt(i).value().toString();
+ else if (name == generateAttribute())
+ generateChild = convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true);
+ }
+ if (typeSystemName.isEmpty()) {
+ m_error = QLatin1String("No typesystem name specified");
+ return false;
+ }
+ const bool result =
+ m_database->parseFile(typeSystemName, m_currentPath, generateChild
+ && m_generate == TypeEntry::GenerateAll);
+ if (!result)
+ m_error = QStringLiteral("Failed to parse: '%1'").arg(typeSystemName);
+ return result;
+}
+
+bool Handler::parseRejectEnumValue(const QXmlStreamReader &,
+ QXmlStreamAttributes *attributes)
+{
+ if (!m_currentEnum) {
+ m_error = QLatin1String("<reject-enum-value> node must be used inside a <enum-type> node");
+ return false;
+ }
+ const int nameIndex = indexOfAttribute(*attributes, nameAttribute());
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute());
+ return false;
+ }
+ m_currentEnum->addEnumValueRejection(attributes->takeAt(nameIndex).value().toString());
+ return true;
+}
+
+bool Handler::parseReplaceArgumentType(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("Type replacement can only be specified for argument modifications");
+ return false;
+ }
+ const int modifiedTypeIndex = indexOfAttribute(*attributes, modifiedTypeAttribute());
+ if (modifiedTypeIndex == -1) {
+ m_error = QLatin1String("Type replacement requires 'modified-type' attribute");
+ return false;
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().modified_type =
+ attributes->takeAt(modifiedTypeIndex).value().toString();
+ return true;
+}
+
+bool Handler::parseCustomConversion(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument
+ && topElement.type != StackElement::ValueTypeEntry
+ && topElement.type != StackElement::PrimitiveTypeEntry
+ && topElement.type != StackElement::ContainerTypeEntry) {
+ m_error = QLatin1String("Conversion rules can only be specified for argument modification, "
+ "value-type, primitive-type or container-type conversion.");
+ return false;
+ }
+
+ QString sourceFile;
+ QString snippetLabel;
+ TypeSystem::Language lang = TypeSystem::NativeCode;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == classAttribute()) {
+ const QStringRef languageAttribute = attributes->takeAt(i).value();
+ lang = languageFromAttribute(languageAttribute);
+ if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(languageAttribute);
+ return false;
+ }
+ } else if (name == QLatin1String("file")) {
+ sourceFile = attributes->takeAt(i).value().toString();
+ } else if (name == snippetAttribute()) {
+ snippetLabel = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (topElement.type == StackElement::ModifyArgument) {
+ CodeSnip snip;
+ snip.language = lang;
+ m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.append(snip);
+ return true;
+ }
+
+ if (topElement.entry->hasConversionRule() || topElement.entry->hasCustomConversion()) {
+ m_error = QLatin1String("Types can have only one conversion rule");
+ return false;
+ }
+
+ // The old conversion rule tag that uses a file containing the conversion
+ // will be kept temporarily for compatibility reasons.
+ if (!sourceFile.isEmpty()) {
+ if (m_generate != TypeEntry::GenerateForSubclass
+ && m_generate != TypeEntry::GenerateNothing) {
+
+ const char* conversionFlag = NATIVE_CONVERSION_RULE_FLAG;
+ if (lang == TypeSystem::TargetLangCode)
+ conversionFlag = TARGET_CONVERSION_RULE_FLAG;
+
+ QFile conversionSource(sourceFile);
+ if (conversionSource.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ const QString conversionRule =
+ extractSnippet(QString::fromUtf8(conversionSource.readAll()), snippetLabel);
+ topElement.entry->setConversionRule(QLatin1String(conversionFlag) + conversionRule);
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "File containing conversion code for "
+ << topElement.entry->name() << " type does not exist or is not readable: "
+ << sourceFile;
+ }
+ }
+ }
+
+ CustomConversion* customConversion = new CustomConversion(m_current->entry);
+ customConversionsForReview.append(customConversion);
+ return true;
+}
+
+bool Handler::parseAddConversion(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::TargetToNative) {
+ m_error = QLatin1String("Target to Native conversions can only be added inside 'target-to-native' tags.");
+ return false;
+ }
+ QString sourceTypeName;
+ QString typeCheck;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("type"))
+ sourceTypeName = attributes->takeAt(i).value().toString();
+ else if (name == QLatin1String("check"))
+ typeCheck = attributes->takeAt(i).value().toString();
+ }
+ if (sourceTypeName.isEmpty()) {
+ m_error = QLatin1String("Target to Native conversions must specify the input type with the 'type' attribute.");
+ return false;
+ }
+ m_current->entry->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck);
+ m_contextStack.top()->codeSnips << CodeSnip();
+ return true;
+}
+
+static bool parseIndex(const QString &index, int *result, QString *errorMessage)
+{
+ bool ok = false;
+ *result = index.toInt(&ok);
+ if (!ok)
+ *errorMessage = QStringLiteral("Cannot convert '%1' to integer").arg(index);
+ return ok;
+}
+
+static bool parseArgumentIndex(const QString &index, int *result, QString *errorMessage)
+{
+ if (index == QLatin1String("return")) {
+ *result = 0;
+ return true;
+ }
+ if (index == QLatin1String("this")) {
+ *result = -1;
+ return true;
+ }
+ return parseIndex(index, result, errorMessage);
+}
+
+bool Handler::parseModifyArgument(const QXmlStreamReader &,
+ const StackElement &topElement, QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyFunction
+ && topElement.type != StackElement::AddFunction) {
+ m_error = QString::fromLatin1("argument modification requires function"
+ " modification as parent, was %1")
+ .arg(topElement.type, 0, 16);
+ return false;
+ }
+
+ QString index;
+ QString replaceValue;
+ bool resetAfterUse = false;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == indexAttribute()) {
+ index = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("replace-value")) {
+ replaceValue = attributes->takeAt(i).value().toString();
+ } else if (name == invalidateAfterUseAttribute()) {
+ resetAfterUse = convertBoolean(attributes->takeAt(i).value(),
+ invalidateAfterUseAttribute(), false);
+ }
+ }
+
+ if (index.isEmpty()) {
+ m_error = msgMissingAttribute(indexAttribute());
+ return false;
+ }
+
+ int idx;
+ if (!parseArgumentIndex(index, &idx, &m_error))
+ return false;
+
+ if (!replaceValue.isEmpty() && idx) {
+ m_error = QLatin1String("replace-value is only supported for return values (index=0).");
+ return false;
+ }
+
+ ArgumentModification argumentModification = ArgumentModification(idx);
+ argumentModification.replace_value = replaceValue;
+ argumentModification.resetAfterUse = resetAfterUse;
+ m_contextStack.top()->functionMods.last().argument_mods.append(argumentModification);
+ return true;
+}
+
+bool Handler::parseNoNullPointer(const QXmlStreamReader &reader,
+ const StackElement &topElement, QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("no-null-pointer requires argument modification as parent");
+ return false;
+ }
+
+ ArgumentModification &lastArgMod = m_contextStack.top()->functionMods.last().argument_mods.last();
+ lastArgMod.noNullPointers = true;
+
+ const int defaultValueIndex =
+ indexOfAttribute(*attributes, QStringViewLiteral("default-value"));
+ if (defaultValueIndex != -1) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(defaultValueIndex);
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, attribute)));
+ }
+ return true;
+}
+
+bool Handler::parseDefineOwnership(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("define-ownership requires argument modification as parent");
+ return false;
+ }
+
+ TypeSystem::Language lang = TypeSystem::TargetLangCode;
+ QString ownership;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == classAttribute()) {
+ const QStringRef className = attributes->takeAt(i).value();
+ lang = languageFromAttribute(className);
+ if (lang != TypeSystem::TargetLangCode && lang != TypeSystem::NativeCode) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(className);
+ return false;
+ }
+ } else if (name == ownershipAttribute()) {
+ ownership = attributes->takeAt(i).value().toString();
+ }
+ }
+ const TypeSystem::Ownership owner = ownershipFromFromAttribute(ownership);
+ if (owner == TypeSystem::InvalidOwnership) {
+ m_error = QStringLiteral("unsupported owner attribute: '%1'").arg(ownership);
+ return false;
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().ownerships[lang] = owner;
return true;
}
-bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts)
+bool Handler::parseArgumentMap(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::CodeSnipMask)) {
+ m_error = QLatin1String("Argument maps requires code injection as parent");
+ return false;
+ }
+
+ int pos = 1;
+ QString metaName;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == indexAttribute()) {
+ if (!parseIndex(attributes->takeAt(i).value().toString(), &pos, &m_error))
+ return false;
+ if (pos <= 0) {
+ m_error = QStringLiteral("Argument position %1 must be a positive number").arg(pos);
+ return false;
+ }
+ } else if (name == QLatin1String("meta-name")) {
+ metaName = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ if (metaName.isEmpty())
+ qCWarning(lcShiboken) << "Empty meta name in argument map";
+
+ if (topElement.type == StackElement::InjectCodeInFunction) {
+ m_contextStack.top()->functionMods.last().snips.last().argumentMap[pos] = metaName;
+ } else {
+ qCWarning(lcShiboken) << "Argument maps are only useful for injection of code "
+ "into functions.";
+ }
+ return true;
+}
+
+bool Handler::parseRemoval(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyFunction) {
+ m_error = QLatin1String("Function modification parent required");
+ return false;
+ }
+
+ TypeSystem::Language lang = TypeSystem::All;
+ const int classIndex = indexOfAttribute(*attributes, classAttribute());
+ if (classIndex != -1) {
+ const QStringRef value = attributes->takeAt(classIndex).value();
+ lang = languageFromAttribute(value);
+ if (lang == TypeSystem::TargetLangCode) // "target" means TargetLangAndNativeCode here
+ lang = TypeSystem::TargetLangAndNativeCode;
+ if (lang != TypeSystem::TargetLangAndNativeCode && lang != TypeSystem::All) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(value);
+ return false;
+ }
+ }
+ m_contextStack.top()->functionMods.last().removal = lang;
+ return true;
+}
+
+bool Handler::parseRename(const QXmlStreamReader &reader,
+ StackElement::ElementType type,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyField
+ && topElement.type != StackElement::ModifyFunction
+ && topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("Function, field or argument modification parent required");
+ return false;
+ }
+
+ Modification *mod = nullptr;
+ if (topElement.type == StackElement::ModifyFunction)
+ mod = &m_contextStack.top()->functionMods.last();
+ else if (topElement.type == StackElement::ModifyField)
+ mod = &m_contextStack.top()->fieldMods.last();
+
+ Modification::Modifiers modifierFlag = Modification::Rename;
+ if (type == StackElement::Rename) {
+ const int toIndex = indexOfAttribute(*attributes, toAttribute());
+ if (toIndex == -1) {
+ m_error = msgMissingAttribute(toAttribute());
+ return false;
+ }
+ const QString renamed_to = attributes->takeAt(toIndex).value().toString();
+ if (topElement.type == StackElement::ModifyFunction)
+ mod->setRenamedTo(renamed_to);
+ else if (topElement.type == StackElement::ModifyField)
+ mod->setRenamedTo(renamed_to);
+ else
+ m_contextStack.top()->functionMods.last().argument_mods.last().renamed_to = renamed_to;
+ } else {
+ const int modifierIndex = indexOfAttribute(*attributes, modifierAttribute());
+ if (modifierIndex == -1) {
+ m_error = msgMissingAttribute(modifierAttribute());
+ return false;
+ }
+ const QStringRef modifier = attributes->takeAt(modifierIndex).value();
+ modifierFlag = modifierFromAttribute(modifier);
+ if (modifierFlag == Modification::InvalidModifier) {
+ m_error = QStringLiteral("Unknown access modifier: '%1'").arg(modifier);
+ return false;
+ }
+ if (modifierFlag == Modification::Friendly) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader, modifierAttribute(), modifier)));
+ }
+ }
+
+ if (mod)
+ mod->modifiers |= modifierFlag;
+ return true;
+}
+
+bool Handler::parseModifyField(const QXmlStreamReader &reader,
+ QXmlStreamAttributes *attributes)
+{
+ FieldModification fm;
+ fm.modifiers = FieldModification::Readable | FieldModification::Writable;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute()) {
+ fm.name = attributes->takeAt(i).value().toString();
+ } else if (name == removeAttribute()) {
+ if (!convertRemovalAttribute(attributes->takeAt(i).value(), fm, m_error))
+ return false;
+ } else if (name == readAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ if (!convertBoolean(attributes->takeAt(i).value(), readAttribute(), true))
+ fm.modifiers &= ~FieldModification::Readable;
+ } else if (name == writeAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ if (!convertBoolean(attributes->takeAt(i).value(), writeAttribute(), true))
+ fm.modifiers &= ~FieldModification::Writable;
+ }
+ }
+ if (fm.name.isEmpty()) {
+ m_error = msgMissingAttribute(nameAttribute());
+ return false;
+ }
+ m_contextStack.top()->fieldMods << fm;
+ return true;
+}
+
+bool Handler::parseAddFunction(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & (StackElement::ComplexTypeEntryMask | StackElement::Root))) {
+ m_error = QString::fromLatin1("Add function requires a complex type or a root tag as parent"
+ ", was=%1").arg(topElement.type, 0, 16);
+ return false;
+ }
+ QString originalSignature;
+ QString returnType = QLatin1String("void");
+ bool staticFunction = false;
+ QString access;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("signature")) {
+ originalSignature = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("return-type")) {
+ returnType = attributes->takeAt(i).value().toString();
+ } else if (name == staticAttribute()) {
+ staticFunction = convertBoolean(attributes->takeAt(i).value(),
+ staticAttribute(), false);
+ } else if (name == accessAttribute()) {
+ access = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ QString signature = TypeDatabase::normalizedSignature(originalSignature);
+ if (signature.isEmpty()) {
+ m_error = QLatin1String("No signature for the added function");
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature, QLatin1String("add-function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ AddedFunction func(signature, returnType);
+ func.setStatic(staticFunction);
+ if (!signature.contains(QLatin1Char('(')))
+ signature += QLatin1String("()");
+ m_currentSignature = signature;
+
+ if (!access.isEmpty()) {
+ const AddedFunction::Access a = addedFunctionAccessFromAttribute(access);
+ if (a == AddedFunction::InvalidAccess) {
+ m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
+ return false;
+ }
+ func.setAccess(a);
+ }
+
+ m_contextStack.top()->addedFunctions << func;
+
+ FunctionModification mod;
+ if (!mod.setSignature(m_currentSignature, &m_error))
+ return false;
+ mod.setOriginalSignature(originalSignature);
+ m_contextStack.top()->functionMods << mod;
+ return true;
+}
+
+bool Handler::parseModifyFunction(const QXmlStreamReader &reader,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
+ m_error = QString::fromLatin1("Modify function requires complex type as parent"
+ ", was=%1").arg(topElement.type, 0, 16);
+ return false;
+ }
+
+ QString originalSignature;
+ QString access;
+ QString removal;
+ QString rename;
+ QString association;
+ bool deprecated = false;
+ bool isThread = false;
+ TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
+ TypeSystem::AllowThread allowThread = TypeSystem::AllowThread::Unspecified;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("signature")) {
+ originalSignature = attributes->takeAt(i).value().toString();
+ } else if (name == accessAttribute()) {
+ access = attributes->takeAt(i).value().toString();
+ } else if (name == renameAttribute()) {
+ rename = attributes->takeAt(i).value().toString();
+ } else if (name == QLatin1String("associated-to")) {
+ association = attributes->takeAt(i).value().toString();
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ } else if (name == removeAttribute()) {
+ removal = attributes->takeAt(i).value().toString();
+ } else if (name == deprecatedAttribute()) {
+ deprecated = convertBoolean(attributes->takeAt(i).value(),
+ deprecatedAttribute(), false);
+ } else if (name == threadAttribute()) {
+ isThread = convertBoolean(attributes->takeAt(i).value(),
+ threadAttribute(), false);
+ } else if (name == allowThreadAttribute()) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(i);
+ allowThread = allowThreadFromAttribute(attribute.value());
+ if (allowThread == TypeSystem::AllowThread::Unspecified) {
+ m_error = msgInvalidAttributeValue(attribute);
+ return false;
+ }
+ } else if (name == exceptionHandlingAttribute()) {
+ const auto attribute = attributes->takeAt(i);
+ exceptionHandling = exceptionHandlingFromAttribute(attribute.value());
+ if (exceptionHandling == TypeSystem::ExceptionHandling::Unspecified) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgInvalidAttributeValue(attribute)));
+ }
+ } else if (name == virtualSlotAttribute()) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeWarning(reader, name)));
+ }
+ }
+
+ const QString signature = TypeDatabase::normalizedSignature(originalSignature);
+ if (signature.isEmpty()) {
+ m_error = QLatin1String("No signature for modified function");
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature, QLatin1String("modify-function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ FunctionModification mod;
+ if (!mod.setSignature(signature, &m_error))
+ return false;
+ mod.setOriginalSignature(originalSignature);
+ mod.setExceptionHandling(exceptionHandling);
+ m_currentSignature = signature;
+
+ if (!access.isEmpty()) {
+ const Modification::Modifiers m = modifierFromAttribute(access);
+ if ((m & (Modification::AccessModifierMask | Modification::FinalMask)) == 0) {
+ m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
+ return false;
+ }
+ if (m == Modification::Final || m == Modification::NonFinal) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader,
+ accessAttribute(), access)));
+ }
+ mod.modifiers |= m;
+ }
+
+ if (deprecated)
+ mod.modifiers |= Modification::Deprecated;
+
+ if (!removal.isEmpty() && !convertRemovalAttribute(removal, mod, m_error))
+ return false;
+
+ if (!rename.isEmpty()) {
+ mod.renamedToName = rename;
+ mod.modifiers |= Modification::Rename;
+ }
+
+ if (!association.isEmpty())
+ mod.association = association;
+
+ mod.setIsThread(isThread);
+ if (allowThread != TypeSystem::AllowThread::Unspecified)
+ mod.setAllowThread(allowThread);
+
+ m_contextStack.top()->functionMods << mod;
+ return true;
+}
+
+bool Handler::parseReplaceDefaultExpression(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::ModifyArgument)) {
+ m_error = QLatin1String("Replace default expression only allowed as child of argument modification");
+ return false;
+ }
+ const int withIndex = indexOfAttribute(*attributes, QStringViewLiteral("with"));
+ if (withIndex == -1 || attributes->at(withIndex).value().isEmpty()) {
+ m_error = QLatin1String("Default expression replaced with empty string. Use remove-default-expression instead.");
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().replacedDefaultExpression =
+ attributes->takeAt(withIndex).value().toString();
+ return true;
+}
+
+CustomFunction *
+ Handler::parseCustomMetaConstructor(const QXmlStreamReader &,
+ StackElement::ElementType type,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ QString functionName = topElement.entry->name().toLower()
+ + (type == StackElement::CustomMetaConstructor
+ ? QLatin1String("_create") : QLatin1String("_delete"));
+ QString paramName = QLatin1String("copy");
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == nameAttribute())
+ functionName = attributes->takeAt(i).value().toString();
+ else if (name == QLatin1String("param-name"))
+ paramName = attributes->takeAt(i).value().toString();
+ }
+ CustomFunction *func = new CustomFunction(functionName);
+ func->paramName = paramName;
+ return func;
+}
+
+bool Handler::parseReferenceCount(const QXmlStreamReader &reader,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("reference-count must be child of modify-argument");
+ return false;
+ }
+
+ ReferenceCount rc;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == actionAttribute()) {
+ const QXmlStreamAttribute attribute = attributes->takeAt(i);
+ rc.action = referenceCountFromAttribute(attribute.value());
+ switch (rc.action) {
+ case ReferenceCount::Invalid:
+ m_error = QLatin1String("unrecognized value '") + attribute.value()
+ + QLatin1String("' for action attribute.");
+ return false;
+ case ReferenceCount::AddAll:
+ case ReferenceCount::Ignore:
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedAttributeValueWarning(reader, attribute)));
+ break;
+ default:
+ break;
+ }
+ } else if (name == QLatin1String("variable-name")) {
+ rc.varName = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().referenceCounts.append(rc);
+ return true;
+}
+
+bool Handler::parseParentOwner(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("parent-policy must be child of modify-argument");
+ return false;
+ }
+ ArgumentOwner ao;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == indexAttribute()) {
+ const QString index = attributes->takeAt(i).value().toString();
+ if (!parseArgumentIndex(index, &ao.index, &m_error))
+ return false;
+ } else if (name == actionAttribute()) {
+ const QStringRef action = attributes->takeAt(i).value();
+ ao.action = argumentOwnerActionFromAttribute(action);
+ if (ao.action == ArgumentOwner::Invalid) {
+ m_error = QLatin1String("Invalid parent actionr '") + action + QLatin1String("'.");
+ return false;
+ }
+ }
+ }
+ m_contextStack.top()->functionMods.last().argument_mods.last().owner = ao;
+ return true;
+}
+
+bool Handler::parseInjectCode(const QXmlStreamReader &,
+ const StackElement &topElement,
+ StackElement* element, QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::ComplexTypeEntryMask)
+ && (topElement.type != StackElement::AddFunction)
+ && (topElement.type != StackElement::ModifyFunction)
+ && (topElement.type != StackElement::Root)) {
+ m_error = QLatin1String("wrong parent type for code injection");
+ return false;
+ }
+
+ TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionBeginning;
+ TypeSystem::Language lang = TypeSystem::TargetLangCode;
+ QString fileName;
+ QString snippetLabel;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == classAttribute()) {
+ const QStringRef className = attributes->takeAt(i).value();
+ lang = languageFromAttribute(className);
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QStringLiteral("Invalid class specifier: '%1'").arg(className);
+ return false;
+ }
+ } else if (name == positionAttribute()) {
+ const QStringRef value = attributes->takeAt(i).value();
+ position = codeSnipPositionFromAttribute(value);
+ if (position == TypeSystem::CodeSnipPositionInvalid) {
+ m_error = QStringLiteral("Invalid position: '%1'").arg(value);
+ return false;
+ }
+ } else if (name == QLatin1String("file")) {
+ fileName = attributes->takeAt(i).value().toString();
+ } else if (name == snippetAttribute()) {
+ snippetLabel = attributes->takeAt(i).value().toString();
+ }
+ }
+
+ CodeSnip snip;
+ snip.position = position;
+ snip.language = lang;
+ bool in_file = false;
+
+ // Handler constructor....
+ if (m_generate != TypeEntry::GenerateForSubclass &&
+ m_generate != TypeEntry::GenerateNothing &&
+ !fileName.isEmpty()) {
+ const QString resolved = m_database->modifiedTypesystemFilepath(fileName, m_currentPath);
+ if (QFile::exists(resolved)) {
+ QFile codeFile(resolved);
+ if (codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
+ QString content = QLatin1String("// ========================================================================\n"
+ "// START of custom code block [file: ");
+ content += fileName;
+ content += QLatin1String("]\n");
+ content += extractSnippet(QString::fromUtf8(codeFile.readAll()), snippetLabel);
+ content += QLatin1String("\n// END of custom code block [file: ");
+ content += fileName;
+ content += QLatin1String("]\n// ========================================================================\n");
+ snip.addCode(content);
+ in_file = true;
+ }
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "File for inject code not exist: " << QDir::toNativeSeparators(fileName);
+ }
+
+ }
+
+ if (snip.language == TypeSystem::Interface
+ && topElement.type != StackElement::InterfaceTypeEntry) {
+ m_error = QLatin1String("Interface code injections must be direct child of an interface type entry");
+ return false;
+ }
+
+ if (topElement.type == StackElement::ModifyFunction
+ || topElement.type == StackElement::AddFunction) {
+ if (snip.language == TypeSystem::ShellDeclaration) {
+ m_error = QLatin1String("no function implementation in shell declaration in which to inject code");
+ return false;
+ }
+
+ FunctionModification &mod = m_contextStack.top()->functionMods.last();
+ mod.snips << snip;
+ if (in_file)
+ mod.modifiers |= FunctionModification::CodeInjection;
+ element->type = StackElement::InjectCodeInFunction;
+ } else if (topElement.type == StackElement::Root) {
+ element->entry->addCodeSnip(snip);
+ } else if (topElement.type != StackElement::Root) {
+ m_contextStack.top()->codeSnips << snip;
+ }
+ return true;
+}
+
+bool Handler::parseInclude(const QXmlStreamReader &,
+ const StackElement &topElement,
+ TypeEntry *entry, QXmlStreamAttributes *attributes)
+{
+ QString fileName;
+ QString location;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("file-name"))
+ fileName = attributes->takeAt(i).value().toString();
+ else if (name == locationAttribute())
+ location = attributes->takeAt(i).value().toString();
+ }
+ const Include::IncludeType loc = locationFromAttribute(location);
+ if (loc == Include::InvalidInclude) {
+ m_error = QStringLiteral("Location not recognized: '%1'").arg(location);
+ return false;
+ }
+
+ Include inc(loc, fileName);
+ if (topElement.type
+ & (StackElement::ComplexTypeEntryMask | StackElement::PrimitiveTypeEntry)) {
+ entry->setInclude(inc);
+ } else if (topElement.type == StackElement::ExtraIncludes) {
+ entry->addExtraInclude(inc);
+ } else {
+ m_error = QLatin1String("Only supported parent tags are primitive-type, complex types or extra-includes");
+ return false;
+ }
+ if (InterfaceTypeEntry *di = entry->designatedInterface()) {
+ di->setInclude(entry->include());
+ di->setExtraIncludes(entry->extraIncludes());
+ }
+ return true;
+}
+
+TemplateInstance *
+ Handler::parseTemplateInstanceEnum(const QXmlStreamReader &,
+ const StackElement &topElement,
+ QXmlStreamAttributes *attributes)
+{
+ if (!(topElement.type & StackElement::CodeSnipMask) &&
+ (topElement.type != StackElement::Template) &&
+ (topElement.type != StackElement::CustomMetaConstructor) &&
+ (topElement.type != StackElement::CustomMetaDestructor) &&
+ (topElement.type != StackElement::NativeToTarget) &&
+ (topElement.type != StackElement::AddConversion) &&
+ (topElement.type != StackElement::ConversionRule)) {
+ m_error = QLatin1String("Can only insert templates into code snippets, templates, custom-constructors, "\
+ "custom-destructors, conversion-rule, native-to-target or add-conversion tags.");
+ return nullptr;
+ }
+ const int nameIndex = indexOfAttribute(*attributes, nameAttribute());
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute());
+ return nullptr;
+ }
+ return new TemplateInstance(attributes->takeAt(nameIndex).value().toString());
+}
+
+bool Handler::parseReplace(const QXmlStreamReader &,
+ const StackElement &topElement,
+ StackElement *element, QXmlStreamAttributes *attributes)
+{
+ if (topElement.type != StackElement::TemplateInstanceEnum) {
+ m_error = QLatin1String("Can only insert replace rules into insert-template.");
+ return false;
+ }
+ QString from;
+ QString to;
+ for (int i = attributes->size() - 1; i >= 0; --i) {
+ const QStringRef name = attributes->at(i).qualifiedName();
+ if (name == QLatin1String("from"))
+ from = attributes->takeAt(i).value().toString();
+ else if (name == toAttribute())
+ to = attributes->takeAt(i).value().toString();
+ }
+ element->parent->value.templateInstance->addReplaceRule(from, to);
+ return true;
+}
+
+bool Handler::startElement(const QXmlStreamReader &reader)
{
if (m_ignoreDepth) {
++m_ignoreDepth;
return true;
}
+ const QStringRef tagName = reader.name();
+ QXmlStreamAttributes attributes = reader.attributes();
+
QVersionNumber since(0, 0);
- const QStringRef sinceSpec = atts.value(sinceAttribute());
- if (!sinceSpec.isNull()) {
+ int index = indexOfAttribute(attributes, sinceAttribute());
+ if (index != -1) {
+ const QStringRef sinceSpec = attributes.takeAt(index).value();
since = QVersionNumber::fromString(sinceSpec.toString());
if (since.isNull()) {
m_error = msgInvalidVersion(sinceSpec, m_defaultPackage);
@@ -722,12 +2419,11 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
}
- const QString tagName = n.toString().toLower();
- if (tagName == QLatin1String("import-file"))
- return importFileElement(atts);
+ if (tagName.compare(QLatin1String("import-file"), Qt::CaseInsensitive) == 0)
+ return importFileElement(attributes);
- const QHash<QString, StackElement::ElementType>::const_iterator tit = tagNames.constFind(tagName);
- if (tit == tagNames.constEnd()) {
+ const StackElement::ElementType elementType = elementFromTag(tagName);
+ if (elementType == StackElement::None) {
m_error = QStringLiteral("Unknown tag name: '%1'").arg(tagName);
return false;
}
@@ -738,92 +2434,48 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
StackElement* element = new StackElement(m_current);
- element->type = tit.value();
+ element->type = elementType;
if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateAll)
customConversionsForReview.clear();
- if (element->type == StackElement::Root
- || element->type == StackElement::NamespaceTypeEntry
- || element->type == StackElement::InterfaceTypeEntry
- || element->type == StackElement::ObjectTypeEntry
- || element->type == StackElement::ValueTypeEntry
- || element->type == StackElement::PrimitiveTypeEntry) {
+ if (element->type == StackElement::CustomMetaConstructor
+ || element->type == StackElement::CustomMetaDestructor) {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedElementWarning(reader, tagName)));
+ }
+
+ switch (element->type) {
+ case StackElement::Root:
+ case StackElement::NamespaceTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::PrimitiveTypeEntry:
+ case StackElement::TypedefTypeEntry:
m_contextStack.push(new StackElementContext());
+ break;
+ default:
+ break;
}
if (element->type & StackElement::TypeEntryMask) {
- QHash<QString, QString> attributes;
- attributes.insert(nameAttribute(), QString());
- attributes.insert(QLatin1String("revision"), QLatin1String("0"));
- attributes.insert(sinceAttribute(), QString()); // dummy for matching allowed attributes
-
- switch (element->type) {
- case StackElement::PrimitiveTypeEntry:
- attributes.insert(QLatin1String("target-lang-name"), QString());
- attributes.insert(QLatin1String("target-lang-api-name"), QString());
- attributes.insert(QLatin1String("preferred-conversion"), yesAttributeValue());
- attributes.insert(QLatin1String("preferred-target-lang-type"), yesAttributeValue());
- attributes.insert(QLatin1String("default-constructor"), QString());
- break;
- case StackElement::ContainerTypeEntry:
- attributes.insert(QLatin1String("type"), QString());
- break;
- case StackElement::SmartPointerTypeEntry:
- attributes.insert(QLatin1String("type"), QString());
- attributes.insert(QLatin1String("getter"), QString());
- attributes.insert(QLatin1String("ref-count-method"), QString());
- break;
- case StackElement::EnumTypeEntry:
- attributes.insert(flagsAttribute(), QString());
- attributes.insert(QLatin1String("flags-revision"), QString());
- attributes.insert(QLatin1String("upper-bound"), QString());
- attributes.insert(QLatin1String("lower-bound"), QString());
- attributes.insert(QLatin1String("force-integer"), noAttributeValue());
- attributes.insert(QLatin1String("extensible"), noAttributeValue());
- attributes.insert(enumIdentifiedByValueAttribute(), QString());
- attributes.insert(classAttribute(), falseAttributeValue());
- break;
- case StackElement::ValueTypeEntry:
- attributes.insert(QLatin1String("default-constructor"), QString());
- Q_FALLTHROUGH();
- case StackElement::ObjectTypeEntry:
- attributes.insert(QLatin1String("force-abstract"), noAttributeValue());
- attributes.insert(QLatin1String("deprecated"), noAttributeValue());
- attributes.insert(QLatin1String("hash-function"), QString());
- attributes.insert(QLatin1String("stream"), noAttributeValue());
- Q_FALLTHROUGH();
- case StackElement::InterfaceTypeEntry:
- attributes[QLatin1String("default-superclass")] = m_defaultSuperclass;
- attributes.insert(QLatin1String("polymorphic-id-expression"), QString());
- attributes.insert(QLatin1String("delete-in-main-thread"), noAttributeValue());
- attributes.insert(QLatin1String("held-type"), QString());
- attributes.insert(QLatin1String("copyable"), QString());
- Q_FALLTHROUGH();
- case StackElement::NamespaceTypeEntry:
- attributes.insert(QLatin1String("target-lang-name"), QString());
- attributes[QLatin1String("package")] = m_defaultPackage;
- attributes.insert(QLatin1String("expense-cost"), QLatin1String("1"));
- attributes.insert(QLatin1String("expense-limit"), QLatin1String("none"));
- attributes.insert(QLatin1String("polymorphic-base"), noAttributeValue());
- attributes.insert(QLatin1String("generate"), yesAttributeValue());
- attributes.insert(QLatin1String("target-type"), QString());
- attributes.insert(QLatin1String("generic-class"), noAttributeValue());
- break;
- case StackElement::FunctionTypeEntry:
- attributes.insert(QLatin1String("signature"), QString());
- attributes.insert(QLatin1String("rename"), QString());
- break;
- default:
- { } // nada
- };
-
- fetchAttributeValues(tagName, atts, &attributes);
- QString name = attributes[nameAttribute()];
+ QString name;
+ if (element->type != StackElement::FunctionTypeEntry) {
+ const int nameIndex = indexOfAttribute(attributes, nameAttribute());
+ if (nameIndex != -1) {
+ name = attributes.takeAt(nameIndex).value().toString();
+ } else if (element->type != StackElement::EnumTypeEntry) { // anonymous enum?
+ m_error = msgMissingAttribute(nameAttribute());
+ return false;
+ }
+ }
if (m_database->hasDroppedTypeEntries()) {
QString identifier = getNamePrefix(element) + QLatin1Char('.');
- identifier += (element->type == StackElement::FunctionTypeEntry ? attributes[QLatin1String("signature")] : name);
+ identifier += element->type == StackElement::FunctionTypeEntry
+ ? attributes.value(signatureAttribute()).toString()
+ : name;
if (m_database->shouldDropTypeEntry(identifier)) {
m_currentDroppedEntry = element;
m_currentDroppedEntryDepth = 1;
@@ -837,30 +2489,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
// The top level tag 'function' has only the 'signature' tag
// and we should extract the 'name' value from it.
- if (element->type == StackElement::FunctionTypeEntry) {
- QString signature = attributes[QLatin1String("signature")];
- name = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
- QString errorString = checkSignatureError(signature, QLatin1String("function"));
- if (!errorString.isEmpty()) {
- m_error = errorString;
+ if (element->type == StackElement::FunctionTypeEntry
+ && !parseRenameFunction(reader, &name, &attributes)) {
return false;
- }
- QString rename = attributes[QLatin1String("rename")];
- if (!rename.isEmpty()) {
- static const QRegularExpression functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$"));
- Q_ASSERT(functionNameRegExp.isValid());
- if (!functionNameRegExp.match(rename).hasMatch()) {
- m_error = QLatin1String("can not rename '") + signature + QLatin1String("', '")
- + rename + QLatin1String("' is not a valid function name");
- return false;
- }
- FunctionModification mod;
- if (!mod.setSignature(signature, &m_error))
- return false;
- mod.renamedToName = attributes[QLatin1String("rename")];
- mod.modifiers |= Modification::Rename;
- m_contextStack.top()->functionMods << mod;
- }
}
// We need to be able to have duplicate primitive type entries,
@@ -875,7 +2506,9 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
if (element->type == StackElement::EnumTypeEntry) {
- const QString identifiedByValue = attributes.value(enumIdentifiedByValueAttribute());
+ const int enumIdentifiedByIndex = indexOfAttribute(attributes, enumIdentifiedByValueAttribute());
+ const QString identifiedByValue = enumIdentifiedByIndex != -1
+ ? attributes.takeAt(enumIdentifiedByIndex).value().toString() : QString();
if (name.isEmpty()) {
name = identifiedByValue;
} else if (!identifiedByValue.isEmpty()) {
@@ -900,281 +2533,92 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
case StackElement::CustomTypeEntry:
element->entry = new TypeEntry(name, TypeEntry::CustomType, since);
break;
- case StackElement::PrimitiveTypeEntry: {
- QString targetLangName = attributes[QLatin1String("target-lang-name")];
- QString targetLangApiName = attributes[QLatin1String("target-lang-api-name")];
- QString preferredConversion = attributes[QLatin1String("preferred-conversion")].toLower();
- QString preferredTargetLangType = attributes[QLatin1String("preferred-target-lang-type")].toLower();
- QString defaultConstructor = attributes[QLatin1String("default-constructor")];
-
- if (targetLangName.isEmpty())
- targetLangName = name;
- if (targetLangApiName.isEmpty())
- targetLangApiName = name;
-
- PrimitiveTypeEntry *type = new PrimitiveTypeEntry(name, since);
- type->setCodeGeneration(m_generate);
- type->setTargetLangName(targetLangName);
- type->setTargetLangApiName(targetLangApiName);
- type->setTargetLangPackage(m_defaultPackage);
- type->setDefaultConstructor(defaultConstructor);
-
- bool preferred;
- preferred = convertBoolean(preferredConversion, QLatin1String("preferred-conversion"), true);
- type->setPreferredConversion(preferred);
- preferred = convertBoolean(preferredTargetLangType,
- QLatin1String("preferred-target-lang-type"), true);
- type->setPreferredTargetLangType(preferred);
-
- element->entry = type;
- }
- break;
-
- case StackElement::ContainerTypeEntry: {
- QString typeName = attributes[QLatin1String("type")];
- ContainerTypeEntry::Type containerType =
- ContainerTypeEntry::containerTypeFromString(typeName);
- if (typeName.isEmpty()) {
- m_error = QLatin1String("no 'type' attribute specified");
+ case StackElement::PrimitiveTypeEntry:
+ element->entry = parsePrimitiveTypeEntry(reader, name, since, &attributes);
+ if (Q_UNLIKELY(!element->entry))
return false;
- } else if (containerType == ContainerTypeEntry::NoContainer) {
- m_error = QLatin1String("there is no container of type ") + typeName;
+ break;
+ case StackElement::ContainerTypeEntry:
+ if (ContainerTypeEntry *ce = parseContainerTypeEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, ce, &attributes);
+ element->entry = ce;
+ } else {
return false;
}
+ break;
- ContainerTypeEntry *type = new ContainerTypeEntry(name, containerType, since);
- type->setCodeGeneration(m_generate);
- element->entry = type;
- }
- break;
-
- case StackElement::SmartPointerTypeEntry: {
- bool result = handleSmartPointerEntry(element, attributes, name, since);
- if (!result)
- return result;
- }
- break;
-
- case StackElement::EnumTypeEntry: {
- QStringList names = name.split(colonColon());
- if (names.size() == 1)
- m_currentEnum = new EnumTypeEntry(QString(), name, since);
- else
- m_currentEnum =
- new EnumTypeEntry(QStringList(names.mid(0, names.size() - 1)).join(colonColon()),
- names.constLast(), since);
- element->entry = m_currentEnum;
- m_currentEnum->setCodeGeneration(m_generate);
- m_currentEnum->setTargetLangPackage(m_defaultPackage);
- m_currentEnum->setUpperBound(attributes[QLatin1String("upper-bound")]);
- m_currentEnum->setLowerBound(attributes[QLatin1String("lower-bound")]);
- m_currentEnum->setForceInteger(convertBoolean(attributes[QLatin1String("force-integer")], QLatin1String("force-integer"), false));
- m_currentEnum->setExtensible(convertBoolean(attributes[QLatin1String("extensible")], QLatin1String("extensible"), false));
-
- // put in the flags parallel...
- const QString flagNames = attributes.value(flagsAttribute());
- if (!flagNames.isEmpty()) {
- const QStringList &flagNameList = flagNames.split(QLatin1Char(','));
- for (const QString &flagName : flagNameList)
- addFlags(name, flagName.trimmed(), attributes, since);
+ case StackElement::SmartPointerTypeEntry:
+ if (SmartPointerTypeEntry *se = parseSmartPointerEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, se, &attributes);
+ element->entry = se;
+ } else {
+ return false;
}
- }
- break;
+ break;
+ case StackElement::EnumTypeEntry:
+ m_currentEnum = parseEnumTypeEntry(reader, name, since, &attributes);
+ if (Q_UNLIKELY(!m_currentEnum))
+ return false;
+ element->entry = m_currentEnum;
+ break;
- case StackElement::InterfaceTypeEntry: {
- ObjectTypeEntry *otype = new ObjectTypeEntry(name, since);
- QString targetLangName = attributes[QLatin1String("target-lang-name")];
- if (targetLangName.isEmpty())
- targetLangName = name;
- InterfaceTypeEntry *itype =
- new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName), since);
-
- if (!convertBoolean(attributes[QLatin1String("generate")], QLatin1String("generate"), true))
- itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
- else
- itype->setCodeGeneration(m_generate);
- otype->setDesignatedInterface(itype);
- itype->setOrigin(otype);
- element->entry = otype;
- }
- Q_FALLTHROUGH();
- case StackElement::ValueTypeEntry: {
- if (!element->entry) {
- ValueTypeEntry* typeEntry = new ValueTypeEntry(name, since);
- QString defaultConstructor = attributes[QLatin1String("default-constructor")];
- if (!defaultConstructor.isEmpty())
- typeEntry->setDefaultConstructor(defaultConstructor);
- element->entry = typeEntry;
+ case StackElement::InterfaceTypeEntry:
+ if (ObjectTypeEntry *oe = parseInterfaceTypeEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, oe, &attributes);
+ element->entry = oe;
+ } else {
+ return false;
}
-
- Q_FALLTHROUGH();
+ break;
+ case StackElement::ValueTypeEntry:
+ if (ValueTypeEntry *ve = parseValueTypeEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, ve, &attributes);
+ element->entry = ve;
+ } else {
+ return false;
+ }
+ break;
case StackElement::NamespaceTypeEntry:
- if (!element->entry)
- element->entry = new NamespaceTypeEntry(name, since);
-
- Q_FALLTHROUGH();
+ element->entry = new NamespaceTypeEntry(name, since);
+ applyCommonAttributes(element->entry, &attributes);
+ applyComplexTypeAttributes(reader, static_cast<ComplexTypeEntry *>(element->entry), &attributes);
+ break;
case StackElement::ObjectTypeEntry:
- if (!element->entry)
- element->entry = new ObjectTypeEntry(name, since);
-
- element->entry->setStream(attributes[QLatin1String("stream")] == yesAttributeValue());
-
- ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
- ctype->setTargetLangPackage(attributes[QLatin1String("package")]);
- ctype->setDefaultSuperclass(attributes[QLatin1String("default-superclass")]);
- ctype->setGenericClass(convertBoolean(attributes[QLatin1String("generic-class")], QLatin1String("generic-class"), false));
-
- if (!convertBoolean(attributes[QLatin1String("generate")], QLatin1String("generate"), true))
- element->entry->setCodeGeneration(TypeEntry::GenerateForSubclass);
- else
- element->entry->setCodeGeneration(m_generate);
-
- QString targetLangName = attributes[QLatin1String("target-lang-name")];
- if (!targetLangName.isEmpty())
- ctype->setTargetLangName(targetLangName);
-
- ctype->setIsPolymorphicBase(convertBoolean(attributes[QLatin1String("polymorphic-base")], QLatin1String("polymorphic-base"), false));
- ctype->setPolymorphicIdValue(attributes[QLatin1String("polymorphic-id-expression")]);
- //Copyable
- if (attributes[QLatin1String("copyable")].isEmpty())
- ctype->setCopyable(ComplexTypeEntry::Unknown);
- else {
- if (convertBoolean(attributes[QLatin1String("copyable")], QLatin1String("copyable"), false))
- ctype->setCopyable(ComplexTypeEntry::CopyableSet);
- else
- ctype->setCopyable(ComplexTypeEntry::NonCopyableSet);
-
- }
-
- if (element->type == StackElement::ObjectTypeEntry || element->type == StackElement::ValueTypeEntry)
- ctype->setHashFunction(attributes[QLatin1String("hash-function")]);
-
-
- ctype->setHeldType(attributes[QLatin1String("held-type")]);
-
- if (element->type == StackElement::ObjectTypeEntry
- || element->type == StackElement::ValueTypeEntry) {
- if (convertBoolean(attributes[QLatin1String("force-abstract")], QLatin1String("force-abstract"), false))
- ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract);
- if (convertBoolean(attributes[QLatin1String("deprecated")], QLatin1String("deprecated"), false))
- ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
- }
-
- if (element->type == StackElement::InterfaceTypeEntry
- || element->type == StackElement::ValueTypeEntry
- || element->type == StackElement::ObjectTypeEntry) {
- if (convertBoolean(attributes[QLatin1String("delete-in-main-thread")], QLatin1String("delete-in-main-thread"), false))
- ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DeleteInMainThread);
- }
-
- QString targetType = attributes[QLatin1String("target-type")];
- if (!targetType.isEmpty() && element->entry->isComplex())
- static_cast<ComplexTypeEntry *>(element->entry)->setTargetType(targetType);
-
- // ctype->setInclude(Include(Include::IncludePath, ctype->name()));
- ctype = ctype->designatedInterface();
- if (ctype)
- ctype->setTargetLangPackage(attributes[QLatin1String("package")]);
-
- }
- break;
- case StackElement::FunctionTypeEntry: {
- QString signature = attributes[QLatin1String("signature")];
- signature = TypeDatabase::normalizedSignature(signature);
- element->entry = m_database->findType(name);
- if (element->entry) {
- if (element->entry->type() == TypeEntry::FunctionType) {
- reinterpret_cast<FunctionTypeEntry*>(element->entry)->addSignature(signature);
- } else {
- m_error = QStringLiteral("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.")
- .arg(name);
- return false;
- }
+ element->entry = new ObjectTypeEntry(name, since);
+ applyCommonAttributes(element->entry, &attributes);
+ applyComplexTypeAttributes(reader, static_cast<ComplexTypeEntry *>(element->entry), &attributes);
+ break;
+ case StackElement::FunctionTypeEntry:
+ element->entry = parseFunctionTypeEntry(reader, name, since, &attributes);
+ if (Q_UNLIKELY(!element->entry))
+ return false;
+ break;
+ case StackElement::TypedefTypeEntry:
+ if (TypedefEntry *te = parseTypedefEntry(reader, name, since, &attributes)) {
+ applyComplexTypeAttributes(reader, te, &attributes);
+ element->entry = te;
} else {
- element->entry = new FunctionTypeEntry(name, signature, since);
- element->entry->setCodeGeneration(m_generate);
+ return false;
}
- }
- break;
+ break;
default:
Q_ASSERT(false);
};
if (element->entry) {
- m_database->addType(element->entry);
- setTypeRevision(element->entry, attributes[QLatin1String("revision")].toInt());
+ if (!m_database->addType(element->entry, &m_error))
+ return false;
} else {
qCWarning(lcShiboken).noquote().nospace()
<< QStringLiteral("Type: %1 was rejected by typesystem").arg(name);
}
} else if (element->type == StackElement::InjectDocumentation) {
- // check the XML tag attributes
- QHash<QString, QString> attributes;
- attributes.insert(QLatin1String("mode"), QLatin1String("replace"));
- attributes.insert(QLatin1String("format"), QLatin1String("native"));
- attributes.insert(sinceAttribute(), QString()); // dummy for matching allowed attributes
-
- fetchAttributeValues(tagName, atts, &attributes);
-
- const int validParent = StackElement::TypeEntryMask
- | StackElement::ModifyFunction
- | StackElement::ModifyField;
- if (m_current->parent && m_current->parent->type & validParent) {
- QString modeName = attributes[QLatin1String("mode")];
- TypeSystem::DocModificationMode mode;
- if (modeName == QLatin1String("append")) {
- mode = TypeSystem::DocModificationAppend;
- } else if (modeName == QLatin1String("prepend")) {
- mode = TypeSystem::DocModificationPrepend;
- } else if (modeName == QLatin1String("replace")) {
- mode = TypeSystem::DocModificationReplace;
- } else {
- m_error = QLatin1String("Unknow documentation injection mode: ") + modeName;
- return false;
- }
-
- static QHash<QString, TypeSystem::Language> languageNames;
- if (languageNames.isEmpty()) {
- languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode;
- languageNames[QLatin1String("native")] = TypeSystem::NativeCode;
- }
-
- QString format = attributes[QLatin1String("format")].toLower();
- TypeSystem::Language lang = languageNames.value(format, TypeSystem::NoLanguage);
- if (lang == TypeSystem::NoLanguage) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(format);
- return false;
- }
-
- QString signature = m_current->type & StackElement::TypeEntryMask ? QString() : m_currentSignature;
- DocModification mod(mode, signature);
- mod.setFormat(lang);
- m_contextStack.top()->docModifications << mod;
- } else {
- m_error = QLatin1String("inject-documentation must be inside modify-function, "
- "modify-field or other tags that creates a type");
+ if (!parseInjectDocumentation(reader, &attributes))
return false;
- }
} else if (element->type == StackElement::ModifyDocumentation) {
- // check the XML tag attributes
- QHash<QString, QString> attributes;
- attributes.insert(xPathAttribute(), QString());
- attributes.insert(sinceAttribute(), QString()); // dummy for matching allowed attributes
- fetchAttributeValues(tagName, atts, &attributes);
-
- const int validParent = StackElement::TypeEntryMask
- | StackElement::ModifyFunction
- | StackElement::ModifyField;
- if (m_current->parent && m_current->parent->type & validParent) {
- QString signature = (m_current->type & StackElement::TypeEntryMask) ? QString() : m_currentSignature;
- m_contextStack.top()->docModifications
- << DocModification(attributes.value(xPathAttribute()), signature);
- } else {
- m_error = QLatin1String("modify-documentation must be inside modify-function, "
- "modify-field or other tags that creates a type");
+ if (!parseModifyDocumentation(reader, &attributes))
return false;
- }
} else if (element->type != StackElement::None) {
bool topLevel = element->type == StackElement::Root
|| element->type == StackElement::SuppressedWarning
@@ -1194,494 +2638,89 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
StackElement topElement = !m_current ? StackElement(0) : *m_current;
element->entry = topElement.entry;
- QHash<QString, QString> attributes;
- attributes.insert(sinceAttribute(), QString()); // dummy for matching allowed attributes
switch (element->type) {
case StackElement::Root:
- attributes.insert(QLatin1String("package"), QString());
- attributes.insert(QLatin1String("default-superclass"), QString());
+ element->entry = parseRootElement(reader, since, &attributes);
+ element->type = StackElement::Root;
break;
case StackElement::LoadTypesystem:
- attributes.insert(nameAttribute(), QString());
- attributes.insert(QLatin1String("generate"), yesAttributeValue());
- break;
- case StackElement::NoNullPointers:
- attributes.insert(QLatin1String("default-value"), QString());
- break;
- case StackElement::SuppressedWarning:
- attributes.insert(textAttribute(), QString());
- break;
- case StackElement::ReplaceDefaultExpression:
- attributes.insert(QLatin1String("with"), QString());
- break;
- case StackElement::DefineOwnership:
- attributes.insert(QLatin1String("class"), QLatin1String("target"));
- attributes.insert(QLatin1String("owner"), QString());
- break;
- case StackElement::AddFunction:
- attributes.insert(QLatin1String("signature"), QString());
- attributes.insert(QLatin1String("return-type"), QLatin1String("void"));
- attributes.insert(QLatin1String("access"), QLatin1String("public"));
- attributes.insert(QLatin1String("static"), noAttributeValue());
- break;
- case StackElement::ModifyFunction:
- attributes.insert(QLatin1String("signature"), QString());
- attributes.insert(QLatin1String("access"), QString());
- attributes.insert(QLatin1String("remove"), QString());
- attributes.insert(QLatin1String("rename"), QString());
- attributes.insert(QLatin1String("deprecated"), noAttributeValue());
- attributes.insert(QLatin1String("associated-to"), QString());
- attributes.insert(QLatin1String("virtual-slot"), noAttributeValue());
- attributes.insert(QLatin1String("thread"), noAttributeValue());
- attributes.insert(QLatin1String("allow-thread"), noAttributeValue());
- break;
- case StackElement::ModifyArgument:
- attributes.insert(QLatin1String("index"), QString());
- attributes.insert(QLatin1String("replace-value"), QString());
- attributes.insert(QLatin1String("invalidate-after-use"), noAttributeValue());
- break;
- case StackElement::ModifyField:
- attributes.insert(nameAttribute(), QString());
- attributes.insert(QLatin1String("write"), trueAttributeValue());
- attributes.insert(QLatin1String("read"), trueAttributeValue());
- attributes.insert(QLatin1String("remove"), QString());
- break;
- case StackElement::Access:
- attributes.insert(QLatin1String("modifier"), QString());
- break;
- case StackElement::Include:
- attributes.insert(QLatin1String("file-name"), QString());
- attributes.insert(QLatin1String("location"), QString());
- break;
- case StackElement::CustomMetaConstructor:
- attributes[nameAttribute()] = topElement.entry->name().toLower() + QLatin1String("_create");
- attributes.insert(QLatin1String("param-name"), QLatin1String("copy"));
+ if (!loadTypesystem(reader, &attributes))
+ return false;
break;
- case StackElement::CustomMetaDestructor:
- attributes[nameAttribute()] = topElement.entry->name().toLower() + QLatin1String("_delete");
- attributes.insert(QLatin1String("param-name"), QLatin1String("copy"));
+ case StackElement::RejectEnumValue:
+ if (!parseRejectEnumValue(reader, &attributes))
+ return false;
break;
case StackElement::ReplaceType:
- attributes.insert(QLatin1String("modified-type"), QString());
- break;
- case StackElement::InjectCode:
- attributes.insert(QLatin1String("class"), QLatin1String("target"));
- attributes.insert(QLatin1String("position"), QLatin1String("beginning"));
- attributes.insert(QLatin1String("file"), QString());
+ if (!parseReplaceArgumentType(reader, topElement, &attributes))
+ return false;
break;
case StackElement::ConversionRule:
- attributes.insert(QLatin1String("class"), QString());
- attributes.insert(QLatin1String("file"), QString());
- break;
- case StackElement::TargetToNative:
- attributes.insert(QLatin1String("replace"), yesAttributeValue());
- break;
- case StackElement::AddConversion:
- attributes.insert(QLatin1String("type"), QString());
- attributes.insert(QLatin1String("check"), QString());
- break;
- case StackElement::RejectEnumValue:
- attributes.insert(nameAttribute(), QString());
- break;
- case StackElement::ArgumentMap:
- attributes.insert(QLatin1String("index"), QLatin1String("1"));
- attributes.insert(QLatin1String("meta-name"), QString());
- break;
- case StackElement::Rename:
- attributes.insert(QLatin1String("to"), QString());
- break;
- case StackElement::Rejection:
- attributes.insert(classAttribute(), QString());
- attributes.insert(functionNameAttribute(), QString());
- attributes.insert(fieldNameAttribute(), QString());
- attributes.insert(enumNameAttribute(), QString());
- attributes.insert(argumentTypeAttribute(), QString());
- attributes.insert(returnTypeAttribute(), QString());
- break;
- case StackElement::Removal:
- attributes.insert(QLatin1String("class"), QLatin1String("all"));
- break;
- case StackElement::Template:
- attributes.insert(nameAttribute(), QString());
- break;
- case StackElement::TemplateInstanceEnum:
- attributes.insert(nameAttribute(), QString());
- break;
- case StackElement::Replace:
- attributes.insert(QLatin1String("from"), QString());
- attributes.insert(QLatin1String("to"), QString());
- break;
- case StackElement::ReferenceCount:
- attributes.insert(QLatin1String("action"), QString());
- attributes.insert(QLatin1String("variable-name"), QString());
- break;
- case StackElement::ParentOwner:
- attributes.insert(QLatin1String("index"), QString());
- attributes.insert(QLatin1String("action"), QString());
- break;
- case StackElement::Array:
- break;
- default:
- { };
- };
-
- if (!attributes.isEmpty())
- fetchAttributeValues(tagName, atts, &attributes);
-
- switch (element->type) {
- case StackElement::Root:
- m_defaultPackage = attributes[QLatin1String("package")];
- m_defaultSuperclass = attributes[QLatin1String("default-superclass")];
- element->type = StackElement::Root;
- {
- TypeSystemTypeEntry* moduleEntry = reinterpret_cast<TypeSystemTypeEntry*>(
- m_database->findType(m_defaultPackage));
- element->entry = moduleEntry ? moduleEntry : new TypeSystemTypeEntry(m_defaultPackage, since);
- element->entry->setCodeGeneration(m_generate);
- }
-
- if ((m_generate == TypeEntry::GenerateForSubclass ||
- m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty())
- TypeDatabase::instance()->addRequiredTargetImport(m_defaultPackage);
-
- if (!element->entry->qualifiedCppName().isEmpty())
- m_database->addType(element->entry);
- break;
- case StackElement::LoadTypesystem: {
- QString name = attributes[nameAttribute()];
- if (name.isEmpty()) {
- m_error = QLatin1String("No typesystem name specified");
- return false;
- }
- bool generateChild = (convertBoolean(attributes[QLatin1String("generate")], QLatin1String("generate"), true) && (m_generate == TypeEntry::GenerateAll));
- if (!m_database->parseFile(name, m_currentPath, generateChild)) {
- m_error = QStringLiteral("Failed to parse: '%1'").arg(name);
- return false;
- }
- }
- break;
- case StackElement::RejectEnumValue:
- if (!m_currentEnum) {
- m_error = QLatin1String("<reject-enum-value> node must be used inside a <enum-type> node");
- return false;
- }
- break;
- case StackElement::ReplaceType: {
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("Type replacement can only be specified for argument modifications");
- return false;
- }
-
- if (attributes[QLatin1String("modified-type")].isEmpty()) {
- m_error = QLatin1String("Type replacement requires 'modified-type' attribute");
+ if (!Handler::parseCustomConversion(reader, topElement, &attributes))
return false;
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().modified_type = attributes[QLatin1String("modified-type")];
- }
- break;
- case StackElement::ConversionRule: {
- if (topElement.type != StackElement::ModifyArgument
- && topElement.type != StackElement::ValueTypeEntry
- && topElement.type != StackElement::PrimitiveTypeEntry
- && topElement.type != StackElement::ContainerTypeEntry) {
- m_error = QLatin1String("Conversion rules can only be specified for argument modification, "
- "value-type, primitive-type or container-type conversion.");
- return false;
- }
-
- static QHash<QString, TypeSystem::Language> languageNames;
- if (languageNames.isEmpty()) {
- languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode;
- languageNames[QLatin1String("native")] = TypeSystem::NativeCode;
- }
-
- QString languageAttribute = attributes[QLatin1String("class")].toLower();
- TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
-
- if (topElement.type == StackElement::ModifyArgument) {
- if (lang == TypeSystem::NoLanguage) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(lang);
- return false;
- }
-
- CodeSnip snip;
- snip.language = lang;
- m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.append(snip);
- } else {
- if (topElement.entry->hasConversionRule() || topElement.entry->hasCustomConversion()) {
- m_error = QLatin1String("Types can have only one conversion rule");
- return false;
- }
-
- // The old conversion rule tag that uses a file containing the conversion
- // will be kept temporarily for compatibility reasons.
- QString sourceFile = attributes[QLatin1String("file")];
- if (!sourceFile.isEmpty()) {
- if (m_generate != TypeEntry::GenerateForSubclass
- && m_generate != TypeEntry::GenerateNothing) {
-
- const char* conversionFlag = NATIVE_CONVERSION_RULE_FLAG;
- if (lang == TypeSystem::TargetLangCode)
- conversionFlag = TARGET_CONVERSION_RULE_FLAG;
-
- QFile conversionSource(sourceFile);
- if (conversionSource.open(QIODevice::ReadOnly | QIODevice::Text)) {
- topElement.entry->setConversionRule(QLatin1String(conversionFlag) + QString::fromUtf8(conversionSource.readAll()));
- } else {
- qCWarning(lcShiboken).noquote().nospace()
- << "File containing conversion code for "
- << topElement.entry->name() << " type does not exist or is not readable: "
- << sourceFile;
- }
- }
- }
-
- CustomConversion* customConversion = new CustomConversion(static_cast<TypeEntry*>(m_current->entry));
- customConversionsForReview.append(customConversion);
- }
- }
- break;
- case StackElement::NativeToTarget: {
+ break;
+ case StackElement::NativeToTarget:
if (topElement.type != StackElement::ConversionRule) {
m_error = QLatin1String("Native to Target conversion code can only be specified for custom conversion rules.");
return false;
}
m_contextStack.top()->codeSnips << CodeSnip();
- }
- break;
+ break;
case StackElement::TargetToNative: {
if (topElement.type != StackElement::ConversionRule) {
m_error = QLatin1String("Target to Native conversions can only be specified for custom conversion rules.");
return false;
}
- bool replace = attributes[QLatin1String("replace")] == yesAttributeValue();
- static_cast<TypeEntry*>(m_current->entry)->customConversion()->setReplaceOriginalTargetToNativeConversions(replace);
+ const int replaceIndex = indexOfAttribute(attributes, replaceAttribute());
+ const bool replace = replaceIndex == -1
+ || convertBoolean(attributes.takeAt(replaceIndex).value(),
+ replaceAttribute(), true);
+ m_current->entry->customConversion()->setReplaceOriginalTargetToNativeConversions(replace);
}
break;
- case StackElement::AddConversion: {
- if (topElement.type != StackElement::TargetToNative) {
- m_error = QLatin1String("Target to Native conversions can only be added inside 'target-to-native' tags.");
- return false;
- }
- QString sourceTypeName = attributes[QLatin1String("type")];
- if (sourceTypeName.isEmpty()) {
- m_error = QLatin1String("Target to Native conversions must specify the input type with the 'type' attribute.");
- return false;
- }
- QString typeCheck = attributes[QLatin1String("check")];
- static_cast<TypeEntry*>(m_current->entry)->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck);
- m_contextStack.top()->codeSnips << CodeSnip();
- }
- break;
- case StackElement::ModifyArgument: {
- if (topElement.type != StackElement::ModifyFunction
- && topElement.type != StackElement::AddFunction) {
- m_error = QString::fromLatin1("argument modification requires function"
- " modification as parent, was %1")
- .arg(topElement.type, 0, 16);
- return false;
- }
-
- QString index = attributes[QLatin1String("index")];
- if (index == QLatin1String("return"))
- index = QLatin1String("0");
- else if (index == QLatin1String("this"))
- index = QLatin1String("-1");
-
- bool ok = false;
- int idx = index.toInt(&ok);
- if (!ok) {
- m_error = QStringLiteral("Cannot convert '%1' to integer").arg(index);
- return false;
- }
-
- QString replace_value = attributes[QLatin1String("replace-value")];
-
- if (!replace_value.isEmpty() && idx) {
- m_error = QLatin1String("replace-value is only supported for return values (index=0).");
- return false;
- }
-
- ArgumentModification argumentModification = ArgumentModification(idx);
- argumentModification.replace_value = replace_value;
- argumentModification.resetAfterUse = convertBoolean(attributes[QLatin1String("invalidate-after-use")], QLatin1String("invalidate-after-use"), false);
- m_contextStack.top()->functionMods.last().argument_mods.append(argumentModification);
- }
- break;
- case StackElement::NoNullPointers: {
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("no-null-pointer requires argument modification as parent");
+ case StackElement::AddConversion:
+ if (!parseAddConversion(reader, topElement, &attributes))
return false;
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().noNullPointers = true;
- if (!m_contextStack.top()->functionMods.last().argument_mods.last().index)
- m_contextStack.top()->functionMods.last().argument_mods.last().nullPointerDefaultValue = attributes[QLatin1String("default-value")];
- else if (!attributes[QLatin1String("default-value")].isEmpty())
- qCWarning(lcShiboken) << "default values for null pointer guards are only effective for return values";
-
- }
- break;
- case StackElement::DefineOwnership: {
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("define-ownership requires argument modification as parent");
+ break;
+ case StackElement::ModifyArgument:
+ if (!parseModifyArgument(reader, topElement, &attributes))
return false;
- }
-
- static QHash<QString, TypeSystem::Language> languageNames;
- if (languageNames.isEmpty()) {
- languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode;
- languageNames[QLatin1String("native")] = TypeSystem::NativeCode;
- }
-
- QString classAttribute = attributes[QLatin1String("class")].toLower();
- TypeSystem::Language lang = languageNames.value(classAttribute, TypeSystem::NoLanguage);
- if (lang == TypeSystem::NoLanguage) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(classAttribute);
+ break;
+ case StackElement::NoNullPointers:
+ if (!parseNoNullPointer(reader, topElement, &attributes))
return false;
- }
-
- static QHash<QString, TypeSystem::Ownership> ownershipNames;
- if (ownershipNames.isEmpty()) {
- ownershipNames[QLatin1String("target")] = TypeSystem::TargetLangOwnership;
- ownershipNames[QLatin1String("c++")] = TypeSystem::CppOwnership;
- ownershipNames[QLatin1String("default")] = TypeSystem::DefaultOwnership;
- }
-
- QString ownershipAttribute = attributes[QLatin1String("owner")].toLower();
- TypeSystem::Ownership owner = ownershipNames.value(ownershipAttribute, TypeSystem::InvalidOwnership);
- if (owner == TypeSystem::InvalidOwnership) {
- m_error = QStringLiteral("unsupported owner attribute: '%1'").arg(ownershipAttribute);
+ break;
+ case StackElement::DefineOwnership:
+ if (!parseDefineOwnership(reader, topElement, &attributes))
return false;
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().ownerships[lang] = owner;
- }
- break;
+ break;
case StackElement::SuppressedWarning: {
- const QString suppressedWarning = attributes.value(textAttribute());
- if (suppressedWarning.isEmpty()) {
+ const int textIndex = indexOfAttribute(attributes, textAttribute());
+ if (textIndex == -1) {
qCWarning(lcShiboken) << "Suppressed warning with no text specified";
} else {
+ const QString suppressedWarning =
+ attributes.takeAt(textIndex).value().toString();
if (!m_database->addSuppressedWarning(suppressedWarning, &m_error))
return false;
}
}
break;
- case StackElement::ArgumentMap: {
- if (!(topElement.type & StackElement::CodeSnipMask)) {
- m_error = QLatin1String("Argument maps requires code injection as parent");
- return false;
- }
-
- bool ok;
- int pos = attributes[QLatin1String("index")].toInt(&ok);
- if (!ok) {
- m_error = QStringLiteral("Can't convert position '%1' to integer")
- .arg(attributes[QLatin1String("position")]);
- return false;
- }
-
- if (pos <= 0) {
- m_error = QStringLiteral("Argument position %1 must be a positive number").arg(pos);
- return false;
- }
-
- QString meta_name = attributes[QLatin1String("meta-name")];
- if (meta_name.isEmpty())
- qCWarning(lcShiboken) << "Empty meta name in argument map";
-
-
- if (topElement.type == StackElement::InjectCodeInFunction)
- m_contextStack.top()->functionMods.last().snips.last().argumentMap[pos] = meta_name;
- else {
- qCWarning(lcShiboken) << "Argument maps are only useful for injection of code "
- "into functions.";
- }
- }
- break;
- case StackElement::Removal: {
- if (topElement.type != StackElement::ModifyFunction) {
- m_error = QLatin1String("Function modification parent required");
+ case StackElement::ArgumentMap:
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUnimplementedElementWarning(reader, tagName)));
+ if (!parseArgumentMap(reader, topElement, &attributes))
return false;
- }
-
- static QHash<QString, TypeSystem::Language> languageNames;
- if (languageNames.isEmpty()) {
- languageNames.insert(QLatin1String("target"), TypeSystem::TargetLangAndNativeCode);
- languageNames.insert(QLatin1String("all"), TypeSystem::All);
- }
-
- QString languageAttribute = attributes[QLatin1String("class")].toLower();
- TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
- if (lang == TypeSystem::NoLanguage) {
- m_error = QStringLiteral("unsupported class attribute: '%1'").arg(languageAttribute);
+ break;
+ case StackElement::Removal:
+ if (!parseRemoval(reader, topElement, &attributes))
return false;
- }
-
- m_contextStack.top()->functionMods.last().removal = lang;
- }
- break;
+ break;
case StackElement::Rename:
- case StackElement::Access: {
- if (topElement.type != StackElement::ModifyField
- && topElement.type != StackElement::ModifyFunction
- && topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("Function, field or argument modification parent required");
- return false;
- }
-
- Modification *mod = 0;
- if (topElement.type == StackElement::ModifyFunction)
- mod = &m_contextStack.top()->functionMods.last();
- else if (topElement.type == StackElement::ModifyField)
- mod = &m_contextStack.top()->fieldMods.last();
-
- QString modifier;
- if (element->type == StackElement::Rename) {
- modifier = QLatin1String("rename");
- QString renamed_to = attributes[QLatin1String("to")];
- if (renamed_to.isEmpty()) {
- m_error = QLatin1String("Rename modifier requires 'to' attribute");
- return false;
- }
-
- if (topElement.type == StackElement::ModifyFunction)
- mod->setRenamedTo(renamed_to);
- else if (topElement.type == StackElement::ModifyField)
- mod->setRenamedTo(renamed_to);
- else
- m_contextStack.top()->functionMods.last().argument_mods.last().renamed_to = renamed_to;
- } else
- modifier = attributes[QLatin1String("modifier")].toLower();
-
-
- if (modifier.isEmpty()) {
- m_error = QLatin1String("No access modification specified");
- return false;
- }
-
- static QHash<QString, FunctionModification::Modifiers> modifierNames;
- if (modifierNames.isEmpty()) {
- modifierNames[QLatin1String("private")] = Modification::Private;
- modifierNames[QLatin1String("public")] = Modification::Public;
- modifierNames[QLatin1String("protected")] = Modification::Protected;
- modifierNames[QLatin1String("friendly")] = Modification::Friendly;
- modifierNames[QLatin1String("rename")] = Modification::Rename;
- modifierNames[QLatin1String("final")] = Modification::Final;
- modifierNames[QLatin1String("non-final")] = Modification::NonFinal;
- }
-
- if (!modifierNames.contains(modifier)) {
- m_error = QStringLiteral("Unknown access modifier: '%1'").arg(modifier);
+ case StackElement::Access:
+ if (!parseRename(reader, element->type, topElement, &attributes))
return false;
- }
-
- if (mod)
- mod->modifiers |= modifierNames[modifier];
- }
- break;
+ break;
case StackElement::RemoveArgument:
if (topElement.type != StackElement::ModifyArgument) {
m_error = QLatin1String("Removing argument requires argument modification as parent");
@@ -1691,229 +2730,38 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
m_contextStack.top()->functionMods.last().argument_mods.last().removed = true;
break;
- case StackElement::ModifyField: {
- QString name = attributes[nameAttribute()];
- if (name.isEmpty())
- break;
- FieldModification fm;
- fm.name = name;
- fm.modifiers = 0;
-
- if (!convertRemovalAttribute(attributes[QLatin1String("remove")], fm, m_error))
- return false;
-
- QString read = attributes[QLatin1String("read")];
- QString write = attributes[QLatin1String("write")];
-
- if (read == trueAttributeValue()) fm.modifiers |= FieldModification::Readable;
- if (write == trueAttributeValue()) fm.modifiers |= FieldModification::Writable;
-
- m_contextStack.top()->fieldMods << fm;
- }
- break;
- case StackElement::AddFunction: {
- if (!(topElement.type & (StackElement::ComplexTypeEntryMask | StackElement::Root))) {
- m_error = QString::fromLatin1("Add function requires a complex type or a root tag as parent"
- ", was=%1").arg(topElement.type, 0, 16);
- return false;
- }
- const QString originalSignature = attributes[QLatin1String("signature")];
-
- QString signature = TypeDatabase::normalizedSignature(originalSignature);
- if (signature.isEmpty()) {
- m_error = QLatin1String("No signature for the added function");
- return false;
- }
-
- QString errorString = checkSignatureError(signature, QLatin1String("add-function"));
- if (!errorString.isEmpty()) {
- m_error = errorString;
- return false;
- }
-
- AddedFunction func(signature, attributes[QLatin1String("return-type")]);
- func.setStatic(attributes[QLatin1String("static")] == yesAttributeValue());
- if (!signature.contains(QLatin1Char('(')))
- signature += QLatin1String("()");
- m_currentSignature = signature;
-
- QString access = attributes[QLatin1String("access")].toLower();
- if (!access.isEmpty()) {
- if (access == QLatin1String("protected")) {
- func.setAccess(AddedFunction::Protected);
- } else if (access == QLatin1String("public")) {
- func.setAccess(AddedFunction::Public);
- } else {
- m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
- return false;
- }
- }
-
- m_contextStack.top()->addedFunctions << func;
-
- FunctionModification mod;
- if (!mod.setSignature(m_currentSignature, &m_error))
- return false;
- mod.setOriginalSignature(originalSignature);
- m_contextStack.top()->functionMods << mod;
- }
- break;
- case StackElement::ModifyFunction: {
- if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
- m_error = QString::fromLatin1("Modify function requires complex type as parent"
- ", was=%1").arg(topElement.type, 0, 16);
- return false;
- }
- const QString originalSignature = attributes[QLatin1String("signature")];
-
- const QString signature = TypeDatabase::normalizedSignature(originalSignature);
- if (signature.isEmpty()) {
- m_error = QLatin1String("No signature for modified function");
- return false;
- }
-
- QString errorString = checkSignatureError(signature, QLatin1String("modify-function"));
- if (!errorString.isEmpty()) {
- m_error = errorString;
+ case StackElement::ModifyField:
+ if (!parseModifyField(reader, &attributes))
return false;
- }
-
- FunctionModification mod;
- if (!mod.setSignature(signature, &m_error))
+ break;
+ case StackElement::AddFunction:
+ if (!parseAddFunction(reader, topElement, &attributes))
return false;
- mod.setOriginalSignature(originalSignature);
- m_currentSignature = signature;
-
- QString access = attributes[QLatin1String("access")].toLower();
- if (!access.isEmpty()) {
- if (access == QLatin1String("private"))
- mod.modifiers |= Modification::Private;
- else if (access == QLatin1String("protected"))
- mod.modifiers |= Modification::Protected;
- else if (access == QLatin1String("public"))
- mod.modifiers |= Modification::Public;
- else if (access == QLatin1String("final"))
- mod.modifiers |= Modification::Final;
- else if (access == QLatin1String("non-final"))
- mod.modifiers |= Modification::NonFinal;
- else {
- m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
- return false;
- }
- }
-
- if (convertBoolean(attributes[QLatin1String("deprecated")], QLatin1String("deprecated"), false))
- mod.modifiers |= Modification::Deprecated;
-
- if (!convertRemovalAttribute(attributes[QLatin1String("remove")], mod, m_error))
+ break;
+ case StackElement::ModifyFunction:
+ if (!parseModifyFunction(reader, topElement, &attributes))
return false;
-
- QString rename = attributes[QLatin1String("rename")];
- if (!rename.isEmpty()) {
- mod.renamedToName = rename;
- mod.modifiers |= Modification::Rename;
- }
-
- QString association = attributes[QLatin1String("associated-to")];
- if (!association.isEmpty())
- mod.association = association;
-
- mod.setIsThread(convertBoolean(attributes[QLatin1String("thread")], QLatin1String("thread"), false));
- mod.setAllowThread(convertBoolean(attributes[QLatin1String("allow-thread")], QLatin1String("allow-thread"), false));
-
- mod.modifiers |= (convertBoolean(attributes[QLatin1String("virtual-slot")], QLatin1String("virtual-slot"), false) ? Modification::VirtualSlot : 0);
-
- m_contextStack.top()->functionMods << mod;
- }
- break;
+ break;
case StackElement::ReplaceDefaultExpression:
- if (!(topElement.type & StackElement::ModifyArgument)) {
- m_error = QLatin1String("Replace default expression only allowed as child of argument modification");
- return false;
- }
-
- if (attributes[QLatin1String("with")].isEmpty()) {
- m_error = QLatin1String("Default expression replaced with empty string. Use remove-default-expression instead.");
+ if (!parseReplaceDefaultExpression(reader, topElement, &attributes))
return false;
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().replacedDefaultExpression = attributes[QLatin1String("with")];
break;
case StackElement::RemoveDefaultExpression:
m_contextStack.top()->functionMods.last().argument_mods.last().removedDefaultExpression = true;
break;
case StackElement::CustomMetaConstructor:
- case StackElement::CustomMetaDestructor: {
- CustomFunction *func = new CustomFunction(attributes[nameAttribute()]);
- func->paramName = attributes[QLatin1String("param-name")];
- element->value.customFunction = func;
- }
- break;
- case StackElement::ReferenceCount: {
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("reference-count must be child of modify-argument");
- return false;
- }
-
- ReferenceCount rc;
-
- static QHash<QString, ReferenceCount::Action> actions;
- if (actions.isEmpty()) {
- actions[QLatin1String("add")] = ReferenceCount::Add;
- actions[QLatin1String("add-all")] = ReferenceCount::AddAll;
- actions[QLatin1String("remove")] = ReferenceCount::Remove;
- actions[QLatin1String("set")] = ReferenceCount::Set;
- actions[QLatin1String("ignore")] = ReferenceCount::Ignore;
- }
- rc.action = actions.value(attributes[QLatin1String("action")].toLower(), ReferenceCount::Invalid);
- rc.varName = attributes[QLatin1String("variable-name")];
-
- if (rc.action == ReferenceCount::Invalid) {
- m_error = QLatin1String("unrecognized value for action attribute. supported actions:");
- for (QHash<QString, ReferenceCount::Action>::const_iterator it = actions.cbegin(), end = actions.cend(); it != end; ++it)
- m_error += QLatin1Char(' ') + it.key();
- }
-
- m_contextStack.top()->functionMods.last().argument_mods.last().referenceCounts.append(rc);
- }
- break;
-
- case StackElement::ParentOwner: {
- if (topElement.type != StackElement::ModifyArgument) {
- m_error = QLatin1String("parent-policy must be child of modify-argument");
- return false;
- }
-
- ArgumentOwner ao;
-
- QString index = attributes[QLatin1String("index")];
- if (index == QLatin1String("return"))
- index = QLatin1String("0");
- else if (index == QLatin1String("this"))
- index = QLatin1String("-1");
-
- bool ok = false;
- int idx = index.toInt(&ok);
- if (!ok) {
- m_error = QStringLiteral("Cannot convert '%1' to integer").arg(index);
+ case StackElement::CustomMetaDestructor:
+ element->value.customFunction =
+ parseCustomMetaConstructor(reader, element->type, topElement, &attributes);
+ break;
+ case StackElement::ReferenceCount:
+ if (!parseReferenceCount(reader, topElement, &attributes))
return false;
- }
-
- static QHash<QString, ArgumentOwner::Action> actions;
- if (actions.isEmpty()) {
- actions[QLatin1String("add")] = ArgumentOwner::Add;
- actions[QLatin1String("remove")] = ArgumentOwner::Remove;
- }
-
- ao.action = actions.value(attributes[QLatin1String("action")].toLower(), ArgumentOwner::Invalid);
- if (!ao.action) {
- m_error = QLatin1String("Invalid parent actionr");
+ break;
+ case StackElement::ParentOwner:
+ if (!parseParentOwner(reader, topElement, &attributes))
return false;
- }
- ao.index = idx;
- m_contextStack.top()->functionMods.last().argument_mods.last().owner = ao;
- }
- break;
+ break;
case StackElement::Array:
if (topElement.type != StackElement::ModifyArgument) {
m_error = QLatin1String("array must be child of modify-argument");
@@ -1921,185 +2769,54 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts
}
m_contextStack.top()->functionMods.last().argument_mods.last().array = true;
break;
- case StackElement::InjectCode: {
- if (!(topElement.type & StackElement::ComplexTypeEntryMask)
- && (topElement.type != StackElement::AddFunction)
- && (topElement.type != StackElement::ModifyFunction)
- && (topElement.type != StackElement::Root)) {
- m_error = QLatin1String("wrong parent type for code injection");
- return false;
- }
-
- static QHash<QString, TypeSystem::Language> languageNames;
- if (languageNames.isEmpty()) {
- languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode; // em algum lugar do cpp
- languageNames[QLatin1String("native")] = TypeSystem::NativeCode; // em algum lugar do cpp
- languageNames[QLatin1String("shell")] = TypeSystem::ShellCode; // coloca no header, mas antes da declaracao da classe
- languageNames[QLatin1String("shell-declaration")] = TypeSystem::ShellDeclaration; // coloca no header, dentro da declaracao da classe
- languageNames[QLatin1String("library-initializer")] = TypeSystem::PackageInitializer;
- languageNames[QLatin1String("destructor-function")] = TypeSystem::DestructorFunction;
- languageNames[QLatin1String("constructors")] = TypeSystem::Constructors;
- languageNames[QLatin1String("interface")] = TypeSystem::Interface;
- }
-
- QString className = attributes[QLatin1String("class")].toLower();
- if (!languageNames.contains(className)) {
- m_error = QStringLiteral("Invalid class specifier: '%1'").arg(className);
- return false;
- }
-
-
- static QHash<QString, TypeSystem::CodeSnipPosition> positionNames;
- if (positionNames.isEmpty()) {
- positionNames.insert(QLatin1String("beginning"), TypeSystem::CodeSnipPositionBeginning);
- positionNames.insert(QLatin1String("end"), TypeSystem::CodeSnipPositionEnd);
- // QtScript
- positionNames.insert(QLatin1String("declaration"), TypeSystem::CodeSnipPositionDeclaration);
- positionNames.insert(QLatin1String("prototype-initialization"), TypeSystem::CodeSnipPositionPrototypeInitialization);
- positionNames.insert(QLatin1String("constructor-initialization"), TypeSystem::CodeSnipPositionConstructorInitialization);
- positionNames.insert(QLatin1String("constructor"), TypeSystem::CodeSnipPositionConstructor);
- }
-
- QString position = attributes[QLatin1String("position")].toLower();
- if (!positionNames.contains(position)) {
- m_error = QStringLiteral("Invalid position: '%1'").arg(position);
+ case StackElement::InjectCode:
+ if (!parseInjectCode(reader, topElement, element, &attributes))
return false;
- }
-
- CodeSnip snip;
- snip.language = languageNames[className];
- snip.position = positionNames[position];
- bool in_file = false;
-
- QString file_name = attributes[QLatin1String("file")];
-
- //Handler constructor....
- if (m_generate != TypeEntry::GenerateForSubclass &&
- m_generate != TypeEntry::GenerateNothing &&
- !file_name.isEmpty()) {
- const QString resolved = m_database->modifiedTypesystemFilepath(file_name, m_currentPath);
- if (QFile::exists(resolved)) {
- QFile codeFile(resolved);
- if (codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
- QString content = QLatin1String("// ========================================================================\n"
- "// START of custom code block [file: ");
- content += file_name;
- content += QLatin1String("]\n");
- content += QString::fromUtf8(codeFile.readAll());
- content += QLatin1String("\n// END of custom code block [file: ");
- content += file_name;
- content += QLatin1String("]\n// ========================================================================\n");
- snip.addCode(content);
- in_file = true;
- }
- } else {
- qCWarning(lcShiboken).noquote().nospace()
- << "File for inject code not exist: " << QDir::toNativeSeparators(file_name);
- }
-
- }
-
- if (snip.language == TypeSystem::Interface && topElement.type != StackElement::InterfaceTypeEntry) {
- m_error = QLatin1String("Interface code injections must be direct child of an interface type entry");
+ break;
+ case StackElement::Include:
+ if (!parseInclude(reader, topElement, element->entry, &attributes))
return false;
- }
-
- if (topElement.type == StackElement::ModifyFunction || topElement.type == StackElement::AddFunction) {
- FunctionModification mod = m_contextStack.top()->functionMods.constLast();
- if (snip.language == TypeSystem::ShellDeclaration) {
- m_error = QLatin1String("no function implementation in shell declaration in which to inject code");
- return false;
- }
-
- m_contextStack.top()->functionMods.last().snips << snip;
- if (in_file)
- m_contextStack.top()->functionMods.last().modifiers |= FunctionModification::CodeInjection;
- element->type = StackElement::InjectCodeInFunction;
- } else if (topElement.type == StackElement::Root) {
- element->entry->addCodeSnip(snip);
- } else if (topElement.type != StackElement::Root) {
- m_contextStack.top()->codeSnips << snip;
- }
-
- }
- break;
- case StackElement::Include: {
- QString location = attributes[QLatin1String("location")].toLower();
-
- static QHash<QString, Include::IncludeType> locationNames;
- if (locationNames.isEmpty()) {
- locationNames[QLatin1String("global")] = Include::IncludePath;
- locationNames[QLatin1String("local")] = Include::LocalPath;
- locationNames[QLatin1String("target")] = Include::TargetLangImport;
- }
-
- if (!locationNames.contains(location)) {
- m_error = QStringLiteral("Location not recognized: '%1'").arg(location);
+ break;
+ case StackElement::Rejection:
+ if (!addRejection(m_database, &attributes, &m_error))
return false;
- }
-
- Include::IncludeType loc = locationNames[location];
- Include inc(loc, attributes[QLatin1String("file-name")]);
-
- ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
- if (topElement.type & (StackElement::ComplexTypeEntryMask | StackElement::PrimitiveTypeEntry)) {
- element->entry->setInclude(inc);
- } else if (topElement.type == StackElement::ExtraIncludes) {
- element->entry->addExtraInclude(inc);
- } else {
- m_error = QLatin1String("Only supported parent tags are primitive-type, complex types or extra-includes");
+ break;
+ case StackElement::Template: {
+ const int nameIndex = indexOfAttribute(attributes, nameAttribute());
+ if (nameIndex == -1) {
+ m_error = msgMissingAttribute(nameAttribute());
return false;
}
-
- inc = ctype->include();
- IncludeList lst = ctype->extraIncludes();
- ctype = ctype->designatedInterface();
- if (ctype) {
- ctype->setExtraIncludes(lst);
- ctype->setInclude(inc);
- }
+ element->value.templateEntry =
+ new TemplateEntry(attributes.takeAt(nameIndex).value().toString());
}
- break;
- case StackElement::Rejection:
- if (!addRejection(m_database, attributes, &m_error))
- return false;
- break;
- case StackElement::Template:
- element->value.templateEntry = new TemplateEntry(attributes.value(nameAttribute()));
break;
case StackElement::TemplateInstanceEnum:
- if (!(topElement.type & StackElement::CodeSnipMask) &&
- (topElement.type != StackElement::Template) &&
- (topElement.type != StackElement::CustomMetaConstructor) &&
- (topElement.type != StackElement::CustomMetaDestructor) &&
- (topElement.type != StackElement::NativeToTarget) &&
- (topElement.type != StackElement::AddConversion) &&
- (topElement.type != StackElement::ConversionRule)) {
- m_error = QLatin1String("Can only insert templates into code snippets, templates, custom-constructors, "\
- "custom-destructors, conversion-rule, native-to-target or add-conversion tags.");
+ element->value.templateInstance =
+ parseTemplateInstanceEnum(reader, topElement, &attributes);
+ if (!element->value.templateInstance)
return false;
- }
- element->value.templateInstance = new TemplateInstance(attributes.value(nameAttribute()));
break;
case StackElement::Replace:
- if (topElement.type != StackElement::TemplateInstanceEnum) {
- m_error = QLatin1String("Can only insert replace rules into insert-template.");
+ if (!parseReplace(reader, topElement, element, &attributes))
return false;
- }
- element->parent->value.templateInstance->addReplaceRule(attributes[QLatin1String("from")], attributes[QLatin1String("to")]);
break;
default:
break; // nada
};
}
+ if (!attributes.isEmpty()) {
+ const QString message = msgUnusedAttributes(tagName, attributes);
+ qCWarning(lcShiboken, "%s", qPrintable(msgReaderWarning(reader, message)));
+ }
+
m_current = element;
return true;
}
PrimitiveTypeEntry::PrimitiveTypeEntry(const QString &name, const QVersionNumber &vr) :
TypeEntry(name, PrimitiveType, vr),
- m_preferredConversion(true),
m_preferredTargetLangType(true)
{
}
@@ -2120,35 +2837,15 @@ PrimitiveTypeEntry *PrimitiveTypeEntry::basicReferencedTypeEntry() const
return 0;
PrimitiveTypeEntry *baseReferencedTypeEntry = m_referencedTypeEntry->basicReferencedTypeEntry();
- if (baseReferencedTypeEntry)
- return baseReferencedTypeEntry;
- else
- return m_referencedTypeEntry;
-}
-
-bool PrimitiveTypeEntry::preferredConversion() const
-{
- return m_preferredConversion;
+ return baseReferencedTypeEntry ? baseReferencedTypeEntry : m_referencedTypeEntry;
}
-void PrimitiveTypeEntry::setPreferredConversion(bool b)
+TypeEntry *PrimitiveTypeEntry::clone() const
{
- m_preferredConversion = b;
+ return new PrimitiveTypeEntry(*this);
}
-typedef QHash<const PrimitiveTypeEntry*, QString> PrimitiveTypeEntryTargetLangPackageMap;
-Q_GLOBAL_STATIC(PrimitiveTypeEntryTargetLangPackageMap, primitiveTypeEntryTargetLangPackages);
-
-void PrimitiveTypeEntry::setTargetLangPackage(const QString& package)
-{
- primitiveTypeEntryTargetLangPackages()->insert(this, package);
-}
-QString PrimitiveTypeEntry::targetLangPackage() const
-{
- if (!primitiveTypeEntryTargetLangPackages()->contains(this))
- return this->::TypeEntry::targetLangPackage();
- return primitiveTypeEntryTargetLangPackages()->value(this);
-}
+PrimitiveTypeEntry::PrimitiveTypeEntry(const PrimitiveTypeEntry &) = default;
CodeSnipList TypeEntry::codeSnips() const
{
@@ -2186,42 +2883,42 @@ FieldModification ComplexTypeEntry::fieldModification(const QString &name) const
return mod;
}
-QString ComplexTypeEntry::targetLangPackage() const
-{
- return m_package;
-}
-
QString ComplexTypeEntry::targetLangName() const
{
return m_targetLangName.isEmpty() ?
TypeEntry::targetLangName() : m_targetLangName;
}
-// The things we do not to break the ABI...
-typedef QHash<const ComplexTypeEntry*, QString> ComplexTypeEntryDefaultConstructorMap;
-Q_GLOBAL_STATIC(ComplexTypeEntryDefaultConstructorMap, complexTypeEntryDefaultConstructors);
-
void ComplexTypeEntry::setDefaultConstructor(const QString& defaultConstructor)
{
- if (!defaultConstructor.isEmpty())
- complexTypeEntryDefaultConstructors()->insert(this, defaultConstructor);
+ m_defaultConstructor = defaultConstructor;
}
QString ComplexTypeEntry::defaultConstructor() const
{
- if (!complexTypeEntryDefaultConstructors()->contains(this))
- return QString();
- return complexTypeEntryDefaultConstructors()->value(this);
+ return m_defaultConstructor;
}
bool ComplexTypeEntry::hasDefaultConstructor() const
{
- return complexTypeEntryDefaultConstructors()->contains(this);
+ return !m_defaultConstructor.isEmpty();
}
-QString ContainerTypeEntry::targetLangPackage() const
+TypeEntry *ComplexTypeEntry::clone() const
{
- return QString();
+ return new ComplexTypeEntry(*this);
}
+// Take over parameters relevant for typedefs
+void ComplexTypeEntry::useAsTypedef(const ComplexTypeEntry *source)
+{
+ TypeEntry::useAsTypedef(source);
+ m_qualifiedCppName = source->m_qualifiedCppName;
+ m_targetLangName = source->m_targetLangName;
+ m_lookupName = source->m_lookupName;
+ m_targetType = source->m_targetType;
+}
+
+ComplexTypeEntry::ComplexTypeEntry(const ComplexTypeEntry &) = default;
+
QString ContainerTypeEntry::targetLangName() const
{
@@ -2252,13 +2949,17 @@ QString ContainerTypeEntry::qualifiedCppName() const
return ComplexTypeEntry::qualifiedCppName();
}
+TypeEntry *ContainerTypeEntry::clone() const
+{
+ return new ContainerTypeEntry(*this);
+}
+
+ContainerTypeEntry::ContainerTypeEntry(const ContainerTypeEntry &) = default;
+
QString EnumTypeEntry::targetLangQualifier() const
{
TypeEntry *te = TypeDatabase::instance()->findType(m_qualifier);
- if (te)
- return te->targetLangName();
- else
- return m_qualifier;
+ return te ? te->targetLangName() : m_qualifier;
}
QString EnumTypeEntry::qualifiedTargetLangName() const
@@ -2281,26 +2982,25 @@ QString EnumTypeEntry::targetLangApiName() const
return QLatin1String("jint");
}
-bool EnumTypeEntry::preferredConversion() const
-{
- return false;
-}
-
QString FlagsTypeEntry::targetLangApiName() const
{
return QLatin1String("jint");
}
-bool FlagsTypeEntry::preferredConversion() const
+TypeEntry *EnumTypeEntry::clone() const
{
- return false;
+ return new EnumTypeEntry(*this);
}
-QString FlagsTypeEntry::targetLangPackage() const
+EnumTypeEntry::EnumTypeEntry(const EnumTypeEntry &) = default;
+
+TypeEntry *FlagsTypeEntry::clone() const
{
- return m_enum->targetLangPackage();
+ return new FlagsTypeEntry(*this);
}
+FlagsTypeEntry::FlagsTypeEntry(const FlagsTypeEntry &) = default;
+
QString FlagsTypeEntry::qualifiedTargetLangName() const
{
return targetLangPackage() + QLatin1Char('.') + m_enum->targetLangQualifier()
@@ -2320,7 +3020,7 @@ QString fixCppTypeName(const QString &name)
{
if (name == QLatin1String("long long"))
return QLatin1String("qint64");
- else if (name == QLatin1String("unsigned long long"))
+ if (name == QLatin1String("unsigned long long"))
return QLatin1String("quint64");
return name;
}
@@ -2341,11 +3041,9 @@ QString TemplateInstance::expandCode() const
result += code;
result += QLatin1String("\n// TEMPLATE - ") + m_name + QLatin1String(" - END");
return result;
- } else {
- qCWarning(lcShiboken).noquote().nospace()
- << "insert-template referring to non-existing template '" << m_name << '\'';
}
-
+ qCWarning(lcShiboken).noquote().nospace()
+ << "insert-template referring to non-existing template '" << m_name << '\'';
return QString();
}
@@ -2361,10 +3059,7 @@ QString CodeSnipAbstract::code() const
QString CodeSnipFragment::code() const
{
- if (m_instance)
- return m_instance->expandCode();
- else
- return m_code;
+ return m_instance ? m_instance->expandCode() : m_code;
}
bool FunctionModification::setSignature(const QString &s, QString *errorMessage)
@@ -2556,11 +3251,12 @@ AddedFunction::TypeInfo AddedFunction::TypeInfo::fromSignature(const QString& si
ComplexTypeEntry::ComplexTypeEntry(const QString &name, TypeEntry::Type t,
const QVersionNumber &vr) :
- TypeEntry(QString(name).replace(QLatin1String(".*::"), QString()), t, vr),
+ TypeEntry(name, t, vr),
m_qualifiedCppName(name),
m_qobject(false),
m_polymorphicBase(false),
- m_genericClass(false)
+ m_genericClass(false),
+ m_deleteInMainThread(false)
{
}
@@ -2578,71 +3274,6 @@ QString ComplexTypeEntry::targetLangApiName() const
{
return strings_jobject;
}
-QString StringTypeEntry::targetLangApiName() const
-{
- return strings_jobject;
-}
-QString StringTypeEntry::targetLangName() const
-{
- return strings_String;
-}
-QString StringTypeEntry::targetLangPackage() const
-{
- return QString();
-}
-
-bool StringTypeEntry::isNativeIdBased() const
-{
- return false;
-}
-
-CharTypeEntry::CharTypeEntry(const QString &name, const QVersionNumber &vr) :
- ValueTypeEntry(name, CharType, vr)
-{
- setCodeGeneration(GenerateNothing);
-}
-
-QString CharTypeEntry::targetLangApiName() const
-{
- return strings_jchar;
-}
-QString CharTypeEntry::targetLangName() const
-{
- return strings_char;
-}
-
-QString CharTypeEntry::targetLangPackage() const
-{
- return QString();
-}
-
-bool CharTypeEntry::isNativeIdBased() const
-{
- return false;
-}
-
-VariantTypeEntry::VariantTypeEntry(const QString &name, const QVersionNumber &vr) :
- ValueTypeEntry(name, VariantType, vr)
-{
-}
-
-QString VariantTypeEntry::targetLangApiName() const
-{
- return strings_jobject;
-}
-QString VariantTypeEntry::targetLangName() const
-{
- return strings_Object;
-}
-QString VariantTypeEntry::targetLangPackage() const
-{
- return QString();
-}
-
-bool VariantTypeEntry::isNativeIdBased() const
-{
- return false;
-}
QString ContainerTypeEntry::typeName() const
{
@@ -2706,10 +3337,6 @@ bool TypeEntry::isCppPrimitive() const
return typeName.contains(QLatin1Char(' ')) || primitiveCppTypes().contains(typeName);
}
-// Again, stuff to avoid ABI breakage.
-typedef QHash<const TypeEntry*, CustomConversion*> TypeEntryCustomConversionMap;
-Q_GLOBAL_STATIC(TypeEntryCustomConversionMap, typeEntryCustomConversionMap);
-
TypeEntry::TypeEntry(const QString &name, TypeEntry::Type t, const QVersionNumber &vr) :
m_name(name),
m_type(t),
@@ -2719,51 +3346,88 @@ TypeEntry::TypeEntry(const QString &name, TypeEntry::Type t, const QVersionNumbe
TypeEntry::~TypeEntry()
{
- if (typeEntryCustomConversionMap()->contains(this)) {
- CustomConversion* customConversion = typeEntryCustomConversionMap()->value(this);
- typeEntryCustomConversionMap()->remove(this);
- delete customConversion;
- }
+ delete m_customConversion;
}
bool TypeEntry::hasCustomConversion() const
{
- return typeEntryCustomConversionMap()->contains(this);
+ return m_customConversion != nullptr;
}
+
void TypeEntry::setCustomConversion(CustomConversion* customConversion)
{
- if (customConversion)
- typeEntryCustomConversionMap()->insert(this, customConversion);
- else if (typeEntryCustomConversionMap()->contains(this))
- typeEntryCustomConversionMap()->remove(this);
+ m_customConversion = customConversion;
}
+
CustomConversion* TypeEntry::customConversion() const
{
- if (typeEntryCustomConversionMap()->contains(this))
- return typeEntryCustomConversionMap()->value(this);
- return 0;
+ return m_customConversion;
+}
+
+TypeEntry *TypeEntry::clone() const
+{
+ return new TypeEntry(*this);
}
+// Take over parameters relevant for typedefs
+void TypeEntry::useAsTypedef(const TypeEntry *source)
+{
+ m_name = source->m_name;
+ m_targetLangPackage = source->m_targetLangPackage;
+ m_codeGeneration = source->m_codeGeneration;
+ m_version = source->m_version;
+}
+
+TypeEntry::TypeEntry(const TypeEntry &) = default;
+
TypeSystemTypeEntry::TypeSystemTypeEntry(const QString &name, const QVersionNumber &vr) :
TypeEntry(name, TypeSystemType, vr)
{
}
+TypeEntry *TypeSystemTypeEntry::clone() const
+{
+ return new TypeSystemTypeEntry(*this);
+}
+
+TypeSystemTypeEntry::TypeSystemTypeEntry(const TypeSystemTypeEntry &) = default;
+
VoidTypeEntry::VoidTypeEntry() :
TypeEntry(QLatin1String("void"), VoidType, QVersionNumber(0, 0))
{
}
+TypeEntry *VoidTypeEntry::clone() const
+{
+ return new VoidTypeEntry(*this);
+}
+
+VoidTypeEntry::VoidTypeEntry(const VoidTypeEntry &) = default;
+
VarargsTypeEntry::VarargsTypeEntry() :
TypeEntry(QLatin1String("..."), VarargsType, QVersionNumber(0, 0))
{
}
+TypeEntry *VarargsTypeEntry::clone() const
+{
+ return new VarargsTypeEntry(*this);
+}
+
+VarargsTypeEntry::VarargsTypeEntry(const VarargsTypeEntry &) = default;
+
TemplateArgumentEntry::TemplateArgumentEntry(const QString &name, const QVersionNumber &vr) :
TypeEntry(name, TemplateArgumentType, vr)
{
}
+TypeEntry *TemplateArgumentEntry::clone() const
+{
+ return new TemplateArgumentEntry(*this);
+}
+
+TemplateArgumentEntry::TemplateArgumentEntry(const TemplateArgumentEntry &) = default;
+
ArrayTypeEntry::ArrayTypeEntry(const TypeEntry *nested_type, const QVersionNumber &vr) :
TypeEntry(QLatin1String("Array"), ArrayType, vr),
m_nestedType(nested_type)
@@ -2778,12 +3442,18 @@ QString ArrayTypeEntry::targetLangName() const
QString ArrayTypeEntry::targetLangApiName() const
{
- if (m_nestedType->isPrimitive())
- return m_nestedType->targetLangApiName() + QLatin1String("Array");
- else
- return QLatin1String("jobjectArray");
+ return m_nestedType->isPrimitive()
+ ? m_nestedType->targetLangApiName() + QLatin1String("Array")
+ : QLatin1String("jobjectArray");
+}
+
+TypeEntry *ArrayTypeEntry::clone() const
+{
+ return new ArrayTypeEntry(*this);
}
+ArrayTypeEntry::ArrayTypeEntry(const ArrayTypeEntry &) = default;
+
EnumTypeEntry::EnumTypeEntry(const QString &nspace, const QString &enumName,
const QVersionNumber &vr) :
TypeEntry(nspace.isEmpty() ? enumName : nspace + QLatin1String("::") + enumName,
@@ -2793,16 +3463,6 @@ EnumTypeEntry::EnumTypeEntry(const QString &nspace, const QString &enumName,
{
}
-QString EnumTypeEntry::targetLangPackage() const
-{
- return m_packageName;
-}
-
-void EnumTypeEntry::setTargetLangPackage(const QString &package)
-{
- m_packageName = package;
-}
-
QString EnumTypeEntry::targetLangName() const
{
return m_targetLangName;
@@ -2817,11 +3477,34 @@ EnumValueTypeEntry::EnumValueTypeEntry(const QString &name, const QString &value
{
}
+TypeEntry *EnumValueTypeEntry::clone() const
+{
+ return new EnumValueTypeEntry(*this);
+}
+
+EnumValueTypeEntry::EnumValueTypeEntry(const EnumValueTypeEntry &) = default;
+
FlagsTypeEntry::FlagsTypeEntry(const QString &name, const QVersionNumber &vr) :
TypeEntry(name, FlagsType, vr)
{
}
+/* A typedef entry allows for specifying template specializations in the
+ * typesystem XML file. */
+TypedefEntry::TypedefEntry(const QString &name, const QString &sourceType,
+ const QVersionNumber &vr) :
+ ComplexTypeEntry(name, TypedefType, vr),
+ m_sourceType(sourceType)
+{
+}
+
+TypeEntry *TypedefEntry::clone() const
+{
+ return new TypedefEntry(*this);
+}
+
+TypedefEntry::TypedefEntry(const TypedefEntry &) = default;
+
ContainerTypeEntry::ContainerTypeEntry(const QString &name, Type type,
const QVersionNumber &vr) :
ComplexTypeEntry(name, ContainerType, vr),
@@ -2842,11 +3525,25 @@ SmartPointerTypeEntry::SmartPointerTypeEntry(const QString &name,
{
}
+TypeEntry *SmartPointerTypeEntry::clone() const
+{
+ return new SmartPointerTypeEntry(*this);
+}
+
+SmartPointerTypeEntry::SmartPointerTypeEntry(const SmartPointerTypeEntry &) = default;
+
NamespaceTypeEntry::NamespaceTypeEntry(const QString &name, const QVersionNumber &vr) :
ComplexTypeEntry(name, NamespaceType, vr)
{
}
+TypeEntry *NamespaceTypeEntry::clone() const
+{
+ return new NamespaceTypeEntry(*this);
+}
+
+NamespaceTypeEntry::NamespaceTypeEntry(const NamespaceTypeEntry &) = default;
+
ValueTypeEntry::ValueTypeEntry(const QString &name, const QVersionNumber &vr) :
ComplexTypeEntry(name, BasicValueType, vr)
{
@@ -2862,35 +3559,17 @@ bool ValueTypeEntry::isNativeIdBased() const
return true;
}
-ValueTypeEntry::ValueTypeEntry(const QString &name, Type t, const QVersionNumber &vr) :
- ComplexTypeEntry(name, t, vr)
+TypeEntry *ValueTypeEntry::clone() const
{
+ return new ValueTypeEntry(*this);
}
-StringTypeEntry::StringTypeEntry(const QString &name, const QVersionNumber &vr) :
- ValueTypeEntry(name, StringType, vr)
-{
- setCodeGeneration(GenerateNothing);
-}
+ValueTypeEntry::ValueTypeEntry(const ValueTypeEntry &) = default;
-/*
-static void injectCode(ComplexTypeEntry *e,
- const char *signature,
- const QByteArray &code,
- const ArgumentMap &args)
+ValueTypeEntry::ValueTypeEntry(const QString &name, Type t, const QVersionNumber &vr) :
+ ComplexTypeEntry(name, t, vr)
{
- CodeSnip snip;
- snip.language = TypeSystem::NativeCode;
- snip.position = CodeSnip::Beginning;
- snip.addCode(QString::fromLatin1(code));
- snip.argumentMap = args;
-
- FunctionModification mod;
- mod.signature = QMetaObject::normalizedSignature(signature);
- mod.snips << snip;
- mod.modifiers = Modification::CodeInjection;
}
-*/
struct CustomConversion::CustomConversionPrivate
{
@@ -3042,6 +3721,13 @@ QString InterfaceTypeEntry::qualifiedCppName() const
return ComplexTypeEntry::qualifiedCppName().left(len);
}
+TypeEntry *InterfaceTypeEntry::clone() const
+{
+ return new InterfaceTypeEntry(*this);
+}
+
+InterfaceTypeEntry::InterfaceTypeEntry(const InterfaceTypeEntry &) = default;
+
FunctionTypeEntry::FunctionTypeEntry(const QString &name, const QString &signature,
const QVersionNumber &vr) :
TypeEntry(name, FunctionType, vr)
@@ -3049,6 +3735,13 @@ FunctionTypeEntry::FunctionTypeEntry(const QString &name, const QString &signatu
addSignature(signature);
}
+TypeEntry *FunctionTypeEntry::clone() const
+{
+ return new FunctionTypeEntry(*this);
+}
+
+FunctionTypeEntry::FunctionTypeEntry(const FunctionTypeEntry &) = default;
+
ObjectTypeEntry::ObjectTypeEntry(const QString &name, const QVersionNumber &vr)
: ComplexTypeEntry(name, ObjectType, vr)
{
@@ -3063,3 +3756,10 @@ bool ObjectTypeEntry::isNativeIdBased() const
{
return true;
}
+
+TypeEntry *ObjectTypeEntry::clone() const
+{
+ return new ObjectTypeEntry(*this);
+}
+
+ObjectTypeEntry::ObjectTypeEntry(const ObjectTypeEntry &) = default;
diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h
index 186c4b24d..721d19f29 100644
--- a/sources/shiboken2/ApiExtractor/typesystem.h
+++ b/sources/shiboken2/ApiExtractor/typesystem.h
@@ -43,8 +43,8 @@
#include <QtCore/QVersionNumber>
//Used to identify the conversion rule to avoid break API
-#define TARGET_CONVERSION_RULE_FLAG "0"
-#define NATIVE_CONVERSION_RULE_FLAG "1"
+extern const char *TARGET_CONVERSION_RULE_FLAG;
+extern const char *NATIVE_CONVERSION_RULE_FLAG;
class Indentor;
@@ -203,12 +203,6 @@ struct ArgumentModification
QString replace_value;
- // The code to be used to construct a return value when noNullPointers is true and
- // the returned value is null. If noNullPointers is true and this string is
- // empty, then the base class implementation will be used (or a default construction
- // if there is no implementation)
- QString nullPointerDefaultValue;
-
// The text of the new default expression of the argument
QString replacedDefaultExpression;
@@ -237,6 +231,7 @@ struct ArgumentModification
struct Modification
{
enum Modifiers {
+ InvalidModifier = 0x0000,
Private = 0x0001,
Protected = 0x0002,
Public = 0x0003,
@@ -253,8 +248,7 @@ struct Modification
CodeInjection = 0x1000,
Rename = 0x2000,
Deprecated = 0x4000,
- ReplaceExpression = 0x8000,
- VirtualSlot = 0x10000 | NonFinal
+ ReplaceExpression = 0x8000
};
bool isAccessModifier() const
@@ -289,10 +283,6 @@ struct Modification
{
return modifiers & NonFinal;
}
- bool isVirtualSlot() const
- {
- return (modifiers & VirtualSlot) == VirtualSlot;
- }
QString accessModifierString() const;
bool isDeprecated() const
@@ -325,6 +315,8 @@ struct Modification
struct FunctionModification: public Modification
{
+ using AllowThread = TypeSystem::AllowThread;
+
bool isCodeInjection() const
{
return modifiers & CodeInjection;
@@ -337,14 +329,9 @@ struct FunctionModification: public Modification
{
return m_thread;
}
- bool allowThread() const
- {
- return m_allowThread;
- }
- void setAllowThread(bool allow)
- {
- m_allowThread = allow;
- }
+
+ AllowThread allowThread() const { return m_allowThread; }
+ void setAllowThread(AllowThread allow) { m_allowThread = allow; }
bool matches(const QString &functionSignature) const
{
@@ -359,6 +346,9 @@ struct FunctionModification: public Modification
void setOriginalSignature(const QString &s) { m_originalSignature = s; }
QString originalSignature() const { return m_originalSignature; }
+ TypeSystem::ExceptionHandling exceptionHandling() const { return m_exceptionHandling; }
+ void setExceptionHandling(TypeSystem::ExceptionHandling e) { m_exceptionHandling = e; }
+
QString toString() const;
QString association;
@@ -371,7 +361,8 @@ private:
QString m_originalSignature;
QRegularExpression m_signaturePattern;
bool m_thread = false;
- bool m_allowThread = false;
+ AllowThread m_allowThread = AllowThread::Unspecified;
+ TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
};
struct FieldModification: public Modification
@@ -398,6 +389,7 @@ struct AddedFunction
{
/// Function access types.
enum Access {
+ InvalidAccess = 0,
Protected = 0x1,
Public = 0x2
};
@@ -532,7 +524,6 @@ class CustomConversion;
class TypeEntry
{
- Q_DISABLE_COPY(TypeEntry)
Q_GADGET
public:
enum Type {
@@ -558,7 +549,8 @@ public:
CustomType,
TargetLangType,
FunctionType,
- SmartPointerType
+ SmartPointerType,
+ TypedefType
};
Q_ENUM(Type)
@@ -670,15 +662,6 @@ public:
return m_type == EnumValue;
}
- virtual bool preferredConversion() const
- {
- return m_preferredConversion;
- }
- virtual void setPreferredConversion(bool b)
- {
- m_preferredConversion = b;
- }
-
bool stream() const
{
return m_stream;
@@ -715,6 +698,11 @@ public:
&& m_codeGeneration != TypeEntry::GenerateNothing;
}
+ int revision() const { return m_revision; }
+ void setRevision(int r); // see typedatabase.cpp
+ int sbkIndex() const;
+ void setSbkIndex(int i) { m_sbkIndex = i; }
+
virtual QString qualifiedCppName() const
{
return m_name;
@@ -747,10 +735,8 @@ public:
}
// The package
- virtual QString targetLangPackage() const
- {
- return QString();
- }
+ QString targetLangPackage() const { return m_targetLangPackage; }
+ void setTargetLangPackage(const QString &p) { m_targetLangPackage = p; }
virtual QString qualifiedTargetLangName() const
{
@@ -889,13 +875,29 @@ public:
bool hasCustomConversion() const;
void setCustomConversion(CustomConversion* customConversion);
CustomConversion* customConversion() const;
+
+ virtual TypeEntry *clone() const;
+
+ void useAsTypedef(const TypeEntry *source);
+
+#ifndef QT_NO_DEBUG_STREAM
+ virtual void formatDebug(QDebug &d) const;
+#endif
+
+protected:
+ TypeEntry(const TypeEntry &);
+
private:
+ TypeEntry &operator=(const TypeEntry &) = delete;
+ TypeEntry &operator=(TypeEntry &&) = delete;
+ TypeEntry(TypeEntry &&) = delete;
+
QString m_name;
+ QString m_targetLangPackage;
Type m_type;
uint m_codeGeneration = GenerateAll;
CustomFunction m_customConstructor;
CustomFunction m_customDestructor;
- bool m_preferredConversion = true;
CodeSnipList m_codeSnips;
DocModificationList m_docModifications;
IncludeList m_extraIncludes;
@@ -904,24 +906,42 @@ private:
QString m_conversionRule;
bool m_stream = false;
QVersionNumber m_version;
+ CustomConversion *m_customConversion = nullptr;
+ int m_revision = 0;
+ int m_sbkIndex = 0;
};
class TypeSystemTypeEntry : public TypeEntry
{
public:
explicit TypeSystemTypeEntry(const QString &name, const QVersionNumber &vr);
+
+ TypeEntry *clone() const override;
+
+protected:
+ TypeSystemTypeEntry(const TypeSystemTypeEntry &);
};
class VoidTypeEntry : public TypeEntry
{
public:
VoidTypeEntry();
+
+ TypeEntry *clone() const override;
+
+protected:
+ VoidTypeEntry(const VoidTypeEntry &);
};
class VarargsTypeEntry : public TypeEntry
{
public:
VarargsTypeEntry();
+
+ TypeEntry *clone() const override;
+
+protected:
+ VarargsTypeEntry(const VarargsTypeEntry &);
};
class TemplateArgumentEntry : public TypeEntry
@@ -938,6 +958,11 @@ public:
m_ordinal = o;
}
+ TypeEntry *clone() const override;
+
+protected:
+ TemplateArgumentEntry(const TemplateArgumentEntry &);
+
private:
int m_ordinal = 0;
};
@@ -959,6 +984,11 @@ public:
QString targetLangName() const override;
QString targetLangApiName() const override;
+ TypeEntry *clone() const override;
+
+protected:
+ ArrayTypeEntry(const ArrayTypeEntry &);
+
private:
const TypeEntry *m_nestedType;
};
@@ -1019,9 +1049,6 @@ public:
*/
PrimitiveTypeEntry* basicReferencedTypeEntry() const;
- bool preferredConversion() const override;
- void setPreferredConversion(bool b) override;
-
bool preferredTargetLangType() const
{
return m_preferredTargetLangType;
@@ -1031,26 +1058,27 @@ public:
m_preferredTargetLangType = b;
}
- void setTargetLangPackage(const QString& package);
- QString targetLangPackage() const override;
+ TypeEntry *clone() const override;
+
+protected:
+ PrimitiveTypeEntry(const PrimitiveTypeEntry &);
+
private:
QString m_targetLangName;
QString m_targetLangApiName;
QString m_defaultConstructor;
- uint m_preferredConversion : 1;
uint m_preferredTargetLangType : 1;
PrimitiveTypeEntry* m_referencedTypeEntry = nullptr;
};
+class EnumValueTypeEntry;
+
class EnumTypeEntry : public TypeEntry
{
public:
explicit EnumTypeEntry(const QString &nspace, const QString &enumName,
const QVersionNumber &vr);
- QString targetLangPackage() const override;
- void setTargetLangPackage(const QString &package);
-
QString targetLangName() const override;
QString targetLangQualifier() const;
QString qualifiedTargetLangName() const override;
@@ -1066,30 +1094,8 @@ public:
m_qualifier = q;
}
- bool preferredConversion() const override;
-
- bool isBoundsChecked() const
- {
- return m_lowerBound.isEmpty() && m_upperBound.isEmpty();
- }
-
- QString upperBound() const
- {
- return m_upperBound;
- }
- void setUpperBound(const QString &bound)
- {
- m_upperBound = bound;
- }
-
- QString lowerBound() const
- {
- return m_lowerBound;
- }
- void setLowerBound(const QString &bound)
- {
- m_lowerBound = bound;
- }
+ const EnumValueTypeEntry *nullValue() const { return m_nullValue; }
+ void setNullValue(const EnumValueTypeEntry *n) { m_nullValue = n; }
void setFlags(FlagsTypeEntry *flags)
{
@@ -1100,15 +1106,6 @@ public:
return m_flags;
}
- bool isExtensible() const
- {
- return m_extensible;
- }
- void setExtensible(bool is)
- {
- m_extensible = is;
- }
-
bool isEnumValueRejected(const QString &name) const
{
return m_rejectedEnums.contains(name);
@@ -1122,33 +1119,27 @@ public:
return m_rejectedEnums;
}
- bool forceInteger() const
- {
- return m_forceInteger;
- }
- void setForceInteger(bool force)
- {
- m_forceInteger = force;
- }
+ TypeEntry *clone() const override;
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ EnumTypeEntry(const EnumTypeEntry &);
private:
QString m_packageName;
QString m_qualifier;
QString m_targetLangName;
-
- QString m_lowerBound;
- QString m_upperBound;
+ const EnumValueTypeEntry *m_nullValue = nullptr;
QStringList m_rejectedEnums;
FlagsTypeEntry *m_flags = nullptr;
-
- bool m_extensible = false;
- bool m_forceInteger = false;
};
// EnumValueTypeEntry is used for resolving integer type templates
-// like array<EnumValue>.
+// like array<EnumValue>. Note: Dummy entries for integer values will
+// be created for non-type template parameters, where m_enclosingEnum==nullptr.
class EnumValueTypeEntry : public TypeEntry
{
public:
@@ -1156,6 +1147,12 @@ public:
QString value() const { return m_value; }
const EnumTypeEntry* enclosingEnum() const { return m_enclosingEnum; }
+
+ TypeEntry *clone() const override;
+
+protected:
+ EnumValueTypeEntry(const EnumValueTypeEntry &);
+
private:
QString m_value;
const EnumTypeEntry* m_enclosingEnum;
@@ -1169,7 +1166,6 @@ public:
QString qualifiedTargetLangName() const override;
QString targetLangName() const override;
QString targetLangApiName() const override;
- bool preferredConversion() const override;
QString originalName() const
{
@@ -1189,11 +1185,6 @@ public:
m_targetLangName = name;
}
- bool forceInteger() const
- {
- return m_enum->forceInteger();
- }
-
EnumTypeEntry *originator() const
{
return m_enum;
@@ -1203,7 +1194,10 @@ public:
m_enum = e;
}
- QString targetLangPackage() const override;
+ TypeEntry *clone() const override;
+
+protected:
+ FlagsTypeEntry(const FlagsTypeEntry &);
private:
QString m_originalName;
@@ -1216,8 +1210,6 @@ class ComplexTypeEntry : public TypeEntry
{
public:
enum TypeFlag {
- ForceAbstract = 0x1,
- DeleteInMainThread = 0x2,
Deprecated = 0x4
};
typedef QFlags<TypeFlag> TypeFlags;
@@ -1288,12 +1280,6 @@ public:
return m_fieldMods;
}
- QString targetLangPackage() const override;
- void setTargetLangPackage(const QString &package)
- {
- m_package = package;
- }
-
bool isQObject() const
{
return m_qobject;
@@ -1336,15 +1322,6 @@ public:
return m_polymorphicIdValue;
}
- void setHeldType(const QString &value)
- {
- m_heldTypeValue = value;
- }
- QString heldTypeValue() const
- {
- return m_heldTypeValue;
- }
-
QString targetType() const
{
return m_targetType;
@@ -1369,6 +1346,9 @@ public:
m_genericClass = isGeneric;
}
+ bool deleteInMainThread() const { return m_deleteInMainThread; }
+ void setDeleteInMainThread(bool d) { m_deleteInMainThread = d; }
+
CopyableFlag copyable() const
{
return m_copyableFlag;
@@ -1397,15 +1377,28 @@ public:
return m_baseContainerType;
}
+ TypeSystem::ExceptionHandling exceptionHandling() const { return m_exceptionHandling; }
+ void setExceptionHandling(TypeSystem::ExceptionHandling e) { m_exceptionHandling = e; }
+
QString defaultConstructor() const;
void setDefaultConstructor(const QString& defaultConstructor);
bool hasDefaultConstructor() const;
+ TypeEntry *clone() const override;
+
+ void useAsTypedef(const ComplexTypeEntry *source);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ ComplexTypeEntry(const ComplexTypeEntry &);
+
private:
AddedFunctionList m_addedFunctions;
FunctionModificationList m_functionMods;
FieldModificationList m_fieldMods;
- QString m_package;
+ QString m_defaultConstructor;
QString m_defaultSuperclass;
QString m_qualifiedCppName;
QString m_targetLangName;
@@ -1413,9 +1406,9 @@ private:
uint m_qobject : 1;
uint m_polymorphicBase : 1;
uint m_genericClass : 1;
+ uint m_deleteInMainThread : 1;
QString m_polymorphicIdValue;
- QString m_heldTypeValue;
QString m_lookupName;
QString m_targetType;
TypeFlags m_typeFlags;
@@ -1423,6 +1416,38 @@ private:
QString m_hashFunction;
const ComplexTypeEntry* m_baseContainerType = nullptr;
+ // For class functions
+ TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
+};
+
+class TypedefEntry : public ComplexTypeEntry
+{
+public:
+ explicit TypedefEntry(const QString &name,
+ const QString &sourceType,
+ const QVersionNumber &vr);
+
+ QString sourceType() const { return m_sourceType; }
+ void setSourceType(const QString &s) { m_sourceType =s; }
+
+ TypeEntry *clone() const override;
+
+ ComplexTypeEntry *source() const { return m_source; }
+ void setSource(ComplexTypeEntry *source) { m_source = source; }
+
+ ComplexTypeEntry *target() const { return m_target; }
+ void setTarget(ComplexTypeEntry *target) { m_target = target; }
+
+#ifndef QT_NO_DEBUG_STREAM
+ virtual void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ TypedefEntry(const TypedefEntry &);
+
+private:
+ QString m_sourceType;
+ ComplexTypeEntry *m_source = nullptr;
+ ComplexTypeEntry *m_target = nullptr;
};
class ContainerTypeEntry : public ComplexTypeEntry
@@ -1455,28 +1480,15 @@ public:
QString typeName() const;
QString targetLangName() const override;
- QString targetLangPackage() const override;
QString qualifiedCppName() const override;
- static Type containerTypeFromString(QString typeName)
- {
- static QHash<QString, Type> m_stringToContainerType;
- if (m_stringToContainerType.isEmpty()) {
- m_stringToContainerType.insert(QLatin1String("list"), ListContainer);
- m_stringToContainerType.insert(QLatin1String("string-list"), StringListContainer);
- m_stringToContainerType.insert(QLatin1String("linked-list"), LinkedListContainer);
- m_stringToContainerType.insert(QLatin1String("vector"), VectorContainer);
- m_stringToContainerType.insert(QLatin1String("stack"), StackContainer);
- m_stringToContainerType.insert(QLatin1String("queue"), QueueContainer);
- m_stringToContainerType.insert(QLatin1String("set"), SetContainer);
- m_stringToContainerType.insert(QLatin1String("map"), MapContainer);
- m_stringToContainerType.insert(QLatin1String("multi-map"), MultiMapContainer);
- m_stringToContainerType.insert(QLatin1String("hash"), HashContainer);
- m_stringToContainerType.insert(QLatin1String("multi-hash"), MultiHashContainer);
- m_stringToContainerType.insert(QLatin1String("pair"), PairContainer);
- }
- return m_stringToContainerType.value(typeName, NoContainer);
- }
+ TypeEntry *clone() const override;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+protected:
+ ContainerTypeEntry(const ContainerTypeEntry &);
private:
Type m_type;
@@ -1501,6 +1513,11 @@ public:
return m_refCountMethodName;
}
+ TypeEntry *clone() const override;
+
+protected:
+ SmartPointerTypeEntry(const SmartPointerTypeEntry &);
+
private:
QString m_getterName;
QString m_smartPointerType;
@@ -1511,6 +1528,11 @@ class NamespaceTypeEntry : public ComplexTypeEntry
{
public:
explicit NamespaceTypeEntry(const QString &name, const QVersionNumber &vr);
+
+ TypeEntry *clone() const override;
+
+protected:
+ NamespaceTypeEntry(const NamespaceTypeEntry &);
};
@@ -1523,48 +1545,13 @@ public:
bool isNativeIdBased() const override;
+ TypeEntry *clone() const override;
+
protected:
explicit ValueTypeEntry(const QString &name, Type t, const QVersionNumber &vr);
+ ValueTypeEntry(const ValueTypeEntry &);
};
-
-class StringTypeEntry : public ValueTypeEntry
-{
-public:
- explicit StringTypeEntry(const QString &name, const QVersionNumber &vr);
-
- QString targetLangApiName() const override;
- QString targetLangName() const override;
- QString targetLangPackage() const override;
-
- bool isNativeIdBased() const override;
-};
-
-class CharTypeEntry : public ValueTypeEntry
-{
-public:
- explicit CharTypeEntry(const QString &name, const QVersionNumber &vr);
-
- QString targetLangApiName() const override;
- QString targetLangName() const override;
- QString targetLangPackage() const override;
-
- bool isNativeIdBased() const override;
-};
-
-class VariantTypeEntry: public ValueTypeEntry
-{
-public:
- explicit VariantTypeEntry(const QString &name, const QVersionNumber &vr);
-
- QString targetLangApiName() const override;
- QString targetLangName() const override;
- QString targetLangPackage() const override;
-
- bool isNativeIdBased() const override;
-};
-
-
class InterfaceTypeEntry : public ComplexTypeEntry
{
public:
@@ -1587,6 +1574,11 @@ public:
bool isNativeIdBased() const override;
QString qualifiedCppName() const override;
+ TypeEntry *clone() const override;
+
+protected:
+ InterfaceTypeEntry(const InterfaceTypeEntry &);
+
private:
ObjectTypeEntry *m_origin;
};
@@ -1611,6 +1603,12 @@ public:
{
return m_signatures.contains(signature);
}
+
+ TypeEntry *clone() const override;
+
+protected:
+ FunctionTypeEntry(const FunctionTypeEntry &);
+
private:
QStringList m_signatures;
};
@@ -1628,6 +1626,11 @@ public:
bool isNativeIdBased() const override;
+ TypeEntry *clone() const override;
+
+protected:
+ ObjectTypeEntry(const ObjectTypeEntry &);
+
private:
InterfaceTypeEntry *m_interface = nullptr;
};
@@ -1641,7 +1644,8 @@ struct TypeRejection
Field, // Match className and field name
Enum, // Match className and enum name
ArgumentType, // Match className and argument type
- ReturnType // Match className and return type
+ ReturnType, // Match className and return type
+ Invalid
};
QRegularExpression className;
diff --git a/sources/shiboken2/ApiExtractor/typesystem_enums.h b/sources/shiboken2/ApiExtractor/typesystem_enums.h
index 6bfc94368..df83429d0 100644
--- a/sources/shiboken2/ApiExtractor/typesystem_enums.h
+++ b/sources/shiboken2/ApiExtractor/typesystem_enums.h
@@ -55,6 +55,13 @@ enum Language {
TargetLangAndNativeCode = TargetLangCode | NativeCode
};
+enum class AllowThread {
+ Allow,
+ Disallow,
+ Auto,
+ Unspecified
+};
+
enum Ownership {
InvalidOwnership,
DefaultOwnership,
@@ -71,14 +78,24 @@ enum CodeSnipPosition {
CodeSnipPositionPrototypeInitialization,
CodeSnipPositionConstructorInitialization,
CodeSnipPositionConstructor,
- CodeSnipPositionAny
+ CodeSnipPositionAny,
+ CodeSnipPositionInvalid
};
enum DocModificationMode {
DocModificationAppend,
DocModificationPrepend,
DocModificationReplace,
- DocModificationXPathReplace
+ DocModificationXPathReplace,
+ DocModificationInvalid
+};
+
+enum class ExceptionHandling {
+ Unspecified,
+ Off,
+ AutoDefaultToOff,
+ AutoDefaultToOn,
+ On
};
} // namespace TypeSystem
diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystem_p.h
index 882cf3fab..e36df5151 100644
--- a/sources/shiboken2/ApiExtractor/typesystem_p.h
+++ b/sources/shiboken2/ApiExtractor/typesystem_p.h
@@ -55,6 +55,7 @@ class StackElement
FunctionTypeEntry = 0xb,
CustomTypeEntry = 0xc,
SmartPointerTypeEntry = 0xd,
+ TypedefTypeEntry = 0xe,
TypeEntryMask = 0xf,
// Documentation tags
@@ -140,37 +141,114 @@ public:
bool parse(QXmlStreamReader &reader);
+ QString errorString() const { return m_error; }
+
private:
- bool startElement(const QStringRef& localName, const QXmlStreamAttributes& atts);
- bool handleSmartPointerEntry(StackElement *element,
- QHash<QString, QString> &attributes,
- const QString &name,
- const QVersionNumber &since);
+ bool startElement(const QXmlStreamReader &reader);
+ SmartPointerTypeEntry *parseSmartPointerEntry(const QXmlStreamReader &,
+ const QString &name,
+ const QVersionNumber &since,
+ QXmlStreamAttributes *attributes);
bool endElement(const QStringRef& localName);
template <class String> // QString/QStringRef
bool characters(const String &ch);
- void fetchAttributeValues(const QString &name, const QXmlStreamAttributes &atts,
- QHash<QString, QString> *acceptedAttributes);
bool importFileElement(const QXmlStreamAttributes &atts);
- void addFlags(const QString &name, QString flagName,
- const QHash<QString, QString> &attributes,
- const QVersionNumber &since);
+
+ void applyCommonAttributes(TypeEntry *type, QXmlStreamAttributes *attributes) const;
+ PrimitiveTypeEntry *
+ parsePrimitiveTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ ContainerTypeEntry *
+ parseContainerTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ EnumTypeEntry *
+ parseEnumTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ FlagsTypeEntry *
+ parseFlagsEntry(const QXmlStreamReader &, EnumTypeEntry *enumEntry,
+ const QString &name, QString flagName,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ ObjectTypeEntry *
+ parseInterfaceTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ ValueTypeEntry *
+ parseValueTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ FunctionTypeEntry *
+ parseFunctionTypeEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ TypedefEntry *
+ parseTypedefEntry(const QXmlStreamReader &, const QString &name,
+ const QVersionNumber &since, QXmlStreamAttributes *);
+ void applyComplexTypeAttributes(const QXmlStreamReader &, ComplexTypeEntry *ctype,
+ QXmlStreamAttributes *) const;
+ bool parseRenameFunction(const QXmlStreamReader &, QString *name,
+ QXmlStreamAttributes *);
+ bool parseInjectDocumentation(const QXmlStreamReader &, QXmlStreamAttributes *);
+ bool parseModifyDocumentation(const QXmlStreamReader &, QXmlStreamAttributes *);
+ TypeSystemTypeEntry *
+ parseRootElement(const QXmlStreamReader &, const QVersionNumber &since,
+ QXmlStreamAttributes *);
+ bool loadTypesystem(const QXmlStreamReader &, QXmlStreamAttributes *);
+ bool parseRejectEnumValue(const QXmlStreamReader &, QXmlStreamAttributes *);
+ bool parseReplaceArgumentType(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseCustomConversion(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseAddConversion(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseModifyArgument(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *attributes);
+ bool parseNoNullPointer(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *attributes);
+ bool parseDefineOwnership(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseArgumentMap(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseRemoval(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseRename(const QXmlStreamReader &, StackElement::ElementType type,
+ const StackElement &topElement, QXmlStreamAttributes *);
+ bool parseModifyField(const QXmlStreamReader &, QXmlStreamAttributes *);
+ bool parseAddFunction(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseModifyFunction(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseReplaceDefaultExpression(const QXmlStreamReader &,
+ const StackElement &topElement, QXmlStreamAttributes *);
+ CustomFunction *
+ parseCustomMetaConstructor(const QXmlStreamReader &,
+ StackElement::ElementType type,
+ const StackElement &topElement, QXmlStreamAttributes *);
+ bool parseReferenceCount(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseParentOwner(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseInjectCode(const QXmlStreamReader &, const StackElement &topElement,
+ StackElement* element, QXmlStreamAttributes *);
+ bool parseInclude(const QXmlStreamReader &, const StackElement &topElement,
+ TypeEntry *entry, QXmlStreamAttributes *);
+ TemplateInstance
+ *parseTemplateInstanceEnum(const QXmlStreamReader &, const StackElement &topElement,
+ QXmlStreamAttributes *);
+ bool parseReplace(const QXmlStreamReader &, const StackElement &topElement,
+ StackElement *element, QXmlStreamAttributes *);
TypeDatabase* m_database;
- StackElement* m_current;
- StackElement* m_currentDroppedEntry;
- int m_currentDroppedEntryDepth;
- int m_ignoreDepth;
+ StackElement* m_current = nullptr;
+ StackElement* m_currentDroppedEntry = nullptr;
+ int m_currentDroppedEntryDepth = 0;
+ int m_ignoreDepth = 0;
QString m_defaultPackage;
QString m_defaultSuperclass;
+ TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified;
QString m_error;
- TypeEntry::CodeGeneration m_generate;
+ const TypeEntry::CodeGeneration m_generate;
- EnumTypeEntry* m_currentEnum;
+ EnumTypeEntry* m_currentEnum = nullptr;
QStack<StackElementContext*> m_contextStack;
- QHash<QString, StackElement::ElementType> tagNames;
QString m_currentSignature;
QString m_currentPath;
};
diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt
index 1af84fca1..12a9b8773 100644
--- a/sources/shiboken2/CMakeLists.txt
+++ b/sources/shiboken2/CMakeLists.txt
@@ -5,8 +5,9 @@ include(CheckIncludeFileCXX)
cmake_minimum_required(VERSION 3.1)
cmake_policy(VERSION 3.1)
-set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules/
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/../cmake_helpers/
${CMAKE_MODULE_PATH})
+include(helpers)
find_package(Qt5 5.7 REQUIRED COMPONENTS Core Xml XmlPatterns)
@@ -158,6 +159,8 @@ list(GET SHIBOKEN_VERSION_OUTPUT 4 shiboken_PRE_RELEASE_VERSION)
set(shiboken2_VERSION "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}.${shiboken_MICRO_VERSION}")
set(shiboken2_library_so_version "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}")
+compute_config_py_values(shiboken2_VERSION)
+
## For debugging the PYTHON* variables
message("PYTHONLIBS_FOUND: " ${PYTHONLIBS_FOUND})
message("PYTHON_LIBRARIES: " ${PYTHON_LIBRARIES})
diff --git a/sources/shiboken2/doc/commandlineoptions.rst b/sources/shiboken2/doc/commandlineoptions.rst
index d373561cd..c335fab75 100644
--- a/sources/shiboken2/doc/commandlineoptions.rst
+++ b/sources/shiboken2/doc/commandlineoptions.rst
@@ -37,16 +37,22 @@ Options
Enable heuristics to detect parent relationship on return values.
For more info, check :ref:`return-value-heuristics`.
+.. _avoid-protected-hack:
+
+``--avoid-protected-hack``
+ Avoid the use of the '#define protected public' hack.
+
+.. _use-isnull-as-nb_nonzero:
+
+``--use-isnull-as-nb_nonzero``
+ If a class have an isNull() const method, it will be used to
+ compute the value of boolean casts
+
.. _api-version:
``--api-version=<version>``
Specify the supported api version used to generate the bindings.
-.. _debug-level:
-
-``--debug-level=[sparse|medium|full]``
- Set the debug level.
-
.. _documentation-only:
``--documentation-only``
@@ -63,16 +69,52 @@ Options
``--generation-set``
Generator set to be used (e.g. qtdoc).
-.. _help:
+.. _diff:
-``--help``
- Display this help and exit.
+``--diff``
+ Print a diff of wrapper files.
+
+.. _dryrun:
+
+``--dryrun``
+ Dry run, do not generate wrapper files.
+
+.. _--project-file:
+
+``--project-file=<file>``
+ Text file containing a description of the binding project.
+ Replaces and overrides command line arguments.
.. _include-paths:
-``--include-paths=<path>[:<path>:...]``
+``-I<path>, --include-paths=<path>[:<path>:...]``
Include paths used by the C++ parser.
+... _system-include-paths:
+
+``-isystem<path>, --system-include-paths=<path>[:<path>:...]``
+ System include paths used by the C++ parser
+
+.. _framework-include-paths:
+
+``-F<path>, --framework-include-paths=<path>[:<path>:...]``
+ Framework include paths used by the C++ parser
+
+.. _language-level:
+
+``--language-level=, -std=<level>``
+ C++ Language level (c++11..c++17, default=c++14)
+
+.. _typesystem-paths:
+
+``-T<path>, --typesystem-paths=<path>[:<path>:...]``
+ Paths used when searching for type system files.
+
+.. _output-directory:
+
+``--output-directory=[dir]``
+ The directory where the generated files will be written.
+
.. _license-file=[license-file]:
``--license-file=[license-file]``
@@ -83,23 +125,57 @@ Options
``--no-suppress-warnings``
Show all warnings.
-.. _output-directory:
-
-``--output-directory=[dir]``
- The directory where the generated files will be written.
-
.. _silent:
``--silent``
Avoid printing any message.
-.. _typesystem-paths:
+.. _debug-level:
-``--typesystem-paths=<path>[:<path>:...]``
- Paths used when searching for type system files.
+``--debug-level=[sparse|medium|full]``
+ Set the debug level.
+
+.. _help:
+
+``--help``
+ Display this help and exit.
.. _version:
``--version``
Output version information and exit.
+QtDocGenerator Options
+----------------------
+
+.. _doc-parser:
+
+``--doc-parser=<parser>``
+ The documentation parser used to interpret the documentation
+ input files (qdoc|doxygen).
+
+.. _documentation-code-snippets-dir:
+
+``--documentation-code-snippets-dir=<dir>``
+ Directory used to search code snippets used by the documentation.
+
+.. _documentation-data-dir:
+
+``--documentation-data-dir=<dir>``
+ Directory with XML files generated by documentation tool.
+
+.. _documentation-extra-sections-dir=<dir>:
+
+``--documentation-extra-sections-dir=<dir>``
+ Directory used to search for extra documentation sections.
+
+.. _library-source-dir:
+
+``--library-source-dir=<dir>``
+ Directory where library source code is located.
+
+.. _additional-documentation:
+
+``--additional-documentation=<file>``
+ List of additional XML files to be converted to .rst files
+ (for example, tutorials).
diff --git a/sources/shiboken2/generator/CMakeLists.txt b/sources/shiboken2/generator/CMakeLists.txt
index 032118666..fb8058b2d 100644
--- a/sources/shiboken2/generator/CMakeLists.txt
+++ b/sources/shiboken2/generator/CMakeLists.txt
@@ -38,3 +38,33 @@ target_link_libraries(shiboken2
configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
install(TARGETS shiboken2 DESTINATION bin)
+
+set(shiboken_generator_package_name "shiboken2_generator")
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/_config.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/_config.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
+
+# shiboken2 setuptools entry point
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_tool.py
+ DESTINATION bin
+ PERMISSIONS
+ OWNER_EXECUTE OWNER_WRITE OWNER_READ
+ GROUP_EXECUTE GROUP_READ
+ WORLD_EXECUTE WORLD_READ)
+
+# Use absolute path instead of relative path, to avoid ninja build errors due to
+# duplicate file dependency inconsistency.
+set(shiboken_version_relative_path "${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_version.py")
+get_filename_component(shiboken_version_path ${shiboken_version_relative_path} ABSOLUTE)
+configure_file("${shiboken_version_path}"
+ "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_generator_version.py" @ONLY)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_generator_version.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
diff --git a/sources/shiboken2/generator/__init__.py.in b/sources/shiboken2/generator/__init__.py.in
new file mode 100644
index 000000000..4be6a833b
--- /dev/null
+++ b/sources/shiboken2/generator/__init__.py.in
@@ -0,0 +1,2 @@
+__version__ = "@FINAL_PACKAGE_VERSION@"
+__version_info__ = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
diff --git a/sources/shiboken2/generator/_config.py.in b/sources/shiboken2/generator/_config.py.in
new file mode 100644
index 000000000..985735fa4
--- /dev/null
+++ b/sources/shiboken2/generator/_config.py.in
@@ -0,0 +1,9 @@
+version = "@FINAL_PACKAGE_VERSION@"
+version_info = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
+
+@PACKAGE_BUILD_DATE@
+@PACKAGE_BUILD_COMMIT_DATE@
+@PACKAGE_BUILD_COMMIT_HASH@
+@PACKAGE_BUILD_COMMIT_HASH_DESCRIBED@
+@PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
+@PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT@
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
index 1e2f03932..8b37b44e0 100644
--- a/sources/shiboken2/generator/generator.cpp
+++ b/sources/shiboken2/generator/generator.cpp
@@ -28,6 +28,7 @@
#include "generator.h"
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "fileout.h"
#include "apiextractor.h"
@@ -40,8 +41,113 @@
#include <QDebug>
#include <typedatabase.h>
-struct Generator::GeneratorPrivate {
- const ApiExtractor* apiextractor;
+/**
+ * DefaultValue is used for storing default values of types for which code is
+ * generated in different contexts:
+ *
+ * Context | Example: "Class *" | Example: "Class" with default Constructor
+ * --------------------+-------------------------------+------------------------------------------
+ * Variable | var{nullptr}; | var;
+ * initializations | |
+ * --------------------+-------------------------------+------------------------------------------
+ * Return values | return nullptr; | return {}
+ * --------------------+-------------------------------+------------------------------------------
+ * constructor | static_cast<Class *>(nullptr) | Class()
+ * arguments lists | |
+ * (recursive, precise | |
+ * matching). | |
+ */
+
+DefaultValue::DefaultValue(Type t, QString value) :
+ m_type(t), m_value(std::move(value))
+{
+}
+
+DefaultValue::DefaultValue(QString customValue) :
+ m_type(Custom), m_value(std::move(customValue))
+{
+}
+
+QString DefaultValue::returnValue() const
+{
+ switch (m_type) {
+ case DefaultValue::Error:
+ return QLatin1String("#error");
+ case DefaultValue::Boolean:
+ return QLatin1String("false");
+ case DefaultValue::CppScalar:
+ return QLatin1String("0");
+ case DefaultValue::Custom:
+ case DefaultValue::Enum:
+ return m_value;
+ case DefaultValue::Pointer:
+ return QLatin1String("nullptr");
+ case DefaultValue::Void:
+ return QString();
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ return m_value + QLatin1String("()");
+ case DefaultValue::DefaultConstructor:
+ break;
+ }
+ return QLatin1String("{}");
+}
+
+QString DefaultValue::initialization() const
+{
+ switch (m_type) {
+ case DefaultValue::Error:
+ return QLatin1String("#error");
+ case DefaultValue::Boolean:
+ return QLatin1String("{false}");
+ case DefaultValue::CppScalar:
+ return QLatin1String("{0}");
+ case DefaultValue::Custom:
+ return QLatin1String(" = ") + m_value;
+ case DefaultValue::Enum:
+ return QLatin1Char('{') + m_value + QLatin1Char('}');
+ case DefaultValue::Pointer:
+ return QLatin1String("{nullptr}");
+ case DefaultValue::Void:
+ Q_ASSERT(false);
+ break;
+ case DefaultValue::DefaultConstructor:
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ break;
+ }
+ return QString();
+}
+
+QString DefaultValue::constructorParameter() const
+{
+ switch (m_type) {
+ case DefaultValue::Error:
+ return QLatin1String("#error");
+ case DefaultValue::Boolean:
+ return QLatin1String("false");
+ case DefaultValue::CppScalar:
+ return m_value + QLatin1String("(0)");
+ case DefaultValue::Custom:
+ case DefaultValue::Enum:
+ return m_value;
+ case DefaultValue::Pointer:
+ // Be precise here to be able to differentiate between constructors
+ // taking different pointer types, cf
+ // QTreeWidgetItemIterator(QTreeWidget *) and
+ // QTreeWidgetItemIterator(QTreeWidgetItemIterator *).
+ return QLatin1String("static_cast<") + m_value + QLatin1String("*>(nullptr)");
+ case DefaultValue::Void:
+ Q_ASSERT(false);
+ break;
+ case DefaultValue::DefaultConstructor:
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ break;
+ }
+ return m_value + QLatin1String("()");
+}
+
+struct Generator::GeneratorPrivate
+{
+ const ApiExtractor* apiextractor = nullptr;
QString outDir;
// License comment
QString licenseComment;
@@ -62,20 +168,17 @@ Generator::~Generator()
delete m_d;
}
-bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QString > args)
+bool Generator::setup(const ApiExtractor& extractor)
{
m_d->apiextractor = &extractor;
- TypeEntryHash allEntries = TypeDatabase::instance()->allEntries();
+ const auto &allEntries = TypeDatabase::instance()->entries();
TypeEntry* entryFound = 0;
- for (TypeEntryHash::const_iterator it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
- for (TypeEntry *entry : it.value()) {
- if (entry->type() == TypeEntry::TypeSystemType && entry->generateCode()) {
- entryFound = entry;
- break;
- }
- }
- if (entryFound)
+ for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
+ TypeEntry *entry = it.value();
+ if (entry->type() == TypeEntry::TypeSystemType && entry->generateCode()) {
+ entryFound = entry;
break;
+ }
}
if (entryFound)
m_d->packageName = entryFound->name();
@@ -84,7 +187,7 @@ bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QStrin
collectInstantiatedContainersAndSmartPointers();
- return doSetup(args);
+ return doSetup();
}
QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType* type)
@@ -197,6 +300,11 @@ Generator::OptionDescriptions Generator::options() const
return OptionDescriptions();
}
+bool Generator::handleOption(const QString & /* key */, const QString & /* value */)
+{
+ return false;
+}
+
AbstractMetaClassList Generator::classes() const
{
return m_d->apiextractor->classes();
@@ -227,24 +335,14 @@ ContainerTypeEntryList Generator::containerTypes() const
return m_d->apiextractor->containerTypes();
}
-const AbstractMetaEnum* Generator::findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const
-{
- return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
-}
-
const AbstractMetaEnum* Generator::findAbstractMetaEnum(const TypeEntry* typeEntry) const
{
return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
}
-const AbstractMetaEnum* Generator::findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const
-{
- return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
-}
-
const AbstractMetaEnum* Generator::findAbstractMetaEnum(const AbstractMetaType* metaType) const
{
- return m_d->apiextractor->findAbstractMetaEnum(metaType);
+ return m_d->apiextractor->findAbstractMetaEnum(metaType->typeEntry());
}
QString Generator::licenseComment() const
@@ -278,21 +376,6 @@ void Generator::setOutputDirectory(const QString &outDir)
m_d->outDir = outDir;
}
-inline void touchFile(const QString &filePath)
-{
- QFile toucher(filePath);
- qint64 size = toucher.size();
- if (!toucher.open(QIODevice::ReadWrite)) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("Failed to touch file '%1'")
- .arg(QDir::toNativeSeparators(filePath));
- return;
- }
- toucher.resize(size+1);
- toucher.resize(size);
- toucher.close();
-}
-
bool Generator::generateFileForContext(GeneratorContext &context)
{
AbstractMetaClass *cls = context.metaClass();
@@ -312,20 +395,7 @@ bool Generator::generateFileForContext(GeneratorContext &context)
generateClass(fileOut.stream, context);
- FileOut::State state = fileOut.done();
- switch (state) {
- case FileOut::Failure:
- return false;
- case FileOut::Unchanged:
- // Even if contents is unchanged, the last file modification time should be updated,
- // so that the build system can rely on the fact the generated file is up-to-date.
- touchFile(filePath);
- break;
- case FileOut::Success:
- break;
- }
-
- return true;
+ return fileOut.done() != FileOut::Failure;
}
QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
@@ -369,9 +439,9 @@ bool Generator::shouldGenerate(const AbstractMetaClass* metaClass) const
return shouldGenerateTypeEntry(metaClass->typeEntry());
}
-void verifyDirectoryFor(const QFile &file)
+void verifyDirectoryFor(const QString &file)
{
- QDir dir = QFileInfo(file).dir();
+ QDir dir = QFileInfo(file).absoluteDir();
if (!dir.exists()) {
if (!dir.mkpath(dir.absolutePath())) {
qCWarning(lcShiboken).noquote().nospace()
@@ -463,7 +533,7 @@ AbstractMetaFunctionList Generator::implicitConversions(const AbstractMetaType*
bool Generator::isObjectType(const TypeEntry* type)
{
if (type->isComplex())
- return Generator::isObjectType((const ComplexTypeEntry*)type);
+ return Generator::isObjectType(static_cast<const ComplexTypeEntry *>(type));
return type->isObject();
}
bool Generator::isObjectType(const ComplexTypeEntry* type)
@@ -557,184 +627,178 @@ QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type)
return QLatin1String("::") + typeName;
}
-QString Generator::minimalConstructor(const AbstractMetaType* type) const
+DefaultValue Generator::minimalConstructor(const AbstractMetaType* type) const
{
if (!type || (type->referenceType() == LValueReference && Generator::isObjectType(type)))
- return QString();
+ return DefaultValue(DefaultValue::Error);
if (type->isContainer()) {
QString ctor = type->cppSignature();
- if (ctor.endsWith(QLatin1Char('*')))
- return QLatin1String("0");
+ if (ctor.endsWith(QLatin1Char('*'))) {
+ ctor.chop(1);
+ return DefaultValue(DefaultValue::Pointer, ctor.trimmed());
+ }
if (ctor.startsWith(QLatin1String("const ")))
ctor.remove(0, sizeof("const ") / sizeof(char) - 1);
if (ctor.endsWith(QLatin1Char('&'))) {
ctor.chop(1);
ctor = ctor.trimmed();
}
- return QLatin1String("::") + ctor + QLatin1String("()");
+ return DefaultValue(DefaultValue::DefaultConstructor, QLatin1String("::") + ctor);
}
if (type->isNativePointer())
- return QLatin1String("static_cast<") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)");
+ return DefaultValue(DefaultValue::Pointer, type->typeEntry()->qualifiedCppName());
if (Generator::isPointer(type))
- return QLatin1String("static_cast< ::") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)");
+ return DefaultValue(DefaultValue::Pointer, QLatin1String("::") + type->typeEntry()->qualifiedCppName());
if (type->typeEntry()->isComplex()) {
- const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(type->typeEntry());
- QString ctor = cType->defaultConstructor();
- if (!ctor.isEmpty())
- return ctor;
- ctor = minimalConstructor(AbstractMetaClass::findClass(classes(), cType));
- if (type->hasInstantiations())
- ctor = ctor.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
+ const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(type->typeEntry());
+ if (cType->hasDefaultConstructor())
+ return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
+ auto ctor = minimalConstructor(AbstractMetaClass::findClass(classes(), cType));
+ if (ctor.isValid() && type->hasInstantiations()) {
+ QString v = ctor.value();
+ v.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
+ ctor.setValue(v);
+ }
return ctor;
}
return minimalConstructor(type->typeEntry());
}
-QString Generator::minimalConstructor(const TypeEntry* type) const
+DefaultValue Generator::minimalConstructor(const TypeEntry* type) const
{
if (!type)
- return QString();
+ return DefaultValue(DefaultValue::Error);
if (type->isCppPrimitive()) {
const QString &name = type->qualifiedCppName();
return name == QLatin1String("bool")
- ? QLatin1String("false") : name + QLatin1String("(0)");
+ ? DefaultValue(DefaultValue::Boolean)
+ : DefaultValue(DefaultValue::CppScalar, name);
}
- if (type->isEnum())
- return QLatin1String("static_cast< ::") + type->qualifiedCppName() + QLatin1String(">(0)");
+ if (type->isEnum()) {
+ const auto enumEntry = static_cast<const EnumTypeEntry *>(type);
+ if (const auto *nullValue = enumEntry->nullValue())
+ return DefaultValue(DefaultValue::Enum, nullValue->name());
+ return DefaultValue(DefaultValue::Custom,
+ QLatin1String("static_cast< ::") + type->qualifiedCppName()
+ + QLatin1String(">(0)"));
+ }
- if (type->isFlags())
- return type->qualifiedCppName() + QLatin1String("(0)");
+ if (type->isFlags()) {
+ return DefaultValue(DefaultValue::Custom,
+ type->qualifiedCppName() + QLatin1String("(0)"));
+ }
if (type->isPrimitive()) {
- QString ctor = reinterpret_cast<const PrimitiveTypeEntry*>(type)->defaultConstructor();
+ QString ctor = static_cast<const PrimitiveTypeEntry*>(type)->defaultConstructor();
// If a non-C++ (i.e. defined by the user) primitive type does not have
// a default constructor defined by the user, the empty constructor is
// heuristically returned. If this is wrong the build of the generated
// bindings will tell.
return ctor.isEmpty()
- ? (QLatin1String("::") + type->qualifiedCppName() + QLatin1String("()"))
- : ctor;
+ ? DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues, QLatin1String("::")
+ + type->qualifiedCppName())
+ : DefaultValue(DefaultValue::Custom, ctor);
}
if (type->isComplex())
return minimalConstructor(AbstractMetaClass::findClass(classes(), type));
- return QString();
+ return DefaultValue(DefaultValue::Error);
}
-QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
+static QString constructorCall(const QString &qualifiedCppName, const QStringList &args)
+{
+ return QLatin1String("::") + qualifiedCppName + QLatin1Char('(')
+ + args.join(QLatin1String(", ")) + QLatin1Char(')');
+}
+
+DefaultValue Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
{
if (!metaClass)
- return QString();
+ return DefaultValue(DefaultValue::Error);
- const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(metaClass->typeEntry());
+ const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(metaClass->typeEntry());
if (cType->hasDefaultConstructor())
- return cType->defaultConstructor();
+ return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
+ const QString qualifiedCppName = cType->qualifiedCppName();
+ // Obtain a list of constructors sorted by complexity and number of arguments
+ QMultiMap<int, const AbstractMetaFunction *> candidates;
const AbstractMetaFunctionList &constructors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
- int maxArgs = 0;
for (const AbstractMetaFunction *ctor : constructors) {
- if (ctor->isUserAdded() || ctor->isPrivate() || ctor->functionType() != AbstractMetaFunction::ConstructorFunction)
- continue;
-
- int numArgs = ctor->arguments().size();
- if (numArgs == 0) {
- maxArgs = 0;
- break;
- }
- if (numArgs > maxArgs)
- maxArgs = numArgs;
- }
-
- QString qualifiedCppName = metaClass->typeEntry()->qualifiedCppName();
- QStringList templateTypes;
- const QVector<TypeEntry *> &templateArguments = metaClass->templateArguments();
- for (TypeEntry *templateType : templateArguments)
- templateTypes << templateType->qualifiedCppName();
-
- // Empty constructor.
- if (maxArgs == 0)
- return QLatin1String("::") + qualifiedCppName + QLatin1String("()");
-
- QVector<const AbstractMetaFunction *> candidates;
-
- // Constructors with C++ primitive types, enums or pointers only.
- // Start with the ones with fewer arguments.
- for (int i = 1; i <= maxArgs; ++i) {
- for (const AbstractMetaFunction *ctor : constructors) {
- if (ctor->isUserAdded() || ctor->isPrivate() || ctor->functionType() != AbstractMetaFunction::ConstructorFunction)
- continue;
-
- const AbstractMetaArgumentList &arguments = ctor->arguments();
- if (arguments.size() != i)
- continue;
-
- QStringList args;
- for (const AbstractMetaArgument *arg : arguments) {
- const TypeEntry* type = arg->type()->typeEntry();
- if (type == metaClass->typeEntry()) {
- args.clear();
- break;
- }
-
- if (!arg->originalDefaultValueExpression().isEmpty()) {
- if (!arg->defaultValueExpression().isEmpty()
- && arg->defaultValueExpression() != arg->originalDefaultValueExpression()) {
- args << arg->defaultValueExpression();
- }
- break;
- }
-
- if (type->isCppPrimitive() || type->isEnum() || isPointer(arg->type())) {
- QString argValue = minimalConstructor(arg->type());
- if (argValue.isEmpty()) {
- args.clear();
- break;
- }
- args << argValue;
- } else {
- args.clear();
- break;
- }
+ if (!ctor->isUserAdded() && !ctor->isPrivate()
+ && ctor->functionType() == AbstractMetaFunction::ConstructorFunction) {
+ // No arguments: Default constructible
+ const auto &arguments = ctor->arguments();
+ if (arguments.isEmpty()) {
+ return DefaultValue(DefaultValue::DefaultConstructor,
+ QLatin1String("::") + qualifiedCppName);
}
-
- if (!args.isEmpty())
- return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", ")));
-
- candidates << ctor;
+ // First argument has unmodified default: Default constructible with values
+ if (arguments.constFirst()->hasUnmodifiedDefaultValueExpression()) {
+ return DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues,
+ QLatin1String("::") + qualifiedCppName);
+ }
+ // Examine arguments, exclude functions taking a self parameter
+ bool simple = true;
+ bool suitable = true;
+ for (int i = 0, size = arguments.size();
+ suitable && i < size && !arguments.at(i)->hasDefaultValueExpression(); ++i) {
+ const AbstractMetaArgument *arg = arguments.at(i);
+ const TypeEntry *aType = arg->type()->typeEntry();
+ suitable &= aType != cType;
+ simple &= aType->isCppPrimitive() || aType->isEnum() || isPointer(arg->type());
+ }
+ if (suitable)
+ candidates.insert(arguments.size() + (simple ? 0 : 100), ctor);
}
}
- // Constructors with C++ primitive types, enums, pointers, value types,
- // and user defined primitive types.
- // Builds the minimal constructor recursively.
- for (const AbstractMetaFunction *ctor : qAsConst(candidates)) {
+ for (auto it = candidates.cbegin(), end = candidates.cend(); it != end; ++it) {
+ const AbstractMetaArgumentList &arguments = it.value()->arguments();
QStringList args;
- const AbstractMetaArgumentList &arguments = ctor->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (arg->type()->typeEntry() == metaClass->typeEntry()) {
- args.clear();
+ bool ok = true;
+ for (int i =0, size = arguments.size(); ok && i < size; ++i) {
+ const AbstractMetaArgument *arg = arguments.at(i);
+ if (arg->hasDefaultValueExpression()) {
+ if (arg->hasModifiedDefaultValueExpression())
+ args << arg->defaultValueExpression(); // Spell out modified values
break;
}
- QString argValue = minimalConstructor(arg->type());
- if (argValue.isEmpty()) {
- args.clear();
- break;
- }
- args << argValue;
- }
- if (!args.isEmpty()) {
- return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", ")));
+ auto argValue = minimalConstructor(arg->type());
+ ok &= argValue.isValid();
+ args << argValue.constructorParameter();
}
+ if (ok)
+ return DefaultValue(DefaultValue::Custom, constructorCall(qualifiedCppName, args));
}
- return QString();
+ return DefaultValue(DefaultValue::Error);
+}
+
+// Should int be used for a (protected) enum when generating the public wrapper?
+bool Generator::useEnumAsIntForProtectedHack(const AbstractMetaType *metaType) const
+{
+ if (metaType->isFlags())
+ return true;
+ if (!metaType->isEnum())
+ return false;
+ const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(metaType);
+ if (!metaEnum)
+ return true;
+ if (metaEnum->attributes() & AbstractMetaAttributes::Public) // No reason, type is public
+ return false;
+ // Only ordinary C-enums can be used as int, scoped enums fail when used
+ // as function arguments.
+ if (metaEnum->enumKind() == EnumKind::EnumClass)
+ qWarning(lcShiboken, "%s", qPrintable(msgCannotUseEnumAsInt(metaEnum->name())));
+ return true;
}
QString Generator::translateType(const AbstractMetaType *cType,
@@ -754,7 +818,7 @@ QString Generator::translateType(const AbstractMetaType *cType,
s = QLatin1String("void");
} else if (cType->isArray()) {
s = translateType(cType->arrayElementType(), context, options) + QLatin1String("[]");
- } else if (options & Generator::EnumAsInts && (cType->isEnum() || cType->isFlags())) {
+ } else if ((options & Generator::EnumAsInts) && useEnumAsIntForProtectedHack(cType)) {
s = QLatin1String("int");
} else {
if (options & Generator::OriginalName) {
diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h
index 010ed868c..225e7aec7 100644
--- a/sources/shiboken2/generator/generator.h
+++ b/sources/shiboken2/generator/generator.h
@@ -57,7 +57,7 @@ class ContainerTypeEntry;
class Indentor;
QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor);
-void verifyDirectoryFor(const QFile &file);
+void verifyDirectoryFor(const QString &file);
QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName = true);
QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePackageName = true);
@@ -95,6 +95,42 @@ const int alwaysGenerateDestructor = 1;
const int alwaysGenerateDestructor = 0;
#endif
+class DefaultValue
+{
+public:
+ enum Type
+ {
+ Error,
+ Boolean,
+ CppScalar, // A C++ scalar type (int,..) specified by value()
+ Custom, // A custom constructor/expression, uses value() as is
+ DefaultConstructor, // For classes named value()
+ DefaultConstructorWithDefaultValues, // as DefaultConstructor, but can't return {} though.
+ Enum, // Enum value as specified by value()
+ Pointer, // Pointer of type value()
+ Void // "", for return values only
+ };
+
+ explicit DefaultValue(Type t = Error, QString value = QString());
+ explicit DefaultValue(QString customValue);
+
+ bool isValid() const { return m_type != Error; }
+
+ QString returnValue() const;
+ QString initialization() const;
+ QString constructorParameter() const;
+
+ QString value() const { return m_value; }
+ void setValue(const QString &value) { m_value = value; }
+
+ Type type() const { return m_type; }
+ void setType(Type type) { m_type = type; }
+
+private:
+ Type m_type;
+ QString m_value;
+};
+
/**
* A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized
* AbstractMetaType, for which code is currently being generated.
@@ -166,13 +202,74 @@ public:
Generator();
virtual ~Generator();
- bool setup(const ApiExtractor& extractor, const QMap<QString, QString> args);
+ bool setup(const ApiExtractor& extractor);
virtual OptionDescriptions options() const;
+ virtual bool handleOption(const QString &key, const QString &value);
/// Returns the classes used to generate the binding code.
AbstractMetaClassList classes() const;
+ /// Returns the output directory
+ QString outputDirectory() const;
+
+ /// Set the output directory
+ void setOutputDirectory(const QString &outDir);
+
+ /**
+ * Start the code generation, be sure to call setClasses before callign this method.
+ * For each class it creates a QTextStream, call the write method with the current
+ * class and the associated text stream, then write the text stream contents if needed.
+ * \see #write
+ */
+ bool generate();
+
+ /// Returns the license comment to be prepended to each source file generated.
+ QString licenseComment() const;
+
+ /// Sets the license comment to be prepended to each source file generated.
+ void setLicenseComment(const QString &licenseComment);
+
+ /// Returns the generator's name. Used for cosmetic purposes.
+ virtual const char* name() const = 0;
+
+ /**
+ * Retrieves the name of the currently processed module.
+ * While package name is a complete package idetification, e.g. 'PySide.QtCore',
+ * a module name represents the last part of the package, e.g. 'QtCore'.
+ * If the target language separates the modules with characters other than
+ * dots ('.') the generator subclass must overload this method.
+ * \return a string representing the last part of a package name
+ */
+ QString moduleName() const;
+
+ /**
+ * Retrieves a list of constructors used in implicit conversions
+ * available on the given type. The TypeEntry must be a value-type
+ * or else it will return an empty list.
+ * \param type a TypeEntry that is expected to be a value-type
+ * \return a list of constructors that could be used as implicit converters
+ */
+ AbstractMetaFunctionList implicitConversions(const TypeEntry* type) const;
+
+ /// Convenience function for implicitConversions(const TypeEntry* type).
+ AbstractMetaFunctionList implicitConversions(const AbstractMetaType* metaType) const;
+
+ /// Check if type is a pointer.
+ static bool isPointer(const AbstractMetaType* type);
+
+ /// Tells if the type or class is an Object (or QObject) Type.
+ static bool isObjectType(const TypeEntry* type);
+ static bool isObjectType(const ComplexTypeEntry* type);
+ static bool isObjectType(const AbstractMetaType* metaType);
+ static bool isObjectType(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the type is a C string (const char*).
+ static bool isCString(const AbstractMetaType* type);
+ /// Returns true if the type is a void pointer.
+ static bool isVoidPointer(const AbstractMetaType* type);
+
+protected:
/// Returns the classes, topologically ordered, used to generate the binding code.
///
/// The classes are ordered such that derived classes appear later in the list than
@@ -191,33 +288,12 @@ public:
/// Returns all container types found by APIExtractor
ContainerTypeEntryList containerTypes() const;
- /// Returns an AbstractMetaEnum for a given EnumTypeEntry, or NULL if not found.
- const AbstractMetaEnum* findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const;
-
/// Returns an AbstractMetaEnum for a given TypeEntry that is an EnumTypeEntry, or NULL if not found.
const AbstractMetaEnum* findAbstractMetaEnum(const TypeEntry* typeEntry) const;
- /// Returns an AbstractMetaEnum for the enum related to a given FlagsTypeEntry, or NULL if not found.
- const AbstractMetaEnum* findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const;
-
/// Returns an AbstractMetaEnum for a given AbstractMetaType that holds an EnumTypeEntry, or NULL if not found.
const AbstractMetaEnum* findAbstractMetaEnum(const AbstractMetaType* metaType) const;
- /// Returns the output directory
- QString outputDirectory() const;
-
- /// Set the output directory
- void setOutputDirectory(const QString &outDir);
-
- /**
- * Start the code generation, be sure to call setClasses before callign this method.
- * For each class it creates a QTextStream, call the write method with the current
- * class and the associated text stream, then write the text stream contents if needed.
- * \see #write
- */
- bool generate();
-
-
/// Generates a file for given AbstractMetaClass or AbstractMetaType (smart pointer case).
bool generateFileForContext(GeneratorContext &context);
@@ -225,9 +301,6 @@ public:
QString getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
const AbstractMetaClass *smartPointerClass) const;
- /// Returns the generator's name. Used for cosmetic purposes.
- virtual const char* name() const = 0;
-
/// Returns true if the generator should generate any code for the TypeEntry.
bool shouldGenerateTypeEntry(const TypeEntry*) const;
@@ -266,56 +339,10 @@ public:
void replaceTemplateVariables(QString &code, const AbstractMetaFunction *func);
/**
- * Returns the license comment to be prepended to each source file generated.
- */
- QString licenseComment() const;
-
- /**
- * Sets the license comment to be prepended to each source file generated.
- */
- void setLicenseComment(const QString &licenseComment);
-
- /**
* Returns the package name.
*/
QString packageName() const;
- /**
- * Retrieves the name of the currently processed module.
- * While package name is a complete package idetification, e.g. 'PySide.QtCore',
- * a module name represents the last part of the package, e.g. 'QtCore'.
- * If the target language separates the modules with characters other than
- * dots ('.') the generator subclass must overload this method.
- * \return a string representing the last part of a package name
- */
- virtual QString moduleName() const;
-
- /**
- * Retrieves a list of constructors used in implicit conversions
- * available on the given type. The TypeEntry must be a value-type
- * or else it will return an empty list.
- * \param type a TypeEntry that is expected to be a value-type
- * \return a list of constructors that could be used as implicit converters
- */
- AbstractMetaFunctionList implicitConversions(const TypeEntry* type) const;
-
- /// Convenience function for implicitConversions(const TypeEntry* type).
- AbstractMetaFunctionList implicitConversions(const AbstractMetaType* metaType) const;
-
- /// Check if type is a pointer.
- static bool isPointer(const AbstractMetaType* type);
-
- /// Tells if the type or class is an Object (or QObject) Type.
- static bool isObjectType(const TypeEntry* type);
- static bool isObjectType(const ComplexTypeEntry* type);
- static bool isObjectType(const AbstractMetaType* metaType);
- static bool isObjectType(const AbstractMetaClass* metaClass);
-
- /// Returns true if the type is a C string (const char*).
- static bool isCString(const AbstractMetaType* type);
- /// Returns true if the type is a void pointer.
- static bool isVoidPointer(const AbstractMetaType* type);
-
// Returns the full name of the type.
QString getFullTypeName(const TypeEntry* type) const;
QString getFullTypeName(const AbstractMetaType* type) const;
@@ -333,11 +360,10 @@ public:
* It will check first for a user defined default constructor.
* Returns a null string if it fails.
*/
- QString minimalConstructor(const TypeEntry* type) const;
- QString minimalConstructor(const AbstractMetaType* type) const;
- QString minimalConstructor(const AbstractMetaClass* metaClass) const;
+ DefaultValue minimalConstructor(const TypeEntry* type) const;
+ DefaultValue minimalConstructor(const AbstractMetaType* type) const;
+ DefaultValue minimalConstructor(const AbstractMetaClass* metaClass) const;
-protected:
/**
* Returns the file name used to write the binding code of an AbstractMetaClass/Type.
* \param context the GeneratorContext which contains an AbstractMetaClass or AbstractMetaType
@@ -348,7 +374,7 @@ protected:
virtual QString fileNameForContext(GeneratorContext &context) const = 0;
- virtual bool doSetup(const QMap<QString, QString>& args) = 0;
+ virtual bool doSetup() = 0;
/**
* Write the bindding code for an AbstractMetaClass.
@@ -378,6 +404,8 @@ protected:
const QString &context);
private:
+ bool useEnumAsIntForProtectedHack(const AbstractMetaType *cType) const;
+
struct GeneratorPrivate;
GeneratorPrivate* m_d;
void collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction* func);
diff --git a/sources/shiboken2/generator/main.cpp b/sources/shiboken2/generator/main.cpp
index 0b7c15244..362191fd0 100644
--- a/sources/shiboken2/generator/main.cpp
+++ b/sources/shiboken2/generator/main.cpp
@@ -34,6 +34,9 @@
#include <QtCore/QDir>
#include <iostream>
#include <apiextractor.h>
+#include <fileout.h>
+#include <typedatabase.h>
+#include <messages.h>
#include "generator.h"
#include "shibokenconfig.h"
#include "cppgenerator.h"
@@ -41,9 +44,9 @@
#include "qtdocgenerator.h"
#ifdef _WINDOWS
- #define PATH_SPLITTER ";"
+static const QChar pathSplitter = QLatin1Char(';');
#else
- #define PATH_SPLITTER ":"
+static const QChar pathSplitter = QLatin1Char(':');
#endif
static inline QString languageLevelOption() { return QStringLiteral("language-level"); }
@@ -52,95 +55,12 @@ static inline QString frameworkIncludePathOption() { return QStringLiteral("fram
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";
-
-namespace {
-
-class ArgsHandler
-{
-public:
- explicit ArgsHandler(const QMap<QString, QString>& other);
- virtual ~ArgsHandler();
-
- inline QMap<QString, QString>& args() const
- {
- return *m_args;
- }
-
- inline bool argExists(const QString& s) const
- {
- return m_args->contains(s);
- }
-
- QString removeArg(const QString& s);
- bool argExistsRemove(const QString& s);
+static inline QString diffOption() { return QStringLiteral("diff"); }
+static inline QString dryrunOption() { return QStringLiteral("dry-run"); }
- inline QString argValue(const QString& s) const
- {
- return m_args->value(s);
- }
-
- inline bool noArgs() const
- {
- return m_args->isEmpty();
- }
-
- QString errorMessage() const;
-
-private:
- QMap<QString, QString>* m_args;
-};
-
-ArgsHandler::ArgsHandler(const QMap<QString, QString>& other)
- : m_args(new QMap<QString, QString>(other))
-{
-}
-
-ArgsHandler::~ArgsHandler()
-{
- delete m_args;
-}
-
-QString ArgsHandler::removeArg(const QString& s)
-{
- QString retval;
-
- if (argExists(s)) {
- retval = argValue(s);
- m_args->remove(s);
- }
-
- return retval;
-}
-
-bool ArgsHandler::argExistsRemove(const QString& s)
-{
- bool retval = false;
-
- if (argExists(s)) {
- retval = true;
- m_args->remove(s);
- }
+static const char helpHint[] = "Note: use --help or -h for more information.\n";
- return retval;
-}
-
-QString ArgsHandler::errorMessage() const
-{
- typedef QMap<QString, QString>::ConstIterator StringMapConstIt;
-
- QString message;
- QTextStream str(&message);
- str << "shiboken: Called with wrong arguments:";
- for (StringMapConstIt it = m_args->cbegin(), end = m_args->cend(); it != end; ++it) {
- str << ' ' << it.key();
- if (!it.value().isEmpty())
- str << ' ' << it.value();
- }
- str << "\nCommand line: " << QCoreApplication::arguments().join(QLatin1Char(' '));
- return message;
-}
-}
+typedef QMap<QString, QString> CommandArgumentMap;
typedef Generator::OptionDescriptions OptionDescriptions;
@@ -214,18 +134,18 @@ static bool processProjectFile(QFile& projectFile, QMap<QString, QString>& args)
}
if (!includePaths.isEmpty())
- args.insert(includePathOption(), includePaths.join(QLatin1String(PATH_SPLITTER)));
+ args.insert(includePathOption(), includePaths.join(pathSplitter));
if (!frameworkIncludePaths.isEmpty())
args.insert(frameworkIncludePathOption(),
- frameworkIncludePaths.join(QLatin1String(PATH_SPLITTER)));
+ frameworkIncludePaths.join(pathSplitter));
if (!systemIncludePaths.isEmpty()) {
args.insert(systemIncludePathOption(),
- systemIncludePaths.join(QLatin1String(PATH_SPLITTER)));
+ systemIncludePaths.join(pathSplitter));
}
if (!typesystemPaths.isEmpty())
- args.insert(typesystemPathOption(), typesystemPaths.join(QLatin1String(PATH_SPLITTER)));
+ args.insert(typesystemPathOption(), typesystemPaths.join(pathSplitter));
if (!apiVersions.isEmpty())
args.insert(QLatin1String("api-version"), apiVersions.join(QLatin1Char('|')));
if (!languageLevel.isEmpty())
@@ -233,9 +153,9 @@ static bool processProjectFile(QFile& projectFile, QMap<QString, QString>& args)
return true;
}
-static QMap<QString, QString> getInitializedArguments()
+static CommandArgumentMap getInitializedArguments()
{
- QMap<QString, QString> args;
+ CommandArgumentMap args;
QStringList arguments = QCoreApplication::arguments();
QString appName = arguments.constFirst();
arguments.removeFirst();
@@ -277,11 +197,11 @@ static QMap<QString, QString> getInitializedArguments()
// Concatenate values of path arguments that can occur multiple times on the
// command line.
static void addPathOptionValue(const QString &option, const QString &value,
- QMap<QString, QString> &args)
+ CommandArgumentMap &args)
{
- const QMap<QString, QString>::iterator it = args.find(option);
+ const CommandArgumentMap::iterator it = args.find(option);
if (it != args.end())
- it.value().append(QLatin1String(PATH_SPLITTER) + value);
+ it.value().append(pathSplitter + value);
else
args.insert(option, value);
}
@@ -369,7 +289,9 @@ void printUsage()
s << "Usage:\n "
<< "shiboken [options] header-file typesystem-file\n\n"
<< "General options:\n";
- const QString pathSyntax = QLatin1String("<path>[" PATH_SPLITTER "<path>" PATH_SPLITTER "...]");
+ QString pathSyntax;
+ QTextStream(&pathSyntax) << "<path>[" << pathSplitter << "<path>"
+ << pathSplitter << "...]";
OptionDescriptions generalOptions = OptionDescriptions()
<< qMakePair(QLatin1String("api-version=<\"package mask\">,<\"version\">"),
QLatin1String("Specify the supported api version used to generate the bindings"))
@@ -380,18 +302,22 @@ void printUsage()
<< qMakePair(QLatin1String("drop-type-entries=\"<TypeEntry0>[;TypeEntry1;...]\""),
QLatin1String("Semicolon separated list of type system entries (classes, namespaces,\n"
"global functions and enums) to be dropped from generation."))
- << qMakePair(QLatin1String("-F") + pathSyntax, QString())
+ << qMakePair(QLatin1String("-F<path>"), QString())
<< qMakePair(QLatin1String("framework-include-paths=") + pathSyntax,
QLatin1String("Framework include paths used by the C++ parser"))
- << qMakePair(QLatin1String("-isystem") + pathSyntax, QString())
+ << qMakePair(QLatin1String("-isystem<path>"), 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(diffOption(),
+ QLatin1String("Print a diff of wrapper files"))
+ << qMakePair(dryrunOption(),
+ QLatin1String("Dry run, do not generate wrapper files"))
<< qMakePair(QLatin1String("-h"), QString())
<< qMakePair(helpOption(),
QLatin1String("Display this help and exit"))
- << qMakePair(QLatin1String("-I") + pathSyntax, QString())
+ << qMakePair(QLatin1String("-I<path>"), QString())
<< qMakePair(QLatin1String("include-paths=") + pathSyntax,
QLatin1String("Include paths used by the C++ parser"))
<< qMakePair(languageLevelOption() + QLatin1String("=, -std=<level>"),
@@ -407,7 +333,7 @@ void printUsage()
"Replaces and overrides command line arguments"))
<< qMakePair(QLatin1String("silent"),
QLatin1String("Avoid printing any message"))
- << qMakePair(QLatin1String("-T") + pathSyntax, QString())
+ << qMakePair(QLatin1String("-T<path>"), QString())
<< qMakePair(QLatin1String("typesystem-paths=") + pathSyntax,
QLatin1String("Paths used when searching for typesystems"))
<< qMakePair(QLatin1String("version"),
@@ -438,19 +364,15 @@ static inline void errorPrint(const QString& s)
<< "\nCommand line: " << qPrintable(arguments.join(QLatin1Char(' '))) << '\n';
}
-static QString msgInvalidVersion(const QString &package, const QString &version)
-{
- return QLatin1String("Invalid version \"") + version
- + QLatin1String("\" specified for package ") + package + QLatin1Char('.');
-}
-
static void parseIncludePathOption(const QString &option, HeaderType headerType,
- ArgsHandler &args,
+ CommandArgumentMap &args,
ApiExtractor &extractor)
{
- const QString path = args.removeArg(option);
- if (!path.isEmpty()) {
- const QStringList includePathListList = path.split(QLatin1String(PATH_SPLITTER));
+ const CommandArgumentMap::iterator it = args.find(option);
+ if (it != args.end()) {
+ const QStringList includePathListList =
+ it.value().split(pathSplitter, QString::SkipEmptyParts);
+ args.erase(it);
for (const QString &s : includePathListList)
extractor.addIncludePath(HeaderPath{QFile::encodeName(s), headerType});
}
@@ -469,19 +391,24 @@ int main(int argc, char *argv[])
qCDebug(lcShiboken()).noquote().nospace() << QCoreApplication::arguments().join(QLatin1Char(' '));
// Store command arguments in a map
- QMap<QString, QString> args = getCommandLineArgs();
- ArgsHandler argsHandler(args);
+ CommandArgumentMap args = getCommandLineArgs();
Generators generators;
- if (argsHandler.argExistsRemove(QLatin1String("version"))) {
+ CommandArgumentMap::iterator ait = args.find(QLatin1String("version"));
+ if (ait != args.end()) {
+ args.erase(ait);
printVerAndBanner();
return EXIT_SUCCESS;
}
- QString generatorSet = argsHandler.removeArg(QLatin1String("generator-set"));
- // Also check QLatin1String("generatorSet") command line argument for backward compatibility.
- if (generatorSet.isEmpty())
- generatorSet = argsHandler.removeArg(QLatin1String("generatorSet"));
+ QString generatorSet;
+ ait = args.find(QLatin1String("generator-set"));
+ if (ait == args.end()) // Also check QLatin1String("generatorSet") command line argument for backward compatibility.
+ ait = args.find(QLatin1String("generatorSet"));
+ if (ait != args.end()) {
+ generatorSet = ait.value();
+ args.erase(ait);
+ }
// Pre-defined generator sets.
if (generatorSet == QLatin1String("qtdoc")) {
@@ -497,28 +424,45 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
- if (argsHandler.argExistsRemove(QLatin1String("help"))) {
+ ait = args.find(QLatin1String("help"));
+ if (ait != args.end()) {
+ args.erase(ait);
printUsage();
return EXIT_SUCCESS;
}
+ ait = args.find(diffOption());
+ if (ait != args.end()) {
+ args.erase(ait);
+ FileOut::diff = true;
+ }
+
+ ait = args.find(dryrunOption());
+ if (ait != args.end()) {
+ args.erase(ait);
+ FileOut::dummy = true;
+ }
+
QString licenseComment;
- QString licenseFileName = argsHandler.removeArg(QLatin1String("license-file"));
- if (!licenseFileName.isEmpty()) {
- if (QFile::exists(licenseFileName)) {
- QFile licenseFile(licenseFileName);
- if (licenseFile.open(QIODevice::ReadOnly))
- licenseComment = QString::fromUtf8(licenseFile.readAll());
+ ait = args.find(QLatin1String("license-file"));
+ if (ait != args.end()) {
+ QFile licenseFile(ait.value());
+ args.erase(ait);
+ if (licenseFile.open(QIODevice::ReadOnly)) {
+ licenseComment = QString::fromUtf8(licenseFile.readAll());
} else {
- errorPrint(QStringLiteral("Couldn't find the file containing the license heading: %1").
- arg(licenseFileName));
+ errorPrint(QStringLiteral("Could not open the file \"%1\" containing the license heading: %2").
+ arg(QDir::toNativeSeparators(licenseFile.fileName()), licenseFile.errorString()));
return EXIT_FAILURE;
}
}
- QString outputDirectory = argsHandler.removeArg(QLatin1String("output-directory"));
- if (outputDirectory.isEmpty())
- outputDirectory = QLatin1String("out");
+ QString outputDirectory = QLatin1String("out");
+ ait = args.find(QLatin1String("output-directory"));
+ if (ait != args.end()) {
+ outputDirectory = ait.value();
+ args.erase(ait);
+ }
if (!QDir(outputDirectory).exists()) {
if (!QDir().mkpath(outputDirectory)) {
@@ -532,11 +476,15 @@ int main(int argc, char *argv[])
ApiExtractor extractor;
extractor.setLogDirectory(outputDirectory);
- if (argsHandler.argExistsRemove(QLatin1String("silent"))) {
+ ait = args.find(QLatin1String("silent"));
+ if (ait != args.end()) {
extractor.setSilent(true);
+ args.erase(ait);
} else {
- QString level = argsHandler.removeArg(QLatin1String("debug-level"));
- if (!level.isEmpty()) {
+ ait = args.find(QLatin1String("debug-level"));
+ if (ait != args.end()) {
+ const QString level = ait.value();
+ args.erase(ait);
if (level == QLatin1String("sparse"))
extractor.setDebugLevel(ReportHandler::SparseDebug);
else if (level == QLatin1String("medium"))
@@ -545,11 +493,15 @@ int main(int argc, char *argv[])
extractor.setDebugLevel(ReportHandler::FullDebug);
}
}
- if (argsHandler.argExistsRemove(QLatin1String("no-suppress-warnings")))
+ ait = args.find(QLatin1String("no-suppress-warnings"));
+ if (ait != args.end()) {
+ args.erase(ait);
extractor.setSuppressWarnings(false);
-
- if (argsHandler.argExists(QLatin1String("api-version"))) {
- const QStringList &versions = argsHandler.removeArg(QLatin1String("api-version")).split(QLatin1Char('|'));
+ }
+ ait = args.find(QLatin1String("api-version"));
+ if (ait != args.end()) {
+ const QStringList &versions = ait.value().split(QLatin1Char('|'));
+ args.erase(ait);
for (const QString &fullVersion : versions) {
QStringList parts = fullVersion.split(QLatin1Char(','));
QString package;
@@ -563,54 +515,65 @@ int main(int argc, char *argv[])
}
}
- if (argsHandler.argExists(QLatin1String("drop-type-entries")))
- extractor.setDropTypeEntries(argsHandler.removeArg(QLatin1String("drop-type-entries")));
+ ait = args.find(QLatin1String("drop-type-entries"));
+ if (ait != args.end()) {
+ extractor.setDropTypeEntries(ait.value());
+ args.erase(ait);
+ }
- QString path = argsHandler.removeArg(QLatin1String("typesystem-paths"));
- if (!path.isEmpty())
- extractor.addTypesystemSearchPath(path.split(QLatin1String(PATH_SPLITTER)));
+ ait = args.find(QLatin1String("typesystem-paths"));
+ if (ait != args.end()) {
+ extractor.addTypesystemSearchPath(ait.value().split(pathSplitter));
+ args.erase(ait);
+ }
parseIncludePathOption(includePathOption(), HeaderType::Standard,
- argsHandler, extractor);
+ args, extractor);
parseIncludePathOption(frameworkIncludePathOption(), HeaderType::Framework,
- argsHandler, extractor);
+ args, extractor);
parseIncludePathOption(systemIncludePathOption(), HeaderType::System,
- argsHandler, extractor);
+ args, extractor);
- QString cppFileName = argsHandler.removeArg(QLatin1String("arg-1"));
+ ait = args.find(QLatin1String("arg-1"));
+ if (ait == args.end()) {
+ errorPrint(QLatin1String("Required argument header-file is missing."));
+ return EXIT_FAILURE;
+ }
+ const QString cppFileName = ait.value();
+ args.erase(ait);
const QFileInfo cppFileNameFi(cppFileName);
if (!cppFileNameFi.isFile() && !cppFileNameFi.isSymLink()) {
errorPrint(QLatin1Char('"') + cppFileName + QLatin1String("\" does not exist."));
return EXIT_FAILURE;
}
- QString typeSystemFileName = argsHandler.removeArg(QLatin1String("arg-2"));
+ ait = args.find(QLatin1String("arg-2"));
+ if (ait == args.end()) {
+ errorPrint(QLatin1String("Required argument typesystem-file is missing."));
+ return EXIT_FAILURE;
+ }
+ const QString typeSystemFileName = ait.value();
+ args.erase(ait);
QString messagePrefix = QFileInfo(typeSystemFileName).baseName();
if (messagePrefix.startsWith(QLatin1String("typesystem_")))
messagePrefix.remove(0, 11);
ReportHandler::setPrefix(QLatin1Char('(') + messagePrefix + QLatin1Char(')'));
- /* Make sure to remove the project file's arguments (if any) and
- * --project-file, also the arguments of each generator before
- * checking if there isn't any existing arguments in argsHandler.
- */
- argsHandler.removeArg(QLatin1String("project-file"));
- QMap<QString, QString> projectFileArgs = getInitializedArguments();
- if (!projectFileArgs.isEmpty()) {
- QMap<QString, QString>::const_iterator it =
- projectFileArgs.constBegin();
- for ( ; it != projectFileArgs.constEnd(); ++it)
- argsHandler.removeArg(it.key());
- }
- for (const GeneratorPtr &generator : qAsConst(generators)) {
- const OptionDescriptions &options = generator->options();
- for (const auto &od : options)
- argsHandler.removeArg(od.first);
- }
-
- const QString languageLevel = argsHandler.removeArg(languageLevelOption());
- if (!languageLevel.isEmpty()) {
- const QByteArray languageLevelBA = languageLevel.toLatin1();
+ // Pass option to all generators (Cpp/Header generator have the same options)
+ for (ait = args.begin(); ait != args.end(); ) {
+ bool found = false;
+ for (const GeneratorPtr &generator : qAsConst(generators))
+ found |= generator->handleOption(ait.key(), ait.value());
+ if (found)
+ ait = args.erase(ait);
+ else
+ ++ait;
+ }
+
+ ait = args.find(languageLevelOption());
+ if (ait != args.end()) {
+ const QByteArray languageLevelBA = ait.value().toLatin1();
+ args.erase(ait);
const LanguageLevel level = clang::languageLevelFromOption(languageLevelBA.constData());
if (level == LanguageLevel::Default) {
std::cout << "Invalid argument for language level: \""
@@ -620,8 +583,17 @@ int main(int argc, char *argv[])
extractor.setLanguageLevel(level);
}
- if (!argsHandler.noArgs()) {
- errorPrint(argsHandler.errorMessage());
+ /* Make sure to remove the project file's arguments (if any) and
+ * --project-file, also the arguments of each generator before
+ * checking if there isn't any existing arguments in argsHandler.
+ */
+ args.remove(QLatin1String("project-file"));
+ CommandArgumentMap projectFileArgs = getInitializedArguments();
+ for (auto it = projectFileArgs.cbegin(), end = projectFileArgs.cend(); it != end; ++it)
+ args.remove(it.key());
+
+ if (!args.isEmpty()) {
+ errorPrint(msgLeftOverArguments(args));
std::cout << helpHint;
return EXIT_FAILURE;
}
@@ -642,17 +614,16 @@ int main(int argc, char *argv[])
if (!extractor.classCount())
qCWarning(lcShiboken) << "No C++ classes found!";
- qCDebug(lcShiboken) << extractor;
+ qCDebug(lcShiboken) << extractor << '\n'
+ << *TypeDatabase::instance();
for (const GeneratorPtr &g : qAsConst(generators)) {
g->setOutputDirectory(outputDirectory);
g->setLicenseComment(licenseComment);
- if (g->setup(extractor, args)) {
- if (!g->generate()) {
- errorPrint(QLatin1String("Error running generator: ")
- + QLatin1String(g->name()) + QLatin1Char('.'));
- return EXIT_FAILURE;
- }
+ if (!g->setup(extractor) || !g->generate()) {
+ errorPrint(QLatin1String("Error running generator: ")
+ + QLatin1String(g->name()) + QLatin1Char('.'));
+ return EXIT_FAILURE;
}
}
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
index d47ba8bd7..19ddd5f37 100644
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
@@ -28,6 +28,7 @@
#include "qtdocgenerator.h"
#include <abstractmetalang.h>
+#include <messages.h>
#include <reporthandler.h>
#include <typesystem.h>
#include <qtdocparser.h>
@@ -202,34 +203,6 @@ private:
const QString &m_label;
};
-static QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
- const QString &tag, const QString &message)
-{
- QString result;
- QTextStream str(&result);
- str << "While handling <";
- const QStringRef currentTag = reader.name();
- if (currentTag.isEmpty())
- str << tag;
- else
- str << currentTag;
- str << "> in " << context << ", line "<< reader.lineNumber()
- << ": " << message;
- return result;
-}
-
-static QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context,
- const QString &tag, const QString &location, const QString &identifier,
- const QString &fallback)
-{
- QString message = QLatin1String("Falling back to \"")
- + QDir::toNativeSeparators(fallback) + QLatin1String("\" for \"") + location
- + QLatin1Char('"');
- if (!identifier.isEmpty())
- message += QLatin1String(" [") + identifier + QLatin1Char(']');
- return msgTagWarning(reader, context, tag, message);
-}
-
struct QtXmlToSphinx::LinkContext
{
enum Type
@@ -305,7 +278,7 @@ QTextStream &operator<<(QTextStream &str, const QtXmlToSphinx::LinkContext &link
}
QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context)
- : m_context(context), m_generator(generator), m_insideBold(false), m_insideItalic(false)
+ : m_tableHasHeader(false), m_context(context), m_generator(generator), m_insideBold(false), m_insideItalic(false)
{
m_handlerMap.insert(QLatin1String("heading"), &QtXmlToSphinx::handleHeadingTag);
m_handlerMap.insert(QLatin1String("brief"), &QtXmlToSphinx::handleParaTag);
@@ -1302,7 +1275,7 @@ bool QtXmlToSphinx::convertToRst(QtDocGenerator *generator,
QFile sourceFile(sourceFileName);
if (!sourceFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
if (errorMessage)
- *errorMessage = FileOut::msgCannotOpenForReading(sourceFile);
+ *errorMessage = msgCannotOpenForReading(sourceFile);
return false;
}
const QString doc = QString::fromUtf8(sourceFile.readAll());
@@ -1325,7 +1298,13 @@ void QtXmlToSphinx::Table::normalize()
//QDoc3 generates tables with wrong number of columns. We have to
//check and if necessary, merge the last columns.
- int maxCols = self.at(0).count();
+ int maxCols = -1;
+ for (const auto &row : qAsConst(self)) {
+ if (row.count() > maxCols)
+ maxCols = row.count();
+ }
+ if (maxCols <= 0)
+ return;
// add col spans
for (row = 0; row < count(); ++row) {
for (col = 0; col < at(row).count(); ++col) {
@@ -1513,11 +1492,10 @@ QString QtDocGenerator::fileNameForContext(GeneratorContext &context) const
const AbstractMetaClass *metaClass = context.metaClass();
if (!context.forSmartPointer()) {
return getClassTargetFullName(metaClass, false) + fileNameSuffix();
- } else {
- const AbstractMetaType *smartPointerType = context.preciseType();
- QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
- return fileNameBase + fileNameSuffix();
}
+ const AbstractMetaType *smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
+ return fileNameBase + fileNameSuffix();
}
void QtDocGenerator::writeFormattedText(QTextStream &s, const Documentation &doc,
@@ -1534,7 +1512,7 @@ void QtDocGenerator::writeFormattedText(QTextStream &s, const Documentation &doc
} else {
const QString &value = doc.value();
const QVector<QStringRef> lines = value.splitRef(QLatin1Char('\n'));
- int typesystemIndentation = std::numeric_limits<int>().max();
+ int typesystemIndentation = std::numeric_limits<int>::max();
// check how many spaces must be removed from the beginning of each line
for (const QStringRef &line : lines) {
const auto it = std::find_if(line.cbegin(), line.cend(),
@@ -1542,7 +1520,7 @@ void QtDocGenerator::writeFormattedText(QTextStream &s, const Documentation &doc
if (it != line.cend())
typesystemIndentation = qMin(typesystemIndentation, int(it - line.cbegin()));
}
- if (typesystemIndentation == std::numeric_limits<int>().max())
+ if (typesystemIndentation == std::numeric_limits<int>::max())
typesystemIndentation = 0;
for (const QStringRef &line : lines) {
s << INDENT
@@ -1677,7 +1655,7 @@ void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass*
functionList << str;
}
- if ((functionList.size() > 0) || (staticFunctionList.size() > 0)) {
+ if (!functionList.isEmpty() || !staticFunctionList.isEmpty()) {
QtXmlToSphinx::Table functionTable;
s << endl
@@ -1694,7 +1672,7 @@ void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass*
void QtDocGenerator::writeFunctionBlock(QTextStream& s, const QString& title, QStringList& functions)
{
- if (functions.size() > 0) {
+ if (!functions.isEmpty()) {
s << title << endl
<< QString(title.size(), QLatin1Char('^')) << endl;
@@ -1777,7 +1755,8 @@ void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass*
writeFormattedText(s, func->documentation(), cppClass);
}
-QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* /* cppClass */,
+ const AbstractMetaFunction* func)
{
QString ret;
int optArgs = 0;
@@ -1859,8 +1838,7 @@ void QtDocGenerator::writeDocSnips(QTextStream &s,
if (row.trimmed().size() == 0) {
if (currenRow == 0)
continue;
- else
- s << endl;
+ s << endl;
}
if (currenRow == 0) {
@@ -2124,7 +2102,7 @@ void QtDocGenerator::writeModuleDocumentation()
s << ".. module:: " << it.key() << endl << endl;
- QString title = it.key();
+ const QString &title = it.key();
s << title << endl;
s << Pad('*', title.length()) << endl << endl;
@@ -2201,7 +2179,7 @@ void QtDocGenerator::writeAdditionalDocumentation()
QFile additionalDocumentationFile(m_additionalDocumentationList);
if (!additionalDocumentationFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(lcShiboken, "%s",
- qPrintable(FileOut::msgCannotOpenForReading(additionalDocumentationFile)));
+ qPrintable(msgCannotOpenForReading(additionalDocumentationFile)));
return;
}
@@ -2261,32 +2239,28 @@ void QtDocGenerator::writeAdditionalDocumentation()
successCount, count);
}
-bool QtDocGenerator::doSetup(const QMap<QString, QString>& args)
-{
- m_libSourceDir = args.value(QLatin1String("library-source-dir"));
- m_docDataDir = args.value(QLatin1String("documentation-data-dir"));
#ifdef __WIN32__
# define PATH_SEP ';'
#else
# define PATH_SEP ':'
#endif
- m_codeSnippetDirs = args.value(QLatin1String("documentation-code-snippets-dir"), m_libSourceDir).split(QLatin1Char(PATH_SEP));
- m_extraSectionDir = args.value(QLatin1String("documentation-extra-sections-dir"));
- m_docParser = args.value(QLatin1String("doc-parser")) == QLatin1String("doxygen")
- ? static_cast<DocParser*>(new DoxygenParser)
- : static_cast<DocParser*>(new QtDocParser);
- qCDebug(lcShiboken).noquote().nospace() << "doc-parser: " << args.value(QLatin1String("doc-parser"));
+bool QtDocGenerator::doSetup()
+{
+ if (m_codeSnippetDirs.isEmpty())
+ m_codeSnippetDirs = m_libSourceDir.split(QLatin1Char(PATH_SEP));
+
+ if (!m_docParser)
+ m_docParser = new QtDocParser;
if (m_libSourceDir.isEmpty() || m_docDataDir.isEmpty()) {
qCWarning(lcShiboken) << "Documentation data dir and/or Qt source dir not informed, "
"documentation will not be extracted from Qt sources.";
return false;
- } else {
- m_docParser->setDocumentationDataDirectory(m_docDataDir);
- m_docParser->setLibrarySourceDirectory(m_libSourceDir);
}
- m_additionalDocumentationList = args.value(additionalDocumentationOption());
+
+ m_docParser->setDocumentationDataDirectory(m_docDataDir);
+ m_docParser->setLibrarySourceDirectory(m_libSourceDir);
return true;
}
@@ -2294,19 +2268,49 @@ bool QtDocGenerator::doSetup(const QMap<QString, QString>& args)
Generator::OptionDescriptions QtDocGenerator::options() const
{
return OptionDescriptions()
- << qMakePair(QLatin1String("doc-parser"),
+ << qMakePair(QLatin1String("doc-parser=<parser>"),
QLatin1String("The documentation parser used to interpret the documentation\n"
"input files (qdoc|doxygen)"))
- << qMakePair(QLatin1String("documentation-code-snippets-dir"),
+ << qMakePair(QLatin1String("documentation-code-snippets-dir=<dir>"),
QLatin1String("Directory used to search code snippets used by the documentation"))
- << qMakePair(QLatin1String("documentation-data-dir"),
+ << qMakePair(QLatin1String("documentation-data-dir=<dir>"),
QLatin1String("Directory with XML files generated by documentation tool"))
- << qMakePair(QLatin1String("documentation-extra-sections-dir"),
+ << qMakePair(QLatin1String("documentation-extra-sections-dir=<dir>"),
QLatin1String("Directory used to search for extra documentation sections"))
- << qMakePair(QLatin1String("library-source-dir"),
+ << qMakePair(QLatin1String("library-source-dir=<dir>"),
QLatin1String("Directory where library source code is located"))
- << qMakePair(additionalDocumentationOption(),
+ << qMakePair(additionalDocumentationOption() + QLatin1String("=<file>"),
QLatin1String("List of additional XML files to be converted to .rst files\n"
"(for example, tutorials)."));
}
+bool QtDocGenerator::handleOption(const QString &key, const QString &value)
+{
+ if (key == QLatin1String("library-source-dir")) {
+ m_libSourceDir = value;
+ return true;
+ }
+ if (key == QLatin1String("documentation-data-dir")) {
+ m_docDataDir = value;
+ return true;
+ }
+ if (key == QLatin1String("documentation-code-snippets-dir")) {
+ m_codeSnippetDirs = value.split(QLatin1Char(PATH_SEP));
+ return true;
+ }
+ if (key == QLatin1String("documentation-extra-sections-dir")) {
+ m_extraSectionDir = value;
+ return true;
+ }
+ if (key == QLatin1String("doc-parser")) {
+ qCDebug(lcShiboken).noquote().nospace() << "doc-parser: " << value;
+ if (value == QLatin1String("doxygen"))
+ m_docParser = new DoxygenParser;
+ return true;
+ }
+ if (key == additionalDocumentationOption()) {
+ m_additionalDocumentationList = value;
+ return true;
+ }
+ return false;
+}
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h
index e467abe90..5545de9a9 100644
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h
@@ -209,7 +209,7 @@ public:
QString docDataDir() const { return m_docDataDir; }
- bool doSetup(const QMap<QString, QString>& args) override;
+ bool doSetup() override;
const char* name() const override
{
@@ -217,15 +217,15 @@ public:
}
OptionDescriptions options() const override;
+ bool handleOption(const QString &key, const QString &value) override;
QStringList codeSnippetDirs() const
{
return m_codeSnippetDirs;
}
- bool shouldGenerate(const AbstractMetaClass *) const override;
-
protected:
+ bool shouldGenerate(const AbstractMetaClass *) const override;
QString fileNameSuffix() const override;
QString fileNameForContext(GeneratorContext &context) const override;
void generateClass(QTextStream &s, GeneratorContext &classContext) override;
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 9e1d6926e..99947d347 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -29,8 +29,10 @@
#include <memory>
#include "cppgenerator.h"
+#include "fileout.h"
#include "overloaddata.h"
#include <abstractmetalang.h>
+#include <messages.h>
#include <reporthandler.h>
#include <typedatabase.h>
@@ -41,6 +43,8 @@
#include <QtCore/QDebug>
#include <QMetaType>
+static const char CPP_ARG0[] = "cppArg0";
+
QHash<QString, QString> CppGenerator::m_nbFuncs = QHash<QString, QString>();
QHash<QString, QString> CppGenerator::m_sqFuncs = QHash<QString, QString>();
QHash<QString, QString> CppGenerator::m_mpFuncs = QHash<QString, QString>();
@@ -58,6 +62,28 @@ inline AbstractMetaType* getTypeWithoutContainer(AbstractMetaType* arg)
return arg;
}
+// A helper for writing C++ return statements for either void ("return;")
+// or some return value ("return value;")
+class returnStatement
+{
+public:
+ explicit returnStatement(QString s) : m_returnValue(std::move(s)) {}
+
+ friend QTextStream &operator<<(QTextStream &s, const returnStatement &r);
+
+private:
+ const QString m_returnValue;
+};
+
+QTextStream &operator<<(QTextStream &s, const returnStatement &r)
+{
+ s << "return";
+ if (!r.m_returnValue.isEmpty())
+ s << ' ' << r.m_returnValue;
+ s << ';';
+ return s;
+}
+
CppGenerator::CppGenerator()
{
// Number protocol structure members names
@@ -87,27 +113,27 @@ CppGenerator::CppGenerator()
m_nbFuncs.insert(QLatin1String("bool"), QLatin1String("nb_nonzero"));
// sequence protocol functions
- typedef QPair<QString, QString> StrPair;
m_sequenceProtocol.insert(QLatin1String("__len__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR), QLatin1String("Py_ssize_t")));
+ {QLatin1String("PyObject* self"),
+ QLatin1String("Py_ssize_t")});
m_sequenceProtocol.insert(QLatin1String("__getitem__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i"),
- QLatin1String("PyObject*")));
+ {QLatin1String("PyObject* self, Py_ssize_t _i"),
+ QLatin1String("PyObject*")});
m_sequenceProtocol.insert(QLatin1String("__setitem__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* _value"),
- QLatin1String("int")));
+ {QLatin1String("PyObject* self, Py_ssize_t _i, PyObject* _value"),
+ QLatin1String("int")});
m_sequenceProtocol.insert(QLatin1String("__getslice__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i1, Py_ssize_t _i2"),
- QLatin1String("PyObject*")));
+ {QLatin1String("PyObject* self, Py_ssize_t _i1, Py_ssize_t _i2"),
+ QLatin1String("PyObject*")});
m_sequenceProtocol.insert(QLatin1String("__setslice__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i1, Py_ssize_t _i2, PyObject* _value"),
- QLatin1String("int")));
+ {QLatin1String("PyObject* self, Py_ssize_t _i1, Py_ssize_t _i2, PyObject* _value"),
+ QLatin1String("int")});
m_sequenceProtocol.insert(QLatin1String("__contains__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _value"),
- QLatin1String("int")));
+ {QLatin1String("PyObject* self, PyObject* _value"),
+ QLatin1String("int")});
m_sequenceProtocol.insert(QLatin1String("__concat__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _other"),
- QLatin1String("PyObject*")));
+ {QLatin1String("PyObject* self, PyObject* _other"),
+ QLatin1String("PyObject*")});
// Sequence protocol structure members names
m_sqFuncs.insert(QLatin1String("__concat__"), QLatin1String("sq_concat"));
@@ -120,14 +146,14 @@ CppGenerator::CppGenerator()
// mapping protocol function
m_mappingProtocol.insert(QLatin1String("__mlen__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR),
- QLatin1String("Py_ssize_t")));
+ {QLatin1String("PyObject* self"),
+ QLatin1String("Py_ssize_t")});
m_mappingProtocol.insert(QLatin1String("__mgetitem__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key"),
- QLatin1String("PyObject*")));
+ {QLatin1String("PyObject* self, PyObject* _key"),
+ QLatin1String("PyObject*")});
m_mappingProtocol.insert(QLatin1String("__msetitem__"),
- StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key, PyObject* _value"),
- QLatin1String("int")));
+ {QLatin1String("PyObject* self, PyObject* _key, PyObject* _value"),
+ QLatin1String("int")});
// Sequence protocol structure members names
m_mpFuncs.insert(QLatin1String("__mlen__"), QLatin1String("mp_length"));
@@ -186,18 +212,19 @@ QVector<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(c
return result;
}
-bool CppGenerator::hasBoolCast(const AbstractMetaClass* metaClass) const
+const AbstractMetaFunction *CppGenerator::boolCast(const AbstractMetaClass* metaClass) const
{
if (!useIsNullAsNbNonZero())
- return false;
+ return nullptr;
// TODO: This could be configurable someday
const AbstractMetaFunction* func = metaClass->findFunction(QLatin1String("isNull"));
if (!func || !func->type() || !func->type()->typeEntry()->isPrimitive() || !func->isPublic())
- return false;
+ return nullptr;
const PrimitiveTypeEntry* pte = static_cast<const PrimitiveTypeEntry*>(func->type()->typeEntry());
while (pte->referencedTypeEntry())
pte = pte->referencedTypeEntry();
- return func && func->isConstant() && pte->name() == QLatin1String("bool") && func->arguments().isEmpty();
+ return func && func->isConstant() && pte->name() == QLatin1String("bool")
+ && func->arguments().isEmpty() ? func : nullptr;
}
typedef QMap<QString, AbstractMetaFunctionList> FunctionGroupMap;
@@ -219,6 +246,21 @@ static QString chopType(QString s)
return s;
}
+// Helper for field setters: Check for "const QWidget *" (settable field),
+// but not "int *const" (read-only field).
+static bool isPointerToConst(const AbstractMetaType *t)
+{
+ const AbstractMetaType::Indirections &indirections = t->indirectionsV();
+ return t->isConstant() && !indirections.isEmpty()
+ && indirections.constLast() != Indirection::ConstPointer;
+}
+
+static inline bool canGenerateFieldSetter(const AbstractMetaField *field)
+{
+ const AbstractMetaType *type = field->type();
+ return !type->isConstant() || isPointerToConst(type);
+}
+
/*!
Function used to write the class generated binding code on the buffer
\param s the output buffer
@@ -260,6 +302,8 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
// needs the 'set' class from C++ STL.
if (hasMultipleInheritanceInAncestry(metaClass))
s << "#include <set>" << endl;
+ if (metaClass->generateExceptionHandling())
+ s << "#include <exception>" << endl;
s << endl << "// module include" << endl << "#include \"" << getModuleHeaderFileName() << '"' << endl;
@@ -315,7 +359,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
static_cast<const SmartPointerTypeEntry *>(classContext.preciseType()
->typeEntry());
QString rawGetter = typeEntry->getter();
- s << "static const char * " SMART_POINTER_GETTER " = \"" << rawGetter << "\";";
+ s << "static const char * " << SMART_POINTER_GETTER << " = \"" << rawGetter << "\";";
}
// class inject-code native/beginning
@@ -459,7 +503,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
writeCopyFunction(s, classContext);
- signatureStream << metaClass->fullName() << ".__copy__()" << endl;
+ signatureStream << fullPythonClassName(metaClass) << ".__copy__()" << endl;
}
// Write single method definitions
@@ -490,16 +534,20 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
}
}
- if (hasBoolCast(metaClass)) {
+ if (const AbstractMetaFunction *f = boolCast(metaClass)) {
ErrorCode errorCode(-1);
- s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* self)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, classContext);
- s << INDENT << "int result;" << endl;
- s << INDENT << BEGIN_ALLOW_THREADS << endl;
- s << INDENT << "result = !" CPP_SELF_VAR "->isNull();" << endl;
- s << INDENT << END_ALLOW_THREADS << endl;
- s << INDENT << "return result;" << endl;
+ if (f->allowThread()) {
+ s << INDENT << "int result;" << endl;
+ s << INDENT << BEGIN_ALLOW_THREADS << endl;
+ s << INDENT << "result = !" << CPP_SELF_VAR << "->isNull();" << endl;
+ s << INDENT << END_ALLOW_THREADS << endl;
+ s << INDENT << "return result;" << endl;
+ } else {
+ s << INDENT << "return !" << CPP_SELF_VAR << "->isNull();" << endl;
+ }
s << '}' << endl << endl;
}
@@ -546,7 +594,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
if (metaField->isStatic())
continue;
writeGetterFunction(s, metaField, classContext);
- if (!metaField->type()->isConstant())
+ if (canGenerateFieldSetter(metaField))
writeSetterFunction(s, metaField, classContext);
s << endl;
}
@@ -557,10 +605,12 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
if (metaField->isStatic())
continue;
- bool hasSetter = !metaField->type()->isConstant();
s << INDENT << "{const_cast<char*>(\"" << metaField->name() << "\"), ";
- s << cpythonGetterFunctionName(metaField);
- s << ", " << (hasSetter ? cpythonSetterFunctionName(metaField) : QLatin1String("0"));
+ s << cpythonGetterFunctionName(metaField) << ", ";
+ if (canGenerateFieldSetter(metaField))
+ s << cpythonSetterFunctionName(metaField);
+ else
+ s << '0';
s << "}," << endl;
}
s << INDENT << "{0} // Sentinel" << endl;
@@ -686,7 +736,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
Indentation indentation(INDENT);
- QString defaultReturnExpr;
+ DefaultValue defaultReturnExpr;
if (retType) {
const FunctionModificationList &mods = func->modifications();
for (const FunctionModification &mod : mods) {
@@ -694,9 +744,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) {
static const QRegularExpression regex(QStringLiteral("%(\\d+)"));
Q_ASSERT(regex.isValid());
- defaultReturnExpr = argMod.replacedDefaultExpression;
+ QString expr = argMod.replacedDefaultExpression;
for (int offset = 0; ; ) {
- const QRegularExpressionMatch match = regex.match(defaultReturnExpr, offset);
+ const QRegularExpressionMatch match = regex.match(expr, offset);
if (!match.hasMatch())
break;
const int argId = match.capturedRef(1).toInt() - 1;
@@ -704,23 +754,27 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
qCWarning(lcShiboken) << "The expression used in return value contains an invalid index.";
break;
}
- defaultReturnExpr.replace(match.captured(0), func->arguments().at(argId)->name());
+ expr.replace(match.captured(0), func->arguments().at(argId)->name());
offset = match.capturedStart(1);
}
+ defaultReturnExpr.setType(DefaultValue::Custom);
+ defaultReturnExpr.setValue(expr);
}
}
}
- if (defaultReturnExpr.isEmpty())
+ if (!defaultReturnExpr.isValid())
defaultReturnExpr = minimalConstructor(func->type());
- if (defaultReturnExpr.isEmpty()) {
+ if (!defaultReturnExpr.isValid()) {
QString errorMsg = QLatin1String(__FUNCTION__) + QLatin1String(": ");
if (const AbstractMetaClass *c = func->implementingClass())
errorMsg += c->qualifiedCppName() + QLatin1String("::");
errorMsg += func->signature();
- errorMsg = ShibokenGenerator::msgCouldNotFindMinimalConstructor(errorMsg, func->type()->cppSignature());
+ errorMsg = msgCouldNotFindMinimalConstructor(errorMsg, func->type()->cppSignature());
qCWarning(lcShiboken).noquote().nospace() << errorMsg;
s << endl << INDENT << "#error " << errorMsg << endl;
}
+ } else {
+ defaultReturnExpr.setType(DefaultValue::Void);
}
if (func->isAbstract() && func->isModifiedRemoved()) {
@@ -728,7 +782,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
<< QString::fromLatin1("Pure virtual method '%1::%2' must be implement but was "\
"completely removed on type system.")
.arg(func->ownerClass()->name(), func->minimalSignature());
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
s << '}' << endl << endl;
return;
}
@@ -747,13 +801,13 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
s << INDENT << "if (PyErr_Occurred())" << endl;
{
Indentation indentation(INDENT);
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
- s << INDENT << "Shiboken::AutoDecRef " PYTHON_OVERRIDE_VAR "(Shiboken::BindingManager::instance().getOverride(this, \"";
+ s << INDENT << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR << "(Shiboken::BindingManager::instance().getOverride(this, \"";
s << funcName << "\"));" << endl;
- s << INDENT << "if (" PYTHON_OVERRIDE_VAR ".isNull()) {" << endl;
+ s << INDENT << "if (" << PYTHON_OVERRIDE_VAR << ".isNull()) {" << endl;
{
Indentation indentation(INDENT);
CodeSnipList snips;
@@ -768,7 +822,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
s << func->ownerClass()->name() << '.' << funcName;
s << "()' not implemented.\");" << endl;
- s << INDENT << "return " << (retType ? defaultReturnExpr : QString());
+ s << INDENT << "return";
+ if (retType)
+ s << ' ' << defaultReturnExpr.returnValue();
} else {
s << INDENT << "gil.release();" << endl;
s << INDENT;
@@ -785,7 +841,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
writeConversionRule(s, func, TypeSystem::TargetLangCode);
- s << INDENT << "Shiboken::AutoDecRef " PYTHON_ARGS "(";
+ s << INDENT << "Shiboken::AutoDecRef " << PYTHON_ARGS << "(";
if (func->arguments().isEmpty() || allArgumentsRemoved(func)) {
s << "PyTuple_New(0));" << endl;
@@ -844,7 +900,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
if (argMod.resetAfterUse && !invalidateArgs.contains(argMod.index)) {
invalidateArgs.insert(argMod.index);
s << INDENT << "bool invalidateArg" << argMod.index;
- s << " = PyTuple_GET_ITEM(" PYTHON_ARGS ", " << argMod.index - 1 << ")->ob_refcnt == 1;" << endl;
+ s << " = PyTuple_GET_ITEM(" << PYTHON_ARGS << ", " << argMod.index - 1 << ")->ob_refcnt == 1;" << endl;
} else if (argMod.index == 0 && argMod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::CppOwnership) {
invalidateReturn = true;
}
@@ -866,36 +922,36 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
if (!injectedCodeCallsPythonOverride(func)) {
s << INDENT;
- s << "Shiboken::AutoDecRef " PYTHON_RETURN_VAR "(PyObject_Call(" PYTHON_OVERRIDE_VAR ", " PYTHON_ARGS ", NULL));" << endl;
+ s << "Shiboken::AutoDecRef " << PYTHON_RETURN_VAR << "(PyObject_Call(" << PYTHON_OVERRIDE_VAR << ", " << PYTHON_ARGS << ", NULL));" << endl;
s << INDENT << "// An error happened in python code!" << endl;
- s << INDENT << "if (" PYTHON_RETURN_VAR ".isNull()) {" << endl;
+ s << INDENT << "if (" << PYTHON_RETURN_VAR << ".isNull()) {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "PyErr_Print();" << endl;
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
s << INDENT << '}' << endl;
if (retType) {
if (invalidateReturn)
- s << INDENT << "bool invalidateArg0 = " PYTHON_RETURN_VAR "->ob_refcnt == 1;" << endl;
+ s << INDENT << "bool invalidateArg0 = " << PYTHON_RETURN_VAR << "->ob_refcnt == 1;" << endl;
if (func->typeReplaced(0) != QLatin1String("PyObject")) {
s << INDENT << "// Check return type" << endl;
s << INDENT;
if (func->typeReplaced(0).isEmpty()) {
- s << "PythonToCppFunc " PYTHON_TO_CPP_VAR " = " << cpythonIsConvertibleFunction(func->type());
- s << PYTHON_RETURN_VAR ");" << endl;
- s << INDENT << "if (!" PYTHON_TO_CPP_VAR ") {" << endl;
+ s << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << " = " << cpythonIsConvertibleFunction(func->type());
+ s << PYTHON_RETURN_VAR << ");" << endl;
+ s << INDENT << "if (!" << PYTHON_TO_CPP_VAR << ") {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
"\"Invalid return value in function %s, expected %s, got %s.\", \"";
s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
- s << ", Py_TYPE(" PYTHON_RETURN_VAR ")->tp_name);" << endl;
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);" << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
s << INDENT << '}' << endl;
@@ -907,15 +963,16 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
isNumber(func->type()->typeEntry()), func->typeReplaced(0));
s << ';' << endl;
s << INDENT << "if (!typeIsValid";
- s << (isPointerToWrapperType(func->type()) ? " && " PYTHON_RETURN_VAR " != Py_None" : "");
+ if (isPointerToWrapperType(func->type()))
+ s << " && " << PYTHON_RETURN_VAR << " != Py_None";
s << ") {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
"\"Invalid return value in function %s, expected %s, got %s.\", \"";
s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
- s << ", Py_TYPE(" PYTHON_RETURN_VAR ")->tp_name);" << endl;
- s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);" << endl;
+ s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl;
}
s << INDENT << '}' << endl;
@@ -935,12 +992,12 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
if (invalidateReturn) {
s << INDENT << "if (invalidateArg0)" << endl;
Indentation indentation(INDENT);
- s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR ".object());" << endl;
+ s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR << ".object());" << endl;
}
for (int argIndex : qAsConst(invalidateArgs)) {
s << INDENT << "if (invalidateArg" << argIndex << ')' << endl;
Indentation indentation(INDENT);
- s << INDENT << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" PYTHON_ARGS ", ";
+ s << INDENT << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" << PYTHON_ARGS << ", ";
s << (argIndex - 1) << "));" << endl;
}
@@ -950,9 +1007,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
for (const ArgumentModification &argMod : funcMod.argument_mods) {
if (argMod.ownerships.contains(TypeSystem::NativeCode)
&& argMod.index == 0 && argMod.ownerships[TypeSystem::NativeCode] == TypeSystem::CppOwnership) {
- s << INDENT << "if (Shiboken::Object::checkType(" PYTHON_RETURN_VAR "))" << endl;
+ s << INDENT << "if (Shiboken::Object::checkType(" << PYTHON_RETURN_VAR << "))" << endl;
Indentation indent(INDENT);
- s << INDENT << "Shiboken::Object::releaseOwnership(" PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR << ");" << endl;
}
}
}
@@ -978,7 +1035,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun
}
if (func->type()->referenceType() == LValueReference && !isPointer(func->type()))
s << '*';
- s << CPP_RETURN_VAR ";" << endl;
+ s << CPP_RETURN_VAR << ';' << endl;
}
s << '}' << endl << endl;
@@ -995,7 +1052,7 @@ void CppGenerator::writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass
s << INDENT << "SbkObject* pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);" << endl;
s << INDENT << "if (pySelf == NULL)" << endl;
s << INDENT << INDENT << "return " << metaClass->qualifiedCppName() << "::metaObject();" << endl;
- s << INDENT << "return PySide::SignalManager::retriveMetaObject(reinterpret_cast<PyObject*>(pySelf));" << endl;
+ s << INDENT << "return PySide::SignalManager::retrieveMetaObject(reinterpret_cast<PyObject*>(pySelf));" << endl;
s << '}' << endl << endl;
// qt_metacall function
@@ -1259,7 +1316,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla
toCppConv = QLatin1Char('*') + cpythonWrapperCPtr(sourceClass->typeEntry(), QLatin1String("pyIn"));
} else {
// Constructor that does implicit conversion.
- if (!conv->typeReplaced(1).isEmpty())
+ if (!conv->typeReplaced(1).isEmpty() || conv->isModifiedToArray(1))
continue;
const AbstractMetaType* sourceType = conv->arguments().constFirst()->type();
typeCheck = cpythonCheckFunction(sourceType);
@@ -1419,7 +1476,7 @@ void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClas
sourceType = buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass());
} else {
// Constructor that does implicit conversion.
- if (!conv->typeReplaced(1).isEmpty())
+ if (!conv->typeReplaced(1).isEmpty() || conv->isModifiedToArray(1))
continue;
sourceType = conv->arguments().constFirst()->type();
}
@@ -1467,7 +1524,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
// Check if the right constructor was called.
if (!ownerClass->hasPrivateDestructor()) {
s << INDENT;
- s << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ") && !Shiboken::ObjectType::canCallConstructor(" PYTHON_SELF_VAR "->ob_type, Shiboken::SbkType< ::";
+ s << "if (Shiboken::Object::isUserType(self) && !Shiboken::ObjectType::canCallConstructor(self->ob_type, Shiboken::SbkType< ::";
QString qualifiedCppName;
if (!context.forSmartPointer())
qualifiedCppName = ownerClass->qualifiedCppName();
@@ -1476,7 +1533,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
s << qualifiedCppName << " >()))" << endl;
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl << endl;
}
// Declare pointer for the underlying C++ object.
s << INDENT << "::";
@@ -1497,7 +1554,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
writeCppSelfDefinition(s, rfunc, context, overloadData.hasStaticFunction());
}
if (!rfunc->isInplaceOperator() && overloadData.hasNonVoidReturnType())
- s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
+ s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = 0;" << endl;
initPythonArguments = minArgs != maxArgs || maxArgs > 1;
usesNamedArguments = rfunc->isCallOperator() || overloadData.hasArgumentWithDefaultValue();
@@ -1505,7 +1562,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
if (maxArgs > 0) {
s << INDENT << "int overloadId = -1;" << endl;
- s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR;
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR;
if (pythonFunctionWrapperUsesListOfArguments(overloadData))
s << "[] = { 0" << QString::fromLatin1(", 0").repeated(maxArgs-1) << " }";
s << ';' << endl;
@@ -1518,7 +1575,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over
if (initPythonArguments) {
s << INDENT << "int numArgs = ";
if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData))
- s << "(" PYTHON_ARG " == 0 ? 0 : 1);" << endl;
+ s << "(" << PYTHON_ARG << " == 0 ? 0 : 1);" << endl;
else
writeArgumentsInitializer(s, overloadData);
}
@@ -1534,7 +1591,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
const AbstractMetaClass* metaClass = rfunc->ownerClass();
s << "static int" << endl;
- s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* args, PyObject* kwds)" << endl;
+ s << cpythonFunctionName(rfunc) << "(PyObject* self, PyObject* args, PyObject* kwds)" << endl;
s << '{' << endl;
QSet<QString> argNamesSet;
@@ -1560,10 +1617,10 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
s << INDENT << "const QMetaObject* metaObject;" << endl;
}
- s << INDENT << "SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(self);" << endl;
if (metaClass->isAbstract() || metaClass->baseClassNames().size() > 1) {
- s << INDENT << "SbkObjectType* type = reinterpret_cast<SbkObjectType*>(" PYTHON_SELF_VAR "->ob_type);" << endl;
+ s << INDENT << "SbkObjectType* type = reinterpret_cast<SbkObjectType*>(self->ob_type);" << endl;
s << INDENT << "SbkObjectType* myType = reinterpret_cast<SbkObjectType*>(" << cpythonTypeNameExt(metaClass->typeEntry()) << ");" << endl;
}
@@ -1577,7 +1634,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
s << INDENT << "\"'" << metaClass->qualifiedCppName();
}
s << "' represents a C++ abstract class and cannot be instantiated\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}' << endl << endl;
}
@@ -1608,7 +1665,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
{
Indentation indent(INDENT);
s << INDENT << "delete cptr;" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}' << endl;
if (overloadData.maxArgs() > 0) {
@@ -1636,12 +1693,12 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun
// Create metaObject and register signal/slot
if (metaClass->isQObject() && usePySideExtensions()) {
s << endl << INDENT << "// QObject setup" << endl;
- s << INDENT << "PySide::Signal::updateSourceObject(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "PySide::Signal::updateSourceObject(self);" << endl;
s << INDENT << "metaObject = cptr->metaObject(); // <- init python qt properties" << endl;
- s << INDENT << "if (kwds && !PySide::fillQtProperties(" PYTHON_SELF_VAR ", metaObject, kwds, argNames, " << argNamesSet.count() << "))" << endl;
+ s << INDENT << "if (kwds && !PySide::fillQtProperties(self, metaObject, kwds, argNames, " << argNamesSet.count() << "))" << endl;
{
Indentation indentation(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
}
@@ -1694,7 +1751,7 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
int maxArgs = overloadData.maxArgs();
s << "static PyObject* ";
- s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR;
+ s << cpythonFunctionName(rfunc) << "(PyObject* self";
if (maxArgs > 0) {
s << ", PyObject* " << (pythonFunctionWrapperUsesListOfArguments(overloadData) ? "args" : PYTHON_ARG);
if (overloadData.hasArgumentWithDefaultValue() || rfunc->isCallOperator())
@@ -1725,26 +1782,26 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
s << INDENT << "if (!isReverse" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "&& Shiboken::Object::checkType(" PYTHON_ARG ")" << endl;
- s << INDENT << "&& !PyObject_TypeCheck(" PYTHON_ARG ", " PYTHON_SELF_VAR "->ob_type)" << endl;
- s << INDENT << "&& PyObject_HasAttrString(" PYTHON_ARG ", const_cast<char*>(\"" << revOpName << "\"))) {" << endl;
+ s << INDENT << "&& Shiboken::Object::checkType(" << PYTHON_ARG << ")" << endl;
+ s << INDENT << "&& !PyObject_TypeCheck(" << PYTHON_ARG << ", self->ob_type)" << endl;
+ s << INDENT << "&& PyObject_HasAttrString(" << PYTHON_ARG << ", const_cast<char*>(\"" << revOpName << "\"))) {" << endl;
// This PyObject_CallMethod call will emit lots of warnings like
// "deprecated conversion from string constant to char *" during compilation
// due to the method name argument being declared as "char*" instead of "const char*"
// issue 6952 http://bugs.python.org/issue6952
- s << INDENT << "PyObject* revOpMethod = PyObject_GetAttrString(" PYTHON_ARG ", const_cast<char*>(\"" << revOpName << "\"));" << endl;
+ s << INDENT << "PyObject* revOpMethod = PyObject_GetAttrString(" << PYTHON_ARG << ", const_cast<char*>(\"" << revOpName << "\"));" << endl;
s << INDENT << "if (revOpMethod && PyCallable_Check(revOpMethod)) {" << endl;
{
Indentation indent(INDENT);
- s << INDENT << PYTHON_RETURN_VAR " = PyObject_CallFunction(revOpMethod, const_cast<char*>(\"O\"), " PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << PYTHON_RETURN_VAR << " = PyObject_CallFunction(revOpMethod, const_cast<char*>(\"O\"), self);" << endl;
s << INDENT << "if (PyErr_Occurred() && (PyErr_ExceptionMatches(PyExc_NotImplementedError)";
s << " || PyErr_ExceptionMatches(PyExc_AttributeError))) {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "PyErr_Clear();" << endl;
- s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl;
- s << INDENT << PYTHON_RETURN_VAR " = 0;" << endl;
+ s << INDENT << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");" << endl;
+ s << INDENT << PYTHON_RETURN_VAR << " = 0;" << endl;
}
s << INDENT << '}' << endl;
}
@@ -1754,7 +1811,7 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
s << INDENT << "}" << endl;
}
s << INDENT << "// Do not enter here if other object has implemented a reverse operator." << endl;
- s << INDENT << "if (!" PYTHON_RETURN_VAR ") {" << endl << endl;
+ s << INDENT << "if (!" << PYTHON_RETURN_VAR << ") {" << endl << endl;
}
if (maxArgs > 0)
@@ -1763,7 +1820,7 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
writeFunctionCalls(s, overloadData, classContext);
if (callExtendedReverseOperator)
- s << endl << INDENT << "} // End of \"if (!" PYTHON_RETURN_VAR ")\"" << endl;
+ s << endl << INDENT << "} // End of \"if (!" << PYTHON_RETURN_VAR << ")\"" << endl;
s << endl;
@@ -1771,10 +1828,10 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction
if (hasReturnValue) {
if (rfunc->isInplaceOperator()) {
- s << INDENT << "Py_INCREF(" PYTHON_SELF_VAR ");\n";
- s << INDENT << "return " PYTHON_SELF_VAR ";\n";
+ s << INDENT << "Py_INCREF(self);\n";
+ s << INDENT << "return self;\n";
} else {
- s << INDENT << "return " PYTHON_RETURN_VAR ";\n";
+ s << INDENT << "return " << PYTHON_RETURN_VAR << ";\n";
}
} else {
s << INDENT << "Py_RETURN_NONE;" << endl;
@@ -1795,7 +1852,7 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl
int maxArgs = overloadData.maxArgs();
s << INDENT << "PyObject* ";
- s << PYTHON_ARGS "[] = {"
+ s << PYTHON_ARGS << "[] = {"
<< QString(maxArgs, QLatin1Char('0')).split(QLatin1String(""), QString::SkipEmptyParts).join(QLatin1String(", "))
<< "};" << endl;
s << endl;
@@ -1807,8 +1864,8 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl
s << INDENT << "PyObject* nonvarargs = PyTuple_GetSlice(args, 0, " << maxArgs << ");" << endl;
s << INDENT << "Shiboken::AutoDecRef auto_nonvarargs(nonvarargs);" << endl;
- s << INDENT << PYTHON_ARGS "[" << maxArgs << "] = PyTuple_GetSlice(args, " << maxArgs << ", numArgs);" << endl;
- s << INDENT << "Shiboken::AutoDecRef auto_varargs(" PYTHON_ARGS "[" << maxArgs << "]);" << endl;
+ s << INDENT << PYTHON_ARGS << '[' << maxArgs << "] = PyTuple_GetSlice(args, " << maxArgs << ", numArgs);" << endl;
+ s << INDENT << "Shiboken::AutoDecRef auto_varargs(" << PYTHON_ARGS << "[" << maxArgs << "]);" << endl;
s << endl;
}
@@ -1822,7 +1879,7 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): too many arguments\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}';
}
@@ -1835,7 +1892,7 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): not enough arguments\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}';
}
@@ -1867,13 +1924,12 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl
s << "PyArg_ParseTuple(" << argsVar << ", \"|" << QByteArray(maxArgs, 'O') << ':' << funcName << '"';
else
s << "PyArg_UnpackTuple(" << argsVar << ", \"" << funcName << "\", " << minArgs << ", " << maxArgs;
- QStringList palist;
for (int i = 0; i < maxArgs; i++)
- palist << QString::fromLatin1("&(" PYTHON_ARGS "[%1])").arg(i);
- s << ", " << palist.join(QLatin1String(", ")) << "))" << endl;
+ s << ", &(" << PYTHON_ARGS << '[' << i << "])";
+ s << "))" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << endl;
}
@@ -1895,7 +1951,7 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s,
}
QString cppSelfAttribution;
- QString pythonSelfVar = QLatin1String(PYTHON_SELF_VAR);
+ QString pythonSelfVar = QLatin1String("self");
QString cpythonWrapperCPtrResult;
if (!context.forSmartPointer())
cpythonWrapperCPtrResult = cpythonWrapperCPtr(metaClass, pythonSelfVar);
@@ -1908,7 +1964,7 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s,
.arg(className, QLatin1String(CPP_SELF_VAR), cast,
cpythonWrapperCPtrResult);
} else {
- s << INDENT << className << "* " CPP_SELF_VAR " = 0;" << endl;
+ s << INDENT << className << "* " << CPP_SELF_VAR << " = 0;" << endl;
writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
cppSelfAttribution = QString::fromLatin1("%1 = %2%3")
.arg(QLatin1String(CPP_SELF_VAR),
@@ -1918,17 +1974,17 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s,
// Checks if the underlying C++ object is valid.
if (hasStaticOverload && !cppSelfAsReference) {
- s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl;
+ s << INDENT << "if (self) {" << endl;
{
Indentation indent(INDENT);
- writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ writeInvalidPyObjectCheck(s, QLatin1String("self"));
s << INDENT << cppSelfAttribution << ';' << endl;
}
s << INDENT << '}' << endl;
return;
}
- writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ writeInvalidPyObjectCheck(s, QLatin1String("self"));
s << INDENT << cppSelfAttribution << ';' << endl;
}
@@ -1942,17 +1998,17 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s,
if (func->isOperatorOverload() && func->isBinaryOperator()) {
QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry());
- s << INDENT << "bool isReverse = " << checkFunc << PYTHON_ARG ")" << endl;
+ s << INDENT << "bool isReverse = " << checkFunc << PYTHON_ARG << ')' << endl;
{
Indentation indent1(INDENT);
Indentation indent2(INDENT);
Indentation indent3(INDENT);
Indentation indent4(INDENT);
- s << INDENT << "&& !" << checkFunc << PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "&& !" << checkFunc << "self);" << endl;
}
s << INDENT << "if (isReverse)" << endl;
Indentation indent(INDENT);
- s << INDENT << "std::swap(" PYTHON_SELF_VAR ", " PYTHON_ARG ");" << endl;
+ s << INDENT << "std::swap(self, " << PYTHON_ARG << ");" << endl;
}
writeCppSelfDefinition(s, context, hasStaticOverload);
@@ -2053,17 +2109,20 @@ void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData)
<< ", 0};" << endl;
s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", overloads);" << endl;
}
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
void CppGenerator::writeFunctionReturnErrorCheckSection(QTextStream& s, bool hasReturnValue)
{
- s << INDENT << "if (PyErr_Occurred()" << (hasReturnValue ? " || !" PYTHON_RETURN_VAR : "") << ") {" << endl;
+ s << INDENT << "if (PyErr_Occurred()";
+ if (hasReturnValue)
+ s << " || !" << PYTHON_RETURN_VAR;
+ s << ") {" << endl;
{
Indentation indent(INDENT);
if (hasReturnValue)
- s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");" << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}' << endl;
}
@@ -2072,12 +2131,13 @@ void CppGenerator::writeInvalidPyObjectCheck(QTextStream& s, const QString& pyOb
{
s << INDENT << "if (!Shiboken::Object::isValid(" << pyObj << "))" << endl;
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
static QString pythonToCppConverterForArgumentName(const QString& argumentName)
{
- static const QRegularExpression pyArgsRegex(QLatin1String(PYTHON_ARGS"(\\[\\d+[-]?\\d*\\])"));
+ static const QRegularExpression pyArgsRegex(QLatin1String(PYTHON_ARGS)
+ + QLatin1String(R"((\[\d+[-]?\d*\]))"));
Q_ASSERT(pyArgsRegex.isValid());
const QRegularExpressionMatch match = pyArgsRegex.match(argumentName);
QString result = QLatin1String(PYTHON_TO_CPP_VAR);
@@ -2379,7 +2439,7 @@ void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunctio
void CppGenerator::writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue)
{
if (thereIsReturnValue && (!func->type() || func->argumentRemoved(0)) && !injectedCodeHasReturnValueAttribution(func)) {
- s << INDENT << PYTHON_RETURN_VAR " = Py_None;" << endl;
+ s << INDENT << PYTHON_RETURN_VAR << " = Py_None;" << endl;
s << INDENT << "Py_INCREF(Py_None);" << endl;
}
}
@@ -2493,8 +2553,9 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const Ov
const AbstractMetaFunction* refFunc = overloadData->referenceFunction();
QStringList typeChecks;
+
QString pyArgName = (usePyArgs && maxArgs > 1)
- ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(overloadData->argPos())
+ ? pythonArgsAt(overloadData->argPos())
: QLatin1String(PYTHON_ARG);
OverloadData* od = overloadData;
int startArg = od->argPos();
@@ -2503,7 +2564,7 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const Ov
bool typeReplacedByPyObject = od->argumentTypeReplaced() == QLatin1String("PyObject");
if (!typeReplacedByPyObject) {
if (usePyArgs)
- pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(od->argPos());
+ pyArgName = pythonArgsAt(od->argPos());
QString typeCheck;
QTextStream tck(&typeCheck);
const AbstractMetaFunction* func = od->referenceFunction();
@@ -2613,7 +2674,7 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s,
s << INDENT << "PyErr_Format(PyExc_TypeError, \"%s is a private method.\", \""
<< func->signature().replace(QLatin1String("::"), QLatin1String("."))
<< "\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
return;
}
@@ -2630,7 +2691,8 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s,
const AbstractMetaArgument* arg = func->arguments().at(argIdx);
if (func->argumentRemoved(argIdx + 1)) {
if (!arg->defaultValueExpression().isEmpty()) {
- QString cppArgRemoved = QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(argIdx);
+ const QString cppArgRemoved = QLatin1String(CPP_ARG_REMOVED)
+ + QString::number(argIdx);
s << INDENT << getFullTypeName(arg->type()) << ' ' << cppArgRemoved;
s << " = " << guessScopeForDefaultValue(func, arg) << ';' << endl;
writeUnusedVariableCast(s, cppArgRemoved);
@@ -2649,8 +2711,8 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s,
if (!argType || (mayHaveUnunsedArguments && !injectedCodeUsesArgument(func, argIdx)))
continue;
int argPos = argIdx - removedArgs;
- QString argName = QString::fromLatin1(CPP_ARG"%1").arg(argPos);
- QString pyArgName = usePyArgs ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argPos) : QLatin1String(PYTHON_ARG);
+ QString argName = QLatin1String(CPP_ARG) + QString::number(argPos);
+ QString pyArgName = usePyArgs ? pythonArgsAt(argPos) : QLatin1String(PYTHON_ARG);
QString defaultValue = guessScopeForDefaultValue(func, arg);
writeArgumentConversion(s, argType, argName, pyArgName, func->implementingClass(), defaultValue, func->isUserAdded());
}
@@ -2896,10 +2958,8 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, const Abs
const AbstractMetaType* type = containerType->instantiations().at(i);
QString typeName = getFullTypeName(type);
if (type->isValue() && isValueTypeWithCopyConstructorOnly(type)) {
- static const QRegularExpression regex(QLatin1String(CONVERTTOCPP_REGEX));
- Q_ASSERT(regex.isValid());
for (int pos = 0; ; ) {
- const QRegularExpressionMatch match = regex.match(code, pos);
+ const QRegularExpressionMatch match = convertToCppRegEx().match(code, pos);
if (!match.hasMatch())
break;
pos = match.capturedEnd();
@@ -2954,15 +3014,13 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream& s, const AbstractMe
s << INDENT << "PyObject* ";
for (const AbstractMetaArgument *arg : args) {
int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
- QString pyArgName = usePyArgs
- ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(pyArgIndex)
- : QLatin1String(PYTHON_ARG);
+ QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex) : QLatin1String(PYTHON_ARG);
s << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl;
s << INDENT << "if (value && " << pyArgName << ") {" << endl;
{
Indentation indent(INDENT);
s << INDENT << pyErrString.arg(arg->name()) << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << "} else if (value) {" << endl;
{
@@ -2989,7 +3047,7 @@ QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, in
*wrappedClass = 0;
QString pyArgName;
if (argIndex == -1) {
- pyArgName = QLatin1String(PYTHON_SELF_VAR);
+ pyArgName = QLatin1String("self");
*wrappedClass = func->implementingClass();
} else if (argIndex == 0) {
AbstractMetaType *funcType = func->type();
@@ -3016,12 +3074,23 @@ QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, in
&& OverloadData::isSingleArgument(getFunctionGroups(func->implementingClass())[func->name()]))
pyArgName = QLatin1String(PYTHON_ARG);
else
- pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argIndex - 1);
+ pyArgName = pythonArgsAt(argIndex - 1);
}
}
return pyArgName;
}
+static QStringList defaultExceptionHandling()
+{
+ static const QStringList result{
+ QLatin1String("} catch (const std::exception &e) {"),
+ QLatin1String(" PyErr_SetString(PyExc_RuntimeError, e.what());"),
+ QLatin1String("} catch (...) {"),
+ QLatin1String(" PyErr_SetString(PyExc_RuntimeError, \"An unknown exception was caught\");"),
+ QLatin1String("}")};
+ return result;
+}
+
void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *func,
GeneratorContext &context, int maxArgs)
{
@@ -3037,12 +3106,12 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
}
if (func->isAbstract()) {
- s << INDENT << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "))) {\n";
+ s << INDENT << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(self))) {\n";
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
s << func->ownerClass()->name() << '.' << func->name() << "()' not implemented.\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << "}\n";
}
@@ -3091,16 +3160,21 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
if (hasConversionRule)
userArgs << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
else if (!arg->defaultValueExpression().isEmpty())
- userArgs << QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(i);
+ userArgs.append(QLatin1String(CPP_ARG_REMOVED) + QString::number(i));
} else {
int idx = arg->argumentIndex() - removedArgs;
bool deRef = isValueTypeWithCopyConstructorOnly(arg->type())
|| isObjectTypeUsedAsValueType(arg->type())
|| (arg->type()->referenceType() == LValueReference && isWrapperType(arg->type()) && !isPointer(arg->type()));
- QString argName = hasConversionRule
- ? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)
- : QString::fromLatin1("%1" CPP_ARG "%2").arg(deRef ? QLatin1String("*") : QString()).arg(idx);
- userArgs << argName;
+ if (hasConversionRule) {
+ userArgs.append(arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX));
+ } else {
+ QString argName;
+ if (deRef)
+ argName += QLatin1Char('*');
+ argName += QLatin1String(CPP_ARG) + QString::number(idx);
+ userArgs.append(argName);
+ }
}
}
@@ -3113,17 +3187,16 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
bool argsClear = true;
for (int i = func->arguments().size() - 1; i >= maxArgs + removedArgs; i--) {
const AbstractMetaArgument* arg = func->arguments().at(i);
- bool defValModified = arg->defaultValueExpression() != arg->originalDefaultValueExpression();
+ const bool defValModified = arg->hasModifiedDefaultValueExpression();
bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
if (argsClear && !defValModified && !hasConversionRule)
continue;
- else
- argsClear = false;
+ argsClear = false;
otherArgsModified |= defValModified || hasConversionRule || func->argumentRemoved(i + 1);
if (hasConversionRule)
otherArgs.prepend(arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX));
else
- otherArgs.prepend(QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(i));
+ otherArgs.prepend(QLatin1String(CPP_ARG_REMOVED) + QString::number(i));
}
if (otherArgsModified)
userArgs << otherArgs;
@@ -3135,10 +3208,11 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
QString useVAddr;
QTextStream uva(&useVAddr);
if (func->isOperatorOverload() && !func->isCallOperator()) {
- QString firstArg = QLatin1String("(*" CPP_SELF_VAR ")");
- if (func->isPointerOperator())
- firstArg.remove(1, 1); // remove the de-reference operator
-
+ QString firstArg(QLatin1Char('('));
+ if (!func->isPointerOperator()) // no de-reference operator
+ firstArg += QLatin1Char('*');
+ firstArg += QLatin1String(CPP_SELF_VAR);
+ firstArg += QLatin1Char(')');
QString secondArg = QLatin1String(CPP_ARG0);
if (!func->isUnaryOperator() && shouldDereferenceArgumentPointer(func->arguments().constFirst())) {
secondArg.prepend(QLatin1String("(*"));
@@ -3211,7 +3285,8 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
} else {
const QString selfVarCast = func->ownerClass() == func->implementingClass()
? QLatin1String(CPP_SELF_VAR)
- : QLatin1String("reinterpret_cast<") + methodCallClassName + QLatin1String(" *>(" CPP_SELF_VAR ")");
+ : QLatin1String("reinterpret_cast<") + methodCallClassName
+ + QLatin1String(" *>(") + QLatin1String(CPP_SELF_VAR) + QLatin1Char(')');
if (func->isConstant()) {
if (avoidProtectedHack()) {
mc << "const_cast<const ::";
@@ -3219,7 +3294,8 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
// PYSIDE-500: Need a special wrapper cast when inherited
const QString selfWrapCast = func->ownerClass() == func->implementingClass()
? QLatin1String(CPP_SELF_VAR)
- : QLatin1String("reinterpret_cast<") + wrapperName(func->ownerClass()) + QLatin1String(" *>(" CPP_SELF_VAR ")");
+ : QLatin1String("reinterpret_cast<") + wrapperName(func->ownerClass())
+ + QLatin1String(" *>(") + QLatin1String(CPP_SELF_VAR) + QLatin1Char(')');
mc << wrapperName(func->ownerClass());
mc << "*>(" << selfWrapCast << ")->";
}
@@ -3263,7 +3339,7 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
methodCallClassName);
normalCall.remove(QLatin1String("::%CLASS_NAME::"));
methodCall.clear();
- mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")) ? ";
+ mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(self)) ? ";
mc << virtualCall << " : " << normalCall;
}
}
@@ -3271,7 +3347,19 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
}
if (!injectedCodeCallsCppFunction(func)) {
- s << INDENT << BEGIN_ALLOW_THREADS << endl << INDENT;
+ const bool allowThread = func->allowThread();
+ const bool generateExceptionHandling = func->generateExceptionHandling();
+ if (generateExceptionHandling) {
+ s << INDENT << "try {\n";
+ ++INDENT.indent;
+ if (allowThread) {
+ s << INDENT << "Shiboken::ThreadStateSaver threadSaver;\n"
+ << INDENT << "threadSaver.save();\n";
+ }
+ } else if (allowThread) {
+ s << INDENT << BEGIN_ALLOW_THREADS << endl;
+ }
+ s << INDENT;
if (isCtor) {
s << (useVAddr.isEmpty() ?
QString::fromLatin1("cptr = %1;").arg(methodCall) : useVAddr) << endl;
@@ -3299,18 +3387,23 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
methodCall.append(QLatin1Char(')'));
}
}
- s << " " CPP_RETURN_VAR " = ";
+ s << " " << CPP_RETURN_VAR << " = ";
s << methodCall << ';' << endl;
} else {
s << methodCall << ';' << endl;
}
- s << INDENT << END_ALLOW_THREADS << endl;
+ if (allowThread) {
+ s << INDENT << (generateExceptionHandling
+ ? "threadSaver.restore();" : END_ALLOW_THREADS) << '\n';
+ }
+
+ // Convert result
if (!func->conversionRule(TypeSystem::TargetLangCode, 0).isEmpty()) {
writeConversionRule(s, func, TypeSystem::TargetLangCode, QLatin1String(PYTHON_RETURN_VAR));
} else if (!isCtor && !func->isInplaceOperator() && func->type()
&& !injectedCodeHasReturnValueAttribution(func, TypeSystem::TargetLangCode)) {
- s << INDENT << PYTHON_RETURN_VAR " = ";
+ s << INDENT << PYTHON_RETURN_VAR << " = ";
if (isObjectTypeUsedAsValueType(func->type())) {
s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(func->type()->typeEntry())
<< "), " << CPP_RETURN_VAR << ", true, true)";
@@ -3319,6 +3412,13 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
}
s << ';' << endl;
}
+
+ if (generateExceptionHandling) { // "catch" code
+ --INDENT.indent;
+ const QStringList handlingCode = defaultExceptionHandling();
+ for (const auto &line : handlingCode)
+ s << INDENT << line << '\n';
+ }
}
}
@@ -3370,7 +3470,7 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
s << "getOwnership(" << pyArgName << ");";
} else if (wrappedClass->hasVirtualDestructor()) {
if (arg_mod.index == 0)
- s << "releaseOwnership(" PYTHON_RETURN_VAR ");";
+ s << "releaseOwnership(" << PYTHON_RETURN_VAR << ");";
else
s << "releaseOwnership(" << pyArgName << ");";
} else {
@@ -3406,10 +3506,10 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f
else
s << INDENT << "Shiboken::Object::removeReference(";
- s << "reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \"";
+ s << "reinterpret_cast<SbkObject*>(self), \"";
QString varName = arg_mod.referenceCounts.constFirst().varName;
if (varName.isEmpty())
- varName = func->minimalSignature() + QString().number(arg_mod.index);
+ varName = func->minimalSignature() + QString::number(arg_mod.index);
s << varName << "\", " << pyArgName
<< (refCount.action == ReferenceCount::Add ? ", true" : "")
@@ -3531,7 +3631,7 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn
const FlagsTypeEntry* flags = 0;
if (enumType->isFlags())
- flags = reinterpret_cast<const FlagsTypeEntry*>(enumType);
+ flags = static_cast<const FlagsTypeEntry*>(enumType);
s << INDENT << "// Register converter for " << enumFlagName << " '" << enumType->qualifiedCppName() << "'." << endl;
s << INDENT << '{' << endl;
@@ -3575,7 +3675,7 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn
s << INDENT << '}' << endl;
if (!flags)
- writeEnumConverterInitialization(s, reinterpret_cast<const EnumTypeEntry*>(enumType)->flags());
+ writeEnumConverterInitialization(s, static_cast<const EnumTypeEntry*>(enumType)->flags());
}
void CppGenerator::writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type)
@@ -3656,10 +3756,7 @@ bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClass* metaClass)
}
const ComplexTypeEntry* baseType = metaClass->typeEntry()->baseContainerType();
- if (baseType && baseType->isContainer())
- return true;
-
- return false;
+ return baseType && baseType->isContainer();
}
bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass* metaClass)
@@ -3872,7 +3969,7 @@ void CppGenerator::writeMappingMethods(QTextStream &s,
CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl;
- writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ writeInvalidPyObjectCheck(s, QLatin1String("self"));
writeCppSelfDefinition(s, func, context);
@@ -3899,7 +3996,7 @@ void CppGenerator::writeSequenceMethods(QTextStream &s,
CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl;
- writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ writeInvalidPyObjectCheck(s, QLatin1String("self"));
writeCppSelfDefinition(s, func, context);
@@ -3964,7 +4061,6 @@ void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMe
funcs.insert(QLatin1String("__msetitem__"), QString());
}
- QString baseName = cpythonBaseName(metaClass);
for (auto it = m_mpFuncs.cbegin(), end = m_mpFuncs.cend(); it != end; ++it) {
const QString &mpName = it.key();
if (funcs[mpName].isEmpty())
@@ -4015,7 +4111,8 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet
QString baseName = cpythonBaseName(metaClass);
- nb[QLatin1String("bool")] = hasBoolCast(metaClass) ? baseName + QLatin1String("___nb_bool") : QString();
+ if (hasBoolCast(metaClass))
+ nb.insert(QLatin1String("bool"), baseName + QLatin1String("___nb_bool"));
for (QHash<QString, QString>::const_iterator it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) {
const QString &nbName = it.key();
@@ -4054,9 +4151,9 @@ void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaCla
{
QString baseName = cpythonBaseName(metaClass);
s << "static int ";
- s << baseName << "_traverse(PyObject* " PYTHON_SELF_VAR ", visitproc visit, void* arg)" << endl;
+ s << baseName << "_traverse(PyObject* self, visitproc visit, void* arg)" << endl;
s << '{' << endl;
- s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl;
+ s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_traverse(self, visit, arg);" << endl;
s << '}' << endl;
}
@@ -4064,9 +4161,9 @@ void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass*
{
QString baseName = cpythonBaseName(metaClass);
s << "static int ";
- s << baseName << "_clear(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << baseName << "_clear(PyObject* self)" << endl;
s << '{' << endl;
- s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_clear(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_clear(self);" << endl;
s << '}' << endl;
}
@@ -4074,7 +4171,7 @@ void CppGenerator::writeCopyFunction(QTextStream &s, GeneratorContext &context)
{
const AbstractMetaClass *metaClass = context.metaClass();
const QString className = chopType(cpythonTypeName(metaClass));
- s << "static PyObject* " << className << "___copy__(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "static PyObject* " << className << "___copy__(PyObject* self)" << endl;
s << "{" << endl;
writeCppSelfDefinition(s, context, false, true);
QString conversionCode;
@@ -4084,9 +4181,9 @@ void CppGenerator::writeCopyFunction(QTextStream &s, GeneratorContext &context)
conversionCode = cpythonToPythonConversionFunction(context.preciseType());
s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = " << conversionCode;
- s << CPP_SELF_VAR ");" << endl;
+ s << CPP_SELF_VAR << ");" << endl;
writeFunctionReturnErrorCheckSection(s);
- s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl;
+ s << INDENT << "return " << PYTHON_RETURN_VAR << ";" << endl;
s << "}" << endl;
s << endl;
}
@@ -4096,7 +4193,7 @@ void CppGenerator::writeGetterFunction(QTextStream &s,
GeneratorContext &context)
{
ErrorCode errorCode(0);
- s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", void*)" << endl;
+ s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* self, void*)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context);
@@ -4161,7 +4258,7 @@ void CppGenerator::writeGetterFunction(QTextStream &s,
s << INDENT << "pyOut = ";
s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(fieldType)
<< "), " << cppField << ", false, true);" << endl;
- s << INDENT << "Shiboken::Object::setParent(" PYTHON_SELF_VAR ", pyOut)";
+ s << INDENT << "Shiboken::Object::setParent(self, pyOut)";
} else {
s << INDENT << "pyOut = ";
writeToPythonConversion(s, fieldType, metaField->enclosingClass(), cppField);
@@ -4177,7 +4274,7 @@ void CppGenerator::writeSetterFunction(QTextStream &s,
GeneratorContext &context)
{
ErrorCode errorCode(0);
- s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* pyIn, void*)" << endl;
+ s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* self, PyObject* pyIn, void*)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context);
@@ -4193,7 +4290,7 @@ void CppGenerator::writeSetterFunction(QTextStream &s,
AbstractMetaType* fieldType = metaField->type();
- s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << "{nullptr};" << endl;
s << INDENT << "if (!";
writeTypeCheck(s, fieldType, QLatin1String("pyIn"), isNumber(fieldType->typeEntry()));
s << ") {" << endl;
@@ -4219,6 +4316,8 @@ void CppGenerator::writeSetterFunction(QTextStream &s,
s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);" << endl;
s << INDENT << cppField << " = cppOut_local";
} else {
+ if (isPointerToConst(fieldType))
+ s << "const ";
s << getFullTypeNameWithoutModifiers(fieldType);
s << QString::fromLatin1("*").repeated(fieldType->indirections()) << "& cppOut_ptr = ";
s << cppField << ';' << endl;
@@ -4227,7 +4326,7 @@ void CppGenerator::writeSetterFunction(QTextStream &s,
s << ';' << endl << endl;
if (isPointerToWrapperType(fieldType)) {
- s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \"";
+ s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject*>(self), \"";
s << metaField->name() << "\", pyIn);" << endl;
}
@@ -4240,12 +4339,12 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co
const AbstractMetaClass *metaClass = context.metaClass();
QString baseName = cpythonBaseName(metaClass);
s << "static PyObject* ";
- s << baseName << "_richcompare(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ", int op)" << endl;
+ s << baseName << "_richcompare(PyObject* self, PyObject* " << PYTHON_ARG << ", int op)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context, false, true);
writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
- s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
- s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR << ';' << endl;
+ s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = 0;" << endl;
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR));
s << endl;
@@ -4302,15 +4401,17 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co
CodeSnipList snips = func->injectedCodeSnips();
writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, func->arguments().constLast());
} else {
- QString expression = QString::fromLatin1("%1%2 %3 (%4" CPP_ARG0 ")")
- .arg(func->isPointerOperator() ? QLatin1String("&") : QString(),
- QLatin1String(CPP_SELF_VAR), op,
- shouldDereferenceAbstractMetaTypePointer(argType) ? QLatin1String("*") : QString());
s << INDENT;
if (func->type())
- s << func->type()->cppSignature() << " " CPP_RETURN_VAR " = ";
- s << expression << ';' << endl;
- s << INDENT << PYTHON_RETURN_VAR " = ";
+ s << func->type()->cppSignature() << " " << CPP_RETURN_VAR << " = ";
+ // expression
+ if (func->isPointerOperator())
+ s << '&';
+ s << CPP_SELF_VAR << ' ' << op << '(';
+ if (shouldDereferenceAbstractMetaTypePointer(argType))
+ s << '*';
+ s << CPP_ARG0 << ");" << endl;
+ s << INDENT << PYTHON_RETURN_VAR << " = ";
if (func->type())
writeToPythonConversion(s, func->type(), metaClass, QLatin1String(CPP_RETURN_VAR));
else
@@ -4324,9 +4425,9 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co
s << " else {" << endl;
if (operatorId == QLatin1String("Py_EQ") || operatorId == QLatin1String("Py_NE")) {
Indentation indent(INDENT);
- s << INDENT << PYTHON_RETURN_VAR " = "
+ s << INDENT << PYTHON_RETURN_VAR << " = "
<< (operatorId == QLatin1String("Py_EQ") ? "Py_False" : "Py_True") << ';' << endl;
- s << INDENT << "Py_INCREF(" PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "Py_INCREF(" << PYTHON_RETURN_VAR << ");" << endl;
} else {
Indentation indent(INDENT);
s << INDENT << "goto " << baseName << "_RichComparison_TypeError;" << endl;
@@ -4343,18 +4444,18 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co
}
s << INDENT << '}' << endl << endl;
- s << INDENT << "if (" PYTHON_RETURN_VAR " && !PyErr_Occurred())" << endl;
+ s << INDENT << "if (" << PYTHON_RETURN_VAR << " && !PyErr_Occurred())" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl;
+ s << INDENT << "return " << PYTHON_RETURN_VAR << ";" << endl;
}
s << INDENT << baseName << "_RichComparison_TypeError:" << endl;
s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"operator not implemented.\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl << endl;
s << '}' << endl << endl;
}
-void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads)
+void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList &overloads)
{
Q_ASSERT(!overloads.isEmpty());
OverloadData overloadData(overloads, this);
@@ -4378,7 +4479,7 @@ void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMeta
s << "|METH_STATIC";
}
-void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads)
+void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList &overloads)
{
Q_ASSERT(!overloads.isEmpty());
const AbstractMetaFunction* func = overloads.constFirst();
@@ -4510,7 +4611,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu
s << INDENT << "if (!" << cpythonTypeNameExt(cppEnum->typeEntry()) << ')' << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl << endl;
}
}
@@ -4543,7 +4644,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu
<< "))->tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << "Py_DECREF(anonEnumItem);" << endl;
}
@@ -4553,7 +4654,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu
s << enumValueText << ") < 0)" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
}
break;
@@ -4564,7 +4665,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu
Indentation indent(INDENT);
s << INDENT << enclosingObjectVariable << ", \"" << enumValue->name() << "\", ";
s << enumValueText << "))" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
break;
case EnumClass: {
@@ -4573,7 +4674,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu
Indentation indent(INDENT);
s << INDENT << enumVarTypeObj<< ", \"" << enumValue->name() << "\", "
<< enumValueText << "))" << endl
- << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ << INDENT << returnStatement(m_currentErrorCode) << endl;
}
break;
}
@@ -4618,11 +4719,11 @@ void CppGenerator::writeFlagsToLong(QTextStream& s, const AbstractMetaEnum* cppE
FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
if (!flagsEntry)
return;
- s << "static PyObject* " << cpythonEnumName(cppEnum) << "_long(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "static PyObject* " << cpythonEnumName(cppEnum) << "_long(PyObject* self)" << endl;
s << "{" << endl;
s << INDENT << "int val;" << endl;
AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl;
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &val);" << endl;
s << INDENT << "return Shiboken::Conversions::copyToPython(Shiboken::Conversions::PrimitiveTypeConverter<int>(), &val);" << endl;
s << "}" << endl;
}
@@ -4632,12 +4733,12 @@ void CppGenerator::writeFlagsNonZero(QTextStream& s, const AbstractMetaEnum* cpp
FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
if (!flagsEntry)
return;
- s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject* self)" << endl;
s << "{" << endl;
s << INDENT << "int val;" << endl;
AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl;
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &val);" << endl;
s << INDENT << "return val != 0;" << endl;
s << "}" << endl;
}
@@ -4679,24 +4780,24 @@ void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream& s, const Abstr
}
void CppGenerator::writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
- QString pyOpName, QString cppOpName)
+ const QString &pyOpName, const QString &cppOpName)
{
FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
Q_ASSERT(flagsEntry);
- s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ")" << endl;
+ s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* self, PyObject* " << PYTHON_ARG << ")" << endl;
s << '{' << endl;
AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << "::" << flagsEntry->originalName() << " cppResult, " CPP_SELF_VAR ", cppArg;" << endl;
+ s << INDENT << "::" << flagsEntry->originalName() << " cppResult, " << CPP_SELF_VAR << ", cppArg;" << endl;
s << "#ifdef IS_PY3K" << endl;
- s << INDENT << CPP_SELF_VAR " = (::" << flagsEntry->originalName() << ")(int)PyLong_AsLong(" PYTHON_SELF_VAR ");" << endl;
- s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyLong_AsLong(" PYTHON_ARG ");" << endl;
+ s << INDENT << CPP_SELF_VAR << " = (::" << flagsEntry->originalName() << ")(int)PyLong_AsLong(self);" << endl;
+ s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyLong_AsLong(" << PYTHON_ARG << ");" << endl;
s << "#else" << endl;
- s << INDENT << CPP_SELF_VAR " = (::" << flagsEntry->originalName() << ")(int)PyInt_AsLong(" PYTHON_SELF_VAR ");" << endl;
- s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyInt_AsLong(" PYTHON_ARG ");" << endl;
+ s << INDENT << CPP_SELF_VAR << " = (::" << flagsEntry->originalName() << ")(int)PyInt_AsLong(self);" << endl;
+ s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyInt_AsLong(" << PYTHON_ARG << ");" << endl;
s << "#endif" << endl << endl;
- s << INDENT << "cppResult = " CPP_SELF_VAR " " << cppOpName << " cppArg;" << endl;
+ s << INDENT << "cppResult = " << CPP_SELF_VAR << " " << cppOpName << " cppArg;" << endl;
s << INDENT << "return ";
writeToPythonConversion(s, flagsType, 0, QLatin1String("cppResult"));
s << ';' << endl;
@@ -4704,23 +4805,24 @@ void CppGenerator::writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEn
}
void CppGenerator::writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
- QString pyOpName, QString cppOpName, bool boolResult)
+ const QString &pyOpName,
+ const QString &cppOpName, bool boolResult)
{
FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
Q_ASSERT(flagsEntry);
- s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ")" << endl;
+ s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* self, PyObject* " << PYTHON_ARG << ")" << endl;
s << '{' << endl;
AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << "::" << flagsEntry->originalName() << " " CPP_SELF_VAR ";" << endl;
- s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &" CPP_SELF_VAR ");" << endl;
+ s << INDENT << "::" << flagsEntry->originalName() << " " << CPP_SELF_VAR << ";" << endl;
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &" << CPP_SELF_VAR << ");" << endl;
s << INDENT;
if (boolResult)
s << "bool";
else
s << "::" << flagsEntry->originalName();
- s << " cppResult = " << cppOpName << CPP_SELF_VAR ";" << endl;
+ s << " cppResult = " << cppOpName << CPP_SELF_VAR << ';' << endl;
s << INDENT << "return ";
if (boolResult)
s << "PyBool_FromLong(cppResult)";
@@ -4846,8 +4948,16 @@ void CppGenerator::writeClassRegister(QTextStream &s,
else
s << INDENT << "0," << endl;
- // 9:isInnerClass
- s << INDENT << (hasEnclosingClass ? "true" : "false") << endl;
+ // 9:wrapperflags
+ QByteArrayList wrapperFlags;
+ if (hasEnclosingClass)
+ wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::InnerClass"));
+ if (metaClass->deleteInMainThread())
+ wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::DeleteInMainThread"));
+ if (wrapperFlags.isEmpty())
+ s << INDENT << '0';
+ else
+ s << INDENT << wrapperFlags.join(" | ");
}
s << INDENT << ");" << endl;
s << INDENT << endl;
@@ -5042,25 +5152,27 @@ void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMeta
s << "}\n\n";
}
-QString CppGenerator::writeSmartPointerGetterCast() {
- return QLatin1String("const_cast<char *>(" SMART_POINTER_GETTER ")");
+QString CppGenerator::writeSmartPointerGetterCast()
+{
+ return QLatin1String("const_cast<char *>(")
+ + QLatin1String(SMART_POINTER_GETTER) + QLatin1Char(')');
}
void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &context)
{
const AbstractMetaClass* metaClass = context.metaClass();
- s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name, PyObject* value)" << endl;
+ s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* self, PyObject* name, PyObject* value)" << endl;
s << '{' << endl;
if (usePySideExtensions()) {
- s << INDENT << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject*>(PySide::Property::getObject(" PYTHON_SELF_VAR ", name)));" << endl;
+ s << INDENT << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject*>(PySide::Property::getObject(self, name)));" << endl;
s << INDENT << "if (!pp.isNull())" << endl;
Indentation indent(INDENT);
- s << INDENT << "return PySide::Property::setValue(reinterpret_cast<PySideProperty*>(pp.object()), " PYTHON_SELF_VAR ", value);" << endl;
+ s << INDENT << "return PySide::Property::setValue(reinterpret_cast<PySideProperty*>(pp.object()), self, value);" << endl;
}
if (context.forSmartPointer()) {
s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for the corresponding C++ object held by the smart pointer." << endl;
- s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", "
+ s << INDENT << "PyObject *rawObj = PyObject_CallMethod(self, "
<< writeSmartPointerGetterCast() << ", 0);" << endl;
s << INDENT << "if (rawObj) {" << endl;
{
@@ -5078,7 +5190,7 @@ void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &conte
}
- s << INDENT << "return PyObject_GenericSetAttr(" PYTHON_SELF_VAR ", name, value);" << endl;
+ s << INDENT << "return PyObject_GenericSetAttr(self, name, value);" << endl;
s << '}' << endl;
}
@@ -5088,27 +5200,29 @@ static inline QString qMetaObjectClassName() { return QStringLiteral("QMetaObjec
void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &context)
{
const AbstractMetaClass* metaClass = context.metaClass();
- s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name)" << endl;
+ s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* self, PyObject* name)" << endl;
s << '{' << endl;
QString getattrFunc;
if (usePySideExtensions() && metaClass->isQObject()) {
AbstractMetaClass *qobjectClass = AbstractMetaClass::findClass(classes(), qObjectClassName());
- getattrFunc = QString::fromLatin1("PySide::getMetaDataFromQObject(%1, " PYTHON_SELF_VAR ", name)")
- .arg(cpythonWrapperCPtr(qobjectClass, QLatin1String(PYTHON_SELF_VAR)));
+ QTextStream(&getattrFunc) << "PySide::getMetaDataFromQObject("
+ << cpythonWrapperCPtr(qobjectClass, QLatin1String("self"))
+ << ", self, name)";
} else {
- getattrFunc = QLatin1String("PyObject_GenericGetAttr(" PYTHON_SELF_VAR ", name)");
+ getattrFunc = QLatin1String("PyObject_GenericGetAttr(") + QLatin1String("self")
+ + QLatin1String(", name)");
}
if (classNeedsGetattroFunction(metaClass)) {
- s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl;
+ s << INDENT << "if (self) {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "// Search the method in the instance dict" << endl;
- s << INDENT << "if (reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")->ob_dict) {" << endl;
+ s << INDENT << "if (reinterpret_cast<SbkObject*>(self)->ob_dict) {" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "PyObject* meth = PyDict_GetItem(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")->ob_dict, name);" << endl;
+ s << INDENT << "PyObject* meth = PyDict_GetItem(reinterpret_cast<SbkObject*>(self)->ob_dict, name);" << endl;
s << INDENT << "if (meth) {" << endl;
{
Indentation indent(INDENT);
@@ -5119,16 +5233,16 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte
}
s << INDENT << '}' << endl;
s << INDENT << "// Search the method in the type dict" << endl;
- s << INDENT << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ")) {" << endl;
+ s << INDENT << "if (Shiboken::Object::isUserType(self)) {" << endl;
{
Indentation indent(INDENT);
// PYSIDE-772: Perform optimized name mangling.
- s << INDENT << "Shiboken::AutoDecRef tmp(_Pep_PrivateMangle(" PYTHON_SELF_VAR ", name));" << endl;
- s << INDENT << "PyObject *meth = PyDict_GetItem(Py_TYPE(" PYTHON_SELF_VAR ")->tp_dict, tmp);" << endl;
+ s << INDENT << "Shiboken::AutoDecRef tmp(_Pep_PrivateMangle(self, name));" << endl;
+ s << INDENT << "PyObject *meth = PyDict_GetItem(Py_TYPE(self)->tp_dict, tmp);" << endl;
s << INDENT << "if (meth)" << endl;
{
Indentation indent(INDENT);
- s << INDENT << "return PyFunction_Check(meth) ? SBK_PyMethod_New(meth, " PYTHON_SELF_VAR ") : " << getattrFunc << ';' << endl;
+ s << INDENT << "return PyFunction_Check(meth) ? SBK_PyMethod_New(meth, self) : " << getattrFunc << ';' << endl;
}
}
s << INDENT << '}' << endl;
@@ -5147,7 +5261,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte
s << INDENT << "};" << endl;
s << INDENT << "if (Shiboken::String::compare(name, \"" << func->name() << "\") == 0)" << endl;
Indentation indent(INDENT);
- s << INDENT << "return PyCFunction_NewEx(&non_static_" << defName << ", " PYTHON_SELF_VAR ", 0);" << endl;
+ s << INDENT << "return PyCFunction_NewEx(&non_static_" << defName << ", self, 0);" << endl;
}
}
s << INDENT << '}' << endl;
@@ -5168,7 +5282,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte
s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for "
"the corresponding C++ object held by the smart pointer." << endl;
- s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", "
+ s << INDENT << "PyObject *rawObj = PyObject_CallMethod(self, "
<< writeSmartPointerGetterCast() << ", 0);" << endl;
s << INDENT << "if (rawObj) {" << endl;
{
@@ -5289,15 +5403,11 @@ bool CppGenerator::finishGeneration()
QString moduleFileName(outputDirectory() + QLatin1Char('/') + subDirectoryForPackage(packageName()));
moduleFileName += QLatin1Char('/') + moduleName().toLower() + QLatin1String("_module_wrapper.cpp");
- QFile file(moduleFileName);
- verifyDirectoryFor(file);
- if (!file.open(QFile::WriteOnly)) {
- qCWarning(lcShiboken).noquote().nospace()
- << "Error writing file: " << QDir::toNativeSeparators(moduleFileName);
- return false;
- }
- QTextStream s(&file);
+ verifyDirectoryFor(moduleFileName);
+ FileOut file(moduleFileName);
+
+ QTextStream &s = file.stream;
// write license comment
s << licenseComment() << endl;
@@ -5328,13 +5438,12 @@ bool CppGenerator::finishGeneration()
}
TypeDatabase* typeDb = TypeDatabase::instance();
- TypeSystemTypeEntry* moduleEntry = reinterpret_cast<TypeSystemTypeEntry*>(typeDb->findType(packageName()));
+ const TypeSystemTypeEntry *moduleEntry = typeDb->findTypeSystemType(packageName());
+ Q_ASSERT(moduleEntry);
//Extra includes
s << endl << "// Extra includes" << endl;
- QVector<Include> extraIncludes;
- if (moduleEntry)
- extraIncludes = moduleEntry->extraIncludes();
+ QVector<Include> extraIncludes = moduleEntry->extraIncludes();
for (AbstractMetaEnum *cppEnum : qAsConst(globalEnums))
extraIncludes.append(cppEnum->typeEntry()->extraIncludes());
qSort(extraIncludes.begin(), extraIncludes.end());
@@ -5343,14 +5452,15 @@ bool CppGenerator::finishGeneration()
s << endl;
s << "// Current module's type array." << endl;
- s << "PyTypeObject** " << cppApiVariableName() << ';' << endl;
+ s << "PyTypeObject** " << cppApiVariableName() << " = nullptr;" << endl;
+
+ s << "// Current module's PyObject pointer." << endl;
+ s << "PyObject* " << pythonModuleObjectName() << " = nullptr;" << endl;
s << "// Current module's converter array." << endl;
- s << "SbkConverter** " << convertersVariableName() << ';' << endl;
+ s << "SbkConverter** " << convertersVariableName() << " = nullptr;" << endl;
- CodeSnipList snips;
- if (moduleEntry)
- snips = moduleEntry->codeSnips();
+ const CodeSnipList snips = moduleEntry->codeSnips();
// module inject-code native/beginning
if (!snips.isEmpty()) {
@@ -5519,6 +5629,9 @@ bool CppGenerator::finishGeneration()
s << moduleName() << "_methods);" << endl;
s << "#endif" << endl << endl;
+ s << INDENT << "// Make module available from global scope" << endl;
+ s << INDENT << pythonModuleObjectName() << " = module;" << endl << endl;
+
//s << INDENT << "// Initialize converters for primitive types." << endl;
//s << INDENT << "initConverters();" << endl << endl;
@@ -5619,7 +5732,7 @@ bool CppGenerator::finishGeneration()
s << "SBK_MODULE_INIT_FUNCTION_END" << endl;
- return true;
+ return file.done() != FileOut::Failure;
}
static ArgumentOwner getArgumentOwner(const AbstractMetaFunction* func, int argIndex)
@@ -5663,22 +5776,20 @@ bool CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMeta
if (parentIndex == 0) {
parentVariable = QLatin1String(PYTHON_RETURN_VAR);
} else if (parentIndex == -1) {
- parentVariable = QLatin1String(PYTHON_SELF_VAR);
+ parentVariable = QLatin1String("self");
} else {
parentVariable = usePyArgs
- ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(parentIndex - 1)
- : QLatin1String(PYTHON_ARG);
+ ? pythonArgsAt(parentIndex - 1) : QLatin1String(PYTHON_ARG);
}
}
if (childIndex == 0) {
childVariable = QLatin1String(PYTHON_RETURN_VAR);
} else if (childIndex == -1) {
- childVariable = QLatin1String(PYTHON_SELF_VAR);
+ childVariable = QLatin1String("self");
} else {
childVariable = usePyArgs
- ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(childIndex - 1)
- : QLatin1String(PYTHON_ARG);
+ ? pythonArgsAt(childIndex - 1) : QLatin1String(PYTHON_ARG);
}
s << INDENT << "Shiboken::Object::setParent(" << parentVariable << ", " << childVariable << ");\n";
@@ -5717,7 +5828,7 @@ void CppGenerator::writeReturnValueHeuristics(QTextStream& s, const AbstractMeta
ArgumentOwner argOwner = getArgumentOwner(func, ArgumentOwner::ReturnIndex);
if (argOwner.action == ArgumentOwner::Invalid || argOwner.index != ArgumentOwner::ThisIndex) {
if (isPointerToWrapperType(type))
- s << INDENT << "Shiboken::Object::setParent(" << self << ", " PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "Shiboken::Object::setParent(self, " << PYTHON_RETURN_VAR << ");" << endl;
}
}
@@ -5737,19 +5848,19 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &
ErrorCode errorCode(0);
// __len__
- s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* self)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context);
- s << INDENT << "return " CPP_SELF_VAR "->size();" << endl;
+ s << INDENT << "return " << CPP_SELF_VAR << "->size();" << endl;
s << '}' << endl;
// __getitem__
- s << "PyObject* " << cpythonBaseName(metaClass->typeEntry()) << "__getitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i)" << endl;
+ s << "PyObject* " << cpythonBaseName(metaClass->typeEntry()) << "__getitem__(PyObject* self, Py_ssize_t _i)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context);
writeIndexError(s, QLatin1String("index out of bounds"));
- s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " CPP_SELF_VAR "->begin();" << endl;
+ s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " << CPP_SELF_VAR << "->begin();" << endl;
s << INDENT << "for (Py_ssize_t pos = 0; pos < _i; pos++) _item++;" << endl;
const AbstractMetaType* itemType = metaClass->templateBaseClassInstantiations().constFirst();
@@ -5761,7 +5872,7 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &
// __setitem__
ErrorCode errorCode2(-1);
- s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* pyArg)" << endl;
+ s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__(PyObject* self, Py_ssize_t _i, PyObject* pyArg)" << endl;
s << '{' << endl;
writeCppSelfDefinition(s, context);
writeIndexError(s, QLatin1String("list assignment index out of range"));
@@ -5779,7 +5890,7 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &
s << INDENT << '}' << endl;
writeArgumentConversion(s, itemType, QLatin1String("cppValue"), QLatin1String("pyArg"), metaClass);
- s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " CPP_SELF_VAR "->begin();" << endl;
+ s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " << CPP_SELF_VAR << "->begin();" << endl;
s << INDENT << "for (Py_ssize_t pos = 0; pos < _i; pos++) _item++;" << endl;
s << INDENT << "*_item = cppValue;" << endl;
s << INDENT << "return 0;" << endl;
@@ -5787,11 +5898,11 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &
}
void CppGenerator::writeIndexError(QTextStream& s, const QString& errorMsg)
{
- s << INDENT << "if (_i < 0 || _i >= (Py_ssize_t) " CPP_SELF_VAR "->size()) {" << endl;
+ s << INDENT << "if (_i < 0 || _i >= (Py_ssize_t) " << CPP_SELF_VAR << "->size()) {" << endl;
{
Indentation indent(INDENT);
s << INDENT << "PyErr_SetString(PyExc_IndexError, \"" << errorMsg << "\");" << endl;
- s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ s << INDENT << returnStatement(m_currentErrorCode) << endl;
}
s << INDENT << '}' << endl;
}
@@ -5808,7 +5919,10 @@ QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &contex
s << INDENT << "QBuffer buffer;" << endl;
s << INDENT << "buffer.open(QBuffer::ReadWrite);" << endl;
s << INDENT << "QDebug dbg(&buffer);" << endl;
- s << INDENT << "dbg << " << (metaClass->typeEntry()->isValue() ? "*" : "") << CPP_SELF_VAR ";" << endl;
+ s << INDENT << "dbg << ";
+ if (metaClass->typeEntry()->isValue())
+ s << '*';
+ s << CPP_SELF_VAR << ';' << endl;
s << INDENT << "buffer.close();" << endl;
s << INDENT << "QByteArray str = buffer.data();" << endl;
s << INDENT << "int idx = str.indexOf('(');" << endl;
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
index 1b59bcda7..55a1c265d 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.h
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h
@@ -234,8 +234,8 @@ private:
void writeClassDefinition(QTextStream &s,
const AbstractMetaClass *metaClass,
GeneratorContext &classContext);
- void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads);
- void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads);
+ void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList &overloads);
+ void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList &overloads);
void writeSignatureInfo(QTextStream &s, const AbstractMetaFunctionList &overloads);
/// Writes the implementation of all methods part of python sequence protocol
void writeSequenceMethods(QTextStream &s,
@@ -275,9 +275,10 @@ private:
void writeFlagsNonZero(QTextStream& s, const AbstractMetaEnum* cppEnum);
void writeFlagsNumberMethodsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum);
void writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
- QString pyOpName, QString cppOpName);
+ const QString &pyOpName, const QString &cppOpName);
void writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
- QString pyOpName, QString cppOpName, bool boolResult = false);
+ const QString &pyOpName, const QString &cppOpName,
+ bool boolResult = false);
/// Writes the function that registers the multiple inheritance information for the classes that need it.
void writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass);
@@ -292,7 +293,7 @@ private:
void writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool userHeuristicForReturn);
bool writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, int argIndex, bool userHeuristicPolicy);
- void writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self = QLatin1String(PYTHON_SELF_VAR));
+ void writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self = QLatin1String("self"));
void writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const;
/**
@@ -327,7 +328,9 @@ private:
QString writeReprFunction(QTextStream &s, GeneratorContext &context);
- bool hasBoolCast(const AbstractMetaClass* metaClass) const;
+ const AbstractMetaFunction *boolCast(const AbstractMetaClass* metaClass) const;
+ bool hasBoolCast(const AbstractMetaClass* metaClass) const
+ { return boolCast(metaClass) != nullptr; }
// Number protocol structure members names.
static QHash<QString, QString> m_nbFuncs;
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
index 8fde3cd31..8881d71f4 100644
--- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
@@ -32,6 +32,8 @@
#include <reporthandler.h>
#include <fileout.h>
+#include <algorithm>
+
#include <QtCore/QDir>
#include <QtCore/QTextStream>
#include <QtCore/QVariant>
@@ -49,11 +51,10 @@ QString HeaderGenerator::fileNameForContext(GeneratorContext &context) const
QString fileNameBase = metaClass->qualifiedCppName().toLower();
fileNameBase.replace(QLatin1String("::"), QLatin1String("_"));
return fileNameBase + fileNameSuffix();
- } else {
- const AbstractMetaType *smartPointerType = context.preciseType();
- QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
- return fileNameBase + fileNameSuffix();
}
+ const AbstractMetaType *smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
+ return fileNameBase + fileNameSuffix();
}
void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const
@@ -116,8 +117,6 @@ void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classConte
if (!avoidProtectedHack())
s << "#define protected public" << endl << endl;
- s << "#include <shiboken.h>" << endl << endl;
-
//Includes
s << metaClass->typeEntry()->include() << endl;
@@ -173,7 +172,7 @@ void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classConte
s << INDENT << "void* qt_metacast(const char* _clname) override;" << endl;
}
- if (m_inheritedOverloads.size()) {
+ if (!m_inheritedOverloads.isEmpty()) {
s << INDENT << "// Inherited overloads, because the using keyword sux" << endl;
writeInheritedOverloads(s);
m_inheritedOverloads.clear();
@@ -230,7 +229,7 @@ void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction*
QString argName = arg->name();
const TypeEntry* enumTypeEntry = 0;
if (arg->type()->isFlags())
- enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
+ enumTypeEntry = static_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
else if (arg->type()->isEnum())
enumTypeEntry = arg->type()->typeEntry();
if (enumTypeEntry)
@@ -284,49 +283,86 @@ void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction*
}
}
-static void _writeTypeIndexDefineLine(QTextStream& s, const QString& variableName, int typeIndex)
+static void _writeTypeIndexValue(QTextStream& s, const QString& variableName,
+ int typeIndex)
{
- s << "#define ";
- s.setFieldWidth(60);
+ s << " ";
+ s.setFieldWidth(56);
s << variableName;
s.setFieldWidth(0);
- s << ' ' << typeIndex << endl;
+ s << " = " << typeIndex;
+}
+
+static inline void _writeTypeIndexValueLine(QTextStream& s,
+ const QString& variableName,
+ int typeIndex)
+{
+ _writeTypeIndexValue(s, variableName, typeIndex);
+ s << ",\n";
}
-void HeaderGenerator::writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry)
+
+void HeaderGenerator::writeTypeIndexValueLine(QTextStream& s, const TypeEntry* typeEntry)
{
if (!typeEntry || !typeEntry->generateCode())
return;
s.setFieldAlignment(QTextStream::AlignLeft);
- int typeIndex = getTypeIndex(typeEntry);
- _writeTypeIndexDefineLine(s, getTypeIndexVariableName(typeEntry), typeIndex);
+ const int typeIndex = typeEntry->sbkIndex();
+ _writeTypeIndexValueLine(s, getTypeIndexVariableName(typeEntry), typeIndex);
if (typeEntry->isComplex()) {
- const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(typeEntry);
+ const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(typeEntry);
if (cType->baseContainerType()) {
const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), cType);
if (metaClass->templateBaseClass())
- _writeTypeIndexDefineLine(s, getTypeIndexVariableName(metaClass, true), typeIndex);
+ _writeTypeIndexValueLine(s, getTypeIndexVariableName(metaClass, true), typeIndex);
}
}
if (typeEntry->isEnum()) {
- const EnumTypeEntry* ete = reinterpret_cast<const EnumTypeEntry*>(typeEntry);
+ const EnumTypeEntry* ete = static_cast<const EnumTypeEntry*>(typeEntry);
if (ete->flags())
- writeTypeIndexDefineLine(s, ete->flags());
+ writeTypeIndexValueLine(s, ete->flags());
}
}
-void HeaderGenerator::writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass)
+void HeaderGenerator::writeTypeIndexValueLines(QTextStream& s, const AbstractMetaClass* metaClass)
{
if (!metaClass->typeEntry()->generateCode())
return;
- writeTypeIndexDefineLine(s, metaClass->typeEntry());
+ writeTypeIndexValueLine(s, metaClass->typeEntry());
const AbstractMetaEnumList &enums = metaClass->enums();
for (const AbstractMetaEnum *metaEnum : enums) {
if (metaEnum->isPrivate())
continue;
- writeTypeIndexDefineLine(s, metaEnum->typeEntry());
+ writeTypeIndexValueLine(s, metaEnum->typeEntry());
}
}
+// Format the typedefs for the typedef entries to be generated
+static void formatTypeDefEntries(QTextStream &s)
+{
+ QVector<const TypedefEntry *> entries;
+ const auto typeDbEntries = TypeDatabase::instance()->typedefEntries();
+ for (auto it = typeDbEntries.cbegin(), end = typeDbEntries.cend(); it != end; ++it) {
+ if (it.value()->generateCode() != 0)
+ entries.append(it.value());
+ }
+ if (entries.isEmpty())
+ return;
+ s << "\n// typedef entries\n";
+ for (const auto e : entries) {
+ const QString name = e->qualifiedCppName();
+ // Fixme: simplify by using nested namespaces in C++ 17.
+ const auto components = name.splitRef(QLatin1String("::"));
+ const int nameSpaceCount = components.size() - 1;
+ for (int n = 0; n < nameSpaceCount; ++n)
+ s << "namespace " << components.at(n) << " {\n";
+ s << "using " << components.constLast() << " = " << e->sourceType() << ";\n";
+ for (int n = 0; n < nameSpaceCount; ++n)
+ s << "}\n";
+ }
+ s << '\n';
+}
+
+
bool HeaderGenerator::finishGeneration()
{
// Generate the main header for this module.
@@ -342,47 +378,49 @@ bool HeaderGenerator::finishGeneration()
Indentation indent(INDENT);
- macrosStream << "// Type indices" << endl;
+ macrosStream << "// Type indices\nenum : int {\n";
AbstractMetaEnumList globalEnums = this->globalEnums();
- const AbstractMetaClassList &classList = classes();
+ AbstractMetaClassList classList = classes();
+
+ std::sort(classList.begin(), classList.end(), [](AbstractMetaClass *a, AbstractMetaClass* b) {
+ return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex();
+ });
+
for (const AbstractMetaClass *metaClass : classList) {
- writeTypeIndexDefine(macrosStream, metaClass);
+ writeTypeIndexValueLines(macrosStream, metaClass);
lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass);
}
for (const AbstractMetaEnum *metaEnum : qAsConst(globalEnums))
- writeTypeIndexDefineLine(macrosStream, metaEnum->typeEntry());
+ writeTypeIndexValueLine(macrosStream, metaEnum->typeEntry());
// Write the smart pointer define indexes.
int smartPointerCountIndex = getMaxTypeIndex();
int smartPointerCount = 0;
const QVector<const AbstractMetaType *> &instantiatedSmartPtrs = instantiatedSmartPointers();
for (const AbstractMetaType *metaType : instantiatedSmartPtrs) {
- QString variableName = getTypeIndexVariableName(metaType);
- macrosStream << "#define ";
- macrosStream.setFieldWidth(60);
- macrosStream << variableName;
- macrosStream.setFieldWidth(0);
- macrosStream << ' ' << smartPointerCountIndex << " // " << metaType->cppSignature()
- << endl;
+ _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(metaType),
+ smartPointerCountIndex);
+ macrosStream << ", // " << metaType->cppSignature() << endl;
++smartPointerCountIndex;
++smartPointerCount;
}
+ _writeTypeIndexValue(macrosStream,
+ QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT"),
+ getMaxTypeIndex() + smartPointerCount);
+ macrosStream << "\n};\n";
- macrosStream << "#define ";
- macrosStream.setFieldWidth(60);
- macrosStream << QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT");
- macrosStream.setFieldWidth(0);
- macrosStream << ' ' << getMaxTypeIndex() + smartPointerCount << endl << endl;
macrosStream << "// This variable stores all Python types exported by this module." << endl;
macrosStream << "extern PyTypeObject** " << cppApiVariableName() << ';' << endl << endl;
+ macrosStream << "// This variable stores the Python module object exported by this module." << endl;
+ macrosStream << "extern PyObject* " << pythonModuleObjectName() << ';' << endl << endl;
macrosStream << "// This variable stores all type converters exported by this module." << endl;
macrosStream << "extern SbkConverter** " << convertersVariableName() << ';' << endl << endl;
// TODO-CONVERTER ------------------------------------------------------------------------------
// Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex().
- macrosStream << "// Converter indices" << endl;
+ macrosStream << "// Converter indices\nenum : int {\n";
const PrimitiveTypeEntryList &primitives = primitiveTypes();
int pCount = 0;
for (const PrimitiveTypeEntry *ptype : primitives) {
@@ -393,28 +431,25 @@ bool HeaderGenerator::finishGeneration()
if (!ptype->generateCode() || !ptype->customConversion())
continue;
- _writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(ptype), pCount++);
+ _writeTypeIndexValueLine(macrosStream, getTypeIndexVariableName(ptype), pCount++);
}
const QVector<const AbstractMetaType *> &containers = instantiatedContainers();
for (const AbstractMetaType *container : containers) {
- //_writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(container), pCount);
- // DEBUG
- QString variableName = getTypeIndexVariableName(container);
- macrosStream << "#define ";
- macrosStream.setFieldWidth(60);
- macrosStream << variableName;
- macrosStream.setFieldWidth(0);
- macrosStream << ' ' << pCount << " // " << container->cppSignature() << endl;
- // DEBUG
+ _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(container), pCount);
+ macrosStream << ", // " << container->cppSignature() << endl;
pCount++;
}
// Because on win32 the compiler will not accept a zero length array.
if (pCount == 0)
pCount++;
- _writeTypeIndexDefineLine(macrosStream, QStringLiteral("SBK_%1_CONVERTERS_IDX_COUNT").arg(moduleName()), pCount);
- macrosStream << endl;
+ _writeTypeIndexValue(macrosStream, QStringLiteral("SBK_%1_CONVERTERS_IDX_COUNT")
+ .arg(moduleName()), pCount);
+ macrosStream << "\n};\n";
+
+ formatTypeDefEntries(macrosStream);
+
// TODO-CONVERTER ------------------------------------------------------------------------------
macrosStream << "// Macros for type check" << endl;
@@ -474,12 +509,6 @@ bool HeaderGenerator::finishGeneration()
s << "#include <sbkpython.h>" << endl;
s << "#include <sbkconverter.h>" << endl;
- s << "#include <sbkenum.h>" << endl;
- s << "#include <basewrapper.h>" << endl;
- s << "#include <bindingmanager.h>" << endl;
- s << "#include <memory>" << endl << endl;
- if (usePySideExtensions())
- s << "#include <pysidesignal.h>" << endl;
QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports();
if (!requiredTargetImports.isEmpty()) {
@@ -580,7 +609,7 @@ void HeaderGenerator::writeInheritedOverloads(QTextStream& s)
QString argName = arg->name();
const TypeEntry* enumTypeEntry = 0;
if (arg->type()->isFlags())
- enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
+ enumTypeEntry = static_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
else if (arg->type()->isEnum())
enumTypeEntry = arg->type()->typeEntry();
if (enumTypeEntry)
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.h b/sources/shiboken2/generator/shiboken2/headergenerator.h
index acf0448a7..821531aab 100644
--- a/sources/shiboken2/generator/shiboken2/headergenerator.h
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.h
@@ -55,8 +55,8 @@ private:
void writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum);
void writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass);
void writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType);
- void writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry);
- void writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeTypeIndexValueLine(QTextStream& s, const TypeEntry* typeEntry);
+ void writeTypeIndexValueLines(QTextStream& s, const AbstractMetaClass* metaClass);
void writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum);
void writeInheritedOverloads(QTextStream& s);
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
index 73198ba12..a95603754 100644
--- a/sources/shiboken2/generator/shiboken2/overloaddata.cpp
+++ b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
@@ -94,8 +94,6 @@ static bool typesAreEqual(const AbstractMetaType* typeA, const AbstractMetaType*
*/
struct OverloadSortData
{
- OverloadSortData() : counter(0) {}
-
/**
* Adds a typeName into the type map without associating it with
* a OverloadData. This is done to express type dependencies that could
@@ -121,7 +119,7 @@ struct OverloadSortData
int lastProcessedItemId() { return counter - 1; }
- int counter;
+ int counter = 0;
QHash<QString, int> map; // typeName -> id
QHash<int, OverloadData*> reverseMap; // id -> OverloadData;
};
@@ -149,11 +147,11 @@ static QString getImplicitConversionTypeName(const AbstractMetaType* containerTy
for (const AbstractMetaType *otherType : instantiations)
types << (otherType == instantiation ? impConv : getTypeName(otherType));
- const ContainerTypeEntry* containerTypeEntry = dynamic_cast<const ContainerTypeEntry*>(containerType->typeEntry());
- return containerTypeEntry->qualifiedCppName() + QLatin1Char('<')
+ return containerType->typeEntry()->qualifiedCppName() + QLatin1Char('<')
+ types.join(QLatin1String(", ")) + QLatin1String(" >");
}
+// overloaddata.cpp
static QString msgCyclicDependency(const QString &funcName, const QString &graphName,
const OverloadData::MetaFunctionList &involvedConversions)
{
@@ -499,7 +497,8 @@ OverloadData::OverloadData(const AbstractMetaFunctionList& overloads, const Shib
OverloadData::OverloadData(OverloadData* headOverloadData, const AbstractMetaFunction* func,
const AbstractMetaType* argType, int argPos)
: m_minArgs(256), m_maxArgs(0), m_argPos(argPos), m_argType(argType),
- m_headOverloadData(headOverloadData), m_previousOverloadData(0)
+ m_headOverloadData(headOverloadData), m_previousOverloadData(nullptr),
+ m_generator(nullptr)
{
if (func)
this->addOverload(func);
@@ -808,8 +807,7 @@ QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList&
{
int minArgs = 10000;
int maxArgs = 0;
- for (int i = 0; i < overloads.size(); i++) {
- const AbstractMetaFunction* func = overloads[i];
+ for (const AbstractMetaFunction *func : overloads) {
int origNumArgs = func->arguments().size();
int removed = numberOfRemovedArguments(func);
int numArgs = origNumArgs - removed;
@@ -825,7 +823,7 @@ QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList&
minArgs = fixedArgIndex;
}
}
- return QPair<int, int>(minArgs, maxArgs);
+ return {minArgs, maxArgs};
}
bool OverloadData::isSingleArgument(const AbstractMetaFunctionList& overloads)
@@ -840,7 +838,7 @@ bool OverloadData::isSingleArgument(const AbstractMetaFunctionList& overloads)
return singleArgument;
}
-void OverloadData::dumpGraph(QString filename) const
+void OverloadData::dumpGraph(const QString &filename) const
{
QFile file(filename);
if (file.open(QFile::WriteOnly)) {
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.h b/sources/shiboken2/generator/shiboken2/overloaddata.h
index 435c19aa2..4759ca9c3 100644
--- a/sources/shiboken2/generator/shiboken2/overloaddata.h
+++ b/sources/shiboken2/generator/shiboken2/overloaddata.h
@@ -114,7 +114,7 @@ public:
/// Returns true if all overloads have no more than one argument.
static bool isSingleArgument(const AbstractMetaFunctionList& overloads);
- void dumpGraph(QString filename) const;
+ void dumpGraph(const QString &filename) const;
QString dumpGraph() const;
bool hasArgumentTypeReplace() const;
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 80096cbf2..b9eea7529 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -28,9 +28,11 @@
#include "shibokengenerator.h"
#include <abstractmetalang.h>
+#include <messages.h>
#include "overloaddata.h"
#include <reporthandler.h>
#include <typedatabase.h>
+#include <abstractmetabuilder.h>
#include <iostream>
#include <QtCore/QDir>
@@ -39,13 +41,29 @@
#include <limits>
#include <memory>
-#define NULL_VALUE "NULL"
-#define AVOID_PROTECTED_HACK "avoid-protected-hack"
-#define PARENT_CTOR_HEURISTIC "enable-parent-ctor-heuristic"
-#define RETURN_VALUE_HEURISTIC "enable-return-value-heuristic"
-#define ENABLE_PYSIDE_EXTENSIONS "enable-pyside-extensions"
-#define DISABLE_VERBOSE_ERROR_MESSAGES "disable-verbose-error-messages"
-#define USE_ISNULL_AS_NB_NONZERO "use-isnull-as-nb_nonzero"
+static const char NULL_VALUE[] = "NULL";
+static const char AVOID_PROTECTED_HACK[] = "avoid-protected-hack";
+static const char PARENT_CTOR_HEURISTIC[] = "enable-parent-ctor-heuristic";
+static const char RETURN_VALUE_HEURISTIC[] = "enable-return-value-heuristic";
+static const char ENABLE_PYSIDE_EXTENSIONS[] = "enable-pyside-extensions";
+static const char DISABLE_VERBOSE_ERROR_MESSAGES[] = "disable-verbose-error-messages";
+static const char USE_ISNULL_AS_NB_NONZERO[] = "use-isnull-as-nb_nonzero";
+
+const char *CPP_ARG = "cppArg";
+const char *CPP_ARG_REMOVED = "removed_cppArg";
+const char *CPP_RETURN_VAR = "cppResult";
+const char *CPP_SELF_VAR = "cppSelf";
+const char *PYTHON_ARG = "pyArg";
+const char *PYTHON_ARGS = "pyArgs";
+const char *PYTHON_OVERRIDE_VAR = "pyOverride";
+const char *PYTHON_RETURN_VAR = "pyResult";
+const char *PYTHON_TO_CPP_VAR = "pythonToCpp";
+const char *SMART_POINTER_GETTER = "kSmartPointerGetter";
+
+const char *CONV_RULE_OUT_VAR_SUFFIX = "_out";
+const char *BEGIN_ALLOW_THREADS =
+ "PyThreadState* _save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS";
+const char *END_ALLOW_THREADS = "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS";
//static void dumpFunction(AbstractMetaFunctionList lst);
@@ -100,7 +118,7 @@ static QString resolveScopePrefix(const AbstractMetaEnum *metaEnum,
return resolveScopePrefix(parts, value);
}
-ShibokenGenerator::ShibokenGenerator() : Generator()
+ShibokenGenerator::ShibokenGenerator()
{
if (m_pythonPrimitiveTypeName.isEmpty())
ShibokenGenerator::initPrimitiveTypesCorrespondences();
@@ -117,17 +135,19 @@ ShibokenGenerator::ShibokenGenerator() : Generator()
m_typeSystemConvName[TypeSystemIsConvertibleFunction] = QLatin1String("isConvertible");
m_typeSystemConvName[TypeSystemToCppFunction] = QLatin1String("toCpp");
m_typeSystemConvName[TypeSystemToPythonFunction] = QLatin1String("toPython");
+
+ const char CHECKTYPE_REGEX[] = R"(%CHECKTYPE\[([^\[]*)\]\()";
+ const char ISCONVERTIBLE_REGEX[] = R"(%ISCONVERTIBLE\[([^\[]*)\]\()";
+ const char CONVERTTOPYTHON_REGEX[] = R"(%CONVERTTOPYTHON\[([^\[]*)\]\()";
+ const char CONVERTTOCPP_REGEX[] =
+ R"((\*?%?[a-zA-Z_][\w\.]*(?:\[[^\[^<^>]+\])*)(?:\s+)=(?:\s+)%CONVERTTOCPP\[([^\[]*)\]\()";
m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegularExpression(QLatin1String(CHECKTYPE_REGEX));
m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegularExpression(QLatin1String(ISCONVERTIBLE_REGEX));
m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegularExpression(QLatin1String(CONVERTTOPYTHON_REGEX));
m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegularExpression(QLatin1String(CONVERTTOCPP_REGEX));
}
-ShibokenGenerator::~ShibokenGenerator()
-{
- // TODO-CONVERTER: it must be caching types that were not created here.
- //qDeleteAll(m_metaTypeFromStringCache.values());
-}
+ShibokenGenerator::~ShibokenGenerator() = default;
void ShibokenGenerator::clearTpFuncs()
{
@@ -277,7 +297,7 @@ bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass* metaCl
for (const AbstractMetaFunction *func : funcs) {
if (!func->isProtected() || func->isSignal() || func->isModifiedRemoved())
continue;
- else if (func->isOperatorOverload())
+ if (func->isOperatorOverload())
protectedOperators++;
else
protectedFunctions++;
@@ -332,9 +352,8 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const
result += QLatin1String("Wrapper");
return result;
- } else {
- return metaClass->qualifiedCppName();
}
+ return metaClass->qualifiedCppName();
}
QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const
@@ -342,7 +361,19 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const
return metaType->cppSignature();
}
-QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func)
+QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClass *metaClass)
+{
+ QString fullClassName = metaClass->name();
+ const AbstractMetaClass *enclosing = metaClass->enclosingClass();
+ while (enclosing) {
+ fullClassName.prepend(enclosing->name() + QLatin1Char('.'));
+ enclosing = enclosing->enclosingClass();
+ }
+ fullClassName.prepend(packageName() + QLatin1Char('.'));
+ return fullClassName;
+}
+
+QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction *func) //WS
{
QString funcName;
if (func->isOperatorOverload())
@@ -350,11 +381,11 @@ QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* fu
else
funcName = func->name();
if (func->ownerClass()) {
- QString fullName = func->ownerClass()->fullName();
+ QString fullClassName = fullPythonClassName(func->ownerClass());
if (func->isConstructor())
- funcName = fullName;
+ funcName = fullClassName;
else
- funcName.prepend(fullName + QLatin1Char('.'));
+ funcName.prepend(fullClassName + QLatin1Char('.'));
}
else {
funcName = packageName() + QLatin1Char('.') + func->name();
@@ -434,7 +465,8 @@ QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField* me
return QStringLiteral("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name());
}
-static QString cpythonEnumFlagsName(QString moduleName, QString qualifiedCppName)
+static QString cpythonEnumFlagsName(const QString &moduleName,
+ const QString &qualifiedCppName)
{
QString result = QStringLiteral("Sbk%1_%2").arg(moduleName, qualifiedCppName);
result.replace(QLatin1String("::"), QLatin1String("_"));
@@ -570,7 +602,7 @@ QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunction
fieldName.prepend(prefix);
prefix.clear();
} else {
- fieldName.prepend(QLatin1String(CPP_SELF_VAR "->"));
+ fieldName.prepend(QLatin1String(CPP_SELF_VAR) + QLatin1String("->"));
}
value.replace(match.captured(1), fieldName);
break;
@@ -616,12 +648,14 @@ QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClas
return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("SpecialCastFunction");
}
-QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName)
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass,
+ const QString &argName)
{
return cpythonWrapperCPtr(metaClass->typeEntry(), argName);
}
-QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName)
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType,
+ const QString &argName)
{
if (!ShibokenGenerator::isWrapperType(metaType->typeEntry()))
return QString();
@@ -630,7 +664,8 @@ QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType,
+ QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))");
}
-QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString argName)
+QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type,
+ const QString &argName)
{
if (!ShibokenGenerator::isWrapperType(type))
return QString();
@@ -706,7 +741,8 @@ QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunction* func,
|| arg->type()->referenceType() == LValueReference) {
result += QLatin1Char(objType);
} else if (arg->type()->isPrimitive()) {
- const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) arg->type()->typeEntry();
+ const PrimitiveTypeEntry *ptype =
+ static_cast<const PrimitiveTypeEntry *>(arg->type()->typeEntry());
if (ptype->basicReferencedTypeEntry())
ptype = ptype->basicReferencedTypeEntry();
if (m_formatUnits.contains(ptype->name()))
@@ -745,7 +781,7 @@ QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type)
if (ShibokenGenerator::isWrapperType(type) || type->isNamespace()) { // && type->referenceType() == NoReference) {
baseName = QLatin1String("Sbk_") + type->name();
} else if (type->isPrimitive()) {
- const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type;
+ const PrimitiveTypeEntry *ptype = static_cast<const PrimitiveTypeEntry *>(type);
while (ptype->basicReferencedTypeEntry())
ptype = ptype->basicReferencedTypeEntry();
if (ptype->targetLangApiName() == ptype->name())
@@ -753,11 +789,11 @@ QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type)
else
baseName = ptype->targetLangApiName();
} else if (type->isEnum()) {
- baseName = cpythonEnumName((const EnumTypeEntry*) type);
+ baseName = cpythonEnumName(static_cast<const EnumTypeEntry *>(type));
} else if (type->isFlags()) {
- baseName = cpythonFlagsName((const FlagsTypeEntry*) type);
+ baseName = cpythonFlagsName(static_cast<const FlagsTypeEntry *>(type));
} else if (type->isContainer()) {
- const ContainerTypeEntry* ctype = (const ContainerTypeEntry*) type;
+ const ContainerTypeEntry *ctype = static_cast<const ContainerTypeEntry *>(type);
switch (ctype->type()) {
case ContainerTypeEntry::ListContainer:
case ContainerTypeEntry::StringListContainer:
@@ -858,14 +894,6 @@ QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType* type)
+ getTypeIndexVariableName(type) + QLatin1Char(']');
}
-static QString msgUnknownOperator(const AbstractMetaFunction* func)
-{
- QString result = QLatin1String("Unknown operator: \"") + func->originalName() + QLatin1Char('"');
- if (const AbstractMetaClass *c = func->implementingClass())
- result += QLatin1String(" in class: ") + c->name();
- return result;
-}
-
static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); }
QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative)
@@ -925,7 +953,7 @@ QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry* typ
return pythonPrimitiveTypeName(type->name());
}
-QString ShibokenGenerator::pythonOperatorFunctionName(QString cppOpFuncName)
+QString ShibokenGenerator::pythonOperatorFunctionName(const QString &cppOpFuncName)
{
QString value = m_pythonOperators.value(cppOpFuncName);
if (value.isEmpty())
@@ -953,7 +981,7 @@ QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction
return op;
}
-QString ShibokenGenerator::pythonRichCompareOperatorId(QString cppOpFuncName)
+QString ShibokenGenerator::pythonRichCompareOperatorId(const QString &cppOpFuncName)
{
return QLatin1String("Py_") + m_pythonOperators.value(cppOpFuncName).toUpper();
}
@@ -963,7 +991,7 @@ QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunctio
return pythonRichCompareOperatorId(func->originalName());
}
-bool ShibokenGenerator::isNumber(QString cpythonApiName)
+bool ShibokenGenerator::isNumber(const QString &cpythonApiName)
{
return cpythonApiName == QLatin1String("PyInt")
|| cpythonApiName == QLatin1String("PyFloat")
@@ -975,7 +1003,7 @@ bool ShibokenGenerator::isNumber(const TypeEntry* type)
{
if (!type->isPrimitive())
return false;
- return isNumber(pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type));
+ return isNumber(pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type)));
}
bool ShibokenGenerator::isNumber(const AbstractMetaType* type)
@@ -987,7 +1015,8 @@ bool ShibokenGenerator::isPyInt(const TypeEntry* type)
{
if (!type->isPrimitive())
return false;
- return pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type) == QLatin1String("PyInt");
+ return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type))
+ == QLatin1String("PyInt");
}
bool ShibokenGenerator::isPyInt(const AbstractMetaType* type)
@@ -998,7 +1027,7 @@ bool ShibokenGenerator::isPyInt(const AbstractMetaType* type)
bool ShibokenGenerator::isWrapperType(const TypeEntry* type)
{
if (type->isComplex())
- return ShibokenGenerator::isWrapperType((const ComplexTypeEntry*)type);
+ return ShibokenGenerator::isWrapperType(static_cast<const ComplexTypeEntry *>(type));
return type->isObject() || type->isValue() || type->isSmartPointer();
}
bool ShibokenGenerator::isWrapperType(const ComplexTypeEntry* type)
@@ -1052,7 +1081,7 @@ bool ShibokenGenerator::isUserPrimitive(const TypeEntry* type)
{
if (!type->isPrimitive())
return false;
- const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry *>(type);
if (trueType->basicReferencedTypeEntry())
trueType = trueType->basicReferencedTypeEntry();
return trueType->isPrimitive() && !trueType->isCppPrimitive()
@@ -1072,7 +1101,7 @@ bool ShibokenGenerator::isCppPrimitive(const TypeEntry* type)
return true;
if (!type->isPrimitive())
return false;
- const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry *>(type);
if (trueType->basicReferencedTypeEntry())
trueType = trueType->basicReferencedTypeEntry();
return trueType->qualifiedCppName() == QLatin1String("std::string");
@@ -1125,9 +1154,11 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType
if (isVoidPointer(metaType))
return QLatin1String("PyObject_Check");
return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
- } else if (metaType->typeEntry()->isContainer()) {
+ }
+ if (metaType->typeEntry()->isContainer()) {
QString typeCheck = QLatin1String("Shiboken::Conversions::");
- ContainerTypeEntry::Type type = ((const ContainerTypeEntry*)metaType->typeEntry())->type();
+ ContainerTypeEntry::Type type =
+ static_cast<const ContainerTypeEntry *>(metaType->typeEntry())->type();
if (type == ContainerTypeEntry::ListContainer
|| type == ContainerTypeEntry::StringListContainer
|| type == ContainerTypeEntry::LinkedListContainer
@@ -1154,8 +1185,8 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType
const AbstractMetaType* firstType = metaType->instantiations().constFirst();
const AbstractMetaType* secondType = metaType->instantiations().constLast();
if (isPointerToWrapperType(firstType) && isPointerToWrapperType(secondType)) {
- typeCheck += QString::fromLatin1("check%1Types(%2, %3, ").arg(pyType)
- .arg(cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType));
+ typeCheck += QString::fromLatin1("check%1Types(%2, %3, ")
+ .arg(pyType, cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType));
} else {
typeCheck += QString::fromLatin1("convertible%1Types(%2, %3, %4, %5, ")
.arg(pyType, converterObject(firstType),
@@ -1182,8 +1213,10 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool gene
if (type->isEnum() || type->isFlags() || isWrapperType(type))
return QString::fromLatin1("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type));
- else if (isCppPrimitive(type))
- return pythonPrimitiveTypeName((const PrimitiveTypeEntry*)type) + QLatin1String("_Check");
+ if (isCppPrimitive(type)) {
+ return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type))
+ + QLatin1String("_Check");
+ }
QString typeCheck;
if (type->targetLangApiName() == type->name())
typeCheck = cpythonIsConvertibleFunction(type);
@@ -1392,7 +1425,7 @@ void ShibokenGenerator::writeFunctionArguments(QTextStream &s,
if (options & Generator::WriteSelf) {
s << func->implementingClass()->name() << '&';
if (!(options & SkipName))
- s << " " PYTHON_SELF_VAR;
+ s << " self";
}
int argUsed = 0;
@@ -1412,13 +1445,12 @@ QString ShibokenGenerator::functionReturnType(const AbstractMetaFunction* func,
QString modifiedReturnType = QString(func->typeReplaced(0));
if (!modifiedReturnType.isNull() && !(options & OriginalTypeDescription))
return modifiedReturnType;
- else
- return translateType(func->type(), func->implementingClass(), options);
+ return translateType(func->type(), func->implementingClass(), options);
}
QString ShibokenGenerator::functionSignature(const AbstractMetaFunction *func,
- QString prepend,
- QString append,
+ const QString &prepend,
+ const QString &append,
Options options,
int /* argCount */) const
{
@@ -1619,8 +1651,9 @@ ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentRepl
QString argValue;
if (language == TypeSystem::TargetLangCode) {
bool hasConversionRule = !func->conversionRule(convLang, i+1).isEmpty();
- bool argRemoved = func->argumentRemoved(i+1);
- removed = removed + (int) argRemoved;
+ const bool argRemoved = func->argumentRemoved(i+1);
+ if (argRemoved)
+ ++removed;
if (argRemoved && hasConversionRule)
argValue = arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
else if (argRemoved || (lastArg && arg->argumentIndex() > lastArg->argumentIndex()))
@@ -1636,8 +1669,7 @@ ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentRepl
}
if (type->typeEntry()->isCustom()) {
argValue = usePyArgs
- ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argPos)
- : QLatin1String(PYTHON_ARG);
+ ? pythonArgsAt(argPos) : QLatin1String(PYTHON_ARG);
} else {
argValue = hasConversionRule
? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)
@@ -1673,17 +1705,6 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
s << INDENT << "// End of code injection" << endl;
}
-static QString msgWrongIndex(const char *varName, const QString &capture, const AbstractMetaFunction *func)
-{
- QString result;
- QTextStream str(&result);
- str << "Wrong index for " << varName << " variable (" << capture << ") on ";
- if (const AbstractMetaClass *c = func->implementingClass())
- str << c->name() << "::";
- str << func->signature();
- return result;
-}
-
void ShibokenGenerator::writeCodeSnips(QTextStream& s,
const CodeSnipList& codeSnips,
TypeSystem::CodeSnipPosition position,
@@ -1712,7 +1733,7 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
Q_ASSERT(pyArgsRegex.isValid());
if (language == TypeSystem::TargetLangCode) {
if (usePyArgs) {
- code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS"[\\1-1]"));
+ code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS) + QLatin1String("[\\1-1]"));
} else {
static const QRegularExpression pyArgsRegexCheck(QStringLiteral("%PYARG_([2-9]+)"));
Q_ASSERT(pyArgsRegexCheck.isValid());
@@ -1729,8 +1750,10 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
// Python argument on the binding virtual method.
static const QRegularExpression pyArgsAttributionRegex(QStringLiteral("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"));
Q_ASSERT(pyArgsAttributionRegex.isValid());
- code.replace(pyArgsAttributionRegex, QLatin1String("PyTuple_SET_ITEM(" PYTHON_ARGS ", \\1-1, \\2)"));
- code.replace(pyArgsRegex, QLatin1String("PyTuple_GET_ITEM(" PYTHON_ARGS ", \\1-1)"));
+ code.replace(pyArgsAttributionRegex, QLatin1String("PyTuple_SET_ITEM(")
+ + QLatin1String(PYTHON_ARGS) + QLatin1String(", \\1-1, \\2)"));
+ code.replace(pyArgsRegex, QLatin1String("PyTuple_GET_ITEM(")
+ + QLatin1String(PYTHON_ARGS) + QLatin1String(", \\1-1)"));
}
// Replace %ARG#_TYPE variables.
@@ -1763,7 +1786,8 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
}
// Replace template variable for self Python object.
- QString pySelf = (language == TypeSystem::NativeCode) ? QLatin1String("pySelf") : QLatin1String(PYTHON_SELF_VAR);
+ QString pySelf = language == TypeSystem::NativeCode
+ ? QLatin1String("pySelf") : QLatin1String("self");
code.replace(QLatin1String("%PYSELF"), pySelf);
// Replace template variable for a pointer to C++ of this object.
@@ -1960,16 +1984,6 @@ static QString getConverterTypeSystemVariableArgument(const QString& code, int p
}
typedef QPair<QString, QString> StringPair;
-static QString msgCannotFindType(const QString &type, const QString &variable,
- const QString &why)
-{
- QString result;
- QTextStream(&result) << "Could not find type '"
- << type << "' for use in '" << variable << "' conversion: " << why
- << "\nMake sure to use the full C++ name, e.g. 'Namespace::Class'.";
- return result;
-}
-
void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code)
{
QVector<StringPair> replacements;
@@ -1978,7 +1992,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
const QRegularExpressionMatch match = rit.next();
const QStringList list = match.capturedTexts();
QString conversionString = list.constFirst();
- QString conversionTypeName = list.constLast();
+ const QString &conversionTypeName = list.constLast();
QString message;
const AbstractMetaType *conversionType = buildAbstractMetaTypeFromString(conversionTypeName, &message);
if (!conversionType) {
@@ -2002,8 +2016,8 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
QString varName = list.at(1).trimmed();
if (!varType.isEmpty()) {
if (varType != conversionType->cppSignature()) {
- qFatal(qPrintable(QString::fromLatin1("Types of receiver variable ('%1') and %CONVERTTOCPP type system variable ('%2') differ.")
- .arg(varType, conversionType->cppSignature())), NULL);
+ qFatal("Types of receiver variable ('%s') and %%CONVERTTOCPP type system variable ('%s') differ.",
+ qPrintable(varType), qPrintable(conversionType->cppSignature()));
}
c << getFullTypeName(conversionType) << ' ' << varName;
writeMinimalConstructorExpression(c, conversionType);
@@ -2032,18 +2046,21 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
c << '(';
break;
}
+ Q_FALLTHROUGH();
case TypeSystemIsConvertibleFunction:
if (conversion.isEmpty())
conversion = cpythonIsConvertibleFunction(conversionType);
+ Q_FALLTHROUGH();
case TypeSystemToPythonFunction:
if (conversion.isEmpty())
conversion = cpythonToPythonConversionFunction(conversionType);
+ Q_FALLTHROUGH();
default: {
QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd());
conversionString += arg;
if (converterVariable == TypeSystemToPythonFunction && !isVariable(arg)) {
- qFatal(qPrintable(QString::fromLatin1("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%1'")
- .arg(code)), NULL);
+ qFatal("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%s'",
+ qPrintable(code));
}
if (conversion.contains(QLatin1String("%in"))) {
conversion.prepend(QLatin1Char('('));
@@ -2172,9 +2189,7 @@ bool ShibokenGenerator::classNeedsSetattroFunction(const AbstractMetaClass *meta
{
if (!metaClass)
return false;
- if (metaClass->typeEntry()->isSmartPointer())
- return true;
- return false;
+ return metaClass->typeEntry()->isSmartPointer();
}
AbstractMetaFunctionList ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass)
@@ -2244,9 +2259,7 @@ AbstractMetaClassList ShibokenGenerator::getAllAncestors(const AbstractMetaClass
QString ShibokenGenerator::getModuleHeaderFileName(const QString& moduleName) const
{
- QString result = moduleName.isEmpty() ? packageName() : moduleName;
- result.replace(QLatin1Char('.'), QLatin1Char('_'));
- return result.toLower() + QLatin1String("_python.h");
+ return moduleCppPrefix(moduleName).toLower() + QLatin1String("_python.h");
}
bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass)
@@ -2254,12 +2267,10 @@ bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass)
{
if (metaClass->isNamespace() || isObjectType(metaClass))
return false;
- else if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown)
+ if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown)
return metaClass->hasCloneOperator();
- else
- return (metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet);
- return false;
+ return metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet;
}
AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromString(QString typeSignature,
@@ -2269,110 +2280,18 @@ AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ
if (typeSignature.startsWith(QLatin1String("::")))
typeSignature.remove(0, 2);
- if (m_metaTypeFromStringCache.contains(typeSignature))
- return m_metaTypeFromStringCache.value(typeSignature);
-
- QString typeString = typeSignature;
- bool isConst = typeString.startsWith(QLatin1String("const "));
- if (isConst)
- typeString.remove(0, sizeof("const ") / sizeof(char) - 1);
-
- ReferenceType refType = NoReference;
- if (typeString.endsWith(QLatin1String("&&"))) {
- refType = RValueReference;
- typeString.chop(2);
- typeString = typeString.trimmed();
- } else if (typeString.endsWith(QLatin1Char('&'))) {
- refType = LValueReference;
- typeString.chop(1);
- typeString = typeString.trimmed();
- }
-
- int indirections = 0;
- while (typeString.endsWith(QLatin1Char('*'))) {
- ++indirections;
- typeString.chop(1);
- typeString = typeString.trimmed();
- }
-
- if (typeString.startsWith(QLatin1String("::")))
- typeString.remove(0, 2);
-
- QString adjustedTypeName = typeString;
- AbstractMetaTypeList instantiations;
- int lpos = typeString.indexOf(QLatin1Char('<'));
- if (lpos > -1) {
- QStringList instantiatedTypes;
- int rpos = typeString.lastIndexOf(QLatin1Char('>'));
- if ((lpos != -1) && (rpos != -1)) {
- QString type = typeString.mid(lpos + 1, rpos - lpos - 1);
- int depth = 0;
- int start = 0;
- for (int i = 0; i < type.count(); ++i) {
- if (type.at(i) == QLatin1Char('<')) {
- ++depth;
- } else if (type.at(i) == QLatin1Char('>')) {
- --depth;
- } else if (type.at(i) == QLatin1Char(',') && depth == 0) {
- instantiatedTypes << type.mid(start, i - start).trimmed();
- start = i + 1;
- }
- }
- instantiatedTypes << type.mid(start).trimmed();
- adjustedTypeName.truncate(lpos);
- }
- for (const QString &instantiatedType : qAsConst(instantiatedTypes)) {
- AbstractMetaType *tmplArgType = buildAbstractMetaTypeFromString(instantiatedType);
- if (!tmplArgType) {
- if (errorMessage) {
- QTextStream(errorMessage) << "Cannot find template type \""
- << instantiatedType << "\" for \"" << typeSignature << "\".";
- }
- return nullptr;
- }
- instantiations.append(tmplArgType);
- }
- }
-
- TypeEntry *typeEntry = nullptr;
- AbstractMetaType::TypeUsagePattern pattern = AbstractMetaType::InvalidPattern;
-
- if (instantiations.size() == 1
- && instantiations.at(0)->typeUsagePattern() == AbstractMetaType::EnumPattern
- && adjustedTypeName == QLatin1String("QFlags")) {
- pattern = AbstractMetaType::FlagsPattern;
- typeEntry = TypeDatabase::instance()->findType(typeSignature);
- } else {
- typeEntry = TypeDatabase::instance()->findType(adjustedTypeName);
- }
-
- if (!typeEntry) {
- if (errorMessage) {
- QTextStream(errorMessage) << "Cannot find type \"" << adjustedTypeName
- << "\" for \"" << typeSignature << "\".";
+ auto it = m_metaTypeFromStringCache.find(typeSignature);
+ if (it == m_metaTypeFromStringCache.end()) {
+ AbstractMetaType *metaType =
+ AbstractMetaBuilder::translateType(typeSignature, nullptr, true, errorMessage);
+ if (Q_UNLIKELY(!metaType)) {
+ if (errorMessage)
+ errorMessage->prepend(msgCannotBuildMetaType(typeSignature));
+ return nullptr;
}
- return nullptr;
+ it = m_metaTypeFromStringCache.insert(typeSignature, metaType);
}
-
- AbstractMetaType *metaType = new AbstractMetaType();
- metaType->setTypeEntry(typeEntry);
- metaType->setIndirections(indirections);
- metaType->setReferenceType(refType);
- metaType->setConstant(isConst);
- metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
- switch (pattern) {
- case AbstractMetaType::FlagsPattern:
- metaType->setTypeUsagePattern(pattern);
- break;
- default:
- metaType->setInstantiations(instantiations);
- metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
- metaType->decideUsagePattern();
- break;
- }
-
- m_metaTypeFromStringCache.insert(typeSignature, metaType);
- return metaType;
+ return it.value();
}
AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry)
@@ -2384,7 +2303,7 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const Ty
return m_metaTypeFromStringCache.value(typeName);
AbstractMetaType* metaType = new AbstractMetaType;
metaType->setTypeEntry(typeEntry);
- metaType->setIndirections(0);
+ metaType->clearIndirections();
metaType->setReferenceType(NoReference);
metaType->setConstant(false);
metaType->decideUsagePattern();
@@ -2449,7 +2368,7 @@ AbstractMetaFunctionList ShibokenGenerator::getInheritedOverloads(const Abstract
{
AbstractMetaFunctionList results;
AbstractMetaClass* basis;
- if (func->ownerClass() && (basis = func->ownerClass()->baseClass(), basis)) {
+ if (func->ownerClass() && (basis = func->ownerClass()->baseClass())) {
for (; basis; basis = basis->baseClass()) {
const AbstractMetaFunction* inFunc = basis->findFunction(func->name());
if (inFunc && !seen->contains(inFunc->minimalSignature())) {
@@ -2509,6 +2428,23 @@ Generator::OptionDescriptions ShibokenGenerator::options() const
"the value of boolean casts"));
}
+bool ShibokenGenerator::handleOption(const QString &key, const QString & /* value */)
+{
+ if (key == QLatin1String(PARENT_CTOR_HEURISTIC))
+ return (m_useCtorHeuristic = true);
+ if (key == QLatin1String(ENABLE_PYSIDE_EXTENSIONS))
+ return (m_usePySideExtensions = true);
+ if (key == QLatin1String(RETURN_VALUE_HEURISTIC))
+ return (m_userReturnValueHeuristic = true);
+ if (key == QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES))
+ return (m_verboseErrorMessagesDisabled = true);
+ if (key == QLatin1String(USE_ISNULL_AS_NB_NONZERO))
+ return (m_useIsNullAsNbNonZero = true);
+ if (key == QLatin1String(AVOID_PROTECTED_HACK))
+ return (m_avoidProtectedHack = true);
+ return false;
+}
+
static void getCode(QStringList& code, const CodeSnipList& codeSnips)
{
for (const CodeSnip &snip : qAsConst(codeSnips))
@@ -2534,15 +2470,8 @@ static void getCode(QStringList& code, const TypeEntry* type)
code.append(toNative->conversion());
}
-bool ShibokenGenerator::doSetup(const QMap<QString, QString>& args)
+bool ShibokenGenerator::doSetup()
{
- m_useCtorHeuristic = args.contains(QLatin1String(PARENT_CTOR_HEURISTIC));
- m_usePySideExtensions = args.contains(QLatin1String(ENABLE_PYSIDE_EXTENSIONS));
- m_userReturnValueHeuristic = args.contains(QLatin1String(RETURN_VALUE_HEURISTIC));
- m_verboseErrorMessagesDisabled = args.contains(QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES));
- m_useIsNullAsNbNonZero = args.contains(QLatin1String(USE_ISNULL_AS_NB_NONZERO));
- m_avoidProtectedHack = args.contains(QLatin1String(AVOID_PROTECTED_HACK));
-
TypeDatabase* td = TypeDatabase::instance();
QStringList snips;
const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
@@ -2554,7 +2483,11 @@ bool ShibokenGenerator::doSetup(const QMap<QString, QString>& args)
const AbstractMetaClassList &classList = classes();
for (const AbstractMetaClass *metaClass : classList)
getCode(snips, metaClass->typeEntry());
- getCode(snips, td->findType(packageName()));
+
+ const TypeSystemTypeEntry *moduleEntry = td->findTypeSystemType(packageName());
+ Q_ASSERT(moduleEntry);
+ getCode(snips, moduleEntry);
+
const FunctionGroupMap &functionGroups = getFunctionGroups();
for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
for (AbstractMetaFunction *func : it.value())
@@ -2611,15 +2544,25 @@ bool ShibokenGenerator::avoidProtectedHack() const
return m_avoidProtectedHack;
}
-QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const
-{
- QString result = moduleName.isEmpty() ? ShibokenGenerator::packageName() : moduleName;
+QString ShibokenGenerator::moduleCppPrefix(const QString& moduleName) const
+ {
+ QString result = moduleName.isEmpty() ? packageName() : moduleName;
result.replace(QLatin1Char('.'), QLatin1Char('_'));
- result.prepend(QLatin1String("Sbk"));
- result.append(QLatin1String("Types"));
return result;
}
+QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const
+{
+ return QLatin1String("Sbk") + moduleCppPrefix(moduleName)
+ + QLatin1String("Types");
+}
+
+QString ShibokenGenerator::pythonModuleObjectName(const QString& moduleName) const
+{
+ return QLatin1String("Sbk") + moduleCppPrefix(moduleName)
+ + QLatin1String("ModuleObject");
+}
+
QString ShibokenGenerator::convertersVariableName(const QString& moduleName) const
{
QString result = cppApiVariableName(moduleName);
@@ -2639,35 +2582,50 @@ static QString processInstantiationsVariableName(const AbstractMetaType* type)
}
return res;
}
+
+static void appendIndexSuffix(QString *s)
+{
+ if (!s->endsWith(QLatin1Char('_')))
+ s->append(QLatin1Char('_'));
+ s->append(QStringLiteral("IDX"));
+}
+
QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass* metaClass, bool alternativeTemplateName)
{
if (alternativeTemplateName) {
const AbstractMetaClass* templateBaseClass = metaClass->templateBaseClass();
if (!templateBaseClass)
return QString();
- QString base = _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper();
- QString instantiations;
+ QString result = QLatin1String("SBK_")
+ + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper();
const AbstractMetaTypeList &templateBaseClassInstantiations = metaClass->templateBaseClassInstantiations();
for (const AbstractMetaType *instantiation : templateBaseClassInstantiations)
- instantiations += processInstantiationsVariableName(instantiation);
- return QString::fromLatin1("SBK_%1%2_IDX").arg(base, instantiations);
+ result += processInstantiationsVariableName(instantiation);
+ appendIndexSuffix(&result);
+ return result;
}
return getTypeIndexVariableName(metaClass->typeEntry());
}
QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type)
{
if (type->isCppPrimitive()) {
- const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry*>(type);
if (trueType->basicReferencedTypeEntry())
type = trueType->basicReferencedTypeEntry();
}
- return QString::fromLatin1("SBK_%1_IDX").arg(_fixedCppTypeName(type->qualifiedCppName()).toUpper());
+ QString result = QLatin1String("SBK_")
+ + _fixedCppTypeName(type->qualifiedCppName()).toUpper();
+ appendIndexSuffix(&result);
+ return result;
}
QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type)
{
- return QString::fromLatin1("SBK%1%2_IDX")
- .arg(type->typeEntry()->isContainer() ? QLatin1Char('_') + moduleName().toUpper() : QString(),
- processInstantiationsVariableName(type));
+ QString result = QLatin1String("SBK");
+ if (type->typeEntry()->isContainer())
+ result += QLatin1Char('_') + moduleName().toUpper();
+ result += processInstantiationsVariableName(type);
+ appendIndexSuffix(&result);
+ return result;
}
bool ShibokenGenerator::verboseErrorMessagesDisabled() const
@@ -2707,30 +2665,37 @@ QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, co
void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor)
{
- if (defaultCtor.isEmpty() && isCppPrimitive(type))
+ if (!defaultCtor.isEmpty()) {
+ s << " = " << defaultCtor;
+ return;
+ }
+ if (isCppPrimitive(type))
return;
- QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
- if (ctor.isEmpty()) {
+ const auto ctor = minimalConstructor(type);
+ if (ctor.isValid()) {
+ s << ctor.initialization();
+ } else {
const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->cppSignature());
qCWarning(lcShiboken()).noquote() << message;
s << ";\n#error " << message << '\n';
- } else {
- s << " = " << ctor;
}
}
void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor)
{
- if (defaultCtor.isEmpty() && isCppPrimitive(type))
+ if (!defaultCtor.isEmpty()) {
+ s << " = " << defaultCtor;
+ return;
+ }
+ if (isCppPrimitive(type))
return;
- QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
-
- if (ctor.isEmpty()) {
+ const auto ctor = minimalConstructor(type);
+ if (ctor.isValid()) {
+ s << ctor.initialization();
+ } else {
const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName());
qCWarning(lcShiboken()).noquote() << message;
s << ";\n#error " << message << endl;
- } else {
- s << " = " << ctor;
}
}
@@ -2738,7 +2703,7 @@ bool ShibokenGenerator::isCppIntegralPrimitive(const TypeEntry* type)
{
if (!type->isCppPrimitive())
return false;
- const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry *>(type);
if (trueType->basicReferencedTypeEntry())
trueType = trueType->basicReferencedTypeEntry();
QString typeName = trueType->qualifiedCppName();
@@ -2751,8 +2716,8 @@ bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType* type)
return isCppIntegralPrimitive(type->typeEntry());
}
-QString ShibokenGenerator::msgCouldNotFindMinimalConstructor(const QString &where, const QString &type)
+QString ShibokenGenerator::pythonArgsAt(int i)
{
- return where + QLatin1String(": Could not find a minimal constructor for type '") + type
- + QLatin1String("'. This will result in a compilation error.");
+ return QLatin1String(PYTHON_ARGS) + QLatin1Char('[')
+ + QString::number(i) + QLatin1Char(']');
}
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
index cb1bdd11f..60e31a99b 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
@@ -29,28 +29,20 @@
#ifndef SHIBOKENGENERATOR_H
#define SHIBOKENGENERATOR_H
-#define CONV_RULE_OUT_VAR_SUFFIX "_out"
-#define CPP_ARG "cppArg"
-#define CPP_ARG0 CPP_ARG"0"
-#define CPP_ARG_REMOVED "removed_" CPP_ARG
-#define CPP_RETURN_VAR "cppResult"
-#define CPP_SELF_VAR "cppSelf"
-#define PYTHON_ARG "pyArg"
-#define PYTHON_ARGS PYTHON_ARG "s"
-#define PYTHON_OVERRIDE_VAR "pyOverride"
-#define PYTHON_RETURN_VAR "pyResult"
-#define PYTHON_SELF_VAR "self"
-#define THREAD_STATE_SAVER_VAR "threadStateSaver"
-#define BEGIN_ALLOW_THREADS "PyThreadState* _save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS"
-#define END_ALLOW_THREADS "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS"
-#define PYTHON_TO_CPP_VAR "pythonToCpp"
-#define SMART_POINTER_GETTER "kSmartPointerGetter"
-
-#define CHECKTYPE_REGEX "%CHECKTYPE\\[([^\\[]*)\\]\\("
-#define ISCONVERTIBLE_REGEX "%ISCONVERTIBLE\\[([^\\[]*)\\]\\("
-#define CONVERTTOPYTHON_REGEX "%CONVERTTOPYTHON\\[([^\\[]*)\\]\\("
-#define CONVERTTOCPP_REGEX "(\\*?%?[a-zA-Z_][\\w\\.]*(?:\\[[^\\[^<^>]+\\])*)"\
- "(?:\\s+)=(?:\\s+)%CONVERTTOCPP\\[([^\\[]*)\\]\\("
+extern const char *CPP_ARG;
+extern const char *CPP_ARG_REMOVED;
+extern const char *CPP_RETURN_VAR;
+extern const char *CPP_SELF_VAR;
+extern const char *PYTHON_ARG;
+extern const char *PYTHON_ARGS;
+extern const char *PYTHON_OVERRIDE_VAR;
+extern const char *PYTHON_RETURN_VAR;
+extern const char *PYTHON_TO_CPP_VAR;
+extern const char *SMART_POINTER_GETTER;
+
+extern const char *CONV_RULE_OUT_VAR_SUFFIX;
+extern const char *BEGIN_ALLOW_THREADS;
+extern const char *END_ALLOW_THREADS;
#include <generator.h>
@@ -71,61 +63,20 @@ class ShibokenGenerator : public Generator
{
public:
ShibokenGenerator();
- virtual ~ShibokenGenerator();
+ ~ShibokenGenerator() override;
- QString translateTypeForWrapperMethod(const AbstractMetaType* cType,
- const AbstractMetaClass* context, Options opt = NoOption) const;
+ const char *name() const override { return "Shiboken"; }
/**
- * Returns a map with all functions grouped, the function name is used as key.
- * Example of return value: { "foo" -> ["foo(int)", "foo(int, long)], "bar" -> "bar(double)"}
- * \param scope Where to search for functions, null means all global functions.
- */
- QMap<QString, AbstractMetaFunctionList> getFunctionGroups(const AbstractMetaClass* scope = 0);
-
- /**
- * Returns all different inherited overloads of func.
- * The function can be called multiple times without duplication.
- * \param func the metafunction to be searched in subclasses.
- * \param seen the function's minimal signatures already seen.
- */
- AbstractMetaFunctionList getInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
+ * Helper function to find for argument default value
+ */
+ static QString getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
- /**
- * Returns all different inherited overloads of func, and includes func as well.
- * The function can be called multiple times without duplication.
- * \param func the metafunction to be searched in subclasses.
- * \param seen the function's minimal signatures already seen.
- */
- AbstractMetaFunctionList getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
+ /// Returns a list of all ancestor classes for the given class.
+ AbstractMetaClassList getAllAncestors(const AbstractMetaClass* metaClass) const;
- /**
- * Returns all overloads for a function named \p functionName.
- * \param scope scope used to search for overloads.
- * \param functionName the function name.
- */
- AbstractMetaFunctionList getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName);
- /**
- * 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.
- * \param func the current metafunction.
- * \param argument metaargument information to be parsed.
- * \param options some extra options.
- */
- void writeArgument(QTextStream &s,
- const AbstractMetaFunction* func,
- const AbstractMetaArgument* argument,
- Options options = NoOption) const;
- /**
- * Create a QString in the C++ format to an function argument.
- * \param func the current metafunction.
- * \param argument metaargument information to be parsed.
- * \param options some extra options.
- */
- QString argumentString(const AbstractMetaFunction* func,
- const AbstractMetaArgument* argument,
- Options options = NoOption) const;
+protected:
+ bool doSetup() override;
void writeArgumentNames(QTextStream &s,
const AbstractMetaFunction* func,
@@ -141,14 +92,21 @@ public:
void writeFunctionArguments(QTextStream &s,
const AbstractMetaFunction* func,
Options options = NoOption) const override;
- QString functionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const;
- /// Utility function for writeCodeSnips.
- typedef QPair<const AbstractMetaArgument*, QString> ArgumentVarReplacementPair;
- typedef QVector<ArgumentVarReplacementPair> ArgumentVarReplacementList;
- ArgumentVarReplacementList getArgumentReplacement(const AbstractMetaFunction* func,
- bool usePyArgs, TypeSystem::Language language,
- const AbstractMetaArgument* lastArg);
+ /**
+ * Returns a map with all functions grouped, the function name is used as key.
+ * Example of return value: { "foo" -> ["foo(int)", "foo(int, long)], "bar" -> "bar(double)"}
+ * \param scope Where to search for functions, null means all global functions.
+ */
+ QMap<QString, AbstractMetaFunctionList> getFunctionGroups(const AbstractMetaClass* scope = 0);
+
+ /**
+ * Returns all different inherited overloads of func, and includes func as well.
+ * The function can be called multiple times without duplication.
+ * \param func the metafunction to be searched in subclasses.
+ * \param seen the function's minimal signatures already seen.
+ */
+ AbstractMetaFunctionList getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
/// Write user's custom code snippets at class or module level.
void writeCodeSnips(QTextStream& s,
@@ -164,33 +122,9 @@ public:
const AbstractMetaFunction* func,
const AbstractMetaArgument* lastArg = 0);
- /// Returns a string with the user's custom code snippets that comply with \p position and \p language.
- QString getCodeSnippets(const QVector<CodeSnip> & codeSnips, TypeSystem::CodeSnipPosition position, TypeSystem::Language language);
-
/// Replaces variables for the user's custom code at global or class level.
void processCodeSnip(QString& code, const AbstractMetaClass* context = 0);
- /// Replaces the %CONVERTTOPYTHON type system variable.
- inline void replaceConvertToPythonTypeSystemVariable(QString& code)
- {
- replaceConverterTypeSystemVariable(TypeSystemToPythonFunction, code);
- }
- /// Replaces the %CONVERTTOCPP type system variable.
- inline void replaceConvertToCppTypeSystemVariable(QString& code)
- {
- replaceConverterTypeSystemVariable(TypeSystemToCppFunction, code);
- }
- /// Replaces the %ISCONVERTIBLE type system variable.
- inline void replaceIsConvertibleToCppTypeSystemVariable(QString& code)
- {
- replaceConverterTypeSystemVariable(TypeSystemIsConvertibleFunction, code);
- }
- /// Replaces the %CHECKTYPE type system variable.
- inline void replaceTypeCheckTypeSystemVariable(QString& code)
- {
- replaceConverterTypeSystemVariable(TypeSystemCheckFunction, code);
- }
-
/**
* Verifies if any of the function's code injections of the "native"
* type needs the type system variable "%PYSELF".
@@ -239,8 +173,8 @@ public:
* \param arg_count the number of function arguments
*/
QString functionSignature(const AbstractMetaFunction* func,
- QString prepend = QString(),
- QString append = QString(),
+ const QString &prepend = QString(),
+ const QString &append = QString(),
Options options = NoOption,
int arg_count = -1) const;
@@ -259,9 +193,6 @@ public:
/// Returns a list of parent classes for a given class.
AbstractMetaClassList getBaseClasses(const AbstractMetaClass* metaClass) const;
- /// Returns a list of all ancestor classes for the given class.
- AbstractMetaClassList getAllAncestors(const AbstractMetaClass* metaClass) const;
-
const AbstractMetaClass* getMultipleInheritingClass(const AbstractMetaClass* metaClass);
void writeToPythonConversion(QTextStream& s, const AbstractMetaType* type,
@@ -283,7 +214,8 @@ public:
QString wrapperName(const AbstractMetaClass* metaClass) const;
QString wrapperName(const AbstractMetaType *metaType) const;
- QString fullPythonFunctionName(const AbstractMetaFunction* func);
+ QString fullPythonClassName(const AbstractMetaClass *metaClass);
+ QString fullPythonFunctionName(const AbstractMetaFunction *func); //WS
static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum);
static QString protectedFieldGetterName(const AbstractMetaField* field);
@@ -292,16 +224,16 @@ public:
static QString pythonPrimitiveTypeName(const QString& cppTypeName);
static QString pythonPrimitiveTypeName(const PrimitiveTypeEntry* type);
- static QString pythonOperatorFunctionName(QString cppOpFuncName);
+ static QString pythonOperatorFunctionName(const QString &cppOpFuncName);
static QString pythonOperatorFunctionName(const AbstractMetaFunction* func);
- static QString pythonRichCompareOperatorId(QString cppOpFuncName);
+ static QString pythonRichCompareOperatorId(const QString &cppOpFuncName);
static QString pythonRichCompareOperatorId(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());
- static bool isNumber(QString cpythonApiName);
+ static bool isNumber(const QString &cpythonApiName);
static bool isNumber(const TypeEntry* type);
static bool isNumber(const AbstractMetaType* type);
static bool isPyInt(const TypeEntry* type);
@@ -389,9 +321,10 @@ public:
QString cpythonSetattroFunctionName(const AbstractMetaClass* metaClass);
QString cpythonGetterFunctionName(const AbstractMetaField* metaField);
QString cpythonSetterFunctionName(const AbstractMetaField* metaField);
- QString cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName = QLatin1String(PYTHON_SELF_VAR));
- QString cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName);
- QString cpythonWrapperCPtr(const TypeEntry* type, QString argName);
+ QString cpythonWrapperCPtr(const AbstractMetaClass* metaClass,
+ const QString &argName = QLatin1String("self"));
+ QString cpythonWrapperCPtr(const AbstractMetaType *metaType, const QString &argName);
+ QString cpythonWrapperCPtr(const TypeEntry* type, const QString &argName);
/// Guesses the scope to where belongs an argument's default value.
QString guessScopeForDefaultValue(const AbstractMetaFunction *func,
@@ -414,6 +347,7 @@ public:
QString getModuleHeaderFileName(const QString& moduleName = QString()) const;
OptionDescriptions options() const override;
+ bool handleOption(const QString &key, const QString &value) override;
/// Returns true if the user enabled the so called "parent constructor heuristic".
bool useCtorHeuristic() const;
@@ -426,6 +360,7 @@ public:
/// Returns true if the generated code should use the "#define protected public" hack.
bool avoidProtectedHack() const;
QString cppApiVariableName(const QString& moduleName = QString()) const;
+ QString pythonModuleObjectName(const QString& moduleName = QString()) const;
QString convertersVariableName(const QString& moduleName = QString()) const;
/**
* Returns the type index variable name for a given class. If \p alternativeTemplateName is true
@@ -457,26 +392,12 @@ public:
void writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor = QString());
void writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor = QString());
- /**
- * Helper function to find for argument default value
- */
- static QString getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
-protected:
- bool doSetup(const QMap<QString, QString>& args);
void collectContainerTypesFromConverterMacros(const QString& code, bool toPythonMacro);
// verify whether the class is copyable
bool isCopyable(const AbstractMetaClass* metaClass);
- bool m_native_jump_table;
- static QHash<QString, QString> m_pythonPrimitiveTypeName;
- static QHash<QString, QString> m_pythonOperators;
- static QHash<QString, QString> m_formatUnits;
- static QHash<QString, QString> m_tpFuncs;
- static QStringList m_knownPythonTypes;
-
void clearTpFuncs();
- const char* name() const { return "Shiboken"; }
/// Initializes correspondences between primitive and Python types.
static void initPrimitiveTypesCorrespondences();
@@ -505,6 +426,74 @@ protected:
Indentor INDENT;
+ const QRegularExpression &convertToCppRegEx() const
+ { return m_typeSystemConvRegEx[TypeSystemToCppFunction]; }
+
+ static QString pythonArgsAt(int i);
+
+ static QHash<QString, QString> m_pythonPrimitiveTypeName;
+ static QHash<QString, QString> m_pythonOperators;
+ static QHash<QString, QString> m_formatUnits;
+ static QHash<QString, QString> m_tpFuncs;
+ static QStringList m_knownPythonTypes;
+
+private:
+ QString translateTypeForWrapperMethod(const AbstractMetaType* cType,
+ const AbstractMetaClass* context,
+ Options opt = NoOption) const;
+
+ /**
+ * Returns all different inherited overloads of func.
+ * The function can be called multiple times without duplication.
+ * \param func the metafunction to be searched in subclasses.
+ * \param seen the function's minimal signatures already seen.
+ */
+ AbstractMetaFunctionList getInheritedOverloads(const AbstractMetaFunction *func,
+ QSet<QString> *seen);
+
+ /**
+ * Returns all overloads for a function named \p functionName.
+ * \param scope scope used to search for overloads.
+ * \param functionName the function name.
+ */
+ AbstractMetaFunctionList getFunctionOverloads(const AbstractMetaClass* scope,
+ const QString& functionName);
+ /**
+ * 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.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ void writeArgument(QTextStream &s,
+ const AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ Options options = NoOption) const;
+ /**
+ * Create a QString in the C++ format to an function argument.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ QString argumentString(const AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ Options options = NoOption) const;
+
+ QString functionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const;
+
+ /// Utility function for writeCodeSnips.
+ typedef QPair<const AbstractMetaArgument*, QString> ArgumentVarReplacementPair;
+ typedef QVector<ArgumentVarReplacementPair> ArgumentVarReplacementList;
+ ArgumentVarReplacementList getArgumentReplacement(const AbstractMetaFunction* func,
+ bool usePyArgs, TypeSystem::Language language,
+ const AbstractMetaArgument* lastArg);
+
+ /// Returns a string with the user's custom code snippets that comply with \p position and \p language.
+ QString getCodeSnippets(const QVector<CodeSnip> & codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language);
+
enum TypeSystemConverterVariable {
TypeSystemCheckFunction = 0,
TypeSystemIsConvertibleFunction,
@@ -514,15 +503,36 @@ protected:
};
void replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code);
- static QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type);
+ /// Replaces the %CONVERTTOPYTHON type system variable.
+ inline void replaceConvertToPythonTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemToPythonFunction, code);
+ }
+ /// Replaces the %CONVERTTOCPP type system variable.
+ inline void replaceConvertToCppTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemToCppFunction, code);
+ }
+ /// Replaces the %ISCONVERTIBLE type system variable.
+ inline void replaceIsConvertibleToCppTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemIsConvertibleFunction, code);
+ }
+ /// Replaces the %CHECKTYPE type system variable.
+ inline void replaceTypeCheckTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemCheckFunction, code);
+ }
-private:
- bool m_useCtorHeuristic;
- bool m_userReturnValueHeuristic;
- bool m_usePySideExtensions;
- bool m_verboseErrorMessagesDisabled;
- bool m_useIsNullAsNbNonZero;
- bool m_avoidProtectedHack;
+ /// Return a prefix with '_' suitable for names in C++
+ QString moduleCppPrefix(const QString& moduleName = QString()) const;
+
+ bool m_useCtorHeuristic = false;
+ bool m_userReturnValueHeuristic = false;
+ bool m_usePySideExtensions = false;
+ bool m_verboseErrorMessagesDisabled = false;
+ bool m_useIsNullAsNbNonZero = false;
+ bool m_avoidProtectedHack = false;
typedef QHash<QString, AbstractMetaType*> AbstractMetaTypeCache;
AbstractMetaTypeCache m_metaTypeFromStringCache;
diff --git a/sources/shiboken2/libshiboken/autodecref.h b/sources/shiboken2/libshiboken/autodecref.h
index 7b6aa47da..72fd236de 100644
--- a/sources/shiboken2/libshiboken/autodecref.h
+++ b/sources/shiboken2/libshiboken/autodecref.h
@@ -43,11 +43,6 @@
#include "sbkpython.h"
#include "basewrapper.h"
-#ifdef _MSC_VER
-__pragma(warning(push))
-__pragma(warning(disable:4522)) // warning: C4522: 'Shiboken::AutoDecRef': multiple assignment operators specified
-#endif
-
struct SbkObject;
namespace Shiboken
{
@@ -58,6 +53,11 @@ namespace Shiboken
struct LIBSHIBOKEN_API AutoDecRef
{
public:
+ AutoDecRef(const AutoDecRef&) = delete;
+ AutoDecRef(AutoDecRef&&) = delete;
+ AutoDecRef& operator=(const AutoDecRef&) = delete;
+ AutoDecRef& operator=(AutoDecRef&&) = delete;
+
/**
* AutoDecRef constructor.
* \param pyobj A borrowed reference to a Python object
@@ -92,35 +92,18 @@ public:
}
/**
- * Decref the current borrowed python reference and take the reference
- * borrowed by \p other, so other.isNull() will return true.
- */
- void operator=(AutoDecRef& other)
- {
- Py_XDECREF(m_pyObj);
- m_pyObj = other.m_pyObj;
- other.m_pyObj = 0;
- }
-
- /**
* Decref the current borrowed python reference and borrow \p other.
*/
- void operator=(PyObject* other)
+ void reset(PyObject* other)
{
Py_XDECREF(m_pyObj);
m_pyObj = other;
}
private:
PyObject* m_pyObj;
- AutoDecRef(const AutoDecRef&);
- AutoDecRef& operator=(const AutoDecRef&);
};
} // namespace Shiboken
-#ifdef _MSC_VER
-__pragma(warning(pop))
-#endif
-
#endif // AUTODECREF_H
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 5ca4172c8..c9e3b9d1b 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -40,6 +40,7 @@
#include "basewrapper.h"
#include "basewrapper_p.h"
#include "bindingmanager.h"
+#include "helper.h"
#include "sbkconverter.h"
#include "sbkenum.h"
#include "sbkstring.h"
@@ -60,6 +61,15 @@ namespace {
void _destroyParentInfo(SbkObject* obj, bool keepReference);
}
+static void callDestructor(const Shiboken::DtorAccumulatorVisitor::DestructorEntries &dts)
+{
+ for (const auto &e : dts) {
+ Shiboken::ThreadStateSaver threadSaver;
+ threadSaver.save();
+ e.destructor(e.cppInstance);
+ }
+}
+
extern "C"
{
@@ -118,20 +128,15 @@ static int SbkObject_traverse(PyObject* self, visitproc visit, void* arg)
//Visit children
Shiboken::ParentInfo* pInfo = sbkSelf->d->parentInfo;
if (pInfo) {
- std::set<SbkObject*>::const_iterator it = pInfo->children.begin();
- for(; it != pInfo->children.end(); ++it)
- Py_VISIT(*it);
+ for (SbkObject *c : pInfo->children)
+ Py_VISIT(c);
}
//Visit refs
Shiboken::RefCountMap* rInfo = sbkSelf->d->referredObjects;
if (rInfo) {
- Shiboken::RefCountMap::const_iterator it = rInfo->begin();
- for (; it != rInfo->end(); ++it) {
- std::list<PyObject*>::const_iterator ref = it->second.begin();
- for(; ref != it->second.end(); ++ref)
- Py_VISIT(*ref);
- }
+ for (auto it = rInfo->begin(), end = rInfo->end(); it != end; ++it)
+ Py_VISIT(it->second);
}
if (sbkSelf->ob_dict)
@@ -186,6 +191,12 @@ SbkObjectType *SbkObject_TypeF(void)
return reinterpret_cast<SbkObjectType *>(type);
}
+static int mainThreadDeletionHandler(void *)
+{
+ if (Py_IsInitialized())
+ Shiboken::BindingManager::instance().runDeletionInMainThread();
+ return 0;
+}
static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete)
{
@@ -214,11 +225,32 @@ static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete)
PyObject_ClearWeakRefs(pyObj);
// If I have ownership and is valid delete C++ pointer
- if (canDelete && sbkObj->d->hasOwnership && sbkObj->d->validCppObject) {
- SbkObjectTypePrivate *sotp = PepType_SOTP(pyType);
+ SbkObjectTypePrivate *sotp{nullptr};
+ canDelete &= sbkObj->d->hasOwnership && sbkObj->d->validCppObject;
+ if (canDelete) {
+ sotp = PepType_SOTP(pyType);
+ if (sotp->delete_in_main_thread && Shiboken::currentThreadId() != Shiboken::mainThreadId()) {
+ auto &bindingManager = Shiboken::BindingManager::instance();
+ if (sotp->is_multicpp) {
+ Shiboken::DtorAccumulatorVisitor visitor(sbkObj);
+ Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor);
+ for (const auto &e : visitor.entries())
+ bindingManager.addToDeletionInMainThread(e);
+ } else {
+ Shiboken::DestructorEntry e{sotp->cpp_dtor, sbkObj->d->cptr[0]};
+ bindingManager.addToDeletionInMainThread(e);
+ }
+ Py_AddPendingCall(mainThreadDeletionHandler, nullptr);
+ canDelete = false;
+ }
+ }
+
+ if (canDelete) {
if (sotp->is_multicpp) {
- Shiboken::DeallocVisitor visitor(sbkObj);
+ Shiboken::DtorAccumulatorVisitor visitor(sbkObj);
Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor);
+ Shiboken::Object::deallocData(sbkObj, true);
+ callDestructor(visitor.entries());
} else {
void* cptr = sbkObj->d->cptr[0];
Shiboken::Object::deallocData(sbkObj, true);
@@ -325,7 +357,7 @@ PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* k
Shiboken::ObjectType::initPrivateData(newType);
SbkObjectTypePrivate *sotp = PepType_SOTP(newType);
- std::list<SbkObjectType*> bases = Shiboken::getCppBaseClasses(reinterpret_cast<PyTypeObject*>(newType));
+ const auto bases = Shiboken::getCppBaseClasses(reinterpret_cast<PyTypeObject*>(newType));
if (bases.size() == 1) {
SbkObjectTypePrivate *parentType = PepType_SOTP(bases.front());
sotp->mi_offsets = parentType->mi_offsets;
@@ -352,10 +384,9 @@ PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* k
sotp->d_func = nullptr;
sotp->is_user_type = 1;
- std::list<SbkObjectType*>::const_iterator it = bases.begin();
- for (; it != bases.end(); ++it) {
- if (PepType_SOTP(*it)->subtype_init)
- PepType_SOTP(*it)->subtype_init(newType, args, kwds);
+ for (SbkObjectType *base : bases) {
+ if (PepType_SOTP(base)->subtype_init)
+ PepType_SOTP(base)->subtype_init(newType, args, kwds);
}
return reinterpret_cast<PyObject*>(newType);
@@ -455,37 +486,22 @@ void _destroyParentInfo(SbkObject* obj, bool keepReference)
namespace Shiboken
{
-
-static void decRefPyObjectList(const std::list<PyObject*> &pyObj, PyObject* skip = 0);
-
-static void _walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor)
+bool walkThroughClassHierarchy(PyTypeObject *currentType, HierarchyVisitor *visitor)
{
PyObject* bases = currentType->tp_bases;
Py_ssize_t numBases = PyTuple_GET_SIZE(bases);
- for (int i = 0; i < numBases; ++i) {
+ bool result = false;
+ for (int i = 0; !result && i < numBases; ++i) {
PyTypeObject* type = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i));
-
- if (!PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) {
- continue;
- } else {
+ if (PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(SbkObject_TypeF()))) {
SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(type);
- if (PepType_SOTP(sbkType)->is_user_type)
- _walkThroughClassHierarchy(type, visitor);
- else
- visitor->visit(sbkType);
+ result = PepType_SOTP(sbkType)->is_user_type
+ ? walkThroughClassHierarchy(type, visitor) : visitor->visit(sbkType);
}
- if (visitor->wasFinished())
- break;
}
+ return result;
}
-void walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor)
-{
- _walkThroughClassHierarchy(currentType, visitor);
- visitor->done();
-}
-
-
bool importModule(const char* moduleName, PyTypeObject*** cppApiPtr)
{
PyObject* sysModules = PyImport_GetModuleDict();
@@ -517,27 +533,36 @@ bool importModule(const char* moduleName, PyTypeObject*** cppApiPtr)
// Wrapper metatype and base type ----------------------------------------------------------
-void DtorCallerVisitor::visit(SbkObjectType* node)
+HierarchyVisitor::HierarchyVisitor() = default;
+HierarchyVisitor::~HierarchyVisitor() = default;
+
+bool BaseCountVisitor::visit(SbkObjectType *)
{
- m_ptrs.push_back(std::make_pair(m_pyObj->d->cptr[m_ptrs.size()], node));
+ m_count++;
+ return false;
}
-void DtorCallerVisitor::done()
+bool BaseAccumulatorVisitor::visit(SbkObjectType *node)
{
- std::list<std::pair<void*, SbkObjectType*> >::const_iterator it = m_ptrs.begin();
- for (; it != m_ptrs.end(); ++it) {
- Shiboken::ThreadStateSaver threadSaver;
- threadSaver.save();
- PepType_SOTP(it->second)->cpp_dtor(it->first);
- }
+ m_bases.push_back(node);
+ return false;
}
-void DeallocVisitor::done()
+bool GetIndexVisitor::visit(SbkObjectType *node)
{
- Shiboken::Object::deallocData(m_pyObj, true);
- DtorCallerVisitor::done();
+ m_index++;
+ return PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(node), m_desiredType);
}
+bool DtorAccumulatorVisitor::visit(SbkObjectType *node)
+{
+ m_entries.push_back(DestructorEntry{PepType_SOTP(node)->cpp_dtor,
+ m_pyObject->d->cptr[m_entries.size()]});
+ return false;
+}
+
+void _initMainThreadId(); // helper.cpp
+
namespace Conversions { void init(); }
void init()
@@ -546,6 +571,8 @@ void init()
if (shibokenAlreadInitialised)
return;
+ _initMainThreadId();
+
Conversions::init();
PyEval_InitThreads();
@@ -609,25 +636,21 @@ void setErrorAboutWrongArguments(PyObject* args, const char* funcName, const cha
class FindBaseTypeVisitor : public HierarchyVisitor
{
- public:
- FindBaseTypeVisitor(PyTypeObject* typeToFind) : m_found(false), m_typeToFind(typeToFind) {}
- virtual void visit(SbkObjectType* node)
- {
- if (reinterpret_cast<PyTypeObject*>(node) == m_typeToFind) {
- m_found = true;
- finish();
- }
- }
- bool found() const { return m_found; }
+public:
+ explicit FindBaseTypeVisitor(PyTypeObject *typeToFind) : m_typeToFind(typeToFind) {}
+
+ bool visit(SbkObjectType *node) override
+ {
+ return reinterpret_cast<PyTypeObject*>(node) == m_typeToFind;
+ }
- private:
- bool m_found;
- PyTypeObject* m_typeToFind;
+private:
+ PyTypeObject *m_typeToFind;
};
-std::list<SbkObject*> splitPyObject(PyObject* pyObj)
+std::vector<SbkObject *> splitPyObject(PyObject* pyObj)
{
- std::list<SbkObject*> result;
+ std::vector<SbkObject *> result;
if (PySequence_Check(pyObj)) {
AutoDecRef lst(PySequence_Fast(pyObj, "Invalid keep reference object."));
if (!lst.isNull()) {
@@ -643,14 +666,11 @@ std::list<SbkObject*> splitPyObject(PyObject* pyObj)
return result;
}
-static void decRefPyObjectList(const std::list<PyObject*>& lst, PyObject *skip)
+template <class Iterator>
+inline void decRefPyObjectList(Iterator i1, Iterator i2)
{
- std::list<PyObject*>::const_iterator iter = lst.begin();
- while(iter != lst.end()) {
- if (*iter != skip)
- Py_DECREF(*iter);
- ++iter;
- }
+ for (; i1 != i2; ++i1)
+ Py_DECREF(i1->second);
}
namespace ObjectType
@@ -669,8 +689,7 @@ bool isUserType(PyTypeObject* type)
bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType)
{
FindBaseTypeVisitor visitor(ctorType);
- walkThroughClassHierarchy(myType, &visitor);
- if (!visitor.found()) {
+ if (!walkThroughClassHierarchy(myType, &visitor)) {
PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", ctorType->tp_name, myType->tp_name);
return false;
}
@@ -748,7 +767,7 @@ introduceWrapperType(PyObject *enclosingObject,
ObjectDestructor cppObjDtor,
SbkObjectType *baseType,
PyObject *baseTypes,
- bool isInnerClass)
+ unsigned wrapperFlags)
{
if (baseType) {
typeSpec->slots[0].pfunc = reinterpret_cast<void *>(baseType);
@@ -773,10 +792,14 @@ introduceWrapperType(PyObject *enclosingObject,
return nullptr;
initPrivateData(type);
+ auto sotp = PepType_SOTP(type);
+ if (wrapperFlags & DeleteInMainThread)
+ sotp->delete_in_main_thread = 1;
+
setOriginalName(type, originalName);
setDestructorFunction(type, cppObjDtor);
- if (isInnerClass) {
+ if (wrapperFlags & InnerClass) {
if (PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0)
return type;
else
@@ -844,12 +867,13 @@ static void setSequenceOwnership(PyObject* pyObj, bool owner)
if (PySequence_Check(pyObj) && has_length) {
Py_ssize_t size = PySequence_Size(pyObj);
if (size > 0) {
- std::list<SbkObject*> objs = splitPyObject(pyObj);
- for (auto it = objs.begin(), end = objs.end(); it != end; ++it) {
- if (owner)
- getOwnership(*it);
- else
- releaseOwnership(*it);
+ const auto objs = splitPyObject(pyObj);
+ if (owner) {
+ for (SbkObject *o : objs)
+ getOwnership(o);
+ } else {
+ for (SbkObject *o : objs)
+ releaseOwnership(o);
}
}
} else if (Object::checkType(pyObj)) {
@@ -885,8 +909,9 @@ void callCppDestructors(SbkObject* pyObj)
PyTypeObject *type = Py_TYPE(pyObj);
SbkObjectTypePrivate * sotp = PepType_SOTP(type);
if (sotp->is_multicpp) {
- Shiboken::DtorCallerVisitor visitor(pyObj);
+ Shiboken::DtorAccumulatorVisitor visitor(pyObj);
Shiboken::walkThroughClassHierarchy(type, &visitor);
+ callDestructor(visitor.entries());
} else {
Shiboken::ThreadStateSaver threadSaver;
threadSaver.save();
@@ -977,10 +1002,9 @@ void invalidate(SbkObject* self)
static void recursive_invalidate(PyObject* pyobj, std::set<SbkObject*>& seen)
{
- std::list<SbkObject*> objs = splitPyObject(pyobj);
- std::list<SbkObject*>::const_iterator it = objs.begin();
- for (; it != objs.end(); it++)
- recursive_invalidate(*it, seen);
+ const auto objs = splitPyObject(pyobj);
+ for (SbkObject *o : objs)
+ recursive_invalidate(o, seen);
}
static void recursive_invalidate(SbkObject* self, std::set<SbkObject*>& seen)
@@ -999,30 +1023,22 @@ static void recursive_invalidate(SbkObject* self, std::set<SbkObject*>& seen)
if (self->d->parentInfo) {
// Create a copy because this list can be changed during the process
ChildrenList copy = self->d->parentInfo->children;
- ChildrenList::iterator it = copy.begin();
- for (; it != copy.end(); ++it) {
+ for (SbkObject *child : copy) {
// invalidate the child
- recursive_invalidate(*it, seen);
+ recursive_invalidate(child, seen);
// if the parent not is a wrapper class, then remove children from him, because We do not know when this object will be destroyed
if (!self->d->validCppObject)
- removeParent(*it, true, true);
+ removeParent(child, true, true);
}
}
// If has ref to other objects invalidate all
if (self->d->referredObjects) {
RefCountMap& refCountMap = *(self->d->referredObjects);
- RefCountMap::iterator iter;
- for (iter = refCountMap.begin(); iter != refCountMap.end(); ++iter) {
- const std::list<PyObject*> lst = iter->second;
- std::list<PyObject*>::const_iterator it = lst.begin();
- while(it != lst.end()) {
- recursive_invalidate(*it, seen);
- ++it;
- }
- }
+ for (auto it = refCountMap.begin(), end = refCountMap.end(); it != end; ++it)
+ recursive_invalidate(it->second, seen);
}
}
@@ -1037,23 +1053,17 @@ void makeValid(SbkObject* self)
// If it is a parent make all children valid
if (self->d->parentInfo) {
- ChildrenList::iterator it = self->d->parentInfo->children.begin();
- for (; it != self->d->parentInfo->children.end(); ++it)
- makeValid(*it);
+ for (SbkObject *child : self->d->parentInfo->children)
+ makeValid(child);
}
// If has ref to other objects make all valid again
if (self->d->referredObjects) {
RefCountMap& refCountMap = *(self->d->referredObjects);
RefCountMap::iterator iter;
- for (iter = refCountMap.begin(); iter != refCountMap.end(); ++iter) {
- const std::list<PyObject*> lst = iter->second;
- std::list<PyObject*>::const_iterator it = lst.begin();
- while(it != lst.end()) {
- if (Shiboken::Object::checkType(*it))
- makeValid(reinterpret_cast<SbkObject*>(*it));
- ++it;
- }
+ for (auto it = refCountMap.begin(), end = refCountMap.end(); it != end; ++it) {
+ if (Shiboken::Object::checkType(it->second))
+ makeValid(reinterpret_cast<SbkObject *>(it->second));
}
}
}
@@ -1168,15 +1178,14 @@ SbkObject *findColocatedChild(SbkObject *wrapper,
ChildrenList& children = pInfo->children;
- ChildrenList::iterator childrenEnd = children.end();
- for (ChildrenList::iterator iChild = children.begin(); iChild != childrenEnd; ++iChild) {
- if (!((*iChild)->d && (*iChild)->d->cptr))
+ for (SbkObject *child : children) {
+ if (!(child->d && child->d->cptr))
continue;
- if ((*iChild)->d->cptr[0] == wrapper->d->cptr[0]) {
- if (reinterpret_cast<const void *>(Py_TYPE(*iChild)) == reinterpret_cast<const void *>(instanceType))
- return const_cast<SbkObject *>((*iChild));
+ if (child->d->cptr[0] == wrapper->d->cptr[0]) {
+ if (reinterpret_cast<const void *>(Py_TYPE(child)) == reinterpret_cast<const void *>(instanceType))
+ return child;
else
- return findColocatedChild(const_cast<SbkObject *>(*iChild), instanceType);
+ return findColocatedChild(child, instanceType);
}
}
return 0;
@@ -1435,57 +1444,56 @@ void* getTypeUserData(SbkObject* wrapper)
return PepType_SOTP(Py_TYPE(wrapper))->user_data;
}
-void keepReference(SbkObject* self, const char* key, PyObject* referredObject, bool append)
+static inline bool isNone(const PyObject *o)
{
- bool isNone = (!referredObject || (referredObject == Py_None));
-
- if (!self->d->referredObjects)
- self->d->referredObjects = new Shiboken::RefCountMap;
-
- RefCountMap& refCountMap = *(self->d->referredObjects);
- RefCountMap::iterator iter = refCountMap.find(key);
- std::list<PyObject*> objects;
- if (iter != refCountMap.end()) {
- objects = (*iter).second;
- std::list<PyObject*>::const_iterator found = std::find(objects.begin(), objects.end(), referredObject);
-
- // skip if objects already exists
- if (found != objects.end())
- return;
- }
+ return o == nullptr || o == Py_None;
+}
- if (append && !isNone) {
- refCountMap[key].push_back(referredObject);
- Py_INCREF(referredObject);
- } else if (!append) {
- if (objects.size() > 0)
- decRefPyObjectList(objects, isNone ? 0 : referredObject);
- if (isNone) {
- if (iter != refCountMap.end())
- refCountMap.erase(iter);
- } else {
- objects.clear();
- objects.push_back(referredObject);
- refCountMap[key] = objects;
- Py_INCREF(referredObject);
+static void removeRefCountKey(SbkObject* self, const char *key)
+{
+ if (self->d->referredObjects) {
+ const auto iterPair = self->d->referredObjects->equal_range(key);
+ if (iterPair.first != iterPair.second) {
+ decRefPyObjectList(iterPair.first, iterPair.second);
+ self->d->referredObjects->erase(iterPair.first, iterPair.second);
}
}
}
-void removeReference(SbkObject* self, const char* key, PyObject* referredObject)
+void keepReference(SbkObject* self, const char* key, PyObject* referredObject, bool append)
{
- if (!referredObject || (referredObject == Py_None))
+ if (isNone(referredObject)) {
+ removeRefCountKey(self, key);
return;
+ }
- if (!self->d->referredObjects)
+ if (!self->d->referredObjects) {
+ self->d->referredObjects =
+ new Shiboken::RefCountMap{RefCountMap::value_type{key, referredObject}};
+ Py_INCREF(referredObject);
return;
+ }
RefCountMap& refCountMap = *(self->d->referredObjects);
- RefCountMap::iterator iter = refCountMap.find(key);
- if (iter != refCountMap.end()) {
- decRefPyObjectList(iter->second);
- refCountMap.erase(iter);
+ const auto iterPair = refCountMap.equal_range(key);
+ if (std::any_of(iterPair.first, iterPair.second,
+ [referredObject](const RefCountMap::value_type &v) { return v.second == referredObject; })) {
+ return;
+ }
+
+ if (!append && iterPair.first != iterPair.second) {
+ decRefPyObjectList(iterPair.first, iterPair.second);
+ refCountMap.erase(iterPair.first, iterPair.second);
}
+
+ refCountMap.insert(RefCountMap::value_type{key, referredObject});
+ Py_INCREF(referredObject);
+}
+
+void removeReference(SbkObject* self, const char* key, PyObject* referredObject)
+{
+ if (!isNone(referredObject))
+ removeRefCountKey(self, key);
}
void clearReferences(SbkObject* self)
@@ -1494,27 +1502,27 @@ void clearReferences(SbkObject* self)
return;
RefCountMap& refCountMap = *(self->d->referredObjects);
- RefCountMap::iterator iter;
- for (iter = refCountMap.begin(); iter != refCountMap.end(); ++iter)
- decRefPyObjectList(iter->second);
+ for (auto it = refCountMap.begin(), end = refCountMap.end(); it != end; ++it)
+ Py_DECREF(it->second);
self->d->referredObjects->clear();
}
std::string info(SbkObject* self)
{
std::ostringstream s;
- std::list<SbkObjectType*> bases;
if (self->d && self->d->cptr) {
+ std::vector<SbkObjectType *> bases;
if (ObjectType::isUserType(Py_TYPE(self)))
bases = getCppBaseClasses(Py_TYPE(self));
else
bases.push_back(reinterpret_cast<SbkObjectType*>(Py_TYPE(self)));
s << "C++ address....... ";
- std::list<SbkObjectType*>::const_iterator it = bases.begin();
- for (int i = 0; it != bases.end(); ++it, ++i)
- s << reinterpret_cast<PyTypeObject *>(*it)->tp_name << '/' << self->d->cptr[i] << ' ';
+ for (size_t i = 0, size = bases.size(); i < size; ++i) {
+ auto base = reinterpret_cast<PyTypeObject *>(bases[i]);
+ s << base->tp_name << '/' << self->d->cptr[i] << ' ';
+ }
s << "\n";
}
else {
@@ -1535,9 +1543,8 @@ std::string info(SbkObject* self)
if (self->d->parentInfo && !self->d->parentInfo->children.empty()) {
s << "children.......... ";
- ChildrenList& children = self->d->parentInfo->children;
- for (ChildrenList::const_iterator it = children.begin(); it != children.end(); ++it) {
- Shiboken::AutoDecRef child(PyObject_Str(reinterpret_cast<PyObject *>(*it)));
+ for (SbkObject *sbkChild : self->d->parentInfo->children) {
+ Shiboken::AutoDecRef child(PyObject_Str(reinterpret_cast<PyObject *>(sbkChild)));
s << String::toCString(child) << ' ';
}
s << '\n';
@@ -1546,17 +1553,16 @@ std::string info(SbkObject* self)
if (self->d->referredObjects && !self->d->referredObjects->empty()) {
Shiboken::RefCountMap& map = *self->d->referredObjects;
s << "referred objects.. ";
- Shiboken::RefCountMap::const_iterator it = map.begin();
- for (; it != map.end(); ++it) {
- if (it != map.begin())
- s << " ";
- s << '"' << it->first << "\" => ";
- std::list<PyObject*>::const_iterator j = it->second.begin();
- for (; j != it->second.end(); ++j) {
- Shiboken::AutoDecRef obj(PyObject_Str(*j));
- s << String::toCString(obj) << ' ';
+ std::string lastKey;
+ for (auto it = map.begin(), end = map.end(); it != end; ++it) {
+ if (it->first != lastKey) {
+ if (!lastKey.empty())
+ s << " ";
+ s << '"' << it->first << "\" => ";
+ lastKey = it->first;
}
- s << ' ';
+ Shiboken::AutoDecRef obj(PyObject_Str(it->second));
+ s << String::toCString(obj) << ' ';
}
s << '\n';
}
diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h
index 134a3bc51..65849d783 100644
--- a/sources/shiboken2/libshiboken/basewrapper.h
+++ b/sources/shiboken2/libshiboken/basewrapper.h
@@ -190,6 +190,12 @@ LIBSHIBOKEN_API void setDestructorFunction(SbkObjectType* self, ObjectDes
LIBSHIBOKEN_API void initPrivateData(SbkObjectType* self);
+enum WrapperFlags
+{
+ InnerClass = 0x1,
+ DeleteInMainThread = 0x2
+};
+
/**
* Initializes a Shiboken wrapper type and adds it to the module,
* or to the enclosing class if the type is an inner class.
@@ -215,7 +221,7 @@ LIBSHIBOKEN_API SbkObjectType *introduceWrapperType(PyObject *enclosingObject,
ObjectDestructor cppObjDtor,
SbkObjectType *baseType,
PyObject *baseTypes,
- bool isInnerClass);
+ unsigned wrapperFlags = 0);
/**
* Set the subtype init hook for a type.
diff --git a/sources/shiboken2/libshiboken/basewrapper_p.h b/sources/shiboken2/libshiboken/basewrapper_p.h
index ebd2648e7..f8a381078 100644
--- a/sources/shiboken2/libshiboken/basewrapper_p.h
+++ b/sources/shiboken2/libshiboken/basewrapper_p.h
@@ -43,10 +43,10 @@
#include "sbkpython.h"
#include "basewrapper.h"
-#include <list>
-#include <map>
+#include <unordered_map>
#include <set>
#include <string>
+#include <vector>
struct SbkObject;
struct SbkObjectType;
@@ -58,7 +58,7 @@ namespace Shiboken
* This mapping associates a method and argument of an wrapper object with the wrapper of
* said argument when it needs the binding to help manage its reference count.
*/
-typedef std::map<std::string, std::list<PyObject*> > RefCountMap;
+typedef std::unordered_multimap<std::string, PyObject *> RefCountMap;
/// Linked list of SbkBaseWrapper pointers
typedef std::set<SbkObject*> ChildrenList;
@@ -137,6 +137,7 @@ struct SbkObjectTypePrivate
/// Tells is the type is a value type or an object-type, see BEHAVIOUR_* constants.
// TODO-CONVERTERS: to be deprecated/removed
int type_behaviour : 2;
+ int delete_in_main_thread : 1;
/// C++ name
char* original_name;
/// Type user data
@@ -150,10 +151,21 @@ struct SbkObjectTypePrivate
namespace Shiboken
{
+
+/**
+ * \internal
+ * Data required to invoke a C++ destructor
+ */
+struct DestructorEntry
+{
+ ObjectDestructor destructor;
+ void *cppInstance;
+};
+
/**
* Utility function used to transform a PyObject that implements sequence protocol into a std::list.
**/
-std::list<SbkObject*> splitPyObject(PyObject* pyObj);
+std::vector<SbkObject *> splitPyObject(PyObject* pyObj);
/**
* Visitor class used by walkOnClassHierarchy function.
@@ -161,81 +173,71 @@ std::list<SbkObject*> splitPyObject(PyObject* pyObj);
class HierarchyVisitor
{
public:
- HierarchyVisitor() : m_wasFinished(false) {}
- virtual ~HierarchyVisitor() {}
- virtual void visit(SbkObjectType* node) = 0;
- virtual void done() {}
- void finish() { m_wasFinished = true; };
- bool wasFinished() const { return m_wasFinished; }
-private:
- bool m_wasFinished;
+ HierarchyVisitor(const HierarchyVisitor &) = delete;
+ HierarchyVisitor(HierarchyVisitor &&) = delete;
+ HierarchyVisitor &operator=(const HierarchyVisitor &) = delete;
+ HierarchyVisitor &operator=(HierarchyVisitor &&) = delete;
+
+ HierarchyVisitor();
+ virtual ~HierarchyVisitor();
+
+ virtual bool visit(SbkObjectType *node) = 0; // return true to terminate
};
class BaseCountVisitor : public HierarchyVisitor
{
public:
- BaseCountVisitor() : m_count(0) {}
-
- void visit(SbkObjectType*)
- {
- m_count++;
- }
+ bool visit(SbkObjectType *) override;
int count() const { return m_count; }
+
private:
- int m_count;
+ int m_count = 0;
};
class BaseAccumulatorVisitor : public HierarchyVisitor
{
public:
- BaseAccumulatorVisitor() {}
+ typedef std::vector<SbkObjectType *> Result;
- void visit(SbkObjectType* node)
- {
- m_bases.push_back(node);
- }
+ bool visit(SbkObjectType *node) override;
+
+ Result bases() const { return m_bases; }
- std::list<SbkObjectType*> bases() const { return m_bases; }
private:
- std::list<SbkObjectType*> m_bases;
+ Result m_bases;
};
class GetIndexVisitor : public HierarchyVisitor
{
public:
- GetIndexVisitor(PyTypeObject* desiredType) : m_index(-1), m_desiredType(desiredType) {}
- virtual void visit(SbkObjectType* node)
- {
- m_index++;
- if (PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(node), m_desiredType))
- finish();
- }
+ explicit GetIndexVisitor(PyTypeObject* desiredType) : m_desiredType(desiredType) {}
+
+ bool visit(SbkObjectType *node) override;
+
int index() const { return m_index; }
private:
- int m_index;
- PyTypeObject* m_desiredType;
+ int m_index = -1;
+ PyTypeObject *m_desiredType;
};
-/// Call the destructor of each C++ object held by a Python object
-class DtorCallerVisitor : public HierarchyVisitor
+/// Collect destructors and C++ instances of each C++ object held by a Python
+/// object
+class DtorAccumulatorVisitor : public HierarchyVisitor
{
public:
- DtorCallerVisitor(SbkObject* pyObj) : m_pyObj(pyObj) {}
- void visit(SbkObjectType* node);
- void done();
-protected:
- std::list<std::pair<void*, SbkObjectType*> > m_ptrs;
- SbkObject* m_pyObj;
-};
+ explicit DtorAccumulatorVisitor(SbkObject *pyObj) : m_pyObject(pyObj) {}
-/// Dealloc of each C++ object held by a Python object, this implies a call to the C++ object destructor
-class DeallocVisitor : public DtorCallerVisitor
-{
-public:
- DeallocVisitor(SbkObject* pyObj) : DtorCallerVisitor(pyObj) {}
- void done();
+ bool visit(SbkObjectType *node) override;
+
+ using DestructorEntries = std::vector<DestructorEntry>;
+
+ const DestructorEntries &entries() const { return m_entries; }
+
+private:
+ DestructorEntries m_entries;
+ SbkObject *m_pyObject;
};
/// \internal Internal function used to walk on classes inheritance trees.
@@ -244,7 +246,7 @@ public:
* For each pure Shiboken type found, HiearchyVisitor::visit is called and the algorithm consider
* all children of this type as visited.
*/
-void walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor);
+bool walkThroughClassHierarchy(PyTypeObject *currentType, HierarchyVisitor *visitor);
inline int getTypeIndexOnHierarchy(PyTypeObject* baseType, PyTypeObject* desiredType)
{
@@ -260,7 +262,7 @@ inline int getNumberOfCppBaseClasses(PyTypeObject* baseType)
return visitor.count();
}
-inline std::list<SbkObjectType*> getCppBaseClasses(PyTypeObject* baseType)
+inline std::vector<SbkObjectType *> getCppBaseClasses(PyTypeObject* baseType)
{
BaseAccumulatorVisitor visitor;
walkThroughClassHierarchy(baseType, &visitor);
diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp
index 0aa520b38..8a9e912fd 100644
--- a/sources/shiboken2/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken2/libshiboken/bindingmanager.cpp
@@ -57,14 +57,12 @@ typedef std::unordered_map<const void *, SbkObject *> WrapperMap;
class Graph
{
public:
- typedef std::list<SbkObjectType*> NodeList;
+ typedef std::vector<SbkObjectType *> NodeList;
typedef std::unordered_map<SbkObjectType *, NodeList> Edges;
Edges m_edges;
- Graph()
- {
- }
+ Graph() = default;
void addEdge(SbkObjectType* from, SbkObjectType* to)
{
@@ -78,14 +76,13 @@ public:
file << "digraph D {\n";
- Edges::const_iterator i = m_edges.begin();
- for (; i != m_edges.end(); ++i) {
- SbkObjectType* node1 = i->first;
+ for (auto i = m_edges.begin(), end = m_edges.end(); i != end; ++i) {
+ auto node1 = reinterpret_cast<const PyTypeObject *>(i->first);
const NodeList& nodeList = i->second;
- NodeList::const_iterator j = nodeList.begin();
- for (; j != nodeList.end(); ++j) {
- file << '"' << reinterpret_cast<PyTypeObject *>(*j)->tp_name << "\" -> \""
- << reinterpret_cast<PyTypeObject *>(node1)->tp_name << "\"\n";
+ for (const SbkObjectType *o : nodeList) {
+ auto node2 = reinterpret_cast<const PyTypeObject *>(o);
+ file << '"' << node2->tp_name << "\" -> \""
+ << node1->tp_name << "\"\n";
}
}
file << "}\n";
@@ -97,9 +94,8 @@ public:
Edges::const_iterator edgesIt = m_edges.find(type);
if (edgesIt != m_edges.end()) {
const NodeList& adjNodes = m_edges.find(type)->second;
- NodeList::const_iterator i = adjNodes.begin();
- for (; i != adjNodes.end(); ++i) {
- SbkObjectType* newType = identifyType(cptr, *i, baseType);
+ for (SbkObjectType *node : adjNodes) {
+ SbkObjectType* newType = identifyType(cptr, node, baseType);
if (newType)
return newType;
}
@@ -115,9 +111,8 @@ public:
if (typeFound != type)
*cptr = typeFound;
return type;
- } else {
- return nullptr;
}
+ return nullptr;
}
};
@@ -128,10 +123,9 @@ static void showWrapperMap(const WrapperMap& wrapperMap)
if (Py_VerboseFlag > 0) {
fprintf(stderr, "-------------------------------\n");
fprintf(stderr, "WrapperMap: %p (size: %d)\n", &wrapperMap, (int) wrapperMap.size());
- WrapperMap::const_iterator iter;
- for (iter = wrapperMap.begin(); iter != wrapperMap.end(); ++iter) {
- const SbkObject *sbkObj = iter->second;
- fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", iter->first,
+ for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) {
+ const SbkObject *sbkObj = it->second;
+ fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", it->first,
static_cast<const void *>(sbkObj),
(Py_TYPE(sbkObj))->tp_name,
int(reinterpret_cast<const PyObject *>(sbkObj)->ob_refcnt));
@@ -142,8 +136,11 @@ static void showWrapperMap(const WrapperMap& wrapperMap)
#endif
struct BindingManager::BindingManagerPrivate {
+ using DestructorEntries = std::vector<DestructorEntry>;
+
WrapperMap wrapperMapper;
Graph classHierarchy;
+ DestructorEntries deleteInMainThread;
bool destroying;
BindingManagerPrivate() : destroying(false) {}
@@ -255,6 +252,18 @@ void BindingManager::releaseWrapper(SbkObject* sbkObj)
sbkObj->d->validCppObject = false;
}
+void BindingManager::runDeletionInMainThread()
+{
+ for (const DestructorEntry &e : m_d->deleteInMainThread)
+ e.destructor(e.cppInstance);
+ m_d->deleteInMainThread.clear();
+}
+
+void BindingManager::addToDeletionInMainThread(const DestructorEntry &e)
+{
+ m_d->deleteInMainThread.push_back(e);
+}
+
SbkObject* BindingManager::retrieveWrapper(const void* cptr)
{
WrapperMap::iterator iter = m_d->wrapperMapper.find(cptr);
diff --git a/sources/shiboken2/libshiboken/bindingmanager.h b/sources/shiboken2/libshiboken/bindingmanager.h
index 13a4d3a2e..d03aa999a 100644
--- a/sources/shiboken2/libshiboken/bindingmanager.h
+++ b/sources/shiboken2/libshiboken/bindingmanager.h
@@ -50,11 +50,18 @@ struct SbkObjectType;
namespace Shiboken
{
+struct DestructorEntry;
+
typedef void (*ObjectVisitor)(SbkObject*, void*);
class LIBSHIBOKEN_API BindingManager
{
public:
+ BindingManager(const BindingManager&) = delete;
+ BindingManager(BindingManager&&) = delete;
+ BindingManager& operator=(const BindingManager&) = delete;
+ BindingManager& operator=(BindingManager&&) = delete;
+
static BindingManager& instance();
bool hasWrapper(const void *cptr);
@@ -62,6 +69,9 @@ public:
void registerWrapper(SbkObject* pyObj, void* cptr);
void releaseWrapper(SbkObject* wrapper);
+ void runDeletionInMainThread();
+ void addToDeletionInMainThread(const DestructorEntry &);
+
SbkObject* retrieveWrapper(const void* cptr);
PyObject* getOverride(const void* cptr, const char* methodName);
@@ -94,10 +104,7 @@ public:
private:
~BindingManager();
- // disable copy
BindingManager();
- BindingManager(const BindingManager&);
- BindingManager& operator=(const BindingManager&);
struct BindingManagerPrivate;
BindingManagerPrivate* m_d;
diff --git a/sources/shiboken2/libshiboken/gilstate.h b/sources/shiboken2/libshiboken/gilstate.h
index 00b049802..9da4871d1 100644
--- a/sources/shiboken2/libshiboken/gilstate.h
+++ b/sources/shiboken2/libshiboken/gilstate.h
@@ -49,6 +49,11 @@ namespace Shiboken
class LIBSHIBOKEN_API GilState
{
public:
+ GilState(const GilState&) = delete;
+ GilState(GilState&&) = delete;
+ GilState& operator=(const GilState&) = delete;
+ GilState& operator=(GilState&&) = delete;
+
GilState();
~GilState();
void release();
diff --git a/sources/shiboken2/libshiboken/helper.cpp b/sources/shiboken2/libshiboken/helper.cpp
index 472924723..e42daff07 100644
--- a/sources/shiboken2/libshiboken/helper.cpp
+++ b/sources/shiboken2/libshiboken/helper.cpp
@@ -41,6 +41,12 @@
#include "sbkstring.h"
#include <stdarg.h>
+#ifdef _WIN32
+# include <windows.h>
+#else
+# include <pthread.h>
+#endif
+
namespace Shiboken
{
@@ -141,4 +147,24 @@ int warning(PyObject* category, int stacklevel, const char* format, ...)
return result;
}
+ThreadId currentThreadId()
+{
+#if defined(_WIN32)
+ return GetCurrentThreadId();
+#elif defined(__APPLE_CC__)
+ return reinterpret_cast<ThreadId>(pthread_self());
+#else
+ return pthread_self();
+#endif
+}
+
+// Internal, used by init() from main thread
+static ThreadId _mainThreadId{0};
+void _initMainThreadId() { _mainThreadId = currentThreadId(); }
+
+ThreadId mainThreadId()
+{
+ return _mainThreadId;
+}
+
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/helper.h b/sources/shiboken2/libshiboken/helper.h
index b215142c7..9b6d8903f 100644
--- a/sources/shiboken2/libshiboken/helper.h
+++ b/sources/shiboken2/libshiboken/helper.h
@@ -77,7 +77,12 @@ template<class T>
class AutoArrayPointer
{
public:
- AutoArrayPointer(int size) { data = new T[size]; }
+ AutoArrayPointer(const AutoArrayPointer&) = delete;
+ AutoArrayPointer(AutoArrayPointer&&) = delete;
+ AutoArrayPointer& operator=(const AutoArrayPointer&) = delete;
+ AutoArrayPointer& operator=(AutoArrayPointer&&) = delete;
+
+ explicit AutoArrayPointer(int size) { data = new T[size]; }
T& operator[](int pos) { return data[pos]; }
operator T*() const { return data; }
~AutoArrayPointer() { delete[] data; }
@@ -85,6 +90,10 @@ class AutoArrayPointer
T* data;
};
+typedef unsigned long long ThreadId;
+LIBSHIBOKEN_API ThreadId currentThreadId();
+LIBSHIBOKEN_API ThreadId mainThreadId();
+
/**
* An utility function used to call PyErr_WarnEx with a formatted message.
*/
diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp
index 0baf6ed42..869d09529 100644
--- a/sources/shiboken2/libshiboken/pep384impl.cpp
+++ b/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -398,7 +398,10 @@ PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)
return ret;
}
+#endif // Py_LIMITED_API
+
// This is only a simple local helper that returns a computed variable.
+// Used also in Python 2.
static PyObject *
PepRun_GetResult(const char *command, const char *resvar)
{
@@ -415,6 +418,8 @@ PepRun_GetResult(const char *command, const char *resvar)
return res;
}
+#ifdef Py_LIMITED_API
+
/*****************************************************************************
*
* Support for classobject.h
@@ -499,13 +504,26 @@ PyTypeObject *PepStaticMethod_TypePtr = NULL;
static PyTypeObject *getStaticMethodType(void)
{
+ // this works for Python 3, only
+ // "StaticMethodType = type(str.__dict__['maketrans'])\n";
static const char prog[] =
- "StaticMethodType = type(str.__dict__['maketrans'])\n";
- return (PyTypeObject *) PepRun_GetResult(prog, "StaticMethodType");
+ "from xxsubtype import spamlist\n"
+ "StaticMethod_Type = type(spamlist.__dict__['staticmeth'])\n";
+ return (PyTypeObject *) PepRun_GetResult(prog, "StaticMethod_Type");
}
-
#endif // Py_LIMITED_API
+#if PY_VERSION_HEX < 0x03000000
+PyTypeObject *PepMethodDescr_TypePtr = NULL;
+
+static PyTypeObject *getMethodDescrType(void)
+{
+ static const char prog[] =
+ "MethodDescr_Type = type(str.split)\n";
+ return (PyTypeObject *) PepRun_GetResult(prog, "MethodDescr_Type");
+}
+#endif
+
/*****************************************************************************
*
* Common newly needed functions
@@ -630,6 +648,9 @@ Pep384_Init()
PepFunction_TypePtr = getFunctionType();
PepStaticMethod_TypePtr = getStaticMethodType();
#endif
+#if PY_VERSION_HEX < 0x03000000
+ PepMethodDescr_TypePtr = getMethodDescrType();
+#endif
}
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h
index b566a6218..6649fa95e 100644
--- a/sources/shiboken2/libshiboken/pep384impl.h
+++ b/sources/shiboken2/libshiboken/pep384impl.h
@@ -286,7 +286,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 < 0X0307FFFF)
+ PY_VERSION_HEX < 0x0307FFFF)
#if !PYTHON_BUFFER_VERSION_COMPATIBLE
# error Please check the buffer compatibility for this python version!
#endif
@@ -470,6 +470,12 @@ extern LIBSHIBOKEN_API PyTypeObject *PepStaticMethod_TypePtr;
#else
#define PepStaticMethod_TypePtr &PyStaticMethod_Type
#endif
+// Although not PEP specific, we resolve this similar issue, here:
+#if PY_VERSION_HEX < 0x03000000
+extern LIBSHIBOKEN_API PyTypeObject *PepMethodDescr_TypePtr;
+#else
+#define PepMethodDescr_TypePtr &PyMethodDescr_Type
+#endif
/*****************************************************************************
*
diff --git a/sources/shiboken2/libshiboken/sbkconverter.cpp b/sources/shiboken2/libshiboken/sbkconverter.cpp
index a13222de6..65844151f 100644
--- a/sources/shiboken2/libshiboken/sbkconverter.cpp
+++ b/sources/shiboken2/libshiboken/sbkconverter.cpp
@@ -246,10 +246,8 @@ PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType *type, PyObject *p
static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn)
{
assert(pyIn);
- const ToCppConversionList& convs = converter->toCppConversions;
- for (ToCppConversionList::const_iterator conv = convs.begin(), end = convs.end(); conv != end; ++conv) {
- PythonToCppFunc toCppFunc = 0;
- if ((toCppFunc = (*conv).first(pyIn)))
+ for (const ToCppConversion &c : converter->toCppConversions) {
+ if (PythonToCppFunc toCppFunc = c.first(pyIn))
return toCppFunc;
}
return 0;
@@ -361,7 +359,7 @@ bool isImplicitConversion(SbkObjectType *type, PythonToCppFunc toCppFunc)
// Note that we don't check if the Python to C++ conversion is in
// the list of the type's conversions, for it is expected that the
// caller knows what he's doing.
- ToCppConversionList::iterator conv = PepType_SOTP(type)->converter->toCppConversions.begin();
+ const auto conv = PepType_SOTP(type)->converter->toCppConversions.cbegin();
return toCppFunc != (*conv).second;
}
diff --git a/sources/shiboken2/libshiboken/sbkconverter_p.h b/sources/shiboken2/libshiboken/sbkconverter_p.h
index f39608663..a4edfe81e 100644
--- a/sources/shiboken2/libshiboken/sbkconverter_p.h
+++ b/sources/shiboken2/libshiboken/sbkconverter_p.h
@@ -43,11 +43,11 @@
#include "sbkpython.h"
#include "sbkconverter.h"
#include "sbkstring.h"
-#include <list>
#include <limits>
#include <typeinfo>
#include <sstream>
#include <iostream>
+#include <vector>
#include "sbkdbg.h"
@@ -55,7 +55,7 @@ extern "C"
{
typedef std::pair<IsConvertibleToCppFunc, PythonToCppFunc> ToCppConversion;
-typedef std::list<ToCppConversion> ToCppConversionList;
+typedef std::vector<ToCppConversion> ToCppConversionVector;
/**
* \internal
@@ -104,7 +104,7 @@ struct SbkConverter
* For Object Types, that never have implicit conversions, this
* list is always empty.
*/
- ToCppConversionList toCppConversions;
+ ToCppConversionVector toCppConversions;
};
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/sbkdbg.h b/sources/shiboken2/libshiboken/sbkdbg.h
index c26816bbd..fdaf2a27a 100644
--- a/sources/shiboken2/libshiboken/sbkdbg.h
+++ b/sources/shiboken2/libshiboken/sbkdbg.h
@@ -63,6 +63,11 @@
class BaseLogger
{
public:
+ BaseLogger(const BaseLogger&) = delete;
+ BaseLogger(BaseLogger&&) = delete;
+ BaseLogger& operator=(const BaseLogger&) = delete;
+ BaseLogger& operator=(BaseLogger&&) = delete;
+
BaseLogger(std::ostream& output, const char* function, const char* context)
: m_stream(output), m_function(function), m_context(context) {}
~BaseLogger()
diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp
index d129e6380..3c6582adc 100644
--- a/sources/shiboken2/libshiboken/sbkenum.cpp
+++ b/sources/shiboken2/libshiboken/sbkenum.cpp
@@ -47,7 +47,7 @@
#include <string.h>
#include <cstring>
-#include <list>
+#include <vector>
#define SBK_ENUM(ENUM) reinterpret_cast<SbkEnumObject*>(ENUM)
@@ -339,15 +339,18 @@ namespace Shiboken {
class DeclaredEnumTypes
{
public:
+ DeclaredEnumTypes(const DeclaredEnumTypes&) = delete;
+ DeclaredEnumTypes(DeclaredEnumTypes&&) = delete;
+ DeclaredEnumTypes& operator=(const DeclaredEnumTypes&) = delete;
+ DeclaredEnumTypes& operator=(DeclaredEnumTypes&&) = delete;
+
DeclaredEnumTypes();
~DeclaredEnumTypes();
static DeclaredEnumTypes& instance();
void addEnumType(PyTypeObject* type);
private:
- DeclaredEnumTypes(const DeclaredEnumTypes&);
- DeclaredEnumTypes& operator=(const DeclaredEnumTypes&);
- std::list<PyTypeObject*> m_enumTypes;
+ std::vector<PyTypeObject *> m_enumTypes;
};
namespace Enum {
@@ -373,7 +376,9 @@ PyObject* getEnumItemFromValue(PyTypeObject* enumType, long itemValue)
return 0;
}
-static PyTypeObject* createEnum(const char* fullName, const char* cppName, const char* shortName, PyTypeObject* flagsType)
+static PyTypeObject* createEnum(const char* fullName, const char* cppName,
+ const char* /* shortName */,
+ PyTypeObject* flagsType)
{
PyTypeObject* enumType = newTypeWithName(fullName, cppName, flagsType);
if (PyType_Ready(enumType) < 0)
@@ -524,13 +529,8 @@ copyNumberMethods(PyTypeObject *flagsType,
int *pidx)
{
int idx = *pidx;
-#ifdef IS_PY3K
-# define SLOT slot
-#else
-# define SLOT slot_
-#endif
#define PUT_SLOT(name) \
- number_slots[idx].SLOT = (name); \
+ number_slots[idx].slot = (name); \
number_slots[idx].pfunc = PyType_GetSlot(flagsType, (name)); \
++idx;
@@ -593,8 +593,8 @@ newTypeWithName(const char* name,
newspec->flags = SbkNewType_spec.flags;
// we must append all the number methods, so rebuild everything:
int idx = 0;
- while (SbkNewType_slots[idx].SLOT) {
- newslots[idx].SLOT = SbkNewType_slots[idx].SLOT;
+ while (SbkNewType_slots[idx].slot) {
+ newslots[idx].slot = SbkNewType_slots[idx].slot;
newslots[idx].pfunc = SbkNewType_slots[idx].pfunc;
++idx;
}
@@ -644,14 +644,10 @@ DeclaredEnumTypes& DeclaredEnumTypes::instance()
return me;
}
-DeclaredEnumTypes::DeclaredEnumTypes()
-{
-}
+DeclaredEnumTypes::DeclaredEnumTypes() = default;
DeclaredEnumTypes::~DeclaredEnumTypes()
{
- std::list<PyTypeObject*>::const_iterator it = m_enumTypes.begin();
- for (; it != m_enumTypes.end(); ++it) {
/*
* PYSIDE-595: This was "delete *it;" before introducing 'PyType_FromSpec'.
* XXX what should I do now?
@@ -660,8 +656,8 @@ DeclaredEnumTypes::~DeclaredEnumTypes()
* So right now I am doing nothing. Surely wrong but no crash.
* See also the comment in function 'createGlobalEnumItem'.
*/
- //fprintf(stderr, "ttt %d %s\n", Py_REFCNT(*it), *it->tp_name);
- }
+ // for (PyTypeObject *o : m_enumTypes)
+ // fprintf(stderr, "ttt %d %s\n", Py_REFCNT(o), o->tp_name);
m_enumTypes.clear();
}
diff --git a/sources/shiboken2/libshiboken/sbkpython.h b/sources/shiboken2/libshiboken/sbkpython.h
index 29e25605a..f06b0b19e 100644
--- a/sources/shiboken2/libshiboken/sbkpython.h
+++ b/sources/shiboken2/libshiboken/sbkpython.h
@@ -42,19 +42,65 @@
#include "sbkversion.h"
+// Qt's "slots" macro collides with the "slots" member variables
+// used in some Python structs. For compilers that support push_macro,
+// temporarily undefine it.
+#if defined(slots) && (defined(__GNUC__) || defined(_MSC_VER) || defined(__clang__))
+# pragma push_macro("slots")
+# undef slots
/*
* Python 2 has function _Py_Mangle directly in Python.h .
* This creates wrong language binding unless we define 'extern "C"' here.
*/
extern "C" {
-#include <Python.h>
+/*
+ * Python 2 uses the "register" keyword, which is deprecated in C++ 11
+ * and forbidden in C++17.
+ */
+# if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-register"
+# endif
+
+# include <Python.h>
+
+# if defined(__clang__)
+# pragma clang diagnostic pop
+# endif
}
-#include <structmember.h>
+# include <structmember.h>
// Now we have the usual variables from Python.h .
-#include "python25compat.h"
-#include "shibokenmacros.h"
-#include "pep384impl.h"
-#include "typespec.h"
+# include "python25compat.h"
+# include "shibokenmacros.h"
+# include "pep384impl.h"
+# include "typespec.h"
+# pragma pop_macro("slots")
+
+#else
+
+extern "C" {
+/*
+ * Python 2 uses the "register" keyword, which is deprecated in C++ 11
+ * and forbidden in C++17.
+ */
+# if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-register"
+# endif
+
+# include <Python.h>
+
+# if defined(__clang__)
+# pragma clang diagnostic pop
+# endif
+}
+# include <structmember.h>
+// Now we have the usual variables from Python.h .
+# include "python25compat.h"
+# include "shibokenmacros.h"
+# include "pep384impl.h"
+# include "typespec.h"
+#endif
#if PY_MAJOR_VERSION >= 3
#define IS_PY3K
diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp
index 6ca35f12e..a3ffcdabb 100644
--- a/sources/shiboken2/libshiboken/sbkstring.cpp
+++ b/sources/shiboken2/libshiboken/sbkstring.cpp
@@ -66,10 +66,7 @@ bool check(PyObject* obj)
bool checkChar(PyObject* pyobj)
{
- if (check(pyobj) && (len(pyobj) == 1))
- return true;
-
- return false;
+ return check(pyobj) && (len(pyobj) == 1);
}
bool isConvertible(PyObject* obj)
diff --git a/sources/shiboken2/libshiboken/shibokenbuffer.cpp b/sources/shiboken2/libshiboken/shibokenbuffer.cpp
index dc29b40a7..a691a31ee 100644
--- a/sources/shiboken2/libshiboken/shibokenbuffer.cpp
+++ b/sources/shiboken2/libshiboken/shibokenbuffer.cpp
@@ -58,6 +58,7 @@ void* Shiboken::Buffer::getPointer(PyObject* pyObj, Py_ssize_t* size)
PyBuffer_Release(&view);
return view.buf;
}
+ return nullptr;
#else
Py_ssize_t bufferSize = 0;
@@ -85,7 +86,8 @@ PyObject* Shiboken::Buffer::newObject(void* memory, Py_ssize_t size, Type type)
view.shape = shape;
// Pep384: This is way too complicated and impossible with the limited api:
//return PyMemoryView_FromBuffer(&view);
- return PyMemoryView_FromMemory((char *)view.buf, size, type == ReadOnly ? PyBUF_READ : PyBUF_WRITE);
+ return PyMemoryView_FromMemory(reinterpret_cast<char *>(view.buf),
+ size, type == ReadOnly ? PyBUF_READ : PyBUF_WRITE);
#else
return type == ReadOnly ? PyBuffer_FromMemory(memory, size) : PyBuffer_FromReadWriteMemory(memory, size);
#endif
diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp
index f0bb8e609..24d60acc4 100644
--- a/sources/shiboken2/libshiboken/signature.cpp
+++ b/sources/shiboken2/libshiboken/signature.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -77,18 +77,23 @@ typedef struct safe_globals_struc {
static safe_globals pyside_globals = 0;
-static PyObject *GetSignature_Function(PyCFunctionObject *);
-static PyObject *GetSignature_TypeMod(PyObject *);
+static PyObject *GetSignature_Function(PyCFunctionObject *, const char *);
+static PyObject *GetSignature_TypeMod(PyObject *, const char *);
+static PyObject *GetSignature_Wrapper(PyObject *, const char *);
+static PyObject *get_signature(PyObject *self, PyObject *args);
static PyObject *PySide_BuildSignatureProps(PyObject *class_mod);
+static void init_module_1(void);
+static void init_module_2(void);
+
const char helper_module_name[] = "signature_loader";
const char bootstrap_name[] = "bootstrap";
const char arg_name[] = "pyside_arg_dict";
const char func_name[] = "pyside_type_init";
static PyObject *
-CreateSignature(PyObject *props, const char *sig_kind)
+CreateSignature(PyObject *props, PyObject *key)
{
/*
* Here is the new function to create all signatures. It simply calls
@@ -97,22 +102,22 @@ CreateSignature(PyObject *props, const char *sig_kind)
* to support '_signature_is_functionlike()'.
*/
return PyObject_CallFunction(pyside_globals->createsig_func,
- (char *)"(Os)", props, sig_kind);
+ (char *)"(OO)", props, key);
}
static PyObject *
-pyside_cf_get___signature__(PyObject *func)
+pyside_cf_get___signature__(PyObject *func, const char *modifier)
{
- return GetSignature_Function((PyCFunctionObject *)func);
+ return GetSignature_Function((PyCFunctionObject *)func, modifier);
}
static PyObject *
-pyside_sm_get___signature__(PyObject *sm)
+pyside_sm_get___signature__(PyObject *sm, const char *modifier)
{
PyObject *func, *ret;
func = PyObject_GetAttrString(sm, "__func__");
- ret = GetSignature_Function((PyCFunctionObject *)func);
+ ret = GetSignature_Function((PyCFunctionObject *)func, modifier);
Py_XDECREF(func);
return ret;
}
@@ -192,7 +197,7 @@ qualname_to_func(PyObject *ob)
#endif
static PyObject *
-pyside_md_get___signature__(PyObject *ob)
+pyside_md_get___signature__(PyObject *ob, const char *modifier)
{
PyObject *func;
PyObject *result;
@@ -218,21 +223,31 @@ pyside_md_get___signature__(PyObject *ob)
return Py_None;
if (func == NULL)
Py_FatalError("missing mapping in MethodDescriptor");
- result = pyside_cf_get___signature__(func);
+ result = pyside_cf_get___signature__(func, modifier);
Py_DECREF(func);
return result;
}
static PyObject *
-pyside_tp_get___signature__(PyObject *typemod)
+pyside_wd_get___signature__(PyObject *ob, const char *modifier)
+{
+ return GetSignature_Wrapper(ob, modifier);
+}
+
+static PyObject *
+pyside_tp_get___signature__(PyObject *typemod, const char *modifier)
{
- return GetSignature_TypeMod(typemod);
+ return GetSignature_TypeMod(typemod, modifier);
}
+// forward
+static PyObject *
+GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier);
+
static PyObject *
-GetSignature_Function(PyCFunctionObject *func)
+GetSignature_Function(PyCFunctionObject *func, const char *modifier)
{
- PyObject *typemod, *type_name, *dict, *props, *value, *selftype;
+ PyObject *typemod, *type_name, *dict, *props, *selftype;
PyObject *func_name = PyObject_GetAttrString((PyObject *)func, "__name__");
const char *sig_kind;
int flags;
@@ -241,12 +256,8 @@ GetSignature_Function(PyCFunctionObject *func)
if (selftype == NULL)
selftype = PyDict_GetItem(pyside_globals->map_dict, (PyObject *)func);
if (selftype == NULL) {
- if (!PyErr_Occurred()) {
- PyErr_Format(PyExc_SystemError,
- "the signature for \"%s\" should exist",
- PepCFunction_GET_NAMESTR(func)
- );
- }
+ if (!PyErr_Occurred())
+ Py_RETURN_NONE;
return NULL;
}
if ((PyType_Check(selftype) || PyModule_Check(selftype)))
@@ -279,24 +290,46 @@ GetSignature_Function(PyCFunctionObject *func)
sig_kind = "staticmethod";
else
sig_kind = "method";
- value = PyDict_GetItemString(props, sig_kind);
- if (value == NULL) {
- // we need to compute a signature object
- value = CreateSignature(props, sig_kind);
- if (value != NULL) {
- if (PyDict_SetItemString(props, sig_kind, value) < 0)
- return NULL;
- }
- else
+ return GetSignature_Cached(props, sig_kind, modifier);
+}
+
+static PyObject *
+GetSignature_Wrapper(PyObject *ob, const char *modifier)
+{
+ PyObject *dict, *props;
+ PyObject *func_name = PyObject_GetAttrString(ob, "__name__");
+ PyObject *objclass = PyObject_GetAttrString(ob, "__objclass__");
+ PyObject *class_name = PyObject_GetAttrString(objclass, "__name__");
+ const char *sig_kind;
+
+ if (func_name == nullptr || objclass == nullptr || class_name == nullptr)
+ return nullptr;
+ dict = PyDict_GetItem(pyside_globals->arg_dict, class_name);
+ if (dict == NULL)
+ Py_RETURN_NONE;
+ if (PyTuple_Check(dict)) {
+ /*
+ * We do the initialization lazily.
+ * This has also the advantage that we can freely import PySide.
+ */
+ dict = PySide_BuildSignatureProps(objclass);
+ if (dict == NULL)
Py_RETURN_NONE;
}
- return Py_INCREF(value), value;
+ props = PyDict_GetItem(dict, func_name);
+ Py_DECREF(func_name);
+ Py_DECREF(objclass);
+ Py_DECREF(class_name);
+ if (props == NULL)
+ Py_RETURN_NONE;
+ sig_kind = "method";
+ return GetSignature_Cached(props, sig_kind, modifier);
}
static PyObject *
-GetSignature_TypeMod(PyObject *ob)
+GetSignature_TypeMod(PyObject *ob, const char *modifier)
{
- PyObject *ob_name, *dict, *props, *value;
+ PyObject *ob_name, *dict, *props;
const char *sig_kind;
ob_name = PyObject_GetAttrString(ob, "__name__");
@@ -314,37 +347,62 @@ GetSignature_TypeMod(PyObject *ob)
if (props == NULL)
Py_RETURN_NONE;
sig_kind = "method";
- value = PyDict_GetItemString(props, sig_kind);
- if (value == NULL) {
+ return GetSignature_Cached(props, sig_kind, modifier);
+}
+
+static PyObject *
+GetSignature_Cached(PyObject *props, const char *sig_kind, const char *modifier)
+{
+ PyObject *key, *value;
+
+ if (modifier == nullptr)
+ key = Py_BuildValue("s", sig_kind);
+ else
+ key = Py_BuildValue("(ss)", sig_kind, modifier);
+ if (key == nullptr)
+ return nullptr;
+ value = PyDict_GetItem(props, key);
+ if (value == nullptr) {
// we need to compute a signature object
- value = CreateSignature(props, sig_kind);
- if (value != NULL) {
- if (PyDict_SetItemString(props, sig_kind, value) < 0)
- return NULL;
+ value = CreateSignature(props, key);
+ if (value != nullptr) {
+ if (PyDict_SetItem(props, key, value) < 0) {
+ // this is an error
+ Py_DECREF(key);
+ return nullptr;
+ }
}
- else
+ else {
+ // key not found
+ Py_DECREF(key);
Py_RETURN_NONE;
+ }
}
return Py_INCREF(value), value;
}
-
static const char PySide_PythonCode[] =
- "from __future__ import print_function, absolute_import\n"
- "import sys, os, traceback\n"
-
- "pyside_package_dir = os.environ.get('PYSIDE_PACKAGE_DIR', '.')\n"
- "__file__ = os.path.join(pyside_package_dir, 'support', 'signature', 'loader.py')\n"
-
- "def bootstrap():\n"
- " try:\n"
- " with open(__file__) as _f:\n"
- " exec(compile(_f.read(), __file__, 'exec'))\n"
- " except Exception as e:\n"
- " print('Exception:', e)\n"
- " traceback.print_exc(file=sys.stdout)\n"
- " globals().update(locals())\n"
- ;
+ "from __future__ import print_function, absolute_import\n" R"~(if True:
+
+ import sys, os, traceback
+
+ pyside_package_dir = os.environ.get('PYSIDE_PACKAGE_DIR')
+ if pyside_package_dir is None:
+ # This happens in shiboken running ctest.
+ from distutils.sysconfig import get_python_lib
+ pyside_package_dir = os.path.join(get_python_lib(), 'PySide2')
+ __file__ = os.path.join(pyside_package_dir, 'support', 'signature', 'loader.py')
+
+ def bootstrap():
+ try:
+ with open(__file__) as _f:
+ exec(compile(_f.read(), __file__, 'exec'))
+ except Exception as e:
+ print('Exception:', e)
+ traceback.print_exc(file=sys.stdout)
+ globals().update(locals())
+
+ )~";
static safe_globals_struc *
init_phase_1(void)
@@ -387,9 +445,10 @@ error:
}
static int
-init_phase_2(safe_globals_struc *p)
+init_phase_2(safe_globals_struc *p, PyMethodDef *methods)
{
- PyObject *bootstrap_func;
+ PyObject *bootstrap_func, *v = nullptr;
+ PyMethodDef *ml;
bootstrap_func = PyObject_GetAttrString(p->helper_module, bootstrap_name);
if (bootstrap_func == NULL)
@@ -403,9 +462,22 @@ init_phase_2(safe_globals_struc *p)
p->createsig_func = PyObject_GetAttrString(p->helper_module, "create_signature");
if (p->createsig_func == NULL)
goto error;
+
+ // The single function to be called, but maybe more to come.
+ for (ml = methods; ml->ml_name != NULL; ml++) {
+ v = PyCFunction_NewEx(ml, nullptr, nullptr);
+ if (v == nullptr) {
+ goto error;
+ }
+ if (PyObject_SetAttrString(p->helper_module, ml->ml_name, v) != 0) {
+ goto error;
+ }
+ Py_DECREF(v);
+ }
return 0;
error:
+ Py_XDECREF(v);
PyErr_SetString(PyExc_SystemError, "could not initialize part 2");
return -1;
}
@@ -413,8 +485,11 @@ error:
static int
add_more_getsets(PyTypeObject *type, PyGetSetDef *gsp)
{
- PyObject *dict = type->tp_dict;
+ PyObject *dict;
+ assert(PyType_Check(type));
+ PyType_Ready(type);
+ dict = type->tp_dict;
for (; gsp->name != NULL; gsp++) {
PyObject *descr;
if (PyDict_GetItemString(dict, gsp->name))
@@ -463,6 +538,45 @@ static PyGetSetDef new_PyType_getsets[] = {
{0}
};
+static PyGetSetDef new_PyWrapperDescr_getsets[] = {
+ {(char *) "__signature__", (getter)pyside_wd_get___signature__},
+ {0}
+};
+
+////////////////////////////////////////////////////////////////////////////
+//
+// get_signature -- providing a superior interface
+//
+// Additionally to the interface via __signature__, we also provide
+// a general function, which allows for different signature layouts.
+// The "modifier" argument is a string that is passed in from loader.py .
+// Configuration what the modifiers mean is completely in Python.
+//
+
+static PyObject *
+get_signature(PyObject *self, PyObject *args)
+{
+ PyObject *ob;
+ const char *modifier = nullptr;
+
+ init_module_1();
+ init_module_2();
+
+ if (!PyArg_ParseTuple(args, "O|s", &ob, &modifier))
+ return NULL;
+ if (Py_TYPE(ob) == &PyCFunction_Type)
+ return pyside_cf_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == PepStaticMethod_TypePtr)
+ return pyside_sm_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == PepMethodDescr_TypePtr)
+ return pyside_md_get___signature__(ob, modifier);
+ if (PyType_Check(ob))
+ return pyside_tp_get___signature__(ob, modifier);
+ if (Py_TYPE(ob) == &PyWrapperDescr_Type)
+ return pyside_wd_get___signature__(ob, modifier);
+ Py_RETURN_NONE;
+}
+
////////////////////////////////////////////////////////////////////////////
//
// This special Type_Ready does certain initializations earlier with
@@ -497,23 +611,23 @@ void handler(int sig) {
static int
PySideType_Ready(PyTypeObject *type)
{
- PyObject *md;
+ PyObject *md, *wd;
static int init_done = 0;
if (!init_done) {
- // Python2 does not expose certain types. We look them up:
- // PyMethodDescr_Type 'type(str.__dict__["split"])'
- // PyClassMethodDescr_Type. 'type(dict.__dict__["fromkeys"])'
- // The latter is not needed until we use class methods in PySide.
- md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split");
- if (md == NULL
+ md = PyObject_GetAttrString((PyObject *)&PyString_Type, "split"); // method-descriptor
+ wd = PyObject_GetAttrString((PyObject *)Py_TYPE(Py_True), "__add__"); // wrapper-descriptor
+ if (md == nullptr || wd == nullptr
|| PyType_Ready(Py_TYPE(md)) < 0
- || add_more_getsets(Py_TYPE(md), new_PyMethodDescr_getsets) < 0
+ || add_more_getsets(PepMethodDescr_TypePtr, new_PyMethodDescr_getsets) < 0
|| add_more_getsets(&PyCFunction_Type, new_PyCFunction_getsets) < 0
|| add_more_getsets(PepStaticMethod_TypePtr, new_PyStaticMethod_getsets) < 0
- || add_more_getsets(&PyType_Type, new_PyType_getsets) < 0)
+ || add_more_getsets(&PyType_Type, new_PyType_getsets) < 0
+ || add_more_getsets(Py_TYPE(wd), new_PyWrapperDescr_getsets) < 0
+ )
return -1;
Py_DECREF(md);
+ Py_DECREF(wd);
#ifndef _WIN32
// We enable the stack trace in CI, only.
const char *testEnv = getenv("QTEST_ENVIRONMENT");
@@ -550,20 +664,26 @@ build_func_to_type(PyObject *obtype)
return 0;
}
+static void
+init_module_1(void)
+{
+ static int init_done = 0;
+
+ if (!init_done) {
+ pyside_globals = init_phase_1();
+ if (pyside_globals != nullptr)
+ init_done = 1;
+ }
+}
+
static int
PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
const char *signatures)
{
PyObject *type_name, *arg_tup;
const char *name = NULL;
- static int init_done = 0;
- if (!init_done) {
- pyside_globals = init_phase_1();
- if (pyside_globals == NULL)
- return -1;
- init_done = 1;
- }
+ init_module_1();;
arg_tup = Py_BuildValue("(Os)", type, signatures);
if (arg_tup == NULL)
return -1;
@@ -599,23 +719,34 @@ PySide_BuildSignatureArgs(PyObject *module, PyObject *type,
return 0;
}
-static PyObject *
-PySide_BuildSignatureProps(PyObject *classmod)
+static PyMethodDef signature_methods[] = {
+ {"get_signature", (PyCFunction)get_signature, METH_VARARGS,
+ "get the __signature__, but pass an optional string parameter"},
+ {NULL, NULL}
+};
+
+static void
+init_module_2(void)
{
- PyObject *arg_tup, *dict, *type_name;
static int init_done = 0;
if (!init_done) {
- if (init_phase_2(pyside_globals) < 0)
- return NULL;
+ init_phase_2(pyside_globals, signature_methods);
init_done = 1;
}
+}
+
+static PyObject *
+PySide_BuildSignatureProps(PyObject *classmod)
+{
+ PyObject *arg_tup, *dict, *type_name;
/*
* Here is the second part of the function.
* This part will be called on-demand when needed by some attribute.
* We simply pick up the arguments that we stored here and replace
* them by the function result.
*/
+ init_module_2();
type_name = PyObject_GetAttrString(classmod, "__name__");
if (type_name == NULL)
return NULL;
diff --git a/sources/shiboken2/libshiboken/signature.h b/sources/shiboken2/libshiboken/signature.h
index 3a229cb5c..b65317662 100644
--- a/sources/shiboken2/libshiboken/signature.h
+++ b/sources/shiboken2/libshiboken/signature.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
@@ -45,8 +45,8 @@
extern "C"
{
-LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char*);
-LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char*);
+LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char *); //WS
+LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *);
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/threadstatesaver.h b/sources/shiboken2/libshiboken/threadstatesaver.h
index e9f97f300..ddad9b67f 100644
--- a/sources/shiboken2/libshiboken/threadstatesaver.h
+++ b/sources/shiboken2/libshiboken/threadstatesaver.h
@@ -49,15 +49,17 @@ namespace Shiboken
class LIBSHIBOKEN_API ThreadStateSaver
{
public:
+ ThreadStateSaver(const ThreadStateSaver&) = delete;
+ ThreadStateSaver(ThreadStateSaver&&) = delete;
+ ThreadStateSaver &operator=(const ThreadStateSaver&) = delete;
+ ThreadStateSaver &operator=(ThreadStateSaver&&) = delete;
+
ThreadStateSaver();
~ThreadStateSaver();
void save();
void restore();
private:
PyThreadState* m_threadState;
-
- ThreadStateSaver(const ThreadStateSaver&);
- ThreadStateSaver& operator=(const ThreadStateSaver&);
};
} // namespace Shiboken
diff --git a/sources/shiboken2/libshiboken/typespec.cpp b/sources/shiboken2/libshiboken/typespec.cpp
index d532c97ed..a67daf12d 100644
--- a/sources/shiboken2/libshiboken/typespec.cpp
+++ b/sources/shiboken2/libshiboken/typespec.cpp
@@ -37,6 +37,7 @@
**
****************************************************************************/
+#include "sbkpython.h"
#include "typespec.h"
#include <structmember.h>
@@ -514,7 +515,7 @@ best_base(PyObject *bases)
}
static const short slotoffsets[] = {
- -1, /* invalid slot_ */
+ -1, /* invalid slot */
/* Generated by typeslots.py */
0,
0,
@@ -603,7 +604,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
PyObject *modname;
char *s;
char *res_start = (char*)res;
- PyType_Slot *slot_;
+ PyType_Slot *slot;
/* Set the type name and qualname */
s = (char *)strrchr(spec->name, '.'); // C++11
@@ -632,11 +633,11 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
if (!bases) {
base = &PyBaseObject_Type;
/* See whether Py_tp_base(s) was specified */
- for (slot_ = spec->slots; slot_->slot_; slot_++) {
- if (slot_->slot_ == Py_tp_base)
- base = (PyTypeObject *)slot_->pfunc; // C++11
- else if (slot_->slot_ == Py_tp_bases) {
- bases = (PyObject *)slot_->pfunc; // C++11
+ for (slot = spec->slots; slot->slot; slot++) {
+ if (slot->slot == Py_tp_base)
+ base = (PyTypeObject *)slot->pfunc; // C++11
+ else if (slot->slot == Py_tp_bases) {
+ bases = (PyObject *)slot->pfunc; // C++11
Py_INCREF(bases);
}
}
@@ -676,23 +677,23 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
type->tp_basicsize = spec->basicsize;
type->tp_itemsize = spec->itemsize;
- for (slot_ = spec->slots; slot_->slot_; slot_++) {
- if (slot_->slot_ < 0
- || (size_t)slot_->slot_ >= Py_ARRAY_LENGTH(slotoffsets)) {
- PyErr_SetString(PyExc_RuntimeError, "invalid slot_ offset");
+ for (slot = spec->slots; slot->slot; slot++) {
+ if (slot->slot < 0
+ || (size_t)slot->slot >= Py_ARRAY_LENGTH(slotoffsets)) {
+ PyErr_SetString(PyExc_RuntimeError, "invalid slot offset");
goto fail;
}
- if (slot_->slot_ == Py_tp_base || slot_->slot_ == Py_tp_bases)
+ if (slot->slot == Py_tp_base || slot->slot == Py_tp_bases)
/* Processed above */
continue;
- *(void**)(res_start + slotoffsets[slot_->slot_]) = slot_->pfunc;
+ *(void**)(res_start + slotoffsets[slot->slot]) = slot->pfunc;
- /* need to make a copy of the docstring slot_, which usually
+ /* need to make a copy of the docstring slot, which usually
points to a static string literal */
- if (slot_->slot_ == Py_tp_doc) {
+ if (slot->slot == Py_tp_doc) {
// No signature in Python 2
- // const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot_->pfunc);
- const char *old_doc = (const char *)slot_->pfunc;
+ // const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot->pfunc);
+ const char *old_doc = (const char *)slot->pfunc;
size_t len = strlen(old_doc)+1;
char *tp_doc = (char *)PyObject_MALLOC(len); // C++11
if (tp_doc == NULL) {
@@ -759,17 +760,17 @@ PyType_FromSpec(PyType_Spec *spec)
}
void *
-PyType_GetSlot(PyTypeObject *type, int slot_)
+PyType_GetSlot(PyTypeObject *type, int slot)
{
- if (!PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot_ < 0) {
+ if (!PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot < 0) {
PyErr_BadInternalCall();
return NULL;
}
- if ((size_t)slot_ >= Py_ARRAY_LENGTH(slotoffsets)) {
- /* Extension module requesting slot_ from a future version */
+ if ((size_t)slot >= Py_ARRAY_LENGTH(slotoffsets)) {
+ /* Extension module requesting slot from a future version */
return NULL;
}
- return *(void**)(((char*)type) + slotoffsets[slot_]);
+ return *(void**)(((char*)type) + slotoffsets[slot]);
}
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/typespec.h b/sources/shiboken2/libshiboken/typespec.h
index 799fcb1b8..81227acac 100644
--- a/sources/shiboken2/libshiboken/typespec.h
+++ b/sources/shiboken2/libshiboken/typespec.h
@@ -40,7 +40,7 @@
#ifndef TYPESPEC_H
#define TYPESPEC_H
-#include <Python.h>
+#include "sbkpython.h"
#include "shibokenmacros.h"
#if PY_MAJOR_VERSION < 3
@@ -48,7 +48,7 @@ extern "C"
{
typedef struct{
- int slot_; // slot is somehow reserved in Qt /* slot id, see below */
+ int slot; // slot is somehow reserved in Qt /* slot id, see below */
void *pfunc; /* function pointer */
} PyType_Slot;
diff --git a/sources/shiboken2/shiboken_tool.py b/sources/shiboken2/shiboken_tool.py
new file mode 100755
index 000000000..8494c5d57
--- /dev/null
+++ b/sources/shiboken2/shiboken_tool.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#############################################################################
+##
+## 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$
+##
+#############################################################################
+import sys
+import os
+import subprocess
+
+def main():
+ # The tools listed as entrypoints in setup.py are copied to 'scripts/..'
+ cmd = os.path.join("..", os.path.basename(sys.argv[0]))
+ command = [os.path.join(os.path.dirname(os.path.realpath(__file__)), cmd)]
+ command.extend(sys.argv[1:])
+ sys.exit(subprocess.call(command))
+
+if __name__ == "__main__":
+ main()
diff --git a/sources/shiboken2/shiboken_version.py b/sources/shiboken2/shiboken_version.py
index 789812464..a883bab96 100644
--- a/sources/shiboken2/shiboken_version.py
+++ b/sources/shiboken2/shiboken_version.py
@@ -38,16 +38,10 @@
#############################################################################
major_version = "5"
-minor_version = "11"
-patch_version = "1"
-
-# For example: "a", "b", "rc"
-# (which means "alpha", "beta", "release candidate").
-# An empty string means the generated package will be an official release.
-pre_release_version_type = "a"
-
-# For example: "1", "2" (which means "beta1", "beta2", if type is "b").
-pre_release_version = "1"
+minor_version = "12"
+patch_version = "0"
+pre_release_version_type = "a" # e.g. "a", "b", "rc".
+pre_release_version = "1" # e.g "1", "2", (which means "beta1", "beta2", if type is "b")
if __name__ == '__main__':
# Used by CMake.
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index f2d7b30f2..20baf9f7e 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -12,7 +12,9 @@ set(shibokenmodule_TYPESYSTEM
${CMAKE_CURRENT_SOURCE_DIR}/typesystem_shiboken.xml
)
-add_custom_command(OUTPUT ${sample_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${sample_SRC}
# Note: shiboken2 is an executable target. By not specifying its explicit
# path, CMAKE figures it out, itself!
# This fixes an issue with Visual Studio, see https://github.com/PySide/shiboken2/pull/11
@@ -39,5 +41,26 @@ target_link_libraries(shibokenmodule
libshiboken)
add_dependencies(shibokenmodule shiboken2)
+create_generator_target(shibokenmodule)
-install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES})
+install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}/shiboken2)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/_config.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/_config.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2")
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2")
+
+# Use absolute path instead of relative path, to avoid ninja build errors due to
+# duplicate file dependency inconsistency.
+set(shiboken_version_relative_path "${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_version.py")
+get_filename_component(shiboken_version_path ${shiboken_version_relative_path} ABSOLUTE)
+configure_file("${shiboken_version_path}"
+ "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_module_version.py" @ONLY)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_module_version.py"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2")
diff --git a/sources/shiboken2/shibokenmodule/__init__.py.in b/sources/shiboken2/shibokenmodule/__init__.py.in
new file mode 100644
index 000000000..81ab0063a
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/__init__.py.in
@@ -0,0 +1,4 @@
+__version__ = "@FINAL_PACKAGE_VERSION@"
+__version_info__ = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
+
+from .shiboken2 import *
diff --git a/sources/shiboken2/shibokenmodule/_config.py.in b/sources/shiboken2/shibokenmodule/_config.py.in
new file mode 100644
index 000000000..9607e5ca7
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/_config.py.in
@@ -0,0 +1,11 @@
+shiboken_library_soversion = str(@shiboken2_library_so_version@)
+
+version = "@FINAL_PACKAGE_VERSION@"
+version_info = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
+
+@PACKAGE_BUILD_DATE@
+@PACKAGE_BUILD_COMMIT_DATE@
+@PACKAGE_BUILD_COMMIT_HASH@
+@PACKAGE_BUILD_COMMIT_HASH_DESCRIBED@
+@PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
+@PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT@
diff --git a/sources/shiboken2/tests/libsample/CMakeLists.txt b/sources/shiboken2/tests/libsample/CMakeLists.txt
index 7bbc0c3dd..ae3d40312 100644
--- a/sources/shiboken2/tests/libsample/CMakeLists.txt
+++ b/sources/shiboken2/tests/libsample/CMakeLists.txt
@@ -10,6 +10,7 @@ complex.cpp
onlycopy.cpp
derived.cpp
echo.cpp
+exceptiontest.cpp
functions.cpp
handle.cpp
implicitconv.cpp
diff --git a/sources/shiboken2/tests/libsample/exceptiontest.cpp b/sources/shiboken2/tests/libsample/exceptiontest.cpp
new file mode 100644
index 000000000..1302a8e43
--- /dev/null
+++ b/sources/shiboken2/tests/libsample/exceptiontest.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "exceptiontest.h"
+
+class TestException : public std::exception
+{
+public:
+ const char *what() const noexcept override
+ { return "TestException"; }
+};
+
+ExceptionTest::ExceptionTest() = default;
+
+int ExceptionTest::intThrowStdException(bool doThrow)
+{
+ if (doThrow)
+ throw TestException();
+ return 1;
+}
+
+void ExceptionTest::voidThrowStdException(bool doThrow)
+{
+ if (doThrow)
+ throw TestException();
+}
+
+int ExceptionTest::intThrowInt(bool doThrow)
+{
+ if (doThrow)
+ throw 42;
+ return 1;
+}
+
+void ExceptionTest::voidThrowInt(bool doThrow)
+{
+ if (doThrow)
+ throw 42;
+}
diff --git a/sources/shiboken2/tests/libsample/exceptiontest.h b/sources/shiboken2/tests/libsample/exceptiontest.h
new file mode 100644
index 000000000..8ab3e2b67
--- /dev/null
+++ b/sources/shiboken2/tests/libsample/exceptiontest.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EXCEPTIONTEST_H
+#define EXCEPTIONTEST_H
+
+#include "libsamplemacros.h"
+
+#include <exception>
+
+class LIBSAMPLE_API ExceptionTest
+{
+ public:
+ ExceptionTest();
+
+ int intThrowStdException(bool doThrow);
+ void voidThrowStdException(bool doThrow);
+
+ int intThrowInt(bool doThrow);
+ void voidThrowInt(bool doThrow);
+};
+
+#endif // EXCEPTIONTEST_H
diff --git a/sources/shiboken2/tests/libsample/mapuser.cpp b/sources/shiboken2/tests/libsample/mapuser.cpp
index 1dbd02d26..89a835af8 100644
--- a/sources/shiboken2/tests/libsample/mapuser.cpp
+++ b/sources/shiboken2/tests/libsample/mapuser.cpp
@@ -67,3 +67,8 @@ MapUser::showMap(std::map<std::string, int> mapping)
cout << (*it).first << " => " << (*it).second << endl;
}
+std::map<int, std::list<std::list<double> > > MapUser::foo() const
+{
+ std::map<int, std::list<std::list<double> > > result;
+ return result;
+}
diff --git a/sources/shiboken2/tests/libsample/mapuser.h b/sources/shiboken2/tests/libsample/mapuser.h
index 9677d2df2..ad434b957 100644
--- a/sources/shiboken2/tests/libsample/mapuser.h
+++ b/sources/shiboken2/tests/libsample/mapuser.h
@@ -58,6 +58,8 @@ public:
inline const std::map<int, ByteArray>& passMapIntValueType(const std::map<int, ByteArray>& arg) { return arg; }
+ std::map<int, std::list<std::list<double> > > foo() const;
+
private:
std::map<std::string, std::list<int> > m_map;
};
diff --git a/sources/shiboken2/tests/libsample/nontypetemplate.h b/sources/shiboken2/tests/libsample/nontypetemplate.h
new file mode 100644
index 000000000..4e2100626
--- /dev/null
+++ b/sources/shiboken2/tests/libsample/nontypetemplate.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NONTYPETEMPLATE_H
+#define NONTYPETEMPLATE_H
+
+#include "libsamplemacros.h"
+
+#include <algorithm>
+#include <numeric>
+
+template <int Size> class IntArray
+{
+public:
+ explicit IntArray(int v) { std::fill(m_array, m_array + Size, v); }
+
+ int sum() const { return std::accumulate(m_array, m_array + Size, int(0)); }
+
+private:
+ int m_array[Size];
+};
+
+typedef IntArray<2> IntArray2;
+typedef IntArray<3> IntArray3;
+
+#endif // NONTYPETEMPLATE_H
diff --git a/sources/shiboken2/tests/libsample/objecttype.cpp b/sources/shiboken2/tests/libsample/objecttype.cpp
index e09a92f47..f82b7cf0d 100644
--- a/sources/shiboken2/tests/libsample/objecttype.cpp
+++ b/sources/shiboken2/tests/libsample/objecttype.cpp
@@ -282,6 +282,7 @@ void ObjectType::callVirtualCreateChild()
ObjectType* fake_parent = new ObjectType();
ObjectType* fake_child = createChild(fake_parent);
assert(fake_child->isPython());
+ (void)fake_child;
delete fake_parent;
}
diff --git a/sources/shiboken2/tests/libsample/objecttype.h b/sources/shiboken2/tests/libsample/objecttype.h
index bcb4f3332..ecd67b684 100644
--- a/sources/shiboken2/tests/libsample/objecttype.h
+++ b/sources/shiboken2/tests/libsample/objecttype.h
@@ -63,7 +63,7 @@ private:
class ObjectTypeLayout;
class ObjectType;
-typedef std::list<ObjectType*> ObjectTypeList;
+using ObjectTypeList = std::list<ObjectType*>;
class LIBSAMPLE_API ObjectType
{
diff --git a/sources/shiboken2/tests/libsample/samplenamespace.cpp b/sources/shiboken2/tests/libsample/samplenamespace.cpp
index ec3da3dbf..e066869d2 100644
--- a/sources/shiboken2/tests/libsample/samplenamespace.cpp
+++ b/sources/shiboken2/tests/libsample/samplenamespace.cpp
@@ -36,6 +36,13 @@ using namespace std;
namespace SampleNamespace
{
+// PYSIDE-817, scoped enums must not be converted to int in the wrappers generated
+// for the protected hacks
+SomeClass::PublicScopedEnum SomeClass::protectedMethodReturningPublicScopedEnum() const
+{
+ return PublicScopedEnum::v1;
+}
+
OutValue
enumInEnumOut(InValue in)
{
diff --git a/sources/shiboken2/tests/libsample/samplenamespace.h b/sources/shiboken2/tests/libsample/samplenamespace.h
index 37a445e51..27fa11290 100644
--- a/sources/shiboken2/tests/libsample/samplenamespace.h
+++ b/sources/shiboken2/tests/libsample/samplenamespace.h
@@ -96,9 +96,11 @@ LIBSAMPLE_API void doSomethingWithArray(const unsigned char* data, unsigned int
LIBSAMPLE_API int enumItemAsDefaultValueToIntArgument(int value = ZeroIn);
-class SomeClass
+class LIBSAMPLE_API SomeClass
{
public:
+ enum class PublicScopedEnum { v1, v2 };
+
class SomeInnerClass
{
public:
@@ -131,6 +133,8 @@ protected:
ProtectedItem0,
ProtectedItem1
};
+
+ PublicScopedEnum protectedMethodReturningPublicScopedEnum() const;
};
class DerivedFromNamespace : public SomeClass::SomeInnerClass::OkThisIsRecursiveEnough
diff --git a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt
index b8b6417d1..ec674b56b 100644
--- a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt
@@ -15,7 +15,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/minimal/minbooluser_wrapper.cpp
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/minimal-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt" @ONLY)
-add_custom_command(OUTPUT ${minimal_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${minimal_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${minimal_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -38,3 +40,4 @@ target_link_libraries(minimal
libminimal
${SBK_PYTHON_LIBRARIES}
libshiboken)
+create_generator_target(minimal)
diff --git a/sources/shiboken2/tests/otherbinding/CMakeLists.txt b/sources/shiboken2/tests/otherbinding/CMakeLists.txt
index 186766b41..0be66f797 100644
--- a/sources/shiboken2/tests/otherbinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/otherbinding/CMakeLists.txt
@@ -17,7 +17,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/other/other_module_wrapper.cpp
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/other-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt" @ONLY)
-add_custom_command(OUTPUT ${other_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${other_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${other_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -48,4 +50,5 @@ target_link_libraries(other
libshiboken)
add_dependencies(other sample)
+create_generator_target(other)
diff --git a/sources/shiboken2/tests/samplebinding/CMakeLists.txt b/sources/shiboken2/tests/samplebinding/CMakeLists.txt
index 32117e44a..7f4bec5f4 100644
--- a/sources/shiboken2/tests/samplebinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/samplebinding/CMakeLists.txt
@@ -29,11 +29,14 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/derived_someinnerclass_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/echo_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/event_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/expression_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/exceptiontest_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/friendofonlycopy_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/handleholder_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/implicitconv_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/implicitbase_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/implicittarget_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/intarray2_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/intarray3_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/intlist_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/sortedoverload_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/intwrapper_wrapper.cpp
@@ -125,7 +128,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/union_wrapper.cpp
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sample-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt" @ONLY)
-add_custom_command(OUTPUT ${sample_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${sample_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${sample_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -149,3 +154,4 @@ target_link_libraries(sample
libsample
${SBK_PYTHON_LIBRARIES}
libshiboken)
+create_generator_target(sample)
diff --git a/sources/shiboken2/tests/samplebinding/exception_test.py b/sources/shiboken2/tests/samplebinding/exception_test.py
new file mode 100644
index 000000000..d6c02433a
--- /dev/null
+++ b/sources/shiboken2/tests/samplebinding/exception_test.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+#
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import unittest
+
+from sample import ExceptionTest
+
+class CppExceptionTest(unittest.TestCase):
+
+ def testVoid(self):
+ exceptionCount = 0
+ et = ExceptionTest()
+
+ et.voidThrowStdException(False)
+
+ try:
+ et.voidThrowStdException(True)
+ except:
+ exceptionCount += 1
+
+ et.voidThrowInt(False)
+
+ try:
+ et.voidThrowInt(True)
+ except:
+ exceptionCount += 1
+
+ self.assertEqual(exceptionCount, 2)
+
+ def testReturnValue(self):
+ exceptionCount = 0
+ et = ExceptionTest()
+
+ result = et.intThrowStdException(False);
+
+ try:
+ result = et.intThrowStdException(True);
+ except:
+ exceptionCount += 1
+
+ result = et.intThrowInt(False);
+
+ try:
+ result = et.intThrowInt(True);
+ except:
+ exceptionCount += 1
+
+ self.assertEqual(exceptionCount, 2)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken2/tests/samplebinding/global.h b/sources/shiboken2/tests/samplebinding/global.h
index f2add93ff..3984102a8 100644
--- a/sources/shiboken2/tests/samplebinding/global.h
+++ b/sources/shiboken2/tests/samplebinding/global.h
@@ -37,8 +37,10 @@
#include "sbkdate.h"
#include "derived.h"
#include "echo.h"
+#include "exceptiontest.h"
#include "functions.h"
#include "implicitconv.h"
+#include "nontypetemplate.h"
#include "overloadsort.h"
#include "handle.h"
#include "injectcode.h"
diff --git a/sources/shiboken2/tests/samplebinding/nontypetemplate_test.py b/sources/shiboken2/tests/samplebinding/nontypetemplate_test.py
new file mode 100644
index 000000000..9adfa2441
--- /dev/null
+++ b/sources/shiboken2/tests/samplebinding/nontypetemplate_test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#
+#############################################################################
+##
+## Copyright (C) 2018 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import unittest
+
+from sample import IntArray2, IntArray3
+
+class NonTypeTemplateTest(unittest.TestCase):
+
+ def testNonTypeTemplate(self):
+ array2 = IntArray2(3)
+ self.assertEqual(array2.sum(), 6)
+ array3 = IntArray3(5)
+ self.assertEqual(array3.sum(), 15)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
index 00052e881..9b967fc53 100644
--- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
+++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml
@@ -520,6 +520,10 @@
<suppress-warning text="skipping function 'ClassWithFunctionPointer::callFunctionPointer', unmatched parameter type 'void (*)(void*)'" />
</value-type>
+ <value-type name="IntArray" generate="no"/>
+ <value-type name="IntArray2"/>
+ <value-type name="IntArray3"/>
+
<enum-type name="OverloadedFuncEnum"/>
<!-- BUG:
renaming the ICOverloadedFuncEnum to the same name
@@ -545,6 +549,7 @@
<enum-type name="SampleNamespace"/>
</object-type>
<value-type name="SomeClass">
+ <enum-type name="PublicScopedEnum"/>
<value-type name="SomeInnerClass">
<object-type name="OkThisIsRecursiveEnough">
<enum-type name="NiceEnum" />
@@ -1964,7 +1969,7 @@
<define-ownership owner="c++"/>
</modify-argument>
</modify-function>
- <modify-function signature="acceptSequence(const char*[])">
+ <modify-function signature="acceptSequence(const char*const[])">
<modify-argument index="1">
<replace-type modified-type="PySequence" />
<conversion-rule class="native">
@@ -2388,6 +2393,8 @@
<value-type name="Expression" />
+ <object-type name="ExceptionTest" exception-handling="auto-on"/>
+
<value-type name="ModelIndex" />
<value-type name="ReferentModelIndex">
<modify-function signature="operator const ModelIndex&amp;()const">
diff --git a/sources/shiboken2/tests/smartbinding/CMakeLists.txt b/sources/shiboken2/tests/smartbinding/CMakeLists.txt
index faaa797b6..43888fae2 100644
--- a/sources/shiboken2/tests/smartbinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/smartbinding/CMakeLists.txt
@@ -16,7 +16,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/smart/registry_wrapper.cpp
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/smart-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt" @ONLY)
-add_custom_command(OUTPUT ${smart_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${smart_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${smart_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -40,3 +42,4 @@ target_link_libraries(smart
libsmart
${SBK_PYTHON_LIBRARIES}
libshiboken)
+create_generator_target(smart)