diff generator/typesystem.cpp @ 1:e78566595089

initial import
author mandel
date Mon, 11 May 2009 16:01:50 +0000
parents
children 0a29ce1ae854
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/generator/typesystem.cpp	Mon May 11 16:01:50 2009 +0000
@@ -0,0 +1,2047 @@
+/****************************************************************************
+**
+** Copyright (C) 1992-2008 Nokia. All rights reserved.
+**
+** This file is part of Qt Jambi.
+**
+** * Commercial Usage
+* Licensees holding valid Qt Commercial licenses may use this file in
+* accordance with the Qt Commercial License Agreement provided with the
+* Software or, alternatively, in accordance with the terms contained in
+* a written agreement between you and Nokia.
+*
+*
+* GNU General Public License Usage
+* Alternatively, this file may be used under the terms of the GNU
+* General Public License versions 2.0 or 3.0 as published by the Free
+* Software Foundation and appearing in the file LICENSE.GPL included in
+* the packaging of this file.  Please review the following information
+* to ensure GNU General Public Licensing requirements will be met:
+* http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+* http://www.gnu.org/copyleft/gpl.html.  In addition, as a special
+* exception, Nokia gives you certain additional rights. These rights
+* are described in the Nokia Qt GPL Exception version 1.2, included in
+* the file GPL_EXCEPTION.txt in this package.
+* 
+* Qt for Windows(R) Licensees
+* As a special exception, Nokia, as the sole copyright holder for Qt
+* Designer, grants users of the Qt/Eclipse Integration plug-in the
+* right for the Qt/Eclipse Integration to link to functionality
+* provided by Qt Designer and its related libraries.
+*
+*
+* If you are unsure which license is appropriate for your use, please
+* contact the sales department at qt-sales@nokia.com.
+
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "typesystem.h"
+#include "generator.h"
+
+#include "customtypes.h"
+
+#include <reporthandler.h>
+
+#include <QtXml>
+
+QString strings_Object = QLatin1String("Object");
+QString strings_String = QLatin1String("string");
+QString strings_Thread = QLatin1String("Thread");
+QString strings_char = QLatin1String("char");
+QString strings_java_lang = QLatin1String("java.lang");
+QString strings_jchar = QLatin1String("jchar");
+QString strings_jobject = QLatin1String("jobject");
+
+static void addRemoveFunctionToTemplates(TypeDatabase *db);
+
+class StackElement
+{
+    public:
+    enum ElementType {
+        None = 0x0,
+
+        // Type tags (0x1, ... , 0xff)
+        ObjectTypeEntry      = 0x1,
+        ValueTypeEntry       = 0x2,
+        InterfaceTypeEntry   = 0x3,
+        NamespaceTypeEntry   = 0x4,
+        ComplexTypeEntryMask = 0xf,
+
+        // Non-complex type tags (0x10, 0x20, ... , 0xf0)
+        PrimitiveTypeEntry   = 0x10,
+        EnumTypeEntry        = 0x20,
+        TypeEntryMask        = 0xff,
+
+        // Simple tags (0x100, 0x200, ... , 0xf00)
+        ExtraIncludes               = 0x100,
+        Include                     = 0x200,
+        ModifyFunction              = 0x300,
+        ModifyField                 = 0x400,
+        Root                        = 0x500,
+        CustomMetaConstructor       = 0x600,
+        CustomMetaDestructor        = 0x700,
+        ArgumentMap                 = 0x800,
+        SuppressedWarning           = 0x900,
+        Rejection                   = 0xa00,
+        LoadTypesystem              = 0xb00,
+        RejectEnumValue             = 0xc00,
+        Template                    = 0xd00,
+        TemplateInstanceEnum        = 0xe00,
+        Replace                     = 0xf00,
+        SimpleMask                  = 0xf00,
+        // qtd stuff
+        AddClass                    = 0x1100,
+
+        // Code snip tags (0x1000, 0x2000, ... , 0xf000)
+        InjectCode =           0x1000,
+        InjectCodeInFunction = 0x2000,
+        CodeSnipMask =         0xf000,
+
+        // Function modifier tags (0x010000, 0x020000, ... , 0xf00000)
+        Access                   = 0x010000,
+        Removal                  = 0x020000,
+        Rename                   = 0x040000,
+        ModifyArgument           = 0x080000,
+        FunctionModifiers        = 0xff0000,
+        StoreResult              = 0x110000,
+
+        // Argument modifier tags (0x01000000 ... 0xf0000000)
+        ConversionRule           = 0x01000000,
+        ReplaceType              = 0x02000000,
+        ReplaceDefaultExpression = 0x04000000,
+        RemoveArgument           = 0x08000000,
+        DefineOwnership          = 0x10000000,
+        RemoveDefaultExpression  = 0x20000000,
+        NoNullPointers           = 0x40000000,
+        ReferenceCount           = 0x80000000,
+        ArgumentModifiers        = 0xff000000
+
+    };
+
+    StackElement(StackElement *p) : entry(0), type(None), parent(p){ }
+
+    TypeEntry *entry;
+    ElementType type;
+    StackElement *parent;
+
+    union {
+        TemplateInstance *templateInstance;
+        TemplateEntry *templateEntry;
+        CustomFunction *customFunction;
+    } value;
+};
+
+class Handler : public QXmlDefaultHandler
+{
+public:
+    Handler(TypeDatabase *database, bool generate)
+        : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
+    {
+        m_current_enum = 0;
+        current = 0;
+
+        tagNames["rejection"] = StackElement::Rejection;
+        tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry;
+        tagNames["object-type"] = StackElement::ObjectTypeEntry;
+        tagNames["value-type"] = StackElement::ValueTypeEntry;
+        tagNames["interface-type"] = StackElement::InterfaceTypeEntry;
+        tagNames["namespace-type"] = StackElement::NamespaceTypeEntry;
+        tagNames["enum-type"] = StackElement::EnumTypeEntry;
+        tagNames["extra-includes"] = StackElement::ExtraIncludes;
+        tagNames["include"] = StackElement::Include;
+        tagNames["inject-code"] = StackElement::InjectCode;
+        tagNames["modify-function"] = StackElement::ModifyFunction;
+        tagNames["modify-field"] = StackElement::ModifyField;
+        tagNames["access"] = StackElement::Access;
+        tagNames["remove"] = StackElement::Removal;
+        tagNames["rename"] = StackElement::Rename;
+        tagNames["typesystem"] = StackElement::Root;
+        tagNames["custom-constructor"] = StackElement::CustomMetaConstructor;
+        tagNames["custom-destructor"] = StackElement::CustomMetaDestructor;
+        tagNames["argument-map"] = StackElement::ArgumentMap;
+        tagNames["suppress-warning"] = StackElement::SuppressedWarning;
+        tagNames["load-typesystem"] = StackElement::LoadTypesystem;
+        tagNames["define-ownership"] = StackElement::DefineOwnership;
+        tagNames["replace-default-expression"] = StackElement::ReplaceDefaultExpression;
+        tagNames["reject-enum-value"] = StackElement::RejectEnumValue;
+        tagNames["replace-type"] = StackElement::ReplaceType;
+        tagNames["conversion-rule"] = StackElement::ConversionRule;
+        tagNames["modify-argument"] = StackElement::ModifyArgument;
+        tagNames["remove-argument"] = StackElement::RemoveArgument;
+        tagNames["remove-default-expression"] = StackElement::RemoveDefaultExpression;
+        tagNames["template"] = StackElement::Template;
+        tagNames["insert-template"] = StackElement::TemplateInstanceEnum;
+        tagNames["replace"] = StackElement::Replace;
+        tagNames["no-null-pointer"] = StackElement::NoNullPointers;
+        tagNames["reference-count"] = StackElement::ReferenceCount;
+        // qtd
+        tagNames["add-class"] = StackElement::AddClass;
+        tagNames["store-result"] = StackElement::StoreResult;
+    }
+
+    bool startElement(const QString &namespaceURI, const QString &localName,
+                      const QString &qName, const QXmlAttributes &atts);
+    bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
+
+    QString errorString() const { return m_error; }
+    bool error(const QXmlParseException &exception);
+    bool fatalError(const QXmlParseException &exception);
+    bool warning(const QXmlParseException &exception);
+
+    bool characters(const QString &ch);
+
+private:
+    void fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
+                              QHash<QString, QString> *acceptedAttributes);
+
+    bool importFileElement(const QXmlAttributes &atts);
+    bool convertBoolean(const QString &, const QString &, bool);
+
+    TypeDatabase *m_database;
+    StackElement* current;
+    QString m_defaultPackage;
+    QString m_defaultSuperclass;
+    QString m_error;
+    TypeEntry::CodeGeneration m_generate;
+
+    EnumTypeEntry *m_current_enum;
+
+    CodeSnipList m_code_snips;
+    FunctionModificationList m_function_mods;
+    FieldModificationList m_field_mods;
+
+    QHash<QString, StackElement::ElementType> tagNames;
+};
+
+bool Handler::error(const QXmlParseException &e)
+{
+    qWarning("Error: line=%d, column=%d, message=%s\n",
+             e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
+    return false;
+}
+
+bool Handler::fatalError(const QXmlParseException &e)
+{
+    qWarning("Fatal error: line=%d, column=%d, message=%s\n",
+             e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
+
+    return false;
+}
+
+bool Handler::warning(const QXmlParseException &e)
+{
+    qWarning("Warning: line=%d, column=%d, message=%s\n",
+             e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
+
+    return false;
+}
+
+void Handler::fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
+                                   QHash<QString, QString> *acceptedAttributes)
+{
+    Q_ASSERT(acceptedAttributes != 0);
+
+    for (int i=0; i<atts.length(); ++i) {
+        QString key = atts.localName(i).toLower();
+        QString val = atts.value(i);
+
+        if (!acceptedAttributes->contains(key)) {
+            ReportHandler::warning(QString("Unknown attribute for '%1': '%2'").arg(name).arg(key));
+        } else {
+            (*acceptedAttributes)[key] = val;
+        }
+    }
+}
+
+bool Handler::endElement(const QString &, const QString &localName, const QString &)
+{
+    QString tagName = localName.toLower();
+    if(tagName == "import-file")
+        return true;
+
+    if (!current)
+        return true;
+
+    switch (current->type) {
+    case StackElement::ObjectTypeEntry:
+    case StackElement::ValueTypeEntry:
+    case StackElement::InterfaceTypeEntry:
+    case StackElement::NamespaceTypeEntry:
+        {
+            ComplexTypeEntry *centry = static_cast<ComplexTypeEntry *>(current->entry);
+            centry->setFunctionModifications(m_function_mods);
+            centry->setFieldModifications(m_field_mods);
+            centry->setCodeSnips(m_code_snips);
+
+            if (centry->designatedInterface()) {
+                centry->designatedInterface()->setCodeSnips(m_code_snips);
+                centry->designatedInterface()->setFunctionModifications(m_function_mods);
+            }
+            m_code_snips = CodeSnipList();
+            m_function_mods = FunctionModificationList();
+            m_field_mods = FieldModificationList();
+        }
+        break;
+    case StackElement::CustomMetaConstructor:
+        {
+            current->entry->setCustomConstructor(*current->value.customFunction);
+            delete current->value.customFunction;
+        }
+        break;
+    case StackElement::CustomMetaDestructor:
+        {
+            current->entry->setCustomDestructor(*current->value.customFunction);
+            delete current->value.customFunction;
+        }
+        break;
+    case StackElement::EnumTypeEntry:
+        m_current_enum = 0;
+        break;
+    case StackElement::Template:
+        m_database->addTemplate(current->value.templateEntry);
+        break;
+    case StackElement::TemplateInstanceEnum:
+        if(current->parent->type == StackElement::InjectCode){
+            m_code_snips.last().addTemplateInstance(current->value.templateInstance);
+        }else if(current->parent->type == StackElement::Template){
+            current->parent->value.templateEntry->addTemplateInstance(current->value.templateInstance);
+        }else if(current->parent->type == StackElement::CustomMetaConstructor || current->parent->type == StackElement::CustomMetaConstructor){
+            current->parent->value.customFunction->addTemplateInstance(current->value.templateInstance);
+        }else if(current->parent->type == StackElement::ConversionRule){
+            m_function_mods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(current->value.templateInstance);
+        }else if(current->parent->type == StackElement::InjectCodeInFunction){
+            m_function_mods.last().snips.last().addTemplateInstance(current->value.templateInstance);
+        }
+        break;
+    default:
+        break;
+    }
+
+    StackElement *child = current;
+    current=current->parent;
+    delete(child);
+
+    return true;
+}
+
+bool Handler::characters(const QString &ch)
+{
+    if(current->type == StackElement::Template){
+        current->value.templateEntry->addCode(ch);
+        return true;
+    }
+
+    if (current->type == StackElement::CustomMetaConstructor || current->type == StackElement::CustomMetaDestructor){
+        current->value.customFunction->addCode(ch);
+        return true;
+    }
+
+    if (current->type == StackElement::ConversionRule){
+        m_function_mods.last().argument_mods.last().conversion_rules.last().addCode(ch);
+        return true;
+    }
+
+    if  (current->parent){
+        if ((current->type & StackElement::CodeSnipMask) != 0) {
+            switch (current->parent->type) {
+                case StackElement::Root:
+                    ((TypeSystemTypeEntry *) current->parent->entry)->snips.last().addCode(ch);
+                    break;
+                case StackElement::ModifyFunction:
+                    m_function_mods.last().snips.last().addCode(ch);
+                    break;
+                case StackElement::NamespaceTypeEntry:
+                case StackElement::ObjectTypeEntry:
+                case StackElement::ValueTypeEntry:
+                case StackElement::InterfaceTypeEntry:
+                    m_code_snips.last().addCode(ch);
+                    break;
+                default:
+                    Q_ASSERT(false);
+            };
+            return true;
+        }
+    }
+
+    return true;
+}
+
+bool Handler::importFileElement(const QXmlAttributes &atts)
+{
+    QString fileName = atts.value("name");
+    if(fileName.isEmpty()){
+        m_error = "Required attribute 'name' missing for include-file tag.";
+        return false;
+    }
+
+    QFile file(fileName);
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        file.setFileName(":/trolltech/generator/" + fileName);
+        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+            m_error = QString("Could not open file: '%1'").arg(fileName);
+            return false;
+        }
+    }
+
+    QString quoteFrom = atts.value("quote-after-line");
+    bool foundFromOk = quoteFrom.isEmpty();
+    bool from = quoteFrom.isEmpty();
+
+    QString quoteTo = atts.value("quote-before-line");
+    bool foundToOk = quoteTo.isEmpty();
+    bool to = true;
+
+    QTextStream in(&file);
+    while (!in.atEnd()) {
+        QString line = in.readLine();
+        if(from && to && line.contains(quoteTo)) {
+            to = false;
+            foundToOk = true;
+            break;
+        }
+        if(from && to)
+            characters(line + "\n");
+        if(!from && line.contains(quoteFrom)) {
+            from = true;
+            foundFromOk = true;
+        }
+    }
+    if(!foundFromOk || !foundToOk){
+        QString fromError = QString("Could not find quote-after-line='%1' in file '%2'.").arg(quoteFrom).arg(fileName);
+        QString toError = QString("Could not find quote-before-line='%1' in file '%2'.").arg(quoteTo).arg(fileName);
+
+        if(!foundToOk)
+            m_error = toError;
+        if(!foundFromOk)
+            m_error = fromError;
+        if(!foundFromOk && !foundToOk)
+            m_error = fromError + " " + toError;
+        return false;
+    }
+
+    return true;
+}
+
+bool Handler::convertBoolean(const QString &_value, const QString &attributeName, bool defaultValue)
+{
+    QString value = _value.toLower();
+    if (value == "true" || value == "yes") {
+        return true;
+    } else if (value == "false" || value == "no") {
+        return false;
+    } else {
+        QString warn = QString("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
+            .arg(value).arg(attributeName).arg(defaultValue ? "yes" : "no");
+
+        ReportHandler::warning(warn);
+        return defaultValue;
+    }
+}
+
+bool Handler::startElement(const QString &, const QString &n,
+                           const QString &, const QXmlAttributes &atts)
+{
+    QString tagName = n.toLower();
+    if(tagName == "import-file"){
+        return importFileElement(atts);
+    }
+
+    StackElement *element = new StackElement(current);
+
+    if (!tagNames.contains(tagName)) {
+        m_error = QString("Unknown tag name: '%1'").arg(tagName);
+        return false;
+    }
+
+    element->type = tagNames[tagName];
+    if (element->type & StackElement::TypeEntryMask) {
+        if (current->type != StackElement::Root) {
+            m_error = "Nested types not supported";
+            return false;
+        }
+
+        QHash<QString, QString> attributes;
+        attributes["name"] = QString();
+
+        switch (element->type) {
+        case StackElement::PrimitiveTypeEntry:
+            attributes["java-name"] = QString();
+            attributes["jni-name"] = QString();
+            attributes["preferred-conversion"] = "yes";
+            attributes["preferred-java-type"] = "yes";
+            break;
+        case StackElement::EnumTypeEntry:
+            attributes["flags"] = "no";
+            attributes["upper-bound"] = QString();
+            attributes["lower-bound"] = QString();
+            attributes["force-integer"] = "no";
+            attributes["extensible"] = "no";
+
+            break;
+
+        case StackElement::ObjectTypeEntry:
+        case StackElement::ValueTypeEntry:
+            attributes["force-abstract"] = QString("no");
+            attributes["deprecated"] = QString("no");
+            attributes["wrap"] = QString();
+            // fall throooough
+        case StackElement::InterfaceTypeEntry:
+            attributes["default-superclass"] = m_defaultSuperclass;
+            attributes["polymorphic-id-expression"] = QString();
+            attributes["delete-in-main-thread"] = QString("no");
+            // fall through
+        case StackElement::NamespaceTypeEntry:
+            attributes["java-name"] = QString();
+            attributes["package"] = m_defaultPackage;
+            attributes["expense-cost"] = "1";
+            attributes["expense-limit"] = "none";
+            attributes["polymorphic-base"] = QString("no");
+            attributes["generate"] = QString("yes");
+            attributes["target-type"] = QString();
+            attributes["generic-class"] = QString("no");
+            break;
+        default:
+            ; // nada
+        };
+
+        fetchAttributeValues(tagName, atts, &attributes);
+
+        QString name = attributes["name"];
+
+        // We need to be able to have duplicate primitive type entries, or it's not possible to
+        // cover all primitive java types (which we need to do in order to support fake
+        // meta objects)
+        if (element->type != StackElement::PrimitiveTypeEntry) {
+            TypeEntry *tmp = m_database->findType(name);
+            if (tmp != 0) {
+                ReportHandler::warning(QString("Duplicate type entry: '%1'").arg(name));
+            }
+        }
+
+        if (name.isEmpty()) {
+            m_error = "no 'name' attribute specified";
+            return false;
+        }
+        switch (element->type) {
+        case StackElement::PrimitiveTypeEntry:
+            {
+                QString java_name = attributes["java-name"];
+                QString jni_name = attributes["jni-name"];
+                QString preferred_conversion = attributes["preferred-conversion"].toLower();
+                QString preferred_java_type = attributes["preferred-java-type"].toLower();
+
+                if (java_name.isEmpty())
+                    java_name = name;
+                if (jni_name.isEmpty())
+                    jni_name = name;
+
+                PrimitiveTypeEntry *type = new PrimitiveTypeEntry(name);
+                type->setCodeGeneration(m_generate);
+                type->setTargetLangName(java_name);
+                type->setJniName(jni_name);
+
+                type->setPreferredConversion(convertBoolean(preferred_conversion, "preferred-conversion", true));
+                type->setPreferredTargetLangType(convertBoolean(preferred_java_type, "preferred-java-type", true));
+
+                element->entry = type;
+            }
+            break;
+        case StackElement::EnumTypeEntry: {
+            QStringList names = name.split(QLatin1String("::"));
+
+            if (names.size() == 1) {
+                m_current_enum = new EnumTypeEntry(QString(), name);
+            }
+            else
+                m_current_enum =
+                    new EnumTypeEntry(QStringList(names.mid(0, names.size() - 1)).join("::"),
+                                      names.last());
+            element->entry = m_current_enum;
+            m_current_enum->setCodeGeneration(m_generate);
+            m_current_enum->setTargetLangPackage(m_defaultPackage);
+            m_current_enum->setUpperBound(attributes["upper-bound"]);
+            m_current_enum->setLowerBound(attributes["lower-bound"]);
+            m_current_enum->setForceInteger(convertBoolean(attributes["force-integer"], "force-integer", false));
+            m_current_enum->setExtensible(convertBoolean(attributes["extensible"], "extensible", false));
+
+            // put in the flags parallel...
+            if (!attributes["flags"].isEmpty() && attributes["flags"].toLower() != "no") {
+                FlagsTypeEntry *ftype = new FlagsTypeEntry("QFlags<" + name + ">");
+                ftype->setOriginator(m_current_enum);
+                ftype->setOriginalName(attributes["flags"]);
+                ftype->setCodeGeneration(m_generate);
+                QString n = ftype->originalName();
+
+                QStringList lst = n.split("::");
+                if (QStringList(lst.mid(0, lst.size() - 1)).join("::") != m_current_enum->javaQualifier()) {
+                    ReportHandler::warning(QString("enum %1 and flags %2 differ in qualifiers")
+                                           .arg(m_current_enum->javaQualifier())
+                                           .arg(lst.at(0)));
+                }
+
+                ftype->setFlagsName(lst.last());
+                m_current_enum->setFlags(ftype);
+
+                m_database->addFlagsType(ftype);
+                m_database->addType(ftype);
+            }
+            }
+            break;
+
+        case StackElement::InterfaceTypeEntry:
+            {
+                ObjectTypeEntry *otype = new ObjectTypeEntry(name);
+                QString javaName = attributes["java-name"];
+                if (javaName.isEmpty())
+                    javaName = name;
+                InterfaceTypeEntry *itype =
+                    new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(javaName));
+
+                if (!convertBoolean(attributes["generate"], "generate", true))
+                    itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
+                else
+                    itype->setCodeGeneration(m_generate);
+                otype->setDesignatedInterface(itype);
+                itype->setOrigin(otype);
+                element->entry = otype;
+            }
+            // fall through
+        case StackElement::NamespaceTypeEntry:
+            if (element->entry == 0) {
+                element->entry = new NamespaceTypeEntry(name);
+            }
+            // fall through
+        case StackElement::ObjectTypeEntry:
+            if (element->entry == 0) {
+                element->entry = new ObjectTypeEntry(name);
+            }
+            // fall through
+        case StackElement::ValueTypeEntry:
+            {
+                if (element->entry == 0) {
+                    if(name == "QVariant")
+                        element->entry = new VariantTypeEntry(name);
+                    else
+                        element->entry = new ValueTypeEntry(name);
+                }
+
+                ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
+                ctype->setTargetLangPackage(attributes["package"]);
+                ctype->setDefaultSuperclass(attributes["default-superclass"]);
+                ctype->setGenericClass(convertBoolean(attributes["generic-class"], "generic-class", false));
+
+                // qtd
+                QString wrap = attributes["wrap"];
+                ctype->setStructInD(wrap == "struct" ? true : false);
+                //
+
+                if (!convertBoolean(attributes["generate"], "generate", true))
+                    element->entry->setCodeGeneration(TypeEntry::GenerateForSubclass);
+                else
+                    element->entry->setCodeGeneration(m_generate);
+
+                QString javaName = attributes["java-name"];
+                if (!javaName.isEmpty())
+                    ctype->setTargetLangName(javaName);
+
+                // The expense policy
+                QString limit = attributes["expense-limit"];
+                if (!limit.isEmpty() && limit != "none") {
+                    ExpensePolicy ep;
+                    ep.limit = limit.toInt();
+                    ep.cost = attributes["expense-cost"];
+                    ctype->setExpensePolicy(ep);
+                }
+
+                ctype->setIsPolymorphicBase(convertBoolean(attributes["polymorphic-base"], "polymorphic-base", false));
+                ctype->setPolymorphicIdValue(attributes["polymorphic-id-expression"]);
+
+                if (element->type == StackElement::ObjectTypeEntry || element->type == StackElement::ValueTypeEntry) {
+                    if (convertBoolean(attributes["force-abstract"], "force-abstract", false))
+                        ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract);
+                    if (convertBoolean(attributes["deprecated"], "deprecated", false))
+                        ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
+                }
+
+                if (element->type == StackElement::InterfaceTypeEntry ||
+                    element->type == StackElement::ValueTypeEntry ||
+                    element->type == StackElement::ObjectTypeEntry) {
+                    if (convertBoolean(attributes["delete-in-main-thread"], "delete-in-main-thread", false))
+                        ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DeleteInMainThread);
+                }
+
+                QString targetType = attributes["target-type"];
+                if (!targetType.isEmpty() && element->entry->isComplex())
+                    static_cast<ComplexTypeEntry *>(element->entry)->setTargetType(targetType);
+
+                // ctype->setInclude(Include(Include::IncludePath, ctype->name()));
+                ctype = ctype->designatedInterface();
+                if (ctype != 0)
+                    ctype->setTargetLangPackage(attributes["package"]);
+            }
+            break;
+        default:
+            Q_ASSERT(false);
+        };
+
+        if (element->entry)
+            m_database->addType(element->entry);
+        else
+            ReportHandler::warning(QString("Type: %1 was rejected by typesystem").arg(name));
+
+    } else if (element->type != StackElement::None) {
+        bool topLevel = element->type == StackElement::Root
+      || element->type == StackElement::SuppressedWarning
+      || element->type == StackElement::Rejection
+      || element->type == StackElement::LoadTypesystem
+      || element->type == StackElement::InjectCode
+      || element->type == StackElement::Template;
+
+        if (!topLevel && current->type == StackElement::Root) {
+            m_error = QString("Tag requires parent: '%1'").arg(tagName);
+            return false;
+        }
+
+        StackElement topElement = current==0 ? StackElement(0) : *current;
+        element->entry = topElement.entry;
+
+        QHash<QString, QString> attributes;
+        switch (element->type) {
+        case StackElement::Root:
+            attributes["package"] = QString();
+            attributes["default-superclass"] = QString();
+            break;
+        case StackElement::LoadTypesystem:
+            attributes["name"] = QString();
+            attributes["generate"] = "yes";
+            break;
+        case StackElement::NoNullPointers:
+            attributes["default-value"] = QString();
+            break;
+        case StackElement::SuppressedWarning:
+            attributes["text"] = QString();
+            break;
+        case StackElement::ReplaceDefaultExpression:
+            attributes["with"] = QString();
+            break;
+        case StackElement::DefineOwnership:
+            attributes["class"] = "java";
+            attributes["owner"] = "";
+            break;
+        case StackElement::ModifyFunction:
+            attributes["signature"] = QString();
+            attributes["access"] = QString();
+            attributes["remove"] = QString();
+            attributes["rename"] = QString();
+            attributes["deprecated"] = QString("no");
+            attributes["associated-to"] = QString();
+            attributes["virtual-slot"] = QString("no");
+            break;
+        case StackElement::ModifyArgument:
+            attributes["index"] = QString();
+            attributes["replace-value"] = QString();
+            attributes["invalidate-after-use"] = QString("no");
+            break;
+        case StackElement::ModifyField:
+            attributes["name"] = QString();
+            attributes["write"] = "true";
+            attributes["read"] = "true";
+            break;
+        case StackElement::Access:
+            attributes["modifier"] = QString();
+            break;
+        case StackElement::Include:
+            attributes["file-name"] = QString();
+            attributes["location"] = QString();
+            break;
+        case StackElement::CustomMetaConstructor:
+            attributes["name"] = topElement.entry->name().toLower() + "_create";
+            attributes["param-name"] = "copy";
+            break;
+        case StackElement::CustomMetaDestructor:
+            attributes["name"] = topElement.entry->name().toLower() + "_delete";
+            attributes["param-name"] = "copy";
+            break;
+        case StackElement::ReplaceType:
+            attributes["modified-type"] = QString();
+            break;
+        case StackElement::InjectCode:
+            attributes["class"] = "java";
+            attributes["position"] = "beginning";
+            break;
+        case StackElement::ConversionRule:
+            attributes["class"] = "";
+            break;
+        case StackElement::RejectEnumValue:
+            attributes["name"] = "";
+            break;
+        case StackElement::ArgumentMap:
+            attributes["index"] = "1";
+            attributes["meta-name"] = QString();
+            break;
+        case StackElement::Rename:
+            attributes["to"] = QString();
+            break;
+        case StackElement::Rejection:
+            attributes["class"] = "*";
+            attributes["function-name"] = "*";
+            attributes["field-name"] = "*";
+            attributes["enum-name"] = "*";
+            break;
+        case StackElement::Removal:
+            attributes["class"] = "all";
+            break;
+        case StackElement::Template:
+            attributes["name"] = QString();
+            break;
+        case StackElement::TemplateInstanceEnum:
+            attributes["name"] = QString();
+            break;
+        case StackElement::Replace:
+            attributes["from"] = QString();
+            attributes["to"] = QString();
+            break;
+        case StackElement::ReferenceCount:
+            attributes["action"] = QString();
+            attributes["variable-name"] = QString();
+            attributes["thread-safe"] = QString("no");
+            attributes["declare-variable"] = QString();
+            attributes["access"] = QString("private");
+            attributes["conditional"] = QString("");
+            break;
+            // qtd
+        case StackElement::AddClass:
+            attributes["name"] = QString();
+            break;
+        default:
+            ; // nada
+        };
+
+        if (attributes.count() > 0)
+            fetchAttributeValues(tagName, atts, &attributes);
+
+        switch (element->type) {
+        case StackElement::Root:
+            m_defaultPackage = attributes["package"];
+            m_defaultSuperclass = attributes["default-superclass"];
+            element->type = StackElement::Root;
+            element->entry = new TypeSystemTypeEntry(m_defaultPackage);
+            TypeDatabase::instance()->addType(element->entry);
+            break;
+        case StackElement::LoadTypesystem:
+            {
+                QString name = attributes["name"];
+                if (name.isEmpty()) {
+                    m_error = "No typesystem name specified";
+                    return false;
+                }
+
+                if (!m_database->parseFile(name, convertBoolean(attributes["generate"], "generate", true))) {
+                    m_error = QString("Failed to parse: '%1'").arg(name);
+                    return false;
+                }
+            }
+            break;
+        case StackElement::RejectEnumValue: {
+            if (!m_current_enum) {
+                m_error = "<reject-enum-value> node must be used inside a <enum-type> node";
+                return false;
+            }
+            QString name = attributes["name"];
+
+            bool added = false;
+            if (!name.isEmpty()) {
+                added = true;
+                m_current_enum->addEnumValueRejection(name);
+            }
+
+            } break;
+        case StackElement::ReplaceType:
+            {
+                if (topElement.type != StackElement::ModifyArgument) {
+                    m_error = "Type replacement can only be specified for argument modifications";
+                    return false;
+                }
+
+                if (attributes["modified-type"].isEmpty()) {
+                    m_error = "Type replacement requires 'modified-type' attribute";
+                    return false;
+                }
+
+                m_function_mods.last().argument_mods.last().modified_type = attributes["modified-type"];
+            }
+            break;
+        case StackElement::ConversionRule:
+            {
+                if (topElement.type != StackElement::ModifyArgument) {
+                    m_error = "Conversion rules can only be specified for argument modification";
+                    return false;
+                }
+
+                static QHash<QString, TypeSystem::Language> languageNames;
+                if (languageNames.isEmpty()) {
+                    languageNames["native"] = TypeSystem::NativeCode;
+                    languageNames["shell"] = TypeSystem::ShellCode;
+                }
+
+                CodeSnip snip;
+                QString languageAttribute = attributes["class"].toLower();
+                TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
+                if (lang == TypeSystem::NoLanguage) {
+                    m_error = QString("unsupported class attribute: '%1'").arg(languageAttribute);
+                    return false;
+                }
+
+                snip.language = lang;
+                m_function_mods.last().argument_mods.last().conversion_rules.append(snip);
+            }
+
+            break;
+        case StackElement::StoreResult:
+            {
+                if (topElement.type != StackElement::ModifyFunction) {
+                    m_error = QString::fromLatin1("result storage requires function"
+                                                  " modification as parent, was %1")
+                              .arg(topElement.type, 0, 16);
+                    return false;
+                }
+
+                m_function_mods.last().store_result = true;
+            }
+            break;
+        case StackElement::ModifyArgument:
+            {
+                if (topElement.type != StackElement::ModifyFunction) {
+                    m_error = QString::fromLatin1("argument modification requires function"
+                                                  " modification as parent, was %1")
+                              .arg(topElement.type, 0, 16);
+                    return false;
+                }
+
+                QString index = attributes["index"];
+                if (index == "return")
+                    index = "0";
+                else if (index == "this")
+                    index = "-1";
+
+                bool ok = false;
+                int idx = index.toInt(&ok);
+                if (!ok) {
+                    m_error = QString("Cannot convert '%1' to integer").arg(index);
+                    return false;
+                }
+
+                QString replace_value = attributes["replace-value"];
+
+                if (!replace_value.isEmpty() && idx != 0) {
+                    m_error = QString("replace-value is only supported for return values (index=0).");
+                    return false;
+                }
+
+                ArgumentModification argumentModification = ArgumentModification(idx);
+                argumentModification.replace_value = replace_value;
+                argumentModification.reset_after_use = convertBoolean(attributes["invalidate-after-use"], "invalidate-after-use", false);
+                m_function_mods.last().argument_mods.append(argumentModification);
+            }
+            break;
+        case StackElement::NoNullPointers:
+            {
+                if (topElement.type != StackElement::ModifyArgument) {
+                    m_error = "no-null-pointer requires argument modification as parent";
+                    return false;
+                }
+
+                m_function_mods.last().argument_mods.last().no_null_pointers = true;
+                if (m_function_mods.last().argument_mods.last().index == 0) {
+                    m_function_mods.last().argument_mods.last().null_pointer_default_value = attributes["default-value"];
+                } else if (!attributes["default-value"].isEmpty()) {
+                    ReportHandler::warning("default values for null pointer guards are only effective for return values");
+                }
+            }
+            break;
+        case StackElement::DefineOwnership:
+            {
+                if (topElement.type != StackElement::ModifyArgument) {
+                    m_error = "define-ownership requires argument modification as parent";
+                    return false;
+                }
+
+                static QHash<QString, TypeSystem::Language> languageNames;
+                if (languageNames.isEmpty()) {
+                    languageNames["java"] = TypeSystem::TargetLangCode;
+                    languageNames["shell"] = TypeSystem::ShellCode;
+                }
+
+                QString classAttribute = attributes["class"].toLower();
+                TypeSystem::Language lang = languageNames.value(classAttribute, TypeSystem::NoLanguage);
+                if (lang == TypeSystem::NoLanguage) {
+                    m_error = QString("unsupported class attribute: '%1'").arg(classAttribute);
+                    return false;
+                }
+
+                static QHash<QString, TypeSystem::Ownership> ownershipNames;
+                if (ownershipNames.isEmpty()) {
+                    ownershipNames["java"] = TypeSystem::TargetLangOwnership;
+                    ownershipNames["c++"] = TypeSystem::CppOwnership;
+                    ownershipNames["default"] = TypeSystem::DefaultOwnership;
+                }
+
+                QString ownershipAttribute = attributes["owner"].toLower();
+                TypeSystem::Ownership owner = ownershipNames.value(ownershipAttribute, TypeSystem::InvalidOwnership);
+                if (owner == TypeSystem::InvalidOwnership) {
+                    m_error = QString("unsupported owner attribute: '%1'").arg(ownershipAttribute);
+                    return false;
+                }
+
+                m_function_mods.last().argument_mods.last().ownerships[lang] = owner;
+            }
+            break;
+        case StackElement::SuppressedWarning:
+            if (attributes["text"].isEmpty())
+                ReportHandler::warning("Suppressed warning with no text specified");
+            else
+                m_database->addSuppressedWarning(attributes["text"]);
+            break;
+        case StackElement::ArgumentMap:
+            {
+                if (!(topElement.type & StackElement::CodeSnipMask)) {
+                    m_error = "Argument maps requires code injection as parent";
+                    return false;
+                }
+
+                bool ok;
+                int pos = attributes["index"].toInt(&ok);
+                if (!ok) {
+                    m_error = QString("Can't convert position '%1' to integer")
+                              .arg(attributes["position"]);
+                    return false;
+                }
+
+                if (pos <= 0) {
+                    m_error = QString("Argument position %1 must be a positive number").arg(pos);
+                    return false;
+                }
+
+                QString meta_name = attributes["meta-name"];
+                if (meta_name.isEmpty()) {
+                    ReportHandler::warning("Empty meta name in argument map");
+                }
+
+                if (topElement.type == StackElement::InjectCodeInFunction) {
+                    m_function_mods.last().snips.last().argumentMap[pos] = meta_name;
+                } else {
+                    ReportHandler::warning("Argument maps are only useful for injection of code "
+                                           "into functions.");
+                }
+            }
+            break;
+        case StackElement::Removal:
+            {
+                if (topElement.type != StackElement::ModifyFunction) {
+                    m_error = "Function modification parent required";
+                    return false;
+                }
+
+                static QHash<QString, TypeSystem::Language> languageNames;
+                if (languageNames.isEmpty()) {
+                    languageNames["java"] = TypeSystem::TargetLangAndNativeCode;
+                    languageNames["all"] = TypeSystem::All;
+                }
+
+                QString languageAttribute = attributes["class"].toLower();
+                TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
+                if (lang == TypeSystem::NoLanguage) {
+                    m_error = QString("unsupported class attribute: '%1'").arg(languageAttribute);
+                    return false;
+                }
+
+                m_function_mods.last().removal = lang;
+            }
+            break;
+        case StackElement::Rename:
+        case StackElement::Access:
+            {
+                if (topElement.type != StackElement::ModifyField
+                    && topElement.type != StackElement::ModifyFunction) {
+                    m_error = "Function or field modification parent required";
+                    return false;
+                }
+
+                Modification *mod = 0;
+                if (topElement.type == StackElement::ModifyFunction)
+                    mod = &m_function_mods.last();
+                else
+                    mod = &m_field_mods.last();
+
+                QString modifier;
+                if (element->type == StackElement::Rename) {
+                    modifier = "rename";
+                    QString renamed_to = attributes["to"];
+                    if (renamed_to.isEmpty()) {
+                        m_error = "Rename modifier requires 'to' attribute";
+                        return false;
+                    }
+
+                    if (topElement.type == StackElement::ModifyFunction)
+                        mod->setRenamedTo(renamed_to);
+                    else
+                        mod->setRenamedTo(renamed_to);
+                } else {
+                    modifier = attributes["modifier"].toLower();
+                }
+
+                if (modifier.isEmpty()) {
+                    m_error = "No access modification specified";
+                    return false;
+                }
+
+                static QHash<QString, FunctionModification::Modifiers> modifierNames;
+                if (modifierNames.isEmpty()) {
+                    modifierNames["private"] = Modification::Private;
+                    modifierNames["public"] = Modification::Public;
+                    modifierNames["protected"] = Modification::Protected;
+                    modifierNames["friendly"] = Modification::Friendly;
+                    modifierNames["rename"] = Modification::Rename;
+                    modifierNames["final"] = Modification::Final;
+                    modifierNames["non-final"] = Modification::NonFinal;
+                }
+
+                if (!modifierNames.contains(modifier)) {
+                    m_error = QString("Unknown access modifier: '%1'").arg(modifier);
+                    return false;
+                }
+
+                mod->modifiers |= modifierNames[modifier];
+            }
+            break;
+        case StackElement::RemoveArgument:
+            if (topElement.type != StackElement::ModifyArgument) {
+                m_error = "Removing argument requires argument modification as parent";
+                return false;
+            }
+
+            m_function_mods.last().argument_mods.last().removed = true;
+
+            break;
+
+        case StackElement::ModifyField:
+            {
+                QString name = attributes["name"];
+                if (name.isEmpty())
+                    break;
+                FieldModification fm;
+                fm.name = name;
+                fm.modifiers = 0;
+
+                QString read = attributes["read"];
+                QString write = attributes["write"];
+
+                if (read == "true") fm.modifiers |= FieldModification::Readable;
+                if (write == "true") fm.modifiers |= FieldModification::Writable;
+
+                m_field_mods << fm;
+            }
+            break;
+        case StackElement::AddClass: // qtd - fully :)
+            {
+                if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
+                    m_error = QString::fromLatin1("Add class to module requires complex type as parent"
+                                                  ", was=%1").arg(topElement.type, 0, 16);
+                    return false;
+                }
+                QString class_name = attributes["name"];
+                ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(topElement.entry);
+                if(!class_name.isEmpty())
+                    ctype->includedClasses << class_name;
+            }
+            break;
+        case StackElement::ModifyFunction:
+            {
+                if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
+                    m_error = QString::fromLatin1("Modify function requires complex type as parent"
+                                                  ", was=%1").arg(topElement.type, 0, 16);
+                    return false;
+                }
+                QString signature = attributes["signature"];
+
+                signature = QMetaObject::normalizedSignature(signature.toLocal8Bit().constData());
+                if (signature.isEmpty()) {
+                    m_error = "No signature for modified function";
+                    return false;
+                }
+
+                FunctionModification mod;
+                mod.signature = signature;
+
+                QString access = attributes["access"].toLower();
+                if (!access.isEmpty()) {
+                    if (access == QLatin1String("private"))
+                        mod.modifiers |= Modification::Private;
+                    else if (access == QLatin1String("protected"))
+                        mod.modifiers |= Modification::Protected;
+                    else if (access == QLatin1String("public"))
+                        mod.modifiers |= Modification::Public;
+                    else if (access == QLatin1String("final"))
+                        mod.modifiers |= Modification::Final;
+                    else if (access == QLatin1String("non-final"))
+                        mod.modifiers |= Modification::NonFinal;
+                    else {
+                        m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
+                        return false;
+                    }
+                }
+
+                if (convertBoolean(attributes["deprecated"], "deprecated", false)) {
+                    mod.modifiers |= Modification::Deprecated;
+                }
+
+                QString remove = attributes["remove"].toLower();
+                if (!remove.isEmpty()) {
+                    if (remove == QLatin1String("all"))
+                        mod.removal = TypeSystem::All;
+                    else if (remove == QLatin1String("java"))
+                        mod.removal = TypeSystem::TargetLangAndNativeCode;
+                    else {
+                        m_error = QString::fromLatin1("Bad removal type '%1'").arg(remove);
+                        return false;
+                    }
+                }
+
+                QString rename = attributes["rename"];
+                if (!rename.isEmpty()) {
+                    mod.renamedToName = rename;
+                    mod.modifiers |= Modification::Rename;
+                }
+
+                QString association = attributes["associated-to"];
+                if (!association.isEmpty())
+                    mod.association = association;
+
+                mod.modifiers |= (convertBoolean(attributes["virtual-slot"], "virtual-slot", false) ? Modification::VirtualSlot : 0);
+
+                m_function_mods << mod;
+            }
+            break;
+        case StackElement::ReplaceDefaultExpression:
+            if (!(topElement.type & StackElement::ModifyArgument)) {
+                m_error = "Replace default expression only allowed as child of argument modification";
+                return false;
+            }
+
+            if (attributes["with"].isEmpty()) {
+               m_error = "Default expression replaced with empty string. Use remove-default-expression instead.";
+               return false;
+            }
+
+            m_function_mods.last().argument_mods.last().replaced_default_expression = attributes["with"];
+            break;
+        case StackElement::RemoveDefaultExpression:
+            m_function_mods.last().argument_mods.last().removed_default_expression = true;
+            break;
+        case StackElement::CustomMetaConstructor:
+        case StackElement::CustomMetaDestructor:
+            {
+                CustomFunction *func = new CustomFunction(attributes["name"]);
+                func->param_name = attributes["param-name"];
+                element->value.customFunction = func;
+            }
+            break;
+        case StackElement::ReferenceCount:
+            {
+                if (topElement.type != StackElement::ModifyArgument) {
+                    m_error = "reference-count must be child of modify-argument";
+                    return false;
+                }
+
+                ReferenceCount rc;
+                rc.threadSafe = convertBoolean(attributes["thread-safe"], "thread-safe", false);
+
+                static QHash<QString, ReferenceCount::Action> actions;
+                if (actions.isEmpty()) {
+                    actions["add"] = ReferenceCount::Add;
+                    actions["add-all"] = ReferenceCount::AddAll;
+                    actions["remove"] = ReferenceCount::Remove;
+                    actions["set"] = ReferenceCount::Set;
+                    actions["ignore"] = ReferenceCount::Ignore;
+                }
+                rc.action = actions.value(attributes["action"].toLower(), ReferenceCount::Invalid);
+
+                rc.variableName = attributes["variable-name"];
+                if (rc.action != ReferenceCount::Ignore && rc.variableName.isEmpty()) {
+                    m_error = "variable-name attribute must be specified";
+                    return false;
+                }
+
+                rc.declareVariable = attributes["declare-variable"];
+                rc.conditional = attributes["conditional"];
+
+                static QHash<QString, int> accessRights;
+                if (accessRights.isEmpty()) {
+                    accessRights["private"] = ReferenceCount::Private;
+                    accessRights["public"] = ReferenceCount::Public;
+                    accessRights["protected"] = ReferenceCount::Protected;
+                    accessRights["friendly"] = ReferenceCount::Friendly;
+                }
+                rc.access = accessRights.value(attributes["access"].toLower(), 0);
+                if (rc.access == 0) {
+                    m_error = "unrecognized access value: " + attributes["access"];
+                    return false;
+                }
+
+                if (rc.action == ReferenceCount::Invalid) {
+                    m_error = "unrecognized value for action attribute. supported actions:";
+                    foreach (QString action, actions.keys())
+                        m_error += " " + action;
+                }
+
+                m_function_mods.last().argument_mods.last().referenceCounts.append(rc);
+            }
+            break;
+        case StackElement::InjectCode:
+            {
+                if (((topElement.type & StackElement::ComplexTypeEntryMask) == 0)
+                    && (topElement.type != StackElement::ModifyFunction)
+                    && (topElement.type != StackElement::Root)) {
+                    m_error = "wrong parent type for code injection";
+                    return false;
+                }
+
+                static QHash<QString, TypeSystem::Language> languageNames;
+                if (languageNames.isEmpty()) {
+                    languageNames["java"] = TypeSystem::TargetLangCode;
+                    languageNames["native"] = TypeSystem::NativeCode;
+                    languageNames["shell"] = TypeSystem::ShellCode;
+                    languageNames["shell-declaration"] = TypeSystem::ShellDeclaration;
+                    languageNames["library-initializer"] = TypeSystem::PackageInitializer;
+                    languageNames["destructor-function"] = TypeSystem::DestructorFunction;
+                    languageNames["constructors"] = TypeSystem::Constructors;
+                    languageNames["interface"] = TypeSystem::Interface;
+                }
+
+                QString className = attributes["class"].toLower();
+                if (!languageNames.contains(className)) {
+                    m_error = QString("Invalid class specifier: '%1'").arg(className);
+                    return false;
+                }
+
+
+                static QHash<QString, CodeSnip::Position> positionNames;
+                if (positionNames.isEmpty()) {
+                    positionNames["beginning"] = CodeSnip::Beginning;
+                    positionNames["end"] = CodeSnip::End;
+                }
+
+                QString position = attributes["position"].toLower();
+                if (!positionNames.contains(position)) {
+                    m_error = QString("Invalid position: '%1'").arg(position);
+                    return false;
+                }
+
+                CodeSnip snip;
+                snip.language = languageNames[className];
+                snip.position = positionNames[position];
+
+                if (snip.language == TypeSystem::Interface && topElement.type != StackElement::InterfaceTypeEntry) {
+                    m_error = "Interface code injections must be direct child of an interface type entry";
+                    return false;
+                }
+
+                if (topElement.type == StackElement::ModifyFunction) {
+                    FunctionModification mod = m_function_mods.last();
+                    if (snip.language == TypeSystem::ShellDeclaration) {
+                        m_error = "no function implementation in shell declaration in which to inject code";
+                        return false;
+                    }
+
+                    m_function_mods.last().snips << snip;
+                    element->type = StackElement::InjectCodeInFunction;
+                } else if (topElement.type == StackElement::Root) {
+                    ((TypeSystemTypeEntry *) element->entry)->snips << snip;
+
+                } else if (topElement.type != StackElement::Root) {
+                    m_code_snips << snip;
+                }
+            }
+            break;
+        case StackElement::Include:
+            {
+                QString location = attributes["location"].toLower();
+
+                static QHash<QString, Include::IncludeType> locationNames;
+                if (locationNames.isEmpty()) {
+                    locationNames["global"] = Include::IncludePath;
+                    locationNames["local"] = Include::LocalPath;
+                    locationNames["java"] = Include::TargetLangImport;
+                }
+
+                if (!locationNames.contains(location)) {
+                    m_error = QString("Location not recognized: '%1'").arg(location);
+                    return false;
+                }
+
+                Include::IncludeType loc = locationNames[location];
+                Include inc(loc, attributes["file-name"]);
+
+                ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
+                if (topElement.type & StackElement::ComplexTypeEntryMask) {
+                    ctype->setInclude(inc);
+                } else if (topElement.type == StackElement::ExtraIncludes) {
+                    ctype->addExtraInclude(inc);
+                } else {
+                    m_error = "Only supported parents are complex types and extra-includes";
+                    return false;
+                }
+
+                inc = ctype->include();
+                IncludeList lst = ctype->extraIncludes();
+                ctype = ctype->designatedInterface();
+                if (ctype != 0) {
+                    ctype->setExtraIncludes(lst);
+                    ctype->setInclude(inc);
+                }
+            }
+            break;
+        case StackElement::Rejection:
+            {
+                QString cls = attributes["class"];
+                QString function = attributes["function-name"];
+                QString field = attributes["field-name"];
+                QString enum_ = attributes["enum-name"];
+                if (cls == "*" && function == "*" && field == "*" && enum_ == "*") {
+                    m_error = "bad reject entry, neither 'class', 'function-name' nor "
+                              "'field' specified";
+                    return false;
+                }
+                m_database->addRejection(cls, function, field, enum_);
+            }
+            break;
+        case StackElement::Template:
+            element->value.templateEntry = new TemplateEntry(attributes["name"]);
+            break;
+        case StackElement::TemplateInstanceEnum:
+            if (!(topElement.type & StackElement::CodeSnipMask) &&
+                  (topElement.type != StackElement::Template) &&
+                  (topElement.type != StackElement::CustomMetaConstructor) &&
+                  (topElement.type != StackElement::CustomMetaDestructor) &&
+                  (topElement.type != StackElement::ConversionRule))
+            {
+                m_error = "Can only insert templates into code snippets, templates, custom-constructors, custom-destructors or conversion-rule.";
+                return false;
+            }
+            element->value.templateInstance = new TemplateInstance(attributes["name"]);
+            break;
+        case StackElement::Replace:
+            if (topElement.type != StackElement::TemplateInstanceEnum) {
+                m_error = "Can only insert replace rules into insert-template.";
+                return false;
+            }
+            element->parent->value.templateInstance->addReplaceRule(attributes["from"],attributes["to"]);
+            break;
+        default:
+            break; // nada
+        };
+    }
+
+    current = element;
+    return true;
+}
+
+TypeDatabase *TypeDatabase::instance()
+{
+    static TypeDatabase *db = new TypeDatabase();
+    return db;
+}
+
+TypeDatabase::TypeDatabase() : m_suppressWarnings(true), m_includeEclipseWarnings(false)
+{
+    addType(new StringTypeEntry("QString"));
+
+    StringTypeEntry *e = new StringTypeEntry("QLatin1String");
+    e->setPreferredConversion(false);
+    addType(e);
+
+    e = new StringTypeEntry("QStringRef");
+    e->setPreferredConversion(false);
+    addType(e);
+
+    e = new StringTypeEntry("QXmlStreamStringRef");
+    e->setPreferredConversion(false);
+    addType(e);
+
+    addType(new CharTypeEntry("QChar"));
+
+    CharTypeEntry *c = new CharTypeEntry("QLatin1Char");
+    c->setPreferredConversion(false);
+    addType(c);
+
+    {
+        VariantTypeEntry *qvariant = new VariantTypeEntry("QVariant");
+        qvariant->setCodeGeneration(TypeEntry::GenerateAll);
+        addType(qvariant);
+    }
+
+    {
+        JObjectWrapperTypeEntry *wrapper = new JObjectWrapperTypeEntry("JObjectWrapper");
+        wrapper->setCodeGeneration(TypeEntry::GenerateNothing);
+        addType(wrapper);
+    }
+
+    addType(new ThreadTypeEntry());
+    addType(new VoidTypeEntry());
+
+    // Predefined containers...
+    addType(new ContainerTypeEntry("QList", ContainerTypeEntry::ListContainer));
+    addType(new ContainerTypeEntry("QStringList", ContainerTypeEntry::StringListContainer));
+    addType(new ContainerTypeEntry("QLinkedList", ContainerTypeEntry::LinkedListContainer));
+    addType(new ContainerTypeEntry("QVector", ContainerTypeEntry::VectorContainer));
+    addType(new ContainerTypeEntry("QStack", ContainerTypeEntry::StackContainer));
+    addType(new ContainerTypeEntry("QSet", ContainerTypeEntry::SetContainer));
+    addType(new ContainerTypeEntry("QMap", ContainerTypeEntry::MapContainer));
+    addType(new ContainerTypeEntry("QHash", ContainerTypeEntry::HashContainer));
+    addType(new ContainerTypeEntry("QPair", ContainerTypeEntry::PairContainer));
+    addType(new ContainerTypeEntry("QQueue", ContainerTypeEntry::QueueContainer));
+    addType(new ContainerTypeEntry("QMultiMap", ContainerTypeEntry::MultiMapContainer));
+
+    // Custom types...
+//    addType(new QModelIndexTypeEntry());
+
+    addRemoveFunctionToTemplates(this);
+}
+
+bool TypeDatabase::parseFile(const QString &filename, bool generate)
+{
+    QFile file(filename);
+    Q_ASSERT(file.exists());
+    QXmlInputSource source(&file);
+
+    int count = m_entries.size();
+
+    QXmlSimpleReader reader;
+    Handler handler(this, generate);
+
+    reader.setContentHandler(&handler);
+    reader.setErrorHandler(&handler);
+
+    bool ok = reader.parse(&source, false);
+
+    int newCount = m_entries.size();
+
+    ReportHandler::debugSparse(QString::fromLatin1("Parsed: '%1', %2 new entries")
+                               .arg(filename)
+                               .arg(newCount - count));
+
+    return ok;
+}
+
+QString PrimitiveTypeEntry::javaObjectName() const
+{
+    static QHash<QString, QString> table;
+    if (table.isEmpty()) {
+        table["boolean"] = "Boolean";
+        table["byte"] = "Byte";
+        table["char"] = "Character";
+        table["short"] = "Short";
+        table["int"] = "Integer";
+        table["long"] = "Long";
+        table["float"] = "Float";
+        table["double"] = "Double";
+    }
+    Q_ASSERT(table.contains(targetLangName()));
+    return table[targetLangName()];
+}
+
+ContainerTypeEntry *TypeDatabase::findContainerType(const QString &name)
+{
+    QString template_name = name;
+
+    int pos = name.indexOf('<');
+    if (pos > 0)
+        template_name = name.left(pos);
+
+    TypeEntry *type_entry = findType(template_name);
+    if (type_entry && type_entry->isContainer())
+        return static_cast<ContainerTypeEntry *>(type_entry);
+    return 0;
+}
+
+PrimitiveTypeEntry *TypeDatabase::findTargetLangPrimitiveType(const QString &java_name)
+{
+    foreach (QList<TypeEntry *> entries, m_entries.values()) {
+        foreach (TypeEntry *e, entries) {
+            if (e && e->isPrimitive()) {
+                PrimitiveTypeEntry *pe = static_cast<PrimitiveTypeEntry *>(e);
+                if (pe->targetLangName() == java_name && pe->preferredConversion())
+                    return pe;
+            }
+        }
+    }
+
+    return 0;
+}
+
+IncludeList TypeDatabase::extraIncludes(const QString &className)
+{
+    ComplexTypeEntry *typeEntry = findComplexType(className);
+    if (typeEntry != 0)
+        return typeEntry->extraIncludes();
+    else
+        return IncludeList();
+}
+
+
+
+QString Include::toString() const
+{
+    if (type == IncludePath)
+        return "#include <" + name + '>';
+    else if (type == LocalPath)
+        return "#include \"" + name + "\"";
+    else
+        return "import " + name + ";";
+}
+
+QString Modification::accessModifierString() const
+{
+    if (isPrivate()) return "private";
+    if (isProtected()) return "protected";
+    if (isPublic()) return "public";
+    if (isFriendly()) return "friendly";
+    return QString();
+}
+
+FunctionModificationList ComplexTypeEntry::functionModifications(const QString &signature) const
+{
+    FunctionModificationList lst;
+    for (int i=0; i<m_function_mods.count(); ++i) {
+        FunctionModification mod = m_function_mods.at(i);
+        if (mod.signature == signature) {
+            lst << mod;
+        }
+    }
+
+    return lst;
+}
+
+FieldModification ComplexTypeEntry::fieldModification(const QString &name) const
+{
+    for (int i=0; i<m_field_mods.size(); ++i)
+        if (m_field_mods.at(i).name == name)
+            return m_field_mods.at(i);
+    FieldModification mod;
+    mod.name = name;
+    mod.modifiers = FieldModification::Readable | FieldModification::Writable;
+    return mod;
+}
+
+QString ContainerTypeEntry::javaPackage() const
+{
+    if (m_type == PairContainer)
+        return "qt";
+    return "java.util";
+}
+
+QString ContainerTypeEntry::targetLangName() const
+{
+
+    switch (m_type) {
+    case StringListContainer: return "List";
+    case ListContainer: return "List";
+    case LinkedListContainer: return "LinkedList";
+    case VectorContainer: return "List";
+    case StackContainer: return "Stack";
+    case QueueContainer: return "Queue";
+    case SetContainer: return "Set";
+    case MapContainer: return "SortedMap";
+    case MultiMapContainer: return "SortedMap";
+    case HashContainer: return "HashMap";
+        //     case MultiHashCollectio: return "MultiHash";
+    case PairContainer: return "QPair";
+    default:
+        qWarning("bad type... %d", m_type);
+        break;
+    }
+    return QString();
+}
+
+QString ContainerTypeEntry::qualifiedCppName() const
+{
+    if (m_type == StringListContainer)
+        return "QStringList";
+    return ComplexTypeEntry::qualifiedCppName();
+}
+
+QString EnumTypeEntry::javaQualifier() const
+{
+    TypeEntry *te = TypeDatabase::instance()->findType(m_qualifier);
+    if (te != 0)
+        return te->targetLangName();
+    else
+        return m_qualifier;
+}
+
+QString EnumTypeEntry::jniName() const
+{
+    return "jint";
+}
+
+QString FlagsTypeEntry::jniName() const
+{
+    return "jint";
+}
+
+void EnumTypeEntry::addEnumValueRedirection(const QString &rejected, const QString &usedValue)
+{
+    m_enum_redirections << EnumValueRedirection(rejected, usedValue);
+}
+
+QString EnumTypeEntry::enumValueRedirection(const QString &value) const
+{
+    for (int i=0; i<m_enum_redirections.size(); ++i)
+        if (m_enum_redirections.at(i).rejected == value)
+            return m_enum_redirections.at(i).used;
+    return QString();
+}
+
+QString FlagsTypeEntry::qualifiedTargetLangName() const
+{
+    return m_enum->javaQualifier() + "." + targetLangName();
+}
+
+
+void TypeDatabase::addRejection(const QString &class_name, const QString &function_name,
+                                const QString &field_name, const QString &enum_name)
+{
+    TypeRejection r;
+    r.class_name = class_name;
+    r.function_name = function_name;
+    r.field_name = field_name;
+    r.enum_name = enum_name;
+
+    m_rejections << r;
+}
+
+bool TypeDatabase::isClassRejected(const QString &class_name)
+{
+    if (!m_rebuild_classes.isEmpty())
+        return !m_rebuild_classes.contains(class_name);
+
+    foreach (const TypeRejection &r, m_rejections)
+        if (r.class_name == class_name && r.function_name == "*" && r.field_name == "*" && r.enum_name == "*") {
+            return true;
+        }
+    return false;
+}
+
+bool TypeDatabase::isEnumRejected(const QString &class_name, const QString &enum_name)
+{
+    foreach (const TypeRejection &r, m_rejections) {
+        if (r.enum_name == enum_name
+            && (r.class_name == class_name || r.class_name == "*")) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool TypeDatabase::isFunctionRejected(const QString &class_name, const QString &function_name)
+{
+    foreach (const TypeRejection &r, m_rejections)
+        if (r.function_name == function_name &&
+            (r.class_name == class_name || r.class_name == "*"))
+            return true;
+    return false;
+}
+
+
+bool TypeDatabase::isFieldRejected(const QString &class_name, const QString &field_name)
+{
+    foreach (const TypeRejection &r, m_rejections)
+        if (r.field_name == field_name &&
+            (r.class_name == class_name || r.class_name == "*"))
+            return true;
+    return false;
+}
+
+FlagsTypeEntry *TypeDatabase::findFlagsType(const QString &name) const
+{
+    FlagsTypeEntry *fte = (FlagsTypeEntry *) findType(name);
+    return fte ? fte : (FlagsTypeEntry *) m_flags_entries.value(name);
+}
+
+QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/) {
+    return QLatin1String("Global");
+}
+
+
+/*!
+ * The Visual Studio 2002 compiler doesn't support these symbols,
+ * which our typedefs unforntuatly expand to.
+ */
+QString fixCppTypeName(const QString &name)
+{
+    if (name == "long long") return "qint64";
+    else if (name == "unsigned long long") return "quint64";
+    return name;
+}
+
+QString formattedCodeHelper(QTextStream &s, Indentor &indentor, QStringList &lines) {
+    bool multilineComment = false;
+    bool lastEmpty = true;
+    QString lastLine;
+    while (!lines.isEmpty()) {
+        const QString line = lines.takeFirst().trimmed();
+        if (line.isEmpty()) {
+            if (!lastEmpty)
+                s << endl;
+            lastEmpty = true;
+            continue;
+        } else {
+            lastEmpty = false;
+        }
+        if (line.startsWith("/*"))
+            multilineComment = true;
+
+        if (multilineComment) {
+            s << indentor;
+            if (line.startsWith("*"))
+                s << " ";
+            s << line << endl;
+            if (line.endsWith("*/"))
+                multilineComment = false;
+        } else if (line.startsWith("}")) {
+            return line;
+        } else if (line.endsWith("}")) {
+            s << indentor << line << endl;
+            return 0;
+        } else if(line.endsWith("{")) {
+            s << indentor << line << endl;
+            QString tmp;
+            {
+                Indentation indent(indentor);
+                tmp = formattedCodeHelper(s, indentor, lines);
+            }
+            if (!tmp.isNull()) {
+                s << indentor << tmp << endl;
+            }
+            lastLine = tmp;
+            continue;
+        } else {
+            s << indentor;
+            if (!lastLine.isEmpty() &&
+                !lastLine.endsWith(";") &&
+                !line.startsWith("@") &&
+                !line.startsWith("//") &&
+                !lastLine.startsWith("//") &&
+                !lastLine.endsWith("}") &&
+                !line.startsWith("{"))
+                s << "    ";
+            s << line << endl;
+        }
+        lastLine = line;
+    }
+    return 0;
+}
+
+
+QTextStream &CodeSnip::formattedCode(QTextStream &s, Indentor &indentor) const
+{
+    QStringList lst(code().split("\n"));
+    while (!lst.isEmpty()) {
+        QString tmp = formattedCodeHelper(s, indentor, lst);
+        if (!tmp.isNull()) {
+            s << indentor << tmp << endl;
+        }
+    }
+    s.flush();
+    return s;
+}
+
+QString TemplateInstance::expandCode() const{
+    TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name);
+    if(templateEntry){
+        QString res = templateEntry->code();
+        foreach(QString key, replaceRules.keys()){
+            res.replace(key, replaceRules[key]);
+        }
+        return "// TEMPLATE - " + m_name + " - START" + res + "// TEMPLATE - " + m_name + " - END";
+    }
+    else{
+        ReportHandler::warning("insert-template referring to non-existing template '" + m_name + "'");
+    }
+    return QString();
+}
+
+
+QString CodeSnipAbstract::code() const{
+    QString res;
+    foreach(CodeSnipFragment *codeFrag, codeList){
+        res.append(codeFrag->code());
+    }
+    return res;
+}
+
+QString CodeSnipFragment::code() const{
+    if(m_instance)
+        return m_instance->expandCode();
+    else
+        return m_code;
+}
+
+QString FunctionModification::toString() const
+{
+    QString str = signature + QLatin1String("->");
+    if (modifiers & AccessModifierMask) {
+        switch (modifiers & AccessModifierMask) {
+        case Private: str += QLatin1String("private"); break;
+        case Protected: str += QLatin1String("protected"); break;
+        case Public: str += QLatin1String("public"); break;
+        case Friendly: str += QLatin1String("friendly"); break;
+        }
+    }
+
+    if (modifiers & Final) str += QLatin1String("final");
+    if (modifiers & NonFinal) str += QLatin1String("non-final");
+
+    if (modifiers & Readable) str += QLatin1String("readable");
+    if (modifiers & Writable) str += QLatin1String("writable");
+
+    if (modifiers & CodeInjection) {
+        foreach (CodeSnip s, snips) {
+            str += QLatin1String("\n//code injection:\n");
+            str += s.code();
+        }
+    }
+
+    if (modifiers & Rename) str += QLatin1String("renamed:") + renamedToName;
+
+    if (modifiers & Deprecated) str += QLatin1String("deprecate");
+
+    if (modifiers & ReplaceExpression) str += QLatin1String("replace-expression");
+
+    return str;
+}
+
+static void removeFunction(ComplexTypeEntry *e, const char *signature)
+{
+    FunctionModification mod;
+    mod.signature = QMetaObject::normalizedSignature(signature);
+    mod.removal = TypeSystem::All;
+
+    e->addFunctionModification(mod);
+}
+
+
+
+
+static void injectCode(ComplexTypeEntry *e,
+                       const char *signature,
+                       const QByteArray &code,
+                       const ArgumentMap &args,
+                       TypeSystem::Language lang = TypeSystem::NativeCode)
+{
+    CodeSnip snip;
+    snip.language = lang;
+    snip.position = CodeSnip::Beginning;
+    snip.addCode(QString::fromLatin1(code));
+    snip.argumentMap = args;
+
+    FunctionModification mod;
+    mod.signature = QMetaObject::normalizedSignature(signature);
+    mod.snips << snip;
+    mod.modifiers = Modification::CodeInjection;
+    e->addFunctionModification(mod);
+}
+
+
+static void addRemoveFunctionToTemplates(TypeDatabase *db)
+{
+    ContainerTypeEntry *qvector = db->findContainerType(QLatin1String("QVector"));
+    removeFunction(qvector, "constData() const");
+    removeFunction(qvector, "data() const");
+    removeFunction(qvector, "data()");
+    removeFunction(qvector, "first()");
+    removeFunction(qvector, "last()");
+    removeFunction(qvector, "operator[](int)");
+    removeFunction(qvector, "operator[](int) const");
+    removeFunction(qvector, "operator=(QVector<T>)");
+
+    ContainerTypeEntry *qlist = db->findContainerType(QLatin1String("QList"));
+    removeFunction(qlist, "constData() const");
+    removeFunction(qlist, "data() const");
+    removeFunction(qlist, "data()");
+    removeFunction(qlist, "back()");
+    removeFunction(qlist, "front()");
+    removeFunction(qlist, "first()");
+    removeFunction(qlist, "last()");
+    removeFunction(qlist, "operator[](int)");
+    removeFunction(qlist, "operator[](int) const");
+    removeFunction(qlist, "operator=(QList<T>)");
+
+    ContainerTypeEntry *qqueue = db->findContainerType(QLatin1String("QQueue"));
+    removeFunction(qqueue, "head() const");
+
+
+    ArgumentMap args1;
+    args1[1] = QLatin1String("$1");
+    ArgumentMap args2 = args1;
+    args2[2] = QLatin1String("$2");
+
+    QByteArray code =
+        "\nif ($1 >= __qt_this->size() || $1 < 0) {"
+        "\n   __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
+        "\n                       QString::fromLatin1(\"Accessing container of size %3 at %4\")"
+        "\n                       .arg(__qt_this->size()).arg($1).toLatin1());"
+        "\n   return;"
+        "\n}";
+
+    QByteArray code_with_return = QByteArray(code).replace("return;", "return 0;");
+
+    QByteArray code_index_length =
+        "\nif ($1 < 0 || $2 < 0 || ($1 + $2) >= __qt_this->size()) {"
+        "\n   __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
+        "\n                       QString::fromLatin1(\"Accessing container of size %3 from %4 to %5\")"
+        "\n                       .arg(__qt_this->size()).arg($1).arg($1+$2).toLatin1());"
+        "\n   return;"
+        "\n}";
+
+    QByteArray code_non_empty =
+        "\nif (__qt_this->isEmpty()) {"
+        "\n   __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
+        "\n                       QString::fromLatin1(\"Accessing empty container...\").toLatin1());"
+        "\n   return;"
+        "\n}";
+
+    QByteArray code_two_indices =
+        "\nif ($1 < 0 || $2 < 0 || $1 >= __qt_this->size() || $2 >= __qt_this->size()) {"
+        "\n   __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
+        "\n                       QString::fromLatin1(\"Accessing container of size %3 from %4 to %5\")"
+        "\n                       .arg(__qt_this->size()).arg($1).arg($1+$2).toLatin1());"
+        "\n   return;"
+        "\n}";
+/* qtd2
+    { // QVector safty...
+        injectCode(qvector, "at(int) const", code_with_return, args1, TypeSystem::TargetLangCode);
+        injectCode(qvector, "replace(int,T)", code, args1, TypeSystem::TargetLangCode);
+        injectCode(qvector, "remove(int)", code, args1, TypeSystem::TargetLangCode);
+        injectCode(qvector, "remove(int, int)", code_index_length, args2, TypeSystem::TargetLangCode);
+        injectCode(qvector, "pop_back()", code_non_empty, ArgumentMap(), TypeSystem::TargetLangCode);
+        injectCode(qvector, "pop_front()", code_non_empty, ArgumentMap(), TypeSystem::TargetLangCode);
+    }
+
+    { // QList safty...
+        injectCode(qlist, "at(int) const", code_with_return, args1);
+        injectCode(qlist, "replace(int, T)", code, args1);
+        injectCode(qlist, "pop_back()", code_non_empty, ArgumentMap());
+        injectCode(qlist, "pop_front()", code_non_empty, ArgumentMap());
+        injectCode(qlist, "swap(int, int)", code_two_indices, args2);
+        injectCode(qlist, "move(int, int)", code_two_indices, args2);
+        injectCode(qlist, "removeAt(int)", code, args1);
+        injectCode(qlist, "takeAt(int)", code_with_return, args1);
+    }
+*/
+}