Alien-SmokeQt

 view release on metacpan or  search on metacpan

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


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);
            }
        }
        foreach (BasicTypeDeclaration* decl, klass.children()) {
            Enum* e = 0;
            if ((e = dynamic_cast<Enum*>(decl))) {
                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;
                foreach (const EnumMember& member, e->members()) {
                    if (Options::typeExcluded(member.toString())) {
                        e->membersRef().removeOne(member);
                    }
                }
            }
            
        }
        
    }
}

bool Util::canClassBeInstanciated(const Class* klass)
{
    static QHash<const Class*, bool> cache;
    if (cache.contains(klass))
        return cache[klass];
    
    bool ctorFound = false, publicCtorFound = false, privatePureVirtualsFound = false;
    foreach (const Method& meth, klass->methods()) {
        if (meth.isConstructor()) {
            ctorFound = true;
            if (meth.access() != Access_private) {
                // this class can be instanstiated
                publicCtorFound = true;
            }
        } else if ((meth.flags() & Method::PureVirtual) && meth.access() == Access_private) {
            privatePureVirtualsFound = true;
        }
    }
    
    // The class can be instanstiated if it has a public constructor or no constructor at all
    // because then it has a default one generated by the compiler.
    // If it has private pure virtuals, then it can't be instanstiated either.
    bool ret = ((publicCtorFound || !ctorFound) && !privatePureVirtualsFound);
    cache[klass] = ret;
    return ret;
}

bool Util::canClassBeCopied(const Class* klass)
{
    static QHash<const Class*, bool> cache;
    if (cache.contains(klass))
        return cache[klass];

    bool privateCopyCtorFound = false;
    foreach (const Method& meth, klass->methods()) {
        if (meth.access() != Access_private)
            continue;
        if (meth.isConstructor() && meth.parameters().count() == 1) {
            const Type* type = meth.parameters()[0].type();
            // c'tor should be Foo(const Foo& copy)
            if (type->isConst() && type->isRef() && type->getClass() == klass) {
                privateCopyCtorFound = true;
                break;
            }
        }
    }
    
    bool parentCanBeCopied = true;
    foreach (const Class::BaseClassSpecifier& base, klass->baseClasses()) {
        if (!canClassBeCopied(base.baseClass)) {
            parentCanBeCopied = false;
            break;
        }
    }
    
    // if the parent can be copied and we didn't find a private copy c'tor, the class is copiable
    bool ret = (parentCanBeCopied && !privateCopyCtorFound);
    cache[klass] = ret;
    return ret;
}

bool Util::hasClassVirtualDestructor(const Class* klass)
{
    static QHash<const Class*, bool> cache;
    if (cache.contains(klass))
        return cache[klass];

    bool virtualDtorFound = false;
    foreach (const Method& meth, klass->methods()) {
        if (meth.isDestructor() && meth.flags() & Method::Virtual) {
            virtualDtorFound = true;
            break;
        }
    }
    
    bool superClassHasVirtualDtor = false;
    foreach (const Class::BaseClassSpecifier& bspec, klass->baseClasses()) {
        if (hasClassVirtualDestructor(bspec.baseClass)) {
            superClassHasVirtualDtor = true;
            break;
        }
    }
    
    // if the superclass has a virtual d'tor, then the descendants have one automatically, too
    bool ret = (virtualDtorFound || superClassHasVirtualDtor);
    cache[klass] = ret;
    return ret;
}

bool Util::hasClassPublicDestructor(const Class* klass)
{
    static QHash<const Class*, bool> cache;
    if (cache.contains(klass))
        return cache[klass];

    if (klass->isNameSpace()) {
        cache[klass] = false;
        return false;
    }

    bool publicDtorFound = true;
    foreach (const Method& meth, klass->methods()) {
        if (meth.isDestructor()) {
            if (meth.access() != Access_public)
                publicDtorFound = false;
            // a class has only one destructor, so break here
            break;
        }
    }
    
    cache[klass] = publicDtorFound;
    return publicDtorFound;
}

const Method* Util::findDestructor(const Class* klass)
{
    foreach (const Method& meth, klass->methods()) {
        if (meth.isDestructor()) {
            return &meth;
        }
    }
    const Method* dtor = 0;
    foreach (const Class::BaseClassSpecifier& bspec, klass->baseClasses()) {
        if ((dtor = findDestructor(bspec.baseClass))) {
            return dtor;
        }
    }
    return 0;
}

void Util::checkForAbstractClass(Class* klass)
{
    QList<const Method*> list;
    
    bool hasPrivatePureVirtuals = false;
    foreach (const Method& meth, klass->methods()) {
        if ((meth.flags() & Method::PureVirtual) && meth.access() == Access_private)
            hasPrivatePureVirtuals = true;
        if (meth.isConstructor())
            list << &meth;
    }
    
    // abstract classes can't be instanstiated - remove the constructors
    if (hasPrivatePureVirtuals) {
        foreach (const Method* ctor, list) {
            klass->methodsRef().removeOne(*ctor);
        }
    }
}

void Util::addDefaultConstructor(Class* klass)
{
    foreach (const Method& meth, klass->methods()) {
        // if the class already has a constructor or if it has pure virtuals, there's nothing to do for us
        if (meth.isConstructor())
            return;
        else if (meth.isDestructor() && meth.access() == Access_private)
            return;
    }
    
    Type t = Type(klass);
    t.setPointerDepth(1);
    Method meth = Method(klass, klass->name(), Type::registerType(t));
    meth.setIsConstructor(true);
    klass->appendMethod(meth);
}

void Util::addCopyConstructor(Class* klass)
{
    foreach (const Method& meth, klass->methods()) {
        if (meth.isConstructor() && meth.parameters().count() == 1) {
            const Type* type = meth.parameters()[0].type();

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

    if (type->getEnum())
        return "s_enum";
    
    QString typeName = type->name();
    // replace the unsigned stuff, look the type up in Util::typeMap and if
    // necessary, add a 'u' for unsigned types at the beginning again
    bool _unsigned = false;
    if (typeName.startsWith("unsigned ")) {
        typeName.replace("unsigned ", "");
        _unsigned = true;
    }
    typeName.replace("signed ", "");
    typeName = Util::typeMap.value(typeName, typeName);
    if (_unsigned)
        typeName.prepend('u');
    return "s_" + typeName;
}

QString Util::assignmentString(const Type* type, const QString& var)
{
    if (type->getTypedef()) {
        Type resolved = type->getTypedef()->resolve();
        return assignmentString(&resolved, var);
    }

    if (type->pointerDepth() > 0 || type->isFunctionPointer()) {
        return "(void*)" + var;
    } else if (type->isRef()) {
        return "(void*)&" + var;
    } else if (type->isIntegral() && !Options::voidpTypes.contains(type->name())) {
        return var;
    } else if (type->getEnum()) {
        return var;
    } else if (Options::qtMode && type->getClass() && type->getClass()->isTemplate() && type->getClass()->name() == "QFlags")
    {
        return "(uint)" + var;
    } else {
        QString ret = "(void*)new " + type->toString();
        ret += '(' + var + ')';
        return ret;
    }
    return QString();
}

QList<const Method*> Util::collectVirtualMethods(const Class* klass)
{
    QList<const Method*> methods;
    foreach (const Method& meth, klass->methods()) {
        if ((meth.flags() & Method::Virtual || meth.flags() & Method::PureVirtual)
            && !meth.isDestructor() && meth.access() != Access_private)
        {
            methods << &meth;
        }
    }
    foreach (const Class::BaseClassSpecifier& baseClass, klass->baseClasses()) {
        methods += collectVirtualMethods(baseClass.baseClass);
    }
    return methods;
}

// don't make this public - it's just a utility function for the next method and probably not what you would expect it to be
static bool operator==(const Method& rhs, const Method& lhs)
{
    // These have to be equal for methods to be the same. Return types don't have an effect, ignore them.
    bool ok = (rhs.name() == lhs.name() && rhs.isConst() == lhs.isConst() && rhs.parameters().count() == lhs.parameters().count());
    if (!ok)
        return false;
    
    // now check the parameter types for equality
    for (int i = 0; i < rhs.parameters().count(); i++) {
        if (rhs.parameters()[i].type() != lhs.parameters()[i].type())
            return false;
    }
    
    return true;
}

void Util::addAccessorMethods(const Field& field, QSet<Type*> *usedTypes)
{
    Class* klass = field.getClass();
    Type* type = field.type();
    if (type->getClass() && type->pointerDepth() == 0) {
        Type newType = *type;
        newType.setIsRef(true);
        type = Type::registerType(newType);
    }
    (*usedTypes) << type;
    Method getter = Method(klass, field.name(), type, field.access());
    getter.setIsConst(true);
    if (field.flags() & Field::Static)
        getter.setFlag(Method::Static);
    klass->appendMethod(getter);
    fieldAccessors[&klass->methods().last()] = &field;
    
    // constant field? (i.e. no setter method)
    if (field.type()->isConst() && field.type()->pointerDepth() == 0)
        return;
    
    // foo => setFoo
    QString newName = field.name();
    newName[0] = newName[0].toUpper();
    Method setter = Method(klass, "set" + newName, const_cast<Type*>(Type::Void), field.access());
    if (field.flags() & Field::Static)
        setter.setFlag(Method::Static);
    
    // reset
    type = field.type();
    // to avoid copying around more stuff than necessary, convert setFoo(Bar) to setFoo(const Bar&)
    if (type->pointerDepth() == 0 && type->getClass() && !(ParserOptions::qtMode && type->getClass()->name() == "QFlags")) {
        Type newType = *type;
        newType.setIsRef(true);
        newType.setIsConst(true);
        type = Type::registerType(newType);
    }

    (*usedTypes) << type;
    setter.appendParameter(Parameter(QString(), type));
    if (klass->methods().contains(setter))
        return;
    klass->appendMethod(setter);
    fieldAccessors[&klass->methods().last()] = &field;



( run in 1.054 second using v1.01-cache-2.11-cpan-39bf76dae61 )