diff options
Diffstat (limited to 'sources/shiboken2')
49 files changed, 3406 insertions, 2538 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 84c116708..4aa5d72dd 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -241,7 +241,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 +256,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 +269,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 +283,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 +348,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item setupFunctionDefaults(metaFunction, baseoperandClass); baseoperandClass->addFunction(metaFunction); Q_ASSERT(!metaFunction->wasPrivate()); - } else if (metaFunction) { + } else { delete metaFunction; } @@ -356,7 +356,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 +404,7 @@ void AbstractMetaBuilderPrivate::traverseStreamOperator(FunctionModelItem item) funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include()); m_currentClass = oldCurrentClass; - } else if (streamFunction) { + } else { delete streamFunction; } @@ -422,7 +422,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); } } @@ -616,7 +616,7 @@ 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; @@ -848,7 +848,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 +857,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()); @@ -1014,7 +1014,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 @@ -1204,18 +1204,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 +1272,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 +1327,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 +1420,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 +1629,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,10 +1718,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); + metaArg->setDefaultValueExpression(replacedExpression); + metaArg->setOriginalDefaultValueExpression(replacedExpression); if (metaArg->type()->isEnum() || metaArg->type()->isFlags()) m_enumDefaultArguments << QPair<AbstractMetaArgument*, AbstractMetaFunction*>(metaArg, metaFunction); @@ -1784,7 +1777,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(); @@ -1803,7 +1796,8 @@ static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem return result; } -static inline QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n) +static inline QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n, + const QString &why) { QString result; QTextStream str(&result); @@ -1811,23 +1805,16 @@ static inline QString msgUnmatchedParameterType(const ArgumentModelItem &arg, in << (n + 1); if (!arg->name().isEmpty()) str << " \"" << arg->name() << '"'; + str << ": " << why; return result; } -static inline QString msgUnmatchedReturnType(const FunctionModelItem &functionItem) +static inline QString msgUnmatchedReturnType(const FunctionModelItem &functionItem, + const QString &why) { 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; + + functionItem->type().toString() + + QLatin1String("': ") + why; } static QString msgSkippingFunction(const FunctionModelItem &functionItem, @@ -1911,7 +1898,7 @@ bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func return true; } -AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModelItem functionItem) +AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem) { if (functionItem->isDeleted() || !functionItem->templateParameters().isEmpty()) 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; @@ -1987,6 +1977,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel else *metaFunction += AbstractMetaAttributes::Protected; + QString errorMessage; switch (metaFunction->functionType()) { case AbstractMetaFunction::DestructorFunction: break; @@ -2005,9 +1996,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 +2024,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 +2032,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 +2049,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 @@ -2091,7 +2071,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel // 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 @@ -2211,15 +2191,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,51 +2225,83 @@ 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(); } return type; } +static QString msgUnableToTranslateType(const QString &t, const QString &why) +{ + return QLatin1String("Unable to translate type \"") + + t + QLatin1String("\": ") + why; +} + +static inline QString msgUnableToTranslateType(const TypeInfo &typeInfo, + const QString &why) +{ + return msgUnableToTranslateType(typeInfo.toString(), why); +} + +static inline QString msgCannotFindTypeEntry(const QString &t) +{ + return QLatin1String("Cannot find type entry for \"") + t + QLatin1String("\"."); +} + +static inline 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; +} + 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 +2326,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 +2349,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 +2366,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 +2378,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 +2415,44 @@ 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; + if (d) + d->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 +2469,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 +2534,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, @@ -2728,7 +2790,7 @@ 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()) { @@ -2764,13 +2826,13 @@ 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."; + << info.toString() << ", because I don't know what it is."; } } @@ -2827,13 +2889,9 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, // 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; - } - } + const bool found = + std::any_of(funcs.cbegin(), funcs.cend(), + [f] (const AbstractMetaFunction *needle) { return needle->name() == f->name(); }); if (found) { delete f; continue; @@ -2878,9 +2936,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(); diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h index a0ca71b94..bea2ac4c0 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h @@ -38,7 +38,9 @@ QT_FORWARD_DECLARE_CLASS(QIODevice) class AbstractMetaBuilderPrivate; class AbstractMetaClass; +class AbstractMetaType; class AbstractMetaEnumValue; +class TypeInfo; class AbstractMetaBuilder { @@ -83,6 +85,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..7f4d222a3 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h @@ -60,7 +60,7 @@ public: ScopeModelItem currentScope() const { return m_scopes.constLast(); } - AbstractMetaClass *argumentToClass(ArgumentModelItem); + AbstractMetaClass *argumentToClass(const ArgumentModelItem &); void addAbstractMetaClass(AbstractMetaClass *cls); AbstractMetaClass *traverseTypeDef(const FileModelItem &dom, @@ -74,9 +74,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 +85,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 +118,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, diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index 5be7050bf..de7182c71 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -31,6 +31,8 @@ #include "typedatabase.h" #include "typesystem.h" +#include <parser/codemodel.h> + #ifndef QT_NO_DEBUG_STREAM # include <QtCore/QMetaEnum> # include <QtCore/QMetaObject> @@ -112,8 +114,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 +157,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 +281,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 +314,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'; @@ -504,18 +543,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 @@ -809,8 +847,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 +912,14 @@ 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) +bool AbstractMetaFunction::isOperatorOverload(const QString& funcName) { if (isConversionOperator(funcName)) return true; @@ -1723,7 +1762,7 @@ QDebug operator<<(QDebug d, const AbstractMetaEnum *ae) bool AbstractMetaClass::hasConstructors() const { - return queryFunctions(Constructors).size(); + return !queryFunctions(Constructors).isEmpty(); } bool AbstractMetaClass::hasCopyConstructor() const @@ -2002,8 +2041,8 @@ void AbstractMetaClass::fixFunctions() { if (m_functionsFixed) return; - else - m_functionsFixed = true; + + m_functionsFixed = true; AbstractMetaClass *superClass = baseClass(); AbstractMetaFunctionList funcs = functions(); @@ -2046,8 +2085,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 +2152,8 @@ void AbstractMetaClass::fixFunctions() if (mod.isNonFinal()) { hasNonFinalModifier = true; break; - } else if (mod.isPrivate()) { + } + if (mod.isPrivate()) { isBaseImplPrivate = true; break; } @@ -2222,6 +2261,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 +2286,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; @@ -2406,6 +2447,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..d84a82af3 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 @@ -816,13 +834,13 @@ public: return m_explicit; } - static bool isConversionOperator(QString funcName); + static bool isConversionOperator(const QString& funcName); bool isConversionOperator() const { return isConversionOperator(originalName()); } - static bool isOperatorOverload(QString funcName); + static bool isOperatorOverload(const QString& funcName); bool isOperatorOverload() const { return isOperatorOverload(originalName()); diff --git a/sources/shiboken2/ApiExtractor/apiextractor.cpp b/sources/shiboken2/ApiExtractor/apiextractor.cpp index 171011cd4..80ffc3910 100644 --- a/sources/shiboken2/ApiExtractor/apiextractor.cpp +++ b/sources/shiboken2/ApiExtractor/apiextractor.cpp @@ -194,9 +194,9 @@ const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const TypeEntry* type if (!typeEntry) return 0; if (typeEntry->isFlags()) - return findAbstractMetaEnum(reinterpret_cast<const FlagsTypeEntry*>(typeEntry)); + return findAbstractMetaEnum(static_cast<const FlagsTypeEntry*>(typeEntry)); if (typeEntry->isEnum()) - return findAbstractMetaEnum(reinterpret_cast<const EnumTypeEntry*>(typeEntry)); + return findAbstractMetaEnum(static_cast<const EnumTypeEntry*>(typeEntry)); return 0; } diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp index af7f96068..1623e6a6e 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,14 @@ 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; TemplateParameterModelItem createTemplateParameter(const CXCursor &cursor) const; TemplateParameterModelItem createNonTypeTemplateParameter(const CXCursor &cursor) const; @@ -205,6 +211,8 @@ public: CursorClassHash m_cursorClassHash; CursorTypedefHash m_cursorTypedefHash; + mutable TypeInfoHash m_typeInfoHash; // Cache type information + ClassModelItem m_currentClass; EnumModelItem m_currentEnum; FunctionModelItem m_currentFunction; @@ -256,7 +264,7 @@ 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); @@ -335,7 +343,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 +367,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 +388,132 @@ 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); - } - // "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)); + 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()); } - 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::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.setConstant(isConstant); + typeInfo.setIndirectionsV(indirections); - // clang_isVolatileQualifiedType() returns true for "volatile int", but not for "volatile int *" - if (typeName.startsWith(QLatin1String("volatile "))) { - typeName.remove(0, 9); - typeInfo.setVolatile(true); + typeInfo.setConstant(clang_isConstQualifiedType(nestedType) != 0); + typeInfo.setVolatile(clang_isVolatileQualifiedType(nestedType) != 0); + + 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? 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(); +} + // 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 +832,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. 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_specifying_types.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst index 322f9bca6..c5f6463fd 100644 --- a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst @@ -348,6 +348,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..ce089c1f5 100644 --- a/sources/shiboken2/ApiExtractor/docparser.cpp +++ b/sources/shiboken2/ApiExtractor/docparser.cpp @@ -50,9 +50,7 @@ DocParser::DocParser() #endif } -DocParser::~DocParser() -{ -} +DocParser::~DocParser() = default; QString DocParser::getDocumentation(QXmlQuery& xquery, const QString& query, const DocModificationList& mods) const @@ -154,13 +152,16 @@ QString DocParser::msgCannotFindDocumentation(const QString &fileName, 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() { diff --git a/sources/shiboken2/ApiExtractor/doxygenparser.cpp b/sources/shiboken2/ApiExtractor/doxygenparser.cpp index dfdb37a47..7a0346cc6 100644 --- a/sources/shiboken2/ApiExtractor/doxygenparser.cpp +++ b/sources/shiboken2/ApiExtractor/doxygenparser.cpp @@ -35,23 +35,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() @@ -77,9 +71,9 @@ void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass) 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..522c98fb5 100644 --- a/sources/shiboken2/ApiExtractor/fileout.cpp +++ b/sources/shiboken2/ApiExtractor/fileout.cpp @@ -50,24 +50,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 +90,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; + } + 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; } - delete(res); + 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() { diff --git a/sources/shiboken2/ApiExtractor/fileout.h b/sources/shiboken2/ApiExtractor/fileout.h index 539ae7a43..ed995425d 100644 --- a/sources/shiboken2/ApiExtractor/fileout.h +++ b/sources/shiboken2/ApiExtractor/fileout.h @@ -43,12 +43,8 @@ private: public: enum State { Failure, Unchanged, Success }; - FileOut(QString name); - ~FileOut() - { - if (!isDone) - done(); - } + explicit FileOut(QString name); + ~FileOut(); State done(); State done(QString *errorMessage); 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/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp index d862692dd..2c8042dc0 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,41 @@ 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; } #ifndef QT_NO_DEBUG_STREAM @@ -292,8 +375,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 +390,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 +449,7 @@ _CodeModelItem::_CodeModelItem(CodeModel *model, const QString &name, int kind) { } -_CodeModelItem::~_CodeModelItem() -{ -} +_CodeModelItem::~_CodeModelItem() = default; int _CodeModelItem::kind() const { @@ -532,9 +621,7 @@ QDebug operator<<(QDebug d, const _CodeModelItem *t) #endif // !QT_NO_DEBUG_STREAM // --------------------------------------------------------------------------- -_ClassModelItem::~_ClassModelItem() -{ -} +_ClassModelItem::~_ClassModelItem() = default; TemplateParameterList _ClassModelItem::templateParameters() const { @@ -624,9 +711,7 @@ FunctionModelItem _ScopeModelItem::declaredFunction(FunctionModelItem item) return FunctionModelItem(); } -_ScopeModelItem::~_ScopeModelItem() -{ -} +_ScopeModelItem::~_ScopeModelItem() = default; void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration) { @@ -835,11 +920,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 +954,7 @@ ArgumentList _FunctionModelItem::arguments() const return m_arguments; } -void _FunctionModelItem::addArgument(ArgumentModelItem item) +void _FunctionModelItem::addArgument(const ArgumentModelItem& item) { m_arguments.append(item); } @@ -1091,9 +1174,7 @@ void _EnumModelItem::formatDebug(QDebug &d) const #endif // !QT_NO_DEBUG_STREAM // --------------------------------------------------------------------------- -_EnumeratorModelItem::~_EnumeratorModelItem() -{ -} +_EnumeratorModelItem::~_EnumeratorModelItem() = default; QString _EnumeratorModelItem::stringValue() const { @@ -1114,9 +1195,7 @@ void _EnumeratorModelItem::formatDebug(QDebug &d) const #endif // !QT_NO_DEBUG_STREAM // --------------------------------------------------------------------------- -_TemplateParameterModelItem::~_TemplateParameterModelItem() -{ -} +_TemplateParameterModelItem::~_TemplateParameterModelItem() = default; TypeInfo _TemplateParameterModelItem::type() const { @@ -1164,9 +1243,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..a2cbcd6c0 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,13 @@ 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(); } + + QPair<int, int> parseTemplateArgumentList(const QString &l, int from = 0); + bool operator==(const TypeInfo &other) const; bool operator!=(const TypeInfo &other) const @@ -185,8 +199,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 +206,22 @@ 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); + 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 +230,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 +568,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 +603,7 @@ public: bool isVariadics() const; void setVariadics(bool isVariadics); - bool isSimilar(FunctionModelItem other) const; + bool isSimilar(const FunctionModelItem &other) const; #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h index b8a10ba93..9a3cc0e07 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h +++ b/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h @@ -41,4 +41,10 @@ enum EnumKind { EnumClass // C++ 11 : enum class Foo { value1, value2 } }; +enum class Indirection +{ + Pointer, // int * + ConstPointer // int *const +}; + #endif // CODEMODEL_ENUMS_H diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp index 7f1361a7d..86bf64495 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() { 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/testtyperevision.cpp b/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp index 1ec7ce025..a3130e499 100644 --- a/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp @@ -49,21 +49,22 @@ 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); } QTEST_APPLESS_MAIN(TestTypeRevision) diff --git a/sources/shiboken2/ApiExtractor/tests/testutil.h b/sources/shiboken2/ApiExtractor/tests/testutil.h index 6152793f5..dea6d92d8 100644 --- a/sources/shiboken2/ApiExtractor/tests/testutil.h +++ b/sources/shiboken2/ApiExtractor/tests/testutil.h @@ -53,7 +53,8 @@ namespace TestUtil 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..6372a8715 100644 --- a/sources/shiboken2/ApiExtractor/typedatabase.cpp +++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp @@ -263,6 +263,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; } @@ -518,7 +520,10 @@ 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 @@ -574,28 +579,15 @@ 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) -{ - return typeEntryFields()->value(typeEntry).first; -} - -void setTypeRevision(TypeEntry* typeEntry, int revision) +static bool typeEntryLessThan(const TypeEntry* t1, const TypeEntry* t2) { - (*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() @@ -604,8 +596,11 @@ static void _computeTypeIndexes() typedef QMap<int, TypeEntryList> GroupedTypeEntries; GroupedTypeEntries groupedEntries; + TypeEntryList list; + // Group type entries by revision numbers const TypeEntryHash &allEntries = tdb->allEntries(); + list.reserve(allEntries.size()); for (TypeEntryHash::const_iterator tit = allEntries.cbegin(), end = allEntries.cend(); tit != end; ++tit) { for (TypeEntry *entry : tit.value()) { if (entry->isPrimitive() @@ -618,31 +613,33 @@ static void _computeTypeIndexes() || entry->isVoid() || entry->isCustom()) continue; - groupedEntries[getTypeRevision(entry)] << entry; + 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() @@ -684,33 +681,95 @@ 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("preferredConversion", m_preferredConversion) + 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) + if (m_typeFlags != 0) + d << ", typeFlags=" << m_typeFlags; + d << ", copyableFlag=" << m_copyableFlag; + FORMAT_NONEMPTY_STRING("defaultSuperclass", m_defaultSuperclass) + FORMAT_NONEMPTY_STRING("polymorphicIdValue", m_polymorphicIdValue) + FORMAT_NONEMPTY_STRING("held", m_heldTypeValue) + 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 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) + FORMAT_NONEMPTY_STRING("lowerBound", m_lowerBound) + FORMAT_NONEMPTY_STRING("lupperBound", m_upperBound) + FORMAT_BOOL("extensible", m_extensible) + FORMAT_BOOL("forceInteger", m_forceInteger) + if (m_flags) + d << ", flags=(" << m_flags << ')'; +} + 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; } diff --git a/sources/shiboken2/ApiExtractor/typedatabase.h b/sources/shiboken2/ApiExtractor/typedatabase.h index 2e7b009c2..3664d76b7 100644 --- a/sources/shiboken2/ApiExtractor/typedatabase.h +++ b/sources/shiboken2/ApiExtractor/typedatabase.h @@ -54,9 +54,6 @@ 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; 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 baaec6d30..70563286c 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -35,29 +35,62 @@ #include <QtCore/QFileInfo> #include <QtCore/QRegularExpression> #include <QtCore/QSet> +#include <QtCore/QStringView> +#include <QtCore/QStringAlgorithms> #include <QtCore/QXmlStreamAttributes> #include <QtCore/QXmlStreamReader> +#include <algorithm> + 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 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 staticAttribute() { return QStringLiteral("static"); } +static inline QString threadAttribute() { return QStringLiteral("thread"); } +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,49 +123,258 @@ static bool setRejectionRegularExpression(const QString &patternIn, return true; } -static bool addRejection(TypeDatabase *database, const QHash<QString, QString> &attributes, - QString *errorMessage) +template <class EnumType, Qt::CaseSensitivity cs = Qt::CaseInsensitive> +struct EnumLookup { - typedef QPair<QString, TypeRejection::MatchType> AttributeMatchTypePair; + QStringView name; + EnumType value; +}; - TypeRejection rejection; +template <class EnumType, Qt::CaseSensitivity cs> +bool operator==(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2) +{ +#ifdef QTBUG_69389_FIXED + return e1.name.compare(e2.name, cs) == 0; +#else + return QtPrivate::compareStrings(e1.name, e2.name, cs) == 0; +#endif +} - const QString className = attributes.value(classAttribute()); - if (!setRejectionRegularExpression(className, &rejection.className, errorMessage)) - return false; +template <class EnumType, Qt::CaseSensitivity cs> +bool operator<(const EnumLookup<EnumType, cs> &e1, const EnumLookup<EnumType, cs> &e2) +{ +#ifdef QTBUG_69389_FIXED + return e1.name.compare(e2.name, cs) < 0; +#else + return QtPrivate::compareStrings(e1.name, e2.name, cs) < 0; +#endif +} - static const AttributeMatchTypePair attributeMatchTypeMapping[] = - {{functionNameAttribute(), TypeRejection::Function}, - {fieldNameAttribute(), TypeRejection::Field}, - {enumNameAttribute(), TypeRejection::Enum}, - {argumentTypeAttribute(), TypeRejection::ArgumentType}, - {returnTypeAttribute(), TypeRejection::ReturnType} +// 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; \ +} + +#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::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() - // 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::Ownership, Qt::CaseInsensitive, + ownershipFromFromAttribute, TypeSystem::InvalidOwnership) + { + {QStringViewLiteral("target"), TypeSystem::TargetLangOwnership}, + {QStringViewLiteral("c++"), TypeSystem::CppOwnership}, + {QStringViewLiteral("default"), TypeSystem::DefaultOwnership} + }; +ENUM_LOOKUP_LINEAR_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(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(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("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."); +} + +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).qualifiedName() << "=\"" << attributes.at(i).value() << '"'; + } + return result; +} Handler::Handler(TypeDatabase* database, bool generate) : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass) @@ -142,53 +384,6 @@ Handler::Handler(TypeDatabase* database, bool generate) 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); } static QString readerFileName(const QXmlStreamReader &reader) @@ -197,22 +392,31 @@ 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 msgReaderMessage(reader, "Warning", what); +} + +static QString msgReaderError(const QXmlStreamReader &reader, const QString &what) { - return msgReaderError(reader, reader.errorString()); + return msgReaderMessage(reader, "Error", what); } static QString msgInvalidVersion(const QStringRef &version, const QString &package = QString()) @@ -226,6 +430,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 +489,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 +522,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) { @@ -551,8 +786,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 +797,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 +870,1354 @@ 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 &, + 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()) { + const bool v = convertBoolean(attributes->takeAt(i).value(), + preferredConversionAttribute(), true); + type->setPreferredConversion(v); + } 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")) { + entry->setUpperBound(attributes->takeAt(i).value().toString()); + } else if (name == QLatin1String("lower-bound")) { + entry->setLowerBound(attributes->takeAt(i).value().toString()); + } else if (name == forceIntegerAttribute()) { + const bool v = convertBoolean(attributes->takeAt(i).value(), + forceIntegerAttribute(), false); + entry->setForceInteger(v); + } else if (name == extensibleAttribute()) { + const bool v = convertBoolean(attributes->takeAt(i).value(), + extensibleAttribute(), false); + entry->setExtensible(v); + } 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; +} + +void Handler::applyComplexTypeAttributes(const QXmlStreamReader &, + ComplexTypeEntry *ctype, + QXmlStreamAttributes *attributes) const +{ + bool generate = true; + ctype->setCopyable(ComplexTypeEntry::Unknown); + + 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()) { + 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 == QLatin1String("held-type")) { + ctype->setHeldType(attributes->takeAt(i).value().toString()); + } else if (name == QLatin1String("hash-function")) { + ctype->setHashFunction(attributes->takeAt(i).value().toString()); + } else if (name == forceAbstractAttribute()) { + if (convertBoolean(attributes->takeAt(i).value(), forceAbstractAttribute(), false)) + ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract); + } else if (name == deprecatedAttribute()) { + if (convertBoolean(attributes->takeAt(i).value(), deprecatedAttribute(), false)) + ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated); + } else if (name == deleteInMainThreadAttribute()) { + if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute(), false)) + ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DeleteInMainThread); + } else if (name == QLatin1String("target-type")) { + ctype->setTargetType(attributes->takeAt(i).value().toString()); + } + } + + // 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; +} + +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(); + } + + TypeSystemTypeEntry* moduleEntry = + reinterpret_cast<TypeSystemTypeEntry*>(m_database->findType(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; + 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(); + } + } + + 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)) { + 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(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 &, + 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) { + if (lastArgMod.index == 0) { + lastArgMod.nullPointerDefaultValue = + attributes->takeAt(defaultValueIndex).value().toString(); + } else { + qCWarning(lcShiboken) + << "default values for null pointer guards are only effective for return values"; + } + } + 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::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 &, + 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 (mod) + mod->modifiers |= modifierFlag; + return true; +} + +bool Handler::parseModifyField(const QXmlStreamReader &, + 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()) { + if (!convertBoolean(attributes->takeAt(i).value(), readAttribute(), true)) + fm.modifiers &= ~FieldModification::Readable; + } else if (name == writeAttribute()) { + 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 &, + 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; + bool allowThread = false; + bool virtualSlot = false; + 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(); + } 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()) { + allowThread = convertBoolean(attributes->takeAt(i).value(), + allowThreadAttribute(), false); + } else if (name == virtualSlotAttribute()) { + virtualSlot = convertBoolean(attributes->takeAt(i).value(), + virtualSlotAttribute(), false); + } + } + + 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); + 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; + } + 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); + mod.setAllowThread(allowThread); + if (virtualSlot) + mod.modifiers |= Modification::VirtualSlot; + + 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 &, + 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 QStringRef action = attributes->takeAt(i).value(); + rc.action = referenceCountFromAttribute(action); + if (rc.action == ReferenceCount::Invalid) { + m_error = QLatin1String("unrecognized value '") + action + + QLatin1String("' for action attribute."); + return false; + } + } 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; + 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(); + } + } + + 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 += QString::fromUtf8(codeFile.readAll()); + 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 QStringRef &n, const QXmlStreamAttributes &atts) +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 +2233,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,7 +2248,7 @@ 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(); @@ -753,77 +2263,22 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts } 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 +2292,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 +2309,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 +2336,83 @@ 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; - } - } else { - element->entry = new FunctionTypeEntry(name, signature, since); - element->entry->setCodeGeneration(m_generate); - } - } - break; + 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; default: Q_ASSERT(false); }; if (element->entry) { m_database->addType(element->entry); - setTypeRevision(element->entry, attributes[QLatin1String("revision")].toInt()); } 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 +2432,87 @@ 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); - } - 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); + 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::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: + 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 +2522,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,178 +2561,48 @@ 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; } @@ -2120,10 +2630,7 @@ PrimitiveTypeEntry *PrimitiveTypeEntry::basicReferencedTypeEntry() const return 0; PrimitiveTypeEntry *baseReferencedTypeEntry = m_referencedTypeEntry->basicReferencedTypeEntry(); - if (baseReferencedTypeEntry) - return baseReferencedTypeEntry; - else - return m_referencedTypeEntry; + return baseReferencedTypeEntry ? baseReferencedTypeEntry : m_referencedTypeEntry; } bool PrimitiveTypeEntry::preferredConversion() const @@ -2136,20 +2643,6 @@ void PrimitiveTypeEntry::setPreferredConversion(bool b) m_preferredConversion = b; } -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); -} - CodeSnipList TypeEntry::codeSnips() const { return m_codeSnips; @@ -2186,40 +2679,23 @@ 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); -} - -QString ContainerTypeEntry::targetLangPackage() const -{ - return QString(); + return !m_defaultConstructor.isEmpty(); } QString ContainerTypeEntry::targetLangName() const @@ -2255,10 +2731,7 @@ QString ContainerTypeEntry::qualifiedCppName() const 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 @@ -2296,11 +2769,6 @@ bool FlagsTypeEntry::preferredConversion() const return false; } -QString FlagsTypeEntry::targetLangPackage() const -{ - return m_enum->targetLangPackage(); -} - QString FlagsTypeEntry::qualifiedTargetLangName() const { return targetLangPackage() + QLatin1Char('.') + m_enum->targetLangQualifier() @@ -2320,7 +2788,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 +2809,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 +2827,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) @@ -2578,71 +3041,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 +3104,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,29 +3113,22 @@ 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; } TypeSystemTypeEntry::TypeSystemTypeEntry(const QString &name, const QVersionNumber &vr) : @@ -2778,10 +3165,9 @@ 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"); } EnumTypeEntry::EnumTypeEntry(const QString &nspace, const QString &enumName, @@ -2793,16 +3179,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; @@ -2867,31 +3243,6 @@ ValueTypeEntry::ValueTypeEntry(const QString &name, Type t, const QVersionNumber { } -StringTypeEntry::StringTypeEntry(const QString &name, const QVersionNumber &vr) : - ValueTypeEntry(name, StringType, vr) -{ - setCodeGeneration(GenerateNothing); -} - -/* -static void injectCode(ComplexTypeEntry *e, - const char *signature, - const QByteArray &code, - const ArgumentMap &args) -{ - 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 { CustomConversionPrivate(const TypeEntry* ownerType) diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 186c4b24d..13805d47e 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -237,6 +237,7 @@ struct ArgumentModification struct Modification { enum Modifiers { + InvalidModifier = 0x0000, Private = 0x0001, Protected = 0x0002, Public = 0x0003, @@ -398,6 +399,7 @@ struct AddedFunction { /// Function access types. enum Access { + InvalidAccess = 0, Protected = 0x1, Public = 0x2 }; @@ -715,6 +717,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 +754,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,8 +894,13 @@ public: bool hasCustomConversion() const; void setCustomConversion(CustomConversion* customConversion); CustomConversion* customConversion() const; + +#ifndef QT_NO_DEBUG_STREAM + virtual void formatDebug(QDebug &d) const; +#endif private: QString m_name; + QString m_targetLangPackage; Type m_type; uint m_codeGeneration = GenerateAll; CustomFunction m_customConstructor; @@ -904,6 +914,9 @@ 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 @@ -1031,8 +1044,6 @@ public: m_preferredTargetLangType = b; } - void setTargetLangPackage(const QString& package); - QString targetLangPackage() const override; private: QString m_targetLangName; QString m_targetLangApiName; @@ -1048,9 +1059,6 @@ 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; @@ -1131,6 +1139,9 @@ public: m_forceInteger = force; } +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif private: QString m_packageName; QString m_qualifier; @@ -1203,8 +1214,6 @@ public: m_enum = e; } - QString targetLangPackage() const override; - private: QString m_originalName; QString m_targetLangName; @@ -1288,12 +1297,6 @@ public: return m_fieldMods; } - QString targetLangPackage() const override; - void setTargetLangPackage(const QString &package) - { - m_package = package; - } - bool isQObject() const { return m_qobject; @@ -1401,11 +1404,14 @@ public: void setDefaultConstructor(const QString& defaultConstructor); bool hasDefaultConstructor() const; +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif 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; @@ -1455,29 +1461,8 @@ 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); - } - private: Type m_type; }; @@ -1527,44 +1512,6 @@ protected: explicit ValueTypeEntry(const QString &name, Type t, const QVersionNumber &vr); }; - -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: @@ -1641,7 +1588,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..62ae8feb2 100644 --- a/sources/shiboken2/ApiExtractor/typesystem_enums.h +++ b/sources/shiboken2/ApiExtractor/typesystem_enums.h @@ -71,14 +71,16 @@ enum CodeSnipPosition { CodeSnipPositionPrototypeInitialization, CodeSnipPositionConstructorInitialization, CodeSnipPositionConstructor, - CodeSnipPositionAny + CodeSnipPositionAny, + CodeSnipPositionInvalid }; enum DocModificationMode { DocModificationAppend, DocModificationPrepend, DocModificationReplace, - DocModificationXPathReplace + DocModificationXPathReplace, + DocModificationInvalid }; } // namespace TypeSystem diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystem_p.h index 882cf3fab..d54c4cb65 100644 --- a/sources/shiboken2/ApiExtractor/typesystem_p.h +++ b/sources/shiboken2/ApiExtractor/typesystem_p.h @@ -140,22 +140,96 @@ 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 *); + 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; @@ -170,7 +244,6 @@ private: EnumTypeEntry* m_currentEnum; QStack<StackElementContext*> m_contextStack; - QHash<QString, StackElement::ElementType> tagNames; QString m_currentSignature; QString m_currentPath; }; 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/generator.cpp b/sources/shiboken2/generator/generator.cpp index 1e2f03932..63700f2c5 100644 --- a/sources/shiboken2/generator/generator.cpp +++ b/sources/shiboken2/generator/generator.cpp @@ -40,8 +40,9 @@ #include <QDebug> #include <typedatabase.h> -struct Generator::GeneratorPrivate { - const ApiExtractor* apiextractor; +struct Generator::GeneratorPrivate +{ + const ApiExtractor* apiextractor = nullptr; QString outDir; // License comment QString licenseComment; @@ -62,7 +63,7 @@ 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(); @@ -84,7 +85,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 +198,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(); @@ -463,7 +469,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) @@ -581,7 +587,7 @@ QString Generator::minimalConstructor(const AbstractMetaType* type) const return QLatin1String("static_cast< ::") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)"); if (type->typeEntry()->isComplex()) { - const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(type->typeEntry()); + const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(type->typeEntry()); QString ctor = cType->defaultConstructor(); if (!ctor.isEmpty()) return ctor; @@ -612,7 +618,7 @@ QString Generator::minimalConstructor(const TypeEntry* type) const return 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 @@ -633,7 +639,7 @@ QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const if (!metaClass) return QString(); - const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(metaClass->typeEntry()); + const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(metaClass->typeEntry()); if (cType->hasDefaultConstructor()) return cType->defaultConstructor(); diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h index 010ed868c..6028afa64 100644 --- a/sources/shiboken2/generator/generator.h +++ b/sources/shiboken2/generator/generator.h @@ -166,9 +166,10 @@ 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; @@ -348,7 +349,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. diff --git a/sources/shiboken2/generator/main.cpp b/sources/shiboken2/generator/main.cpp index 7ee43710e..c996c7cc3 100644 --- a/sources/shiboken2/generator/main.cpp +++ b/sources/shiboken2/generator/main.cpp @@ -34,6 +34,7 @@ #include <QtCore/QDir> #include <iostream> #include <apiextractor.h> +#include <fileout.h> #include "generator.h" #include "shibokenconfig.h" #include "cppgenerator.h" @@ -52,87 +53,19 @@ 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); - - 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; -}; +static inline QString diffOption() { return QStringLiteral("diff"); } +static inline QString dryrunOption() { return QStringLiteral("dry-run"); } -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; -} +typedef QMap<QString, QString> CommandArgumentMap; -QString ArgsHandler::errorMessage() const +static QString msgLeftOverArguments(const CommandArgumentMap &remainingArgs) { - 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) { + for (auto it = remainingArgs.cbegin(), end = remainingArgs.cend(); it != end; ++it) { str << ' ' << it.key(); if (!it.value().isEmpty()) str << ' ' << it.value(); @@ -140,7 +73,6 @@ QString ArgsHandler::errorMessage() const str << "\nCommand line: " << QCoreApplication::arguments().join(QLatin1Char(' ')); return message; } -} typedef Generator::OptionDescriptions OptionDescriptions; @@ -233,9 +165,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,9 +209,9 @@ 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); else @@ -380,18 +312,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 +343,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"), @@ -445,12 +381,14 @@ static QString msgInvalidVersion(const QString &package, const QString &version) } 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(QLatin1String(PATH_SPLITTER), QString::SkipEmptyParts); + args.erase(it); for (const QString &s : includePathListList) extractor.addIncludePath(HeaderPath{QFile::encodeName(s), headerType}); } @@ -466,19 +404,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")) { @@ -494,28 +437,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)) { @@ -529,11 +489,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")) @@ -542,11 +506,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; @@ -560,54 +528,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(QLatin1String(PATH_SPLITTER))); + 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: \"" @@ -617,8 +596,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; } @@ -644,12 +632,10 @@ int main(int argc, char *argv[]) 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 3ed278871..e8f09df4a 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp @@ -303,7 +303,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); @@ -1511,11 +1511,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, @@ -1532,7 +1531,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(), @@ -1540,7 +1539,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 @@ -1675,7 +1674,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 @@ -1692,7 +1691,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; @@ -1775,7 +1774,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; @@ -1857,8 +1857,7 @@ void QtDocGenerator::writeDocSnips(QTextStream &s, if (row.trimmed().size() == 0) { if (currenRow == 0) continue; - else - s << endl; + s << endl; } if (currenRow == 0) { @@ -2122,7 +2121,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; @@ -2259,32 +2258,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; } @@ -2292,19 +2287,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..978668c4c 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,6 +217,7 @@ public: } OptionDescriptions options() const override; + bool handleOption(const QString &key, const QString &value) override; QStringList codeSnippetDirs() const { diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 5e3f890f8..8bddef700 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -3117,8 +3117,7 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f 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)); @@ -3409,7 +3408,7 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f s << "reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \""; 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 +3530,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 +3574,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 +3655,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) @@ -3964,7 +3960,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()) @@ -4354,7 +4349,7 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co 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 +4373,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(); @@ -4679,7 +4674,7 @@ 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); @@ -4704,7 +4699,8 @@ 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); @@ -5326,7 +5322,7 @@ bool CppGenerator::finishGeneration() } TypeDatabase* typeDb = TypeDatabase::instance(); - TypeSystemTypeEntry* moduleEntry = reinterpret_cast<TypeSystemTypeEntry*>(typeDb->findType(packageName())); + TypeSystemTypeEntry* moduleEntry = static_cast<TypeSystemTypeEntry*>(typeDb->findType(packageName())); //Extra includes s << endl << "// Extra includes" << endl; diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h index 1b59bcda7..49a1e1835 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); diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp index 8fde3cd31..27463490a 100644 --- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp @@ -49,11 +49,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 @@ -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) @@ -297,10 +296,10 @@ void HeaderGenerator::writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* if (!typeEntry || !typeEntry->generateCode()) return; s.setFieldAlignment(QTextStream::AlignLeft); - int typeIndex = getTypeIndex(typeEntry); + const int typeIndex = typeEntry->sbkIndex(); _writeTypeIndexDefineLine(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()) @@ -308,7 +307,7 @@ void HeaderGenerator::writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* } } 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()); } @@ -580,7 +579,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/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp index 73198ba12..333ee00c6 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; }; @@ -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..16f5fafd3 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -31,6 +31,7 @@ #include "overloaddata.h" #include <reporthandler.h> #include <typedatabase.h> +#include <abstractmetabuilder.h> #include <iostream> #include <QtCore/QDir> @@ -100,7 +101,7 @@ static QString resolveScopePrefix(const AbstractMetaEnum *metaEnum, return resolveScopePrefix(parts, value); } -ShibokenGenerator::ShibokenGenerator() : Generator() +ShibokenGenerator::ShibokenGenerator() { if (m_pythonPrimitiveTypeName.isEmpty()) ShibokenGenerator::initPrimitiveTypesCorrespondences(); @@ -123,11 +124,7 @@ ShibokenGenerator::ShibokenGenerator() : Generator() 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 +274,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 +329,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 @@ -434,7 +430,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("_")); @@ -616,12 +613,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 +629,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 +706,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 +746,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 +754,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: @@ -925,7 +926,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 +954,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 +964,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 +976,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 +988,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 +1000,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 +1054,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 +1074,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 +1127,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 +1158,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 +1186,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); @@ -1412,13 +1418,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 +1624,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())) @@ -1978,7 +1984,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 +2008,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 +2038,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 +2181,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) @@ -2254,12 +2261,16 @@ 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; +} + +static inline QString msgCannotBuildMetaType(const QString &s) +{ + return QLatin1String("Unable to build meta type for \"") + + s + QLatin1String("\": "); } 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); + 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; } - 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 << "\"."; - } - 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(); @@ -2657,7 +2586,7 @@ QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass* met 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(); } @@ -2738,7 +2667,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(); diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h index cb1bdd11f..ed8f1bbfb 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h @@ -239,8 +239,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; @@ -292,16 +292,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 +389,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(PYTHON_SELF_VAR)); + 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 +415,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; @@ -462,12 +464,11 @@ public: */ static QString getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg); protected: - bool doSetup(const QMap<QString, QString>& args); + bool doSetup() override; 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; @@ -517,12 +518,12 @@ protected: static QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type); private: - bool m_useCtorHeuristic; - bool m_userReturnValueHeuristic; - bool m_usePySideExtensions; - bool m_verboseErrorMessagesDisabled; - bool m_useIsNullAsNbNonZero; - bool m_avoidProtectedHack; + 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/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/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/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml index 00052e881..bef433784 100644 --- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -1964,7 +1964,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"> |