[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-bindings
Subject: [Kde-bindings] KDE/kdebindings/generator/generators/smoke
From: Arno Rehn <kde () arnorehn ! de>
Date: 2010-06-10 23:33:27
Message-ID: 20100610233327.E804BAC8D3 () svn ! kde ! org
[Download RAW message or body]
SVN commit 1136866 by arnorehn:
Fix this long-standing bug in SMOKE:
Previously, a method call through SMOKE would always call a specific implementation, \
even though dynamic dispatch would be the correct calling way. The problem was to \
distinguish between cases where dynamic dispatch is the correct way of calling and \
cases where that specific method and nothing else should be called.
This is now fixed in the following way: if an object is created through smoke (i.e. \
it's really an x_Foo class), then we DO NOT use dynamic dispatch, so calls to the \
parent implemenation of a method will work.
However, if the object is not an x_Foo class (i.e. it was returned by some other \
method), then we use dynamic dispatch, so internal classes that are not wrapped by \
the bindings will still work (e.g. subclasses of KPluginFactory, KParts::Part, \
etc...).
A virtual method call now looks like this:
// virtual const QMetaObject* metaObject() const
if (typeid(*this) == typeid(x_QObject)) {
const QMetaObject* xret = ((const \
x_QObject*)this)->QObject::metaObject(); x[0].s_class = (void*)xret;
} else {
const QMetaObject* xret = ((const x_QObject*)this)->metaObject();
x[0].s_class = (void*)xret;
}
The overhead for the typeid() calls should be minimal. The information is either \
provided at compile time or directly retrieved from the vtable.
CCMAIL: kde-bindings@kde.org
M +1 -0 globals.h
M +42 -14 writeClasses.cpp
--- trunk/KDE/kdebindings/generator/generators/smoke/globals.h #1136865:1136866
@@ -86,6 +86,7 @@
void write(const QList<QString>& keys);
private:
+ QString generateMethodBody(const QString& indent, const QString& className, \
const QString& smokeClassName, const Method& meth, int index, bool dynamicDispatch, \
QSet< QString >& includes);
void generateMethod(QTextStream& out, const QString& className, const QString& \
smokeClassName, const Method& meth, int index, QSet<QString>& \
includes);
void generateGetAccessor(QTextStream& out, const QString& className, const \
Field& field, const Type* type, int index);
void generateSetAccessor(QTextStream& out, const QString& className, const \
Field& field, const Type* type, int index);
--- trunk/KDE/kdebindings/generator/generators/smoke/writeClasses.cpp \
#1136865:1136866 @@ -91,16 +91,14 @@
}
}
-void SmokeClassFiles::generateMethod(QTextStream& out, const QString& className, \
const QString& smokeClassName,
- const Method& meth, int index, QSet<QString>& \
includes) +QString SmokeClassFiles::generateMethodBody(const QString& indent, const \
QString& className, const QString& smokeClassName, const Method& meth, + \
int index, bool dynamicDispatch, QSet<QString>& includes) {
- out << " ";
- if ((meth.flags() & Method::Static) || meth.isConstructor())
- out << "static ";
- out << QString("void x_%1(Smoke::Stack x) {\n").arg(index);
- out << " // " << meth.toString() << "\n";
- out << " ";
+ QString methodBody;
+ QTextStream out(&methodBody);
+ out << indent;
+
if (meth.isConstructor()) {
out << smokeClassName << "* xret = new " << smokeClassName << "(";
} else {
@@ -123,8 +121,8 @@
out << "this->";
}
}
- if (!(meth.flags() & Method::PureVirtual) && !(meth.flags() & \
Method::DynamicDispatch) && !func) {
- // dynamic dispatch for virtuals
+ if (!dynamicDispatch && !func) {
+ // dynamic dispatch not wanted, call with 'this->Foo::method()'
out << className << "::";
} else if (func) {
if (!func->nameSpace().isEmpty())
@@ -159,8 +157,7 @@
out << "(" << typeName << ")" << "x[" << j + 1 << "]." << field;
}
- // if the method has any other default parameters, append them here as values, \
so
-
+ // if the method has any other default parameters, append them here as values
if (!meth.remainingDefaultValues().isEmpty()) {
const QStringList& defaultParams = meth.remainingDefaultValues();
if (meth.parameters().count() > 0)
@@ -170,13 +167,44 @@
out << ");\n";
if (meth.type() != Type::Void) {
- out << " x[0]." << Util::stackItemField(meth.type()) << " = " << \
Util::assignmentString(meth.type(), "xret") << ";\n"; + out << indent << \
"x[0]." << Util::stackItemField(meth.type()) << " = " << \
Util::assignmentString(meth.type(), "xret") << ";\n"; } else {
- out << " (void)x; // noop (for compiler warning)\n";
+ out << indent << "(void)x; // noop (for compiler warning)\n";
}
+ return methodBody;
+}
+
+void SmokeClassFiles::generateMethod(QTextStream& out, const QString& className, \
const QString& smokeClassName, + const Method& \
meth, int index, QSet<QString>& includes) +{
+ out << " ";
+ if ((meth.flags() & Method::Static) || meth.isConstructor())
+ out << "static ";
+ out << QString("void x_%1(Smoke::Stack x) {\n").arg(index);
+ out << " // " << meth.toString() << "\n";
+
+ bool dynamicDispatch = ((meth.flags() & Method::PureVirtual) || (meth.flags() & \
Method::DynamicDispatch)); +
+ if (dynamicDispatch || \
!Util::virtualMethodsForClass(meth.getClass()).contains(&meth)) { + // This is \
either already flagged as dynamic dispatch or just a normal method. We can generate a \
normal method call for it. +
+ out << generateMethodBody(" ", // indent
+ className, smokeClassName, meth, index, \
dynamicDispatch, includes); + } else {
+ // This is a virtual method. To know whether we should call with dynamic \
dispatch, we need a bit of RTTI magic. + includes.insert("typeinfo");
+ out << " if (typeid(*this) == typeid(" << smokeClassName << ")) {\n"; \
// + out << generateMethodBody(" ", // indent
+ className, smokeClassName, meth, index, false, \
includes); + out << " } else {\n";
+ out << generateMethodBody(" ", // indent
+ className, smokeClassName, meth, index, true, \
includes); out << " }\n";
+ }
+ out << " }\n";
+
// If the constructor was generated from another one with default parameteres, \
we don't need to explicitly create
// it here again. The x_* call will append the default parameters at the end and \
thus choose the right constructor.
if (meth.isConstructor() && meth.remainingDefaultValues().isEmpty()) {
_______________________________________________
Kde-bindings mailing list
Kde-bindings@kde.org
https://mail.kde.org/mailman/listinfo/kde-bindings
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic