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 )