view generator/typesystem.h @ 282:256ab6cb8e85

Signals look-up andNew syntax for connect. The old one will not work from now on. This will allow for the signals overload. Although changes are done for both D1 and D2 versions, D1 won't work because of compiler bugs. I am tired of waiting for fixes.
author eldar
date Fri, 16 Oct 2009 02:43:59 +0000
parents ae34188ddd84
children 17b5e13364b7 adae77fdc1ea
line wrap: on
line source

/****************************************************************************
**
** 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.
**
****************************************************************************/

#ifndef TYPESYSTEM_H
#define TYPESYSTEM_H

#include <QtCore/QHash>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QMap>
#include <QDebug>

class Indentor;

class AbstractMetaType;
class QTextStream;

class EnumTypeEntry;
class FlagsTypeEntry;

extern QString strings_Object;
extern QString strings_String;
extern QString strings_Thread;
extern QString strings_char;
extern QString strings_java_lang;
extern QString strings_jchar;
extern QString strings_jobject;

struct Include
{
    enum IncludeType {
        IncludePath,
        LocalPath,
        TargetLangImport
    };

    Include() : type(IncludePath) { }
    Include(IncludeType t, const QString &nam) : type(t), name(nam) { };

    bool isValid() { return !name.isEmpty(); }

    IncludeType type;
    QString name;

    QString toString() const;

    bool operator<(const Include &other) const { return name < other.name; }
};
typedef QList<Include> IncludeList;

typedef QMap<int, QString> ArgumentMap;

class TemplateInstance;

namespace TypeSystem {
    enum Language {
        NoLanguage          = 0x0000,
        TargetLangCode      = 0x0001,
        NativeCode          = 0x0002,
        TargetLangFreeCode  = 0x0003,
        ShellCode           = 0x0004,
        ShellDeclaration    = 0x0008,
        PackageInitializer  = 0x0010,
        DestructorFunction  = 0x0020,
        Constructors        = 0x0040,
        Interface           = 0x0080,

        // masks
        All                 = TargetLangCode
                              | NativeCode
                              | ShellCode
                              | ShellDeclaration
                              | PackageInitializer
                              | Constructors
                              | Interface
                              | DestructorFunction,

        JavaAndNativeCode   = TargetLangCode | NativeCode,
        TargetLangAndNativeCode   = TargetLangCode | NativeCode
    };

    enum Ownership {
        InvalidOwnership,
        DefaultOwnership,
        TargetLangOwnership,
        CppOwnership
    };
};

struct ReferenceCount
{
    ReferenceCount() : threadSafe(false), access(Public) { }
    enum Action { // 0x01 - 0xff
        Invalid     = 0x00,
        Add         = 0x01,
        AddAll      = 0x02,
        Remove      = 0x04,
        Set         = 0x08,
        Ignore      = 0x10,

        ActionsMask = 0xff,

        Padding     = 0xffffffff
    };

    enum Flag { // 0x100 - 0xf00
        ThreadSafe      = 0x100,
        Static          = 0x200,
        DeclareVariable = 0x400,

        FlagsMask       = 0xf00
    };

    enum Access { // 0x1000 - 0xf000
        Private     = 0x1000,
        Protected   = 0x2000,
        Friendly    = 0x3000,
        Public      = 0x4000,

        AccessMask  = 0xf000
    };

    Action action;
    QString variableName;
    QString conditional;
    QString declareVariable;

    uint threadSafe : 1;

    uint access;
};

class CodeSnipFragment{
    private:
        const QString m_code;
        TemplateInstance *m_instance;

    public:
        CodeSnipFragment(const QString &code)
    : m_code(code),
        m_instance(0)
        {}

        CodeSnipFragment(TemplateInstance *instance)
    : m_instance(instance)
        {}

        QString code() const;
};

class CodeSnipAbstract{
public:
    QString code() const;

    void addCode(const QString &code){
        codeList.append(new CodeSnipFragment(code));
    }

    void addTemplateInstance(TemplateInstance *ti){
        codeList.append(new CodeSnipFragment(ti));
    }

    QList<CodeSnipFragment*> codeList;
};

class CustomFunction : public CodeSnipAbstract
{
    public:
        CustomFunction(const QString &n = QString()) : name(n) { }

        QString name;
        QString param_name;
};

class TemplateEntry : public CodeSnipAbstract
{
public:
    TemplateEntry(const QString &name)
        : m_name(name)
        {
        };

    QString name() const {
        return m_name;
    };

private:
    QString m_name;
};

typedef QHash<QString, TemplateEntry *> TemplateEntryHash;

class TemplateInstance
{
    public:
        TemplateInstance(const QString &name)
           : m_name(name)
        {}

        void addReplaceRule(const QString &name, const QString &value){
            replaceRules[name]=value;
        }

        QString expandCode() const;

        QString name() const {
            return m_name;
        }

    private:
        const QString m_name;
        QHash<QString, QString> replaceRules;
};


class CodeSnip : public CodeSnipAbstract
{
    public:
        enum Position {
            Beginning,
            End,
            AfterThis
        };

        CodeSnip() : language(TypeSystem::TargetLangCode) { }
        CodeSnip(TypeSystem::Language lang) : language(lang) { }

        // Very simple, easy to make code ugly if you try
        QTextStream &formattedCode(QTextStream &s, Indentor &indentor) const;

        TypeSystem::Language language;
        Position position;
        ArgumentMap argumentMap;
};
typedef QList<CodeSnip> CodeSnipList;

struct ArgumentModification
{
    ArgumentModification(int idx) : removed_default_expression(false), removed(false), no_null_pointers(false), index(idx)
    {}

    // Should the default expression be removed?
    uint removed_default_expression : 1;
    uint removed : 1;
    uint no_null_pointers : 1;
    uint reset_after_use : 1;

    // The index of this argument
    int index;

    // Reference count flags for this argument
    QList<ReferenceCount> referenceCounts;

    // The text given for the new type of the argument
    QString modified_type;

    QString replace_value;

    // The code to be used to construct a return value when no_null_pointers is true and
    // the returned value is null. If no_null_pointers is true and this string is
    // empty, then the base class implementation will be used (or a default construction
    // if there is no implementation)
    QString null_pointer_default_value;

    // The text of the new default expression of the argument
    QString replaced_default_expression;

    // The new definition of ownership for a specific argument
    QHash<TypeSystem::Language, TypeSystem::Ownership> ownerships;

    // Different conversion rules
    CodeSnipList conversion_rules;
};

struct Modification {
    enum Modifiers {
        Private =               0x0001,
        Protected =             0x0002,
        Public =                0x0003,
        Friendly =              0x0004,
        AccessModifierMask =    0x000f,

        Final =                 0x0010,
        NonFinal =              0x0020,
        FinalMask =             Final | NonFinal,

        Readable =              0x0100,
        Writable =              0x0200,

        CodeInjection =         0x1000,
        Rename =                0x2000,
        Deprecated =            0x4000,
        ReplaceExpression =     0x8000,
        VirtualSlot =          0x10000 | NonFinal,
        AllowAsSlot =           0x00020000,
        PrivateSignal =         0x00040000

    };

    Modification() : modifiers(0) { }

    bool isAccessModifier() const { return modifiers & AccessModifierMask; }
    Modifiers accessModifier() const { return Modifiers(modifiers & AccessModifierMask); }
    bool isPrivate() const { return accessModifier() == Private; }
    bool isProtected() const { return accessModifier() == Protected; }
    bool isPublic() const { return accessModifier() == Public; }
    bool isFriendly() const { return accessModifier() == Friendly; }
    bool isFinal() const { return modifiers & Final; }
    bool isNonFinal() const { return modifiers & NonFinal; }
    bool isVirtualSlot() const { return (modifiers & VirtualSlot) == VirtualSlot; }
    bool isAllowedAsSlot() const { return (modifiers & AllowAsSlot) == AllowAsSlot; }
    bool isPrivateSignal() const { return (modifiers & PrivateSignal) == PrivateSignal; }
    QString accessModifierString() const;

    bool isDeprecated() const { return modifiers & Deprecated; }

    void setRenamedTo(const QString &name) { renamedToName = name; }
    QString renamedTo() const { return renamedToName; }
    bool isRenameModifier() const { return modifiers & Rename; }

    uint modifiers;
    QString renamedToName;
};

struct FunctionModification: public Modification
{
    FunctionModification() : removal(TypeSystem::NoLanguage), store_result(false) { }

    bool isCodeInjection() const { return modifiers & CodeInjection; }
    bool isRemoveModifier() const { return removal != TypeSystem::NoLanguage; }

    QString toString() const;

    QString signature;
    QString association;
    CodeSnipList snips;
    TypeSystem::Language removal;
    bool store_result;

    QList<ArgumentModification> argument_mods;
};
typedef QList<FunctionModification> FunctionModificationList;

struct FieldModification: public Modification
{
    bool isReadable() const { return modifiers & Readable; }
    bool isWritable() const { return modifiers & Writable; }

    QString name;
};
typedef QList<FieldModification> FieldModificationList;

struct ExpensePolicy {
    ExpensePolicy() : limit(-1) { }
    int limit;
    QString cost;
    bool isValid() const { return limit >= 0; }
};

class InterfaceTypeEntry;
class ObjectTypeEntry;

class TypeEntry
{
public:
    enum Type {
        PrimitiveType,
        VoidType,
        FlagsType,
        EnumType,
        TemplateArgumentType,
        ThreadType,
        BasicValueType,
        StringType,
        ContainerType,
        InterfaceType,
        ObjectType,
        NamespaceType,
        VariantType,
        JObjectWrapperType,
        CharType,
        ArrayType,
        TypeSystemType,
        CustomType,
    };

    enum CodeGeneration {
        GenerateTargetLang      = 0x0001,
        GenerateCpp             = 0x0002,
        GenerateForSubclass     = 0x0004,

        GenerateNothing         = 0,
        GenerateAll             = 0xffff,
        GenerateCode            = GenerateTargetLang | GenerateCpp
    };

    TypeEntry(const QString &name, Type t)
        : m_name(name),
          m_type(t),
          m_code_generation(GenerateAll),
          m_preferred_conversion(true)
    {
    };

    virtual ~TypeEntry() { }

    Type type() const { return m_type; }
    bool isPrimitive() const { return m_type == PrimitiveType; }
    bool isEnum() const { return m_type == EnumType; }
    bool isFlags() const { return m_type == FlagsType; }
    bool isInterface() const { return m_type == InterfaceType; }
    bool isObject() const { return m_type == ObjectType; }
    bool isString() const { return m_type == StringType; }
    bool isChar() const { return m_type == CharType; }
    bool isNamespace() const { return m_type == NamespaceType; }
    bool isContainer() const { return m_type == ContainerType; }
    bool isVariant() const { return m_type == VariantType; }
    bool isJObjectWrapper() const { return m_type == JObjectWrapperType; }
    bool isArray() const { return m_type == ArrayType; }
    bool isTemplateArgument() const { return m_type == TemplateArgumentType; }
    bool isVoid() const { return m_type == VoidType; }
    bool isThread() const { return m_type == ThreadType; }
    bool isCustom() const { return m_type == CustomType; }
    bool isBasicValue() const { return m_type == BasicValueType; }
    bool isTypeSystem() const { return m_type == TypeSystemType; }

    virtual bool preferredConversion() const { return m_preferred_conversion; }
    virtual void setPreferredConversion(bool b) { m_preferred_conversion = b; }

    virtual QString javaQualifier() const { return QString(); }

    // The type's name in C++, fully qualified
    QString name() const { return m_name; }

    uint codeGeneration() const { return m_code_generation; }
    void setCodeGeneration(uint cg) { m_code_generation = cg; }

    virtual QString qualifiedCppName() const { return m_name; }

    // Its type's name in JNI
    virtual QString jniName() const { return m_name; }

    // The type's name in TargetLang
    virtual QString targetLangName() const { return m_name; }

    // The type to lookup when converting to TargetLang
    virtual QString lookupName() const { return targetLangName(); }

    // The package
    virtual QString javaPackage() const { return QString(); }

    virtual QString qualifiedTargetLangName() const {
//        QString pkg = javaPackage();
/*        if (pkg.isEmpty())*/ return targetLangName();
//        return pkg + '.' + targetLangName();
    }

    virtual InterfaceTypeEntry *designatedInterface() const { return 0; }

    void setCustomConstructor(const CustomFunction &func) { m_customConstructor = func; }
    CustomFunction customConstructor() const { return m_customConstructor; }

    void setCustomDestructor(const CustomFunction &func) { m_customDestructor = func; }
    CustomFunction customDestructor() const { return m_customDestructor; }

    virtual bool isValue() const { return false; }
    virtual bool isComplex() const { return false; }

    virtual bool isNativeIdBased() const { return false; }

    // qtd
    virtual bool isStructInD() const { return false; }

private:
    QString m_name;
    Type m_type;
    uint m_code_generation;
    CustomFunction m_customConstructor;
    CustomFunction m_customDestructor;
    bool m_preferred_conversion;
};
typedef QHash<QString, QList<TypeEntry *> > TypeEntryHash;
typedef QHash<QString, TypeEntry *> SingleTypeEntryHash;


class TypeSystemTypeEntry : public TypeEntry
{
public:
    TypeSystemTypeEntry(const QString &name)
        : TypeEntry(name, TypeSystemType)
    {
    };

    QList<CodeSnip> snips;
};


class ThreadTypeEntry : public TypeEntry
{
public:
    ThreadTypeEntry() : TypeEntry("QThread", ThreadType) { setCodeGeneration(GenerateNothing); }

    QString jniName() const { return strings_jobject; }
    QString targetLangName() const { return strings_Thread; }
    QString javaPackage() const { return strings_java_lang; }
};

class VoidTypeEntry : public TypeEntry
{
public:
    VoidTypeEntry() : TypeEntry("void", VoidType) { }
};

class TemplateArgumentEntry : public TypeEntry
{
public:
    TemplateArgumentEntry(const QString &name)
        : TypeEntry(name, TemplateArgumentType), m_ordinal(0)
    {
    }

    int ordinal() const { return m_ordinal; }
    void setOrdinal(int o) { m_ordinal = o; }

private:
    int m_ordinal;
};

class ArrayTypeEntry : public TypeEntry
{
public:
    ArrayTypeEntry(const TypeEntry *nested_type) : TypeEntry("Array", ArrayType), m_nested_type(nested_type)
    {
        Q_ASSERT(m_nested_type);
    }

    void setNestedTypeEntry(TypeEntry *nested) { m_nested_type = nested; }
    const TypeEntry *nestedTypeEntry() const { return m_nested_type; }

    QString targetLangName() const { return m_nested_type->targetLangName() + "[]"; }
    QString jniName() const
    {
        if (m_nested_type->isPrimitive())
            return m_nested_type->jniName() + "Array";
        else
            return "jobjectArray";
    }

private:
    const TypeEntry *m_nested_type;
};


class PrimitiveTypeEntry : public TypeEntry
{
public:
    PrimitiveTypeEntry(const QString &name)
        : TypeEntry(name, PrimitiveType), m_preferred_conversion(true), m_preferred_java_type(true)
    {
    }

    QString targetLangName() const { return m_java_name; }
    void setTargetLangName(const QString &targetLangName) { m_java_name  = targetLangName; }

    QString jniName() const { return m_jni_name; }
    void setJniName(const QString &jniName) { m_jni_name = jniName; }

    QString javaObjectFullName() const { return javaObjectPackage() + "." + javaObjectName(); }
    QString javaObjectName() const;
    QString javaObjectPackage() const { return strings_java_lang; }

    virtual bool preferredConversion() const { return m_preferred_conversion; }
    virtual void setPreferredConversion(bool b) { m_preferred_conversion = b; }

    virtual bool preferredTargetLangType() const { return m_preferred_java_type; }
    virtual void setPreferredTargetLangType(bool b) { m_preferred_java_type = b; }

private:
    QString m_java_name;
    QString m_jni_name;
    uint m_preferred_conversion : 1;
    uint m_preferred_java_type : 1;
};




struct EnumValueRedirection
{
    EnumValueRedirection(const QString &rej, const QString &us)
        : rejected(rej),
          used(us)
    {
    }
    QString rejected;
    QString used;
};

class EnumTypeEntry : public TypeEntry
{
public:
    EnumTypeEntry(const QString &nspace, const QString &enumName)
        : TypeEntry(nspace.isEmpty() ? enumName : nspace + QLatin1String("::") + enumName,
                    EnumType),
          m_flags(0),
          m_extensible(false)
    {
        m_qualifier = nspace;
        m_java_name = enumName;
    }

    QString javaPackage() const { return m_package_name; }
    void setTargetLangPackage(const QString &package) { m_package_name = package; }

    QString targetLangName() const { return m_java_name; }
    QString javaQualifier() const;
    QString qualifiedTargetLangName() const {
        return javaQualifier() + '_' + targetLangName();
//        return targetLangName();
    }

    QString jniName() const;

    QString qualifier() const { return m_qualifier; }
    void setQualifier(const QString &q) { m_qualifier = q; }

    virtual bool preferredConversion() const { return false; }

    bool isBoundsChecked() const { return m_lower_bound.isEmpty() && m_upper_bound.isEmpty(); }

    QString upperBound() const { return m_upper_bound; }
    void setUpperBound(const QString &bound) { m_upper_bound = bound; }

    QString lowerBound() const { return m_lower_bound; }
    void setLowerBound(const QString &bound) { m_lower_bound = bound; }

    void setFlags(FlagsTypeEntry *flags) { m_flags = flags; }
    FlagsTypeEntry *flags() const { return m_flags; }

    bool isExtensible() const { return m_extensible; }
    void setExtensible(bool is) { m_extensible = is; }

    bool isEnumValueRejected(const QString &name) { return m_rejected_enums.contains(name); }
    void addEnumValueRejection(const QString &name) { m_rejected_enums << name; }
    QStringList enumValueRejections() const { return m_rejected_enums; }

    void addEnumValueRedirection(const QString &rejected, const QString &usedValue);
    QString enumValueRedirection(const QString &value) const;

    bool forceInteger() const { return m_force_integer; }
    void setForceInteger(bool force) { m_force_integer = force; }

private:
    QString m_package_name;
    QString m_qualifier;
    QString m_java_name;

    QString m_lower_bound;
    QString m_upper_bound;

    QStringList m_rejected_enums;
    QList<EnumValueRedirection> m_enum_redirections;

    FlagsTypeEntry *m_flags;

    bool m_extensible;
    bool m_force_integer;
};

class FlagsTypeEntry : public TypeEntry
{
public:
    FlagsTypeEntry(const QString &name) : TypeEntry(name, FlagsType), m_enum(0)
    {
    }

    QString qualifiedTargetLangName() const;
    QString targetLangName() const { return m_java_name; }
    QString jniName() const;
    virtual bool preferredConversion() const { return false; }

    QString originalName() const { return m_original_name; }
    void setOriginalName(const QString &s) { m_original_name = s; }

    QString flagsName() const { return m_java_name; }
    void setFlagsName(const QString &name) { m_java_name = name; }

    bool forceInteger() const { return m_enum->forceInteger(); }

    EnumTypeEntry *originator() const { return m_enum; }
    void setOriginator(EnumTypeEntry *e) { m_enum = e; }

    QString javaPackage() const { return m_enum->javaPackage(); }
    QString javaQualifier() const { return m_enum->javaQualifier(); }
    QString qualifier() const { return m_enum->qualifier(); }

private:
    QString m_original_name;
    QString m_java_name;
    EnumTypeEntry *m_enum;
};


class ComplexTypeEntry : public TypeEntry
{
public:
    enum TypeFlag {
        ForceAbstract      = 0x1,
        DeleteInMainThread = 0x2,
        Deprecated         = 0x4
    };
    typedef QFlags<TypeFlag> TypeFlags;

    ComplexTypeEntry(const QString &name, Type t)
        : TypeEntry(QString(name).replace("::", "_"), t),
          m_qualified_cpp_name(name),
          m_qobject(false),
          m_polymorphic_base(false),
          m_generic_class(false),
          m_type_flags(0),
          m_isStructInD(false),
          m_isAbstract(false)
    {
        Include inc;
        inc.name = "QVariant";
        inc.type = Include::IncludePath;

        addExtraInclude(inc);
    }

    bool isComplex() const { return true; }

    IncludeList extraIncludes() const { return m_extra_includes; }
    void setExtraIncludes(const IncludeList &includes) { m_extra_includes = includes; }
    void addExtraInclude(const Include &include)
    {
        if (!m_includes_used.value(include.name, false)) {
            m_extra_includes << include;
            m_includes_used[include.name] = true;
        }
    }

    ComplexTypeEntry *copy() const
    {
        ComplexTypeEntry *centry = new ComplexTypeEntry(name(), type());
        centry->setInclude(include());
        centry->setExtraIncludes(extraIncludes());
        centry->setFunctionModifications(functionModifications());
        centry->setFieldModifications(fieldModifications());
        centry->setQObject(isQObject());
        centry->setDefaultSuperclass(defaultSuperclass());
        centry->setCodeSnips(codeSnips());
        centry->setTargetLangPackage(javaPackage());

        return centry;
    }

    void setLookupName(const QString &name)
    {
        m_lookup_name = name;
    }

    virtual QString lookupName() const
    {
        return m_lookup_name.isEmpty() ? targetLangName() : m_lookup_name;
    }

    QString jniName() const { return strings_jobject; }


    Include include() const { return m_include; }
    void setInclude(const Include &inc) { m_include = inc; }

    void setTypeFlags(TypeFlags flags)
    {
        m_type_flags = flags;
    }

    TypeFlags typeFlags() const
    {
        return m_type_flags;
    }

    CodeSnipList codeSnips() const { return m_code_snips; }
    void setCodeSnips(const CodeSnipList &codeSnips) { m_code_snips = codeSnips; }
    void addCodeSnip(const CodeSnip &codeSnip) { m_code_snips << codeSnip; }

    FunctionModificationList functionModifications() const { return m_function_mods; }
    void setFunctionModifications(const FunctionModificationList &functionModifications) {
        m_function_mods = functionModifications;
    }
    void addFunctionModification(const FunctionModification &functionModification) {
        m_function_mods << functionModification;
    }
    FunctionModificationList functionModifications(const QString &signature) const;

    FieldModification fieldModification(const QString &name) const;
    void setFieldModifications(const FieldModificationList &mods) { m_field_mods = mods; }
    FieldModificationList fieldModifications() const { return m_field_mods; }

    QString javaPackage() const { return m_package; }
    void setTargetLangPackage(const QString &package) { m_package = package; }

    bool isQObject() const { return m_qobject; }
    void setQObject(bool qobject) { m_qobject = qobject; }

    QString defaultSuperclass() const { return m_default_superclass; }
    void setDefaultSuperclass(const QString &sc) { m_default_superclass = sc; }

    virtual QString qualifiedCppName() const { return m_qualified_cpp_name; }


    void setIsPolymorphicBase(bool on)
    {
        m_polymorphic_base = on;
    }
    bool isPolymorphicBase() const { return m_polymorphic_base; }

    void setPolymorphicIdValue(const QString &value)
    {
        m_polymorphic_id_value = value;
    }
    QString polymorphicIdValue() const { return m_polymorphic_id_value; }

    void setExpensePolicy(const ExpensePolicy &policy) { m_expense_policy = policy; }
    const ExpensePolicy &expensePolicy() const { return m_expense_policy; }

    QString targetType() const { return m_target_type; }
    void setTargetType(const QString &code) { m_target_type = code; }

    QString targetLangName() const { return m_java_name.isEmpty()
                                   ? TypeEntry::targetLangName()
                                   : m_java_name;
    }
    void setTargetLangName(const QString &name) { m_java_name = name; }

    bool isGenericClass() const { return m_generic_class; }
    void setGenericClass(bool isGeneric) { m_generic_class = isGeneric; }

    QString injectedImports;

    // qtd
    bool isStructInD() const { return m_isStructInD; }
    void setStructInD(bool isStruct) { m_isStructInD = isStruct; }

    bool isAbstract() const { return m_isAbstract; }
    void setAbstract(bool isAbstract) { m_isAbstract = isAbstract; }

    void setDepends(const QStringList &depends) {m_depends = depends; }
    const QStringList &depends() {return m_depends; }

    QString addedTo;
    QStringList includedClasses;


private:
    IncludeList m_extra_includes;
    Include m_include;
    QHash<QString, bool> m_includes_used;
    FunctionModificationList m_function_mods;
    FieldModificationList m_field_mods;
    CodeSnipList m_code_snips;
    QString m_package;
    QString m_default_superclass;
    QString m_qualified_cpp_name;
    QString m_java_name;

    uint m_qobject : 1;
    uint m_polymorphic_base : 1;
    uint m_generic_class : 1;

    QString m_polymorphic_id_value;
    QString m_lookup_name;
    QString m_target_type;
    ExpensePolicy m_expense_policy;
    TypeFlags m_type_flags;

    // qtd
    bool m_isStructInD;
    bool m_isAbstract;
    QStringList m_depends;
};

class ContainerTypeEntry : public ComplexTypeEntry
{
public:
    enum Type {
        NoContainer,
        ListContainer,
        StringListContainer,
        LinkedListContainer,
        VectorContainer,
        StackContainer,
        QueueContainer,
        SetContainer,
        MapContainer,
        MultiMapContainer,
        HashContainer,
        MultiHashContainer,
        PairContainer,
    };

    ContainerTypeEntry(const QString &name, Type type)
        : ComplexTypeEntry(name, ContainerType)
    {
        m_type = type;
        setCodeGeneration(GenerateForSubclass);
    }

    Type type() const { return m_type; }
    QString targetLangName() const;
    QString javaPackage() const;
    QString qualifiedCppName() const;

private:
    Type m_type;
};


class NamespaceTypeEntry : public ComplexTypeEntry
{
public:
    NamespaceTypeEntry(const QString &name) : ComplexTypeEntry(name, NamespaceType) { }
};


class ValueTypeEntry : public ComplexTypeEntry
{
public:
    ValueTypeEntry(const QString &name) : ComplexTypeEntry(name, BasicValueType) { }

    bool isValue() const { return true; }

    virtual bool isNativeIdBased() const { return true; }

protected:
    ValueTypeEntry(const QString &name, Type t) : ComplexTypeEntry(name, t) { }
};


class StringTypeEntry : public ValueTypeEntry
{
public:
    StringTypeEntry(const QString &name)
        : ValueTypeEntry(name, StringType)
    {
        setCodeGeneration(GenerateNothing);
    }

    QString jniName() const { return strings_jobject; }
    QString targetLangName() const { return strings_String; }
    QString javaPackage() const { return strings_java_lang; }

    virtual bool isNativeIdBased() const { return false; }
};

class CharTypeEntry : public ValueTypeEntry
{
public:
    CharTypeEntry(const QString &name) : ValueTypeEntry(name, CharType)
    {
        setCodeGeneration(GenerateNothing);
    }

    QString jniName() const { return strings_jchar; }
    QString targetLangName() const { return strings_char; }
    QString javaPackage() const { return QString(); }

    virtual bool isNativeIdBased() const { return false; }
};

class JObjectWrapperTypeEntry: public ValueTypeEntry
{
public:
    JObjectWrapperTypeEntry(const QString &name) : ValueTypeEntry(name, JObjectWrapperType) { }

    QString jniName() const { return strings_jobject; }
    QString targetLangName() const { return strings_Object; }
    QString javaPackage() const { return strings_java_lang; }

    bool isNativeIdBased() const { return false; }
};

class VariantTypeEntry: public ValueTypeEntry
{
public:
    VariantTypeEntry(const QString &name) : ValueTypeEntry(name, VariantType) { }

    QString jniName() const { return strings_jobject; }
    QString targetLangName() const { return "QVariant"; }
    QString javaPackage() const { return "qt.core"; }
    virtual bool isNativeIdBased() const { return false; }
};


class InterfaceTypeEntry : public ComplexTypeEntry
{
public:
    InterfaceTypeEntry(const QString &name)
        : ComplexTypeEntry(name, InterfaceType)
    {
    }

    static QString interfaceName(const QString &name) {
        return "I" + name;
    }

    ObjectTypeEntry *origin() const { return m_origin; }
    void setOrigin(ObjectTypeEntry *origin) { m_origin = origin; }

    virtual bool isNativeIdBased() const { return true; }
    virtual QString qualifiedCppName() const {
        return ComplexTypeEntry::qualifiedCppName().right(ComplexTypeEntry::qualifiedCppName().length() - interfaceName("").length());
    }

private:
    ObjectTypeEntry *m_origin;
};


class ObjectTypeEntry : public ComplexTypeEntry
{
public:
    ObjectTypeEntry(const QString &name)
        : ComplexTypeEntry(name, ObjectType), m_interface(0)
    {
    }

    InterfaceTypeEntry *designatedInterface() const { return m_interface; }
    void setDesignatedInterface(InterfaceTypeEntry *entry) { m_interface = entry; }

    virtual bool isNativeIdBased() const { return true; }

private:
    InterfaceTypeEntry *m_interface;
};

class CustomTypeEntry : public ComplexTypeEntry
{
public:
    CustomTypeEntry(const QString &name) : ComplexTypeEntry(name, CustomType) { }

    virtual void generateCppJavaToQt(QTextStream &s,
                                     const AbstractMetaType *java_type,
                                     const QString &env_name,
                                     const QString &qt_name,
                                     const QString &java_name) const = 0;

    virtual void generateCppQtToJava(QTextStream &s,
                                     const AbstractMetaType *java_type,
                                     const QString &env_name,
                                     const QString &qt_name,
                                     const QString &java_name) const = 0;
};

struct TypeRejection
{
    QString class_name;
    QString function_name;
    QString field_name;
    QString enum_name;
};

class TypeDatabase
{
public:
    TypeDatabase();

    static TypeDatabase *instance();

    QList<Include> extraIncludes(const QString &className);

    inline PrimitiveTypeEntry *findPrimitiveType(const QString &name);
    inline ComplexTypeEntry *findComplexType(const QString &name);
    inline ObjectTypeEntry *findObjectType(const QString &name);
    inline NamespaceTypeEntry *findNamespaceType(const QString &name);
    ContainerTypeEntry *findContainerType(const QString &name);

    TypeEntry *findType(const QString &name) const {
        QList<TypeEntry *> entries = findTypes(name);
        foreach (TypeEntry *entry, entries) {
            if (entry != 0 &&
                (!entry->isPrimitive() || static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())) {
                return entry;
            }
        }
        return 0;
    }
    QList<TypeEntry *> findTypes(const QString &name) const { return m_entries.value(name); }
    TypeEntryHash allEntries() { return m_entries; }
    SingleTypeEntryHash entries() {
        TypeEntryHash entries = allEntries();

        SingleTypeEntryHash returned;
        QList<QString> keys = entries.keys();

        foreach(QString key, keys) {
            returned[key] = findType(key);
        }

        return returned;
    }

    PrimitiveTypeEntry *findTargetLangPrimitiveType(const QString &java_name);

    void addRejection(const QString &class_name, const QString &function_name,
                      const QString &field_name, const QString &enum_name);
    bool isClassRejected(const QString &class_name);
    bool isFunctionRejected(const QString &class_name, const QString &function_name);
    bool isFieldRejected(const QString &class_name, const QString &field_name);
    bool isEnumRejected(const QString &class_name, const QString &enum_name);

    void addType(TypeEntry *e) { m_entries[e->qualifiedCppName()].append(e); }

    SingleTypeEntryHash flagsEntries() const { return m_flags_entries; }
    FlagsTypeEntry *findFlagsType(const QString &name) const;
    void addFlagsType(FlagsTypeEntry *fte) { m_flags_entries[fte->originalName()] = fte; }

    TemplateEntry *findTemplate(const QString &name) { return m_templates[name]; }
    void addTemplate(TemplateEntry *t) { m_templates[t->name()] = t; }

    void setIncludeEclipseWarnings(bool on) { m_includeEclipseWarnings = on; }
    bool includeEclipseWarnings() const { return m_includeEclipseWarnings; }

    void setSuppressWarnings(bool on) { m_suppressWarnings = on; }
    void addSuppressedWarning(const QString &s)
    {
        m_suppressedWarnings.append(s);
    }

    bool isSuppressedWarning(const QString &s)
    {
        if (!m_suppressWarnings)
            return false;

        foreach (const QString &_warning, m_suppressedWarnings) {
            QString warning(QString(_warning).replace("\\*", "&place_holder_for_asterisk;"));

            QStringList segs = warning.split("*", QString::SkipEmptyParts);
            if (segs.size() == 0)
                continue ;

            int i = 0;
            int pos = s.indexOf(QString(segs.at(i++)).replace("&place_holder_for_asterisk;", "*"));
            //qDebug() << "s == " << s << ", warning == " << segs;
            while (pos != -1) {
                if (i == segs.size())
                    return true;
                pos = s.indexOf(QString(segs.at(i++)).replace("&place_holder_for_asterisk;", "*"), pos);
            }
        }

        return false;
    }

    void setRebuildClasses(const QStringList &cls) { m_rebuild_classes = cls; }

    static QString globalNamespaceClassName(const TypeEntry *te);
    QString filename() const { return "typesystem.txt"; }

    bool parseFile(const QString &filename, const QString &work_dir, bool generate = true);

private:
    uint m_suppressWarnings : 1;
    uint m_includeEclipseWarnings : 1;
    uint m_reserved : 30;

    TypeEntryHash m_entries;
    SingleTypeEntryHash m_flags_entries;
    TemplateEntryHash m_templates;
    QStringList m_suppressedWarnings;

    QList<TypeRejection> m_rejections;
    QStringList m_rebuild_classes;
};

inline PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString &name)
{
    QList<TypeEntry *> entries = findTypes(name);

    foreach (TypeEntry *entry, entries) {
        if (entry != 0 && entry->isPrimitive() && static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())
            return static_cast<PrimitiveTypeEntry *>(entry);
    }

    return 0;
}

inline ComplexTypeEntry *TypeDatabase::findComplexType(const QString &name)
{
    TypeEntry *entry = findType(name);
    if (entry != 0 && entry->isComplex())
        return static_cast<ComplexTypeEntry *>(entry);
    else
        return 0;
}

inline ObjectTypeEntry *TypeDatabase::findObjectType(const QString &name)
{
    TypeEntry *entry = findType(name);
    if (entry != 0 && entry->isObject())
        return static_cast<ObjectTypeEntry *>(entry);
    else
        return 0;
}

inline NamespaceTypeEntry *TypeDatabase::findNamespaceType(const QString &name)
{
    TypeEntry *entry = findType(name);
    if (entry != 0 && entry->isNamespace())
        return static_cast<NamespaceTypeEntry *>(entry);
    else
        return 0;
}

QString fixCppTypeName(const QString &name);

#endif // TYPESYSTEM_H