Alien-SmokeQt
view release on metacpan or search on metacpan
generator/generators/smoke/helpers.cpp view on Meta::CPAN
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);
}
}
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()) {
generator/generators/smoke/helpers.cpp view on Meta::CPAN
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);
}
void Util::addDestructor(Class* klass)
{
foreach (const Method& meth, klass->methods()) {
// we already have a destructor
if (meth.isDestructor())
return;
}
Method meth = Method(klass, "~" + klass->name(), const_cast<Type*>(Type::Void));
meth.setIsDestructor(true);
const Method* dtor = findDestructor(klass);
if (dtor && dtor->hasExceptionSpec()) {
meth.setHasExceptionSpec(true);
foreach (const Type& t, dtor->exceptionTypes()) {
meth.appendExceptionType(t);
}
}
klass->appendMethod(meth);
}
QChar Util::munge(const Type *type) {
if (type->getTypedef()) {
Type resolved = type->getTypedef()->resolve();
return munge(&resolved);
}
if (type->pointerDepth() > 1 || (type->getClass() && type->getClass()->isTemplate() && (!Options::qtMode || (Options::qtMode && type->getClass()->name() != "QFlags"))) ||
(Options::voidpTypes.contains(type->name()) && !Options::scalarTypes.contains(type->name())) )
{
// QString and QStringList are both mapped to Smoke::t_voidp, but QString is a scalar as well
// TODO: fix this - neither QStringList nor QString should be mapped to Smoke::t_voidp or munged as ? or $
// reference to array or hash or unknown
return '?';
} else if (type->isIntegral() || type->getEnum() || Options::scalarTypes.contains(type->name()) ||
(Options::qtMode && !type->isRef() && type->pointerDepth() == 0 &&
(type->getClass() && type->getClass()->isTemplate() && type->getClass()->name() == "QFlags")))
{
// plain scalar
return '$';
} else if (type->getClass()) {
// object
return '#';
generator/generators/smoke/helpers.cpp view on Meta::CPAN
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;
( run in 0.560 second using v1.01-cache-2.11-cpan-140bd7fdf52 )