Skip to content

Commit

Permalink
Fix redirections of base class methods
Browse files Browse the repository at this point in the history
Move parsing of instantiation types to after base classes have been
otherwise resolved. Remove resolves argument types from TypeEntry
(nothing outside of AbstractMetaBuilder::traverseInstantiation was using
them, and they're first determined in traverseInstantiation and so don't
need to be stored). Move setting up redirections to its own helper
method so that it can be called recursively to also set up redirections
for the base class and other interface classes (and do so).

The sample binding is accordingly updated to test generation of
redirections of base class members.

Change-Id: Ifb89e0e1c14b7788d1839ec4cf30476012cf832b
  • Loading branch information
mwoehlke-kitware committed Oct 15, 2013
1 parent d77266c commit 75d2964
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 60 deletions.
117 changes: 68 additions & 49 deletions ApiExtractor/abstractmetabuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,15 +488,6 @@ bool AbstractMetaBuilder::build(QIODevice* input)
foreach (NamespaceModelItem item, namespaceTypeValues)
traverseNamespaceMembers(item);

// Resolve template instantiation argument types and create redirections
ReportHandler::setProgressReference(instantiationTypes);
foreach (ComplexTypeEntry *entry, instantiationTypes) {
ReportHandler::progress("Fixing template instantiations...");
AbstractMetaClass* cls = m_metaClasses.findClass(entry->qualifiedCppName());
traverseInstantiation(entry, cls);
}
ReportHandler::flush();

// Global functions
foreach (FunctionModelItem func, m_dom->functions()) {
if (func->accessPolicy() != CodeModel::Public || func->name().startsWith("operator"))
Expand Down Expand Up @@ -533,6 +524,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...");
Expand Down Expand Up @@ -1444,10 +1446,9 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac
}
++ordinal;
}
entry->setTemplateArgTypes(argTypeEntries);

QList<TypeTemplateEntry::Argument> args = entry->templateType()->args();
Q_ASSERT(args.count() == ordinal);
Q_ASSERT(args.count() == argTypes.count());

// Add functions and modifications from the type template
foreach (AddedFunction addedFunction, metaClass->typeEntry()->templateType()->addedFunctions())
Expand All @@ -1464,7 +1465,7 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac

QString code = snip.code();
QHash<int, AbstractMetaType *>::const_iterator iter, end = argTypes.constEnd();
for (iter = argTypes.begin(); iter != end; ++iter) {
for (iter = argTypes.constBegin(); iter != end; ++iter) {
code.replace(QRegExp(QString("%INTYPE_%1\\b").arg(iter.key())),
iter.value()->typeEntry()->qualifiedCppName());
}
Expand All @@ -1476,49 +1477,67 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac
}

// Set up redirections
foreach (ordinal, argTypes.keys()) {
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) {
foreach (AbstractMetaFunction *function, argClass->functions()) {
if (!function->isStatic() && !function->isConstructor() && function->isPublic()) {
QString signature = function->minimalSignature();
if (signature.endsWith("const"))
signature = signature.left((signature.length() - 5));

// Generate meta function and add to meta class
QString returnType = (function->type() ? function->type()->cppSignature() : QString("void"));
bool isPublic = function->isPublic();
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);
if (!argClass) {
ReportHandler::warning(QString("template argument '%1' of '%2' is not known; not adding redirections")
.arg(argType->typeEntry()->qualifiedCppName())
.arg(metaClass->name()));
continue;
}

entry->addFunctionModification(redirect);
}
}
addRedirections(entry, metaClass, argClass, accessor);
}
}
}

void AbstractMetaBuilder::addRedirections(ComplexTypeEntry *entry, AbstractMetaClass* metaClass, AbstractMetaClass* fromClass, const QString &accessor)
{
// 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);

// 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));

// 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);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions ApiExtractor/abstractmetabuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class AbstractMetaBuilder
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);
Expand Down
10 changes: 0 additions & 10 deletions ApiExtractor/typesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -1670,15 +1670,6 @@ class ComplexTypeEntry : public TypeEntry
return m_templateType;
}

void setTemplateArgTypes(QList<const TypeEntry*> templateArgs)
{
m_templateArgTypes = templateArgs;
}
QList<const TypeEntry*> templateArgTypes() const
{
return m_templateArgTypes;
}

QString defaultConstructor() const;
void setDefaultConstructor(const QString& defaultConstructor);
bool hasDefaultConstructor() const;
Expand Down Expand Up @@ -1710,7 +1701,6 @@ class ComplexTypeEntry : public TypeEntry
QStringList m_templateArgNames;

const TypeTemplateEntry *m_templateType;
QList<const TypeEntry*> m_templateArgTypes;
};

class ContainerTypeEntry : public ComplexTypeEntry
Expand Down
11 changes: 10 additions & 1 deletion tests/libsample/pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,19 @@ class Pointer
int *m_ref;
};

class SimpleObjectBase
{
public:
inline int square(int value) { return value * value; }

protected:
SimpleObjectBase() {}
};

class SimpleObject;
typedef Pointer<SimpleObject> SimpleObjectPointer;

class LIBSAMPLE_API SimpleObject
class LIBSAMPLE_API SimpleObject : public SimpleObjectBase
{
public:
~SimpleObject();
Expand Down
1 change: 1 addition & 0 deletions tests/samplebinding/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ ${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
Expand Down
1 change: 1 addition & 0 deletions tests/samplebinding/pointer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def testRedirection(self):
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.'''
Expand Down
1 change: 1 addition & 0 deletions tests/samplebinding/typesystem_sample.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2412,6 +2412,7 @@
</inject-code>
</add-function>
</type-template>
<object-type name="SimpleObjectBase"/>
<object-type name="SimpleObject"/>
<value-type template="Pointer" args="SimpleObject">
<add-function signature="get()" return-type="SimpleObject*">
Expand Down

0 comments on commit 75d2964

Please sign in to comment.