/**************************************************************************** ** ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. ** ** This file is part of the Qt Script Generator project on Trolltech Labs. ** ** This file may be used under the terms of the GNU General Public ** License version 2.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of ** this file. Please review the following information to ensure GNU ** General Public Licensing requirements will be met: ** http://www.trolltech.com/products/qt/opensource.html ** ** If you are unsure which license is appropriate for your use, please ** review the following information: ** http://www.trolltech.com/products/qt/licensing.html or contact the ** sales department at sales@trolltech.com. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ #include "abstractmetalang.h" #include "reporthandler.h" /******************************************************************************* * AbstractMetaType */ AbstractMetaType *AbstractMetaType::copy() const { AbstractMetaType *cpy = new AbstractMetaType; cpy->setTypeUsagePattern(typeUsagePattern()); cpy->setConstant(isConstant()); cpy->setReference(isReference()); cpy->setIndirections(indirections()); cpy->setInstantiations(instantiations()); cpy->setArrayElementCount(arrayElementCount()); cpy->setOriginalTypeDescription(originalTypeDescription()); cpy->setOriginalTemplateType(originalTemplateType() ? originalTemplateType()->copy() : 0); cpy->setArrayElementType(arrayElementType() ? arrayElementType()->copy() : 0); cpy->setTypeEntry(typeEntry()); return cpy; } QString AbstractMetaType::cppSignature() const { QString s; if (isConstant()) s += "const "; s += typeEntry()->qualifiedCppName(); if (hasInstantiationInCpp()) { QList types = instantiations(); s += "<"; for (int i=0; i 0) s += ", "; s += types.at(i)->cppSignature(); } s += " >"; } if (actualIndirections()) { s += ' '; if (indirections()) s += QString(indirections(), '*'); if (isReference()) s += '&'; } return s; } /******************************************************************************* * AbstractMetaArgument */ AbstractMetaArgument *AbstractMetaArgument::copy() const { AbstractMetaArgument *cpy = new AbstractMetaArgument; cpy->setName(AbstractMetaVariable::name()); cpy->setDefaultValueExpression(defaultValueExpression()); cpy->setType(type()->copy()); cpy->setArgumentIndex(argumentIndex()); return cpy; } QString AbstractMetaArgument::argumentName() const { QString n = AbstractMetaVariable::name(); if (n.isEmpty()) { return QString("arg__%2").arg(m_argument_index + 1); } return n; } QString AbstractMetaArgument::indexedName() const { QString n = AbstractMetaVariable::name(); if (n.isEmpty()) return argumentName(); return QString("%1%2").arg(n).arg(m_argument_index); } QString AbstractMetaArgument::name() const { Q_ASSERT_X(0, "AbstractMetaArgument::name()", "use argumentName() or indexedName() instead"); return QString(); } /******************************************************************************* * AbstractMetaFunction */ AbstractMetaFunction::~AbstractMetaFunction() { qDeleteAll(m_arguments); delete m_type; } /******************************************************************************* * Indicates that this function has a modification that removes it */ bool AbstractMetaFunction::isModifiedRemoved(int types) const { FunctionModificationList mods = modifications(implementingClass()); foreach (FunctionModification mod, mods) { if (!mod.isRemoveModifier()) continue; if ((mod.removal & types) == types) return true; } return false; } bool AbstractMetaFunction::needsCallThrough() const { if (ownerClass()->isInterface()) return false; if (referenceCounts(implementingClass()).size() > 0) return true; if (argumentsHaveNativeId() || !isStatic()) return true; foreach (const AbstractMetaArgument *arg, arguments()) { if (arg->type()->isArray() || arg->type()->isTargetLangEnum() || arg->type()->isTargetLangFlags()) return true; } if (type() && (type()->isArray() || type()->isTargetLangEnum() || type()->isTargetLangFlags())) return true; for (int i=-1; i<=arguments().size(); ++i) { TypeSystem::Ownership owner = this->ownership(implementingClass(), TypeSystem::TargetLangCode, i); if (owner != TypeSystem::InvalidOwnership) return true; } return false; } bool AbstractMetaFunction::needsSuppressUncheckedWarning() const { for (int i=-1; i<=arguments().size(); ++i) { QList referenceCounts = this->referenceCounts(implementingClass(), i); foreach (ReferenceCount referenceCount, referenceCounts) { if (referenceCount.action != ReferenceCount::Set) return true; } } return false; } QString AbstractMetaFunction::marshalledName() const { QString returned = "__qt_" + name(); AbstractMetaArgumentList arguments = this->arguments(); foreach (const AbstractMetaArgument *arg, arguments) { returned += "_"; if (arg->type()->isNativePointer()) { returned += "nativepointer"; } else if (arg->type()->isIntegerEnum() || arg->type()->isIntegerFlags()) { returned += "int"; } else { returned += arg->type()->name().replace("[]", "_3").replace(".", "_"); } } return returned; } bool AbstractMetaFunction::operator<(const AbstractMetaFunction &other) const { uint result = compareTo(&other); return result & NameLessThan; } /*! Returns a mask of CompareResult describing how this function is compares to another function */ uint AbstractMetaFunction::compareTo(const AbstractMetaFunction *other) const { uint result = 0; // Enclosing class... if (ownerClass() == other->ownerClass()) { result |= EqualImplementor; } // Attributes if (attributes() == other->attributes()) { result |= EqualAttributes; } // Compare types AbstractMetaType *t = type(); AbstractMetaType *ot = other->type(); if ((!t && !ot) || ((t && ot && t->name() == ot->name()))) { result |= EqualReturnType; } // Compare names int cmp = originalName().compare(other->originalName()); if (cmp < 0) { result |= NameLessThan; } else if (cmp == 0) { result |= EqualName; } // compare name after modification... cmp = modifiedName().compare(other->modifiedName()); if (cmp == 0) result |= EqualModifiedName; // Compare arguments... AbstractMetaArgumentList min_arguments; AbstractMetaArgumentList max_arguments; if (arguments().size() < other->arguments().size()) { min_arguments = arguments(); max_arguments = other->arguments(); } else { min_arguments = other->arguments(); max_arguments = arguments(); } int min_count = min_arguments.size(); int max_count = max_arguments.size(); bool same = true; for (int i=0; itype()->name() != max_arg->type()->name() && (min_arg->defaultValueExpression().isEmpty() || max_arg->defaultValueExpression().isEmpty())) { same = false; break; } } else { if (max_arguments.at(i)->defaultValueExpression().isEmpty()) { same = false; break; } } } if (same) result |= min_count == max_count ? EqualArguments : EqualDefaultValueOverload; return result; } AbstractMetaFunction *AbstractMetaFunction::copy() const { AbstractMetaFunction *cpy = new AbstractMetaFunction; cpy->setName(name()); cpy->setOriginalName(originalName()); cpy->setOwnerClass(ownerClass()); cpy->setImplementingClass(implementingClass()); cpy->setInterfaceClass(interfaceClass()); cpy->setFunctionType(functionType()); cpy->setAttributes(attributes()); cpy->setDeclaringClass(declaringClass()); if (type()) cpy->setType(type()->copy()); cpy->setConstant(isConstant()); cpy->setOriginalAttributes(originalAttributes()); foreach (AbstractMetaArgument *arg, arguments()) cpy->addArgument(arg->copy()); Q_ASSERT((!type() && !cpy->type()) || (type()->instantiations() == cpy->type()->instantiations())); return cpy; } QStringList AbstractMetaFunction::introspectionCompatibleSignatures(const QStringList &resolvedArguments) const { AbstractMetaArgumentList arguments = this->arguments(); if (arguments.size() == resolvedArguments.size()) { return (QStringList() << QMetaObject::normalizedSignature((name() + "(" + resolvedArguments.join(",") + ")").toUtf8().constData())); } else { QStringList returned; AbstractMetaArgument *argument = arguments.at(resolvedArguments.size()); QStringList minimalTypeSignature = argument->type()->minimalSignature().split("::"); for (int i=0; i 0) s += ", "; AbstractMetaArgument *a = m_arguments.at(i); s += a->type()->cppSignature(); // We need to have the argument names in the qdoc files s += " "; s += a->argumentName(); } s += ")"; if (isConstant()) s += " const"; return s; } int AbstractMetaFunction::actualMinimumArgumentCount() const { AbstractMetaArgumentList arguments = this->arguments(); int count = 0; for (int i=0; idefaultValueExpression().isEmpty()) break; } return count; } // Returns reference counts for argument at idx, or all arguments if idx == -2 QList AbstractMetaFunction::referenceCounts(const AbstractMetaClass *cls, int idx) const { QList returned; FunctionModificationList mods = this->modifications(cls); foreach (FunctionModification mod, mods) { QList argument_mods = mod.argument_mods; foreach (ArgumentModification argument_mod, argument_mods) { if (argument_mod.index != idx && idx != -2) continue; returned += argument_mod.referenceCounts; } } return returned; } QString AbstractMetaFunction::replacedDefaultExpression(const AbstractMetaClass *cls, int key) const { FunctionModificationList modifications = this->modifications(cls); foreach (FunctionModification modification, modifications) { QList argument_modifications = modification.argument_mods; foreach (ArgumentModification argument_modification, argument_modifications) { if (argument_modification.index == key && !argument_modification.replaced_default_expression.isEmpty()) { return argument_modification.replaced_default_expression; } } } return QString(); } bool AbstractMetaFunction::removedDefaultExpression(const AbstractMetaClass *cls, int key) const { FunctionModificationList modifications = this->modifications(cls); foreach (FunctionModification modification, modifications) { QList argument_modifications = modification.argument_mods; foreach (ArgumentModification argument_modification, argument_modifications) { if (argument_modification.index == key && argument_modification.removed_default_expression) { return true; } } } return false; } bool AbstractMetaFunction::resetObjectAfterUse(int argument_idx) const { const AbstractMetaClass *cls = declaringClass(); FunctionModificationList modifications = this->modifications(cls); foreach (FunctionModification modification, modifications) { QList argumentModifications = modification.argument_mods; foreach (ArgumentModification argumentModification, argumentModifications) { if (argumentModification.index == argument_idx && argumentModification.reset_after_use) return true; } } return false; } QString AbstractMetaFunction::nullPointerDefaultValue(const AbstractMetaClass *mainClass, int argument_idx) const { Q_ASSERT(nullPointersDisabled(mainClass, argument_idx)); const AbstractMetaClass *cls = mainClass; if (cls == 0) cls = implementingClass(); do { FunctionModificationList modifications = this->modifications(cls); foreach (FunctionModification modification, modifications) { QList argument_modifications = modification.argument_mods; foreach (ArgumentModification argument_modification, argument_modifications) { if (argument_modification.index == argument_idx && argument_modification.no_null_pointers) { return argument_modification.null_pointer_default_value; } } } cls = cls->baseClass(); } while (cls != 0 && mainClass == 0); // Once when mainClass != 0, or once for all base classes of implementing class return QString(); } bool AbstractMetaFunction::nullPointersDisabled(const AbstractMetaClass *mainClass, int argument_idx) const { const AbstractMetaClass *cls = mainClass; if (cls == 0) cls = implementingClass(); do { FunctionModificationList modifications = this->modifications(cls); foreach (FunctionModification modification, modifications) { QList argument_modifications = modification.argument_mods; foreach (ArgumentModification argument_modification, argument_modifications) { if (argument_modification.index == argument_idx && argument_modification.no_null_pointers) { return true; } } } cls = cls->baseClass(); } while (cls != 0 && mainClass == 0); // Once when mainClass != 0, or once for all base classes of implementing class return false; } QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int key) const { FunctionModificationList modifications = this->modifications(declaringClass()); foreach (FunctionModification modification, modifications) { QList argument_modifications = modification.argument_mods; foreach (ArgumentModification argument_modification, argument_modifications) { if (argument_modification.index != key) continue; foreach (CodeSnip snip, argument_modification.conversion_rules) { if (snip.language == language && !snip.code().isEmpty()) return snip.code(); } } } return QString(); } QString AbstractMetaFunction::argumentReplaced(int key) const { FunctionModificationList modifications = this->modifications(declaringClass()); foreach (FunctionModification modification, modifications) { QList argument_modifications = modification.argument_mods; foreach (ArgumentModification argument_modification, argument_modifications) { if (argument_modification.index == key && !argument_modification.replace_value.isEmpty()) { return argument_modification.replace_value; } } } return ""; } bool AbstractMetaFunction::argumentRemoved(int key) const { FunctionModificationList modifications = this->modifications(declaringClass()); foreach (FunctionModification modification, modifications) { QList argument_modifications = modification.argument_mods; foreach (ArgumentModification argument_modification, argument_modifications) { if (argument_modification.index == key) { if (argument_modification.removed) { return true; } } } } return false; } bool AbstractMetaFunction::isVirtualSlot() const { FunctionModificationList modifications = this->modifications(declaringClass()); foreach (FunctionModification modification, modifications) { if (modification.isVirtualSlot()) return true; } return false; } bool AbstractMetaFunction::disabledGarbageCollection(const AbstractMetaClass *cls, int key) const { FunctionModificationList modifications = this->modifications(cls); foreach (FunctionModification modification, modifications) { QList argument_modifications = modification.argument_mods; foreach (ArgumentModification argument_modification, argument_modifications) { if (argument_modification.index != key) continue; foreach (TypeSystem::Ownership ownership, argument_modification.ownerships.values()) { if (ownership == TypeSystem::CppOwnership) return true; } } } return false; } bool AbstractMetaFunction::isDeprecated() const { FunctionModificationList modifications = this->modifications(declaringClass()); foreach (FunctionModification modification, modifications) { if (modification.isDeprecated()) return true; } return false; } TypeSystem::Ownership AbstractMetaFunction::ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int key) const { FunctionModificationList modifications = this->modifications(cls); foreach (FunctionModification modification, modifications) { QList argument_modifications = modification.argument_mods; foreach (ArgumentModification argument_modification, argument_modifications) { if (argument_modification.index == key) return argument_modification.ownerships.value(language, TypeSystem::InvalidOwnership); } } return TypeSystem::InvalidOwnership; } bool AbstractMetaFunction::isRemovedFromAllLanguages(const AbstractMetaClass *cls) const { return isRemovedFrom(cls, TypeSystem::All); } bool AbstractMetaFunction::isRemovedFrom(const AbstractMetaClass *cls, TypeSystem::Language language) const { FunctionModificationList modifications = this->modifications(cls); foreach (FunctionModification modification, modifications) { if ((modification.removal & language) == language) return true; } return false; } QString AbstractMetaFunction::typeReplaced(int key) const { FunctionModificationList modifications = this->modifications(declaringClass()); foreach (FunctionModification modification, modifications) { QList argument_modifications = modification.argument_mods; foreach (ArgumentModification argument_modification, argument_modifications) { if (argument_modification.index == key && !argument_modification.modified_type.isEmpty()) { return argument_modification.modified_type; } } } return QString(); } QString AbstractMetaFunction::minimalSignature() const { if (!m_cached_minimal_signature.isEmpty()) return m_cached_minimal_signature; QString minimalSignature = originalName() + "("; AbstractMetaArgumentList arguments = this->arguments(); for (int i=0; itype(); if (i > 0) minimalSignature += ","; minimalSignature += t->minimalSignature(); } minimalSignature += ")"; if (isConstant()) minimalSignature += "const"; minimalSignature = QMetaObject::normalizedSignature(minimalSignature.toLocal8Bit().constData()); m_cached_minimal_signature = minimalSignature; return minimalSignature; } FunctionModificationList AbstractMetaFunction::modifications(const AbstractMetaClass *implementor) const { Q_ASSERT(implementor); return implementor->typeEntry()->functionModifications(minimalSignature()); } bool AbstractMetaFunction::hasModifications(const AbstractMetaClass *implementor) const { FunctionModificationList mods = modifications(implementor); return mods.count() > 0; } QString AbstractMetaFunction::modifiedName() const { if (m_cached_modified_name.isEmpty()) { FunctionModificationList mods = modifications(implementingClass()); foreach (FunctionModification mod, mods) { if (mod.isRenameModifier()) { m_cached_modified_name = mod.renamedToName; break; } } if (m_cached_modified_name.isEmpty()) m_cached_modified_name = name(); } return m_cached_modified_name; } QString AbstractMetaFunction::targetLangSignature(bool minimal) const { QString s; // Attributes... if (!minimal) { #if 0 // jambi if (isPublic()) s += "public "; else if (isProtected()) s += "protected "; else if (isPrivate()) s += "private "; // if (isNative()) s += "native "; // else if (isFinalInTargetLang()) s += "final "; else if (isAbstract()) s += "abstract "; if (isStatic()) s += "static "; #endif // Return type if (type()) s += type()->name() + " "; else s += "void "; } s += modifiedName(); s += "("; int j = 0; for (int i=0; itype()->name(); if (!minimal) { s += " "; s += m_arguments.at(i)->argumentName(); } ++j; } s += ")"; return s; } bool function_sorter(AbstractMetaFunction *a, AbstractMetaFunction *b) { return a->signature() < b->signature(); } /******************************************************************************* * AbstractMetaClass */ AbstractMetaClass::~AbstractMetaClass() { qDeleteAll(m_functions); qDeleteAll(m_fields); } /*AbstractMetaClass *AbstractMetaClass::copy() const { AbstractMetaClass *cls = new AbstractMetaClass; cls->setAttributes(attributes()); cls->setBaseClass(baseClass()); cls->setTypeEntry(typeEntry()); foreach (AbstractMetaFunction *function, functions()) { AbstractMetaFunction *copy = function->copy(); function->setImplementingClass(cls); cls->addFunction(copy); } cls->setEnums(enums()); foreach (const AbstractMetaField *field, fields()) { AbstractMetaField *copy = field->copy(); copy->setEnclosingClass(cls); cls->addField(copy); } cls->setInterfaces(interfaces()); return cls; }*/ /******************************************************************************* * Returns true if this class is a subclass of the given class */ bool AbstractMetaClass::inheritsFrom(const AbstractMetaClass *cls) const { Q_ASSERT(cls != 0); const AbstractMetaClass *clazz = this; while (clazz != 0) { if (clazz == cls) return true; clazz = clazz->baseClass(); } return false; } /******************************************************************************* * Constructs an interface based on the functions and enums in this * class and returns it... */ AbstractMetaClass *AbstractMetaClass::extractInterface() { Q_ASSERT(typeEntry()->designatedInterface()); if (m_extracted_interface == 0) { AbstractMetaClass *iface = new AbstractMetaClass; iface->setAttributes(attributes()); iface->setBaseClass(0); iface->setPrimaryInterfaceImplementor(this); iface->setTypeEntry(typeEntry()->designatedInterface()); foreach (AbstractMetaFunction *function, functions()) { if (!function->isConstructor()) iface->addFunction(function->copy()); } // iface->setEnums(enums()); // setEnums(AbstractMetaEnumList()); foreach (const AbstractMetaField *field, fields()) { if (field->isPublic()) { AbstractMetaField *new_field = field->copy(); new_field->setEnclosingClass(iface); iface->addField(new_field); } } m_extracted_interface = iface; addInterface(iface); } return m_extracted_interface; } /******************************************************************************* * Returns a list of all the functions with a given name */ AbstractMetaFunctionList AbstractMetaClass::queryFunctionsByName(const QString &name) const { AbstractMetaFunctionList returned; AbstractMetaFunctionList functions = this->functions(); foreach (AbstractMetaFunction *function, functions) { if (function->name() == name) returned.append(function); } return returned; } /******************************************************************************* * Returns all reference count modifications for any function in the class */ QList AbstractMetaClass::referenceCounts() const { QList returned; AbstractMetaFunctionList functions = this->functions(); foreach (AbstractMetaFunction *function, functions) { returned += function->referenceCounts(this); } return returned; } /******************************************************************************* * Returns a list of all the functions retrieved during parsing which should * be added to the Java API. */ AbstractMetaFunctionList AbstractMetaClass::functionsInTargetLang() const { int default_flags = NormalFunctions | Visible | NotRemovedFromTargetLang; // Interfaces don't implement functions default_flags |= isInterface() ? 0 : ClassImplements; // Only public functions in final classes // default_flags |= isFinal() ? WasPublic : 0; int public_flags = isFinal() ? WasPublic : 0; // Constructors AbstractMetaFunctionList returned = queryFunctions(Constructors | default_flags | public_flags); // Final functions returned += queryFunctions(FinalInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags); // Virtual functions returned += queryFunctions(VirtualInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags); // Static functions returned += queryFunctions(StaticFunctions | default_flags | public_flags); // Empty, private functions, since they aren't caught by the other ones returned += queryFunctions(Empty | Invisible); return returned; } AbstractMetaFunctionList AbstractMetaClass::virtualFunctions() const { AbstractMetaFunctionList list = functionsInShellClass(); AbstractMetaFunctionList returned; foreach (AbstractMetaFunction *f, list) { if (!f->isFinalInCpp() || f->isVirtualSlot()) returned += f; } return returned; } AbstractMetaFunctionList AbstractMetaClass::nonVirtualShellFunctions() const { AbstractMetaFunctionList list = functionsInShellClass(); AbstractMetaFunctionList returned; foreach (AbstractMetaFunction *f, list) { if (f->isFinalInCpp() && !f->isVirtualSlot()) returned += f; } return returned; } /******************************************************************************* * Returns a list of all functions that should be declared and implemented in * the shell class which is generated as a wrapper on top of the actual C++ class */ AbstractMetaFunctionList AbstractMetaClass::functionsInShellClass() const { // Only functions and only protected and public functions int default_flags = NormalFunctions | Visible | WasVisible | NotRemovedFromShell; // All virtual functions AbstractMetaFunctionList returned = queryFunctions(VirtualFunctions | default_flags); // All functions explicitly set to be implemented by the shell class // (mainly superclass functions that are hidden by other declarations) returned += queryFunctions(ForcedShellFunctions | default_flags); // All functions explicitly set to be virtual slots returned += queryFunctions(VirtualSlots | default_flags); return returned; } /******************************************************************************* * Returns a list of all functions that require a public override function to * be generated in the shell class. This includes all functions that were originally * protected in the superclass. */ AbstractMetaFunctionList AbstractMetaClass::publicOverrideFunctions() const { return queryFunctions(NormalFunctions | WasProtected | FinalInCppFunctions | NotRemovedFromTargetLang) + queryFunctions(Signals | WasProtected | FinalInCppFunctions | NotRemovedFromTargetLang); } AbstractMetaFunctionList AbstractMetaClass::virtualOverrideFunctions() const { return queryFunctions(NormalFunctions | NonEmptyFunctions | Visible | VirtualInCppFunctions | NotRemovedFromShell) + queryFunctions(Signals | NonEmptyFunctions | Visible | VirtualInCppFunctions | NotRemovedFromShell); } void AbstractMetaClass::sortFunctions() { qSort(m_functions.begin(), m_functions.end(), function_sorter); } void AbstractMetaClass::setFunctions(const AbstractMetaFunctionList &functions) { m_functions = functions; // Functions must be sorted by name before next loop sortFunctions(); QString currentName; bool hasVirtuals = false; AbstractMetaFunctionList final_functions; foreach (AbstractMetaFunction *f, m_functions) { f->setOwnerClass(this); m_has_virtual_slots |= f->isVirtualSlot(); m_has_virtuals |= !f->isFinal() || f->isVirtualSlot(); m_has_nonpublic |= !f->isPublic(); // If we have non-virtual overloads of a virtual function, we have to implement // all the overloads in the shell class to override the hiding rule if (currentName == f->name()) { hasVirtuals = hasVirtuals || !f->isFinal(); if (f->isFinal()) final_functions += f; } else { if (hasVirtuals && final_functions.size() > 0) { foreach (AbstractMetaFunction *final_function, final_functions) { *final_function += AbstractMetaAttributes::ForceShellImplementation; QString warn = QString("hiding of function '%1' in class '%2'") .arg(final_function->name()).arg(name()); ReportHandler::warning(warn); } } hasVirtuals = !f->isFinal(); final_functions.clear(); if (f->isFinal()) final_functions += f; currentName = f->name(); } } #ifndef QT_NO_DEBUG bool duplicate_function = false; for (int j=0; jmodifications(m_functions.at(j)->implementingClass()); bool removed = false; foreach (const FunctionModification &mod, mods) { if (mod.isRemoveModifier()) { removed = true; break ; } } if (removed) continue ; for (int i=0; imodifications(m_functions.at(i)->implementingClass()); bool removed = false; foreach (const FunctionModification &mod, mods) { if (mod.isRemoveModifier()) { removed = true; break ; } } if (removed) continue ; uint cmp = m_functions.at(i)->compareTo(m_functions.at(j)); if ((cmp & AbstractMetaFunction::EqualName) && (cmp & AbstractMetaFunction::EqualArguments)) { printf("%s.%s mostly equal to %s.%s\n", qPrintable(m_functions.at(i)->implementingClass()->typeEntry()->qualifiedCppName()), qPrintable(m_functions.at(i)->signature()), qPrintable(m_functions.at(j)->implementingClass()->typeEntry()->qualifiedCppName()), qPrintable(m_functions.at(j)->signature())); duplicate_function = true; } } } //Q_ASSERT(!duplicate_function); #endif } bool AbstractMetaClass::hasFieldAccessors() const { foreach (const AbstractMetaField *field, fields()) { if (field->getter() || field->setter()) return true; } return false; } bool AbstractMetaClass::hasDefaultToStringFunction() const { foreach (AbstractMetaFunction *f, queryFunctionsByName("toString")) { if (f->actualMinimumArgumentCount() == 0) { return true; } } return false; } void AbstractMetaClass::addFunction(AbstractMetaFunction *function) { function->setOwnerClass(this); if (!function->isDestructor()) { m_functions << function; qSort(m_functions.begin(), m_functions.end(), function_sorter); } m_has_virtual_slots |= function->isVirtualSlot(); m_has_virtuals |= !function->isFinal() || function->isVirtualSlot(); m_has_nonpublic |= !function->isPublic(); } bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const { if (!other->isSignal()) return false; foreach (const AbstractMetaFunction *f, functions()) { if (f->isSignal() && f->compareTo(other) & AbstractMetaFunction::EqualName) return other->modifiedName() == f->modifiedName(); } return false; } QString AbstractMetaClass::name() const { return QString(m_type_entry->targetLangName()).replace("::", "_"); } bool AbstractMetaClass::hasFunction(const QString &str) const { foreach (const AbstractMetaFunction *f, functions()) if (f->name() == str) return true; return false; } /* Returns true if this class has one or more functions that are protected. If a class has protected members we need to generate a shell class with public accessors to the protected functions, so they can be called from the native functions. */ bool AbstractMetaClass::hasProtectedFunctions() const { foreach (AbstractMetaFunction *func, m_functions) { if (func->isProtected()) return true; } return false; } bool AbstractMetaClass::generateShellClass() const { return m_force_shell_class || (!isFinal() && (hasVirtualFunctions() || hasProtectedFunctions() || hasFieldAccessors())); } QPropertySpec *AbstractMetaClass::propertySpecForRead(const QString &name) const { for (int i=0; iread()) return m_property_specs.at(i); return 0; } QPropertySpec *AbstractMetaClass::propertySpecForWrite(const QString &name) const { for (int i=0; iwrite()) return m_property_specs.at(i); return 0; } QPropertySpec *AbstractMetaClass::propertySpecForReset(const QString &name) const { for (int i=0; ireset()) return m_property_specs.at(i); } return 0; } static bool functions_contains(const AbstractMetaFunctionList &l, const AbstractMetaFunction *func) { foreach (const AbstractMetaFunction *f, l) { if ((f->compareTo(func) & AbstractMetaFunction::PrettySimilar) == AbstractMetaFunction::PrettySimilar) return true; } return false; } AbstractMetaField::AbstractMetaField() : m_getter(0), m_setter(0), m_class(0) { } AbstractMetaField::~AbstractMetaField() { delete m_setter; delete m_getter; } ushort painters; // refcount AbstractMetaField *AbstractMetaField::copy() const { AbstractMetaField *returned = new AbstractMetaField; returned->setEnclosingClass(0); returned->setAttributes(attributes()); returned->setName(name()); returned->setType(type()->copy()); returned->setOriginalAttributes(originalAttributes()); return returned; } static QString upCaseFirst(const QString &str) { Q_ASSERT(!str.isEmpty()); QString s = str; s[0] = s.at(0).toUpper(); return s; } static AbstractMetaFunction *createXetter(const AbstractMetaField *g, const QString &name, uint type) { AbstractMetaFunction *f = new AbstractMetaFunction; f->setName(name); f->setOriginalName(name); f->setOwnerClass(g->enclosingClass()); f->setImplementingClass(g->enclosingClass()); f->setDeclaringClass(g->enclosingClass()); uint attr = AbstractMetaAttributes::Native | AbstractMetaAttributes::Final | type; if (g->isStatic()) attr |= AbstractMetaAttributes::Static; if (g->isPublic()) attr |= AbstractMetaAttributes::Public; else if (g->isProtected()) attr |= AbstractMetaAttributes::Protected; else attr |= AbstractMetaAttributes::Private; f->setAttributes(attr); f->setOriginalAttributes(attr); FieldModificationList mods = g->modifications(); foreach (FieldModification mod, mods) { if (mod.isRenameModifier()) f->setName(mod.renamedTo()); if (mod.isAccessModifier()) { if (mod.isPrivate()) f->setVisibility(AbstractMetaAttributes::Private); else if (mod.isProtected()) f->setVisibility(AbstractMetaAttributes::Protected); else if (mod.isPublic()) f->setVisibility(AbstractMetaAttributes::Public); else if (mod.isFriendly()) f->setVisibility(AbstractMetaAttributes::Friendly); } } return f; } FieldModificationList AbstractMetaField::modifications() const { FieldModificationList mods = enclosingClass()->typeEntry()->fieldModifications(); FieldModificationList returned; foreach (FieldModification mod, mods) { if (mod.name == name()) returned += mod; } return returned; } const AbstractMetaFunction *AbstractMetaField::setter() const { if (m_setter == 0) { m_setter = createXetter(this, "set" + upCaseFirst(name()), AbstractMetaAttributes::SetterFunction); AbstractMetaArgumentList arguments; AbstractMetaArgument *argument = new AbstractMetaArgument; argument->setType(type()->copy()); argument->setName(name()); arguments.append(argument); m_setter->setArguments(arguments); } return m_setter; } const AbstractMetaFunction *AbstractMetaField::getter() const { if (m_getter == 0) { m_getter = createXetter(this, name(), AbstractMetaAttributes::GetterFunction); m_getter->setType(type()); } return m_getter; } bool AbstractMetaClass::hasConstructors() const { return queryFunctions(Constructors).size() != 0; } void AbstractMetaClass::addDefaultConstructor() { AbstractMetaFunction *f = new AbstractMetaFunction; f->setName(name()); f->setOwnerClass(this); f->setFunctionType(AbstractMetaFunction::ConstructorFunction); f->setArguments(AbstractMetaArgumentList()); f->setDeclaringClass(this); uint attr = AbstractMetaAttributes::Native; attr |= AbstractMetaAttributes::Public; f->setAttributes(attr); f->setImplementingClass(this); f->setOriginalAttributes(f->attributes()); addFunction(f); } bool AbstractMetaClass::hasFunction(const AbstractMetaFunction *f) const { return functions_contains(m_functions, f); } /* Goes through the list of functions and returns a list of all functions matching all of the criteria in \a query. */ AbstractMetaFunctionList AbstractMetaClass::queryFunctions(uint query) const { AbstractMetaFunctionList functions; foreach (AbstractMetaFunction *f, m_functions) { if ((query & VirtualSlots) && !f->isVirtualSlot()) continue; if ((query & NotRemovedFromTargetLang) && f->isRemovedFrom(f->implementingClass(), TypeSystem::TargetLangCode)) { continue; } if ((query & NotRemovedFromTargetLang) && !f->isFinal() && f->isRemovedFrom(f->declaringClass(), TypeSystem::TargetLangCode)) { continue; } if ((query & NotRemovedFromShell) && f->isRemovedFrom(f->implementingClass(), TypeSystem::ShellCode)) { continue; } if ((query & NotRemovedFromShell) && !f->isFinal() && f->isRemovedFrom(f->declaringClass(), TypeSystem::ShellCode)) { continue; } if ((query & Visible) && f->isPrivate()) { continue; } if ((query & VirtualInTargetLangFunctions) && f->isFinalInTargetLang()) { continue; } if ((query & Invisible) && !f->isPrivate()) { continue; } if ((query & Empty) && !f->isEmptyFunction()) { continue; } if ((query & WasPublic) && !f->wasPublic()) { continue; } if ((query & WasVisible) && f->wasPrivate()) { continue; } if ((query & WasProtected) && !f->wasProtected()) { continue; } if ((query & ClassImplements) && f->ownerClass() != f->implementingClass()) { continue; } if ((query & Inconsistent) && (f->isFinalInTargetLang() || !f->isFinalInCpp() || f->isStatic())) { continue; } if ((query & FinalInTargetLangFunctions) && !f->isFinalInTargetLang()) { continue; } if ((query & FinalInCppFunctions) && !f->isFinalInCpp()) { continue; } if ((query & VirtualInCppFunctions) && f->isFinalInCpp()) { continue; } if ((query & Signals) && (!f->isSignal())) { continue; } if ((query & ForcedShellFunctions) && (!f->isForcedShellImplementation() || !f->isFinal())) { continue; } if (((query & Constructors) && (!f->isConstructor() || f->ownerClass() != f->implementingClass())) || (f->isConstructor() && (query & Constructors) == 0)) { continue; } // Destructors are never included in the functions of a class currently /* if ((query & Destructors) && (!f->isDestructor() || f->ownerClass() != f->implementingClass()) || f->isDestructor() && (query & Destructors) == 0) { continue; }*/ if ((query & VirtualFunctions) && (f->isFinal() || f->isSignal() || f->isStatic())) { continue; } if ((query & StaticFunctions) && (!f->isStatic() || f->isSignal())) { continue; } if ((query & NonStaticFunctions) && (f->isStatic())) { continue; } if ((query & NonEmptyFunctions) && (f->isEmptyFunction())) { continue; } if ((query & NormalFunctions) && (f->isSignal())) { continue; } if ((query & AbstractFunctions) && !f->isAbstract()) { continue; } functions << f; } // qDebug() << "queried" << m_type_entry->qualifiedCppName() << "got" << functions.size() << "out of" << m_functions.size(); return functions; } bool AbstractMetaClass::hasInconsistentFunctions() const { return cppInconsistentFunctions().size() > 0; } bool AbstractMetaClass::hasSignals() const { return cppSignalFunctions().size() > 0; } /** * Adds the specified interface to this class by adding all the * functions in the interface to this class. */ void AbstractMetaClass::addInterface(AbstractMetaClass *interface) { Q_ASSERT(!m_interfaces.contains(interface)); m_interfaces << interface; if (m_extracted_interface != 0 && m_extracted_interface != interface) m_extracted_interface->addInterface(interface); foreach (AbstractMetaFunction *function, interface->functions()) if (!hasFunction(function) && !function->isConstructor()) { AbstractMetaFunction *cpy = function->copy(); cpy->setImplementingClass(this); // Setup that this function is an interface class. cpy->setInterfaceClass(interface); *cpy += AbstractMetaAttributes::InterfaceFunction; // Copy the modifications in interface into the implementing classes. FunctionModificationList mods = function->modifications(interface); foreach (const FunctionModification &mod, mods) { m_type_entry->addFunctionModification(mod); } // It should be mostly safe to assume that when we implement an interface // we don't "pass on" pure virtual functions to our sublcasses... // *cpy -= AbstractMetaAttributes::Abstract; addFunction(cpy); } } void AbstractMetaClass::setInterfaces(const AbstractMetaClassList &interfaces) { m_interfaces = interfaces; } AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName) { foreach (AbstractMetaEnum *e, m_enums) { if (e->name() == enumName) return e; } if (typeEntry()->designatedInterface()) return extractInterface()->findEnum(enumName); return 0; } /*! Recursivly searches for the enum value named \a enumValueName in this class and its superclasses and interfaces. Values belonging to \a meta_enum are excluded from the search. */ AbstractMetaEnumValue *AbstractMetaClass::findEnumValue(const QString &enumValueName, AbstractMetaEnum *meta_enum) { foreach (AbstractMetaEnum *e, m_enums) { if (e == meta_enum) continue; foreach (AbstractMetaEnumValue *v, e->values()) { if (v->name() == enumValueName) return v; } } if (typeEntry()->designatedInterface()) return extractInterface()->findEnumValue(enumValueName, meta_enum); if (baseClass() != 0) return baseClass()->findEnumValue(enumValueName, meta_enum); return 0; } /*! * Searches through all of this class' enums for a value matching the * name \a enumValueName. The name is excluding the class/namespace * prefix. The function recursivly searches interfaces and baseclasses * of this class. */ AbstractMetaEnum *AbstractMetaClass::findEnumForValue(const QString &enumValueName) { foreach (AbstractMetaEnum *e, m_enums) { foreach (AbstractMetaEnumValue *v, e->values()) { if (v->name() == enumValueName) return e; } } if (typeEntry()->designatedInterface()) return extractInterface()->findEnumForValue(enumValueName); if (baseClass() != 0) return baseClass()->findEnumForValue(enumValueName); return 0; } static void add_extra_include_for_type(AbstractMetaClass *meta_class, const AbstractMetaType *type) { if (type == 0) return; Q_ASSERT(meta_class != 0); const TypeEntry *entry = (type ? type->typeEntry() : 0); if (entry != 0 && entry->isComplex()) { const ComplexTypeEntry *centry = static_cast(entry); ComplexTypeEntry *class_entry = meta_class->typeEntry(); if (class_entry != 0 && centry->include().isValid()) class_entry->addExtraInclude(centry->include()); } if (type->hasInstantiations()) { QList instantiations = type->instantiations(); foreach (AbstractMetaType *instantiation, instantiations) add_extra_include_for_type(meta_class, instantiation); } } static void add_extra_includes_for_function(AbstractMetaClass *meta_class, const AbstractMetaFunction *meta_function) { Q_ASSERT(meta_class != 0); Q_ASSERT(meta_function != 0); add_extra_include_for_type(meta_class, meta_function->type()); AbstractMetaArgumentList arguments = meta_function->arguments(); foreach (AbstractMetaArgument *argument, arguments) add_extra_include_for_type(meta_class, argument->type()); } void AbstractMetaClass::fixFunctions() { if (m_functions_fixed) return; else m_functions_fixed = true; AbstractMetaClass *super_class = baseClass(); AbstractMetaFunctionList funcs = functions(); // printf("fix functions for %s\n", qPrintable(name())); if (super_class != 0) super_class->fixFunctions(); int iface_idx = 0; while (super_class || iface_idx < interfaces().size()) { // printf(" - base: %s\n", qPrintable(super_class->name())); // Since we always traverse the complete hierarchy we are only // interrested in what each super class implements, not what // we may have propagated from their base classes again. AbstractMetaFunctionList super_funcs; if (super_class) { // Super classes can never be final if (super_class->isFinalInTargetLang()) { ReportHandler::warning("Final class '" + super_class->name() + "' set to non-final, as it is extended by other classes"); *super_class -= AbstractMetaAttributes::FinalInTargetLang; } super_funcs = super_class->queryFunctions(AbstractMetaClass::ClassImplements); } else { super_funcs = interfaces().at(iface_idx)->queryFunctions(AbstractMetaClass::NormalFunctions); } QSet funcs_to_add; for (int sfi=0; sfiisRemovedFromAllLanguages(sf->implementingClass())) continue; // we generally don't care about private functions, but we have to get the ones that are // virtual in case they override abstract functions. bool add = (sf->isNormal() || sf->isSignal() || sf->isEmptyFunction()); for (int fi=0; fiisRemovedFromAllLanguages(f->implementingClass())) continue; uint cmp = f->compareTo(sf); if (cmp & AbstractMetaFunction::EqualModifiedName) { // printf(" - %s::%s similar to %s::%s %x vs %x\n", // qPrintable(sf->implementingClass()->typeEntry()->qualifiedCppName()), // qPrintable(sf->name()), // qPrintable(f->implementingClass()->typeEntry()->qualifiedCppName()), // qPrintable(f->name()), // sf->attributes(), // f->attributes()); add = false; if (cmp & AbstractMetaFunction::EqualArguments) { // if (!(cmp & AbstractMetaFunction::EqualReturnType)) { // ReportHandler::warning(QString("%1::%2 and %3::%4 differ in retur type") // .arg(sf->implementingClass()->name()) // .arg(sf->name()) // .arg(f->implementingClass()->name()) // .arg(f->name())); // } // Same function, propegate virtual... if (!(cmp & AbstractMetaFunction::EqualAttributes)) { if (!f->isEmptyFunction()) { if (!sf->isFinalInCpp() && f->isFinalInCpp()) { *f -= AbstractMetaAttributes::FinalInCpp; // printf(" --- inherit virtual\n"); } if (!sf->isFinalInTargetLang() && f->isFinalInTargetLang()) { *f -= AbstractMetaAttributes::FinalInTargetLang; // printf(" --- inherit virtual\n"); } if (!f->isFinalInTargetLang() && f->isPrivate()) { f->setFunctionType(AbstractMetaFunction::EmptyFunction); f->setVisibility(AbstractMetaAttributes::Protected); *f += AbstractMetaAttributes::FinalInTargetLang; ReportHandler::warning(QString("private virtual function '%1' in '%2'") .arg(f->signature()) .arg(f->implementingClass()->name())); } } } if (f->visibility() != sf->visibility()) { QString warn = QString("visibility of function '%1' modified in class '%2'") .arg(f->name()).arg(name()); ReportHandler::warning(warn); // If new visibility is private, we can't // do anything. If it isn't, then we // prefer the parent class's visibility // setting for the function. if (!f->isPrivate() && !sf->isPrivate()) f->setVisibility(sf->visibility()); // Private overrides of abstract functions have to go into the class or // the subclasses will not compile as non-abstract classes. // But they don't need to be implemented, since they can never be called. if (f->isPrivate() && sf->isAbstract()) { f->setFunctionType(AbstractMetaFunction::EmptyFunction); f->setVisibility(sf->visibility()); *f += AbstractMetaAttributes::FinalInTargetLang; *f += AbstractMetaAttributes::FinalInCpp; } } // Set the class which first declares this function, afawk f->setDeclaringClass(sf->declaringClass()); if (sf->isFinalInTargetLang() && !sf->isPrivate() && !f->isPrivate() && !sf->isStatic() && !f->isStatic()) { // Shadowed funcion, need to make base class // function non-virtual if (f->implementingClass() != sf->implementingClass() && f->implementingClass()->inheritsFrom(sf->implementingClass())) { // Check whether the superclass method has been redefined to non-final bool hasNonFinalModifier = false; bool isBaseImplPrivate = false; FunctionModificationList mods = sf->modifications(sf->implementingClass()); foreach (FunctionModification mod, mods) { if (mod.isNonFinal()) { hasNonFinalModifier = true; break; } else if (mod.isPrivate()) { isBaseImplPrivate = true; break; } } if (!hasNonFinalModifier && !isBaseImplPrivate) { ReportHandler::warning(QString::fromLatin1("Shadowing: %1::%2 and %3::%4; Java code will not compile") .arg(sf->implementingClass()->name()) .arg(sf->signature()) .arg(f->implementingClass()->name()) .arg(f->signature())); } } } } if (cmp & AbstractMetaFunction::EqualDefaultValueOverload) { AbstractMetaArgumentList arguments; if (f->arguments().size() < sf->arguments().size()) arguments = sf->arguments(); else arguments = f->arguments(); for (int i=0; isetDefaultValueExpression(QString()); } // Otherwise we have function shadowing and we can // skip the thing... } else if (cmp & AbstractMetaFunction::EqualName && !sf->isSignal()) { // In the case of function shadowing where the function name has been altered to // avoid conflict, we don't copy in the original. add = false; } } if (add) funcs_to_add << sf; } foreach (AbstractMetaFunction *f, funcs_to_add) funcs << f->copy(); if (super_class) super_class = super_class->baseClass(); else iface_idx++; } bool hasPrivateConstructors = false; bool hasPublicConstructors = false; foreach (AbstractMetaFunction *func, funcs) { FunctionModificationList mods = func->modifications(this); foreach (const FunctionModification &mod, mods) { if (mod.isRenameModifier()) { // qDebug() << name() << func->originalName() << func << " from " // << func->implementingClass()->name() << "renamed to" << mod.renamedTo(); func->setName(mod.renamedTo()); } } // Make sure class is abstract if one of the functions is if (func->isAbstract()) { (*this) += AbstractMetaAttributes::Abstract; (*this) -= AbstractMetaAttributes::Final; } if (func->isConstructor()) { if (func->isPrivate()) hasPrivateConstructors = true; else hasPublicConstructors = true; } // Make sure that we include files for all classes that are in use if (!func->isRemovedFrom(this, TypeSystem::ShellCode)) add_extra_includes_for_function(this, func); } if (hasPrivateConstructors && !hasPublicConstructors) { (*this) += AbstractMetaAttributes::Abstract; (*this) -= AbstractMetaAttributes::Final; } foreach (AbstractMetaFunction *f1, funcs) { foreach (AbstractMetaFunction *f2, funcs) { if (f1 != f2) { uint cmp = f1->compareTo(f2); if ((cmp & AbstractMetaFunction::EqualName) && !f1->isFinalInCpp() && f2->isFinalInCpp()) { *f2 += AbstractMetaAttributes::FinalOverload; // qDebug() << f2 << f2->implementingClass()->name() << "::" << f2->name() << f2->arguments().size() << " vs " << f1 << f1->implementingClass()->name() << "::" << f1->name() << f1->arguments().size(); // qDebug() << " " << f2; // AbstractMetaArgumentList f2Args = f2->arguments(); // foreach (AbstractMetaArgument *a, f2Args) // qDebug() << " " << a->type()->name() << a->name(); // qDebug() << " " << f1; // AbstractMetaArgumentList f1Args = f1->arguments(); // foreach (AbstractMetaArgument *a, f1Args) // qDebug() << " " << a->type()->name() << a->name(); } } } } setFunctions(funcs); } QString AbstractMetaType::minimalSignature() const { QString minimalSignature; if (isConstant()) minimalSignature += "const "; minimalSignature += typeEntry()->qualifiedCppName(); if (hasInstantiations()) { QList instantiations = this->instantiations(); minimalSignature += "<"; for (int i=0;i 0) minimalSignature += ","; minimalSignature += instantiations.at(i)->minimalSignature(); } minimalSignature += ">"; } if (isReference()) minimalSignature += "&"; for (int j=0; jisNativeIdBased(); } /******************************************************************************* * Other stuff... */ AbstractMetaEnum *AbstractMetaClassList::findEnum(const EnumTypeEntry *entry) const { Q_ASSERT(entry->isEnum()); QString qualified_name = entry->qualifiedCppName(); int pos = qualified_name.lastIndexOf("::"); QString enum_name; QString class_name; if (pos > 0) { enum_name = qualified_name.mid(pos + 2); class_name = qualified_name.mid(0, pos); } else { enum_name = qualified_name; class_name = TypeDatabase::globalNamespaceClassName(entry); } AbstractMetaClass *meta_class = findClass(class_name); if (!meta_class) { ReportHandler::warning(QString("AbstractMeta::findEnum(), unknown class '%1' in '%2'") .arg(class_name).arg(entry->qualifiedCppName())); return 0; } return meta_class->findEnum(enum_name); } AbstractMetaEnumValue *AbstractMetaEnumValueList::find(const QString &name) const { for (int i=0; iname()) return at(i); } return 0; } AbstractMetaEnumValue *AbstractMetaClassList::findEnumValue(const QString &name) const { QStringList lst = name.split(QLatin1String("::")); Q_ASSERT_X(lst.size() == 2, "AbstractMetaClassList::findEnumValue()", "Expected qualified enum"); QString prefixName = lst.at(0); QString enumName = lst.at(1); AbstractMetaClass *cl = findClass(prefixName); if (cl) return cl->findEnumValue(enumName, 0); ReportHandler::warning(QString("no matching enum '%1'").arg(name)); return 0; } /*! * Searches the list after a class that mathces \a name; either as * C++, Java base name or complete Java package.class name. */ AbstractMetaClass *AbstractMetaClassList::findClass(const QString &name) const { if (name.isEmpty()) return 0; foreach (AbstractMetaClass *c, *this) { if (c->qualifiedCppName() == name) return c; } foreach (AbstractMetaClass *c, *this) { if (c->fullName() == name) return c; } foreach (AbstractMetaClass *c, *this) { if (c->name() == name) return c; } return 0; }