[Kde-bindings] KDE/kdebindings/generator/generators/smoke
Arno Rehn
kde at arnorehn.de
Mon Nov 2 19:56:33 UTC 2009
SVN commit 1043990 by arnorehn:
Fix inherited virtual methods not showing up in the methods table.
CCMAIL: kde-bindings at kde.org
M +5 -0 globals.h
M +93 -0 helpers.cpp
M +2 -77 writeClasses.cpp
M +36 -6 writeSmokeDataFile.cpp
--- trunk/KDE/kdebindings/generator/generators/smoke/globals.h #1043989:1043990
@@ -75,6 +75,7 @@
QSet<Class*> externalClasses;
QSet<Type*> usedTypes;
QStringList includedClasses;
+ QHash<const Class*, QSet<const Method*> > declaredVirtualMethods;
};
struct SmokeClassFiles
@@ -97,6 +98,9 @@
struct Util
{
+ typedef QPair<const Method*, QString> MethodStringPair;
+ typedef QList<MethodStringPair> VirtualMethodList;
+
static QHash<QString, QString> typeMap;
static QHash<const Method*, const Function*> globalFunctionMap;
static QHash<const Method*, const Field*> fieldAccessors;
@@ -127,6 +131,7 @@
static QString assignmentString(const Type* type, const QString& var);
static QList<const Method*> collectVirtualMethods(const Class* klass);
static const Method* isVirtualOverriden(const Method& meth, const Class* klass);
+ static VirtualMethodList virtualMethodsForClass(const Class* klass);
};
#endif
--- trunk/KDE/kdebindings/generator/generators/smoke/helpers.cpp #1043989:1043990
@@ -646,6 +646,99 @@
return 0;
}
+Util::VirtualMethodList Util::virtualMethodsForClass(const Class* klass)
+{
+ static QHash<const Class*, Util::VirtualMethodList > cache;
+
+ // virtual method callbacks for classes that can't be instanciated aren't useful
+ if (!Util::canClassBeInstanciated(klass))
+ return Util::VirtualMethodList();
+
+ if (cache.contains(klass))
+ return cache[klass];
+
+ Util::VirtualMethodList ret;
+
+ QSet<QString> virtMeths; // virtual methods that already have been taken care of
+ QList<const Method*> pureVirtuals;
+ foreach (const Method& meth, klass->methods()) {
+ // if there are default parameters, it's not the 'original' method.. skip it
+ if (!meth.remainingDefaultValues().isEmpty())
+ continue;
+ // first, generate all virtual methods of this class. inherited ones come after that.
+ if (((meth.flags() & Method::Virtual) || (meth.flags() & Method::PureVirtual)) && !meth.isDestructor()) {
+ if (meth.access() != Access_private) {
+ ret << qMakePair(&meth, klass->toString());
+ }
+ virtMeths.insert(meth.toString(false, false, false));
+ }
+ }
+
+ QList<const Method*> inheritedVirtuals;
+ foreach (const Class::BaseClassSpecifier& bspec, klass->baseClasses()) {
+ // now collect all virtual methods of the base classes
+ inheritedVirtuals += Util::collectVirtualMethods(bspec.baseClass);
+ }
+
+ foreach (const Method* meth, inheritedVirtuals) {
+ if (!meth->remainingDefaultValues().isEmpty())
+ continue;
+ if (meth->flags() & Method::PureVirtual) {
+ // postpone pure virtuals to see if they have been overridden
+ pureVirtuals << meth;
+ continue;
+ }
+
+ QString methString = meth->toString(false, false, false);
+ if (virtMeths.contains(methString))
+ continue;
+ const Method *m = 0;
+ if ((m = Util::isVirtualOverriden(*meth, klass)) && m->access() == Access_private) {
+ // if the method was overriden and put under private access, skip it.
+ virtMeths.insert(methString);
+ continue;
+ }
+ /* If the method was overridden, use the overriding method for getting the classname - else use the virtual method itself
+ Don't use className here, as this won't work with hidden methods. Imagine:
+
+ struct A {
+ virtual void foo() {}
+ };
+
+ struct B : public A {
+ virtual void foo(int) {}
+ };
+
+ B::foo(int) hides A::foo(). So if we have an instance of B, we can't call this->B::foo(), but have to use this->A::foo()
+ */
+ ret << qMakePair(meth, m ? m->getClass()->toString() : meth->getClass()->toString());
+ virtMeths.insert(methString);
+ }
+ foreach (const Method* meth, pureVirtuals) {
+ QString methString = meth->toString(false, false, false);
+ // Check if the pure virtual was overriden somewhere - then we shouldn't generate a callback with the pure virtual flag set
+ // (as it isn't, anymore).
+ // If the overriding method was declared virtual, too, we find it in virtMeths. Then it's already generated and we can continue.
+ // If it hasn't, we have to go looking for it. If we find it, generate a normal virtual method for it.
+ if (virtMeths.contains(methString))
+ continue;
+ const Method* m = 0;
+ if ((m = Util::isVirtualOverriden(*meth, klass))) {
+ if (m->access() != Access_private) {
+ ret << qMakePair(m, klass->toString());
+ }
+ virtMeths.insert(methString);
+ } else {
+ // we didn't find any overriding method - generate a pure virtual one
+ ret << qMakePair(meth, klass->toString());
+ virtMeths.insert(methString);
+ }
+ }
+
+ cache[klass] = ret;
+ return ret;
+}
+
bool Options::typeExcluded(const QString& typeName)
{
foreach (const QRegExp& exp, Options::excludeExpressions) {
--- trunk/KDE/kdebindings/generator/generators/smoke/writeClasses.cpp #1043989:1043990
@@ -409,83 +409,8 @@
enumOut << " break;\n";
}
- // virtual method callbacks for classes that can't be instanciated aren't useful
- if (Util::canClassBeInstanciated(klass)) {
- QSet<QString> virtMeths; // virtual methods that already have been taken care of
- QList<const Method*> pureVirtuals;
- foreach (const Method& meth, klass->methods()) {
- // if there are default parameters, it's not the 'original' method.. skip it
- if (!meth.remainingDefaultValues().isEmpty())
- continue;
- // first, generate all virtual methods of this class. inherited ones come after that.
- if (((meth.flags() & Method::Virtual) || (meth.flags() & Method::PureVirtual)) && !meth.isDestructor()) {
- if (meth.access() != Access_private) {
- generateVirtualMethod(out, className, meth, includes);
- }
- virtMeths.insert(meth.toString(false, false, false));
- }
- }
-
- QList<const Method*> inheritedVirtuals;
- foreach (const Class::BaseClassSpecifier& bspec, klass->baseClasses()) {
- // now collect all virtual methods of the base classes
- inheritedVirtuals += Util::collectVirtualMethods(bspec.baseClass);
- }
-
- foreach (const Method* meth, inheritedVirtuals) {
- if (!meth->remainingDefaultValues().isEmpty())
- continue;
- if (meth->flags() & Method::PureVirtual) {
- // postpone pure virtuals to see if they have been overridden
- pureVirtuals << meth;
- continue;
- }
-
- QString methString = meth->toString(false, false, false);
- if (virtMeths.contains(methString))
- continue;
- const Method *m = 0;
- if ((m = Util::isVirtualOverriden(*meth, klass)) && m->access() == Access_private) {
- // if the method was overriden and put under private access, skip it.
- virtMeths.insert(methString);
- continue;
- }
- /* If the method was overridden, use the overriding method for getting the classname - else use the virtual method itself
- Don't use className here, as this won't work with hidden methods. Imagine:
-
- struct A {
- virtual void foo() {}
- };
-
- struct B : public A {
- virtual void foo(int) {}
- };
-
- B::foo(int) hides A::foo(). So if we have an instance of B, we can't call this->B::foo(), but have to use this->A::foo()
- */
- generateVirtualMethod(out, m ? m->getClass()->toString() : meth->getClass()->toString(), *meth, includes);
- virtMeths.insert(methString);
- }
- foreach (const Method* meth, pureVirtuals) {
- QString methString = meth->toString(false, false, false);
- // Check if the pure virtual was overriden somewhere - then we shouldn't generate a callback with the pure virtual flag set
- // (as it isn't, anymore).
- // If the overriding method was declared virtual, too, we find it in virtMeths. Then it's already generated and we can continue.
- // If it hasn't, we have to go looking for it. If we find it, generate a normal virtual method for it.
- if (virtMeths.contains(methString))
- continue;
- const Method* m = 0;
- if ((m = Util::isVirtualOverriden(*meth, klass))) {
- if (m->access() != Access_private) {
- generateVirtualMethod(out, className, *m, includes);
- }
- virtMeths.insert(methString);
- } else {
- // we didn't find any overriding method - generate a pure virtual one
- generateVirtualMethod(out, className, *meth, includes);
- virtMeths.insert(methString);
- }
- }
+ foreach (const Util::MethodStringPair& pair, Util::virtualMethodsForClass(klass)) {
+ generateVirtualMethod(out, pair.second, *pair.first, includes);
}
// this class contains enums, write out an xenum_operation method
--- trunk/KDE/kdebindings/generator/generators/smoke/writeSmokeDataFile.cpp #1043989:1043990
@@ -50,12 +50,30 @@
includedClasses = classIndex.keys();
Util::preparse(&usedTypes, &superClasses, includedClasses); // collect all used types, add c'tors.. etc.
+ // Collect the classes that are inherited by classes in this smoke module and provide virtual methods.
+ // These classes need to be indexed as well.
+ foreach (const QString& className, includedClasses) {
+ const Class* klass = &classes[className];
+ Util::VirtualMethodList list = Util::virtualMethodsForClass(klass);
+ foreach (const Util::MethodStringPair& pair, list) {
+ const Method* meth = pair.first;
+ usedTypes << meth->type();
+ foreach (const Parameter& param, meth->parameters()) {
+ usedTypes << param.type();
+ }
+ declaredVirtualMethods[meth->getClass()] << meth;
+ }
+ }
+
// if a class is used somewhere but not listed in the class list, mark it external
for (QHash<QString, Class>::iterator iter = ::classes.begin(); iter != ::classes.end(); iter++) {
if (iter.value().isTemplate() || Options::voidpTypes.contains(iter.key()))
continue;
- if ((isClassUsed(&iter.value()) && iter.value().access() != Access_private) || superClasses.contains(&iter.value())) {
+ if ( (isClassUsed(&iter.value()) && iter.value().access() != Access_private)
+ || superClasses.contains(&iter.value())
+ || declaredVirtualMethods.contains(&iter.value()))
+ {
classIndex[iter.key()] = 1;
if (!Options::classList.contains(iter.key()) || iter.value().isForwardDecl())
@@ -344,17 +362,23 @@
currentIdx = 1;
for (QMap<QString, int>::const_iterator iter = classIndex.constBegin(); iter != classIndex.constEnd(); iter++) {
Class* klass = &classes[iter.key()];
- if (externalClasses.contains(klass))
+ bool isExternal = externalClasses.contains(klass);
+ bool isDeclaredVirtual = declaredVirtualMethods.contains(klass);
+ if (isExternal && !isDeclaredVirtual)
continue;
QMap<QString, QList<const Member*> >& map = classMungedNames[klass];
foreach (const Method& meth, klass->methods()) {
if (meth.access() == Access_private)
continue;
+ if (isExternal && !declaredVirtualMethods[klass].contains(&meth))
+ continue;
methodNames[meth.name()] = 1;
- QString mungedName = Util::mungedName(meth);
- methodNames[mungedName] = 1;
- map[mungedName].append(&meth);
+ if (!isExternal) {
+ QString mungedName = Util::mungedName(meth);
+ methodNames[mungedName] = 1;
+ map[mungedName].append(&meth);
+ }
if (!meth.parameters().count()) {
parameterIndices[&meth] = 0;
@@ -418,10 +442,16 @@
for (QMap<QString, int>::const_iterator iter = classIndex.constBegin(); iter != classIndex.constEnd(); iter++) {
Class* klass = &classes[iter.key()];
const Method* destructor = 0;
+ bool isExternal = false;
if (externalClasses.contains(klass))
+ isExternal = true;
+ if (isExternal && !declaredVirtualMethods.contains(klass))
continue;
+
int xcall_index = 1;
foreach (const Method& meth, klass->methods()) {
+ if (isExternal && !declaredVirtualMethods[klass].contains(&meth))
+ continue;
if (meth.access() == Access_private)
continue;
if (meth.isDestructor()) {
@@ -458,7 +488,7 @@
} else {
out << ", " << typeIndex[meth.type()];
}
- out << ", " << xcall_index << "},";
+ out << ", " << (isExternal ? 0 : xcall_index) << "},";
// comment
out << "\t//" << i << " " << klass->toString() << "::";
More information about the Kde-bindings
mailing list