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 )