aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2021-02-12 11:39:36 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2021-03-01 16:28:48 +0100
commit2107b9c16d7be1292c5439a47ed31871906e0b1f (patch)
tree64447316e8885d4bcf3a45c6657eb7372c60c67c /sources/shiboken6
parentc6f4d907190dbd66d09db7d4809c06f1b3e48ec2 (diff)
shiboken6: Add constructors of base classes imported via "using"
Parse "using" declarations in the clang builder using some code from the base class determination algorithm. Resolve them to struct UsingMember containing the base class and the member name in the metabuilder and check whether any base constructors are imported via "using". Add them as functions like the default constructor. Change-Id: I121a70f0591c6d1e6f9daedfb653206c49c07a3f Reviewed-by: Christian Tismer <tismer@stackless.com> Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/shiboken6')
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp29
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h2
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang.cpp104
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang.h9
-rw-r--r--sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h2
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp78
-rw-r--r--sources/shiboken6/ApiExtractor/messages.cpp11
-rw-r--r--sources/shiboken6/ApiExtractor/messages.h4
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel.cpp15
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel.h12
-rw-r--r--sources/shiboken6/ApiExtractor/parser/codemodel_enums.h4
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp43
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h1
-rw-r--r--sources/shiboken6/ApiExtractor/usingmember.h46
-rw-r--r--sources/shiboken6/tests/libsample/CMakeLists.txt2
-rw-r--r--sources/shiboken6/tests/libsample/ctparam.cpp45
-rw-r--r--sources/shiboken6/tests/libsample/ctparam.h51
-rw-r--r--sources/shiboken6/tests/libsample/derivedusingct.cpp34
-rw-r--r--sources/shiboken6/tests/libsample/derivedusingct.h42
-rw-r--r--sources/shiboken6/tests/samplebinding/CMakeLists.txt2
-rw-r--r--sources/shiboken6/tests/samplebinding/derived_test.py8
-rw-r--r--sources/shiboken6/tests/samplebinding/global.h2
-rw-r--r--sources/shiboken6/tests/samplebinding/typesystem_sample.xml4
23 files changed, 525 insertions, 25 deletions
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
index 9fe80f084..b09682e93 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp
@@ -37,6 +37,7 @@
#include "sourcelocation.h"
#include "typedatabase.h"
#include "typesystem.h"
+#include "usingmember.h"
#include "parser/codemodel.h"
@@ -485,6 +486,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) {
if (cls->needsInheritanceSetup()) {
setupInheritance(cls);
+ traverseUsingMembers(cls);
if (cls->templateBaseClass())
inheritTemplateFunctions(cls);
if (!cls->hasVirtualDestructor() && cls->baseClass()
@@ -608,6 +610,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
}
m_itemToClass.clear();
+ m_classToItem.clear();
m_typeSystemTypeDefs.clear();
ReportHandler::endProgress();
@@ -640,6 +643,7 @@ void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls,
const _CodeModelItem *item)
{
m_itemToClass.insert(item, cls);
+ m_classToItem.insert(cls, item);
if (cls->typeEntry()->isContainer()) {
m_templates << cls;
} else if (cls->typeEntry()->isSmartPointer()) {
@@ -1055,6 +1059,31 @@ void AbstractMetaBuilderPrivate::traverseClassMembers(const ClassModelItem &item
traverseScopeMembers(item, metaClass);
}
+void AbstractMetaBuilderPrivate::traverseUsingMembers(AbstractMetaClass *metaClass)
+{
+ const _CodeModelItem *item = m_classToItem.value(metaClass);
+ if (item == nullptr || item->kind() != _CodeModelItem::Kind_Class)
+ return;
+ auto classItem = static_cast<const _ClassModelItem *>(item);
+ for (const auto &um : classItem->usingMembers()) {
+ QString className = um.className;
+ int pos = className.indexOf(u'<'); // strip "QList<value>"
+ if (pos != -1)
+ className.truncate(pos);
+ if (auto baseClass = metaClass->AbstractMetaClass::findBaseClass(className)) {
+ QString name = um.memberName;
+ const int lastQualPos = name.lastIndexOf(colonColon());
+ if (lastQualPos != -1)
+ name.remove(0, lastQualPos + 2);
+ metaClass->addUsingMember({name, baseClass, um.access});
+ } else {
+ qCWarning(lcShiboken, "%s",
+ qPrintable(msgUsingMemberClassNotFound(metaClass, um.className,
+ um.memberName)));
+ }
+ }
+}
+
void AbstractMetaBuilderPrivate::traverseNamespaceMembers(const NamespaceModelItem &item)
{
AbstractMetaClass *metaClass = m_itemToClass.value(item.data());
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
index e7e6f8e10..6256d078c 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder_p.h
@@ -90,6 +90,7 @@ public:
AbstractMetaClass *currentClass);
void traverseScopeMembers(const ScopeModelItem &item, AbstractMetaClass *metaClass);
void traverseClassMembers(const ClassModelItem &scopeItem);
+ void traverseUsingMembers(AbstractMetaClass *metaClass);
void traverseNamespaceMembers(const NamespaceModelItem &scopeItem);
bool setupInheritance(AbstractMetaClass *metaClass);
AbstractMetaClass *traverseNamespace(const FileModelItem &dom,
@@ -198,6 +199,7 @@ public:
AbstractMetaClassList m_templates;
AbstractMetaClassList m_smartPointers;
QHash<const _CodeModelItem *, AbstractMetaClass *> m_itemToClass;
+ QHash<const AbstractMetaClass *, const _CodeModelItem *> m_classToItem;
AbstractMetaFunctionCList m_globalFunctions;
AbstractMetaEnumList m_globalEnums;
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang.cpp b/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
index 564975963..cd3209c0f 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang.cpp
@@ -39,6 +39,7 @@
#include "sourcelocation.h"
#include "typedatabase.h"
#include "typesystem.h"
+#include "usingmember.h"
#include <QtCore/QDebug>
@@ -77,6 +78,10 @@ public:
Access access,
const AbstractMetaArgumentList &arguments,
AbstractMetaClass *q);
+ void addUsingConstructors(AbstractMetaClass *q);
+ bool isUsingMember(const AbstractMetaClass *c, const QString &memberName,
+ Access minimumAccess) const;
+ bool hasConstructors() const;
uint m_hasVirtuals : 1;
uint m_isPolymorphic : 1;
@@ -118,6 +123,7 @@ public:
TypeEntries m_templateArgs;
ComplexTypeEntry *m_typeEntry = nullptr;
SourceLocation m_sourceLocation;
+ UsingMembers m_usingMembers;
mutable AbstractMetaClass::CppWrapper m_cachedWrapper;
AbstractMetaClass::Attributes m_attributes;
@@ -751,12 +757,17 @@ bool AbstractMetaClass::deleteInMainThread() const
|| (!d->m_baseClasses.isEmpty() && d->m_baseClasses.constFirst()->deleteInMainThread());
}
-bool AbstractMetaClass::hasConstructors() const
+bool AbstractMetaClassPrivate::hasConstructors() const
{
- return AbstractMetaClass::queryFirstFunction(d->m_functions,
+ return AbstractMetaClass::queryFirstFunction(m_functions,
FunctionQueryOption::Constructors) != nullptr;
}
+bool AbstractMetaClass::hasConstructors() const
+{
+ return d->hasConstructors();
+}
+
AbstractMetaFunctionCPtr AbstractMetaClass::copyConstructor() const
{
for (const auto &f : d->m_functions) {
@@ -1024,6 +1035,34 @@ AbstractMetaClass::CppWrapper AbstractMetaClass::cppWrapper() const
return d->m_cachedWrapper;
}
+const UsingMembers &AbstractMetaClass::usingMembers() const
+{
+ return d->m_usingMembers;
+}
+
+void AbstractMetaClass::addUsingMember(const UsingMember &um)
+{
+ d->m_usingMembers.append(um);
+}
+
+bool AbstractMetaClassPrivate::isUsingMember(const AbstractMetaClass *c,
+ const QString &memberName,
+ Access minimumAccess) const
+{
+ auto it = std::find_if(m_usingMembers.cbegin(), m_usingMembers.cend(),
+ [c, &memberName](const UsingMember &um) {
+ return um.baseClass == c && um.memberName == memberName;
+ });
+ return it != m_usingMembers.cend() && it->access >= minimumAccess;
+}
+
+bool AbstractMetaClass::isUsingMember(const AbstractMetaClass *c,
+ const QString &memberName,
+ Access minimumAccess) const
+{
+ return d->isUsingMember(c, memberName, minimumAccess);
+}
+
/* Goes through the list of functions and returns a list of all
functions matching all of the criteria in \a query.
*/
@@ -1281,6 +1320,34 @@ static bool addSuperFunction(const AbstractMetaFunctionCPtr &f)
return true;
}
+// Add constructors imported via "using" from the base classes. This is not
+// needed for normal hidden inherited member functions since we generate a
+// cast to the base class to call them into binding code.
+void AbstractMetaClassPrivate::addUsingConstructors(AbstractMetaClass *q)
+{
+ // Restricted to the non-constructor case currently to avoid
+ // having to compare the parameter lists of existing constructors.
+ if (m_baseClasses.isEmpty() || m_usingMembers.isEmpty()
+ || hasConstructors()) {
+ return;
+ }
+
+ for (auto superClass : m_baseClasses) {
+ // Find any "using base-constructor" directives
+ if (isUsingMember(superClass, superClass->name(), Access::Protected)) {
+ // Add to derived class with parameter lists.
+ const auto ctors = superClass->queryFunctions(FunctionQueryOption::Constructors);
+ for (const auto &ctor : ctors) {
+ if (ctor->functionType() == AbstractMetaFunction::ConstructorFunction
+ && !ctor->isPrivate()) {
+ addConstructor(AbstractMetaFunction::ConstructorFunction,
+ ctor->access(), ctor->arguments(), q);
+ }
+ }
+ }
+ }
+}
+
void AbstractMetaClass::fixFunctions()
{
if (d->m_functionsFixed)
@@ -1291,6 +1358,9 @@ void AbstractMetaClass::fixFunctions()
AbstractMetaFunctionCList funcs = functions();
AbstractMetaFunctionCList nonRemovedFuncs;
nonRemovedFuncs.reserve(funcs.size());
+
+ d->addUsingConstructors(this);
+
for (const auto &f : qAsConst(funcs)) {
// Fishy: Setting up of implementing/declaring/base classes changes
// the applicable modifications; clear cached ones.
@@ -1611,6 +1681,17 @@ const AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassCLi
return nullptr;
}
+const AbstractMetaClass *AbstractMetaClass::findBaseClass(const QString &qualifiedName) const
+{
+ if (d->m_templateBaseClass != nullptr
+ && d->m_templateBaseClass->qualifiedCppName() == qualifiedName) {
+ return d->m_templateBaseClass;
+ }
+ return recurseClassHierarchy(this, [&qualifiedName](const AbstractMetaClass *c) {
+ return c->qualifiedCppName() == qualifiedName;
+ });
+}
+
// Query functions for generators
bool AbstractMetaClass::isObjectType() const
{
@@ -1675,6 +1756,15 @@ void AbstractMetaClass::format(QDebug &debug) const
for (auto b : d->m_baseClasses)
debug << " \"" << b->name() << '"';
}
+
+ if (const qsizetype count = d->m_usingMembers.size()) {
+ for (qsizetype i = 0; i < count; ++i) {
+ if (i)
+ debug << ", ";
+ debug << d->m_usingMembers.at(i);
+ }
+ }
+
if (auto templateBase = templateBaseClass()) {
const auto &instantiatedTypes = templateBaseClassInstantiations();
debug << ", instantiates \"" << templateBase->name();
@@ -1728,6 +1818,16 @@ void AbstractMetaClass::setSourceLocation(const SourceLocation &sourceLocation)
d->m_sourceLocation = sourceLocation;
}
+QDebug operator<<(QDebug debug, const UsingMember &d)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "UsingMember(" << d.access << ' '
+ << d.baseClass->qualifiedCppName() << "::" << d.memberName << ')';
+ return debug;
+}
+
QDebug operator<<(QDebug d, const AbstractMetaClass *ac)
{
QDebugStateSaver saver(d);
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang.h b/sources/shiboken6/ApiExtractor/abstractmetalang.h
index b599a82cd..eab7969a6 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetalang.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang.h
@@ -41,12 +41,14 @@
QT_FORWARD_DECLARE_CLASS(QDebug)
+enum class Access;
class AbstractMetaClassPrivate;
class ComplexTypeEntry;
class Documentation;
class EnumTypeEntry;
class QPropertySpec;
class SourceLocation;
+struct UsingMember;
class AbstractMetaClass : public EnclosingClassMixin
{
@@ -136,6 +138,11 @@ public:
CppWrapper cppWrapper() const;
+ const UsingMembers &usingMembers() const;
+ void addUsingMember(const UsingMember &um);
+ bool isUsingMember(const AbstractMetaClass *c, const QString &memberName,
+ Access minimumAccess) const;
+
AbstractMetaFunctionCList queryFunctionsByName(const QString &name) const;
static bool queryFunction(const AbstractMetaFunction *f, FunctionQueryOptions query);
static AbstractMetaFunctionCList queryFunctionList(const AbstractMetaFunctionCList &list,
@@ -343,6 +350,8 @@ public:
const TypeEntry* typeEntry);
static const AbstractMetaClass *findClass(const AbstractMetaClassCList &classes,
const TypeEntry* typeEntry);
+ const AbstractMetaClass *findBaseClass(const QString &qualifiedName) const;
+
static std::optional<AbstractMetaEnumValue> findEnumValue(const AbstractMetaClassList &classes,
const QString &string);
static std::optional<AbstractMetaEnum> findEnum(const AbstractMetaClassList &classes,
diff --git a/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h b/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h
index 66e6e467f..cdfcdab1e 100644
--- a/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h
+++ b/sources/shiboken6/ApiExtractor/abstractmetalang_typedefs.h
@@ -39,6 +39,7 @@ class AbstractMetaEnum;
class AbstractMetaEnumValue;
class AbstractMetaFunction;
class AbstractMetaType;
+struct UsingMember;
using AbstractMetaFunctionPtr = QSharedPointer<AbstractMetaFunction>;
using AbstractMetaFunctionCPtr = QSharedPointer<const AbstractMetaFunction>;
@@ -52,5 +53,6 @@ using AbstractMetaFieldList = QList<AbstractMetaField>;
using AbstractMetaFunctionRawPtrList = QList<AbstractMetaFunction *>;
using AbstractMetaFunctionCList = QList<AbstractMetaFunctionCPtr>;
using AbstractMetaTypeList = QList<AbstractMetaType>;
+using UsingMembers = QList<UsingMember>;
#endif // ABSTRACTMETALANG_TYPEDEFS_H
diff --git a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp
index 2970507ec..de0f2eb4f 100644
--- a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp
+++ b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp
@@ -196,6 +196,7 @@ public:
void addField(const CXCursor &cursor);
static QString cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor);
+ QString getBaseClassName(CXType type) const;
void addBaseClass(const CXCursor &cursor);
template <class Item>
@@ -227,6 +228,8 @@ public:
TemplateTypeAliasModelItem m_currentTemplateTypeAlias;
QByteArrayList m_systemIncludes; // files, like "memory"
QByteArrayList m_systemIncludePaths; // paths, like "/usr/include/Qt/"
+ QString m_usingTypeRef; // Base classes in "using Base::member;"
+ bool m_withinUsingDeclaration = false;
int m_anonymousEnumCount = 0;
CodeModel::FunctionType m_currentFunctionType = CodeModel::Normal;
@@ -670,7 +673,7 @@ QString BuilderPrivate::cursorValueExpression(BaseVisitor *bv, const CXCursor &c
qsizetype(snippet.size() - equalSign)).trimmed();
}
-// Resolve declaration and type of a base class
+// Resolve a type (loop over aliases/typedefs), for example for base classes
struct TypeDeclaration
{
@@ -678,30 +681,28 @@ struct TypeDeclaration
CXCursor declaration;
};
-static TypeDeclaration resolveBaseSpecifier(const CXCursor &cursor)
+static TypeDeclaration resolveType(CXType type)
{
- Q_ASSERT(clang_getCursorKind(cursor) == CXCursor_CXXBaseSpecifier);
- CXType inheritedType = clang_getCursorType(cursor);
- CXCursor decl = clang_getTypeDeclaration(inheritedType);
- if (inheritedType.kind != CXType_Unexposed) {
+ CXCursor decl = clang_getTypeDeclaration(type);
+ if (type.kind != CXType_Unexposed) {
while (true) {
auto kind = clang_getCursorKind(decl);
if (kind != CXCursor_TypeAliasDecl && kind != CXCursor_TypedefDecl)
break;
- inheritedType = clang_getTypedefDeclUnderlyingType(decl);
- decl = clang_getTypeDeclaration(inheritedType);
+ type = clang_getTypedefDeclUnderlyingType(decl);
+ decl = clang_getTypeDeclaration(type);
}
}
- return {inheritedType, decl};
+ return {type, decl};
}
-// Add a base class to the current class from CXCursor_CXXBaseSpecifier
-void BuilderPrivate::addBaseClass(const CXCursor &cursor)
+// Note: Return the baseclass for cursors like CXCursor_CXXBaseSpecifier,
+// where the cursor spelling has "struct baseClass".
+QString BuilderPrivate::getBaseClassName(CXType type) const
{
- Q_ASSERT(clang_getCursorKind(cursor) == CXCursor_CXXBaseSpecifier);
+ const auto decl = resolveType(type);
// Note: spelling has "struct baseClass", use type
QString baseClassName;
- const auto decl = resolveBaseSpecifier(cursor);
if (decl.type.kind == CXType_Unexposed) {
// The type is unexposed when the base class is a template type alias:
// "class QItemSelection : public QList<X>" where QList is aliased to QVector.
@@ -716,13 +717,12 @@ void BuilderPrivate::addBaseClass(const CXCursor &cursor)
baseClassName = getTypeName(decl.type);
auto it = m_cursorClassHash.constFind(decl.declaration);
- const Access access = accessPolicy(clang_getCXXAccessSpecifier(cursor));
- if (it == m_cursorClassHash.constEnd()) {
- // Set unqualified name. This happens in cases like "class X : public std::list<...>"
- // "template<class T> class Foo : public T" and standard types like true_type, false_type.
- m_currentClass->addBaseClass(baseClassName, access);
- return;
- }
+ // Not found: Set unqualified name. This happens in cases like
+ // "class X : public std::list<...>", "template<class T> class Foo : public T"
+ // and standard types like true_type, false_type.
+ if (it == m_cursorClassHash.constEnd())
+ return baseClassName;
+
// Completely qualify the class name by looking it up and taking its scope
// plus the actual baseClass stripped off any scopes. Consider:
// namespace std {
@@ -741,6 +741,15 @@ void BuilderPrivate::addBaseClass(const CXCursor &cursor)
baseClassName.prepend(colonColon());
baseClassName.prepend(baseScope.join(colonColon()));
}
+ return baseClassName;
+}
+
+// Add a base class to the current class from CXCursor_CXXBaseSpecifier
+void BuilderPrivate::addBaseClass(const CXCursor &cursor)
+{
+ Q_ASSERT(clang_getCursorKind(cursor) == CXCursor_CXXBaseSpecifier);
+ const auto access = accessPolicy(clang_getCXXAccessSpecifier(cursor));
+ QString baseClassName = getBaseClassName(clang_getCursorType(cursor));
m_currentClass->addBaseClass(baseClassName, access);
}
@@ -1173,6 +1182,15 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
return Skip;
}
break;
+ // Using declarations look as follows:
+ // 1) Normal, non-template case ("using QObject::parent"): UsingDeclaration, TypeRef
+ // 2) Simple template case ("using QList::append()"): UsingDeclaration, TypeRef "QList<T>"
+ // 3) Template case with parameters ("using QList<T>::append()"):
+ // UsingDeclaration, TemplateRef "QList", TypeRef "T"
+ case CXCursor_TemplateRef:
+ if (d->m_withinUsingDeclaration && d->m_usingTypeRef.isEmpty())
+ d->m_usingTypeRef = getCursorSpelling(cursor);
+ break;
case CXCursor_TypeRef:
if (!d->m_currentFunction.isNull()) {
if (d->m_currentArgument.isNull())
@@ -1181,6 +1199,8 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
d->qualifyTypeDef(cursor, d->m_currentArgument);
} else if (!d->m_currentField.isNull()) {
d->qualifyTypeDef(cursor, d->m_currentField);
+ } else if (d->m_withinUsingDeclaration && d->m_usingTypeRef.isEmpty()) {
+ d->m_usingTypeRef = d->getBaseClassName(clang_getCursorType(cursor));
}
break;
case CXCursor_CXXFinalAttr:
@@ -1206,6 +1226,20 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
}
}
break;
+ // UsingDeclaration: consists of a TypeRef (base) and OverloadedDeclRef (member name)
+ case CXCursor_UsingDeclaration:
+ if (!d->m_currentClass.isNull())
+ d->m_withinUsingDeclaration = true;
+ break;
+ case CXCursor_OverloadedDeclRef:
+ if (d->m_withinUsingDeclaration && !d->m_usingTypeRef.isEmpty()) {
+ QString member = getCursorSpelling(cursor);
+ if (member == d->m_currentClass->name())
+ member = d->m_usingTypeRef; // Overloaded member is Constructor, use base
+ const auto ap = accessPolicy(clang_getCXXAccessSpecifier(cursor));
+ d->m_currentClass->addUsingMember(d->m_usingTypeRef, member, ap);
+ }
+ break;
default:
break;
}
@@ -1273,6 +1307,10 @@ bool Builder::endToken(const CXCursor &cursor)
case CXCursor_TypeAliasTemplateDecl:
d->m_currentTemplateTypeAlias.reset();
break;
+ case CXCursor_UsingDeclaration:
+ d->m_withinUsingDeclaration = false;
+ d->m_usingTypeRef.clear();
+ break;
default:
break;
}
diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp
index 0386eccb8..92d3a97c5 100644
--- a/sources/shiboken6/ApiExtractor/messages.cpp
+++ b/sources/shiboken6/ApiExtractor/messages.cpp
@@ -474,6 +474,17 @@ QString msgFunctionVisibilityModified(const AbstractMetaClass *c,
return result;
}
+QString msgUsingMemberClassNotFound(const AbstractMetaClass *c,
+ const QString &baseClassName,
+ const QString &memberName)
+{
+ QString result;
+ QTextStream str(&result);
+ str << c->sourceLocation() << "base class \"" << baseClassName
+ << "\" of \"" << c->qualifiedCppName() << "\" for using member \""
+ << memberName << "\" not found.";
+ return result;
+}
// docparser.cpp
QString msgCannotFindDocumentation(const QString &fileName,
diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h
index d5994aeab..092135f05 100644
--- a/sources/shiboken6/ApiExtractor/messages.h
+++ b/sources/shiboken6/ApiExtractor/messages.h
@@ -151,6 +151,10 @@ QString msgPropertyExists(const QString &className, const QString &name);
QString msgFunctionVisibilityModified(const AbstractMetaClass *c,
const AbstractMetaFunction *f);
+QString msgUsingMemberClassNotFound(const AbstractMetaClass *c,
+ const QString &baseClassName,
+ const QString &memberName);
+
QString msgCannotFindDocumentation(const QString &fileName,
const char *what, const QString &name,
const QString &query);
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
index 723e8ef63..5dda974a7 100644
--- a/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel.cpp
@@ -394,6 +394,18 @@ bool _ClassModelItem::extendsClass(const QString &name) const
return false;
}
+const QList<_ClassModelItem::UsingMember> &_ClassModelItem::usingMembers() const
+{
+ return m_usingMembers;
+}
+
+void _ClassModelItem::addUsingMember(const QString &className,
+ const QString &memberName,
+ Access accessPolicy)
+{
+ m_usingMembers.append({className, memberName, accessPolicy});
+}
+
void _ClassModelItem::setClassType(CodeModel::ClassType type)
{
m_classType = type;
@@ -449,6 +461,9 @@ void _ClassModelItem::formatDebug(QDebug &d) const
d << m_baseClasses.at(i).name << " (" << m_baseClasses.at(i).accessPolicy << ')';
}
}
+ for (const auto &im : m_usingMembers)
+ d << ", using " << im.className << "::" << im.memberName
+ << " (" << im.access << ')';
formatModelItemList(d, ", templateParameters=", m_templateParameters);
formatScopeItemsDebug(d);
if (!m_propertyDeclarations.isEmpty())
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel.h b/sources/shiboken6/ApiExtractor/parser/codemodel.h
index 621fba97b..c3bda9ef5 100644
--- a/sources/shiboken6/ApiExtractor/parser/codemodel.h
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel.h
@@ -265,6 +265,13 @@ public:
Access accessPolicy = Access::Public;
};
+ struct UsingMember // Introducing a base class member via 'using' directive
+ {
+ QString className;
+ QString memberName;
+ Access access = Access::Public;
+ };
+
explicit _ClassModelItem(CodeModel *model, int kind = __node_kind)
: _ScopeModelItem(model, kind), m_classType(CodeModel::Class) {}
explicit _ClassModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
@@ -273,6 +280,10 @@ public:
QList<BaseClass> baseClasses() const { return m_baseClasses; }
+ const QList<UsingMember> &usingMembers() const;
+ void addUsingMember(const QString &className, const QString &memberName,
+ Access accessPolicy);
+
void addBaseClass(const QString &name, Access accessPolicy);
TemplateParameterList templateParameters() const;
@@ -298,6 +309,7 @@ public:
private:
QList<BaseClass> m_baseClasses;
+ QList<UsingMember> m_usingMembers;
TemplateParameterList m_templateParameters;
CodeModel::ClassType m_classType;
diff --git a/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h
index 39b0d3fac..4f5121a08 100644
--- a/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h
+++ b/sources/shiboken6/ApiExtractor/parser/codemodel_enums.h
@@ -63,9 +63,9 @@ enum class NamespaceType
enum class Access
{
- Public,
+ Private,
Protected,
- Private
+ Public
};
#endif // CODEMODEL_ENUMS_H
diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp
index 0042a67e6..c11a5cc83 100644
--- a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp
+++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp
@@ -32,6 +32,7 @@
#include "testutil.h"
#include <abstractmetafunction.h>
#include <abstractmetalang.h>
+#include <usingmember.h>
#include <typesystem.h>
void TestAbstractMetaClass::testClassName()
@@ -670,4 +671,46 @@ void TestAbstractMetaClass::testFreeOperators()
QCOMPARE(classes.constFirst()->queryFunctions(opts).size(), 1);
}
+void TestAbstractMetaClass::testUsingMembers()
+{
+ const char cppCode[] =R"CPP(
+class Base {
+public:
+ explicit Base(int);
+
+protected:
+ void member();
+};
+
+class Derived : public Base {
+public:
+ using Base::Base;
+ using Base::member;
+};
+)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='Derived'/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ auto base = AbstractMetaClass::findClass(classes, QLatin1String("Base"));
+ QVERIFY(base);
+ auto derived = AbstractMetaClass::findClass(classes, QLatin1String("Derived"));
+ QVERIFY(derived);
+ const auto usingMembers = derived->usingMembers();
+ QCOMPARE(usingMembers.count(), 2);
+ for (const auto &um : usingMembers) {
+ QCOMPARE(um.access, Access::Public);
+ QCOMPARE(um.baseClass, base);
+ QVERIFY(um.memberName == u"Base" || um.memberName == u"member");
+ }
+}
+
QTEST_APPLESS_MAIN(TestAbstractMetaClass)
diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h
index 67e425128..ec30e95bd 100644
--- a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h
+++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h
@@ -54,6 +54,7 @@ private slots:
void testClassTypedefedBaseClass();
void testFreeOperators_data();
void testFreeOperators();
+ void testUsingMembers();
};
#endif // TESTABSTRACTMETACLASS_H
diff --git a/sources/shiboken6/ApiExtractor/usingmember.h b/sources/shiboken6/ApiExtractor/usingmember.h
new file mode 100644
index 000000000..e3354f16d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/usingmember.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef USINGMEMBER_H
+#define USINGMEMBER_H
+
+#include "abstractmetalang_typedefs.h"
+#include "parser/codemodel.h"
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+struct UsingMember // Introducing a base class member via 'using' directive
+{
+ QString memberName;
+ const AbstractMetaClass *baseClass;
+ Access access;
+};
+
+QDebug operator<<(QDebug debug, const UsingMember &d);
+
+#endif // USINGMEMBER_H
diff --git a/sources/shiboken6/tests/libsample/CMakeLists.txt b/sources/shiboken6/tests/libsample/CMakeLists.txt
index af4f3318f..f734ab935 100644
--- a/sources/shiboken6/tests/libsample/CMakeLists.txt
+++ b/sources/shiboken6/tests/libsample/CMakeLists.txt
@@ -7,8 +7,10 @@ bytearray.cpp
bucket.cpp
collector.cpp
complex.cpp
+ctparam.cpp
onlycopy.cpp
derived.cpp
+derivedusingct.cpp
echo.cpp
exceptiontest.cpp
functions.cpp
diff --git a/sources/shiboken6/tests/libsample/ctparam.cpp b/sources/shiboken6/tests/libsample/ctparam.cpp
new file mode 100644
index 000000000..89d4dd744
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/ctparam.cpp
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ctparam.h"
+
+namespace SampleNamespace
+{
+
+CtParam::CtParam(int value) : m_value(value)
+{
+}
+
+CtParam::~CtParam() = default;
+
+int CtParam::value() const
+{
+ return m_value;
+}
+
+} // namespace SampleNamespace
diff --git a/sources/shiboken6/tests/libsample/ctparam.h b/sources/shiboken6/tests/libsample/ctparam.h
new file mode 100644
index 000000000..8acf14aaf
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/ctparam.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CTPARAM_H
+#define CTPARAM_H
+
+#include "libsamplemacros.h"
+
+namespace SampleNamespace
+{
+
+class LIBSAMPLE_API CtParam
+{
+public:
+ explicit CtParam(int value);
+ virtual ~CtParam();
+
+ int value() const;
+
+private:
+ int m_value;
+};
+
+} // namespace SampleNamespace
+
+#endif // CTPARAM_H
diff --git a/sources/shiboken6/tests/libsample/derivedusingct.cpp b/sources/shiboken6/tests/libsample/derivedusingct.cpp
new file mode 100644
index 000000000..3ee5f2cb4
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/derivedusingct.cpp
@@ -0,0 +1,34 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "derivedusingct.h"
+
+void DerivedUsingCt::foo()
+{
+ delete new DerivedUsingCt(42);
+}
diff --git a/sources/shiboken6/tests/libsample/derivedusingct.h b/sources/shiboken6/tests/libsample/derivedusingct.h
new file mode 100644
index 000000000..ae0682cfd
--- /dev/null
+++ b/sources/shiboken6/tests/libsample/derivedusingct.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DERIVEDUSINGCT_H
+#define DERIVEDUSINGCT_H
+
+#include "libsamplemacros.h"
+#include "ctparam.h"
+
+class LIBSAMPLE_API DerivedUsingCt : public SampleNamespace::CtParam
+{
+public:
+ using CtParam::CtParam;
+
+ void foo();
+};
+#endif // DERIVEDUSINGCT_H
diff --git a/sources/shiboken6/tests/samplebinding/CMakeLists.txt b/sources/shiboken6/tests/samplebinding/CMakeLists.txt
index 2630b9c79..cfdc21041 100644
--- a/sources/shiboken6/tests/samplebinding/CMakeLists.txt
+++ b/sources/shiboken6/tests/samplebinding/CMakeLists.txt
@@ -27,6 +27,7 @@ ${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/derivedusingct_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/derived_someinnerclass_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/echo_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/event_wrapper.cpp
@@ -103,6 +104,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/sample_module_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/sample_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/sample_sample_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_wrapper.cpp
+${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_ctparam_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someinnerclass_okthisisrecursiveenough_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someinnerclass_wrapper.cpp
${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someotherinnerclass_wrapper.cpp
diff --git a/sources/shiboken6/tests/samplebinding/derived_test.py b/sources/shiboken6/tests/samplebinding/derived_test.py
index 557698110..8bdb051a8 100644
--- a/sources/shiboken6/tests/samplebinding/derived_test.py
+++ b/sources/shiboken6/tests/samplebinding/derived_test.py
@@ -41,7 +41,7 @@ from shiboken_paths import init_paths
init_paths()
import sample
-from sample import Abstract, Derived, OverloadedFuncEnum
+from sample import Abstract, Derived, DerivedUsingCt, OverloadedFuncEnum
class Deviant(Derived):
def __init__(self):
@@ -154,6 +154,12 @@ class DerivedTest(unittest.TestCase):
obj = Derived.createObject()
self.assertEqual(type(obj), Derived)
+ def testDerivedUsingCt(self):
+ '''Test whether a constructor of the base class declared by using works'''
+ obj = DerivedUsingCt(42)
+ self.assertEqual(obj.value(), 42)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/sources/shiboken6/tests/samplebinding/global.h b/sources/shiboken6/tests/samplebinding/global.h
index f647eb795..dd24f274b 100644
--- a/sources/shiboken6/tests/samplebinding/global.h
+++ b/sources/shiboken6/tests/samplebinding/global.h
@@ -33,9 +33,11 @@
#include "collector.h"
#include "complex.h"
#include "ctorconvrule.h"
+#include "ctparam.h"
#include "cvlist.h"
#include "sbkdate.h"
#include "derived.h"
+#include "derivedusingct.h"
#include "echo.h"
#include "exceptiontest.h"
#include "functions.h"
diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
index d5a3edb34..20fa61334 100644
--- a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
+++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
@@ -595,6 +595,8 @@
%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);
</inject-code>
</add-function>
+
+ <object-type name="CtParam"/>
</namespace-type>
<namespace-type name="RemovedNamespace1" visible='false'>
@@ -649,6 +651,8 @@
<value-type name="SomeInnerClass" />
</object-type>
+ <object-type name="DerivedUsingCt"/>
+
<object-type name="ModifiedConstructor">
<modify-function signature="ModifiedConstructor(int)">
<modify-argument index="1">