aboutsummaryrefslogtreecommitdiffstats
path: root/ApiExtractor/abstractmetabuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ApiExtractor/abstractmetabuilder.cpp')
-rw-r--r--ApiExtractor/abstractmetabuilder.cpp2962
1 files changed, 2962 insertions, 0 deletions
diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp
new file mode 100644
index 000000000..1d01e9ce2
--- /dev/null
+++ b/ApiExtractor/abstractmetabuilder.cpp
@@ -0,0 +1,2962 @@
+/*
+ * This file is part of the API Extractor project.
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: PySide team <contact@pyside.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "abstractmetabuilder.h"
+#include "reporthandler.h"
+#include "typedatabase.h"
+
+#include "parser/ast.h"
+#include "parser/binder.h"
+#include "parser/control.h"
+#include "parser/default_visitor.h"
+#include "parser/dumptree.h"
+#include "parser/lexer.h"
+#include "parser/parser.h"
+#include "parser/tokens.h"
+
+#include <QDebug>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextCodec>
+#include <QTextStream>
+#include <QVariant>
+#include <QTime>
+#include <QQueue>
+#include <QDir>
+
+#include <cstdio>
+#include <algorithm>
+#include "graph.h"
+#include <QTemporaryFile>
+
+static QString stripTemplateArgs(const QString &name)
+{
+ int pos = name.indexOf('<');
+ return pos < 0 ? name : name.left(pos);
+}
+
+AbstractMetaBuilder::AbstractMetaBuilder() : m_currentClass(0), m_logDirectory(QString('.')+QDir::separator())
+{
+}
+
+AbstractMetaBuilder::~AbstractMetaBuilder()
+{
+ qDeleteAll(m_globalEnums);
+ qDeleteAll(m_globalFunctions);
+ qDeleteAll(m_templates);
+ qDeleteAll(m_metaClasses);
+}
+
+void AbstractMetaBuilder::checkFunctionModifications()
+{
+ TypeDatabase *types = TypeDatabase::instance();
+ SingleTypeEntryHash entryHash = types->entries();
+ QList<TypeEntry*> entries = entryHash.values();
+
+ foreach (TypeEntry* entry, entries) {
+ if (!entry)
+ continue;
+ if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing)
+ continue;
+
+ ComplexTypeEntry* centry = static_cast<ComplexTypeEntry*>(entry);
+ FunctionModificationList modifications = centry->functionModifications();
+
+ foreach (FunctionModification modification, modifications) {
+ QString signature = modification.signature;
+
+ QString name = signature.trimmed();
+ name = name.mid(0, signature.indexOf("("));
+
+ AbstractMetaClass* clazz = m_metaClasses.findClass(centry->qualifiedCppName());
+ if (!clazz)
+ continue;
+
+ AbstractMetaFunctionList functions = clazz->functions();
+ bool found = false;
+ QStringList possibleSignatures;
+ foreach (AbstractMetaFunction *function, functions) {
+ if (function->minimalSignature() == signature && function->implementingClass() == clazz) {
+ found = true;
+ break;
+ }
+
+ if (function->originalName() == name)
+ possibleSignatures.append(function->minimalSignature() + " in " + function->implementingClass()->name());
+ }
+
+ if (!found) {
+ QString warning
+ = QString("signature '%1' for function modification in '%2' not found. Possible candidates: %3")
+ .arg(signature)
+ .arg(clazz->qualifiedCppName())
+ .arg(possibleSignatures.join(", "));
+
+ ReportHandler::warning(warning);
+ }
+ }
+ }
+}
+
+AbstractMetaClass* AbstractMetaBuilder::argumentToClass(ArgumentModelItem argument)
+{
+ AbstractMetaClass* returned = 0;
+ bool ok = false;
+ AbstractMetaType* type = translateType(argument->type(), &ok);
+ if (ok && type && type->typeEntry() && type->typeEntry()->isComplex()) {
+ const TypeEntry *entry = type->typeEntry();
+ returned = m_metaClasses.findClass(entry->name());
+ }
+ delete type;
+ return returned;
+}
+
+/**
+ * Checks the argument of a hash function and flags the type if it is a complex type
+ */
+void AbstractMetaBuilder::registerHashFunction(FunctionModelItem function_item)
+{
+ ArgumentList arguments = function_item->arguments();
+ if (arguments.size() == 1) {
+ if (AbstractMetaClass *cls = argumentToClass(arguments.at(0)))
+ cls->setHasHashFunction(true);
+ }
+}
+
+/**
+ * Check if a class has a debug stream operator that can be used as toString
+ */
+
+void AbstractMetaBuilder::registerToStringCapability(FunctionModelItem function_item)
+{
+ ArgumentList arguments = function_item->arguments();
+ if (arguments.size() == 2) {
+ if (arguments.at(0)->type().toString() == "QDebug") {
+ ArgumentModelItem arg = arguments.at(1);
+ if (AbstractMetaClass *cls = argumentToClass(arg)) {
+ if (arg->type().indirections() < 2)
+ cls->setToStringCapability(true);
+ }
+ }
+ }
+}
+
+void AbstractMetaBuilder::traverseOperatorFunction(FunctionModelItem item)
+{
+ if (item->accessPolicy() != CodeModel::Public)
+ return;
+
+ ArgumentList arguments = item->arguments();
+ AbstractMetaClass* baseoperandClass;
+ bool firstArgumentIsSelf = true;
+ bool unaryOperator = false;
+
+ baseoperandClass = argumentToClass(arguments.at(0));
+
+ if (arguments.size() == 1) {
+ unaryOperator = true;
+ } else if (!baseoperandClass
+ || !(baseoperandClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) {
+ baseoperandClass = argumentToClass(arguments.at(1));
+ firstArgumentIsSelf = false;
+ } else {
+ bool ok;
+ AbstractMetaType* type = translateType(item->type(), &ok);
+ const TypeEntry* retType = ok ? type->typeEntry() : 0;
+ AbstractMetaClass* otherArgClass = argumentToClass(arguments.at(1));
+ if (otherArgClass && retType
+ && (retType->isValue() || retType->isObject())
+ && retType != baseoperandClass->typeEntry()
+ && retType == otherArgClass->typeEntry()) {
+ baseoperandClass = m_metaClasses.findClass(retType);
+ firstArgumentIsSelf = false;
+ }
+ delete type;
+ }
+
+ if (baseoperandClass) {
+ AbstractMetaClass* oldCurrentClass = m_currentClass;
+ m_currentClass = baseoperandClass;
+ AbstractMetaFunction *metaFunction = traverseFunction(item);
+ if (metaFunction && !metaFunction->isInvalid()) {
+ // Strip away first argument, since that is the containing object
+ AbstractMetaArgumentList arguments = metaFunction->arguments();
+ if (firstArgumentIsSelf || unaryOperator) {
+ AbstractMetaArgument* first = arguments.takeFirst();
+ if (!unaryOperator && first->type()->indirections())
+ metaFunction->setPointerOperator(true);
+ delete first;
+ metaFunction->setArguments(arguments);
+ } else {
+ // If the operator method is not unary and the first operator is
+ // not of the same type of its owning class we suppose that it
+ // must be an reverse operator (e.g. CLASS::operator(TYPE, CLASS)).
+ // All operator overloads that operate over a class are already
+ // being added as member functions of that class by the API Extractor.
+ AbstractMetaArgument* last = arguments.takeLast();
+ if (last->type()->indirections())
+ metaFunction->setPointerOperator(true);
+ delete last;
+
+ metaFunction->setArguments(arguments);
+ metaFunction->setReverseOperator(true);
+ }
+ metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction);
+ metaFunction->setVisibility(AbstractMetaFunction::Public);
+ metaFunction->setOriginalAttributes(metaFunction->attributes());
+ setupFunctionDefaults(metaFunction, baseoperandClass);
+ baseoperandClass->addFunction(metaFunction);
+ Q_ASSERT(!metaFunction->wasPrivate());
+ } else if (metaFunction) {
+ delete metaFunction;
+ }
+
+ m_currentClass = oldCurrentClass;
+ }
+}
+
+void AbstractMetaBuilder::traverseStreamOperator(FunctionModelItem item)
+{
+ ArgumentList arguments = item->arguments();
+ if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) {
+ AbstractMetaClass* streamClass = argumentToClass(arguments.at(0));
+ AbstractMetaClass* streamedClass = argumentToClass(arguments.at(1));
+
+ if (streamClass && streamedClass && (streamClass->isStream())) {
+ AbstractMetaClass *oldCurrentClass = m_currentClass;
+ m_currentClass = streamedClass;
+ AbstractMetaFunction *streamFunction = traverseFunction(item);
+
+ if (streamFunction && !streamFunction->isInvalid()) {
+ QString name = item->name();
+ streamFunction->setFunctionType(AbstractMetaFunction::GlobalScopeFunction);
+ // Strip first argument, since that is the containing object
+ AbstractMetaArgumentList arguments = streamFunction->arguments();
+ if (!streamClass->typeEntry()->generateCode())
+ delete arguments.takeLast();
+ else
+ delete arguments.takeFirst();
+
+ streamFunction->setArguments(arguments);
+
+ *streamFunction += AbstractMetaAttributes::Final;
+ *streamFunction += AbstractMetaAttributes::Public;
+ streamFunction->setOriginalAttributes(streamFunction->attributes());
+
+// streamFunction->setType(0);
+
+ AbstractMetaClass *funcClass;
+
+ if (!streamClass->typeEntry()->generateCode()) {
+ AbstractMetaArgumentList reverseArgs = reverseList(streamFunction->arguments());
+ streamFunction->setArguments(reverseArgs);
+ streamFunction->setReverseOperator(true);
+ funcClass = streamedClass;
+ } else {
+ funcClass = streamClass;
+ }
+
+ setupFunctionDefaults(streamFunction, funcClass);
+ funcClass->addFunction(streamFunction);
+ if (funcClass == streamClass)
+ funcClass->typeEntry()->addExtraInclude(streamedClass->typeEntry()->include());
+ else
+ funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include());
+
+ m_currentClass = oldCurrentClass;
+ } else if (streamFunction) {
+ delete streamFunction;
+ }
+
+ }
+ }
+}
+
+void AbstractMetaBuilder::fixQObjectForScope(TypeDatabase *types,
+ NamespaceModelItem scope)
+{
+ foreach (ClassModelItem item, scope->classes()) {
+ QString qualifiedName = item->qualifiedName().join("::");
+ TypeEntry* entry = types->findType(qualifiedName);
+ if (entry) {
+ if (isQObject(qualifiedName) && entry->isComplex())
+ ((ComplexTypeEntry*) entry)->setQObject(true);
+ }
+ }
+
+ foreach (NamespaceModelItem item, scope->namespaceMap().values()) {
+ if (scope != item)
+ fixQObjectForScope(types, item);
+ }
+}
+
+void AbstractMetaBuilder::sortLists()
+{
+ foreach (AbstractMetaClass *cls, m_metaClasses)
+ cls->sortFunctions();
+}
+
+bool AbstractMetaBuilder::build(QIODevice* input)
+{
+ Q_ASSERT(input);
+
+ if (!input->isOpen()) {
+ if (!input->open(QIODevice::ReadOnly))
+ return false;
+ }
+
+ TypeDatabase* types = TypeDatabase::instance();
+
+ QByteArray contents = input->readAll();
+ input->close();
+
+ Control control;
+ Parser p(&control);
+ pool __pool;
+
+ TranslationUnitAST* ast = p.parse(contents, contents.size(), &__pool);
+
+ CodeModel model;
+ Binder binder(&model, p.location());
+ m_dom = binder.run(ast);
+
+ pushScope(model_dynamic_cast<ScopeModelItem>(m_dom));
+
+ QHash<QString, ClassModelItem> typeMap = m_dom->classMap();
+
+ // fix up QObject's in the type system..
+ fixQObjectForScope(types, model_dynamic_cast<NamespaceModelItem>(m_dom));
+
+ // Start the generation...
+ ClassList typeValues = typeMap.values();
+ qSort(typeValues);
+ ClassList::iterator it = std::unique(typeValues.begin(), typeValues.end());
+ typeValues.erase(it, typeValues.end());
+
+ ReportHandler::setProgressReference(typeValues);
+ foreach (ClassModelItem item, typeValues) {
+ ReportHandler::progress("Generating class model...");
+ AbstractMetaClass *cls = traverseClass(item);
+ if (!cls)
+ continue;
+
+ addAbstractMetaClass(cls);
+ }
+ ReportHandler::flush();
+
+ // We need to know all global enums
+ QHash<QString, EnumModelItem> enumMap = m_dom->enumMap();
+ ReportHandler::setProgressReference(enumMap);
+ foreach (EnumModelItem item, enumMap) {
+ ReportHandler::progress("Generating enum model...");
+ AbstractMetaEnum *metaEnum = traverseEnum(item, 0, QSet<QString>());
+ if (metaEnum) {
+ if (metaEnum->typeEntry()->generateCode())
+ m_globalEnums << metaEnum;
+ }
+ }
+ ReportHandler::flush();
+
+ QHash<QString, NamespaceModelItem> namespaceMap = m_dom->namespaceMap();
+ NamespaceList namespaceTypeValues = namespaceMap.values();
+ qSort(namespaceTypeValues);
+ NamespaceList::iterator nsit = std::unique(namespaceTypeValues.begin(), namespaceTypeValues.end());
+ namespaceTypeValues.erase(nsit, namespaceTypeValues.end());
+
+ ReportHandler::setProgressReference(namespaceMap);
+ foreach (NamespaceModelItem item, namespaceTypeValues) {
+ ReportHandler::progress("Generating namespace model...");
+ AbstractMetaClass *metaClass = traverseNamespace(item);
+ if (metaClass)
+ m_metaClasses << metaClass;
+ }
+ ReportHandler::flush();
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ TypeAliasList typeAliases = m_dom->typeAliases();
+ ReportHandler::setProgressReference(typeAliases);
+ foreach (TypeAliasModelItem typeAlias, typeAliases) {
+ ReportHandler::progress("Resolving typedefs...");
+ AbstractMetaClass* cls = traverseTypeAlias(typeAlias);
+ addAbstractMetaClass(cls);
+ }
+ ReportHandler::flush();
+
+ figureOutEnumValues();
+
+ foreach (ClassModelItem item, typeValues)
+ traverseClassMembers(item);
+
+ foreach (NamespaceModelItem item, namespaceTypeValues)
+ traverseNamespaceMembers(item);
+
+ // Global functions
+ foreach (FunctionModelItem func, m_dom->functions()) {
+ if (func->accessPolicy() != CodeModel::Public || func->name().startsWith("operator"))
+ continue;
+
+ FunctionTypeEntry* funcEntry = types->findFunctionType(func->name());
+ if (!funcEntry || !funcEntry->generateCode())
+ continue;
+
+ AbstractMetaFunction* metaFunc = traverseFunction(func);
+ if (!metaFunc)
+ continue;
+
+ if (!funcEntry->hasSignature(metaFunc->minimalSignature())) {
+ delete metaFunc;
+ continue;
+ }
+
+ applyFunctionModifications(metaFunc);
+
+ setInclude(funcEntry, func->fileName());
+ if (metaFunc->typeEntry())
+ delete metaFunc->typeEntry();
+
+ metaFunc->setTypeEntry(funcEntry);
+ m_globalFunctions << metaFunc;
+ }
+
+ ReportHandler::setProgressReference(m_metaClasses);
+ foreach (AbstractMetaClass* cls, m_metaClasses) {
+ ReportHandler::progress("Fixing class inheritance...");
+ if (!cls->isInterface() && !cls->isNamespace())
+ setupInheritance(cls);
+ }
+ ReportHandler::flush();
+
+ ReportHandler::setProgressReference(m_metaClasses);
+ foreach (AbstractMetaClass* cls, m_metaClasses) {
+ ReportHandler::progress("Detecting inconsistencies in class model...");
+ cls->fixFunctions();
+
+ if (!cls->typeEntry()) {
+ ReportHandler::warning(QString("class '%1' does not have an entry in the type system")
+ .arg(cls->name()));
+ } else {
+ bool couldAddDefaultCtors = !cls->isFinalInCpp() && !cls->isInterface() && !cls->isNamespace();
+ if (couldAddDefaultCtors) {
+ if (!cls->hasConstructors())
+ cls->addDefaultConstructor();
+ if (cls->typeEntry()->isValue() && !cls->isAbstract() && !cls->hasCopyConstructor())
+ cls->addDefaultCopyConstructor(ancestorHasPrivateCopyConstructor(cls));
+ }
+ }
+
+ if (cls->isAbstract() && !cls->isInterface())
+ cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + "$ConcreteWrapper");
+ }
+ ReportHandler::flush();
+
+ TypeEntryHash allEntries = types->allEntries();
+ ReportHandler::progress("Detecting inconsistencies in typesystem...");
+ foreach (QList<TypeEntry*> entries, allEntries) {
+ foreach (TypeEntry* entry, entries) {
+
+ if (entry->isPrimitive())
+ continue;
+
+ if ((entry->isValue() || entry->isObject())
+ && !entry->isString()
+ && !entry->isChar()
+ && !entry->isContainer()
+ && !entry->isCustom()
+ && !entry->isVariant()
+ && !m_metaClasses.findClass(entry->qualifiedCppName())) {
+ ReportHandler::warning(QString("type '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.")
+ .arg(entry->qualifiedCppName()));
+ } else if (entry->generateCode() && entry->type() == TypeEntry::FunctionType) {
+ const FunctionTypeEntry* fte = static_cast<const FunctionTypeEntry*>(entry);
+ foreach (QString signature, fte->signatures()) {
+ bool ok = false;
+ foreach (AbstractMetaFunction* func, m_globalFunctions) {
+ if (signature == func->minimalSignature()) {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok) {
+ ReportHandler::warning(QString("Global function '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.")
+ .arg(signature));
+ }
+ }
+ } else if (entry->isEnum()) {
+ const QString name = ((EnumTypeEntry*) entry)->targetLangQualifier();
+ AbstractMetaClass* cls = m_metaClasses.findClass(name);
+
+ bool enumFound = false;
+ if (cls) {
+ enumFound = cls->findEnum(entry->targetLangName());
+ } else { // Global enum
+ foreach (AbstractMetaEnum* metaEnum, m_enums) {
+ if (metaEnum->typeEntry() == entry) {
+ enumFound = true;
+ break;
+ }
+ }
+ }
+ if (!enumFound) {
+ entry->setCodeGeneration(TypeEntry::GenerateNothing);
+ ReportHandler::warning(QString("enum '%1' is specified in typesystem, but not declared")
+ .arg(entry->qualifiedCppName()));
+ }
+
+ }
+ }
+ }
+ ReportHandler::flush();
+
+ {
+ FunctionList hashFunctions = m_dom->findFunctions("qHash");
+ foreach (FunctionModelItem item, hashFunctions)
+ registerHashFunction(item);
+ }
+
+ {
+ FunctionList hashFunctions = m_dom->findFunctions("operator<<");
+ foreach (FunctionModelItem item, hashFunctions)
+ registerToStringCapability(item);
+ }
+
+ {
+ FunctionList binaryOperators = m_dom->findFunctions("operator==")
+ + m_dom->findFunctions("operator!=")
+ + m_dom->findFunctions("operator<=")
+ + m_dom->findFunctions("operator>=")
+ + m_dom->findFunctions("operator<")
+ + m_dom->findFunctions("operator+")
+ + m_dom->findFunctions("operator/")
+ + m_dom->findFunctions("operator*")
+ + m_dom->findFunctions("operator-")
+ + m_dom->findFunctions("operator&")
+ + m_dom->findFunctions("operator|")
+ + m_dom->findFunctions("operator^")
+ + m_dom->findFunctions("operator~")
+ + m_dom->findFunctions("operator>");
+
+ foreach (FunctionModelItem item, binaryOperators)
+ traverseOperatorFunction(item);
+ }
+
+ {
+ FunctionList streamOperators = m_dom->findFunctions("operator<<") + m_dom->findFunctions("operator>>");
+ foreach (FunctionModelItem item, streamOperators)
+ traverseStreamOperator(item);
+ }
+
+ figureOutDefaultEnumArguments();
+ checkFunctionModifications();
+
+ // sort all classes topologically
+ m_metaClasses = classesTopologicalSorted();
+
+ foreach (AbstractMetaClass* cls, m_metaClasses) {
+// setupEquals(cls);
+// setupComparable(cls);
+ setupClonable(cls);
+ setupExternalConversion(cls);
+
+ // sort all inner classes topologically
+ if (!cls->typeEntry()->codeGeneration() || cls->innerClasses().size() < 2)
+ continue;
+
+ cls->setInnerClasses(classesTopologicalSorted(cls));
+ }
+
+ dumpLog();
+
+ sortLists();
+
+ m_currentClass = 0;
+
+ // Functions added to the module on the type system.
+ foreach (AddedFunction addedFunc, types->globalUserFunctions()) {
+ AbstractMetaFunction* metaFunc = traverseFunction(addedFunc);
+ metaFunc->setFunctionType(AbstractMetaFunction::NormalFunction);
+ m_globalFunctions << metaFunc;
+ }
+
+ std::puts("");
+ return true;
+}
+
+void AbstractMetaBuilder::setLogDirectory(const QString& logDir)
+{
+ m_logDirectory = logDir;
+ if (!m_logDirectory.endsWith(QDir::separator()))
+ m_logDirectory.append(QDir::separator());
+}
+
+void AbstractMetaBuilder::addAbstractMetaClass(AbstractMetaClass *cls)
+{
+ if (!cls)
+ return;
+
+ cls->setOriginalAttributes(cls->attributes());
+ if (cls->typeEntry()->isContainer()) {
+ m_templates << cls;
+ } else {
+ m_metaClasses << cls;
+ if (cls->typeEntry()->designatedInterface()) {
+ AbstractMetaClass* interface = cls->extractInterface();
+ m_metaClasses << interface;
+ ReportHandler::debugSparse(QString(" -> interface '%1'").arg(interface->name()));
+ }
+ }
+}
+
+AbstractMetaClass* AbstractMetaBuilder::traverseNamespace(NamespaceModelItem namespaceItem)
+{
+ QString namespaceName = (!m_namespacePrefix.isEmpty() ? m_namespacePrefix + "::" : QString()) + namespaceItem->name();
+ NamespaceTypeEntry *type = TypeDatabase::instance()->findNamespaceType(namespaceName);
+
+ if (TypeDatabase::instance()->isClassRejected(namespaceName)) {
+ m_rejectedClasses.insert(namespaceName, GenerationDisabled);
+ return 0;
+ }
+
+ if (!type) {
+ ReportHandler::warning(QString("namespace '%1' does not have a type entry").arg(namespaceName));
+ return 0;
+ }
+
+ AbstractMetaClass* metaClass = createMetaClass();
+ metaClass->setTypeEntry(type);
+
+ *metaClass += AbstractMetaAttributes::Public;
+
+ m_currentClass = metaClass;
+
+ ReportHandler::debugSparse(QString("namespace '%1.%2'")
+ .arg(metaClass->package())
+ .arg(namespaceItem->name()));
+
+ traverseEnums(model_dynamic_cast<ScopeModelItem>(namespaceItem), metaClass, namespaceItem->enumsDeclarations());
+
+ pushScope(model_dynamic_cast<ScopeModelItem>(namespaceItem));
+ m_namespacePrefix = currentScope()->qualifiedName().join("::");
+
+ ClassList classes = namespaceItem->classes();
+ foreach (ClassModelItem cls, classes) {
+ AbstractMetaClass* mjc = traverseClass(cls);
+ if (mjc) {
+ metaClass->addInnerClass(mjc);
+ mjc->setEnclosingClass(metaClass);
+ addAbstractMetaClass(mjc);
+ }
+ }
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ TypeAliasList typeAliases = namespaceItem->typeAliases();
+ foreach (TypeAliasModelItem typeAlias, typeAliases) {
+ AbstractMetaClass* cls = traverseTypeAlias(typeAlias);
+ if (cls) {
+ metaClass->addInnerClass(cls);
+ cls->setEnclosingClass(metaClass);
+ addAbstractMetaClass(cls);
+ }
+ }
+
+ // Traverse namespaces recursively
+ NamespaceList innerNamespaces = namespaceItem->namespaceMap().values();
+ qSort(innerNamespaces);
+ NamespaceList::iterator it = std::unique(innerNamespaces.begin(), innerNamespaces.end());
+ innerNamespaces.erase(it, innerNamespaces.end());
+ foreach (const NamespaceModelItem &ni, innerNamespaces) {
+ AbstractMetaClass* mjc = traverseNamespace(ni);
+ if (mjc) {
+ metaClass->addInnerClass(mjc);
+ mjc->setEnclosingClass(metaClass);
+ addAbstractMetaClass(mjc);
+ }
+ }
+
+ m_currentClass = 0;
+
+ popScope();
+ m_namespacePrefix = currentScope()->qualifiedName().join("::");
+
+ if (!type->include().isValid())
+ setInclude(type, namespaceItem->fileName());
+
+ return metaClass;
+}
+
+struct Operator
+{
+ enum Type { Complement, Plus, ShiftRight, ShiftLeft, None };
+
+ Operator() : type(None) {}
+
+ int calculate(int x)
+ {
+ switch (type) {
+ case Complement: return ~value;
+ case Plus: return x + value;
+ case ShiftRight: return x >> value;
+ case ShiftLeft: return x << value;
+ case None: return x;
+ }
+ return x;
+ }
+
+ Type type;
+ int value;
+};
+
+
+
+Operator findOperator(QString* s)
+{
+ const char *names[] = {
+ "~",
+ "+",
+ ">>",
+ "<<"
+ };
+
+ for (int i = 0; i < Operator::None; ++i) {
+ QString name = QLatin1String(names[i]);
+ QString str = *s;
+ int splitPoint = str.indexOf(name);
+ if (splitPoint > -1) {
+ bool ok;
+ QString right = str.mid(splitPoint + name.length());
+ Operator op;
+
+ op.value = right.toInt(&ok);
+ if (!ok && right.length() > 0 && right.at(right.length() - 1).toLower() == QLatin1Char('u'))
+ op.value = right.left(right.length() - 1).toUInt(&ok, 0);
+
+ if (ok) {
+ op.type = Operator::Type(i);
+ if (splitPoint > 0)
+ *s = str.left(splitPoint).trimmed();
+ else
+ *s = QString();
+ return op;
+ }
+ }
+ }
+ return Operator();
+}
+
+int AbstractMetaBuilder::figureOutEnumValue(const QString &stringValue,
+ int oldValuevalue,
+ AbstractMetaEnum *metaEnum,
+ AbstractMetaFunction *metaFunction)
+{
+ if (stringValue.isEmpty())
+ return oldValuevalue;
+
+ QStringList stringValues = stringValue.split("|");
+
+ int returnValue = 0;
+
+ bool matched = false;
+
+ for (int i = 0; i < stringValues.size(); ++i) {
+ QString s = stringValues.at(i).trimmed();
+
+ bool ok;
+ int v;
+
+ Operator op = findOperator(&s);
+
+ if (s.length() > 0 && s.at(0) == QLatin1Char('0'))
+ v = s.toUInt(&ok, 0);
+ else if (s.length() > 0 && s.at(s.length() - 1).toLower() == QLatin1Char('u'))
+ v = s.left(s.length() - 1).toUInt(&ok, 0);
+ else
+ v = s.toInt(&ok);
+
+ if (ok || s.isEmpty()) {
+ matched = true;
+ } else if (m_enumValues.contains(s)) {
+ v = m_enumValues[s]->value();
+ matched = true;
+ } else {
+ if (metaEnum) {
+ v = findOutValueFromString(s, matched);
+ if (!matched) {
+ QString enclosingClass = QString(metaEnum->enclosingClass() ? metaEnum->enclosingClass()->name() + "::" : QString());
+ ReportHandler::warning("unhandled enum value: " + s + " in "
+ + enclosingClass + metaEnum->name()
+ + " from header '" + metaEnum->typeEntry()->include().name() + "'");
+ }
+ } else {
+ ReportHandler::warning("unhandled enum value: Unknown enum");
+ }
+ }
+
+ if (matched)
+ returnValue |= op.calculate(v);
+ }
+
+ if (!matched) {
+ QString warn = QString("unmatched enum %1").arg(stringValue);
+
+ if (metaFunction) {
+ warn += QString(" when parsing default value of '%1' in class '%2'")
+ .arg(metaFunction->name())
+ .arg(metaFunction->implementingClass()->name());
+ }
+ warn += " from header '" + metaEnum->typeEntry()->include().name() + "'";
+
+ ReportHandler::warning(warn);
+ returnValue = oldValuevalue;
+ }
+
+ return returnValue;
+}
+
+void AbstractMetaBuilder::figureOutEnumValuesForClass(AbstractMetaClass* metaClass,
+ QSet<AbstractMetaClass*>* classes)
+{
+ AbstractMetaClass* base = metaClass->baseClass();
+
+ if (base && !classes->contains(base))
+ figureOutEnumValuesForClass(base, classes);
+
+ if (classes->contains(metaClass))
+ return;
+
+ AbstractMetaEnumList enums = metaClass->enums();
+ foreach (AbstractMetaEnum* e, enums) {
+ if (!e) {
+ ReportHandler::warning("bad enum in class " + metaClass->name());
+ continue;
+ }
+ AbstractMetaEnumValueList lst = e->values();
+ int value = 0;
+ for (int i = 0; i < lst.size(); ++i) {
+ value = figureOutEnumValue(lst.at(i)->stringValue(), value, e);
+ lst.at(i)->setValue(value);
+ value++;
+ }
+ }
+
+ *classes += metaClass;
+}
+
+
+void AbstractMetaBuilder::figureOutEnumValues()
+{
+ // Keep a set of classes that we already traversed. We use this to
+ // enforce that we traverse base classes prior to subclasses.
+ QSet<AbstractMetaClass*> classes;
+ foreach (AbstractMetaClass *c, m_metaClasses)
+ figureOutEnumValuesForClass(c, &classes);
+
+ foreach (AbstractMetaEnum* metaEnum, m_globalEnums) {
+ AbstractMetaEnumValueList enumValues = metaEnum->values();
+ int value = 0;
+ for (int i = 0; i < enumValues.size(); ++i) {
+ value = figureOutEnumValue(enumValues.at(i)->stringValue(), value, metaEnum);
+ enumValues.at(i)->setValue(value);
+ value++;
+ }
+ }
+}
+
+void AbstractMetaBuilder::figureOutDefaultEnumArguments()
+{
+ foreach (AbstractMetaClass* metaClass, m_metaClasses) {
+ foreach (AbstractMetaFunction* metaFunction, metaClass->functions()) {
+ foreach (AbstractMetaArgument *arg, metaFunction->arguments()) {
+ QString expr = arg->defaultValueExpression();
+ if (expr.isEmpty())
+ continue;
+
+ if (!metaFunction->replacedDefaultExpression(metaFunction->implementingClass(),
+ arg->argumentIndex() + 1).isEmpty()) {
+ continue;
+ }
+
+ arg->setDefaultValueExpression(expr);
+ }
+ }
+ }
+}
+
+
+AbstractMetaEnum* AbstractMetaBuilder::traverseEnum(EnumModelItem enumItem, AbstractMetaClass* enclosing, const QSet<QString> &enumsDeclarations)
+{
+ QString qualifiedName = enumItem->qualifiedName().join("::");
+
+ TypeEntry* typeEntry = 0;
+ if (enumItem->accessPolicy() == CodeModel::Private) {
+ QStringList names = enumItem->qualifiedName();
+ QString enumName = names.last();
+ QString nspace;
+ if (names.size() > 1)
+ nspace = QStringList(names.mid(0, names.size() - 1)).join("::");
+ typeEntry = new EnumTypeEntry(nspace, enumName, 0);
+ TypeDatabase::instance()->addType(typeEntry);
+ } else if (!enumItem->isAnonymous()) {
+ typeEntry = TypeDatabase::instance()->findType(qualifiedName);
+ } else {
+ QStringList tmpQualifiedName = enumItem->qualifiedName();
+ foreach (const EnumeratorModelItem& enumValue, enumItem->enumerators()) {
+ tmpQualifiedName.removeLast();
+ tmpQualifiedName << enumValue->name();
+ qualifiedName = tmpQualifiedName.join("::");
+ typeEntry = TypeDatabase::instance()->findType(qualifiedName);
+ if (typeEntry)
+ break;
+ }
+ }
+
+ QString enumName = enumItem->name();
+
+ QString className;
+ if (m_currentClass)
+ className = m_currentClass->typeEntry()->qualifiedCppName();
+
+ if (TypeDatabase::instance()->isEnumRejected(className, enumName)) {
+ if (typeEntry)
+ typeEntry->setCodeGeneration(TypeEntry::GenerateNothing);
+ m_rejectedEnums.insert(qualifiedName, GenerationDisabled);
+ return 0;
+ }
+
+ if (!typeEntry || !typeEntry->isEnum()) {
+ ReportHandler::warning(QString("enum '%1' does not have a type entry or is not an enum")
+ .arg(qualifiedName));
+ m_rejectedEnums.insert(qualifiedName, NotInTypeSystem);
+ return 0;
+ }
+
+ AbstractMetaEnum* metaEnum = createMetaEnum();
+ if (enumsDeclarations.contains(qualifiedName)
+ || enumsDeclarations.contains(enumName)) {
+ metaEnum->setHasQEnumsDeclaration(true);
+ }
+
+ metaEnum->setTypeEntry((EnumTypeEntry*) typeEntry);
+ switch (enumItem->accessPolicy()) {
+ case CodeModel::Public:
+ *metaEnum += AbstractMetaAttributes::Public;
+ break;
+ case CodeModel::Protected:
+ *metaEnum += AbstractMetaAttributes::Protected;
+ break;
+ case CodeModel::Private:
+ *metaEnum += AbstractMetaAttributes::Private;
+ typeEntry->setCodeGeneration(TypeEntry::GenerateNothing);
+ break;
+ default:
+ break;
+ }
+
+ ReportHandler::debugMedium(QString(" - traversing enum %1").arg(metaEnum->fullName()));
+
+ foreach (EnumeratorModelItem value, enumItem->enumerators()) {
+
+ AbstractMetaEnumValue* metaEnumValue = createMetaEnumValue();
+ metaEnumValue->setName(value->name());
+ // Deciding the enum value...
+
+ metaEnumValue->setStringValue(value->value());
+ metaEnum->addEnumValue(metaEnumValue);
+
+ ReportHandler::debugFull(" - " + metaEnumValue->name() + " = "
+ + metaEnumValue->value());
+
+ // Add into global register...
+ if (enclosing)
+ m_enumValues[enclosing->name() + "::" + metaEnumValue->name()] = metaEnumValue;
+ else
+ m_enumValues[metaEnumValue->name()] = metaEnumValue;
+ }
+
+ m_enums << metaEnum;
+
+ if (!metaEnum->typeEntry()->include().isValid())
+ setInclude(metaEnum->typeEntry(), enumItem->fileName());
+
+ metaEnum->setOriginalAttributes(metaEnum->attributes());
+
+ // Register all enum values on Type database
+ foreach(EnumeratorModelItem e, enumItem->enumerators()) {
+ QString name;
+ if (enclosing) {
+ name += enclosing->name();
+ name += "::";
+ }
+ name += e->name();
+ EnumValueTypeEntry* enumValue = new EnumValueTypeEntry(name, e->value(), static_cast<EnumTypeEntry*>(typeEntry), typeEntry->version());
+ TypeDatabase::instance()->addType(enumValue);
+ }
+
+ return metaEnum;
+}
+
+AbstractMetaClass* AbstractMetaBuilder::traverseTypeAlias(TypeAliasModelItem typeAlias)
+{
+ TypeDatabase* types = TypeDatabase::instance();
+ QString className = stripTemplateArgs(typeAlias->name());
+
+ QString fullClassName = className;
+ // we have an inner class
+ if (m_currentClass) {
+ fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName())
+ + "::" + fullClassName;
+ }
+
+ // If this is the alias for a primitive type
+ // we store the aliased type on the alias
+ // TypeEntry
+ PrimitiveTypeEntry* ptype = types->findPrimitiveType(className);
+ if (ptype) {
+ QString typeAliasName = typeAlias->type().qualifiedName()[0];
+ ptype->setAliasedTypeEntry(types->findPrimitiveType(typeAliasName));
+ return 0;
+ }
+
+
+ // If we haven't specified anything for the typedef, then we don't care
+ ComplexTypeEntry* type = types->findComplexType(fullClassName);
+ if (!type)
+ return 0;
+
+ if (type->isObject())
+ static_cast<ObjectTypeEntry *>(type)->setQObject(isQObject(stripTemplateArgs(typeAlias->type().qualifiedName().join("::"))));
+
+ AbstractMetaClass *metaClass = createMetaClass();
+ metaClass->setTypeAlias(true);
+ metaClass->setTypeEntry(type);
+ metaClass->setBaseClassNames(QStringList() << typeAlias->type().qualifiedName().join("::"));
+ *metaClass += AbstractMetaAttributes::Public;
+
+ // Set the default include file name
+ if (!type->include().isValid())
+ setInclude(type, typeAlias->fileName());
+
+ fillAddedFunctions(metaClass);
+
+ return metaClass;
+}
+
+AbstractMetaClass* AbstractMetaBuilder::traverseClass(ClassModelItem classItem)
+{
+ QString className = stripTemplateArgs(classItem->name());
+ QString fullClassName = className;
+
+ // we have inner an class
+ if (m_currentClass) {
+ fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName())
+ + "::" + fullClassName;
+ }
+
+ ComplexTypeEntry* type = TypeDatabase::instance()->findComplexType(fullClassName);
+ RejectReason reason = NoReason;
+
+ if (fullClassName == "QMetaTypeId") {
+ // QtScript: record which types have been declared
+ int lpos = classItem->name().indexOf('<');
+ int rpos = classItem->name().lastIndexOf('>');
+ if ((lpos != -1) && (rpos != -1)) {
+ QString declaredTypename = classItem->name().mid(lpos + 1, rpos - lpos - 1);
+ m_qmetatypeDeclaredTypenames.insert(declaredTypename);
+ }
+ }
+
+ if (TypeDatabase::instance()->isClassRejected(fullClassName)) {
+ reason = GenerationDisabled;
+ } else if (!type) {
+ TypeEntry *te = TypeDatabase::instance()->findType(fullClassName);
+ if (te && !te->isComplex())
+ reason = RedefinedToNotClass;
+ else
+ reason = NotInTypeSystem;
+ } else if (type->codeGeneration() == TypeEntry::GenerateNothing) {
+ reason = GenerationDisabled;
+ }
+ if (reason != NoReason) {
+ m_rejectedClasses.insert(fullClassName, reason);
+ return 0;
+ }
+
+ if (type->isObject())
+ ((ObjectTypeEntry*)type)->setQObject(isQObject(fullClassName));
+
+ AbstractMetaClass* metaClass = createMetaClass();
+ metaClass->setTypeEntry(type);
+ metaClass->setBaseClassNames(classItem->baseClasses());
+ *metaClass += AbstractMetaAttributes::Public;
+ if (type->stream())
+ metaClass->setStream(true);
+
+ AbstractMetaClass* oldCurrentClass = m_currentClass;
+ m_currentClass = metaClass;
+
+ if (type->isContainer())
+ ReportHandler::debugSparse(QString("container: '%1'").arg(fullClassName));
+ else
+ ReportHandler::debugSparse(QString("class: '%1'").arg(metaClass->fullName()));
+
+ TemplateParameterList template_parameters = classItem->templateParameters();
+ QList<TypeEntry *> template_args;
+ template_args.clear();
+ for (int i = 0; i < template_parameters.size(); ++i) {
+ const TemplateParameterModelItem &param = template_parameters.at(i);
+ TemplateArgumentEntry *param_type = new TemplateArgumentEntry(param->name(), type->version());
+ param_type->setOrdinal(i);
+ template_args.append(param_type);
+ }
+ metaClass->setTemplateArguments(template_args);
+
+ parseQ_Property(metaClass, classItem->propertyDeclarations());
+
+ traverseEnums(model_dynamic_cast<ScopeModelItem>(classItem), metaClass, classItem->enumsDeclarations());
+
+ // Inner classes
+ {
+ QList<ClassModelItem> innerClasses = classItem->classMap().values();
+ foreach (const ClassModelItem &ci, innerClasses) {
+ AbstractMetaClass *cl = traverseClass(ci);
+ if (cl) {
+ cl->setEnclosingClass(metaClass);
+ metaClass->addInnerClass(cl);
+ m_metaClasses << cl;
+ }
+ }
+
+ }
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ TypeAliasList typeAliases = classItem->typeAliases();
+ foreach (TypeAliasModelItem typeAlias, typeAliases) {
+ AbstractMetaClass* cls = traverseTypeAlias(typeAlias);
+ if (cls) {
+ cls->setEnclosingClass(metaClass);
+ addAbstractMetaClass(cls);
+ }
+ }
+
+
+ m_currentClass = oldCurrentClass;
+
+ // Set the default include file name
+ if (!type->include().isValid())
+ setInclude(type, classItem->fileName());
+
+ return metaClass;
+}
+
+void AbstractMetaBuilder::traverseScopeMembers(ScopeModelItem item, AbstractMetaClass* metaClass)
+{
+ // Classes/Namespace members
+ traverseFields(item, metaClass);
+ traverseFunctions(item, metaClass);
+
+ // Inner classes
+ ClassList innerClasses = item->classMap().values();
+ qSort(innerClasses);
+ ClassList::iterator it = std::unique(innerClasses.begin(), innerClasses.end());
+ innerClasses.erase(it, innerClasses.end());
+ foreach (const ClassModelItem& ci, innerClasses)
+ traverseClassMembers(ci);
+}
+
+AbstractMetaClass* AbstractMetaBuilder::currentTraversedClass(ScopeModelItem item)
+{
+ QString className = stripTemplateArgs(item->name());
+ QString fullClassName = className;
+
+ // This is an inner class
+ if (m_currentClass)
+ fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName()) + "::" + fullClassName;
+
+ AbstractMetaClass* metaClass = m_metaClasses.findClass(fullClassName);
+ if (!metaClass)
+ metaClass = m_templates.findClass(fullClassName);
+ return metaClass;
+}
+
+void AbstractMetaBuilder::traverseClassMembers(ClassModelItem item)
+{
+ AbstractMetaClass* metaClass = currentTraversedClass(model_dynamic_cast<ScopeModelItem>(item));
+ if (!metaClass)
+ return;
+
+ AbstractMetaClass* oldCurrentClass = m_currentClass;
+ m_currentClass = metaClass;
+
+ // Class members
+ traverseScopeMembers(model_dynamic_cast<ScopeModelItem>(item), metaClass);
+
+ m_currentClass = oldCurrentClass;
+}
+
+void AbstractMetaBuilder::traverseNamespaceMembers(NamespaceModelItem item)
+{
+ AbstractMetaClass* metaClass = currentTraversedClass(model_dynamic_cast<ScopeModelItem>(item));
+ if (!metaClass)
+ return;
+
+ AbstractMetaClass* oldCurrentClass = m_currentClass;
+ m_currentClass = metaClass;
+
+ // Namespace members
+ traverseScopeMembers(model_dynamic_cast<ScopeModelItem>(item), metaClass);
+
+ // Inner namespaces
+ NamespaceList innerNamespaces = item->namespaceMap().values();
+ qSort(innerNamespaces);
+ NamespaceList::iterator it = std::unique(innerNamespaces.begin(), innerNamespaces.end());
+ innerNamespaces.erase(it, innerNamespaces.end());
+ foreach (const NamespaceModelItem &ni, innerNamespaces)
+ traverseNamespaceMembers(ni);
+
+ m_currentClass = oldCurrentClass;
+}
+
+AbstractMetaField* AbstractMetaBuilder::traverseField(VariableModelItem field, const AbstractMetaClass *cls)
+{
+ QString fieldName = field->name();
+ QString className = m_currentClass->typeEntry()->qualifiedCppName();
+
+ // Ignore friend decl.
+ if (field->isFriend())
+ return 0;
+
+ if (field->accessPolicy() == CodeModel::Private)
+ return 0;
+
+ if (TypeDatabase::instance()->isFieldRejected(className, fieldName)) {
+ m_rejectedFields.insert(className + "::" + fieldName, GenerationDisabled);
+ return 0;
+ }
+
+
+ AbstractMetaField* metaField = createMetaField();
+ metaField->setName(fieldName);
+ metaField->setEnclosingClass(cls);
+
+ bool ok;
+ TypeInfo fieldType = field->type();
+ AbstractMetaType *metaType = translateType(fieldType, &ok);
+
+ if (!metaType || !ok) {
+ ReportHandler::warning(QString("skipping field '%1::%2' with unmatched type '%3'")
+ .arg(m_currentClass->name())
+ .arg(fieldName)
+ .arg(TypeInfo::resolveType(fieldType, currentScope()->toItem()).qualifiedName().join("::")));
+ delete metaField;
+ return 0;
+ }
+
+ metaField->setType(metaType);
+
+ uint attr = 0;
+ if (field->isStatic())
+ attr |= AbstractMetaAttributes::Static;
+
+ CodeModel::AccessPolicy policy = field->accessPolicy();
+ if (policy == CodeModel::Public)
+ attr |= AbstractMetaAttributes::Public;
+ else if (policy == CodeModel::Protected)
+ attr |= AbstractMetaAttributes::Protected;
+ else
+ attr |= AbstractMetaAttributes::Private;
+ metaField->setAttributes(attr);
+
+ return metaField;
+}
+
+void AbstractMetaBuilder::traverseFields(ScopeModelItem scope_item, AbstractMetaClass *metaClass)
+{
+ foreach (VariableModelItem field, scope_item->variables()) {
+ AbstractMetaField* metaField = traverseField(field, metaClass);
+
+ if (metaField && !metaField->isModifiedRemoved()) {
+ metaField->setOriginalAttributes(metaField->attributes());
+ metaClass->addField(metaField);
+ }
+ }
+}
+
+void AbstractMetaBuilder::setupFunctionDefaults(AbstractMetaFunction* metaFunction, AbstractMetaClass *metaClass)
+{
+ // Set the default value of the declaring class. This may be changed
+ // in fixFunctions later on
+ metaFunction->setDeclaringClass(metaClass);
+
+ // Some of the queries below depend on the implementing class being set
+ // to function properly. Such as function modifications
+ metaFunction->setImplementingClass(metaClass);
+
+ if (metaFunction->name() == "operator_equal")
+ metaClass->setHasEqualsOperator(true);
+
+ if (!metaFunction->isFinalInTargetLang()
+ && metaFunction->isRemovedFrom(metaClass, TypeSystem::TargetLangCode)) {
+ *metaFunction += AbstractMetaAttributes::FinalInCpp;
+ }
+}
+
+void AbstractMetaBuilder::fixReturnTypeOfConversionOperator(AbstractMetaFunction* metaFunction)
+{
+ if (!metaFunction->isConversionOperator()
+ || metaFunction->implementingClass()->typeEntry() != metaFunction->type()->typeEntry())
+ return;
+
+ TypeDatabase* types = TypeDatabase::instance();
+ QString castTo = metaFunction->name().remove(QRegExp("^operator ")).trimmed();
+
+ if (castTo.endsWith('&'))
+ castTo.chop(1);
+ if (castTo.startsWith("const "))
+ castTo.remove(0, 6);
+
+ TypeEntry* retType = types->findType(castTo);
+ if (!retType)
+ return;
+
+ AbstractMetaType* metaType = createMetaType();
+ metaType->setTypeEntry(retType);
+ metaFunction->replaceType(metaType);
+}
+
+static bool _compareAbstractMetaTypes(const AbstractMetaType* type, const AbstractMetaType* other)
+{
+ if (!type && !other)
+ return true;
+ if (!type || !other)
+ return false;
+ return type->typeEntry() == other->typeEntry()
+ && type->isConstant() == other->isConstant()
+ && type->isReference() == other->isReference()
+ && type->indirections() == other->indirections();
+}
+
+static bool _compareAbstractMetaFunctions(const AbstractMetaFunction* func, const AbstractMetaFunction* other)
+{
+ if (!func && !other)
+ return true;
+ if (!func || !other)
+ return false;
+ if (func->arguments().count() != other->arguments().count()
+ || func->isConstant() != other->isConstant()
+ || func->isStatic() != other->isStatic()
+ || !_compareAbstractMetaTypes(func->type(), other->type())) {
+ return false;
+ }
+ for (int i = 0; i < func->arguments().count(); ++i) {
+ if (!_compareAbstractMetaTypes(func->arguments().at(i)->type(), other->arguments().at(i)->type()))
+ return false;
+ }
+ return true;
+}
+
+static bool _fixFunctionModelItemType(TypeInfo& type, const AbstractMetaClass* metaClass)
+{
+ if (metaClass->templateArguments().isEmpty()
+ || type.qualifiedName().isEmpty()
+ || type.qualifiedName().first() != metaClass->typeEntry()->qualifiedCppName()) {
+ return false;
+ }
+ QStringList templateTypes;
+ foreach (TypeEntry* templateType, metaClass->templateArguments())
+ templateTypes << templateType->qualifiedCppName();
+ QString fixedTypeName = QString("%1<%2 >").arg(metaClass->typeEntry()->qualifiedCppName()).arg(templateTypes.join(", "));
+ type.setQualifiedName(QStringList(fixedTypeName));
+ return true;
+}
+
+static bool _fixFunctionModelItemTypes(FunctionModelItem& function, const AbstractMetaClass* metaClass)
+{
+ TypeInfo functionType = function->type();
+ bool templateTypeFixed = _fixFunctionModelItemType(functionType, metaClass);
+ if (templateTypeFixed)
+ function->setType(functionType);
+
+ ArgumentList arguments = function->arguments();
+ for (int i = 0; i < arguments.size(); ++i) {
+ ArgumentModelItem arg = arguments.at(i);
+ TypeInfo type = arg->type();
+ bool tmpTypeFixed = _fixFunctionModelItemType(type, metaClass);
+ if (tmpTypeFixed)
+ arg->setType(type);
+ templateTypeFixed |= tmpTypeFixed;
+ }
+ return templateTypeFixed;
+}
+
+void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scopeItem, AbstractMetaClass* metaClass)
+{
+ foreach (FunctionModelItem function, scopeItem->functions()) {
+
+ // This fixes method's arguments and return types that are templates
+ // but the template variable wasn't declared in the C++ header.
+ bool templateTypeFixed = _fixFunctionModelItemTypes(function, metaClass);
+
+ AbstractMetaFunction* metaFunction = traverseFunction(function);
+
+ if (!metaFunction)
+ continue;
+
+ if (templateTypeFixed) {
+ foreach (AbstractMetaFunction* func, metaClass->queryFunctionsByName(metaFunction->name())) {
+ if (_compareAbstractMetaFunctions(metaFunction, func)) {
+ delete metaFunction;
+ metaFunction = 0;
+ break;
+ }
+ }
+ if (!metaFunction)
+ continue;
+ }
+
+ metaFunction->setOriginalAttributes(metaFunction->attributes());
+ if (metaClass->isNamespace())
+ *metaFunction += AbstractMetaAttributes::Static;
+
+ QPropertySpec *read = 0;
+ if (!metaFunction->isSignal() && (read = metaClass->propertySpecForRead(metaFunction->name()))) {
+ // Property reader must be in the form "<type> name()"
+ if (metaFunction->type() && (read->type() == metaFunction->type()->typeEntry()) && (metaFunction->arguments().size() == 0)) {
+ *metaFunction += AbstractMetaAttributes::PropertyReader;
+ metaFunction->setPropertySpec(read);
+ }
+ } else if (QPropertySpec* write = metaClass->propertySpecForWrite(metaFunction->name())) {
+ // Property setter must be in the form "void name(<type>)"
+ // make sure the function was created with all aguments, some argument can be missing during the pareser because of errors on typesystem
+ if ((!metaFunction->type()) && (metaFunction->arguments().size() == 1) && (write->type() == metaFunction->arguments().at(0)->type()->typeEntry())) {
+ *metaFunction += AbstractMetaAttributes::PropertyWriter;
+ metaFunction->setPropertySpec(write);
+ }
+ } else if (QPropertySpec* reset = metaClass->propertySpecForReset(metaFunction->name())) {
+ // Property resetter must be in the form "void name()"
+ if ((!metaFunction->type()) && (metaFunction->arguments().size() == 0)) {
+ *metaFunction += AbstractMetaAttributes::PropertyResetter;
+ metaFunction->setPropertySpec(reset);
+ }
+ }
+
+ // Can not use metaFunction->isCopyConstructor() because
+ // the function wasn't assigned to its owner class yet.
+ bool isCopyCtor = false;
+ if (metaFunction->isConstructor() && metaFunction->arguments().size() == 1) {
+ const AbstractMetaType* argType = metaFunction->arguments().first()->type();
+ isCopyCtor = argType->isConstant()
+ && argType->isReference()
+ && argType->typeEntry()->name() == metaFunction->name();
+ }
+
+ bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate();
+ bool isInvalidConstructor = metaFunction->isConstructor()
+ && ((metaFunction->isPrivate() && !isCopyCtor) || metaFunction->isInvalid());
+
+ if ((isInvalidDestructor || isInvalidConstructor)
+ && !metaClass->hasNonPrivateConstructor()) {
+ *metaClass += AbstractMetaAttributes::Final;
+ } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) {
+ *metaClass -= AbstractMetaAttributes::Final;
+ metaClass->setHasNonPrivateConstructor(true);
+ }
+
+ // Classes with virtual destructors should always have a shell class
+ // (since we aren't registering the destructors, we need this extra check)
+ if (metaFunction->isDestructor() && !metaFunction->isFinal())
+ metaClass->setForceShellClass(true);
+
+ if (!metaFunction->isDestructor()
+ && !metaFunction->isInvalid()
+ && !(metaFunction->isPrivate() && metaFunction->isConstructor() && !isCopyCtor)) {
+
+ setupFunctionDefaults(metaFunction, metaClass);
+
+ if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction)) {
+ QString warn = QString("signal '%1' in class '%2' is overloaded.")
+ .arg(metaFunction->name()).arg(metaClass->name());
+ ReportHandler::warning(warn);
+ }
+
+ if (metaFunction->isSignal() && !metaClass->isQObject()) {
+ QString warn = QString("signal '%1' in non-QObject class '%2'")
+ .arg(metaFunction->name()).arg(metaClass->name());
+ ReportHandler::warning(warn);
+ }
+
+ if (metaFunction->isConversionOperator())
+ fixReturnTypeOfConversionOperator(metaFunction);
+
+ metaClass->addFunction(metaFunction);
+ applyFunctionModifications(metaFunction);
+ } else if (metaFunction->isDestructor()) {
+ metaClass->setHasPrivateDestructor(metaFunction->isPrivate());
+ metaClass->setHasProtectedDestructor(metaFunction->isProtected());
+ metaClass->setHasVirtualDestructor(metaFunction->isVirtual());
+ }
+ if (!metaFunction->ownerClass()) {
+ delete metaFunction;
+ metaFunction = 0;
+ }
+ }
+
+ fillAddedFunctions(metaClass);
+}
+
+void AbstractMetaBuilder::fillAddedFunctions(AbstractMetaClass* metaClass)
+{
+ // Add the functions added by the typesystem
+ foreach (AddedFunction addedFunc, metaClass->typeEntry()->addedFunctions())
+ traverseFunction(addedFunc, metaClass);
+}
+
+void AbstractMetaBuilder::applyFunctionModifications(AbstractMetaFunction* func)
+{
+ FunctionModificationList mods = func->modifications(func->implementingClass());
+ AbstractMetaFunction& funcRef = *func;
+ foreach (FunctionModification mod, mods) {
+ if (mod.isRenameModifier()) {
+ func->setOriginalName(func->name());
+ func->setName(mod.renamedTo());
+ } else if (mod.isAccessModifier()) {
+ funcRef -= AbstractMetaAttributes::Public;
+ funcRef -= AbstractMetaAttributes::Protected;
+ funcRef -= AbstractMetaAttributes::Private;
+ funcRef -= AbstractMetaAttributes::Friendly;
+
+ if (mod.isPublic())
+ funcRef += AbstractMetaAttributes::Public;
+ else if (mod.isProtected())
+ funcRef += AbstractMetaAttributes::Protected;
+ else if (mod.isPrivate())
+ funcRef += AbstractMetaAttributes::Private;
+ else if (mod.isFriendly())
+ funcRef += AbstractMetaAttributes::Friendly;
+ }
+
+ if (mod.isFinal())
+ funcRef += AbstractMetaAttributes::FinalInTargetLang;
+ else if (mod.isNonFinal())
+ funcRef -= AbstractMetaAttributes::FinalInTargetLang;
+ }
+}
+
+bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *metaClass)
+{
+ Q_ASSERT(!metaClass->isInterface());
+
+ if (m_setupInheritanceDone.contains(metaClass))
+ return true;
+
+ m_setupInheritanceDone.insert(metaClass);
+
+ QStringList baseClasses = metaClass->baseClassNames();
+
+ TypeDatabase* types = TypeDatabase::instance();
+
+ // we only support our own containers and ONLY if there is only one baseclass
+ if (baseClasses.size() == 1 && baseClasses.first().count('<') == 1) {
+ QStringList scope = metaClass->typeEntry()->qualifiedCppName().split("::");
+ scope.removeLast();
+ for (int i = scope.size(); i >= 0; --i) {
+ QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join("::") + "::" : QString();
+ QString completeName = prefix + baseClasses.first();
+ TypeParser::Info info = TypeParser::parse(completeName);
+ QString baseName = info.qualified_name.join("::");
+
+ AbstractMetaClass* templ = 0;
+ foreach (AbstractMetaClass *c, m_templates) {
+ if (c->typeEntry()->name() == baseName) {
+ templ = c;
+ break;
+ }
+ }
+
+ if (!templ)
+ templ = m_metaClasses.findClass(baseName);
+
+ if (templ) {
+ setupInheritance(templ);
+ inheritTemplate(metaClass, templ, info);
+ metaClass->typeEntry()->setBaseContainerType(templ->typeEntry());
+ return true;
+ }
+ ComplexTypeEntry* baseContainerType = types->findContainerType(baseName);
+ if (baseContainerType)
+ metaClass->typeEntry()->setBaseContainerType(baseContainerType);
+ }
+
+ ReportHandler::warning(QString("template baseclass '%1' of '%2' is not known")
+ .arg(baseClasses.first())
+ .arg(metaClass->name()));
+ return false;
+ }
+
+ int primary = -1;
+ int primaries = 0;
+ for (int i = 0; i < baseClasses.size(); ++i) {
+
+ if (types->isClassRejected(baseClasses.at(i)))
+ continue;
+
+ TypeEntry* baseClassEntry = types->findType(baseClasses.at(i));
+ if (!baseClassEntry)
+ ReportHandler::warning(QString("class '%1' inherits from unknown base class '%2'")
+ .arg(metaClass->name()).arg(baseClasses.at(i)));
+
+ // true for primary base class
+ else if (!baseClassEntry->designatedInterface()) {
+ primaries++;
+ primary = i;
+ }
+ }
+
+ if (primary >= 0) {
+ AbstractMetaClass* baseClass = m_metaClasses.findClass(baseClasses.at(primary));
+ if (!baseClass) {
+ ReportHandler::warning(QString("unknown baseclass for '%1': '%2'")
+ .arg(metaClass->name())
+ .arg(baseClasses.at(primary)));
+ return false;
+ }
+ metaClass->setBaseClass(baseClass);
+ }
+
+ for (int i = 0; i < baseClasses.size(); ++i) {
+ if (types->isClassRejected(baseClasses.at(i)))
+ continue;
+
+ if (i != primary) {
+ AbstractMetaClass* baseClass = m_metaClasses.findClass(baseClasses.at(i));
+ if (!baseClass) {
+ ReportHandler::warning(QString("class not found for setup inheritance '%1'").arg(baseClasses.at(i)));
+ return false;
+ }
+
+ setupInheritance(baseClass);
+
+ QString interfaceName = baseClass->isInterface() ? InterfaceTypeEntry::interfaceName(baseClass->name()) : baseClass->name();
+ AbstractMetaClass* iface = m_metaClasses.findClass(interfaceName);
+ if (!iface) {
+ ReportHandler::warning(QString("unknown interface for '%1': '%2'")
+ .arg(metaClass->name())
+ .arg(interfaceName));
+ return false;
+ }
+ metaClass->addInterface(iface);
+
+ AbstractMetaClassList interfaces = iface->interfaces();
+ foreach (AbstractMetaClass* iface, interfaces)
+ metaClass->addInterface(iface);
+ }
+ }
+
+ return true;
+}
+
+void AbstractMetaBuilder::traverseEnums(ScopeModelItem scopeItem, AbstractMetaClass* metaClass, const QStringList &enumsDeclarations)
+{
+ EnumList enums = scopeItem->enums();
+ foreach (EnumModelItem enumItem, enums) {
+ AbstractMetaEnum* metaEnum = traverseEnum(enumItem, metaClass, QSet<QString>::fromList(enumsDeclarations));
+ if (metaEnum) {
+ metaClass->addEnum(metaEnum);
+ metaEnum->setEnclosingClass(metaClass);
+ }
+ }
+}
+
+AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& addedFunc)
+{
+ return traverseFunction(addedFunc, 0);
+}
+
+AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& addedFunc, AbstractMetaClass* metaClass)
+{
+ AbstractMetaFunction* metaFunction = createMetaFunction();
+ metaFunction->setConstant(addedFunc.isConstant());
+ metaFunction->setName(addedFunc.name());
+ metaFunction->setOriginalName(addedFunc.name());
+ int visibility = addedFunc.access() == AddedFunction::Public ? AbstractMetaAttributes::Public : AbstractMetaAttributes::Protected;
+ metaFunction->setVisibility(visibility);
+ metaFunction->setUserAdded(true);
+ AbstractMetaAttributes::Attribute isStatic = addedFunc.isStatic() ? AbstractMetaFunction::Static : AbstractMetaFunction::None;
+ metaFunction->setAttributes(metaFunction->attributes() | AbstractMetaAttributes::Final | isStatic);
+ metaFunction->setType(translateType(addedFunc.version(), addedFunc.returnType()));
+
+
+ QList<AddedFunction::TypeInfo> args = addedFunc.arguments();
+ AbstractMetaArgumentList metaArguments;
+
+ for (int i = 0; i < args.count(); ++i) {
+ AddedFunction::TypeInfo& typeInfo = args[i];
+ AbstractMetaArgument* metaArg = createMetaArgument();
+ AbstractMetaType* type = translateType(addedFunc.version(), typeInfo);
+ decideUsagePattern(type);
+ metaArg->setType(type);
+ metaArg->setArgumentIndex(i);
+ metaArg->setDefaultValueExpression(typeInfo.defaultValue);
+ metaArg->setOriginalDefaultValueExpression(typeInfo.defaultValue);
+ metaArguments.append(metaArg);
+ }
+
+ metaFunction->setArguments(metaArguments);
+ if (metaFunction->isOperatorOverload() && !metaFunction->isCallOperator()) {
+ if (metaArguments.size() > 2) {
+ ReportHandler::warning("An operator overload need to have 0, 1 or 2 arguments if it's reverse.");
+ } else if (metaArguments.size() == 2) {
+ // Check if it's a reverse operator
+ if (metaArguments[1]->type()->typeEntry() == metaClass->typeEntry()) {
+ metaFunction->setReverseOperator(true);
+ // we need to call these two function to cache the old signature (with two args)
+ // we do this buggy behaviour to comply with the original apiextractor buggy behaviour.
+ metaFunction->signature();
+ metaFunction->minimalSignature();
+ metaArguments.removeLast();
+ metaFunction->setArguments(metaArguments);
+ } else {
+ ReportHandler::warning("Operator overload can have two arguments only if it's a reverse operator!");
+ }
+ }
+ }
+
+
+ // Find the correct default values
+ for (int i = 0; i < metaArguments.size(); ++i) {
+ AbstractMetaArgument* metaArg = metaArguments.at(i);
+
+ //use relace-default-expression for set default value
+ QString replacedExpression;
+ if (m_currentClass)
+ replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1);
+
+ if (!replacedExpression.isEmpty()) {
+ QString expr = replacedExpression;
+ if (!metaFunction->removedDefaultExpression(m_currentClass, i + 1)) {
+ metaArg->setDefaultValueExpression(expr);
+ metaArg->setOriginalDefaultValueExpression(expr);
+
+ if (metaArg->type()->isEnum() || metaArg->type()->isFlags())
+ m_enumDefaultArguments << QPair<AbstractMetaArgument*, AbstractMetaFunction*>(metaArg, metaFunction);
+ }
+ }
+ }
+
+ metaFunction->setOriginalAttributes(metaFunction->attributes());
+ fixArgumentNames(metaFunction);
+
+ if (metaClass) {
+ const AbstractMetaArgumentList fargs = metaFunction->arguments();
+ if (metaClass->isNamespace())
+ *metaFunction += AbstractMetaFunction::Static;
+ if (metaFunction->name() == metaClass->name()) {
+ metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction);
+ if (fargs.size() == 1 && fargs.first()->type()->typeEntry()->isCustom())
+ metaFunction->setExplicit(true);
+ } else {
+ metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction);
+ }
+
+ metaFunction->setDeclaringClass(metaClass);
+ metaFunction->setImplementingClass(metaClass);
+ metaClass->addFunction(metaFunction);
+ metaClass->setHasNonPrivateConstructor(true);
+ }
+
+ return metaFunction;
+}
+
+void AbstractMetaBuilder::fixArgumentNames(AbstractMetaFunction* func)
+{
+ if (func->arguments().isEmpty())
+ return;
+ foreach (FunctionModification mod, func->modifications(m_currentClass)) {
+ foreach (ArgumentModification argMod, mod.argument_mods) {
+ if (!argMod.renamed_to.isEmpty()) {
+ AbstractMetaArgument* arg = func->arguments().at(argMod.index - 1);
+ arg->setOriginalName(arg->name());
+ arg->setName(argMod.renamed_to, false);
+ }
+ }
+ }
+
+ int i = 1;
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ if (arg->name().isEmpty())
+ arg->setName("arg__" + QString::number(i), false);
+ ++i;
+ }
+}
+
+AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(FunctionModelItem functionItem)
+{
+ QString functionName = functionItem->name();
+ QString className;
+ if (m_currentClass)
+ className = m_currentClass->typeEntry()->qualifiedCppName();
+
+ if (TypeDatabase::instance()->isFunctionRejected(className, functionName)) {
+ m_rejectedFunctions.insert(className + "::" + functionName, GenerationDisabled);
+ return 0;
+ }
+
+ Q_ASSERT(functionItem->functionType() == CodeModel::Normal
+ || functionItem->functionType() == CodeModel::Signal
+ || functionItem->functionType() == CodeModel::Slot);
+
+ if (functionItem->isFriend())
+ return 0;
+
+ AbstractMetaFunction* metaFunction = createMetaFunction();
+ metaFunction->setConstant(functionItem->isConstant());
+
+ ReportHandler::debugMedium(QString(" - %2()").arg(functionName));
+
+ metaFunction->setName(functionName);
+ metaFunction->setOriginalName(functionItem->name());
+
+ if (functionItem->isAbstract())
+ *metaFunction += AbstractMetaAttributes::Abstract;
+
+ if (!metaFunction->isAbstract())
+ *metaFunction += AbstractMetaAttributes::Native;
+
+ if (!functionItem->isVirtual())
+ *metaFunction += AbstractMetaAttributes::Final;
+
+ if (functionItem->isInvokable())
+ *metaFunction += AbstractMetaAttributes::Invokable;
+
+ if (functionItem->isStatic()) {
+ *metaFunction += AbstractMetaAttributes::Static;
+ *metaFunction += AbstractMetaAttributes::Final;
+ }
+
+ // Access rights
+ if (functionItem->accessPolicy() == CodeModel::Public)
+ *metaFunction += AbstractMetaAttributes::Public;
+ else if (functionItem->accessPolicy() == CodeModel::Private)
+ *metaFunction += AbstractMetaAttributes::Private;
+ else
+ *metaFunction += AbstractMetaAttributes::Protected;
+
+
+ QString strippedClassName = className;
+ int cc_pos = strippedClassName.lastIndexOf("::");
+ if (cc_pos > 0)
+ strippedClassName = strippedClassName.mid(cc_pos + 2);
+
+ TypeInfo functionType = functionItem->type();
+ if (functionName.startsWith('~')) {
+ metaFunction->setFunctionType(AbstractMetaFunction::DestructorFunction);
+ metaFunction->setInvalid(true);
+ } else if (stripTemplateArgs(functionName) == strippedClassName) {
+ metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction);
+ metaFunction->setExplicit(functionItem->isExplicit());
+ metaFunction->setName(m_currentClass->name());
+ } else {
+ bool ok;
+ AbstractMetaType* type = translateType(functionType, &ok);
+
+ if (!ok) {
+ Q_ASSERT(type == 0);
+ ReportHandler::warning(QString("skipping function '%1::%2', unmatched return type '%3'")
+ .arg(className)
+ .arg(functionItem->name())
+ .arg(functionItem->type().toString()));
+ m_rejectedFunctions[className + "::" + functionName] =
+ UnmatchedReturnType;
+ metaFunction->setInvalid(true);
+ return metaFunction;
+ }
+
+ metaFunction->setType(type);
+
+ if (functionItem->functionType() == CodeModel::Signal)
+ metaFunction->setFunctionType(AbstractMetaFunction::SignalFunction);
+ else if (functionItem->functionType() == CodeModel::Slot)
+ metaFunction->setFunctionType(AbstractMetaFunction::SlotFunction);
+ }
+
+ ArgumentList arguments = functionItem->arguments();
+
+ if (arguments.size() == 1) {
+ ArgumentModelItem arg = arguments.at(0);
+ TypeInfo type = arg->type();
+ if (type.qualifiedName().first() == "void" && type.indirections() == 0)
+ delete arguments.takeFirst();
+ }
+
+ AbstractMetaArgumentList metaArguments;
+
+ for (int i = 0; i < arguments.size(); ++i) {
+ ArgumentModelItem arg = arguments.at(i);
+
+ bool ok;
+ AbstractMetaType* metaType = translateType(arg->type(), &ok);
+ if (!ok) {
+ Q_ASSERT(metaType == 0);
+ ReportHandler::warning(QString("skipping function '%1::%2', "
+ "unmatched parameter type '%3'")
+ .arg(className)
+ .arg(functionItem->name())
+ .arg(arg->type().toString()));
+ m_rejectedFunctions[className + "::" + functionName] =
+ UnmatchedArgumentType;
+ metaFunction->setInvalid(true);
+ return metaFunction;
+ }
+
+ AbstractMetaArgument* metaArgument = createMetaArgument();
+
+ metaArgument->setType(metaType);
+ metaArgument->setName(arg->name());
+ metaArgument->setArgumentIndex(i);
+ metaArguments << metaArgument;
+ }
+
+ metaFunction->setArguments(metaArguments);
+
+ // Find the correct default values
+ for (int i = 0; i < arguments.size(); ++i) {
+ ArgumentModelItem arg = arguments.at(i);
+ AbstractMetaArgument* metaArg = metaArguments.at(i);
+
+ //use relace-default-expression for set default value
+ QString replacedExpression;
+ if (m_currentClass) {
+ replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1);
+ } else {
+ FunctionModificationList mods = TypeDatabase::instance()->functionModifications(metaFunction->minimalSignature());
+ if (!mods.isEmpty()) {
+ QList<ArgumentModification> argMods = mods.first().argument_mods;
+ if (!argMods.isEmpty())
+ replacedExpression = argMods.first().replacedDefaultExpression;
+ }
+ }
+
+ bool hasDefaultValue = false;
+ if (arg->defaultValue() || !replacedExpression.isEmpty()) {
+ QString expr = arg->defaultValueExpression();
+ expr = fixDefaultValue(arg, metaArg->type(), metaFunction, m_currentClass, i);
+ metaArg->setOriginalDefaultValueExpression(expr);
+
+ if (metaFunction->removedDefaultExpression(m_currentClass, i + 1)) {
+ expr = "";
+ } else if (!replacedExpression.isEmpty()) {
+ expr = replacedExpression;
+ }
+ metaArg->setDefaultValueExpression(expr);
+
+ if (metaArg->type()->isEnum() || metaArg->type()->isFlags())
+ m_enumDefaultArguments << QPair<AbstractMetaArgument *, AbstractMetaFunction *>(metaArg, metaFunction);
+
+ hasDefaultValue = !expr.isEmpty();
+ }
+
+ //Check for missing argument name
+ if (hasDefaultValue
+ && !metaArg->hasName()
+ && !metaFunction->isOperatorOverload()
+ && !metaFunction->isSignal()
+ && metaFunction->argumentName(i+1, false, m_currentClass).isEmpty()) {
+ ReportHandler::warning(QString("Argument %1 on function '%2::%3' has default expression but does not have name.").arg(i+1).arg(className).arg(metaFunction->minimalSignature()));
+ }
+
+ }
+
+ fixArgumentNames(metaFunction);
+ return metaFunction;
+}
+
+AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunction::TypeInfo& typeInfo)
+{
+ Q_ASSERT(!typeInfo.name.isEmpty());
+ TypeDatabase* typeDb = TypeDatabase::instance();
+ TypeEntry* type;
+
+ QString typeName = typeInfo.name;
+
+ if (typeName == "void")
+ return 0;
+
+ type = typeDb->findType(typeName);
+
+ // test if the type is a template, like a container
+ bool isTemplate = false;
+ QString templateArg;
+ if (!type) {
+ QRegExp r("(.*)<(.*)>$");
+ if (r.indexIn(typeInfo.name) != -1) {
+ templateArg = r.cap(2);
+ if (templateArg.contains(','))
+ ReportHandler::warning("add-function tag doesn't support container types with more than one argument or template arguments.");
+ else
+ isTemplate = (type = typeDb->findContainerType(r.cap(1)));
+ }
+ }
+
+ if (!type) {
+ QStringList candidates;
+ SingleTypeEntryHash entries = typeDb->entries();
+ foreach (QString candidate, entries.keys()) {
+ // Let's try to find the type in different scopes.
+ if (candidate.endsWith("::"+typeName))
+ candidates << candidate;
+ }
+
+ QString msg = QString("Type '%1' wasn't found in the type database.\n").arg(typeName);
+
+ if (candidates.isEmpty())
+ qFatal(qPrintable(QString(msg + "Declare it in the type system using the proper <*-type> tag.")), NULL);
+
+ msg += "Remember to inform the full qualified name for the type you want to use.\nCandidates are:\n";
+ candidates.sort();
+ foreach (const QString& candidate, candidates) {
+ msg += " " + candidate + "\n";
+ }
+ qFatal(qPrintable(msg), NULL);
+ }
+
+ AbstractMetaType* metaType = createMetaType();
+ metaType->setTypeEntry(type);
+ metaType->setIndirections(typeInfo.indirections);
+ metaType->setReference(typeInfo.isReference);
+ metaType->setConstant(typeInfo.isConstant);
+ if (isTemplate) {
+ type = typeDb->findType(templateArg);
+ if (type) {
+ AbstractMetaType* metaArgType = createMetaType();
+ metaArgType->setTypeEntry(type);
+ metaType->addInstantiation(metaArgType);
+ metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
+ }
+ }
+
+ return metaType;
+}
+
+static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName)
+{
+ const TypeEntry* type = 0;
+ QStringList context = metaClass->qualifiedCppName().split("::");
+ while(!type && (context.size() > 0) ) {
+ type = TypeDatabase::instance()->findType(context.join("::") + "::" + qualifiedName);
+ context.removeLast();
+ }
+ return type;
+}
+
+AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, bool *ok, bool resolveType, bool resolveScope)
+{
+ Q_ASSERT(ok);
+ *ok = true;
+
+ // 1. Test the type info without resolving typedefs in case this is present in the
+ // type system
+ TypeInfo typei;
+ if (resolveType) {
+ bool ok;
+ AbstractMetaType* t = translateType(_typei, &ok, false, resolveScope);
+ if (t && ok)
+ return t;
+ Q_ASSERT(t == 0);
+ }
+
+ if (!resolveType) {
+ typei = _typei;
+ } else {
+ // Go through all parts of the current scope (including global namespace)
+ // to resolve typedefs. The parser does not properly resolve typedefs in
+ // the global scope when they are referenced from inside a namespace.
+ // This is a work around to fix this bug since fixing it in resolveType
+ // seemed non-trivial
+ int i = m_scopes.size() - 1;
+ while (i >= 0) {
+ typei = TypeInfo::resolveType(_typei, m_scopes.at(i--)->toItem());
+ if (typei.qualifiedName().join("::") != _typei.qualifiedName().join("::"))
+ break;
+ }
+
+ }
+
+ if (typei.isFunctionPointer()) {
+ *ok = false;
+ return 0;
+ }
+
+ TypeParser::Info typeInfo = TypeParser::parse(typei.toString());
+ if (typeInfo.is_busted) {
+ *ok = false;
+ return 0;
+ }
+
+ // 2. Handle pointers specified as arrays with unspecified size
+ bool arrayOfUnspecifiedSize = false;
+ if (typeInfo.arrays.size() > 0) {
+ arrayOfUnspecifiedSize = true;
+ for (int i = 0; i < typeInfo.arrays.size(); ++i)
+ arrayOfUnspecifiedSize = arrayOfUnspecifiedSize && typeInfo.arrays.at(i).isEmpty();
+
+ if (!arrayOfUnspecifiedSize) {
+ TypeInfo newInfo;
+ //newInfo.setArguments(typei.arguments());
+ newInfo.setIndirections(typei.indirections());
+ newInfo.setConstant(typei.isConstant());
+ newInfo.setFunctionPointer(typei.isFunctionPointer());
+ newInfo.setQualifiedName(typei.qualifiedName());
+ newInfo.setReference(typei.isReference());
+ newInfo.setVolatile(typei.isVolatile());
+
+ AbstractMetaType* elementType = translateType(newInfo, ok);
+ if (!(*ok))
+ return 0;
+
+ for (int i = typeInfo.arrays.size() - 1; i >= 0; --i) {
+ QString s = typeInfo.arrays.at(i);
+ bool _ok;
+ int elems = findOutValueFromString(s, _ok);
+
+ AbstractMetaType* arrayType = createMetaType();
+ arrayType->setArrayElementCount(elems);
+ arrayType->setArrayElementType(elementType);
+ arrayType->setTypeEntry(new ArrayTypeEntry(elementType->typeEntry() , elementType->typeEntry()->version()));
+ decideUsagePattern(arrayType);
+
+ elementType = arrayType;
+ }
+
+ return elementType;
+ } else {
+ typeInfo.indirections += typeInfo.arrays.size();
+ }
+ }
+
+ QStringList qualifierList = typeInfo.qualified_name;
+ if (qualifierList.isEmpty()) {
+ ReportHandler::warning(QString("horribly broken type '%1'").arg(_typei.toString()));
+ *ok = false;
+ return 0;
+ }
+
+ QString qualifiedName = qualifierList.join("::");
+ QString name = qualifierList.takeLast();
+
+ // 3. Special case 'void' type
+ if (name == "void" && !typeInfo.indirections)
+ return 0;
+
+ // 4. Special case QFlags (include instantiation in name)
+ if (qualifiedName == "QFlags")
+ qualifiedName = typeInfo.toString();
+
+ const TypeEntry *type = 0;
+ // 5. Try to find the type
+
+ // 5.1 - Try first using the current scope
+ if (m_currentClass) {
+ type = findTypeEntryUsingContext(m_currentClass, qualifiedName);
+
+ // 5.1.1 - Try using the class parents' scopes
+ if (!type && !m_currentClass->baseClassNames().isEmpty()) {
+ foreach (const AbstractMetaClass* cls, getBaseClasses(m_currentClass)) {
+ type = findTypeEntryUsingContext(cls, qualifiedName);
+ if (type)
+ break;
+ }
+ }
+ }
+
+ // 5.2 - Try without scope
+ if (!type)
+ type = TypeDatabase::instance()->findType(qualifiedName);
+
+ // 6. No? Try looking it up as a flags type
+ if (!type)
+ type = TypeDatabase::instance()->findFlagsType(qualifiedName);
+
+ // 7. No? Try looking it up as a container type
+ if (!type)
+ type = TypeDatabase::instance()->findContainerType(name);
+
+ // 8. No? Check if the current class is a template and this type is one
+ // of the parameters.
+ if (!type && m_currentClass) {
+ QList<TypeEntry *> template_args = m_currentClass->templateArguments();
+ foreach (TypeEntry *te, template_args) {
+ if (te->name() == qualifiedName)
+ type = te;
+ }
+ }
+
+ // 9. Try finding the type by prefixing it with the current
+ // context and all baseclasses of the current context
+ if (!type && !TypeDatabase::instance()->isClassRejected(qualifiedName) && m_currentClass && resolveScope) {
+ QStringList contexts;
+ contexts.append(m_currentClass->qualifiedCppName());
+ contexts.append(currentScope()->qualifiedName().join("::"));
+
+
+ TypeInfo info = typei;
+ bool subclassesDone = false;
+ while (!contexts.isEmpty() && !type) {
+ type = TypeDatabase::instance()->findType(contexts.at(0) + "::" + qualifiedName);
+ contexts.pop_front();
+
+ // 10. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so
+ // enum types from there may be addressed without any scope resolution in properties.
+ if (!contexts.size() && !subclassesDone) {
+ contexts << "Qt";
+ subclassesDone = true;
+ }
+ }
+
+ }
+
+ if (!type) {
+ *ok = false;
+ return 0;
+ }
+
+ // Used to for diagnostics later...
+ m_usedTypes << type;
+
+ // These are only implicit and should not appear in code...
+ Q_ASSERT(!type->isInterface());
+
+ AbstractMetaType* metaType = createMetaType();
+ metaType->setTypeEntry(type);
+ metaType->setIndirections(typeInfo.indirections);
+ metaType->setReference(typeInfo.is_reference);
+ metaType->setConstant(typeInfo.is_constant);
+ metaType->setOriginalTypeDescription(_typei.toString());
+
+ foreach (const TypeParser::Info &ta, typeInfo.template_instantiations) {
+ TypeInfo info;
+ info.setConstant(ta.is_constant);
+ info.setReference(ta.is_reference);
+ info.setIndirections(ta.indirections);
+
+ info.setFunctionPointer(false);
+ info.setQualifiedName(ta.instantiationName().split("::"));
+
+ AbstractMetaType* targType = translateType(info, ok);
+ if (!(*ok)) {
+ delete metaType;
+ return 0;
+ }
+
+ metaType->addInstantiation(targType, true);
+ }
+
+ // The usage pattern *must* be decided *after* the possible template
+ // instantiations have been determined, or else the absence of
+ // such instantiations will break the caching scheme of
+ // AbstractMetaType::cppSignature().
+ decideUsagePattern(metaType);
+
+ return metaType;
+}
+
+
+int AbstractMetaBuilder::findOutValueFromString(const QString& stringValue, bool& ok)
+{
+ int value = stringValue.toInt(&ok);
+ if (ok)
+ return value;
+
+ if (stringValue == "true" || stringValue == "false") {
+ ok = true;
+ return (stringValue == "true");
+ }
+
+ // This is a very lame way to handle expression evaluation,
+ // but it is not critical and will do for the time being.
+ static QRegExp variableNameRegExp("^[a-zA-Z_][a-zA-Z0-9_]*$");
+ if (!variableNameRegExp.exactMatch(stringValue)) {
+ ok = true;
+ return 0;
+ }
+
+ AbstractMetaEnumValue* enumValue = m_metaClasses.findEnumValue(stringValue);
+ if (enumValue) {
+ ok = true;
+ return enumValue->value();
+ }
+
+ foreach (AbstractMetaEnum* metaEnum, m_globalEnums) {
+ foreach (AbstractMetaEnumValue* ev, metaEnum->values()) {
+ if (ev->name() == stringValue) {
+ ok = true;
+ return ev->value();
+ }
+ }
+ }
+
+ ok = false;
+ return 0;
+}
+
+void AbstractMetaBuilder::decideUsagePattern(AbstractMetaType *metaType)
+{
+ metaType->decideUsagePattern();
+}
+
+QString AbstractMetaBuilder::fixDefaultValue(ArgumentModelItem item, AbstractMetaType* type,
+ AbstractMetaFunction* fnc, AbstractMetaClass* implementingClass,
+ int argumentIndex)
+{
+ QString functionName = fnc->name();
+ QString className = implementingClass ? implementingClass->qualifiedCppName() : QString();
+
+ QString expr = item->defaultValueExpression();
+ if (type) {
+ if (type->isPrimitive()) {
+ if (type->name() == "boolean") {
+ if (expr != "false" && expr != "true") {
+ bool ok = false;
+ int number = expr.toInt(&ok);
+ if (ok && number)
+ expr = "true";
+ else
+ expr = "false";
+ }
+ } else {
+ // This can be an enum or flag so I need to delay the
+ // translation untill all namespaces are completly
+ // processed. This is done in figureOutEnumValues()
+ }
+ } else if (type->isFlags() || type->isEnum()) {
+ bool isNumber;
+ expr.toInt(&isNumber);
+ if (!isNumber && expr.indexOf("::") < 0) {
+ // Add the enum/flag scope to default value, making it usable
+ // from other contexts beside its owner class hierarchy
+ QRegExp typeRegEx("[^<]*[<]([^:]*::).*");
+ typeRegEx.indexIn(type->minimalSignature());
+ expr = typeRegEx.cap(1) + expr;
+ }
+ } else if (type->isContainer() && expr.contains('<')) {
+ QRegExp typeRegEx("[^<]*<(.*)>");
+ typeRegEx.indexIn(type->minimalSignature());
+ QRegExp defaultRegEx("([^<]*<).*(>[^>]*)");
+ defaultRegEx.indexIn(expr);
+ expr = defaultRegEx.cap(1) + typeRegEx.cap(1) + defaultRegEx.cap(2);
+ } else {
+ // Here the default value is supposed to be a constructor,
+ // a class field, or a constructor receiving a class field
+ QRegExp defaultRegEx("([^\\(]*\\(|)([^\\)]*)(\\)|)");
+ defaultRegEx.indexIn(expr);
+
+ QString defaultValueCtorName = defaultRegEx.cap(1);
+ if (defaultValueCtorName.endsWith('('))
+ defaultValueCtorName.chop(1);
+
+ // Fix the scope for constructor using the already
+ // resolved argument type as a reference.
+ // The following regular expression extracts any
+ // use of namespaces/scopes from the type string.
+ QRegExp typeRegEx("^(?:const[\\s]+|)([\\w:]*::|)([A-Za-z_]\\w*)\\s*[&\\*]?$");
+ typeRegEx.indexIn(type->minimalSignature());
+
+ QString typeNamespace = typeRegEx.cap(1);
+ QString typeCtorName = typeRegEx.cap(2);
+ if (!typeNamespace.isEmpty() && defaultValueCtorName == typeCtorName)
+ expr.prepend(typeNamespace);
+
+ // Fix scope if the parameter is a field of the current class
+ if (implementingClass) {
+ foreach (const AbstractMetaField* field, implementingClass->fields()) {
+ if (defaultRegEx.cap(2) == field->name()) {
+ expr = defaultRegEx.cap(1) + implementingClass->name() + "::" + defaultRegEx.cap(2) + defaultRegEx.cap(3);
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ QString warn = QString("undefined type for default value '%3' of argument in function '%1', class '%2'")
+ .arg(functionName).arg(className).arg(item->defaultValueExpression());
+ ReportHandler::warning(warn);
+ expr = QString();
+ }
+
+ return expr;
+}
+
+bool AbstractMetaBuilder::isQObject(const QString& qualifiedName)
+{
+ if (qualifiedName == "QObject")
+ return true;
+
+ ClassModelItem classItem = m_dom->findClass(qualifiedName);
+
+ if (!classItem) {
+ QStringList names = qualifiedName.split(QLatin1String("::"));
+ NamespaceModelItem ns = model_dynamic_cast<NamespaceModelItem>(m_dom);
+ for (int i = 0; i < names.size() - 1 && ns; ++i)
+ ns = ns->namespaceMap().value(names.at(i));
+ if (ns && names.size() >= 2)
+ classItem = ns->findClass(names.at(names.size() - 1));
+ }
+
+ bool isqobject = classItem && classItem->extendsClass("QObject");
+
+ if (classItem && !isqobject) {
+ QStringList baseClasses = classItem->baseClasses();
+ for (int i = 0; i < baseClasses.count(); ++i) {
+
+ isqobject = isQObject(baseClasses.at(i));
+ if (isqobject)
+ break;
+ }
+ }
+
+ return isqobject;
+}
+
+
+bool AbstractMetaBuilder::isEnum(const QStringList& qualified_name)
+{
+ CodeModelItem item = m_dom->model()->findItem(qualified_name, m_dom->toItem());
+ return item && item->kind() == _EnumModelItem::__node_kind;
+}
+
+AbstractMetaClassList AbstractMetaBuilder::getBaseClasses(const AbstractMetaClass* metaClass) const
+{
+ AbstractMetaClassList baseClasses;
+ foreach (const QString& parent, metaClass->baseClassNames()) {
+ AbstractMetaClass* cls = m_metaClasses.findClass(parent);
+ if (cls)
+ baseClasses << cls;
+ }
+ return baseClasses;
+}
+
+bool AbstractMetaBuilder::ancestorHasPrivateCopyConstructor(const AbstractMetaClass* metaClass) const
+{
+ if (metaClass->hasPrivateCopyConstructor())
+ return true;
+ foreach (const AbstractMetaClass* cls, getBaseClasses(metaClass)) {
+ if (ancestorHasPrivateCopyConstructor(cls))
+ return true;
+ }
+ return false;
+}
+
+AbstractMetaType* AbstractMetaBuilder::inheritTemplateType(const QList<AbstractMetaType*>& templateTypes,
+ const AbstractMetaType* metaType, bool* ok)
+{
+ if (ok)
+ *ok = true;
+ if (!metaType || (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations()))
+ return metaType ? metaType->copy() : 0;
+
+ AbstractMetaType *returned = metaType->copy();
+ returned->setOriginalTemplateType(metaType->copy());
+
+ if (returned->typeEntry()->isTemplateArgument()) {
+ const TemplateArgumentEntry* tae = static_cast<const TemplateArgumentEntry*>(returned->typeEntry());
+
+ // If the template is intantiated with void we special case this as rejecting the functions that use this
+ // parameter from the instantiation.
+ if (templateTypes.size() <= tae->ordinal() || templateTypes.at(tae->ordinal())->typeEntry()->name() == "void") {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+
+ AbstractMetaType* t = returned->copy();
+ t->setTypeEntry(templateTypes.at(tae->ordinal())->typeEntry());
+ t->setIndirections(templateTypes.at(tae->ordinal())->indirections() + t->indirections() ? 1 : 0);
+ decideUsagePattern(t);
+
+ delete returned;
+ returned = inheritTemplateType(templateTypes, t, ok);
+ if (ok && !(*ok))
+ return 0;
+ }
+
+ if (returned->hasInstantiations()) {
+ AbstractMetaTypeList instantiations = returned->instantiations();
+ for (int i = 0; i < instantiations.count(); ++i) {
+ AbstractMetaType *type = instantiations[i];
+ instantiations[i] = inheritTemplateType(templateTypes, type, ok);
+ if (ok && !(*ok))
+ return 0;
+ }
+ returned->setInstantiations(instantiations, true);
+ }
+
+ return returned;
+}
+
+bool AbstractMetaBuilder::inheritTemplate(AbstractMetaClass* subclass,
+ const AbstractMetaClass* templateClass,
+ const TypeParser::Info& info)
+{
+ QList<TypeParser::Info> targs = info.template_instantiations;
+ QList<AbstractMetaType*> templateTypes;
+
+ if (subclass->isTypeAlias()) {
+ subclass->setHasCloneOperator(templateClass->hasCloneOperator());
+ subclass->setHasEqualsOperator(templateClass->hasEqualsOperator());
+ subclass->setHasHashFunction(templateClass->hasHashFunction());
+ subclass->setHasNonPrivateConstructor(templateClass->hasNonPrivateConstructor());
+ subclass->setHasPrivateDestructor(templateClass->hasPrivateDestructor());
+ subclass->setHasProtectedDestructor(templateClass->hasProtectedDestructor());
+ subclass->setHasVirtualDestructor(templateClass->hasVirtualDestructor());
+ }
+
+ foreach (const TypeParser::Info &i, targs) {
+ QString typeName = i.qualified_name.join("::");
+ QStringList possibleNames;
+ possibleNames << subclass->qualifiedCppName() + "::" + typeName;
+ possibleNames << templateClass->qualifiedCppName() + "::" + typeName;
+ if (subclass->enclosingClass())
+ possibleNames << subclass->enclosingClass()->qualifiedCppName() + "::" + typeName;
+ possibleNames << typeName;
+
+ TypeDatabase* typeDb = TypeDatabase::instance();
+ TypeEntry* t = 0;
+ QString templateParamName;
+ foreach (QString possibleName, possibleNames) {
+ t = typeDb->findType(possibleName);
+ if (t) {
+ QString templateParamName = possibleName;
+ break;
+ }
+ }
+
+ if (t) {
+ AbstractMetaType* temporaryType = createMetaType();
+ temporaryType->setTypeEntry(t);
+ temporaryType->setConstant(i.is_constant);
+ temporaryType->setReference(i.is_reference);
+ temporaryType->setIndirections(i.indirections);
+ temporaryType->decideUsagePattern();
+ templateTypes << temporaryType;
+ } else {
+ ReportHandler::warning("Ignoring template parameter " + templateParamName + " from " + info.instantiationName() + ", because I don't know what it is.");
+ }
+ }
+
+ AbstractMetaFunctionList funcs = subclass->functions();
+ foreach (const AbstractMetaFunction* function, templateClass->functions()) {
+ if (function->isModifiedRemoved(TypeSystem::All))
+ continue;
+
+ AbstractMetaFunction *f = function->copy();
+ f->setArguments(AbstractMetaArgumentList());
+
+ bool ok = true;
+ AbstractMetaType *ftype = function->type();
+ f->replaceType(inheritTemplateType(templateTypes, ftype, &ok));
+ if (!ok) {
+ delete f;
+ continue;
+ }
+
+ foreach (AbstractMetaArgument* argument, function->arguments()) {
+ AbstractMetaType* atype = argument->type();
+
+ AbstractMetaArgument *arg = argument->copy();
+ arg->replaceType(inheritTemplateType(templateTypes, atype, &ok));
+ if (!ok)
+ break;
+ f->addArgument(arg);
+ }
+
+ if (!ok) {
+ delete f;
+ continue;
+ }
+
+ // There is no base class in the target language to inherit from here, so
+ // the template instantiation is the class that implements the function.
+ f->setImplementingClass(subclass);
+
+ // We also set it as the declaring class, since the superclass is
+ // supposed to disappear. This allows us to make certain function modifications
+ // on the inherited functions.
+ f->setDeclaringClass(subclass);
+
+
+ if (f->isConstructor() && subclass->isTypeAlias()) {
+ f->setName(subclass->name());
+ f->setOriginalName(subclass->name());
+ } else if (f->isConstructor()) {
+ delete f;
+ continue;
+ }
+
+ // if the instantiation has a function named the same as an existing
+ // function we have shadowing so we need to skip it.
+ bool found = false;
+ for (int i = 0; i < funcs.size(); ++i) {
+ if (funcs.at(i)->name() == f->name()) {
+ found = true;
+ continue;
+ }
+ }
+ if (found) {
+ delete f;
+ continue;
+ }
+
+ ComplexTypeEntry* te = subclass->typeEntry();
+ FunctionModificationList mods = function->modifications(templateClass);
+ for (int i = 0; i < mods.size(); ++i) {
+ FunctionModification mod = mods.at(i);
+ mod.signature = f->minimalSignature();
+
+ // If we ever need it... Below is the code to do
+ // substitution of the template instantation type inside
+ // injected code..
+#if 0
+ if (mod.modifiers & Modification::CodeInjection) {
+ for (int j = 0; j < template_types.size(); ++j) {
+ CodeSnip &snip = mod.snips.last();
+ QString code = snip.code();
+ code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j),
+ template_types.at(j)->typeEntry()->qualifiedCppName());
+ snip.codeList.clear();
+ snip.addCode(code);
+ }
+ }
+#endif
+ te->addFunctionModification(mod);
+ }
+
+ subclass->addFunction(f);
+ }
+
+ subclass->setTemplateBaseClass(templateClass);
+ subclass->setTemplateBaseClassInstantiations(templateTypes);
+ subclass->setInterfaces(templateClass->interfaces());
+ subclass->setBaseClass(templateClass->baseClass());
+
+ return true;
+}
+
+void AbstractMetaBuilder::parseQ_Property(AbstractMetaClass* metaClass, const QStringList& declarations)
+{
+ for (int i = 0; i < declarations.size(); ++i) {
+ QString p = declarations.at(i);
+
+ QStringList l = p.split(QLatin1String(" "));
+
+
+ QStringList qualifiedScopeName = currentScope()->qualifiedName();
+ bool ok = false;
+ AbstractMetaType* type = 0;
+ QString scope;
+ for (int j = qualifiedScopeName.size(); j >= 0; --j) {
+ scope = j > 0 ? QStringList(qualifiedScopeName.mid(0, j)).join("::") + "::" : QString();
+ TypeInfo info;
+ info.setQualifiedName((scope + l.at(0)).split("::"));
+
+ type = translateType(info, &ok);
+ if (type && ok)
+ break;
+ }
+
+ if (!type || !ok) {
+ ReportHandler::warning(QString("Unable to decide type of property: '%1' in class '%2'")
+ .arg(l.at(0)).arg(metaClass->name()));
+ continue;
+ }
+
+ QString typeName = scope + l.at(0);
+
+ QPropertySpec* spec = new QPropertySpec(type->typeEntry());
+ spec->setName(l.at(1));
+ spec->setIndex(i);
+
+ for (int pos = 2; pos + 1 < l.size(); pos += 2) {
+ if (l.at(pos) == QLatin1String("READ"))
+ spec->setRead(l.at(pos + 1));
+ else if (l.at(pos) == QLatin1String("WRITE"))
+ spec->setWrite(l.at(pos + 1));
+ else if (l.at(pos) == QLatin1String("DESIGNABLE"))
+ spec->setDesignable(l.at(pos + 1));
+ else if (l.at(pos) == QLatin1String("RESET"))
+ spec->setReset(l.at(pos + 1));
+ }
+
+ metaClass->addPropertySpec(spec);
+ delete type;
+ }
+}
+
+static AbstractMetaFunction* findCopyCtor(AbstractMetaClass* cls)
+{
+ AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::Invisible);
+ functions << cls->queryFunctions(AbstractMetaClass::Visible);
+
+ foreach (AbstractMetaFunction* f, functions) {
+ if (f->isConstructor() || f->name() == "operator=") {
+ AbstractMetaArgumentList arguments = f->arguments();
+ if (arguments.size() == 1) {
+ if (cls->typeEntry()->qualifiedCppName() == arguments.at(0)->type()->typeEntry()->qualifiedCppName())
+ return f;
+ }
+ }
+ }
+ return 0;
+}
+
+void AbstractMetaBuilder::setupClonable(AbstractMetaClass* cls)
+{
+ bool result = true;
+
+ // find copy ctor for the current class
+ AbstractMetaFunction* copyCtor = findCopyCtor(cls);
+ if (copyCtor) { // if exists a copy ctor in this class
+ result = copyCtor->isPublic();
+ } else { // else... lets find one in the parent class
+ QQueue<AbstractMetaClass*> baseClasses;
+ if (cls->baseClass())
+ baseClasses.enqueue(cls->baseClass());
+ baseClasses << cls->interfaces();
+
+ while (!baseClasses.isEmpty()) {
+ AbstractMetaClass* currentClass = baseClasses.dequeue();
+ baseClasses << currentClass->interfaces();
+ if (currentClass->baseClass())
+ baseClasses.enqueue(currentClass->baseClass());
+
+ copyCtor = findCopyCtor(currentClass);
+ if (copyCtor) {
+ result = copyCtor->isPublic();
+ break;
+ }
+ }
+ }
+ cls->setHasCloneOperator(result);
+}
+
+void AbstractMetaBuilder::setupExternalConversion(AbstractMetaClass* cls) {
+ AbstractMetaFunctionList convOps = cls->operatorOverloads(AbstractMetaClass::ConversionOp);
+ foreach (AbstractMetaFunction* func, convOps) {
+ if (func->isModifiedRemoved())
+ continue;
+ AbstractMetaClass* metaClass = m_metaClasses.findClass(func->type()->typeEntry());
+ if (!metaClass)
+ continue;
+ metaClass->addExternalConversionOperator(func);
+ }
+ foreach (AbstractMetaClass* innerClass, cls->innerClasses())
+ setupExternalConversion(innerClass);
+}
+
+static void writeRejectLogFile(const QString &name,
+ const QMap<QString, AbstractMetaBuilder::RejectReason> &rejects)
+{
+ QFile f(name);
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ ReportHandler::warning(QString("failed to write log file: '%1'")
+ .arg(f.fileName()));
+ return;
+ }
+
+ QTextStream s(&f);
+
+
+ for (int reason = 0; reason < AbstractMetaBuilder::NoReason; ++reason) {
+ s << QString(72, '*') << endl;
+ switch (reason) {
+ case AbstractMetaBuilder::NotInTypeSystem:
+ s << "Not in type system";
+ break;
+ case AbstractMetaBuilder::GenerationDisabled:
+ s << "Generation disabled by type system";
+ break;
+ case AbstractMetaBuilder::RedefinedToNotClass:
+ s << "Type redefined to not be a class";
+ break;
+
+ case AbstractMetaBuilder::UnmatchedReturnType:
+ s << "Unmatched return type";
+ break;
+
+ case AbstractMetaBuilder::UnmatchedArgumentType:
+ s << "Unmatched argument type";
+ break;
+
+ case AbstractMetaBuilder::ApiIncompatible:
+ s << "Incompatible API";
+ break;
+
+ default:
+ s << "unknown reason";
+ break;
+ }
+
+ s << endl;
+
+ for (QMap<QString, AbstractMetaBuilder::RejectReason>::const_iterator it = rejects.constBegin();
+ it != rejects.constEnd(); ++it) {
+ if (it.value() != reason)
+ continue;
+ s << " - " << it.key() << endl;
+ }
+
+ s << QString(72, '*') << endl << endl;
+ }
+
+}
+
+
+void AbstractMetaBuilder::dumpLog()
+{
+ writeRejectLogFile(m_logDirectory + "mjb_rejected_classes.log", m_rejectedClasses);
+ writeRejectLogFile(m_logDirectory + "mjb_rejected_enums.log", m_rejectedEnums);
+ writeRejectLogFile(m_logDirectory + "mjb_rejected_functions.log", m_rejectedFunctions);
+ writeRejectLogFile(m_logDirectory + "mjb_rejected_fields.log", m_rejectedFields);
+}
+
+AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted(const AbstractMetaClass* cppClass) const
+{
+ QLinkedList<int> unmappedResult;
+ QHash<QString, int> map;
+ QHash<int, AbstractMetaClass*> reverseMap;
+
+ const AbstractMetaClassList& classList = cppClass ? cppClass->innerClasses() : m_metaClasses;
+
+ int i = 0;
+ foreach (AbstractMetaClass* clazz, classList) {
+ if (map.contains(clazz->qualifiedCppName()))
+ continue;
+ map[clazz->qualifiedCppName()] = i;
+ reverseMap[i] = clazz;
+ i++;
+ }
+
+ Graph graph(map.count());
+
+ // TODO choose a better name to these regexs
+ QRegExp regex1("\\(.*\\)");
+ QRegExp regex2("::.*");
+ foreach (AbstractMetaClass* clazz, classList) {
+ if (clazz->isInterface() || !clazz->typeEntry()->generateCode())
+ continue;
+
+ if (clazz->enclosingClass() && map.contains(clazz->enclosingClass()->qualifiedCppName()))
+ graph.addEdge(map[clazz->enclosingClass()->qualifiedCppName()], map[clazz->qualifiedCppName()]);
+
+ AbstractMetaClassList bases = getBaseClasses(clazz);
+ foreach(AbstractMetaClass* baseClass, bases) {
+ // Fix polymorphic expression
+ if (clazz->baseClass() == baseClass)
+ clazz->setBaseClass(baseClass);
+
+ if (map.contains(baseClass->qualifiedCppName()))
+ graph.addEdge(map[baseClass->qualifiedCppName()], map[clazz->qualifiedCppName()]);
+ }
+
+ foreach (AbstractMetaFunction* func, clazz->functions()) {
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ // check methods with default args
+ QString defaultExpression = arg->originalDefaultValueExpression();
+ if (!defaultExpression.isEmpty()) {
+ if ((defaultExpression == "0") && (arg->type()->isValue()))
+ defaultExpression = arg->type()->name();
+
+ defaultExpression.replace(regex1, "");
+ defaultExpression.replace(regex2, "");
+ }
+ if (!defaultExpression.isEmpty()) {
+ QString exprClassName = clazz->qualifiedCppName() + "::" + defaultExpression;
+ if (!map.contains(exprClassName)) {
+ bool found = false;
+ foreach(AbstractMetaClass* baseClass, bases) {
+ exprClassName = baseClass->qualifiedCppName() + "::" + defaultExpression;
+ if (map.contains(exprClassName)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ if (map.contains(defaultExpression))
+ exprClassName = defaultExpression;
+ else
+ exprClassName.clear();
+ }
+ }
+ if (!exprClassName.isEmpty() && exprClassName != clazz->qualifiedCppName())
+ graph.addEdge(map[exprClassName], map[clazz->qualifiedCppName()]);
+ }
+ }
+ }
+ }
+
+ AbstractMetaClassList result;
+ unmappedResult = graph.topologicalSort();
+ if (unmappedResult.isEmpty() && graph.nodeCount()) {
+ QTemporaryFile tempFile;
+ tempFile.setAutoRemove(false);
+ tempFile.open();
+ QHash<int, QString> hash;
+ QHash<QString, int>::iterator it = map.begin();
+ for (; it != map.end(); ++it)
+ hash[it.value()] = it.key();
+ graph.dumpDot(hash, tempFile.fileName());
+ ReportHandler::warning("Cyclic dependency found! Graph can be found at "+tempFile.fileName());
+ } else {
+ foreach (int i, unmappedResult) {
+ Q_ASSERT(reverseMap.contains(i));
+ if (!reverseMap[i]->isInterface())
+ result << reverseMap[i];
+ }
+ }
+
+ return result;
+}
+
+AbstractMetaArgumentList AbstractMetaBuilder::reverseList(const AbstractMetaArgumentList& list)
+{
+ AbstractMetaArgumentList ret;
+
+ int index = list.size();
+ foreach (AbstractMetaArgument* arg, list) {
+ arg->setArgumentIndex(index);
+ ret.prepend(arg);
+ index--;
+ }
+
+ return ret;
+}
+
+void AbstractMetaBuilder::setGlobalHeader(const QString& globalHeader)
+{
+ m_globalHeader = QFileInfo(globalHeader);
+}
+
+void AbstractMetaBuilder::setInclude(TypeEntry* te, const QString& fileName) const
+{
+ QFileInfo info(fileName);
+ if (m_globalHeader.fileName() != info.fileName())
+ te->setInclude(Include(Include::IncludePath, info.fileName()));
+}