diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index a5c31bf..06c0afe 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -104,6 +104,24 @@ static QStringList parseTemplateType(const QString& name) { return result; } +static bool entryHasFunction(const ComplexTypeEntry *entry, const QString &signature) +{ + foreach (const FunctionModification &mod, entry->functionModifications()) { + if (mod.signature == signature) + return true; + } + return false; +} + +static bool classHasFunction(const AbstractMetaClass *metaClass, const QString &minimalSignature) +{ + foreach (const AbstractMetaFunction *function, metaClass->functions()) { + if (function->minimalSignature() == minimalSignature) + return true; + } + return false; +} + AbstractMetaBuilder::AbstractMetaBuilder() : m_currentClass(0), m_logDirectory(QString('.')+QDir::separator()) { } @@ -413,10 +431,28 @@ bool AbstractMetaBuilder::build(QIODevice* input) } ReportHandler::flush(); + QList instantiationTypes; + foreach (QList entries, types->allEntries()) { + foreach (TypeEntry* entry, entries) { + if (entry->isTemplateInstantiation()) + instantiationTypes << static_cast(entry); + } + } + + ReportHandler::setProgressReference(instantiationTypes); + foreach (ComplexTypeEntry *entry, instantiationTypes) { + ReportHandler::progress("Generating template instantiations model..."); + AbstractMetaClass *cls = createInstantiationMetaClass(entry); + if (!cls) + continue; + + addAbstractMetaClass(cls); + } + ReportHandler::flush(); + // We need to know all global enums - QHash enumMap = m_dom->enumMap(); - ReportHandler::setProgressReference(enumMap); - foreach (EnumModelItem item, enumMap) { + ReportHandler::setProgressReference(m_dom->enumMap()); + foreach (EnumModelItem item, m_dom->enums()) { ReportHandler::progress("Generating enum model..."); AbstractMetaEnum *metaEnum = traverseEnum(item, 0, QSet()); if (metaEnum) { @@ -496,6 +532,17 @@ bool AbstractMetaBuilder::build(QIODevice* input) } ReportHandler::flush(); + // Resolve template instantiation argument types and set up functions on + // the same, including redirections and function modifications from the + // type-template. + ReportHandler::setProgressReference(instantiationTypes); + foreach (ComplexTypeEntry *entry, instantiationTypes) { + ReportHandler::progress("Fixing template instantiations..."); + AbstractMetaClass* cls = m_metaClasses.findClass(entry->qualifiedCppName()); + traverseInstantiation(entry, cls); + } + ReportHandler::flush(); + ReportHandler::setProgressReference(m_metaClasses); foreach (AbstractMetaClass* cls, m_metaClasses) { ReportHandler::progress("Detecting inconsistencies in class model..."); @@ -605,8 +652,12 @@ bool AbstractMetaBuilder::build(QIODevice* input) + m_dom->findFunctions("operator~") + m_dom->findFunctions("operator>"); - foreach (FunctionModelItem item, binaryOperators) + foreach (FunctionModelItem item, binaryOperators) { + if (item->arguments().empty()) { + continue; + } traverseOperatorFunction(item); + } } { @@ -1351,6 +1402,187 @@ void AbstractMetaBuilder::traverseFields(ScopeModelItem scope_item, AbstractMeta } } +AbstractMetaClass* AbstractMetaBuilder::createInstantiationMetaClass(ComplexTypeEntry *entry) +{ + QString fullClassName = entry->name(); + + // Determine base classes + // TODO + + AbstractMetaClass* metaClass = createMetaClass(); + metaClass->setTypeEntry(entry); + *metaClass += AbstractMetaAttributes::Public; + if (entry->stream()) + metaClass->setStream(true); + + ReportHandler::debugSparse(QString("instantiation: '%1'").arg(metaClass->fullName())); + + QStringList template_parameters = entry->templateArgNames(); + QList template_args; + template_args.clear(); + for (int i = 0; i < template_parameters.size(); ++i) { + TemplateArgumentEntry *param_type = new TemplateArgumentEntry(template_parameters.at(i), entry->version()); + param_type->setOrdinal(i); + template_args.append(param_type); + } + metaClass->setTemplateArguments(template_args); + + // Set the default include file name + if (!entry->include().isValid()) + setInclude(entry, entry->include().name()); + + fillAddedFunctions(metaClass); + + return metaClass; +} + +void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, AbstractMetaClass *metaClass) +{ + // Resolve type entries of template instantiation types + QList argTypeEntries; + QHash argTypes; + int ordinal = 0; + foreach (QString argName, entry->templateArgNames()) { + TypeInfo argInfo; + argInfo.setQualifiedName(argName.split("::")); + + bool ok = false; + AbstractMetaType *argType = translateType(argInfo, &ok); + if (ok) { + argTypes.insert(ordinal, argType); + argTypeEntries << argType->typeEntry(); + } else { + ReportHandler::warning(QString("template parameter '%1' of '%2' is not known") + .arg(argName) + .arg(metaClass->name())); + } + ++ordinal; + } + + bool wrapsPointer = !entry->templateType()->wrapsPointerAs().isEmpty(); + QList args = entry->templateType()->args(); + Q_ASSERT(args.count() == argTypes.count()); + + // Add functions and modifications from the type template + foreach (AddedFunction addedFunction, metaClass->typeEntry()->templateType()->addedFunctions()) + traverseFunction(addedFunction, metaClass, argTypes); + + foreach (FunctionModification modification, metaClass->typeEntry()->templateType()->functionModifications()) { + FunctionModification resolvedModification(modification); + resolvedModification.snips.clear(); + + // Resolve template types in code snips + foreach (const CodeSnip &snip, modification.snips) { + CodeSnip resolvedSnip(snip); + resolvedSnip.codeList.clear(); + + QString code = snip.code(); + QHash::const_iterator iter, end = argTypes.constEnd(); + for (iter = argTypes.constBegin(); iter != end; ++iter) { + code.replace(QRegExp(QString("%INTYPE_%1\\b").arg(iter.key())), + iter.value()->typeEntry()->qualifiedCppName()); + } + + resolvedSnip.addCode(code); + resolvedModification.snips.append(resolvedSnip); + } + entry->addFunctionModification(resolvedModification); + } + + // Set up redirections + foreach (int ordinal, argTypes.keys()) { + const AbstractMetaType *argType = argTypes[ordinal]; + QString accessor = args[ordinal].redirect(); + if (!accessor.isEmpty()) { + AbstractMetaClass *argClass = m_metaClasses.findClass(argType->typeEntry()->qualifiedCppName()); + if (!argClass) { + ReportHandler::warning(QString("template argument '%1' of '%2' is not known; not adding redirections") + .arg(argType->typeEntry()->qualifiedCppName()) + .arg(metaClass->name())); + continue; + } + + addRedirections(entry, metaClass, argClass, accessor); + + if (wrapsPointer + && entry->templateType()->wrapsPointerArg() == ordinal + && !argClass->baseClassName().isEmpty()) { + QStringList argList = parseTemplateType(metaClass->qualifiedCppName()); + QString templateClass = argList.takeFirst(); + argList[ordinal] = argClass->baseClass()->qualifiedCppName(); + QString baseTemplateClass = QString("%1< %2 >").arg(templateClass).arg(argList.join(", ")); + + AbstractMetaClass* baseMetaClass = m_metaClasses.findClass(baseTemplateClass); + + if (baseMetaClass) { + metaClass->setHasInjectedDependencies(); + baseMetaClass->setHasInjectedDependencies(); + if (!metaClass->baseClass()) + metaClass->setBaseClass(baseMetaClass); + metaClass->addBaseClassName(baseTemplateClass); + } else { + QString warn = QString("want to inherit %1 from same class with arg %2 replaced with %3, but it is an unknown type.") + .arg(metaClass->name()).arg(ordinal).arg(argClass->baseClass()->qualifiedCppName()); + ReportHandler::warning(warn); + } + } + } + } +} + +void AbstractMetaBuilder::addRedirections(ComplexTypeEntry *entry, AbstractMetaClass* metaClass, AbstractMetaClass* fromClass, const QString &accessor) +{ + // Add redirections from the class itself + foreach (AbstractMetaFunction *function, fromClass->functions()) { + if (!function->isStatic() && !function->isConstructor() && function->isPublic()) { + QString signature = function->minimalSignature(); + if (signature.endsWith("const")) + signature = signature.left((signature.length() - 5)); + + // Skip function if it already exists (e.g. overloaded virtuals or shadowed methods) + if (classHasFunction(metaClass, signature)) + continue; + + // Generate meta function and add to meta class + QString returnType = (function->type() ? function->type()->cppSignature() : QString("void")); + AddedFunction addedFunction(signature, returnType, 0.0); + addedFunction.setAccess(AddedFunction::Public); + addedFunction.setStatic(false); + + traverseFunction(addedFunction, metaClass); + + // If there is not a user-defined modification of this redirection, generate a default one + if (!entryHasFunction(entry, signature)) { + FunctionModification redirect(0.0); + redirect.signature = signature; + redirect.modifiers = Modification::Public; + redirect.modifiers |= Modification::CodeInjection; + + CodeSnip snip(0.0); + if (function->type()) { + snip.addCode("%RETURN_TYPE %0 = " + accessor + "%FUNCTION_NAME(%ARGUMENT_NAMES);\n"); + snip.addCode("%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);\n"); + } else { + snip.addCode(accessor + "%FUNCTION_NAME(%ARGUMENT_NAMES);\n"); + } + snip.position = CodeSnip::Beginning; + snip.language = TypeSystem::TargetLangCode; + redirect.snips.append(snip); + + entry->addFunctionModification(redirect); + } + } + } + + // Add redirections from the class's primary base class + if (fromClass->baseClass()) + addRedirections(entry, metaClass, fromClass->baseClass(), accessor); + + // Add redirections from the class's interfaces + foreach (AbstractMetaClass *iface, fromClass->interfaces()) + addRedirections(entry, metaClass, iface, accessor); +} + void AbstractMetaBuilder::setupFunctionDefaults(AbstractMetaFunction* metaFunction, AbstractMetaClass *metaClass) { // Set the default value of the declaring class. This may be changed @@ -1728,12 +1960,8 @@ void AbstractMetaBuilder::traverseEnums(ScopeModelItem scopeItem, AbstractMetaCl } } -AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& addedFunc) -{ - return traverseFunction(addedFunc, 0); -} - -AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& addedFunc, AbstractMetaClass* metaClass) +AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& addedFunc, AbstractMetaClass* metaClass, + const QHash &templateArgs) { AbstractMetaFunction* metaFunction = createMetaFunction(); metaFunction->setConstant(addedFunc.isConstant()); @@ -1744,7 +1972,7 @@ AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& metaFunction->setUserAdded(true); AbstractMetaAttributes::Attribute isStatic = addedFunc.isStatic() ? AbstractMetaFunction::Static : AbstractMetaFunction::None; metaFunction->setAttributes(metaFunction->attributes() | AbstractMetaAttributes::Final | isStatic); - metaFunction->setType(translateType(addedFunc.version(), addedFunc.returnType())); + metaFunction->setType(translateType(addedFunc.version(), addedFunc.returnType(), templateArgs)); QList args = addedFunc.arguments(); @@ -1753,7 +1981,7 @@ AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& for (int i = 0; i < args.count(); ++i) { AddedFunction::TypeInfo& typeInfo = args[i]; AbstractMetaArgument* metaArg = createMetaArgument(); - AbstractMetaType* type = translateType(addedFunc.version(), typeInfo); + AbstractMetaType* type = translateType(addedFunc.version(), typeInfo, templateArgs); decideUsagePattern(type); metaArg->setType(type); metaArg->setArgumentIndex(i); @@ -1850,6 +2078,14 @@ void AbstractMetaBuilder::fixArgumentNames(AbstractMetaFunction* func) } } +static QString functionSignature(FunctionModelItem functionItem) +{ + QStringList args; + foreach (ArgumentModelItem arg, functionItem->arguments()) + args << arg->type().toString(); + return QString("%1(%2)").arg(functionItem->name(), args.join(",")); +} + AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(FunctionModelItem functionItem) { QString functionName = functionItem->name(); @@ -1861,6 +2097,10 @@ AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(FunctionModelItem fu m_rejectedFunctions.insert(className + "::" + functionName, GenerationDisabled); return 0; } + else if (TypeDatabase::instance()->isFunctionRejected(className, functionSignature(functionItem))) { + m_rejectedFunctions.insert(className + "::" + functionName, GenerationDisabled); + return 0; + } Q_ASSERT(functionItem->functionType() == CodeModel::Normal || functionItem->functionType() == CodeModel::Signal @@ -2043,6 +2283,10 @@ AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunct return 0; type = typeDb->findType(typeName); + if (!type) + type = typeDb->findType(AbstractMetaClass::canonicalizeInstantiationName(typeName)); + if (!type) + type = TypeDatabase::instance()->findTypeTemplate(typeName); // test if the type is a template, like a container bool isTemplate = false; @@ -2095,12 +2339,45 @@ AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunct return metaType; } -static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName) +AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunction::TypeInfo& typeInfo, const QHash< int, AbstractMetaType* >& templateArgs) +{ + if (!templateArgs.isEmpty()) { + // Resolve references to template argument types + QHash::const_iterator iter, end = templateArgs.constEnd(); + for (iter = templateArgs.begin(); iter != end; ++iter) { + if (typeInfo.name == QString("%INTYPE_%1").arg(iter.key())) { + if (iter.value()) { + // Make a copy of the template argument type, and set appropriate indirections + AbstractMetaType* metaType = createMetaType(); + metaType->setTypeEntry(iter.value()->typeEntry()); + metaType->setIndirections(typeInfo.indirections); + metaType->setReference(typeInfo.isReference); + metaType->setConstant(typeInfo.isConstant); + foreach (AbstractMetaType* instantation, iter.value()->instantiations()) { + AbstractMetaType* metaArgType = createMetaType(); + metaArgType->setTypeEntry(instantation->typeEntry()); + metaType->addInstantiation(metaArgType); + } + metaType->setTypeUsagePattern(iter.value()->typeUsagePattern()); + return metaType; + } + return 0; // type is 'void' + } + } + } + return translateType(vr, typeInfo); +} + +static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName, const QString& instantiationName) { const TypeEntry* type = 0; QStringList context = metaClass->qualifiedCppName().split("::"); while(!type && (context.size() > 0) ) { - type = TypeDatabase::instance()->findType(context.join("::") + "::" + qualifiedName); + const QString guess = context.join("::") + "::" + qualifiedName; + if ((type = TypeDatabase::instance()->findTypeTemplate(guess))) + type = TypeDatabase::instance()->findType(context.join("::") + "::" + instantiationName); + else + type = TypeDatabase::instance()->findType(guess); context.removeLast(); } return type; @@ -2214,12 +2491,13 @@ AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, boo // 5.1 - Try first using the current scope if (m_currentClass) { - type = findTypeEntryUsingContext(m_currentClass, qualifiedName); + const QString& instantiationName = typeInfo.instantiationName(); + type = findTypeEntryUsingContext(m_currentClass, qualifiedName, instantiationName); // 5.1.1 - Try using the class parents' scopes if (!type && !m_currentClass->baseClassNames().isEmpty()) { foreach (const AbstractMetaClass* cls, getBaseClasses(m_currentClass)) { - type = findTypeEntryUsingContext(cls, qualifiedName); + type = findTypeEntryUsingContext(cls, qualifiedName, instantiationName); if (type) break; } @@ -2230,15 +2508,22 @@ AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, boo if (!type) type = TypeDatabase::instance()->findType(qualifiedName); - // 6. No? Try looking it up as a flags type + // 6. No? Try looking it up as a template type + if (!type) { + type = TypeDatabase::instance()->findTypeTemplate(qualifiedName); + if (type) + type = TypeDatabase::instance()->findType(typeInfo.instantiationName()); + } + + // 7. No? Try looking it up as a flags type if (!type) type = TypeDatabase::instance()->findFlagsType(qualifiedName); - // 7. No? Try looking it up as a container type + // 8. No? Try looking it up as a container type if (!type) type = TypeDatabase::instance()->findContainerType(name); - // 8. No? Check if the current class is a template and this type is one + // 9. No? Check if the current class is a template and this type is one // of the parameters. if (!type && m_currentClass) { QList template_args = m_currentClass->templateArguments(); @@ -2248,8 +2533,8 @@ AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, boo } } - // 9. Try finding the type by prefixing it with the current - // context and all baseclasses of the current context + // 10. Try finding the type by prefixing it with the current + // context and all baseclasses of the current context if (!type && !TypeDatabase::instance()->isClassRejected(qualifiedName) && m_currentClass && resolveScope) { QStringList contexts; contexts.append(m_currentClass->qualifiedCppName()); @@ -2262,7 +2547,7 @@ AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, boo type = TypeDatabase::instance()->findType(contexts.at(0) + "::" + qualifiedName); contexts.pop_front(); - // 10. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so + // 11. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so // enum types from there may be addressed without any scope resolution in properties. if (!contexts.size() && !subclassesDone) { contexts << "Qt"; @@ -2290,22 +2575,24 @@ AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, boo metaType->setConstant(typeInfo.is_constant); metaType->setOriginalTypeDescription(_typei.toString()); - foreach (const TypeParser::Info &ta, typeInfo.template_instantiations) { - TypeInfo info; - info.setConstant(ta.is_constant); - info.setReference(ta.is_reference); - info.setIndirections(ta.indirections); + if (!type->isTemplateInstantiation()) { + foreach (const TypeParser::Info &ta, typeInfo.template_instantiations) { + TypeInfo info; + info.setConstant(ta.is_constant); + info.setReference(ta.is_reference); + info.setIndirections(ta.indirections); - info.setFunctionPointer(false); - info.setQualifiedName(ta.instantiationName().split("::")); + info.setFunctionPointer(false); + info.setQualifiedName(ta.instantiationName().split("::")); - AbstractMetaType* targType = translateType(info, ok); - if (!(*ok)) { - delete metaType; - return 0; - } + AbstractMetaType* targType = translateType(info, ok); + if (!(*ok)) { + delete metaType; + return 0; + } - metaType->addInstantiation(targType, true); + metaType->addInstantiation(targType, true); + } } // The usage pattern *must* be decided *after* the possible template @@ -2519,12 +2806,12 @@ AbstractMetaClass* AbstractMetaBuilder::findTemplateClass(const QString& name, c return 0; } -AbstractMetaClassList AbstractMetaBuilder::getBaseClasses(const AbstractMetaClass* metaClass) const +AbstractMetaClassList AbstractMetaBuilder::getBaseClasses(const AbstractMetaClass* metaClass, bool useTemplate) const { AbstractMetaClassList baseClasses; foreach (const QString& parent, metaClass->baseClassNames()) { AbstractMetaClass* cls = 0; - if (parent.contains('<')) + if (useTemplate && parent.contains('<')) cls = findTemplateClass(parent, metaClass); else cls = m_metaClasses.findClass(parent); @@ -2941,13 +3228,14 @@ AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted(const Abstra QRegExp regex1("\\(.*\\)"); QRegExp regex2("::.*"); foreach (AbstractMetaClass* clazz, classList) { - if (clazz->isInterface() || !clazz->typeEntry()->generateCode()) + if (!clazz->hasInjectedDependencies() && + (clazz->isInterface() || !clazz->typeEntry()->generateCode())) continue; if (clazz->enclosingClass() && map.contains(clazz->enclosingClass()->qualifiedCppName())) graph.addEdge(map[clazz->enclosingClass()->qualifiedCppName()], map[clazz->qualifiedCppName()]); - AbstractMetaClassList bases = getBaseClasses(clazz); + AbstractMetaClassList bases = getBaseClasses(clazz, false); foreach(AbstractMetaClass* baseClass, bases) { // Fix polymorphic expression if (clazz->baseClass() == baseClass) diff --git a/ApiExtractor/abstractmetabuilder.h b/ApiExtractor/abstractmetabuilder.h index 94f5a75..ef1abb7 100644 --- a/ApiExtractor/abstractmetabuilder.h +++ b/ApiExtractor/abstractmetabuilder.h @@ -37,6 +37,7 @@ class TypeDatabase; class AbstractMetaBuilder { public: + typedef QHash IntAbstractMetaHash; enum RejectReason { NotInTypeSystem, GenerationDisabled, @@ -102,6 +103,9 @@ class AbstractMetaBuilder void figureOutDefaultEnumArguments(); void addAbstractMetaClass(AbstractMetaClass *cls); + AbstractMetaClass *createInstantiationMetaClass(ComplexTypeEntry *entry); + void traverseInstantiation(ComplexTypeEntry *entry, AbstractMetaClass *metaClass); + void addRedirections(ComplexTypeEntry *entry, AbstractMetaClass* metaClass, AbstractMetaClass* fromClass, const QString &accessor); AbstractMetaClass *traverseTypeAlias(TypeAliasModelItem item); AbstractMetaClass *traverseClass(ClassModelItem item); AbstractMetaClass* currentTraversedClass(ScopeModelItem item); @@ -117,8 +121,8 @@ class AbstractMetaBuilder void traverseFields(ScopeModelItem item, AbstractMetaClass *parent); void traverseStreamOperator(FunctionModelItem functionItem); void traverseOperatorFunction(FunctionModelItem item); - AbstractMetaFunction* traverseFunction(const AddedFunction& addedFunc); - AbstractMetaFunction* traverseFunction(const AddedFunction& addedFunc, AbstractMetaClass* metaClass); + AbstractMetaFunction* traverseFunction(const AddedFunction& addedFunc, AbstractMetaClass* metaClass = 0, + const IntAbstractMetaHash &templateArgs = IntAbstractMetaHash()); AbstractMetaFunction *traverseFunction(FunctionModelItem function); AbstractMetaField *traverseField(VariableModelItem field, const AbstractMetaClass *cls); void checkFunctionModifications(); @@ -148,6 +152,7 @@ class AbstractMetaBuilder AbstractMetaFunction *fnc, AbstractMetaClass *, int argumentIndex); AbstractMetaType* translateType(double vr, const AddedFunction::TypeInfo& typeInfo); + AbstractMetaType* translateType(double vr, const AddedFunction::TypeInfo& typeInfo, const QHash &templateArgs); AbstractMetaType *translateType(const TypeInfo &type, bool *ok, bool resolveType = true, bool resolveScope = true); int findOutValueFromString(const QString& stringValue, bool& ok); @@ -166,7 +171,7 @@ class AbstractMetaBuilder AbstractMetaClass *findTemplateClass(const QString& name, const AbstractMetaClass *context, TypeParser::Info *info = 0, ComplexTypeEntry **baseContainerType = 0) const; - AbstractMetaClassList getBaseClasses(const AbstractMetaClass* metaClass) const; + AbstractMetaClassList getBaseClasses(const AbstractMetaClass* metaClass, bool useTemplate = true) const; bool ancestorHasPrivateCopyConstructor(const AbstractMetaClass* metaClass) const; bool inheritTemplate(AbstractMetaClass *subclass, diff --git a/ApiExtractor/abstractmetalang.cpp b/ApiExtractor/abstractmetalang.cpp index 21e7793..47a6fe1 100644 --- a/ApiExtractor/abstractmetalang.cpp +++ b/ApiExtractor/abstractmetalang.cpp @@ -1469,10 +1469,25 @@ bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const return false; } +QString AbstractMetaClass::canonicalizeInstantiationName(QString name) +{ + name.replace(QRegExp("\\s+"), " "); + name.replace(QRegExp("<([^ ])"), "< \\1"); + name.replace(QRegExp("([^ ])>"), "\\1 >"); + return name; +} QString AbstractMetaClass::name() const { - return QString(m_typeEntry->targetLangName()).split("::").last(); + const QString& tlName = m_typeEntry->targetLangName(); + QStringList templateParts = tlName.split('<'); + if (templateParts.count() > 1) { + QString& templateBaseName = templateParts[0]; + templateBaseName = templateBaseName.split("::").last(); + return canonicalizeInstantiationName(templateParts.join("<")); + } else { + return QString(tlName).split("::").last(); + } } void AbstractMetaClass::setBaseClass(AbstractMetaClass *baseClass) diff --git a/ApiExtractor/abstractmetalang.h b/ApiExtractor/abstractmetalang.h index 6d2366e..3a63bfb 100644 --- a/ApiExtractor/abstractmetalang.h +++ b/ApiExtractor/abstractmetalang.h @@ -325,8 +325,17 @@ class AbstractMetaType } QString name() const { - if (m_name.isNull()) - m_name = m_typeEntry->targetLangName().split("::").last(); + if (m_name.isNull()) { + const QString& tlName = m_typeEntry->targetLangName(); + QStringList templateParts = tlName.split('<'); + if (templateParts.count() > 1) { + QString& templateBaseName = templateParts[0]; + templateBaseName = templateBaseName.split("::").last(); + m_name = templateParts.join("<"); + } else { + m_name = QString(tlName).split("::").last(); + } + } return m_name; } QString fullName() const @@ -1419,7 +1428,8 @@ class AbstractMetaClass : public AbstractMetaAttributes m_extractedInterface(0), m_primaryInterfaceImplementor(0), m_typeEntry(0), - m_stream(false) + m_stream(false), + m_hasInjectedDependencies(false) { } @@ -1565,6 +1575,8 @@ class AbstractMetaClass : public AbstractMetaAttributes return package() + "." + name(); } + static QString canonicalizeInstantiationName(QString); + /** * Retrieves the class name without any namespace/scope information. * /return the class name without scope information @@ -1689,6 +1701,21 @@ class AbstractMetaClass : public AbstractMetaAttributes */ bool hasProtectedMembers() const; + /** + * Tells if this class has dependencies injected by the metabuilder. + * \return true if the class has injected dependencies. + */ + bool hasInjectedDependencies() const + { + return m_hasInjectedDependencies; + } + /** + * Tell the metaclass that it has injected dependencies. + */ + void setHasInjectedDependencies() + { + m_hasInjectedDependencies = true; + } QList templateArguments() const { @@ -1708,6 +1735,11 @@ class AbstractMetaClass : public AbstractMetaAttributes return m_baseClassNames; } + void addBaseClassName(const QString &name) + { + m_baseClassNames.append(name); + } + void setBaseClassNames(const QStringList &names) { m_baseClassNames = names; @@ -1955,6 +1987,7 @@ class AbstractMetaClass : public AbstractMetaAttributes // FunctionModelItem m_qDebugStreamFunction; bool m_stream; + bool m_hasInjectedDependencies; static int m_count; }; diff --git a/ApiExtractor/parser/binder.cpp b/ApiExtractor/parser/binder.cpp index 64289c5..93d236f 100644 --- a/ApiExtractor/parser/binder.cpp +++ b/ApiExtractor/parser/binder.cpp @@ -33,7 +33,6 @@ #include "dumptree.h" #include -#include Binder::Binder(CodeModel *__model, LocationManager &__location, Control *__control) : _M_model(__model), @@ -45,13 +44,13 @@ Binder::Binder(CodeModel *__model, LocationManager &__location, Control *__contr name_cc(this), decl_cc(this) { - _M_qualified_types["char"] = QString(); - _M_qualified_types["double"] = QString(); - _M_qualified_types["float"] = QString(); - _M_qualified_types["int"] = QString(); - _M_qualified_types["long"] = QString(); - _M_qualified_types["short"] = QString(); - _M_qualified_types["void"] = QString(); + _M_qualified_types.insert("char"); + _M_qualified_types.insert("double"); + _M_qualified_types.insert("float"); + _M_qualified_types.insert("int"); + _M_qualified_types.insert("long"); + _M_qualified_types.insert("short"); + _M_qualified_types.insert("void"); } Binder::~Binder() @@ -521,7 +520,7 @@ void Binder::visitTypedef(TypedefAST *node) typeAlias->setName(alias_name); typeAlias->setType(qualifyType(typeInfo, currentScope()->qualifiedName())); typeAlias->setScope(typedefScope->qualifiedName()); - _M_qualified_types[typeAlias->qualifiedName().join(".")] = QString(); + addQualifiedType(typeAlias->qualifiedName()); currentScope()->addTypeAlias(typeAlias); } while (it != end); } @@ -574,7 +573,7 @@ void Binder::visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *no return; ScopeModelItem scope = currentScope(); - _M_qualified_types[(scope->qualifiedName() + name_cc.qualifiedName()).join(".")] = QString(); + addQualifiedType((scope->qualifiedName() + name_cc.qualifiedName())); } void Binder::visitClassSpecifier(ClassSpecifierAST *node) @@ -624,7 +623,7 @@ void Binder::visitClassSpecifier(ClassSpecifierAST *node) CodeModel::FunctionType oldFunctionType = changeCurrentFunctionType(CodeModel::Normal); _M_current_class->setScope(scope->qualifiedName()); - _M_qualified_types[_M_current_class->qualifiedName().join(".")] = QString(); + addQualifiedType(_M_current_class->qualifiedName()); scope->addClass(_M_current_class); @@ -673,7 +672,7 @@ void Binder::visitEnumSpecifier(EnumSpecifierAST *node) _M_current_enum->setAnonymous(isAnonymous); _M_current_enum->setScope(enumScope->qualifiedName()); - _M_qualified_types[_M_current_enum->qualifiedName().join(".")] = QString(); + addQualifiedType(_M_current_enum->qualifiedName()); enumScope->addEnum(_M_current_enum); @@ -806,6 +805,33 @@ void Binder::applyFunctionSpecifiers(const ListNode *it, FunctionMo } while (it != end); } +static QString normalizeInstantiationName(const QString &name) +{ + const int n = name.indexOf('<'); + if (n < 0) + return name; + + // Convert template arguments into a 'standard' placeholder. This isn't perfect + // because it can't hope to understand '<' / '>' used as an operator in an + // argument (assuming we don't already fall apart on those elsewhere), but should + // suffice to handle most cases. + QString result = name; + + // First remove any nested instantiation names + QRegExp nested("<([^<>]+)>"); + int i; + while ((i = nested.lastIndexIn(result)) != n) { + result.replace(i, nested.matchedLength(), "_"); + } + + // Now rebuild the name with the template arguments replaced with placeholders + QStringList args = result.split(','); + result = args[0].left(n + 1) + "_1"; + for (int a = 1; a < args.count(); ++a) + result += QString(", _%1").arg(a + 1); + return result + ">"; +} + TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) const { // ### Potentially improve to use string list in the name table to @@ -817,7 +843,9 @@ TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) c } else { QStringList expanded = context; expanded << type.qualifiedName(); - if (_M_qualified_types.contains(expanded.join("."))) { + QStringList normalized = expanded; + normalized.last() = normalizeInstantiationName(normalized.last()); + if (_M_qualified_types.contains(normalized.join("."))) { TypeInfo modified_type = type; modified_type.setQualifiedName(expanded); return modified_type; @@ -843,6 +871,17 @@ TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) c } } +void Binder::addQualifiedType(const QStringList &name) +{ + _M_qualified_types.insert(name.join(".")); + + if (name.last().contains('<')) { + QStringList normalized = name; + normalized.last() = normalizeInstantiationName(normalized.last()); + _M_qualified_types.insert(normalized.join(".")); + } +} + void Binder::updateItemPosition(CodeModelItem item, AST *node) { QString filename; diff --git a/ApiExtractor/parser/binder.h b/ApiExtractor/parser/binder.h index da1b77c..35f0f1b 100644 --- a/ApiExtractor/parser/binder.h +++ b/ApiExtractor/parser/binder.h @@ -32,6 +32,8 @@ #include "name_compiler.h" #include "declarator_compiler.h" +#include + class TokenStream; class LocationManager; class Control; @@ -98,6 +100,8 @@ class Binder: protected DefaultVisitor void updateItemPosition(CodeModelItem item, AST *node); + void addQualifiedType(const QStringList &name); + private: CodeModel *_M_model; LocationManager &_M_location; @@ -113,7 +117,7 @@ class Binder: protected DefaultVisitor EnumModelItem _M_current_enum; QStringList _M_context; TemplateParameterList _M_current_template_parameters; // ### check me - QHash _M_qualified_types; + QSet _M_qualified_types; QHash _M_anonymous_enums; protected: diff --git a/ApiExtractor/parser/codemodel.cpp b/ApiExtractor/parser/codemodel.cpp index 43a8c7e..7e3468a 100644 --- a/ApiExtractor/parser/codemodel.cpp +++ b/ApiExtractor/parser/codemodel.cpp @@ -406,7 +406,10 @@ FunctionDefinitionList _ScopeModelItem::functionDefinitions() const EnumList _ScopeModelItem::enums() const { - return _M_enums.values(); + EnumList result; + foreach (const QString& name, _M_enumNames) + result.append(_M_enums.value(name)); + return result; } void _ScopeModelItem::addClass(ClassModelItem item) @@ -440,7 +443,9 @@ void _ScopeModelItem::addTypeAlias(TypeAliasModelItem item) void _ScopeModelItem::addEnum(EnumModelItem item) { + _M_enumNames.removeOne(item->name()); _M_enums.insert(item->name(), item); + _M_enumNames.append(item->name()); } void _ScopeModelItem::removeClass(ClassModelItem item) @@ -499,8 +504,10 @@ void _ScopeModelItem::removeEnum(EnumModelItem item) { QHash::Iterator it = _M_enums.find(item->name()); - if (it != _M_enums.end() && it.value() == item) + if (it != _M_enums.end() && it.value() == item) { + _M_enumNames.removeOne(item->name()); _M_enums.erase(it); + } } ClassModelItem _ScopeModelItem::findClass(const QString &name) const diff --git a/ApiExtractor/parser/codemodel.h b/ApiExtractor/parser/codemodel.h index 3b3571f..82de75b 100644 --- a/ApiExtractor/parser/codemodel.h +++ b/ApiExtractor/parser/codemodel.h @@ -401,6 +401,7 @@ class _ScopeModelItem: public _CodeModelItem _ScopeModelItem(const _ScopeModelItem &other); void operator = (const _ScopeModelItem &other); + QStringList _M_enumNames; QStringList _M_enumsDeclarations; }; diff --git a/ApiExtractor/parser/lexer.cpp b/ApiExtractor/parser/lexer.cpp index 0d1269e..eff54b7 100644 --- a/ApiExtractor/parser/lexer.cpp +++ b/ApiExtractor/parser/lexer.cpp @@ -1387,6 +1387,19 @@ void Lexer::scanKeyword8() } break; + case 'n': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'e' && + *(cursor + 3) == 'x' && + *(cursor + 4) == 'c' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'p' && + *(cursor + 7) == 't') { + token_stream[(int) index++].kind = Token_noexcept; + return; + } + break; + case 'o': if (*(cursor + 1) == 'p' && *(cursor + 2) == 'e' && diff --git a/ApiExtractor/parser/parser.cpp b/ApiExtractor/parser/parser.cpp index c56369c..c49785f 100644 --- a/ApiExtractor/parser/parser.cpp +++ b/ApiExtractor/parser/parser.cpp @@ -1124,6 +1124,7 @@ bool Parser::parseDeclarator(DeclaratorAST *&node) token_stream.nextToken(); // skip ')' parseCvQualify(ast->fun_cv); + parseNoExcept(); parseExceptionSpecification(ast->exception_spec); if (token_stream.lookAhead() == Token___attribute__) @@ -1863,6 +1864,14 @@ bool Parser::parseElaboratedTypeSpecifier(TypeSpecifierAST *&node) return false; } +bool Parser::parseNoExcept() +{ + // right now we only accept 'noexcept' with no conditional + CHECK(Token_noexcept); + + return true; +} + bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node) { std::size_t start = token_stream.cursor(); diff --git a/ApiExtractor/parser/parser.h b/ApiExtractor/parser/parser.h index 8f31c13..af3c221 100644 --- a/ApiExtractor/parser/parser.h +++ b/ApiExtractor/parser/parser.h @@ -119,6 +119,7 @@ class Parser bool parseNewExpression(ExpressionAST *&node); bool parseNewInitializer(NewInitializerAST *&node); bool parseNewTypeId(NewTypeIdAST *&node); + bool parseNoExcept(); bool parseOperator(OperatorAST *&node); bool parseOperatorFunctionId(OperatorFunctionIdAST *&node); bool parseParameterDeclaration(ParameterDeclarationAST *&node); diff --git a/ApiExtractor/parser/rpp/pp-engine-bits.h b/ApiExtractor/parser/rpp/pp-engine-bits.h index 5552b16..9a6f184 100644 --- a/ApiExtractor/parser/rpp/pp-engine-bits.h +++ b/ApiExtractor/parser/rpp/pp-engine-bits.h @@ -290,7 +290,6 @@ inline FILE *pp::find_include_file(std::string const &__input_filename, std::str __filepath->append(__input_filename.substr(0, slashPos)); __filepath->append(".framework/Headers/"); __filepath->append(__input_filename.substr(slashPos + 1, std::string::npos)); - std::cerr << *__filepath << "\n"; if (file_exists(*__filepath) && !file_isdir(*__filepath)) return fopen(__filepath->c_str(), "r"); @@ -623,6 +622,8 @@ _InputIterator pp::handle_define(_InputIterator __first, _InputIterator __last) } else { __first = skip_comment_or_divop(__first, __last); env.current_line += skip_comment_or_divop.lines; + if (__first == __last) + break; } } diff --git a/ApiExtractor/parser/rpp/pp-qt-configuration b/ApiExtractor/parser/rpp/pp-qt-configuration index 206c3d6..6a3dcfa 100644 --- a/ApiExtractor/parser/rpp/pp-qt-configuration +++ b/ApiExtractor/parser/rpp/pp-qt-configuration @@ -1,5 +1,9 @@ #define __cplusplus 1 +// Provide SHIBOKEN_SKIP macro so projects can eliminate +// code shiboken cannot parse. +#define SHIBOKEN_SKIP + #define __STDC__ // Qt diff --git a/ApiExtractor/parser/tokens.cpp b/ApiExtractor/parser/tokens.cpp index e3008de..34737d1 100644 --- a/ApiExtractor/parser/tokens.cpp +++ b/ApiExtractor/parser/tokens.cpp @@ -86,6 +86,7 @@ static char const * const _S_token_names[] = { "mutable", "namespace", "new", + "noexcept", "not", "not_eq", "number_literal", diff --git a/ApiExtractor/parser/tokens.h b/ApiExtractor/parser/tokens.h index dbe612d..20c17a7 100644 --- a/ApiExtractor/parser/tokens.h +++ b/ApiExtractor/parser/tokens.h @@ -87,6 +87,7 @@ enum TOKEN_KIND { Token_mutable, Token_namespace, Token_new, + Token_noexcept, Token_not, Token_not_eq, Token_number_literal, diff --git a/ApiExtractor/tests/testtemplates.cpp b/ApiExtractor/tests/testtemplates.cpp index 2ae4ce9..e9af7a8 100644 --- a/ApiExtractor/tests/testtemplates.cpp +++ b/ApiExtractor/tests/testtemplates.cpp @@ -324,7 +324,7 @@ void TestTemplates::testTypedefOfInstantiationOfTemplateClass() const ComplexTypeEntry* oneType = one->typeEntry(); const ComplexTypeEntry* baseType = base->typeEntry(); QCOMPARE(oneType->baseContainerType(), baseType); - QCOMPARE(one->baseClassNames(), QStringList("BaseTemplateClass")); + QCOMPARE(one->baseClassNames(), QStringList("NSpace::BaseTemplateClass")); QVERIFY(one->hasTemplateBaseClassInstantiations()); AbstractMetaTypeList instantiations = one->templateBaseClassInstantiations(); diff --git a/ApiExtractor/typedatabase.h b/ApiExtractor/typedatabase.h index 116e0ed..ffa1c62 100644 --- a/ApiExtractor/typedatabase.h +++ b/ApiExtractor/typedatabase.h @@ -113,6 +113,16 @@ class TypeDatabase m_flagsEntries[fte->originalName()] = fte; } + TypeTemplateEntry* findTypeTemplate(const QString& name) const + { + return m_typeTemplates[name]; + } + + void addTypeTemplate(TypeTemplateEntry* t) + { + m_typeTemplates[t->name()] = t; + } + TemplateEntry* findTemplate(const QString& name) const { return m_templates[name]; @@ -206,6 +216,7 @@ class TypeDatabase bool m_suppressWarnings; TypeEntryHash m_entries; SingleTypeEntryHash m_flagsEntries; + TypeTemplateEntryHash m_typeTemplates; TemplateEntryHash m_templates; QStringList m_suppressedWarnings; diff --git a/ApiExtractor/typesystem.cpp b/ApiExtractor/typesystem.cpp index 9925a39..81de5f9 100644 --- a/ApiExtractor/typesystem.cpp +++ b/ApiExtractor/typesystem.cpp @@ -45,6 +45,8 @@ Handler::Handler(TypeDatabase* database, bool generate) m_ignoreDepth = 0; tagNames["rejection"] = StackElement::Rejection; + tagNames["type-template"] = StackElement::TypeTemplate; + tagNames["arg"] = StackElement::Argument; tagNames["custom-type"] = StackElement::CustomTypeEntry; tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry; tagNames["container-type"] = StackElement::ContainerTypeEntry; @@ -167,6 +169,9 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin } } break; + case StackElement::TypeTemplate: + m_database->addTypeTemplate(static_cast(m_current->entry)); + // fall through case StackElement::ObjectTypeEntry: case StackElement::ValueTypeEntry: case StackElement::InterfaceTypeEntry: @@ -259,6 +264,7 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin } if (m_current->type == StackElement::Root + || m_current->type == StackElement::TypeTemplate || m_current->type == StackElement::NamespaceTypeEntry || m_current->type == StackElement::InterfaceTypeEntry || m_current->type == StackElement::ObjectTypeEntry @@ -490,6 +496,7 @@ bool Handler::startElement(const QString &, const QString &n, customConversionsForReview.clear(); if (element->type == StackElement::Root + || element->type == StackElement::TypeTemplate || element->type == StackElement::NamespaceTypeEntry || element->type == StackElement::InterfaceTypeEntry || element->type == StackElement::ObjectTypeEntry @@ -532,6 +539,8 @@ bool Handler::startElement(const QString &, const QString &n, attributes["deprecated"] = QString("no"); attributes["hash-function"] = QString(""); attributes["stream"] = QString("no"); + attributes["template"] = QString(); + attributes["args"] = QString(); // fall throooough case StackElement::InterfaceTypeEntry: attributes["default-superclass"] = m_defaultSuperclass; @@ -623,10 +632,59 @@ bool Handler::startElement(const QString &, const QString &n, name = element->parent->entry->name() + "::" + name; } + TypeTemplateEntry *typeTemplate = 0; + QStringList typeTemplateArgNames; - if (name.isEmpty()) { - m_error = "no 'name' attribute specified"; - return false; + if (element->type == StackElement::ObjectTypeEntry || element->type == StackElement::ValueTypeEntry) { + QString typeTemplateName = attributes["template"]; + + if (!name.isEmpty() && !typeTemplateName.isEmpty()) { + m_error = "can't specify both 'name' and 'template' attributes"; + return false; + } + + if (typeTemplateName.isEmpty()) { + if (name.isEmpty()) { + m_error = "no 'name' attribute specified"; + return false; + } + + if (!attributes["args"].isEmpty()) { + m_error = "'args' attribute may only be specified for template instantiation types"; + return false; + } + } else { + typeTemplate = m_database->findTypeTemplate(typeTemplateName); + if (!typeTemplate) { + m_error = "there is no type-template named " + typeTemplateName; + return false; + } + + if (attributes["args"].isEmpty()) { + m_error = "no 'args' attribute specified for template instantiation type"; + return false; + } + + typeTemplateArgNames = attributes["args"].split(QRegExp(",\\s*"), QString::SkipEmptyParts); + if (typeTemplateArgNames.isEmpty()) { + m_error = "invalid 'args' attribute"; + return false; + } + + int xc = typeTemplate->args().count(); + int ac = typeTemplateArgNames.count(); + if (ac != xc) { + m_error = QString("wrong number of args for template instantiation: expected %1, got %2").arg(xc).arg(ac); + return false; + } + + name = QString("%1< %2 >").arg(typeTemplateName, typeTemplateArgNames.join(",")); + } + } else { + if (name.isEmpty()) { + m_error = "no 'name' attribute specified"; + return false; + } } switch (element->type) { @@ -753,7 +811,7 @@ bool Handler::startElement(const QString &, const QString &n, // fall through case StackElement::ValueTypeEntry: { if (!element->entry) { - ValueTypeEntry* typeEntry = new ValueTypeEntry(name, since); + ValueTypeEntry* typeEntry = new ValueTypeEntry(name, since, typeTemplate, typeTemplateArgNames); QString defaultConstructor = attributes["default-constructor"]; if (!defaultConstructor.isEmpty()) typeEntry->setDefaultConstructor(defaultConstructor); @@ -768,7 +826,7 @@ bool Handler::startElement(const QString &, const QString &n, // fall through case StackElement::ObjectTypeEntry: if (!element->entry) - element->entry = new ObjectTypeEntry(name, since); + element->entry = new ObjectTypeEntry(name, since, typeTemplate, typeTemplateArgNames); element->entry->setStream(attributes["stream"] == QString("yes")); @@ -946,7 +1004,8 @@ bool Handler::startElement(const QString &, const QString &n, || element->type == StackElement::ExtraIncludes || element->type == StackElement::ConversionRule || element->type == StackElement::AddFunction - || element->type == StackElement::Template; + || element->type == StackElement::Template + || element->type == StackElement::TypeTemplate; if (!topLevel && m_current->type == StackElement::Root) { m_error = QString("Tag requires parent: '%1'").arg(tagName); @@ -1071,6 +1130,13 @@ bool Handler::startElement(const QString &, const QString &n, attributes["from"] = QString(); attributes["to"] = QString(); break; + case StackElement::TypeTemplate: + attributes["name"] = QString(); + break; + case StackElement::Argument: + attributes["redirect"] = QString(); + attributes["wraps-pointer-as"] = QString(); + break; case StackElement::ReferenceCount: attributes["action"] = QString(); attributes["variable-name"] = QString(); @@ -1787,8 +1853,10 @@ bool Handler::startElement(const QString &, const QString &n, element->entry->setInclude(inc); } else if (topElement.type == StackElement::ExtraIncludes) { element->entry->addExtraInclude(inc); + } else if (topElement.type == StackElement::TypeTemplate) { + element->entry->setInclude(inc); } else { - m_error = "Only supported parent tags are primitive-type, complex types or extra-includes"; + m_error = "Only supported parent tags are primitive-type, type-template, complex types or extra-includes"; return false; } @@ -1814,6 +1882,34 @@ bool Handler::startElement(const QString &, const QString &n, m_database->addRejection(cls, function, field, enum_); } break; + case StackElement::TypeTemplate: { + QString name = attributes["name"]; + if (name.isEmpty()) { + m_error = "no 'name' attribute specified"; + return false; + } + element->entry = new TypeTemplateEntry(name, since); + } + break; + case StackElement::Argument: { + if (topElement.type != StackElement::TypeTemplate) { + m_error = "Can only specify arguments for type-template tag."; + return false; + } + TypeTemplateEntry *tentry = static_cast(topElement.entry); + const QString &wrapsPointerAs = attributes["wraps-pointer-as"]; + QString redirect = attributes["redirect"]; + if (!wrapsPointerAs.isEmpty()) { + if (!tentry->wrapsPointerAs().isEmpty()) { + m_error = "Template types can only wrap a single type argument as a pointer."; + return false; + } + tentry->setWrapsPointerAs(wrapsPointerAs, tentry->args().size()); + if (redirect.isEmpty()) + redirect = wrapsPointerAs + "->"; + } + tentry->addArg(redirect); + } case StackElement::Template: element->value.templateEntry = new TemplateEntry(attributes["name"], since); break; @@ -2113,7 +2209,7 @@ bool FunctionModification::operator==(const FunctionModification& other) const static AddedFunction::TypeInfo parseType(const QString& signature, int startPos = 0, int* endPos = 0) { AddedFunction::TypeInfo result; - QRegExp regex("\\w"); + QRegExp regex("%?\\w"); int length = signature.length(); int start = signature.indexOf(regex, startPos); if (start == -1) { diff --git a/ApiExtractor/typesystem.h b/ApiExtractor/typesystem.h index 0549672..753113c 100644 --- a/ApiExtractor/typesystem.h +++ b/ApiExtractor/typesystem.h @@ -642,7 +642,8 @@ class TypeEntry TypeSystemType, CustomType, TargetLangType, - FunctionType + FunctionType, + TemplateType }; enum CodeGeneration { @@ -707,6 +708,10 @@ class TypeEntry { return m_type == ContainerType; } + bool isTypeTemplate() const + { + return m_type == TemplateType; + } bool isVariant() const { return m_type == VariantType; @@ -878,6 +883,11 @@ class TypeEntry return false; } + virtual bool isTemplateInstantiation() const + { + return false; + } + virtual bool isNativeIdBased() const { return false; @@ -1403,6 +1413,8 @@ class FlagsTypeEntry : public TypeEntry }; +class TypeTemplateEntry; + class ComplexTypeEntry : public TypeEntry { public: @@ -1419,7 +1431,8 @@ class ComplexTypeEntry : public TypeEntry Unknown }; - ComplexTypeEntry(const QString &name, Type t, double vr) + ComplexTypeEntry(const QString &name, Type t, double vr, const TypeTemplateEntry *typeTemplate = 0, + const QStringList &typeTemplateArgNames = QStringList()) : TypeEntry(QString(name).replace(".*::", ""), t, vr), m_qualifiedCppName(name), m_qobject(false), @@ -1428,7 +1441,9 @@ class ComplexTypeEntry : public TypeEntry m_typeFlags(0), m_copyableFlag(Unknown), m_hashFunction(""), - m_baseContainerType(0) + m_baseContainerType(0), + m_templateArgNames(typeTemplateArgNames), + m_templateType(typeTemplate) { } @@ -1641,6 +1656,20 @@ class ComplexTypeEntry : public TypeEntry return m_baseContainerType; } + bool isTemplateInstantiation() const + { + return m_templateType; + } + + QStringList templateArgNames() const + { + return m_templateArgNames; + } + const TypeTemplateEntry* templateType() const + { + return m_templateType; + } + QString defaultConstructor() const; void setDefaultConstructor(const QString& defaultConstructor); bool hasDefaultConstructor() const; @@ -1668,6 +1697,10 @@ class ComplexTypeEntry : public TypeEntry QString m_hashFunction; const ComplexTypeEntry* m_baseContainerType; + + QStringList m_templateArgNames; + + const TypeTemplateEntry *m_templateType; }; class ContainerTypeEntry : public ComplexTypeEntry @@ -1731,6 +1764,65 @@ class ContainerTypeEntry : public ComplexTypeEntry typedef QList ContainerTypeEntryList; + +class TypeTemplateEntry : public ComplexTypeEntry +{ +public: + class Argument + { + public: + Argument(const QString &redirect) : m_redirect(redirect) { } + + QString redirect() const + { + return m_redirect; + } + + private: + QString m_redirect; + }; + + TypeTemplateEntry(const QString &name, double vr) + : ComplexTypeEntry(name, TemplateType, vr) + { + setCodeGeneration(GenerateNothing); + } + + QList args() const // FIXME array of ?? + { + return m_args; + } + + QString wrapsPointerAs() const + { + return m_wrapsPointerAs; + } + + int wrapsPointerArg() const + { + return m_wrapsPointerArg; + } + + void setWrapsPointerAs(const QString &wrapsPointerAs, int arg) + { + m_wrapsPointerAs = wrapsPointerAs; + m_wrapsPointerArg = arg; + } + + void addArg(const QString &redirect) + { + m_args << Argument(redirect); + } + +private: + QList m_args; + QString m_wrapsPointerAs; + int m_wrapsPointerArg; +}; + +typedef QHash TypeTemplateEntryHash; + + class NamespaceTypeEntry : public ComplexTypeEntry { public: @@ -1741,7 +1833,9 @@ class NamespaceTypeEntry : public ComplexTypeEntry class ValueTypeEntry : public ComplexTypeEntry { public: - ValueTypeEntry(const QString &name, double vr) : ComplexTypeEntry(name, BasicValueType, vr) { } + ValueTypeEntry(const QString &name, double vr, const TypeTemplateEntry *typeTemplate = 0, + const QStringList &typeTemplateArgNames = QStringList()) + : ComplexTypeEntry(name, BasicValueType, vr, typeTemplate, typeTemplateArgNames) { } bool isValue() const { @@ -1877,8 +1971,9 @@ class FunctionTypeEntry : public TypeEntry class ObjectTypeEntry : public ComplexTypeEntry { public: - ObjectTypeEntry(const QString &name, double vr) - : ComplexTypeEntry(name, ObjectType, vr), m_interface(0) {} + ObjectTypeEntry(const QString &name, double vr, const TypeTemplateEntry *typeTemplate = 0, + const QStringList &typeTemplateArgNames = QStringList()) + : ComplexTypeEntry(name, ObjectType, vr, typeTemplate, typeTemplateArgNames), m_interface(0) {} InterfaceTypeEntry *designatedInterface() const { diff --git a/ApiExtractor/typesystem_p.h b/ApiExtractor/typesystem_p.h index 801e71e..23d0ee1 100644 --- a/ApiExtractor/typesystem_p.h +++ b/ApiExtractor/typesystem_p.h @@ -74,6 +74,8 @@ class StackElement NativeToTarget = 0x1100, TargetToNative = 0x1200, AddConversion = 0x1300, + TypeTemplate = 0x1400, + Argument = 0x1500, SimpleMask = 0x3f00, // Code snip tags (0x1000, 0x2000, ... , 0xf000) diff --git a/CMakeLists.txt b/CMakeLists.txt index 00b352a..f9e7d69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ add_definitions(${QT_DEFINITIONS}) set(shiboken_MAJOR_VERSION "1") set(shiboken_MINOR_VERSION "2") -set(shiboken_MICRO_VERSION "1") +set(shiboken_MICRO_VERSION "2") set(shiboken_VERSION "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}.${shiboken_MICRO_VERSION}") option(BUILD_TESTS "Build tests." TRUE) @@ -44,6 +44,7 @@ if (NOT PYTHON_SITE_PACKAGES) elseif (APPLE) message(STATUS "!!! The generated bindings will be installed on ${PYTHON_SITE_PACKAGES}, is it right!?") endif() + file(TO_CMAKE_PATH "${PYTHON_SITE_PACKAGES}" PYTHON_SITE_PACKAGES) endif() if(MSVC) diff --git a/cmake/Modules/FindPython3Libs.cmake b/cmake/Modules/FindPython3Libs.cmake index 8685e9f..20a82ba 100644 --- a/cmake/Modules/FindPython3Libs.cmake +++ b/cmake/Modules/FindPython3Libs.cmake @@ -27,7 +27,7 @@ INCLUDE(CMakeFindFrameworks) # Search for the python framework on Apple. # CMAKE_FIND_FRAMEWORKS(Python) -FOREACH(_CURRENT_VERSION 3.2 3.1 3.0) +FOREACH(_CURRENT_VERSION 3.4 3.3 3.2 3.1 3.0) IF(_CURRENT_VERSION GREATER 3.1) SET(_32FLAGS "m" "u" "mu" "dm" "du" "dmu" "") ELSE() diff --git a/data/ShibokenConfig-spec.cmake.in b/data/ShibokenConfig-spec.cmake.in index e1358b6..95c870d 100644 --- a/data/ShibokenConfig-spec.cmake.in +++ b/data/ShibokenConfig-spec.cmake.in @@ -15,6 +15,7 @@ elseif(WIN32) else() SET(SHIBOKEN_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_SHARED_LIBRARY_PREFIX@shiboken@shiboken_SUFFIX@@PYTHON_SUFFIX@@LIBRARY_OUTPUT_SUFFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@") endif() +SET(SHIBOKEN_PYTHONPATH "@PYTHON_SITE_PACKAGES@") SET(SHIBOKEN_PYTHON_INCLUDE_DIR "@SBK_PYTHON_INCLUDE_DIR@") SET(SHIBOKEN_PYTHON_INCLUDE_DIR "@SBK_PYTHON_INCLUDE_DIR@") SET(SHIBOKEN_PYTHON_INTERPRETER "@PYTHON_EXECUTABLE@") diff --git a/doc/conf.py.in b/doc/conf.py.in index f64b4f6..3a5d985 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -22,7 +22,7 @@ import sys, os # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.refcounting', 'sphinx.ext.coverage'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.coverage'] rst_epilog = """ .. |project| replace:: Shiboken diff --git a/ext/sparsehash/google/sparsehash/sparseconfig.h b/ext/sparsehash/google/sparsehash/sparseconfig.h index 44a4dda..792cc34 100644 --- a/ext/sparsehash/google/sparsehash/sparseconfig.h +++ b/ext/sparsehash/google/sparsehash/sparseconfig.h @@ -13,6 +13,18 @@ #define HASH_NAMESPACE stdext /* The system-provided hash function including the namespace. */ #define SPARSEHASH_HASH HASH_NAMESPACE::hash_compare + +/* libc++ does not implement the tr1 namespace as it provides + * only C++11 support; instead of tr1, the equivalent functionality + * is placed in namespace std, so use when it targeting such + * systems (OS X 10.7 onwards, various Linux distributions) */ +#elif defined(_LIBCPP_VERSION) + /* the location of the header defining hash functions */ + #define HASH_FUN_H + /* the namespace of the hash<> function */ + #define HASH_NAMESPACE std + /* The system-provided hash function including the namespace. */ + #define SPARSEHASH_HASH HASH_NAMESPACE::hash #else /* the location of the header defining hash functions */ #define HASH_FUN_H diff --git a/generator/main.cpp b/generator/main.cpp index 88fe3a9..85d17d5 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -215,13 +215,8 @@ static QMap getInitializedArguments() return args; } -static QMap getCommandLineArgs() +static void parseCommandLine(QMap& args, QStringList arguments, int& argNum) { - QMap args = getInitializedArguments(); - QStringList arguments = QCoreApplication::arguments(); - arguments.removeFirst(); - - int argNum = 0; foreach (QString arg, arguments) { arg = arg.trimmed(); if (arg.startsWith("--")) { @@ -232,11 +227,31 @@ static QMap getCommandLineArgs() args[arg.mid(2)] = QString(); } else if (arg.startsWith("-")) { args[arg.mid(1)] = QString(); + } else if (arg.startsWith("@")) { + QFile responseFile(arg.mid(1)); + if (responseFile.open(QIODevice::ReadOnly)) { + QTextStream stream(&responseFile); + QStringList responseArgs; + while (!stream.atEnd()) { + responseArgs << stream.readLine(); + } + parseCommandLine(args, responseArgs, argNum); + } } else { argNum++; args[QString("arg-%1").arg(argNum)] = arg; } } +} + +static QMap getCommandLineArgs() +{ + QMap args = getInitializedArguments(); + QStringList arguments = QCoreApplication::arguments(); + arguments.removeFirst(); + + int argNum = 0; + parseCommandLine(args, arguments, argNum); return args; } diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index 04a0870..3a8c619 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -108,7 +108,7 @@ CppGenerator::CppGenerator() QString CppGenerator::fileNameForClass(const AbstractMetaClass *metaClass) const { - return metaClass->qualifiedCppName().toLower().replace("::", "_") + QLatin1String("_wrapper.cpp"); + return fixedCppTypeName(metaClass->qualifiedCppName()).toLower() + QLatin1String("_wrapper.cpp"); } QList CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass, @@ -325,8 +325,8 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl s << "static PyMethodDef " << className << "_methods[] = {" << endl; s << methodsDefinitions << endl; if (metaClass->typeEntry()->isValue()) - s << INDENT << "{\"__copy__\", (PyCFunction)" << className << "___copy__" << ", METH_NOARGS}," << endl; - s << INDENT << "{0} // Sentinel" << endl; + s << INDENT << "{\"__copy__\", (PyCFunction)" << className << "___copy__" << ", METH_NOARGS, NULL}," << endl; + s << INDENT << "{NULL, NULL, 0, NULL} // Sentinel" << endl; s << "};" << endl << endl; // Write tp_getattro function @@ -409,9 +409,11 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl s << INDENT << "{const_cast(\"" << metaField->name() << "\"), "; s << cpythonGetterFunctionName(metaField); s << ", " << (hasSetter ? cpythonSetterFunctionName(metaField) : "0"); + s << ", NULL"; // TODO: documentation string goes here + s << ", NULL"; // TODO: closure goes here s << "}," << endl; } - s << INDENT << "{0} // Sentinel" << endl; + s << INDENT << "{NULL, NULL, NULL, NULL, NULL} // Sentinel" << endl; s << "};" << endl << endl; } @@ -961,8 +963,8 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla // Returns the C++ pointer of the Python wrapper. s << "// Python to C++ pointer conversion - returns the C++ object of the Python wrapper (keeps object identity)." << endl; - QString sourceTypeName = metaClass->name(); - QString targetTypeName = QString("%1_PTR").arg(metaClass->name()); + QString sourceTypeName = fixedCppTypeName(metaClass->name()); + QString targetTypeName = QString("%1_PTR").arg(sourceTypeName); QString code; QTextStream c(&code); c << INDENT << "Shiboken::Conversions::pythonToCppPointer(&" << cpythonType << ", pyIn, cppOut);"; @@ -989,6 +991,17 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla } c << INDENT << '}' << endl; c << INDENT << "const char* typeName = typeid(*((" << typeName << "*)cppIn)).name();" << endl; + const TypeTemplateEntry *typeTemplate = metaClass->typeEntry()->templateType(); + if (typeTemplate && !typeTemplate->wrapsPointerAs().isEmpty()) + { + const QString &cppSelfCode = QString("(reinterpret_cast< const %1 * >(cppIn))").arg(typeName); + c << INDENT << "if (!" << typeTemplate->wrapsPointerAs().replace("%CPPSELF", cppSelfCode) << ") {" << endl; + { + Indentation indent(INDENT); + c << INDENT << "Py_RETURN_NONE;" << endl; + } + c << INDENT << "}" << endl; + } c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType; c << ", const_cast(cppIn), false, false, typeName);"; } @@ -1003,9 +1016,23 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla // Always copies C++ value (not pointer, and not reference) to a new Python wrapper. s << endl << "// C++ to Python copy conversion." << endl; - sourceTypeName = QString("%1_COPY").arg(metaClass->name()); - targetTypeName = metaClass->name(); + sourceTypeName = QString("%1_COPY").arg(fixedCppTypeName(metaClass->name())); + targetTypeName = fixedCppTypeName(metaClass->name()); code.clear(); + + // For wrapped pointers, checks internal pointer and returns None if not instantiated + const TypeTemplateEntry *typeTemplate = metaClass->typeEntry()->templateType(); + if (typeTemplate && !typeTemplate->wrapsPointerAs().isEmpty()) + { + const QString &cppSelfCode = QString("(reinterpret_cast< const %1 * >(cppIn))").arg(typeName); + c << INDENT << "if (!" << typeTemplate->wrapsPointerAs().replace("%CPPSELF", cppSelfCode) << ") {" << endl; + { + Indentation indent(INDENT); + c << INDENT << "Py_RETURN_NONE;" << endl; + } + c << INDENT << "}" << endl; + } + c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << wrapperName(metaClass); c << "(*((" << typeName << "*)cppIn)), true, true);"; writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); @@ -1013,7 +1040,7 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla // Python to C++ copy conversion. s << "// Python to C++ copy conversion." << endl; - sourceTypeName = metaClass->name(); + sourceTypeName = fixedCppTypeName(metaClass->name()); targetTypeName = QString("%1_COPY").arg(sourceTypeName); code.clear(); c << INDENT << "*((" << typeName << "*)cppOut) = *" << cpythonWrapperCPtr(metaClass->typeEntry(), "pyIn") << ';'; @@ -1123,20 +1150,21 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas { if (metaClass->isNamespace()) return; + QString cvtname = QString("converter%1").arg(INDENT.indent); s << INDENT << "// Register Converter" << endl; - s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(&"; + s << INDENT << "SbkConverter* " << cvtname << " = Shiboken::Conversions::createConverter(&"; s << cpythonTypeName(metaClass) << ',' << endl; { Indentation indent(INDENT); - QString sourceTypeName = metaClass->name(); - QString targetTypeName = QString("%1_PTR").arg(metaClass->name()); + QString sourceTypeName = fixedCppTypeName(metaClass->name()); + QString targetTypeName = QString("%1_PTR").arg(sourceTypeName); s << INDENT << pythonToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl; s << INDENT << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl; std::swap(targetTypeName, sourceTypeName); s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName); if (metaClass->typeEntry()->isValue()) { s << ',' << endl; - sourceTypeName = QString("%1_COPY").arg(metaClass->name()); + sourceTypeName = QString("%1_COPY").arg(fixedCppTypeName(metaClass->name())); s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName); } } @@ -1147,16 +1175,16 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas QStringList cppSignature = metaClass->qualifiedCppName().split("::", QString::SkipEmptyParts); while (!cppSignature.isEmpty()) { QString signature = cppSignature.join("::"); - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "\");" << endl; - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "*\");" << endl; - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "&\");" << endl; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtname << ", \"" << signature << "\");" << endl; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtname << ", \"" << signature << "*\");" << endl; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtname << ", \"" << signature << "&\");" << endl; cppSignature.removeFirst(); } - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::"; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtname << ", typeid(::"; s << metaClass->qualifiedCppName() << ").name());" << endl; if (shouldGenerateCppWrapper(metaClass)) { - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::"; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtname << ", typeid(::"; s << wrapperName(metaClass) << ").name());" << endl; } @@ -1167,11 +1195,11 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas // Python to C++ copy (value, not pointer neither reference) conversion. s << INDENT << "// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter." << endl; - QString sourceTypeName = metaClass->name(); - QString targetTypeName = QString("%1_COPY").arg(metaClass->name()); + QString sourceTypeName = fixedCppTypeName(metaClass->name()); + QString targetTypeName = QString("%1_COPY").arg(sourceTypeName); QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName); QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); + writeAddPythonToCppConversion(s, cvtname, toCpp, isConv); // User provided implicit conversions. CustomConversion* customConversion = metaClass->typeEntry()->customConversion(); @@ -1203,10 +1231,10 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas } QString toCpp = pythonToCppFunctionName(sourceType, targetType); QString isConv = convertibleToCppFunctionName(sourceType, targetType); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); + writeAddPythonToCppConversion(s, cvtname, toCpp, isConv); } - writeCustomConverterRegister(s, customConversion, "converter"); + writeCustomConverterRegister(s, customConversion, cvtname); } void CppGenerator::writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar) @@ -1248,6 +1276,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream& s, OverloadData& over bool initPythonArguments; bool usesNamedArguments; + s << "(void)" << PYTHON_SELF_VAR << ";\n"; // Avoid warnings when self is unused. // If method is a constructor... if (rfunc->isConstructor()) { // Check if the right constructor was called. @@ -1310,6 +1339,8 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun s << "static int" << endl; s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* args, PyObject* kwds)" << endl; s << '{' << endl; + s << "(void)args;" << endl; // Avoid warnings when args is unused. + s << "(void)kwds;" << endl; // Avoid warnings when kwd is unused. QSet argNamesSet; if (usePySideExtensions() && metaClass->isQObject()) { @@ -1460,6 +1491,18 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction s << ", PyObject* kwds"; } s << ')' << endl << '{' << endl; + // Avoid unused variable warnings + if (maxArgs > 0) + { + if (pythonFunctionWrapperUsesListOfArguments(overloadData)) + { + s << "(void)args;" << endl; + } + else + { + s << "(void)" << PYTHON_ARG << ";" << endl; + } + } writeMethodWrapperPreamble(s, overloadData); @@ -2422,8 +2465,13 @@ void CppGenerator::writeCppToPythonFunction(QTextStream& s, const AbstractMetaTy return; } QString code = customConversion->nativeToTargetConversion(); - for (int i = 0; i < containerType->instantiations().count(); ++i) - code.replace(QString("%INTYPE_%1").arg(i), getFullTypeName(containerType->instantiations().at(i))); + for (int i = 0; i < containerType->instantiations().count(); ++i) { + AbstractMetaType* type = containerType->instantiations().at(i); + QString typeName = getFullTypeName(type); + if (type->isConstant()) + typeName = "const " + typeName; + code.replace(QString("%INTYPE_%1").arg(i), typeName); + } replaceCppToPythonVariables(code, getFullTypeNameWithoutModifiers(containerType)); processCodeSnip(code); writeCppToPythonFunction(s, code, fixedCppTypeName(containerType)); @@ -2453,6 +2501,7 @@ void CppGenerator::writeIsPythonConvertibleToCppFunction(QTextStream& s, s << "static PythonToCppFunc " << convertibleToCppFunctionName(sourceTypeName, targetTypeName); s << "(PyObject* pyIn) {" << endl; + s << "(void)pyIn;" << endl; // Avoid unused-variable warnings. if (acceptNoneAsCppNull) { s << INDENT << "if (pyIn == Py_None)" << endl; Indentation indent(INDENT); @@ -3178,7 +3227,8 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn { Indentation indent(INDENT); QString typeName = fixedCppTypeName(enumType); - s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(" << enumPythonType << ',' << endl; + QString cvtName = QString("converter%1").arg(INDENT.indent); + s << INDENT << "SbkConverter* " << cvtName << " = Shiboken::Conversions::createConverter(" << enumPythonType << ',' << endl; { Indentation indent(INDENT); s << INDENT << cppToPythonFunctionName(typeName, typeName) << ");" << endl; @@ -3188,25 +3238,25 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn QString enumTypeName = fixedCppTypeName(flags->originator()); QString toCpp = pythonToCppFunctionName(enumTypeName, typeName); QString isConv = convertibleToCppFunctionName(enumTypeName, typeName); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); + writeAddPythonToCppConversion(s, cvtName, toCpp, isConv); } QString toCpp = pythonToCppFunctionName(typeName, typeName); QString isConv = convertibleToCppFunctionName(typeName, typeName); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); + writeAddPythonToCppConversion(s, cvtName, toCpp, isConv); if (flags) { QString toCpp = pythonToCppFunctionName("number", typeName); QString isConv = convertibleToCppFunctionName("number", typeName); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); + writeAddPythonToCppConversion(s, cvtName, toCpp, isConv); } - s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl; - s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl; + s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", " << cvtName << ");" << endl; + s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", " << cvtName << ");" << endl; QStringList cppSignature = enumType->qualifiedCppName().split("::", QString::SkipEmptyParts); while (!cppSignature.isEmpty()) { QString signature = cppSignature.join("::"); - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \""; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtName << ", \""; if (flags) s << "QFlags<"; s << signature << "\");" << endl; @@ -3401,9 +3451,24 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* if (callOp && !callOp->isModifiedRemoved()) tp_call = '&' + cpythonFunctionName(callOp); - s << "// Class Definition -----------------------------------------------" << endl; s << "extern \"C\" {" << endl; + + if (supportsNumberProtocol(metaClass)) { + s << "static PyNumberMethods " << className + "_TypeAsNumber" << ";" << endl; + s << endl; + } + + if (supportsSequenceProtocol(metaClass)) { + s << "static PySequenceMethods " << className + "_TypeAsSequence" << ";" << endl; + s << endl; + } + + if (supportsMappingProtocol(metaClass)) { + s << "static PyMappingMethods " << className + "_TypeAsMapping" << ";" << endl; + s << endl; + } + s << "static SbkObjectType " << className + "_Type" << " = { { {" << endl; s << INDENT << "PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0)" << endl; s << INDENT << "/*tp_name*/ \"" << getClassTargetFullName(metaClass) << "\"," << endl; @@ -3536,13 +3601,13 @@ void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractM funcs["__setitem__"] = baseName + "__setitem__"; } - s << INDENT << "memset(&" << baseName << "_Type.super.as_sequence, 0, sizeof(PySequenceMethods));" << endl; + s << INDENT << "memset(&" << baseName << "_TypeAsSequence, 0, sizeof(PySequenceMethods));" << endl; foreach (const QString& sqName, m_sqFuncs.keys()) { if (funcs[sqName].isEmpty()) continue; if (m_sqFuncs[sqName] == "sq_slice") s << "#ifndef IS_PY3K" << endl; - s << INDENT << baseName << "_Type.super.as_sequence." << m_sqFuncs[sqName] << " = " << funcs[sqName] << ';' << endl; + s << INDENT << baseName << "_TypeAsSequence." << m_sqFuncs[sqName] << " = " << funcs[sqName] << ';' << endl; if (m_sqFuncs[sqName] == "sq_slice") s << "#endif" << endl; } @@ -3567,11 +3632,11 @@ void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMe } QString baseName = cpythonBaseName(metaClass); - s << INDENT << "memset(&" << baseName << "_Type.super.as_mapping, 0, sizeof(PyMappingMethods));" << endl; + s << INDENT << "memset(&" << baseName << "_TypeAsMapping, 0, sizeof(PyMappingMethods));" << endl; foreach (const QString& mpName, m_mpFuncs.keys()) { if (funcs[mpName].isEmpty()) continue; - s << INDENT << baseName << "_Type.super.as_mapping." << m_mpFuncs[mpName] << " = " << funcs[mpName] << ';' << endl; + s << INDENT << baseName << "_TypeAsMapping." << m_mpFuncs[mpName] << " = " << funcs[mpName] << ';' << endl; } } @@ -3619,7 +3684,7 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet nb["bool"] = hasBoolCast(metaClass) ? baseName + "___nb_bool" : QString(); - s << INDENT << "memset(&" << baseName << "_Type.super.as_number, 0, sizeof(PyNumberMethods));" << endl; + s << INDENT << "memset(&" << baseName << "_TypeAsNumber, 0, sizeof(PyNumberMethods));" << endl; foreach (const QString& nbName, m_nbFuncs.keys()) { if (nb[nbName].isEmpty()) continue; @@ -3627,18 +3692,18 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet // bool is special because the field name differs on Python 2 and 3 (nb_nonzero vs nb_bool) // so a shiboken macro is used. if (nbName == "bool") { - s << INDENT << "SBK_NB_BOOL(" << baseName << "_Type.super.as_number) = " << nb[nbName] << ';' << endl; + s << INDENT << "SBK_NB_BOOL(" << baseName << "_TypeAsNumber) = " << nb[nbName] << ';' << endl; } else { bool excludeFromPy3K = nbName == "__div__" || nbName == "__idiv__"; if (excludeFromPy3K) s << "#ifndef IS_PY3K" << endl; - s << INDENT << baseName << "_Type.super.as_number." << m_nbFuncs[nbName] << " = " << nb[nbName] << ';' << endl; + s << INDENT << baseName << "_TypeAsNumber." << m_nbFuncs[nbName] << " = " << nb[nbName] << ';' << endl; if (excludeFromPy3K) s << "#endif" << endl; } } if (!nb["__div__"].isEmpty()) - s << INDENT << baseName << "_Type.super.as_number.nb_true_divide = " << nb["__div__"] << ';' << endl; + s << INDENT << baseName << "_TypeAsNumber.nb_true_divide = " << nb["__div__"] << ';' << endl; } void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass) @@ -3924,6 +3989,7 @@ void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMeta } if (func->ownerClass() && overloadData.hasStaticFunction()) s << "|METH_STATIC"; + s << ", NULL"; } void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads) @@ -4236,28 +4302,28 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m QString enclosingObjectVariable = hasEnclosingClass ? "enclosingClass" : "module"; QString pyTypeName = cpythonTypeName(metaClass); - s << "void init_" << metaClass->qualifiedCppName().replace("::", "_"); + s << "void init_" << fixedCppTypeName(metaClass->qualifiedCppName()); s << "(PyObject* " << enclosingObjectVariable << ")" << endl; s << '{' << endl; if (supportsNumberProtocol(metaClass)) { s << INDENT << "// type has number operators" << endl; writeTypeAsNumberDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_number = &" << pyTypeName << ".super.as_number;" << endl; + s << INDENT << pyTypeName << ".super.ht_type.tp_as_number = &" << pyTypeName << "AsNumber;" << endl; s << endl; } if (supportsSequenceProtocol(metaClass)) { s << INDENT << "// type supports sequence protocol" << endl; writeTypeAsSequenceDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_sequence = &" << pyTypeName << ".super.as_sequence;" << endl; + s << INDENT << pyTypeName << ".super.ht_type.tp_as_sequence = &" << pyTypeName << "AsSequence;" << endl; s << endl; } if (supportsMappingProtocol(metaClass)) { s << INDENT << "// type supports mapping protocol" << endl; writeTypeAsMappingDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_mapping = &" << pyTypeName << ".super.as_mapping;" << endl; + s << INDENT << pyTypeName << ".super.ht_type.tp_as_mapping = &" << pyTypeName << "AsMapping;" << endl; s << endl; } @@ -4268,7 +4334,7 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m // Multiple inheritance QString pyTypeBasesVariable = QString("%1_bases").arg(pyTypeName); const AbstractMetaClassList baseClasses = getBaseClasses(metaClass); - if (metaClass->baseClassNames().size() > 1) { + if (!baseClasses.isEmpty()) { s << INDENT << "PyObject* " << pyTypeBasesVariable << " = PyTuple_Pack(" << baseClasses.size() << ',' << endl; QStringList bases; foreach (const AbstractMetaClass* base, baseClasses) @@ -4296,23 +4362,23 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m if ((avoidProtectedHack() && metaClass->hasProtectedDestructor()) || classTypeEntry->isValue()) dtorClassName = wrapperName(metaClass); s << ", &Shiboken::callCppDestructor< ::" << dtorClassName << " >"; - } else if (metaClass->baseClass() || hasEnclosingClass) { + } else s << ", 0"; - } // Base type - if (metaClass->baseClass()) { + if (metaClass->baseClass()) s << ", (SbkObjectType*)" << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()); - // The other base types - if (metaClass->baseClassNames().size() > 1) - s << ", " << pyTypeBasesVariable; - else if (hasEnclosingClass) - s << ", 0"; - } else if (hasEnclosingClass) { - s << ", 0, 0"; - } + else + s << ", 0"; + // The other base types + if (!baseClasses.isEmpty()) + s << ", " << pyTypeBasesVariable; + else + s << ", 0"; if (hasEnclosingClass) s << ", true"; + else + s << ", false"; s << ")) {" << endl; s << INDENT << "return;" << endl; } @@ -4443,6 +4509,9 @@ void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMeta QString polymorphicExpr = metaClass->typeEntry()->polymorphicIdValue(); s << "static void* " << cpythonBaseName(metaClass) << "_typeDiscovery(void* cptr, SbkObjectType* instanceType)\n{" << endl; + // Avoid warnings: + s << "(void)cptr;" << endl; + s << "(void)instanceType;" << endl; if (!polymorphicExpr.isEmpty()) { polymorphicExpr = polymorphicExpr.replace("%1", " reinterpret_cast< ::" + metaClass->qualifiedCppName() + "*>(cptr)"); @@ -4603,9 +4672,9 @@ void CppGenerator::finishGeneration() if (!shouldGenerate(cls)) continue; - s_classInitDecl << "void init_" << cls->qualifiedCppName().replace("::", "_") << "(PyObject* module);" << endl; + s_classInitDecl << "void init_" << fixedCppTypeName(cls->qualifiedCppName()) << "(PyObject* module);" << endl; - QString defineStr = "init_" + cls->qualifiedCppName().replace("::", "_"); + QString defineStr = "init_" + fixedCppTypeName(cls->qualifiedCppName()); if (cls->enclosingClass() && (cls->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)) defineStr += "(" + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) +"->tp_dict);"; @@ -4703,7 +4772,7 @@ void CppGenerator::finishGeneration() s << "static PyMethodDef " << moduleName() << "_methods[] = {" << endl; s << globalFunctionDecl; - s << INDENT << "{0} // Sentinel" << endl << "};" << endl << endl; + s << INDENT << "{NULL, NULL, 0, NULL} // Sentinel" << endl << "};" << endl << endl; s << "// Classes initialization functions "; s << "------------------------------------------------------------" << endl; diff --git a/generator/shiboken/headergenerator.cpp b/generator/shiboken/headergenerator.cpp index b5fa606..76a4615 100644 --- a/generator/shiboken/headergenerator.cpp +++ b/generator/shiboken/headergenerator.cpp @@ -34,7 +34,7 @@ QString HeaderGenerator::fileNameForClass(const AbstractMetaClass* metaClass) const { - return metaClass->qualifiedCppName().toLower().replace("::", "_") + QLatin1String("_wrapper.h"); + return fixedCppTypeName(metaClass->qualifiedCppName()).toLower() + QLatin1String("_wrapper.h"); } void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const @@ -80,7 +80,7 @@ void HeaderGenerator::generateClass(QTextStream& s, const AbstractMetaClass* met s << licenseComment(); QString wrapperName = HeaderGenerator::wrapperName(metaClass); - QString headerGuard = wrapperName.replace("::", "_").toUpper(); + QString headerGuard = fixedCppTypeName(wrapperName).toUpper(); // Header s << "#ifndef SBK_" << headerGuard << "_H" << endl; diff --git a/generator/shiboken/shibokengenerator.cpp b/generator/shiboken/shibokengenerator.cpp index ab3f594..c57b3e0 100644 --- a/generator/shiboken/shibokengenerator.cpp +++ b/generator/shiboken/shibokengenerator.cpp @@ -283,16 +283,10 @@ const AbstractMetaClass* ShibokenGenerator::getProperEnclosingClassForEnum(const QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const { - if (shouldGenerateCppWrapper(metaClass)) { - QString result = metaClass->name(); - if (metaClass->enclosingClass()) // is a inner class - result.replace("::", "_"); - - result +="Wrapper"; - return result; - } else { + if (shouldGenerateCppWrapper(metaClass)) + return fixedCppTypeName(metaClass->qualifiedCppName()) + "Wrapper"; + else return metaClass->qualifiedCppName(); - } } QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func) @@ -677,7 +671,7 @@ QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type) } else { baseName = "PyObject"; } - return baseName.replace("::", "_"); + return fixedCppTypeName(baseName); } QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass* metaClass) @@ -748,7 +742,7 @@ QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType* type) return fixedCppTypeName(type->typeEntry(), type->cppSignature()); } -static QString _fixedCppTypeName(QString typeName) +QString ShibokenGenerator::fixedCppTypeName(QString typeName) { return typeName.replace(" ", "") .replace(".", "_") @@ -765,7 +759,7 @@ QString ShibokenGenerator::fixedCppTypeName(const TypeEntry* type, QString typeN typeName = type->qualifiedCppName(); if (!(type->codeGeneration() & TypeEntry::GenerateTargetLang)) typeName.prepend(QString("%1_").arg(type->targetLangPackage())); - return _fixedCppTypeName(typeName); + return fixedCppTypeName(typeName); } QString ShibokenGenerator::pythonPrimitiveTypeName(const QString& cppTypeName) @@ -2075,6 +2069,7 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ if (typeString.startsWith("::")) typeString.remove(0, 2); + // Try regular types first QString adjustedTypeName = typeString; QStringList instantiatedTypes; int lpos = typeString.indexOf('<'); @@ -2101,9 +2096,8 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ TypeEntry* typeEntry = TypeDatabase::instance()->findType(adjustedTypeName); - AbstractMetaType* metaType = 0; if (typeEntry) { - metaType = new AbstractMetaType(); + AbstractMetaType* metaType = new AbstractMetaType(); metaType->setTypeEntry(typeEntry); metaType->setIndirections(indirections); metaType->setReference(isReference); @@ -2111,12 +2105,36 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern); foreach (const QString& instantiation, instantiatedTypes) { AbstractMetaType* tmplArgType = buildAbstractMetaTypeFromString(instantiation); + if (!tmplArgType) { + qFatal(qPrintable(QString("Could not find template argument type '%1' in type '%2'. " + "Make sure to use the full C++ name, e.g. 'Namespace::Class'.") + .arg(instantiation).arg(typeSignature)), NULL); + } metaType->addInstantiation(tmplArgType); } metaType->decideUsagePattern(); m_metaTypeFromStringCache.insert(typeSignature, metaType); + return metaType; + } + + // If that fails, and the type is a template instantiation, try the unmodified + // type name, which will match template instantiation types + if (typeString != adjustedTypeName) { + if ((typeEntry = TypeDatabase::instance()->findType(AbstractMetaClass::canonicalizeInstantiationName(typeString)))) { + AbstractMetaType* metaType = new AbstractMetaType(); + metaType->setTypeEntry(typeEntry); + metaType->setIndirections(indirections); + metaType->setReference(isReference); + metaType->setConstant(isConst); + metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern); + metaType->decideUsagePattern(); + m_metaTypeFromStringCache.insert(typeSignature, metaType); + return metaType; + } } - return metaType; + + // Type was not found + return 0; } AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry) @@ -2341,11 +2359,11 @@ QString ShibokenGenerator::convertersVariableName(const QString& moduleName) con static QString processInstantiationsVariableName(const AbstractMetaType* type) { - QString res = QString("_%1").arg(_fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper()); + QString res = QString("_%1").arg(ShibokenGenerator::fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper()); foreach (const AbstractMetaType* instantiation, type->instantiations()) { res += instantiation->isContainer() ? processInstantiationsVariableName(instantiation) - : QString("_%1").arg(_fixedCppTypeName(instantiation->cppSignature()).toUpper()); + : QString("_%1").arg(ShibokenGenerator::fixedCppTypeName(instantiation->cppSignature()).toUpper()); } return res; } @@ -2355,7 +2373,7 @@ QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass* met const AbstractMetaClass* templateBaseClass = metaClass->templateBaseClass(); if (!templateBaseClass) return QString(); - QString base = _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper(); + QString base = fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper(); QString instantiations; foreach (const AbstractMetaType* instantiation, metaClass->templateBaseClassInstantiations()) instantiations += processInstantiationsVariableName(instantiation); @@ -2370,7 +2388,7 @@ QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type) if (trueType->basicAliasedTypeEntry()) type = trueType->basicAliasedTypeEntry(); } - return QString("SBK_%1_IDX").arg(_fixedCppTypeName(type->qualifiedCppName()).toUpper()); + return QString("SBK_%1_IDX").arg(fixedCppTypeName(type->qualifiedCppName()).toUpper()); } QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type) { diff --git a/generator/shiboken/shibokengenerator.h b/generator/shiboken/shibokengenerator.h index adeb734..6ff8da5 100644 --- a/generator/shiboken/shibokengenerator.h +++ b/generator/shiboken/shibokengenerator.h @@ -284,6 +284,7 @@ class ShibokenGenerator : public Generator static QString fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative); static QString fixedCppTypeName(const AbstractMetaType* type); static QString fixedCppTypeName(const TypeEntry* type, QString typeName = QString()); + static QString fixedCppTypeName(QString typeName); static bool isNumber(QString cpythonApiName); static bool isNumber(const TypeEntry* type); diff --git a/libshiboken/CMakeLists.txt b/libshiboken/CMakeLists.txt index c8575e7..20d8909 100644 --- a/libshiboken/CMakeLists.txt +++ b/libshiboken/CMakeLists.txt @@ -48,6 +48,7 @@ target_link_libraries(libshiboken ${SBK_PYTHON_LIBRARIES}) set_target_properties(libshiboken PROPERTIES OUTPUT_NAME "shiboken${shiboken_SUFFIX}${PYTHON_SUFFIX}" VERSION ${libshiboken_VERSION} SOVERSION ${libshiboken_SOVERSION} + INSTALL_NAME_DIR "${LIB_INSTALL_DIR}" DEFINE_SYMBOL LIBSHIBOKEN_EXPORTS) install(FILES diff --git a/libshiboken/autodecref.h b/libshiboken/autodecref.h index 5de614c..bc60bd0 100644 --- a/libshiboken/autodecref.h +++ b/libshiboken/autodecref.h @@ -26,7 +26,7 @@ #include "sbkpython.h" #include "shibokenmacros.h" -class SbkObject; +struct SbkObject; namespace Shiboken { diff --git a/libshiboken/conversions.h b/libshiboken/conversions.h index 8b58886..f4fd4a7 100644 --- a/libshiboken/conversions.h +++ b/libshiboken/conversions.h @@ -141,8 +141,8 @@ struct Converter template<> struct Converter { - static inline bool checkType(PyObject* pyObj) { return false; } - static inline bool isConvertible(PyObject* pyobj) { return true; } + static inline bool checkType(PyObject*) { return false; } + static inline bool isConvertible(PyObject*) { return true; } static PyObject* toPython(void* cppobj) { if (!cppobj) @@ -291,7 +291,7 @@ struct OverFlowChecker template<> struct OverFlowChecker { - static bool check(const PY_LONG_LONG& value) + static bool check(const PY_LONG_LONG&) { return false; } @@ -300,7 +300,7 @@ struct OverFlowChecker template<> struct OverFlowChecker { - static bool check(const double& value) + static bool check(const double&) { return false; } diff --git a/shibokenmodule/CMakeLists.txt b/shibokenmodule/CMakeLists.txt index 41b20cd..acdf071 100644 --- a/shibokenmodule/CMakeLists.txt +++ b/shibokenmodule/CMakeLists.txt @@ -22,6 +22,11 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} add_library(shibokenmodule MODULE ${sample_SRC}) set_property(TARGET shibokenmodule PROPERTY PREFIX "") set_property(TARGET shibokenmodule PROPERTY OUTPUT_NAME "shiboken") + +option(SET_RPATH "Set the rvalue to be the origin (used in UNIX)." FALSE) +if(UNIX AND NOT APPLE AND SET_RPATH) + set_property(TARGET shibokenmodule PROPERTY INSTALL_RPATH "\$ORIGIN") +endif() if(WIN32) set_property(TARGET shibokenmodule PROPERTY SUFFIX ".pyd") endif() @@ -31,4 +36,4 @@ target_link_libraries(shibokenmodule add_dependencies(shibokenmodule shiboken) -install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}) \ No newline at end of file +install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}) diff --git a/tests/libsample/CMakeLists.txt b/tests/libsample/CMakeLists.txt index 30205ed..2788f82 100644 --- a/tests/libsample/CMakeLists.txt +++ b/tests/libsample/CMakeLists.txt @@ -31,6 +31,7 @@ pairuser.cpp pen.cpp photon.cpp point.cpp +pointer.cpp pointf.cpp polygon.cpp protected.cpp diff --git a/tests/libsample/cvlist.h b/tests/libsample/cvlist.h new file mode 100644 index 0000000..77b7eca --- /dev/null +++ b/tests/libsample/cvlist.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Shiboken Python Binding Generator project. + * + * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef CONSTVALUELIST_H +#define CONSTVALUELIST_H + +#include +#include "libsamplemacros.h" + +class CVValueType +{ + CVValueType(); +}; + +typedef std::list const_ptr_value_list; + +// This tests binding generation for a container of a const value type. The +// class doesn't need to do anything; this is just to verify that the generated +// binding code (the container conversion in particular) is const-valid. + +class CVListUser +{ +public: + static const_ptr_value_list produce() { return const_ptr_value_list(); } + static void consume(const const_ptr_value_list& l) { (void)l; } +}; + +#endif // LIST_H diff --git a/tests/libsample/handle.h b/tests/libsample/handle.h index 403fc54..d010d01 100644 --- a/tests/libsample/handle.h +++ b/tests/libsample/handle.h @@ -42,7 +42,7 @@ class LIBSAMPLE_API HandleHolder explicit HandleHolder(HANDLE ptr = 0) : m_handle(ptr) {} explicit HandleHolder(Foo::HANDLE val): m_handle2(val) {} - inline void set(HANDLE ptr) { m_handle = m_handle; } + inline void set(HANDLE ptr) { m_handle = ptr; } inline void set(const Foo::HANDLE& val) { m_handle2 = val; } inline HANDLE handle() { return m_handle; } inline Foo::HANDLE handle2() { return m_handle2; } diff --git a/tests/libsample/photon.cpp b/tests/libsample/photon.cpp index b1b3328..ae2031c 100644 --- a/tests/libsample/photon.cpp +++ b/tests/libsample/photon.cpp @@ -24,6 +24,9 @@ namespace Photon { +const ClassType Base::staticType; +template <> const ClassType TemplateBase::staticType; +template <> const ClassType TemplateBase::staticType; int callCalculateForValueDuplicatorPointer(ValueDuplicator* value) { return value->calculate(); diff --git a/tests/libsample/photon.h b/tests/libsample/photon.h index f6c97b7..4662f36 100644 --- a/tests/libsample/photon.h +++ b/tests/libsample/photon.h @@ -33,6 +33,7 @@ namespace Photon { enum ClassType { + BaseType = 0, IdentityType = 1, DuplicatorType = 2 }; @@ -41,8 +42,16 @@ class LIBSAMPLE_API Base { public: explicit Base(int value) : m_value(value) {} + virtual ~Base() {} inline void setValue(int value) { m_value = value; } inline int value() const { return m_value; } + + template bool isType() { return type() == T::staticType; } + bool isType(ClassType t) { return type() == t; } + + virtual ClassType type() const { return BaseType; }; + static const ClassType staticType = BaseType; + protected: int m_value; }; @@ -68,6 +77,9 @@ class LIBSAMPLE_API TemplateBase : public Base } static inline TemplateBase* passPointerThrough(TemplateBase* obj) { return obj; } + + virtual ClassType type() const { return CLASS_TYPE; } + static const ClassType staticType = CLASS_TYPE; }; #if defined _WIN32 || defined __CYGWIN__ @@ -83,6 +95,38 @@ LIBSAMPLE_API int callCalculateForValueDuplicatorReference(ValueDuplicator& valu LIBSAMPLE_API int countValueIdentities(const std::list& values); LIBSAMPLE_API int countValueDuplicators(const std::list >& values); +// This simulates an internal error (SEGV) caused by 'noexcept' in +// boost::intrusive_ptr before support for 'noexcept' was added. The ENTIRE +// code below is needed to trigger the exception; it isn't seen with just a +// 'noexcept' following a declaration. +// +// NOTE: For reasons that should be fairly obvious, this test unfortunately can +// only be "run" when building in C++11 mode. +#if __cplusplus < 201103L +#define noexcept +#endif +class Pointer +{ +public: + Pointer() noexcept : px(0) {} + Pointer(int* p) : px(p) {} + + void reset() noexcept { Pointer().swap(*this); } + + int* get() const noexcept { return px; } + int& operator*() const { return *px; } + + void swap(Pointer& rhs) noexcept + { + int* tmp = px; + px = rhs.px; + rhs.px = tmp; + } + +private: + int* px; +}; + } // namespace Photon #endif // PHOTON_H diff --git a/tests/libsample/pointer.cpp b/tests/libsample/pointer.cpp new file mode 100644 index 0000000..646d539 --- /dev/null +++ b/tests/libsample/pointer.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2013 Kitware, Inc. + * + * This file is part of the Shiboken Python Binding Generator project. + * + * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "pointer.h" + +static int nextId = 0; +static int counter = 0; + +SimpleObject::SimpleObject(int id) : m_id(id) +{ + ++counter; +} + +SimpleObject::~SimpleObject() +{ + --counter; +} + +Pointer SimpleObject::create() +{ + return Pointer(new SimpleObject(++nextId)); +} + +int SimpleObject::count() +{ + return counter; +} + +std::list PointerNamespace::NamespaceObject::numbers(int first, int count) const +{ + std::list result; + while (count--) + result.push_back(first++); + return result; +} + +PointerNamespace::NamespaceObjectPointer PointerNamespace::createNamespaceObject() +{ + return NamespaceObjectPointer(new NamespaceObject); +} + +PointerNamespace::InheritNamespaceObjectPointer PointerNamespace::createInheritNamespaceObject() +{ + return InheritNamespaceObjectPointer(new InheritNamespaceObject); +} + +std::list PointerHelper::numbers(const PointerNamespace::NamespaceObjectPointer& ptr, int first, int count) +{ + return ptr.get()->numbers(first, count); +} + +std::list PointerHelper::numbers(const PointerNamespace::PointerNamespaceObjectAlias& obj, int first, int count) +{ + return obj.numbers(first, count); +} diff --git a/tests/libsample/pointer.h b/tests/libsample/pointer.h new file mode 100644 index 0000000..59c5a45 --- /dev/null +++ b/tests/libsample/pointer.h @@ -0,0 +1,148 @@ +/* + * Copyright 2013 Kitware, Inc. + * + * This file is part of the Shiboken Python Binding Generator project. + * + * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef POINTER_H +#define POINTER_H + +#include + +#include "libsamplemacros.h" + +template +class Pointer +{ +public: + Pointer() : m_obj(0), m_ref(0) {} + + explicit Pointer(T *obj) : m_obj(obj), m_ref(new int) + { + *m_ref = 1; + } + + Pointer(const Pointer &other) : m_obj(other.m_obj), m_ref(other.m_ref) + { + ++(*m_ref); + } + + Pointer& operator=(const Pointer &other) + { + release(); + m_obj = other.m_obj; + m_ref = other.m_ref; + ++(*m_ref); + return *this; + } + + virtual ~Pointer() + { + release(); + } + + inline T* get() const { return m_obj; } + +private: + void release() + { + if (m_ref && --(*m_ref) <= 0) { + delete m_obj; + delete m_ref; + } + } + + T *m_obj; + int *m_ref; +}; + +class SimpleObjectBase +{ +public: + inline int square(int value) { return value * value; } + +protected: + SimpleObjectBase() {} +}; + +class SimpleObject; +typedef Pointer SimpleObjectPointer; + +class LIBSAMPLE_API SimpleObject : public SimpleObjectBase +{ +public: + ~SimpleObject(); + + inline int id() const { return m_id; } + + static Pointer create(); + static SimpleObjectPointer createAliased() { return create(); } + static int count(); + +private: + SimpleObject(int); + + int m_id; +}; + +namespace PointerNamespace +{ + +template class Pointer +{ +public: + Pointer() {} + Pointer(T* obj) : m_ptr(obj) {} + inline T* get() const { return m_ptr.get(); } + +private: + ::Pointer m_ptr; +}; + +class LIBSAMPLE_API NamespaceObject +{ +public: + ::std::list numbers(int first, int count) const; +}; + +class LIBSAMPLE_API InheritNamespaceObject : public NamespaceObject +{ +}; + +typedef Pointer NamespaceObjectPointer; +typedef Pointer InheritNamespaceObjectPointer; +typedef NamespaceObject PointerNamespaceObjectAlias; +typedef InheritNamespaceObject PointerInheritNamespaceObjectAlias; + +LIBSAMPLE_API NamespaceObjectPointer createNamespaceObject(); +LIBSAMPLE_API InheritNamespaceObjectPointer createInheritNamespaceObject(); + +} + +class LIBSAMPLE_API PointerHelper +{ +public: + static ::std::list numbers(const PointerNamespace::NamespaceObjectPointer& ptr, int first, int count); + static ::std::list numbers(const PointerNamespace::PointerNamespaceObjectAlias& obj, int first, int count); +}; + +#endif // POINTER_H + diff --git a/tests/libsample/simplefile.cpp b/tests/libsample/simplefile.cpp index deac166..3eda2ad 100644 --- a/tests/libsample/simplefile.cpp +++ b/tests/libsample/simplefile.cpp @@ -90,13 +90,13 @@ bool SimpleFile::exists() const { std::ifstream ifile(p->m_filename); - return ifile; + return ifile.is_open(); } bool SimpleFile::exists(const char* filename) { std::ifstream ifile(filename); - return ifile; + return ifile.is_open(); } diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index 23ff63c..673fd56 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -19,6 +19,8 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/bucket_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/collector_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/color_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/ctorconvrule_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/cvlistuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/cvvaluetype_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/sbkdate_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/derived_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/derived_someinnerclass_wrapper.cpp @@ -69,6 +71,13 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/photon_base_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueidentity_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueduplicator_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/point_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointer_simpleobject__wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_namespaceobject_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_pointer_pointernamespace_namespaceobject__wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_inheritnamespaceobject_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_pointer_pointernamespace_inheritnamespaceobject__wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointerhelper_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointerholder_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointf_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointvaluelist_wrapper.cpp @@ -97,6 +106,8 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someotherinnerclass ${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_derivedfromnamespace_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/simplefile_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/simpleobject_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/simpleobjectbase_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/size_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/sizef_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/sonofmderived1_wrapper.cpp diff --git a/tests/samplebinding/global.h b/tests/samplebinding/global.h index 28bac0a..5e204e9 100644 --- a/tests/samplebinding/global.h +++ b/tests/samplebinding/global.h @@ -5,6 +5,7 @@ #include "collector.h" #include "complex.h" #include "ctorconvrule.h" +#include "cvlist.h" #include "sbkdate.h" #include "derived.h" #include "echo.h" @@ -38,6 +39,7 @@ #include "photon.h" #include "point.h" #include "pointf.h" +#include "pointer.h" #include "pointerholder.h" #include "polygon.h" #include "privatector.h" diff --git a/tests/samplebinding/pointer_test.py b/tests/samplebinding/pointer_test.py new file mode 100644 index 0000000..6c46db5 --- /dev/null +++ b/tests/samplebinding/pointer_test.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2013 Kitware, Inc. +# +# This file is part of the Shiboken Python Bindings Generator project. +# +# Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +# +# Contact: PySide team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# version 2.1 as published by the Free Software Foundation. Please +# review the following information to ensure the GNU Lesser General +# Public License version 2.1 requirements will be met: +# http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +# # +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +'''Test cases for a template pointer class.''' + +import sys +import unittest + +from sample import SimpleObject, PointerNamespace, PointerHelper + +class TestPointer(unittest.TestCase): + '''Test cases for a template pointer class.''' + + def testRedirection(self): + '''Test method redirection on template pointer class.''' + o1 = SimpleObject.create() + o2 = SimpleObject.create() + self.assertGreater(o2.id(), o1.id()) + self.assertEqual(o1.square(2), 4) + + def testAddedMethods(self): + '''Test method redirection on template pointer class.''' + o = SimpleObject.create() + self.assertEqual(type(o.get()), SimpleObject) + self.assertEqual(type(o.template_get()), SimpleObject) + self.assertTrue(o.valid()) + + def testReferenceCounting(self): + '''Test basic wrapping of template pointer class.''' + o1 = SimpleObject.create() + o2 = SimpleObject.create() + self.assertEqual(SimpleObject.count(), 2) + del o1 + self.assertEqual(SimpleObject.count(), 1) + del o2 + self.assertEqual(SimpleObject.count(), 0) + + def testTypeAlias(self): + '''Test that typedef of type template instantiation is recognized.''' + o1 = SimpleObject.create() + o2 = SimpleObject.createAliased() + self.assertEqual(type(o1), type(o2)) + + def testTypeAlias(self): + '''Test type resolution for some namespace corner cases.''' + o = PointerNamespace.createNamespaceObject() + o.numbers + PointerHelper.numbers(o, 1, 3) + PointerHelper.numbers(o.get(), 4, 2) + + def testInheritMethods(self): + '''Test method redirection on template pointer class to inherited methods.''' + o = PointerNamespace.createInheritNamespaceObject() + # Test that base class members are available. + o.numbers(1, 2) + # Test that the raw pointer downcast is implicit. + PointerHelper.numbers(o.get(), 4, 2) + # Test that the wrapping pointer downcast is implicit as well. + PointerHelper.numbers(o, 1, 3) + +if __name__ == '__main__': + unittest.main() + diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 233a756..eb3768f 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -600,6 +600,11 @@ + + + + + @@ -2384,16 +2389,68 @@ - - - - - + + + + + + + %RETURN_TYPE %0 = %CPPSELF->get(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + %INTYPE_0* ptr = %CPPSELF->get(); + %RETURN_TYPE %0 = !!ptr; + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + %RETURN_TYPE %0 = %CPPSELF->get(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + + + + + + + + + %RETURN_TYPE %0 = %CPPSELF->get(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + + + %RETURN_TYPE %0 = %CPPSELF->get(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + +