[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