Alien-SmokeQt

 view release on metacpan or  search on metacpan

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

                    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();
            // found a copy c'tor? then there's nothing to do
            if (type->isRef() && type->getClass() == klass)
                return;
        } else if (meth.isDestructor() && meth.access() == Access_private) {
            // private destructor, so we can't create instances of that class
            return;
        }
    }
    
    // if the parent can't be copied, a copy c'tor is of no use
    foreach (const Class::BaseClassSpecifier& base, klass->baseClasses()) {
        if (!canClassBeCopied(base.baseClass))
            return;
    }
    
    Type t = Type(klass);
    t.setPointerDepth(1);
    Method meth = Method(klass, klass->name(), Type::registerType(t));
    meth.setIsConstructor(true);
    // parameter is a constant reference to another object of the same types
    Type paramType = Type(klass, true); paramType.setIsRef(true);
    meth.appendParameter(Parameter("copy", Type::registerType(paramType)));
    klass->appendMethod(meth);
}

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

    if (Options::qtMode && !type->isRef() && type->pointerDepth() == 0 &&
        type->getClass() && type->getClass()->isTemplate() && type->getClass()->name() == "QFlags")
    {
        return "s_uint";
    }

    if (type->pointerDepth() > 0 || type->isRef() || type->isFunctionPointer() || type->isArray() || Options::voidpTypes.contains(type->name())
        || (!type->isIntegral() && !type->getEnum()))
    {
        return "s_class";
    }
    
    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;
}

void Util::addOverloads(const Method& meth)
{
    ParameterList params;
    Class* klass = meth.getClass();
    
    for (int i = 0; i < meth.parameters().count(); i++) {
        const Parameter& param = meth.parameters()[i];
        if (!param.isDefault()) {
            params << param;
            continue;
        }
        Method overload = meth;
        if (meth.flags() & Method::PureVirtual) {
            overload.setFlag(Method::DynamicDispatch);
        }
        overload.removeFlag(Method::Virtual);
        overload.removeFlag(Method::PureVirtual);
        overload.setParameterList(params);
        if (klass->methods().contains(overload)) {
            // we already have that, skip it
            params << param;
            continue;
        }
        
        QStringList remainingDefaultValues;
        for (int j = i; j < meth.parameters().count(); j++) {
            const Parameter defParam = meth.parameters()[j];
            QString cast = "(";
            cast += defParam.type()->toString() + ')';
            cast += defParam.defaultValue();
            remainingDefaultValues << cast;
        }
        overload.setRemainingDefaultValues(remainingDefaultValues);
        klass->appendMethod(overload);
        
        params << param;
    }
}

// checks if method meth is overriden in class klass or any of its superclasses
const Method* Util::isVirtualOverriden(const Method& meth, const Class* klass)
{
    // is the method virtual at all?
    if (!(meth.flags() & Method::Virtual) && !(meth.flags() & Method::PureVirtual))
        return 0;
    
    // if the method is defined in klass, it can't be overriden there or in any parent class
    if (meth.getClass() == klass)
        return 0;
    
    foreach (const Method& m, klass->methods()) {
        if (!(m.flags() & Method::Static) && m == meth)
            // the method m overrides meth
            return &m;
    }
    
    foreach (const Class::BaseClassSpecifier& base, klass->baseClasses()) {
        // we reached the class in which meth was defined and we still didn't find any overrides => return
        if (base.baseClass == meth.getClass())
            return 0;
        
        // recurse into the base classes
        const Method* m = 0;
        if ((m = isVirtualOverriden(meth, base.baseClass)))
            return m;
    }
    
    return 0;
}

static bool qListContainsMethodPointer(const QList<const Method*> list, const Method* ptr) {
    foreach (const Method* meth, list) {
        if (*meth == *ptr)
            return true;
    }
    return false;
}

QList<const Method*> Util::virtualMethodsForClass(const Class* klass)
{
    static QHash<const Class*, QList<const Method*> > cache;
    
    // virtual method callbacks for classes that can't be instanstiated aren't useful
    if (!Util::canClassBeInstanciated(klass))
        return QList<const Method*>();
    
    if (cache.contains(klass))
        return cache[klass];
    
    QList<const Method*> ret;

    foreach (const Method* meth, Util::collectVirtualMethods(klass)) {
        // this is a synthesized overload, skip it.
        if (!meth->remainingDefaultValues().isEmpty())
            continue;
        if (meth->getClass() == klass) {
            // this method can't be overriden, because it's defined in the class for which this method was called
            ret << meth;
            continue;
        }
        // Check if the method is overriden, so the callback will always point to the latest definition of the virtual method.
        const Method* override = 0;
        if ((override = Util::isVirtualOverriden(*meth, klass))) {
            // If the method was overriden and put under private access, skip it. If we already have the method, skip it as well.
            if (override->access() == Access_private || qListContainsMethodPointer(ret, override))
                continue;
            ret << override;
        } else if (!qListContainsMethodPointer(ret, meth)) {
            ret << meth;
        }
    }



( run in 0.749 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )