Alien-SmokeQt

 view release on metacpan or  search on metacpan

generator/generators/smoke/helpers.cpp  view on Meta::CPAN

/*
    Generator for the SMOKE sources
    Copyright (C) 2009 Arno Rehn <arno@arnorehn.de>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <QHash>
#include <QList>
#include <QStack>

#include <type.h>

#include "globals.h"
#include "../../options.h"

QHash<QString, QString> Util::typeMap;
QHash<const Method*, const Function*> Util::globalFunctionMap;
QHash<const Method*, const Field*> Util::fieldAccessors;

// looks up the inheritance path from desc to super and sets 'virt' to true if it encounters a virtual base
static bool isVirtualInheritancePathPrivate(const Class* desc, const Class* super, bool *virt)
{
    foreach (const Class::BaseClassSpecifier bspec, desc->baseClasses()) {
        if (bspec.baseClass == super || isVirtualInheritancePathPrivate(bspec.baseClass, super, virt)) {
            if (bspec.isVirtual)
                *virt = true;
            return true;
        }
    }
    return false;
}

bool Util::isVirtualInheritancePath(const Class* desc, const Class* super)
{
    bool isVirtual = false;
    isVirtualInheritancePathPrivate(desc, super, &isVirtual);
    return isVirtual;
}

QList<const Class*> Util::superClassList(const Class* klass)
{
    static QHash<const Class*, QList<const Class*> > superClassCache;

    QList<const Class*> ret;
    if (superClassCache.contains(klass))
        return superClassCache[klass];
    foreach (const Class::BaseClassSpecifier& base, klass->baseClasses()) {
        ret << base.baseClass;
        ret += superClassList(base.baseClass);
    }
    // cache
    superClassCache[klass] = ret;
    return ret;
}

QList<const Class*> Util::descendantsList(const Class* klass)
{
    static QHash<const Class*, QList<const Class*> > descendantsClassCache;

    QList<const Class*> ret;
    if (descendantsClassCache.contains(klass))
        return descendantsClassCache[klass];
    for (QHash<QString, Class>::const_iterator iter = classes.constBegin(); iter != classes.constEnd(); iter++) {
        if (superClassList(&iter.value()).contains(klass))
            ret << &iter.value();
    }
    // cache
    descendantsClassCache[klass] = ret;
    return ret;
}

bool operator==(const Field& lhs, const Field& rhs)
{
    return (lhs.name() == rhs.name() && lhs.declaringType() == rhs.declaringType() && lhs.type() == rhs.type());
}

bool operator==(const EnumMember& lhs, const EnumMember& rhs)
{
    return (lhs.name() == rhs.name() && lhs.declaringType() == rhs.declaringType() && lhs.type() == rhs.type());
}

void Util::preparse(QSet<Type*> *usedTypes, QSet<const Class*> *superClasses, const QList<QString>& keys)
{
    Class& globalSpace = classes["QGlobalSpace"];
    globalSpace.setName("QGlobalSpace");
    globalSpace.setKind(Class::Kind_Class);
    globalSpace.setIsNameSpace(true);
    
    // add all functions as methods to a class called 'QGlobalSpace' or a class that represents a namespace
    for (QHash<QString, Function>::const_iterator it = functions.constBegin(); it != functions.constEnd(); it++) {
        const Function& fn = it.value();
        
        QString fnString = fn.toString();
        
        // gcc doesn't like this function... for whatever reason
        if (fn.name() == "_IO_ftrylockfile"
            // functions in named namespaces are covered by the class list - only check for top-level functions here
            || (fn.nameSpace().isEmpty() && !Options::functionNameIncluded(fn.qualifiedName()) && !Options::functionSignatureIncluded(fnString))
            || Options::typeExcluded(fnString))
        {
            // we don't want that function...
            continue;
        }
        
        Class* parent = &globalSpace;
        if (!fn.nameSpace().isEmpty()) {
            parent = &classes[fn.nameSpace()];
            if (parent->name().isEmpty()) {
                parent->setName(fn.nameSpace());
                parent->setKind(Class::Kind_Class);
                parent->setIsNameSpace(true);
            }
        }
        
        Method meth = Method(parent, fn.name(), fn.type(), Access_public, fn.parameters());
        meth.setFlag(Method::Static);
        parent->appendMethod(meth);
        // map this method to the function, so we can later retrieve the header it was defined in
        globalFunctionMap[&parent->methods().last()] = &fn;
        
        int methIndex = parent->methods().size() - 1;
        addOverloads(meth);
        // handle the methods appended by addOverloads()
        for (int i = parent->methods().size() - 1; i > methIndex; --i)
            globalFunctionMap[&parent->methods()[i]] = &fn;

        (*usedTypes) << meth.type();
        foreach (const Parameter& param, meth.parameters())
            (*usedTypes) << param.type();
    }
    
    // all enums that don't have a parent are put under QGlobalSpace, too
    for (QHash<QString, Enum>::iterator it = enums.begin(); it != enums.end(); it++) {
        Enum& e = it.value();
        if (!e.parent()) {
            Class* parent = &globalSpace;
            if (!e.nameSpace().isEmpty()) {
                parent = &classes[e.nameSpace()];
                if (parent->name().isEmpty()) {
                    parent->setName(e.nameSpace());
                    parent->setKind(Class::Kind_Class);
                    parent->setIsNameSpace(true);
                }
            }

            Type *t = 0;
            if (e.name().isEmpty()) {
                // unnamed enum
                Type longType = Type("long");
                longType.setIsIntegral(true);
                t = Type::registerType(longType);
            } else {
                t = Type::registerType(Type(&e));
            }
            (*usedTypes) << t;
            parent->appendChild(&e);
        }
    }
    
    foreach (const QString& key, keys) {
        Class& klass = classes[key];
        foreach (const Class::BaseClassSpecifier base, klass.baseClasses()) {
            superClasses->insert(base.baseClass);
        }
        if (!klass.isNameSpace()) {
            addDefaultConstructor(&klass);
            addCopyConstructor(&klass);
            addDestructor(&klass);
            checkForAbstractClass(&klass);
            foreach (const Method& m, klass.methods()) {
                if (m.access() == Access_private)
                    continue;
                if ((m.type()->getClass() && m.type()->getClass()->access() == Access_private)
                    || Options::typeExcluded(m.toString(false, true)))
                {
                    klass.methodsRef().removeOne(m);
                    continue;
                }
                addOverloads(m);
                (*usedTypes) << m.type();
                foreach (const Parameter& param, m.parameters())
                    (*usedTypes) << param.type();
            }
            foreach (const Field& f, klass.fields()) {
                if (f.access() == Access_private)
                    continue;
                if (Options::typeExcluded(f.toString(false, true))) {
                    klass.fieldsRef().removeOne(f);
                    continue;
                }
            }
            foreach (const Field& f, klass.fields()) {
                if (f.access() == Access_private)
                    continue;
                addAccessorMethods(f, usedTypes);
            }



( run in 0.511 second using v1.01-cache-2.11-cpan-13bb782fe5a )