diff options
-rw-r--r-- | CMakeLists.txt | 20 | ||||
-rw-r--r-- | abstractmetabuilder.cpp | 139 | ||||
-rw-r--r-- | abstractmetabuilder.h | 17 | ||||
-rw-r--r-- | abstractmetalang.cpp | 1 | ||||
-rw-r--r-- | abstractmetalang.h | 26 | ||||
-rw-r--r-- | apiextractor.cpp | 2 | ||||
-rw-r--r-- | doc/typesystem_specifying_types.rst | 19 | ||||
-rw-r--r-- | graph.cpp | 2 | ||||
-rw-r--r-- | include.cpp | 49 | ||||
-rw-r--r-- | include.h | 83 | ||||
-rw-r--r-- | parser/codemodel.cpp | 6 | ||||
-rw-r--r-- | reporthandler.cpp | 1 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/testabstractmetatype.cpp | 3 | ||||
-rw-r--r-- | tests/testenum.cpp | 7 | ||||
-rw-r--r-- | tests/testfunctiontag.cpp | 64 | ||||
-rw-r--r-- | tests/testfunctiontag.h | 36 | ||||
-rw-r--r-- | tests/testutil.h | 1 | ||||
-rw-r--r-- | typedatabase.cpp | 386 | ||||
-rw-r--r-- | typedatabase.h | 190 | ||||
-rw-r--r-- | typesystem.cpp | 475 | ||||
-rw-r--r-- | typesystem.h | 327 | ||||
-rw-r--r-- | typesystem_p.h | 159 |
23 files changed, 1226 insertions, 788 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c2cdbd611..e6d3034d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,16 +7,20 @@ find_package(Qt4 4.5.0 REQUIRED) find_package(LibXml2 2.6.32 REQUIRED) find_package(LibXslt 1.1.19 REQUIRED) +option(BUILD_TESTS "Build tests." TRUE) + if (MSVC) set(CMAKE_CXX_FLAGS "/DWIN32 /D_WINDOWS /w /EHsc- /GS- /GR- /DAPIEXTRACTOR_ENABLE_DUPLICATE_ENUM_VALUES /DAPIEXTRACTOR_BUILD -D_SCL_SECURE_NO_WARNINGS") else (MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -DAPIEXTRACTOR_ENABLE_DUPLICATE_ENUM_VALUES -fvisibility=hidden") endif(MSVC) -set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/tests) +if (BUILD_TESTS) + set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/tests) +endif() set(apiextractor_MAJOR_VERSION 0) -set(apiextractor_MINOR_VERSION 4) -set(apiextractor_MICRO_VERSION 1) +set(apiextractor_MINOR_VERSION 5) +set(apiextractor_MICRO_VERSION 0) set(apiextractor_VERSION "${apiextractor_MAJOR_VERSION}.${apiextractor_MINOR_VERSION}.${apiextractor_MICRO_VERSION}") configure_file(apiextractorversion.h.in ${CMAKE_CURRENT_BINARY_DIR}/apiextractorversion.h @ONLY) set(QT_USE_QTCORE 1) @@ -40,6 +44,8 @@ graph.cpp reporthandler.cpp typeparser.cpp typesystem.cpp +include.cpp +typedatabase.cpp parser/ast.cpp parser/binder.cpp parser/class_compiler.cpp @@ -110,10 +116,14 @@ typesystem.h fileout.h docparser.h qtdocparser.h +include.h +typedatabase.h ) -enable_testing() -add_subdirectory(tests) +if (BUILD_TESTS) + enable_testing() + add_subdirectory(tests) +endif() install(FILES ${root_HEADERS} DESTINATION include/apiextractor) install(TARGETS apiextractor EXPORT apiextractor diff --git a/abstractmetabuilder.cpp b/abstractmetabuilder.cpp index ac1dcd029..facb15ca5 100644 --- a/abstractmetabuilder.cpp +++ b/abstractmetabuilder.cpp @@ -23,6 +23,7 @@ #include "abstractmetabuilder.h" #include "reporthandler.h" +#include "typedatabase.h" #include "parser/ast.h" #include "parser/binder.h" @@ -44,6 +45,7 @@ #include <QDir> #include <cstdio> +#include <algorithm> #include "graph.h" static QString stripTemplateArgs(const QString &name) @@ -333,7 +335,10 @@ bool AbstractMetaBuilder::build(QIODevice* input) fixQObjectForScope(types, model_dynamic_cast<NamespaceModelItem>(m_dom)); // Start the generation... - QList<ClassModelItem > typeValues = typeMap.values(); + ClassList typeValues = typeMap.values(); + ClassList::iterator it = std::unique(typeValues.begin(), typeValues.end()); + typeValues.erase(it, typeValues.end()); + ReportHandler::setProgressReference(typeValues); foreach (ClassModelItem item, typeValues) { ReportHandler::progress("Generating class model for %s", qPrintable(item->name())); @@ -375,6 +380,28 @@ bool AbstractMetaBuilder::build(QIODevice* input) addAbstractMetaClass(cls); } + // Global functions + foreach (FunctionModelItem func, m_dom->functions()) { + if (func->accessPolicy() != CodeModel::Public || func->name().startsWith("operator")) + continue; + FunctionTypeEntry* funcEntry = types->findFunctionType(func->name()); + if (!funcEntry) + continue; + + AbstractMetaFunction* metaFunc = traverseFunction(func); + if (!metaFunc) + continue; + + if (!funcEntry->hasSignature(metaFunc->minimalSignature())) { + delete metaFunc; + continue; + } + + setInclude(funcEntry, func->fileName()); + metaFunc->setTypeEntry(funcEntry); + m_globalFunctions << metaFunc; + } + ReportHandler::setProgressReference(m_metaClasses); foreach (AbstractMetaClass *cls, m_metaClasses) { ReportHandler::progress("Fixing class inheritance..."); @@ -421,9 +448,22 @@ bool AbstractMetaBuilder::build(QIODevice* input) && !m_metaClasses.findClass(entry->qualifiedCppName())) { ReportHandler::warning(QString("type '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.") .arg(entry->qualifiedCppName())); - } - - if (entry->isEnum()) { + } else if (entry->type() == TypeEntry::FunctionType) { + const FunctionTypeEntry* fte = static_cast<const FunctionTypeEntry*>(entry); + foreach (QString signature, fte->signatures()) { + bool ok = false; + foreach (AbstractMetaFunction* func, m_globalFunctions) { + if (signature == func->minimalSignature()) { + ok = true; + break; + } + } + if (!ok) { + ReportHandler::warning(QString("Global function '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.") + .arg(signature)); + } + } + } else if (entry->isEnum()) { QString pkg = entry->targetLangPackage(); QString name = (pkg.isEmpty() ? QString() : pkg + ".") + ((EnumTypeEntry *) entry)->targetLangQualifier(); @@ -503,17 +543,6 @@ bool AbstractMetaBuilder::build(QIODevice* input) m_currentClass = 0; - foreach (FunctionModelItem func, m_dom->functions()) { - if (func->accessPolicy() != CodeModel::Public || func->name().startsWith("operator")) - continue; - - AbstractMetaFunction* metaFunc = traverseFunction(func); - if (metaFunc) { - metaFunc->setIncludeFile(func->fileName()); - m_globalFunctions << metaFunc; - } - } - // Functions added to the module on the type system. foreach (AddedFunction addedFunc, types->globalUserFunctions()) { AbstractMetaFunction* metaFunc = traverseFunction(addedFunc); @@ -621,10 +650,8 @@ AbstractMetaClass *AbstractMetaBuilder::traverseNamespace(NamespaceModelItem nam popScope(); m_namespacePrefix = currentScope()->qualifiedName().join("::"); - if (!type->include().isValid()) { - QFileInfo info(namespaceItem->fileName()); - type->setInclude(Include(Include::IncludePath, info.fileName())); - } + if (!type->include().isValid()) + setInclude(type, namespaceItem->fileName()); return metaClass; } @@ -903,8 +930,6 @@ AbstractMetaEnum *AbstractMetaBuilder::traverseEnum(EnumModelItem enumItem, Abst default: break; } - metaEnum->setIncludeFile(enumItem->fileName()); - ReportHandler::debugMedium(QString(" - traversing enum %1").arg(metaEnum->fullName())); foreach (EnumeratorModelItem value, enumItem->enumerators()) { @@ -928,6 +953,11 @@ AbstractMetaEnum *AbstractMetaBuilder::traverseEnum(EnumModelItem enumItem, Abst m_enums << metaEnum; + if (!metaEnum->typeEntry()->include().isValid()) + setInclude(metaEnum->typeEntry(), enumItem->fileName()); + + metaEnum->setOriginalAttributes(metaEnum->attributes()); + return metaEnum; } @@ -968,10 +998,8 @@ AbstractMetaClass* AbstractMetaBuilder::traverseTypeAlias(TypeAliasModelItem typ *metaClass += AbstractMetaAttributes::Public; // Set the default include file name - if (!type->include().isValid()) { - QFileInfo info(typeAlias->fileName()); - type->setInclude(Include(Include::IncludePath, info.fileName())); - } + if (!type->include().isValid()) + setInclude(type, typeAlias->fileName()); return metaClass; } @@ -1081,10 +1109,8 @@ AbstractMetaClass *AbstractMetaBuilder::traverseClass(ClassModelItem classItem) m_currentClass = oldCurrentClass; // Set the default include file name - if (!type->include().isValid()) { - QFileInfo info(classItem->fileName()); - type->setInclude(Include(Include::IncludePath, info.fileName())); - } + if (!type->include().isValid()) + setInclude(type, classItem->fileName()); return metaClass; } @@ -1433,12 +1459,11 @@ bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *metaClass) void AbstractMetaBuilder::traverseEnums(ScopeModelItem scopeItem, AbstractMetaClass *metaClass, const QStringList &enumsDeclarations) { EnumList enums = scopeItem->enums(); - foreach (EnumModelItem enum_item, enums) { - AbstractMetaEnum *meta_enum = traverseEnum(enum_item, metaClass, QSet<QString>::fromList(enumsDeclarations)); - if (meta_enum) { - meta_enum->setOriginalAttributes(meta_enum->attributes()); - metaClass->addEnum(meta_enum); - meta_enum->setEnclosingClass(metaClass); + foreach (EnumModelItem enumItem, enums) { + AbstractMetaEnum *metaEnum = traverseEnum(enumItem, metaClass, QSet<QString>::fromList(enumsDeclarations)); + if (metaEnum) { + metaClass->addEnum(metaEnum); + metaEnum->setEnclosingClass(metaClass); } } } @@ -2660,34 +2685,11 @@ AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted(const Abstra if (clazz->isInterface() || !clazz->typeEntry()->generateCode()) continue; - // check base class dep. - QString baseClassName(clazz->baseClassName()); - if (!baseClassName.isNull() && baseClassName != clazz->name() && map.contains(baseClassName)) { - if (clazz->baseClass()->enclosingClass() && - clazz->baseClass()->enclosingClass() != clazz->enclosingClass()) { - baseClassName = clazz->baseClass()->enclosingClass()->name(); - } - graph.addEdge(map[baseClassName], map[clazz->name()]); - } - - // interfaces... - foreach (AbstractMetaClass* interface, clazz->interfaces()) { - if (!interface->typeEntry()->generateCode()) - continue; - - if (interface->isInterface()) - interface = interface->primaryInterfaceImplementor(); + if (clazz->enclosingClass()) + graph.addEdge(map[clazz->enclosingClass()->name()], map[clazz->name()]); - if (interface->enclosingClass() && - interface->enclosingClass() != clazz->enclosingClass()) { - baseClassName = interface->enclosingClass()->name(); - } else { - baseClassName = interface->name(); - } - - if (!baseClassName.isNull() && baseClassName != clazz->name() && map.contains(baseClassName)) - graph.addEdge(map[baseClassName], map[clazz->name()]); - } + foreach(AbstractMetaClass* baseClass, getBaseClasses(clazz)) + graph.addEdge(map[baseClass->name()], map[clazz->name()]); foreach (AbstractMetaFunction* func, clazz->functions()) { foreach (AbstractMetaArgument* arg, func->arguments()) { @@ -2733,3 +2735,16 @@ AbstractMetaArgumentList AbstractMetaBuilder::reverseList(const AbstractMetaArgu return ret; } + +void AbstractMetaBuilder::setGlobalHeader(const QString& globalHeader) +{ + m_globalHeader = QFileInfo(globalHeader); +} + +void AbstractMetaBuilder::setInclude(TypeEntry* te, const QString& fileName) const +{ + + QFileInfo info(fileName); + if (info.exists() && m_globalHeader != info) + te->setInclude(Include(Include::IncludePath, info.fileName())); +} diff --git a/abstractmetabuilder.h b/abstractmetabuilder.h index 525d4d3b1..e676f1217 100644 --- a/abstractmetabuilder.h +++ b/abstractmetabuilder.h @@ -29,7 +29,10 @@ #include "typesystem.h" #include "typeparser.h" -#include <QtCore/QSet> +#include <QSet> +#include <QFileInfo> + +class TypeDatabase; class APIEXTRACTOR_API AbstractMetaBuilder { @@ -160,8 +163,7 @@ public: bool isQObject(const QString &qualifiedName); bool isEnum(const QStringList &qualifiedName); - void fixQObjectForScope(TypeDatabase *types, - NamespaceModelItem item); + void fixQObjectForScope(TypeDatabase* types, NamespaceModelItem item); // QtScript QSet<QString> qtMetaTypeDeclaredTypeNames() const @@ -169,6 +171,13 @@ public: return m_qmetatypeDeclaredTypenames; } + /** + * AbstractMetaBuilder should know what's the global header being used, + * so any class declared under this header wont have the include file + * filled. + */ + void setGlobalHeader(const QString& globalHeader); + protected: AbstractMetaClass *argumentToClass(ArgumentModelItem); @@ -212,6 +221,7 @@ protected: private: void sortLists(); AbstractMetaArgumentList reverseList(const AbstractMetaArgumentList& list); + void setInclude(TypeEntry* te, const QString& fileName) const; AbstractMetaClassList m_metaClasses; AbstractMetaClassList m_templates; @@ -241,6 +251,7 @@ private: QSet<QString> m_qmetatypeDeclaredTypenames; QString m_logDirectory; + QFileInfo m_globalHeader; }; #endif // ABSTRACTMETBUILDER_H diff --git a/abstractmetalang.cpp b/abstractmetalang.cpp index b800696ca..cc9d7715a 100644 --- a/abstractmetalang.cpp +++ b/abstractmetalang.cpp @@ -23,6 +23,7 @@ #include "abstractmetalang.h" #include "reporthandler.h" +#include "typedatabase.h" /******************************************************************************* * AbstractMetaType diff --git a/abstractmetalang.h b/abstractmetalang.h index 512553d04..e4a81e810 100644 --- a/abstractmetalang.h +++ b/abstractmetalang.h @@ -274,18 +274,6 @@ public: return m_originalAttributes & Friendly; } - // valid only for global components - // (e.g.: functions, enums, flags) - QString includeFile() const - { - return m_includeFile; - } - - void setIncludeFile(const QString& file) - { - m_includeFile = file; - } - void setDocumentation(const Documentation& doc) { m_doc = doc; @@ -299,7 +287,6 @@ public: private: uint m_attributes; uint m_originalAttributes; - QString m_includeFile; Documentation m_doc; }; @@ -771,7 +758,8 @@ public: }; AbstractMetaFunction() - : m_functionType(NormalFunction), + : m_typeEntry(0), + m_functionType(NormalFunction), m_type(0), m_class(0), m_implementingClass(0), @@ -1102,12 +1090,22 @@ public: return m_propertySpec; } + FunctionTypeEntry* typeEntry() const + { + return m_typeEntry; + } + + void setTypeEntry(FunctionTypeEntry* typeEntry) + { + m_typeEntry = typeEntry; + } private: QString m_name; QString m_originalName; mutable QString m_cachedMinimalSignature; mutable QString m_cachedModifiedName; + FunctionTypeEntry* m_typeEntry; FunctionType m_functionType; AbstractMetaType *m_type; const AbstractMetaClass *m_class; diff --git a/apiextractor.cpp b/apiextractor.cpp index 38acf46e8..00734de8d 100644 --- a/apiextractor.cpp +++ b/apiextractor.cpp @@ -33,6 +33,7 @@ #include "parser/rpp/pp.h" #include "abstractmetabuilder.h" #include "apiextractorversion.h" +#include "typedatabase.h" static bool preprocess(const QString& sourceFile, QFile& targetFile, @@ -165,6 +166,7 @@ bool ApiExtractor::run() ppFile.seek(0); m_builder = new AbstractMetaBuilder; m_builder->setLogDirectory(m_logDirectory); + m_builder->setGlobalHeader(m_cppFileName); m_builder->build(&ppFile); return true; diff --git a/doc/typesystem_specifying_types.rst b/doc/typesystem_specifying_types.rst index 21392c68a..cd65c4b5b 100644 --- a/doc/typesystem_specifying_types.rst +++ b/doc/typesystem_specifying_types.rst @@ -60,8 +60,7 @@ rejection *optional* **function-name** or **field-name** attributes to reject a particular function or field. Note that the **field-name** and **function-name** cannot be specified at the same time. To remove all occurrences of a given field or - function, set the class attribute to \*. You can use an empty class field - to denote a global function. + function, set the class attribute to \*. .. _primitive-type: @@ -254,4 +253,20 @@ container-type container. It can be: *list*, *string-list*, *linked-list*, *vector*, *stack*, *queue*, *set*, *map*, *multi-map*, *hash*, *multi-hash* or *pair*. +.. _function: +function +^^^^^^^^ + + The function node indicates that the given C++ global function is mapped onto + the target language. + + .. code-block:: xml + + <typesystem> + <function signature="..." /> + </typesystem> + + This tag has some limitations, it doesn't support function modifications, besides you + can't add a function overload using :ref:`add-function` tag to an existent function. + These limitation will be addressed in future versions of ApiExtractor. @@ -124,7 +124,7 @@ void Graph::dumpDot(const QHash< int, QString >& nodeNames, const QString& fileN for (int i = 0; i < m_d->edges.size(); ++i) { GraphPrivate::EdgeIterator it = m_d->edges[i].begin(); for (;it != m_d->edges[i].end(); ++it) - s << nodeNames[i] << " -> " << nodeNames[*it] << '\n'; + s << '"' << nodeNames[i] << "\" -> \"" << nodeNames[*it] << "\"\n"; } s << "}\n"; } diff --git a/include.cpp b/include.cpp new file mode 100644 index 000000000..4d4787d03 --- /dev/null +++ b/include.cpp @@ -0,0 +1,49 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "include.h" +#include <QTextStream> +#include <QHash> + +QString Include::toString() const +{ + if (m_type == IncludePath) + return "#include <" + m_name + '>'; + else if (m_type == LocalPath) + return "#include \"" + m_name + "\""; + else + return "import " + m_name + ";"; +} + +uint qHash(const Include& inc) +{ + return qHash(inc.m_name); +} + +QTextStream& operator<<(QTextStream& out, const Include& include) +{ + if (include.isValid()) + out << include.toString() << endl; + return out; +} + diff --git a/include.h b/include.h new file mode 100644 index 000000000..94e6ced88 --- /dev/null +++ b/include.h @@ -0,0 +1,83 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef INCLUDE_H +#define INCLUDE_H + +#include "apiextractormacros.h" +#include <QString> +#include <QList> + +class QTextStream; + +class APIEXTRACTOR_API Include +{ +public: + enum IncludeType { + IncludePath, + LocalPath, + TargetLangImport + }; + + Include() : m_type(IncludePath) {} + Include(IncludeType t, const QString &nam) : m_type(t), m_name(nam) {}; + + bool isValid() const + { + return !m_name.isEmpty(); + } + + IncludeType type() const + { + return m_type; + } + + QString name() const + { + return m_name; + } + + QString toString() const; + + bool operator<(const Include& other) const + { + return m_name < other.m_name; + } + + bool operator==(const Include& other) const + { + return m_type == other.m_type && m_name == other.m_name; + } + + friend uint qHash(const Include&); + private: + IncludeType m_type; + QString m_name; +}; + +APIEXTRACTOR_API uint qHash(const Include& inc); +APIEXTRACTOR_API QTextStream& operator<<(QTextStream& out, const Include& include); + +typedef QList<Include> IncludeList; + +#endif diff --git a/parser/codemodel.cpp b/parser/codemodel.cpp index ecc8e3036..861a6708c 100644 --- a/parser/codemodel.cpp +++ b/parser/codemodel.cpp @@ -24,6 +24,7 @@ #include "codemodel.h" +#include <algorithm> // --------------------------------------------------------------------------- CodeModel::CodeModel() @@ -371,7 +372,10 @@ FunctionModelItem _ScopeModelItem::declaredFunction(FunctionModelItem item) ClassList _ScopeModelItem::classes() const { - return _M_classes.values(); + ClassList result = _M_classes.values(); + ClassList::iterator it = std::unique(result.begin(), result.end()); + result.erase(it, result.end()); + return result; } TypeAliasList _ScopeModelItem::typeAliases() const diff --git a/reporthandler.cpp b/reporthandler.cpp index fd41983c5..4b0128930 100644 --- a/reporthandler.cpp +++ b/reporthandler.cpp @@ -23,6 +23,7 @@ #include "reporthandler.h" #include "typesystem.h" +#include "typedatabase.h" #include <QtCore/QSet> #include <cstring> #include <cstdarg> diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b4e1fcaec..eaaaf482f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,3 +25,4 @@ declare_test(testreferencetopointer) declare_test(testremoveimplconv) declare_test(testreverseoperators) declare_test(testtoposort) +declare_test(testfunctiontag) diff --git a/tests/testabstractmetatype.cpp b/tests/testabstractmetatype.cpp index 3e75539fb..81e194fd3 100644 --- a/tests/testabstractmetatype.cpp +++ b/tests/testabstractmetatype.cpp @@ -30,6 +30,7 @@ void TestAbstractMetaType::testConstCharPtrType() const char* cppCode ="const char* justAtest();"; const char* xmlCode = "<typesystem package=\"Foo\">\ <primitive-type name='char'/>\ + <function signature='justAtest()' />\ </typesystem>"; TestUtil t(cppCode, xmlCode); QCOMPARE(t.builder()->globalFunctions().size(), 1); @@ -57,6 +58,7 @@ void TestAbstractMetaType::testCharType() const char* xmlCode = "<typesystem package=\"Foo\">\ <primitive-type name='char'/>\ <value-type name='A' />\ + <function signature='justAtest()' />\ </typesystem>"; TestUtil t(cppCode, xmlCode); @@ -118,6 +120,7 @@ void TestAbstractMetaType::testTypedefWithTemplates() const char* xmlCode = "<typesystem package=\"Foo\">\ <container-type name='A' type='list'/>\ <value-type name='B' />\ + <function signature='func(A<B>)' />\ </typesystem>"; TestUtil t(cppCode, xmlCode); diff --git a/tests/testenum.cpp b/tests/testenum.cpp index 93a678e73..24cb4d963 100644 --- a/tests/testenum.cpp +++ b/tests/testenum.cpp @@ -41,12 +41,13 @@ void TestEnum::testEnumCppSignature() <value-type name='A'/> \ <enum-type name='GlobalEnum' />\ <enum-type name='A::ClassEnum' />\ + <function signature='func(A::ClassEnum)' />\ </typesystem>"; TestUtil t(cppCode, xmlCode); AbstractMetaClassList classes = t.builder()->classes(); QCOMPARE(classes.count(), 1); - + AbstractMetaEnumList globalEnums = t.builder()->globalEnums(); QCOMPARE(globalEnums.count(), 1); QCOMPARE(globalEnums.first()->name(), QString("GlobalEnum")); @@ -56,7 +57,7 @@ void TestEnum::testEnumCppSignature() QCOMPARE(functions.count(), 1); QCOMPARE(functions.first()->arguments().count(), 1); QCOMPARE(functions.first()->arguments().first()->type()->cppSignature(), QString("A::ClassEnum")); - + // enum as parameter of a method AbstractMetaClass* classA = classes.findClass("A"); QCOMPARE(classA->enums().count(), 1); @@ -72,8 +73,6 @@ void TestEnum::testEnumCppSignature() AbstractMetaEnumList classEnums = classA->enums(); QCOMPARE(classEnums.first()->name(), QString("ClassEnum")); - - } QTEST_APPLESS_MAIN(TestEnum) diff --git a/tests/testfunctiontag.cpp b/tests/testfunctiontag.cpp new file mode 100644 index 000000000..79e3142a5 --- /dev/null +++ b/tests/testfunctiontag.cpp @@ -0,0 +1,64 @@ +/* +* This file is part of the API Extractor project. +* +* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +* +* Contact: PySide team <contact@pyside.org> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA +* +*/ + +#include "testfunctiontag.h" +#include <QtTest/QTest> +#include "testutil.h" + +void TestFunctionTag::testFunctionTagForSpecificSignature() +{ + const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy()"; + const char xmlCode[] = "\ + <typesystem package=\"Foo\">\ + <primitive-type name='int'/> \ + <primitive-type name='float'/> \ + <function signature='globalFunction(int)'/>\ + </typesystem>"; + TestUtil t(cppCode, xmlCode, false); + + FunctionTypeEntry* func = (FunctionTypeEntry*) TypeDatabase::instance()->findType("globalFunction"); + QVERIFY(func); + QCOMPARE(t.builder()->globalFunctions().size(), 1); +} + +void TestFunctionTag::testFunctionTagForAllSignatures() +{ + const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy();"; + const char xmlCode[] = "\ + <typesystem package=\"Foo\">\ + <primitive-type name='int'/> \ + <primitive-type name='float'/> \ + <function signature='globalFunction(int)'/>\ + <function signature='globalFunction(float)'/>\ + </typesystem>"; + TestUtil t(cppCode, xmlCode, false); + + FunctionTypeEntry* func = (FunctionTypeEntry*) TypeDatabase::instance()->findType("globalFunction"); + QVERIFY(func); + QCOMPARE(t.builder()->globalFunctions().size(), 2); +} + +QTEST_APPLESS_MAIN(TestFunctionTag) + +#include "testfunctiontag.moc" + diff --git a/tests/testfunctiontag.h b/tests/testfunctiontag.h new file mode 100644 index 000000000..8f42774c6 --- /dev/null +++ b/tests/testfunctiontag.h @@ -0,0 +1,36 @@ +/* +* This file is part of the API Extractor project. +* +* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +* +* Contact: PySide team <contact@pyside.org> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA +* +*/ + +#ifndef TESTFUNCTIONTAG_H +#define TESTFUNCTIONTAG_H +#include <QObject> + +class TestFunctionTag : public QObject +{ + Q_OBJECT +private slots: + void testFunctionTagForSpecificSignature(); + void testFunctionTagForAllSignatures(); +}; + +#endif diff --git a/tests/testutil.h b/tests/testutil.h index b4124e4c3..1aed98349 100644 --- a/tests/testutil.h +++ b/tests/testutil.h @@ -26,6 +26,7 @@ #include <QtCore/QBuffer> #include "abstractmetabuilder.h" #include "reporthandler.h" +#include "typedatabase.h" class TestUtil { diff --git a/typedatabase.cpp b/typedatabase.cpp new file mode 100644 index 000000000..ea009eb32 --- /dev/null +++ b/typedatabase.cpp @@ -0,0 +1,386 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "typedatabase.h" +#include "typesystem.h" +#include "typesystem_p.h" + +#include <QFile> +#include <QXmlInputSource> +#include "reporthandler.h" + +TypeDatabase::TypeDatabase() : m_suppressWarnings(true) +{ + addType(new VoidTypeEntry()); + addType(new VarargsTypeEntry()); +} + +TypeDatabase* TypeDatabase::instance(bool newInstance) +{ + static TypeDatabase* db = 0; + if (!db || newInstance) { + if (db) + delete db; + db = new TypeDatabase; + } + return db; +} + +QString TypeDatabase::normalizedSignature(const char* signature) +{ + QString normalized = QMetaObject::normalizedSignature(signature); + + if (!instance() || !QString(signature).contains("unsigned")) + return normalized; + + QStringList types; + types << "char" << "short" << "int" << "long"; + foreach (const QString& type, types) { + if (instance()->findType(QString("u%1").arg(type))) + continue; + normalized.replace(QRegExp(QString("\\bu%1\\b").arg(type)), QString("unsigned %1").arg(type)); + } + + return normalized; +} + +QStringList TypeDatabase::requiredTargetImports() const +{ + return m_requiredTargetImports; +} + +void TypeDatabase::addRequiredTargetImport(const QString& moduleName) +{ + if (!m_requiredTargetImports.contains(moduleName)) + m_requiredTargetImports << moduleName; +} + +void TypeDatabase::addTypesystemPath(const QString& typesystem_paths) +{ + #if defined(Q_OS_WIN32) + char* path_splitter = const_cast<char*>(";"); + #else + char* path_splitter = const_cast<char*>(":"); + #endif + m_typesystemPaths += typesystem_paths.split(path_splitter); +} + +IncludeList TypeDatabase::extraIncludes(const QString& className) const +{ + ComplexTypeEntry* typeEntry = findComplexType(className); + if (typeEntry) + return typeEntry->extraIncludes(); + else + return IncludeList(); +} + +ContainerTypeEntry* TypeDatabase::findContainerType(const QString &name) const +{ + 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; +} + +FunctionTypeEntry* TypeDatabase::findFunctionType(const QString& name) const +{ + TypeEntry* entry = findType(name); + if (entry && entry->type() == TypeEntry::FunctionType) + return static_cast<FunctionTypeEntry*>(entry); + return 0; +} + + +PrimitiveTypeEntry* TypeDatabase::findTargetLangPrimitiveType(const QString& targetLangName) const +{ + foreach (QList<TypeEntry*> entries, m_entries.values()) { + foreach (TypeEntry* e, entries) { + if (e && e->isPrimitive()) { + PrimitiveTypeEntry *pe = static_cast<PrimitiveTypeEntry*>(e); + if (pe->targetLangName() == targetLangName && pe->preferredConversion()) + return pe; + } + } + } + + return 0; +} + +TypeEntry* TypeDatabase::findType(const QString& name) const +{ + QList<TypeEntry *> entries = findTypes(name); + foreach (TypeEntry *entry, entries) { + if (entry && + (!entry->isPrimitive() || static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())) { + return entry; + } + } + return 0; +} + +SingleTypeEntryHash TypeDatabase::entries() const +{ + TypeEntryHash entries = allEntries(); + + SingleTypeEntryHash returned; + QList<QString> keys = entries.keys(); + + foreach (QString key, keys) + returned[key] = findType(key); + + return returned; +} + +QList<const PrimitiveTypeEntry*> TypeDatabase::primitiveTypes() const +{ + TypeEntryHash entries = allEntries(); + QList<const PrimitiveTypeEntry*> returned; + foreach(QString key, entries.keys()) { + foreach(const TypeEntry* typeEntry, entries[key]) { + if (typeEntry->isPrimitive()) + returned.append((PrimitiveTypeEntry*) typeEntry); + } + } + return returned; +} + +QList<const ContainerTypeEntry*> TypeDatabase::containerTypes() const +{ + TypeEntryHash entries = allEntries(); + QList<const ContainerTypeEntry*> returned; + foreach(QString key, entries.keys()) { + foreach(const TypeEntry* typeEntry, entries[key]) { + if (typeEntry->isContainer()) + returned.append((ContainerTypeEntry*) typeEntry); + } + } + return returned; +} +void TypeDatabase::addRejection(const QString& className, const QString& functionName, + const QString& fieldName, const QString& enumName) +{ + TypeRejection r; + r.class_name = className; + r.function_name = functionName; + r.field_name = fieldName; + r.enum_name = enumName; + + m_rejections << r; +} + +bool TypeDatabase::isClassRejected(const QString& className) const +{ + if (!m_rebuildClasses.isEmpty()) + return !m_rebuildClasses.contains(className); + + foreach (const TypeRejection& r, m_rejections) + if (r.class_name == className && r.function_name == "*" && r.field_name == "*" && r.enum_name == "*") + return true; + + return false; +} + +bool TypeDatabase::isEnumRejected(const QString& className, const QString& enumName) const +{ + foreach (const TypeRejection& r, m_rejections) { + if (r.enum_name == enumName + && (r.class_name == className || r.class_name == "*")) { + return true; + } + } + + return false; +} + +bool TypeDatabase::isFunctionRejected(const QString& className, const QString& functionName) const +{ + foreach (const TypeRejection& r, m_rejections) + if (r.function_name == functionName && + (r.class_name == className || r.class_name == "*")) + return true; + return false; +} + + +bool TypeDatabase::isFieldRejected(const QString& className, const QString& fieldName) const +{ + foreach (const TypeRejection& r, m_rejections) + if (r.field_name == fieldName && + (r.class_name == className || r.class_name == "*")) + return true; + return false; +} + +FlagsTypeEntry* TypeDatabase::findFlagsType(const QString &name) const +{ + FlagsTypeEntry* fte = (FlagsTypeEntry*) findType(name); + return fte ? fte : (FlagsTypeEntry*) m_flagsEntries.value(name); +} + +AddedFunctionList TypeDatabase::findGlobalUserFunctions(const QString& name) const +{ + AddedFunctionList addedFunctions; + foreach (AddedFunction func, m_globalUserFunctions) { + if (func.name() == name) + addedFunctions.append(func); + } + return addedFunctions; +} + + +QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/) +{ + return QLatin1String("Global"); +} + +FunctionModificationList TypeDatabase::functionModifications(const QString& signature) const +{ + FunctionModificationList lst; + for (int i = 0; i < m_functionMods.count(); ++i) { + const FunctionModification& mod = m_functionMods.at(i); + if (mod.signature == signature) + lst << mod; + } + + return lst; +} + +bool TypeDatabase::isSuppressedWarning(const QString& s) const +{ + 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()) + 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; +} + +QString TypeDatabase::modifiedTypesystemFilepath(const QString& tsFile) const +{ + if (!QFile::exists(tsFile)) { + int idx = tsFile.lastIndexOf('/'); + QString fileName = idx >= 0 ? tsFile.right(tsFile.length() - idx - 1) : tsFile; + foreach (const QString &path, m_typesystemPaths) { + QString filepath(path + '/' + fileName); + if (QFile::exists(filepath)) + return filepath; + } + } + return tsFile; +} + +bool TypeDatabase::parseFile(const QString &filename, bool generate) +{ + QString filepath = modifiedTypesystemFilepath(filename); + if (m_parsedTypesystemFiles.contains(filepath)) + return m_parsedTypesystemFiles[filepath]; + + QFile file(filepath); + if (!file.exists()) { + ReportHandler::warning("Can't find " + filename+", typesystem paths: "+m_typesystemPaths.join(", ")); + return false; + } + + int count = m_entries.size(); + bool ok = parseFile(&file, generate); + m_parsedTypesystemFiles[filepath] = ok; + int newCount = m_entries.size(); + + ReportHandler::debugSparse(QString::fromLatin1("Parsed: '%1', %2 new entries") + .arg(filename) + .arg(newCount - count)); + return ok; +} + +bool TypeDatabase::parseFile(QIODevice* device, bool generate) +{ + QXmlInputSource source(device); + QXmlSimpleReader reader; + Handler handler(this, generate); + + reader.setContentHandler(&handler); + reader.setErrorHandler(&handler); + + return reader.parse(&source, false); +} + +PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString& name) const +{ + QList<TypeEntry*> entries = findTypes(name); + + foreach (TypeEntry* entry, entries) { + if (entry && entry->isPrimitive() && static_cast<PrimitiveTypeEntry*>(entry)->preferredTargetLangType()) + return static_cast<PrimitiveTypeEntry*>(entry); + } + + return 0; +} + +ComplexTypeEntry* TypeDatabase::findComplexType(const QString& name) const +{ + TypeEntry* entry = findType(name); + if (entry && entry->isComplex()) + return static_cast<ComplexTypeEntry*>(entry); + else + return 0; +} + +ObjectTypeEntry* TypeDatabase::findObjectType(const QString& name) const +{ + TypeEntry* entry = findType(name); + if (entry && entry->isObject()) + return static_cast<ObjectTypeEntry*>(entry); + else + return 0; +} + +NamespaceTypeEntry* TypeDatabase::findNamespaceType(const QString& name) const +{ + TypeEntry* entry = findType(name); + if (entry && entry->isNamespace()) + return static_cast<NamespaceTypeEntry*>(entry); + else + return 0; +} + diff --git a/typedatabase.h b/typedatabase.h new file mode 100644 index 000000000..10be28d15 --- /dev/null +++ b/typedatabase.h @@ -0,0 +1,190 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef TYPEDATABASE_H +#define TYPEDATABASE_H + +#include <QStringList> +#include "typesystem.h" + +class ContainerTypeEntry; +class PrimitiveTypeEntry; +class APIEXTRACTOR_API TypeDatabase +{ + TypeDatabase(); + TypeDatabase(const TypeDatabase&); + TypeDatabase& operator=(const TypeDatabase&); +public: + + /** + * Return the type system instance. + * \param newInstance This parameter is usefull just for unit testing, because singletons causes + * too many side effects on unit testing. + */ + static TypeDatabase* instance(bool newInstance = false); + + static QString normalizedSignature(const char* signature); + + QStringList requiredTargetImports() const; + + void addRequiredTargetImport(const QString& moduleName); + + QStringList typesystemPaths() const + { + return m_typesystemPaths; + } + + void addTypesystemPath(const QString& typesystem_paths); + + IncludeList extraIncludes(const QString& className) const; + + PrimitiveTypeEntry* findPrimitiveType(const QString& name) const; + ComplexTypeEntry* findComplexType(const QString& name) const; + ObjectTypeEntry* findObjectType(const QString& name) const; + NamespaceTypeEntry* findNamespaceType(const QString& name) const; + ContainerTypeEntry* findContainerType(const QString& name) const; + FunctionTypeEntry* findFunctionType(const QString& name) const; + + TypeEntry* findType(const QString& name) const; + + QList<TypeEntry *> findTypes(const QString &name) const + { + return m_entries.value(name); + } + + TypeEntryHash allEntries() const + { + return m_entries; + } + + SingleTypeEntryHash entries() const; + + PrimitiveTypeEntry* findTargetLangPrimitiveType(const QString& targetLangName) const; + + QList<const PrimitiveTypeEntry*> primitiveTypes() const; + + QList<const ContainerTypeEntry*> containerTypes() const; + + void addRejection(const QString& className, const QString& functionName, + const QString& fieldName, const QString& enumName); + bool isClassRejected(const QString& className) const; + bool isFunctionRejected(const QString& className, const QString& functionName) const; + bool isFieldRejected(const QString& className, const QString& fieldName) const; + bool isEnumRejected(const QString& className, const QString& enumName) const; + + void addType(TypeEntry* e) + { + m_entries[e->qualifiedCppName()].append(e); + } + + SingleTypeEntryHash flagsEntries() const + { + return m_flagsEntries; + } + FlagsTypeEntry* findFlagsType(const QString& name) const; + void addFlagsType(FlagsTypeEntry* fte) + { + m_flagsEntries[fte->originalName()] = fte; + } + + TemplateEntry* findTemplate(const QString& name) const + { + return m_templates[name]; + } + + void addTemplate(TemplateEntry* t) + { + m_templates[t->name()] = t; + } + + AddedFunctionList globalUserFunctions() const + { + return m_globalUserFunctions; + } + + void addGlobalUserFunctions(const AddedFunctionList& functions) + { + m_globalUserFunctions << functions; + } + + AddedFunctionList findGlobalUserFunctions(const QString& name) const; + + void addGlobalUserFunctionModifications(const FunctionModificationList& functionModifications) + { + m_functionMods << functionModifications; + } + + void addGlobalUserFunctionModification(const FunctionModification& functionModification) + { + m_functionMods << functionModification; + } + + FunctionModificationList functionModifications(const QString& signature) const; + + void setSuppressWarnings(bool on) + { + m_suppressWarnings = on; + } + + void addSuppressedWarning(const QString& s) + { + m_suppressedWarnings.append(s); + } + + bool isSuppressedWarning(const QString& s) const; + + void setRebuildClasses(const QStringList &cls) + { + m_rebuildClasses = cls; + } + + static QString globalNamespaceClassName(const TypeEntry *te); + QString filename() const + { + return "typesystem.txt"; + } + + QString modifiedTypesystemFilepath(const QString& tsFile) const; + bool parseFile(const QString &filename, bool generate = true); + bool parseFile(QIODevice* device, bool generate = true); + +private: + bool m_suppressWarnings; + TypeEntryHash m_entries; + SingleTypeEntryHash m_flagsEntries; + TemplateEntryHash m_templates; + QStringList m_suppressedWarnings; + + AddedFunctionList m_globalUserFunctions; + FunctionModificationList m_functionMods; + + QStringList m_requiredTargetImports; + + QStringList m_typesystemPaths; + QHash<QString, bool> m_parsedTypesystemFiles; + + QList<TypeRejection> m_rejections; + QStringList m_rebuildClasses; +}; + +#endif diff --git a/typesystem.cpp b/typesystem.cpp index 837a0e0d0..267777564 100644 --- a/typesystem.cpp +++ b/typesystem.cpp @@ -22,6 +22,8 @@ */ #include "typesystem.h" +#include "typesystem_p.h" +#include "typedatabase.h" #include "reporthandler.h" #include <QtXml> @@ -31,177 +33,53 @@ static QString strings_char = QLatin1String("char"); static QString strings_jchar = QLatin1String("jchar"); static QString strings_jobject = QLatin1String("jobject"); -class StackElement -{ -public: - enum ElementType { - None = 0x0, - - // Type tags (0x1, ... , 0xff) - ObjectTypeEntry = 0x1, - ValueTypeEntry = 0x2, - InterfaceTypeEntry = 0x3, - NamespaceTypeEntry = 0x4, - ComplexTypeEntryMask = 0x7, - - // Non-complex type tags (0x8, 0x9, ... , 0xf) - PrimitiveTypeEntry = 0x8, - EnumTypeEntry = 0x9, - ContainerTypeEntry = 0xa, - TypeEntryMask = 0xf, - - // Documentation tags - InjectDocumentation = 0x10, - ModifyDocumentation = 0x20, - DocumentationMask = 0xf0, - - // Simple tags (0x100, 0x200, ... , 0xf00) - ExtraIncludes = 0x0100, - Include = 0x0200, - ModifyFunction = 0x0300, - ModifyField = 0x0400, - Root = 0x0500, - CustomMetaConstructor = 0x0600, - CustomMetaDestructor = 0x0700, - ArgumentMap = 0x0800, - SuppressedWarning = 0x0900, - Rejection = 0x0a00, - LoadTypesystem = 0x0b00, - RejectEnumValue = 0x0c00, - Template = 0x0d00, - TemplateInstanceEnum = 0x0e00, - Replace = 0x0f00, - AddFunction = 0x1000, - SimpleMask = 0x3f00, - - // Code snip tags (0x1000, 0x2000, ... , 0xf000) - InjectCode = 0x4000, - InjectCodeInFunction = 0x8000, - CodeSnipMask = 0xc000, - - // Function modifier tags (0x010000, 0x020000, ... , 0xf00000) - Access = 0x010000, - Removal = 0x020000, - Rename = 0x040000, - ModifyArgument = 0x080000, - Thread = 0x100000, - FunctionModifiers = 0xff0000, - - // Argument modifier tags (0x01000000 ... 0xf0000000) - ConversionRule = 0x01000000, - ReplaceType = 0x02000000, - ReplaceDefaultExpression = 0x04000000, - RemoveArgument = 0x08000000, - DefineOwnership = 0x10000000, - RemoveDefaultExpression = 0x20000000, - NoNullPointers = 0x40000000, - ReferenceCount = 0x80000000, - ParentOwner = 0x90000000, - 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) +Handler::Handler(TypeDatabase* database, bool generate) : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass) - { - m_currentEnum = 0; - m_current = 0; - - tagNames["rejection"] = StackElement::Rejection; - tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry; - tagNames["container-type"] = StackElement::ContainerTypeEntry; - 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; - tagNames["parent"] = StackElement::ParentOwner; - tagNames["inject-documentation"] = StackElement::InjectDocumentation; - tagNames["modify-documentation"] = StackElement::ModifyDocumentation; - tagNames["add-function"] = StackElement::AddFunction; - } - - 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* m_current; - QString m_defaultPackage; - QString m_defaultSuperclass; - QString m_error; - TypeEntry::CodeGeneration m_generate; - - EnumTypeEntry *m_currentEnum; - - CodeSnipList m_codeSnips; - AddedFunctionList m_addedFunctions; - FunctionModificationList m_functionMods; - FieldModificationList m_fieldMods; - DocModificationList m_docModifications; - - QHash<QString, StackElement::ElementType> tagNames; - QString m_currentSignature; -}; +{ + m_currentEnum = 0; + m_current = 0; + + tagNames["rejection"] = StackElement::Rejection; + tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry; + tagNames["container-type"] = StackElement::ContainerTypeEntry; + 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["function"] = StackElement::FunctionTypeEntry; + 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; + tagNames["parent"] = StackElement::ParentOwner; + tagNames["inject-documentation"] = StackElement::InjectDocumentation; + tagNames["modify-documentation"] = StackElement::ModifyDocumentation; + tagNames["add-function"] = StackElement::AddFunction; +} bool Handler::error(const QXmlParseException &e) { @@ -519,6 +397,9 @@ bool Handler::startElement(const QString &, const QString &n, attributes["target-type"] = QString(); attributes["generic-class"] = QString("no"); break; + case StackElement::FunctionTypeEntry: + attributes["signature"] = QString(); + break; default: { } // nada }; @@ -526,11 +407,18 @@ bool Handler::startElement(const QString &, const QString &n, fetchAttributeValues(tagName, atts, &attributes); QString name = attributes["name"]; + // The top level tag 'function' has only the 'signature' tag + // and we should extract the 'name' value from it. + if (element->type == StackElement::FunctionTypeEntry) { + QString signature = attributes["signature"]; + name = signature.left(signature.indexOf('(')).trimmed(); + } // We need to be able to have duplicate primitive type entries, // or it's not possible to cover all primitive target language // types (which we need to do in order to support fake meta objects) - if (element->type != StackElement::PrimitiveTypeEntry) { + if (element->type != StackElement::PrimitiveTypeEntry + && element->type != StackElement::FunctionTypeEntry) { TypeEntry *tmp = m_database->findType(name); if (tmp) ReportHandler::warning(QString("Duplicate type entry: '%1'").arg(name)); @@ -728,6 +616,22 @@ bool Handler::startElement(const QString &, const QString &n, } break; + case StackElement::FunctionTypeEntry: { + QString signature = attributes["signature"]; + signature = TypeDatabase::normalizedSignature(signature.toLatin1().constData()); + element->entry = m_database->findType(name); + if (element->entry) { + if (element->entry->type() == TypeEntry::FunctionType) { + reinterpret_cast<FunctionTypeEntry*>(element->entry)->addSignature(signature); + } else { + m_error = QString("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.").arg(name); + return false; + } + } else { + element->entry = new FunctionTypeEntry(name, signature); + } + } + break; default: Q_ASSERT(false); }; @@ -1654,94 +1558,6 @@ bool Handler::startElement(const QString &, const QString &n, return true; } -TypeDatabase *TypeDatabase::instance(bool newInstance) -{ - static TypeDatabase *db = 0; - if (!db || newInstance) { - if (db) - delete db; - db = new TypeDatabase; - } - return db; -} - -QString TypeDatabase::normalizedSignature(const char* signature) -{ - QString normalized = QMetaObject::normalizedSignature(signature); - - if (!instance() || !QString(signature).contains("unsigned")) - return normalized; - - QStringList types; - types << "char" << "short" << "int" << "long"; - foreach (const QString& type, types) { - if (instance()->findType(QString("u%1").arg(type))) - continue; - normalized.replace(QRegExp(QString("\\bu%1\\b").arg(type)), QString("unsigned %1").arg(type)); - } - - return normalized; -} - -TypeDatabase::TypeDatabase() : m_suppressWarnings(true) -{ - StringTypeEntry* e = new StringTypeEntry("QXmlStreamStringRef"); - e->setPreferredConversion(false); - addType(e); - - addType(new VoidTypeEntry()); - addType(new VarargsTypeEntry()); -} - -QString TypeDatabase::modifiedTypesystemFilepath(const QString &ts_file) -{ - if (!QFile::exists(ts_file)) { - int idx = ts_file.lastIndexOf('/'); - QString fileName = idx >= 0 ? ts_file.right(ts_file.length() - idx - 1) : ts_file; - foreach (const QString &path, m_typesystemPaths) { - QString filepath(path + '/' + fileName); - if (QFile::exists(filepath)) - return filepath; - } - } - return ts_file; -} - -bool TypeDatabase::parseFile(const QString &filename, bool generate) -{ - QString filepath = modifiedTypesystemFilepath(filename); - if (m_parsedTypesystemFiles.contains(filepath)) - return m_parsedTypesystemFiles[filepath]; - - QFile file(filepath); - if (!file.exists()) { - ReportHandler::warning("Can't find " + filename+", typesystem paths: "+m_typesystemPaths.join(", ")); - return false; - } - - int count = m_entries.size(); - bool ok = parseFile(&file, generate); - m_parsedTypesystemFiles[filepath] = ok; - int newCount = m_entries.size(); - - ReportHandler::debugSparse(QString::fromLatin1("Parsed: '%1', %2 new entries") - .arg(filename) - .arg(newCount - count)); - return ok; -} - -bool TypeDatabase::parseFile(QIODevice* device, bool generate) -{ - QXmlInputSource source(device); - QXmlSimpleReader reader; - Handler handler(this, generate); - - reader.setContentHandler(&handler); - reader.setErrorHandler(&handler); - - return reader.parse(&source, false); -} - PrimitiveTypeEntry* PrimitiveTypeEntry::basicAliasedTypeEntry() const { if (!m_aliasedTypeEntry) @@ -1754,56 +1570,6 @@ PrimitiveTypeEntry* PrimitiveTypeEntry::basicAliasedTypeEntry() const return m_aliasedTypeEntry; } -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 &targetLangName) -{ - foreach (QList<TypeEntry *> entries, m_entries.values()) { - foreach (TypeEntry *e, entries) { - if (e && e->isPrimitive()) { - PrimitiveTypeEntry *pe = static_cast<PrimitiveTypeEntry *>(e); - if (pe->targetLangName() == targetLangName && pe->preferredConversion()) - return pe; - } - } - } - - return 0; -} - -IncludeList TypeDatabase::extraIncludes(const QString &className) -{ - ComplexTypeEntry *typeEntry = findComplexType(className); - if (typeEntry) - 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"; @@ -1908,97 +1674,6 @@ QString FlagsTypeEntry::qualifiedTargetLangName() const return targetLangPackage() + "." + m_enum->targetLangQualifier() + "." + 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_rebuildClasses.isEmpty()) - return !m_rebuildClasses.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_flagsEntries.value(name); -} - -AddedFunctionList TypeDatabase::findGlobalUserFunctions(const QString& name) const -{ - AddedFunctionList addedFunctions; - foreach (AddedFunction func, m_globalUserFunctions) { - if (func.name() == name) - addedFunctions.append(func); - } - return addedFunctions; -} - - -QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/) -{ - return QLatin1String("Global"); -} - -FunctionModificationList TypeDatabase::functionModifications(const QString& signature) const -{ - FunctionModificationList lst; - for (int i = 0; i < m_functionMods.count(); ++i) { - const FunctionModification& mod = m_functionMods.at(i); - if (mod.signature == signature) - lst << mod; - } - - return lst; -} - - /*! * The Visual Studio 2002 compiler doesn't support these symbols, * which our typedefs unforntuatly expand to. diff --git a/typesystem.h b/typesystem.h index be2852bd9..dc7ebc0a7 100644 --- a/typesystem.h +++ b/typesystem.h @@ -30,6 +30,7 @@ #include <QtCore/QMap> #include <QtCore/QDebug> #include "apiextractormacros.h" +#include "include.h" class Indentor; @@ -39,34 +40,6 @@ class QTextStream; class EnumTypeEntry; class FlagsTypeEntry; -struct APIEXTRACTOR_API 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; @@ -610,7 +583,8 @@ public: ArrayType, TypeSystemType, CustomType, - TargetLangType + TargetLangType, + FunctionType }; enum CodeGeneration { @@ -874,9 +848,9 @@ public: } void addExtraInclude(const Include &include) { - if (!m_includesUsed.value(include.name, false)) { + if (!m_includesUsed.value(include.name(), false)) { m_extraIncludes << include; - m_includesUsed[include.name] = true; + m_includesUsed[include.name()] = true; } } @@ -1726,6 +1700,32 @@ private: }; +class APIEXTRACTOR_API FunctionTypeEntry : public TypeEntry +{ +public: + FunctionTypeEntry(const QString& name, const QString& signature) + : TypeEntry(name, FunctionType) + { + addSignature(signature); + } + void addSignature(const QString& signature) + { + m_signatures << signature; + } + + QStringList signatures() const + { + return m_signatures; + } + + bool hasSignature(const QString& signature) const + { + return m_signatures.contains(signature); + } +private: + QStringList m_signatures; +}; + class APIEXTRACTOR_API ObjectTypeEntry : public ComplexTypeEntry { public: @@ -1758,271 +1758,6 @@ struct TypeRejection QString enum_name; }; -class APIEXTRACTOR_API TypeDatabase -{ - TypeDatabase(); - TypeDatabase(const TypeDatabase&); - TypeDatabase& operator=(const TypeDatabase&); -public: - - /** - * Return the type system instance. - * \param newInstance This parameter is usefull just for unit testing, because singletons causes - * too many side effects on unit testing. - */ - static TypeDatabase *instance(bool newInstance = false); - - static QString normalizedSignature(const char* signature); - - QStringList requiredTargetImports() - { - return m_requiredTargetImports; - } - - void addRequiredTargetImport(const QString &moduleName) - { - if (!m_requiredTargetImports.contains(moduleName)) - m_requiredTargetImports << moduleName; - } - - QStringList typesystemPaths() - { - return m_typesystemPaths; - } - void addTypesystemPath(const QString &typesystem_paths) - { -#if defined(Q_OS_WIN32) - char *path_splitter = const_cast<char *>(";"); -#else - char *path_splitter = const_cast<char *>(":"); -#endif - m_typesystemPaths += typesystem_paths.split(path_splitter); - } - - IncludeList 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 && - (!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 &targetLangName); - - QList<const PrimitiveTypeEntry*> primitiveTypes() { - TypeEntryHash entries = allEntries(); - QList<const PrimitiveTypeEntry*> returned; - foreach(QString key, entries.keys()) { - foreach(const TypeEntry* typeEntry, entries[key]) { - if (typeEntry->isPrimitive()) - returned.append((PrimitiveTypeEntry*) typeEntry); - } - } - return returned; - } - QList<const ContainerTypeEntry*> containerTypes() { - TypeEntryHash entries = allEntries(); - QList<const ContainerTypeEntry*> returned; - foreach(QString key, entries.keys()) { - foreach(const TypeEntry* typeEntry, entries[key]) { - if (typeEntry->isContainer()) - returned.append((ContainerTypeEntry*) typeEntry); - } - } - return returned; - } - - 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_flagsEntries; - } - FlagsTypeEntry *findFlagsType(const QString &name) const; - void addFlagsType(FlagsTypeEntry *fte) - { - m_flagsEntries[fte->originalName()] = fte; - } - - TemplateEntry *findTemplate(const QString &name) - { - return m_templates[name]; - } - void addTemplate(TemplateEntry *t) - { - m_templates[t->name()] = t; - } - - AddedFunctionList globalUserFunctions() const - { - return m_globalUserFunctions; - } - void addGlobalUserFunctions(const AddedFunctionList& functions) - { - m_globalUserFunctions << functions; - } - AddedFunctionList findGlobalUserFunctions(const QString& name) const; - - void addGlobalUserFunctionModifications(const FunctionModificationList& functionModifications) - { - m_functionMods << functionModifications; - } - void addGlobalUserFunctionModification(const FunctionModification& functionModification) - { - m_functionMods << functionModification; - } - FunctionModificationList functionModifications(const QString& signature) const; - - 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()) - 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_rebuildClasses = cls; - } - - static QString globalNamespaceClassName(const TypeEntry *te); - QString filename() const - { - return "typesystem.txt"; - } - - QString modifiedTypesystemFilepath(const QString &ts_file); - bool parseFile(const QString &filename, bool generate = true); - bool parseFile(QIODevice* device, bool generate = true); - -private: - bool m_suppressWarnings; - TypeEntryHash m_entries; - SingleTypeEntryHash m_flagsEntries; - TemplateEntryHash m_templates; - QStringList m_suppressedWarnings; - - AddedFunctionList m_globalUserFunctions; - FunctionModificationList m_functionMods; - - QStringList m_requiredTargetImports; - - QStringList m_typesystemPaths; - QHash<QString, bool> m_parsedTypesystemFiles; - - QList<TypeRejection> m_rejections; - QStringList m_rebuildClasses; -}; - -inline PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString &name) -{ - QList<TypeEntry *> entries = findTypes(name); - - foreach (TypeEntry *entry, entries) { - if (entry && 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 && entry->isComplex()) - return static_cast<ComplexTypeEntry *>(entry); - else - return 0; -} - -inline ObjectTypeEntry *TypeDatabase::findObjectType(const QString &name) -{ - TypeEntry *entry = findType(name); - if (entry && entry->isObject()) - return static_cast<ObjectTypeEntry *>(entry); - else - return 0; -} - -inline NamespaceTypeEntry *TypeDatabase::findNamespaceType(const QString &name) -{ - TypeEntry *entry = findType(name); - if (entry && entry->isNamespace()) - return static_cast<NamespaceTypeEntry *>(entry); - else - return 0; -} - QString fixCppTypeName(const QString &name); #endif // TYPESYSTEM_H diff --git a/typesystem_p.h b/typesystem_p.h new file mode 100644 index 000000000..a62056db9 --- /dev/null +++ b/typesystem_p.h @@ -0,0 +1,159 @@ +/* + * This file is part of the API Extractor project. + * + * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#ifndef TYPESYSTEM_P_H +#define TYPESYSTEM_P_H + +#include <QXmlDefaultHandler> +#include "typesystem.h" + +class TypeDatabase; +class StackElement +{ + public: + enum ElementType { + None = 0x0, + + // Type tags (0x1, ... , 0xff) + ObjectTypeEntry = 0x1, + ValueTypeEntry = 0x2, + InterfaceTypeEntry = 0x3, + NamespaceTypeEntry = 0x4, + ComplexTypeEntryMask = 0x7, + + // Non-complex type tags (0x8, 0x9, ... , 0xf) + PrimitiveTypeEntry = 0x8, + EnumTypeEntry = 0x9, + ContainerTypeEntry = 0xa, + FunctionTypeEntry = 0xb, + TypeEntryMask = 0xf, + + // Documentation tags + InjectDocumentation = 0x10, + ModifyDocumentation = 0x20, + DocumentationMask = 0xf0, + + // Simple tags (0x100, 0x200, ... , 0xf00) + ExtraIncludes = 0x0100, + Include = 0x0200, + ModifyFunction = 0x0300, + ModifyField = 0x0400, + Root = 0x0500, + CustomMetaConstructor = 0x0600, + CustomMetaDestructor = 0x0700, + ArgumentMap = 0x0800, + SuppressedWarning = 0x0900, + Rejection = 0x0a00, + LoadTypesystem = 0x0b00, + RejectEnumValue = 0x0c00, + Template = 0x0d00, + TemplateInstanceEnum = 0x0e00, + Replace = 0x0f00, + AddFunction = 0x1000, + SimpleMask = 0x3f00, + + // Code snip tags (0x1000, 0x2000, ... , 0xf000) + InjectCode = 0x4000, + InjectCodeInFunction = 0x8000, + CodeSnipMask = 0xc000, + + // Function modifier tags (0x010000, 0x020000, ... , 0xf00000) + Access = 0x010000, + Removal = 0x020000, + Rename = 0x040000, + ModifyArgument = 0x080000, + Thread = 0x100000, + FunctionModifiers = 0xff0000, + + // Argument modifier tags (0x01000000 ... 0xf0000000) + ConversionRule = 0x01000000, + ReplaceType = 0x02000000, + ReplaceDefaultExpression = 0x04000000, + RemoveArgument = 0x08000000, + DefineOwnership = 0x10000000, + RemoveDefaultExpression = 0x20000000, + NoNullPointers = 0x40000000, + ReferenceCount = 0x80000000, + ParentOwner = 0x90000000, + 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); + + 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* m_current; + QString m_defaultPackage; + QString m_defaultSuperclass; + QString m_error; + TypeEntry::CodeGeneration m_generate; + + EnumTypeEntry* m_currentEnum; + + CodeSnipList m_codeSnips; + AddedFunctionList m_addedFunctions; + FunctionModificationList m_functionMods; + FieldModificationList m_fieldMods; + DocModificationList m_docModifications; + + QHash<QString, StackElement::ElementType> tagNames; + QString m_currentSignature; +}; + +#endif |