From 2f8abc0c22539e96b1158e283f4da97acfbe98f8 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 15 Oct 2013 11:38:02 -0400 Subject: [PATCH 01/66] Fix buffer overrun processing macro definitions Fix potential buffer overrun (__first iterator becomes > __last and starts processing garbage) when parsing macro definitions that would occur if a macro definition ends in a comment. This would cause the macro definition to contain incorrect content or even outright garbage (i.e. random memory) if the trailing comment is at the end of the file, as in boost/type_traits/detail/type_trait_def.hpp. In this worst case, the macro expansion could contain a NUL byte which would cause parsing to prematurely halt at the point of expansion. Change-Id: I94ded39d9a20dc9510d827bc18adb2dc1bad17f0 Reviewed-by: John Cummings --- ApiExtractor/parser/rpp/pp-engine-bits.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ApiExtractor/parser/rpp/pp-engine-bits.h b/ApiExtractor/parser/rpp/pp-engine-bits.h index 5552b16..a15059e 100644 --- a/ApiExtractor/parser/rpp/pp-engine-bits.h +++ b/ApiExtractor/parser/rpp/pp-engine-bits.h @@ -623,6 +623,8 @@ _InputIterator pp::handle_define(_InputIterator __first, _InputIterator __last) } else { __first = skip_comment_or_divop(__first, __last); env.current_line += skip_comment_or_divop.lines; + if (__first == __last) + break; } } From 0490b3000a29bcf72d83349dcb7a077f6a6c6c44 Mon Sep 17 00:00:00 2001 From: John Ehresman Date: Mon, 11 Nov 2013 19:10:06 -0500 Subject: [PATCH 02/66] Only use fields in PyTypeObject when defining types Allocate and use separate structures for as_* fields in the PyTypeObject rather than using fields in the PyHeapTypeObject. This is a step away from using the PyHeapTypeObject, which is unnecessary and will make supporting stackless python easier. Change-Id: I6e5c514ab6db5b8bee9bee3107b97d6fbd582641 Reviewed-by: Christian Tismer Reviewed-by: John Cummings --- generator/shiboken/cppgenerator.cpp | 39 ++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index 04a0870..e2ebc59 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -3401,9 +3401,24 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass* if (callOp && !callOp->isModifiedRemoved()) tp_call = '&' + cpythonFunctionName(callOp); - s << "// Class Definition -----------------------------------------------" << endl; s << "extern \"C\" {" << endl; + + if (supportsNumberProtocol(metaClass)) { + s << "static PyNumberMethods " << className + "_TypeAsNumber" << ";" << endl; + s << endl; + } + + if (supportsSequenceProtocol(metaClass)) { + s << "static PySequenceMethods " << className + "_TypeAsSequence" << ";" << endl; + s << endl; + } + + if (supportsMappingProtocol(metaClass)) { + s << "static PyMappingMethods " << className + "_TypeAsMapping" << ";" << endl; + s << endl; + } + s << "static SbkObjectType " << className + "_Type" << " = { { {" << endl; s << INDENT << "PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0)" << endl; s << INDENT << "/*tp_name*/ \"" << getClassTargetFullName(metaClass) << "\"," << endl; @@ -3536,13 +3551,13 @@ void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractM funcs["__setitem__"] = baseName + "__setitem__"; } - s << INDENT << "memset(&" << baseName << "_Type.super.as_sequence, 0, sizeof(PySequenceMethods));" << endl; + s << INDENT << "memset(&" << baseName << "_TypeAsSequence, 0, sizeof(PySequenceMethods));" << endl; foreach (const QString& sqName, m_sqFuncs.keys()) { if (funcs[sqName].isEmpty()) continue; if (m_sqFuncs[sqName] == "sq_slice") s << "#ifndef IS_PY3K" << endl; - s << INDENT << baseName << "_Type.super.as_sequence." << m_sqFuncs[sqName] << " = " << funcs[sqName] << ';' << endl; + s << INDENT << baseName << "_TypeAsSequence." << m_sqFuncs[sqName] << " = " << funcs[sqName] << ';' << endl; if (m_sqFuncs[sqName] == "sq_slice") s << "#endif" << endl; } @@ -3567,11 +3582,11 @@ void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMe } QString baseName = cpythonBaseName(metaClass); - s << INDENT << "memset(&" << baseName << "_Type.super.as_mapping, 0, sizeof(PyMappingMethods));" << endl; + s << INDENT << "memset(&" << baseName << "_TypeAsMapping, 0, sizeof(PyMappingMethods));" << endl; foreach (const QString& mpName, m_mpFuncs.keys()) { if (funcs[mpName].isEmpty()) continue; - s << INDENT << baseName << "_Type.super.as_mapping." << m_mpFuncs[mpName] << " = " << funcs[mpName] << ';' << endl; + s << INDENT << baseName << "_TypeAsMapping." << m_mpFuncs[mpName] << " = " << funcs[mpName] << ';' << endl; } } @@ -3619,7 +3634,7 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet nb["bool"] = hasBoolCast(metaClass) ? baseName + "___nb_bool" : QString(); - s << INDENT << "memset(&" << baseName << "_Type.super.as_number, 0, sizeof(PyNumberMethods));" << endl; + s << INDENT << "memset(&" << baseName << "_TypeAsNumber, 0, sizeof(PyNumberMethods));" << endl; foreach (const QString& nbName, m_nbFuncs.keys()) { if (nb[nbName].isEmpty()) continue; @@ -3627,18 +3642,18 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet // bool is special because the field name differs on Python 2 and 3 (nb_nonzero vs nb_bool) // so a shiboken macro is used. if (nbName == "bool") { - s << INDENT << "SBK_NB_BOOL(" << baseName << "_Type.super.as_number) = " << nb[nbName] << ';' << endl; + s << INDENT << "SBK_NB_BOOL(" << baseName << "_TypeAsNumber) = " << nb[nbName] << ';' << endl; } else { bool excludeFromPy3K = nbName == "__div__" || nbName == "__idiv__"; if (excludeFromPy3K) s << "#ifndef IS_PY3K" << endl; - s << INDENT << baseName << "_Type.super.as_number." << m_nbFuncs[nbName] << " = " << nb[nbName] << ';' << endl; + s << INDENT << baseName << "_TypeAsNumber." << m_nbFuncs[nbName] << " = " << nb[nbName] << ';' << endl; if (excludeFromPy3K) s << "#endif" << endl; } } if (!nb["__div__"].isEmpty()) - s << INDENT << baseName << "_Type.super.as_number.nb_true_divide = " << nb["__div__"] << ';' << endl; + s << INDENT << baseName << "_TypeAsNumber.nb_true_divide = " << nb["__div__"] << ';' << endl; } void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass) @@ -4243,21 +4258,21 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m if (supportsNumberProtocol(metaClass)) { s << INDENT << "// type has number operators" << endl; writeTypeAsNumberDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_number = &" << pyTypeName << ".super.as_number;" << endl; + s << INDENT << pyTypeName << ".super.ht_type.tp_as_number = &" << pyTypeName << "AsNumber;" << endl; s << endl; } if (supportsSequenceProtocol(metaClass)) { s << INDENT << "// type supports sequence protocol" << endl; writeTypeAsSequenceDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_sequence = &" << pyTypeName << ".super.as_sequence;" << endl; + s << INDENT << pyTypeName << ".super.ht_type.tp_as_sequence = &" << pyTypeName << "AsSequence;" << endl; s << endl; } if (supportsMappingProtocol(metaClass)) { s << INDENT << "// type supports mapping protocol" << endl; writeTypeAsMappingDefinition(s, metaClass); - s << INDENT << pyTypeName << ".super.ht_type.tp_as_mapping = &" << pyTypeName << ".super.as_mapping;" << endl; + s << INDENT << pyTypeName << ".super.ht_type.tp_as_mapping = &" << pyTypeName << "AsMapping;" << endl; s << endl; } From faa44f349170667fb918fc25e51cc5f392bfc6ad Mon Sep 17 00:00:00 2001 From: Brian Jensen Date: Sat, 26 Oct 2013 21:48:48 +0200 Subject: [PATCH 03/66] Fix compilation issue on OS X 10.9 Starting with OS X 10.9 the system toolchain defaults to libc++. This is a problem with the current sparse hash config as it defaults to using c++11 functionality under the std::tr1 namespace instead of std, which fails for libc++ since it does not implement the tr1 namespace. This change allows libc++ based systems to use the correct namespace. Change-Id: Ia8dd49fb5fad2915f41e44240e45a7af9d6453a8 Reviewed-by: John Ehresman --- ext/sparsehash/google/sparsehash/sparseconfig.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ext/sparsehash/google/sparsehash/sparseconfig.h b/ext/sparsehash/google/sparsehash/sparseconfig.h index 44a4dda..5073639 100644 --- a/ext/sparsehash/google/sparsehash/sparseconfig.h +++ b/ext/sparsehash/google/sparsehash/sparseconfig.h @@ -13,6 +13,16 @@ #define HASH_NAMESPACE stdext /* The system-provided hash function including the namespace. */ #define SPARSEHASH_HASH HASH_NAMESPACE::hash_compare +/* libc++ does not implement the tr1 namespce, instead the + * equivalient functionality is placed in namespace std, + * so use when it targeting such systems (OS X 10.7 onwards) */ +#elif defined(_LIBCPP_VERSION) + /* the location of the header defining hash functions */ + #define HASH_FUN_H + /* the namespace of the hash<> function */ + #define HASH_NAMESPACE std + /* The system-provided hash function including the namespace. */ + #define SPARSEHASH_HASH HASH_NAMESPACE::hash #else /* the location of the header defining hash functions */ #define HASH_FUN_H From a527dd51e69b80c2d5be3a1d8cd60ab2b2616fa5 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 31 Dec 2013 14:30:53 -0500 Subject: [PATCH 04/66] Fix for containers with 'const' values Fix omission of 'const' specifier when generating binding code for containers whose value type is 'const', which would lead to binding code that does not compile due to 'const' mismatch. Includes test case. Change-Id: Iff99a16ee071bb255f78e86e2456e5206cc00cfb Reviewed-by: John Cummings --- generator/shiboken/cppgenerator.cpp | 9 ++++- tests/libsample/cvlist.h | 47 +++++++++++++++++++++++ tests/samplebinding/CMakeLists.txt | 2 + tests/samplebinding/global.h | 1 + tests/samplebinding/typesystem_sample.xml | 3 ++ 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 tests/libsample/cvlist.h diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index e2ebc59..4fbc134 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -2422,8 +2422,13 @@ void CppGenerator::writeCppToPythonFunction(QTextStream& s, const AbstractMetaTy return; } QString code = customConversion->nativeToTargetConversion(); - for (int i = 0; i < containerType->instantiations().count(); ++i) - code.replace(QString("%INTYPE_%1").arg(i), getFullTypeName(containerType->instantiations().at(i))); + for (int i = 0; i < containerType->instantiations().count(); ++i) { + AbstractMetaType* type = containerType->instantiations().at(i); + QString typeName = getFullTypeName(type); + if (type->isConstant()) + typeName = "const " + typeName; + code.replace(QString("%INTYPE_%1").arg(i), typeName); + } replaceCppToPythonVariables(code, getFullTypeNameWithoutModifiers(containerType)); processCodeSnip(code); writeCppToPythonFunction(s, code, fixedCppTypeName(containerType)); diff --git a/tests/libsample/cvlist.h b/tests/libsample/cvlist.h new file mode 100644 index 0000000..77b7eca --- /dev/null +++ b/tests/libsample/cvlist.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Shiboken Python Binding Generator project. + * + * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef CONSTVALUELIST_H +#define CONSTVALUELIST_H + +#include +#include "libsamplemacros.h" + +class CVValueType +{ + CVValueType(); +}; + +typedef std::list const_ptr_value_list; + +// This tests binding generation for a container of a const value type. The +// class doesn't need to do anything; this is just to verify that the generated +// binding code (the container conversion in particular) is const-valid. + +class CVListUser +{ +public: + static const_ptr_value_list produce() { return const_ptr_value_list(); } + static void consume(const const_ptr_value_list& l) { (void)l; } +}; + +#endif // LIST_H diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index 23ff63c..ce13b91 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -19,6 +19,8 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/bucket_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/collector_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/color_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/ctorconvrule_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/cvlistuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/cvvaluetype_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/sbkdate_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/derived_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/derived_someinnerclass_wrapper.cpp diff --git a/tests/samplebinding/global.h b/tests/samplebinding/global.h index 28bac0a..007a5e3 100644 --- a/tests/samplebinding/global.h +++ b/tests/samplebinding/global.h @@ -5,6 +5,7 @@ #include "collector.h" #include "complex.h" #include "ctorconvrule.h" +#include "cvlist.h" #include "sbkdate.h" #include "derived.h" #include "echo.h" diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 233a756..dee0285 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -601,6 +601,9 @@ + + + From cb0671914f0ea3c88b59200a56648478faf5fc44 Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Wed, 25 Dec 2013 20:12:24 +0200 Subject: [PATCH 05/66] doc: Stop requiring sphinx.ext.refcounting. Sphinx 1.2 made a backwards-incompatible change and removed its `refcounting' extension module because it "is very specific to CPython and has no place in the main distribution". Fix the build with Sphinx 1.2+ by not requiring it in conf.py.in; we were not using it before anyway (the `refcount_file' variable was not set) and it was likely added by default when the configuration file was generated. Change-Id: I6c775fb4c1c2daae25aade68079efc2e77225a0f Reviewed-by: John Ehresman --- doc/conf.py.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py.in b/doc/conf.py.in index f64b4f6..3a5d985 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -22,7 +22,7 @@ import sys, os # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.refcounting', 'sphinx.ext.coverage'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.coverage'] rst_epilog = """ .. |project| replace:: Shiboken From 5b39f7fd9e216dd16e32ee5950d8d3d781cf1d17 Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Wed, 26 Mar 2014 13:02:22 -0300 Subject: [PATCH 06/66] Fix building with python 3.3 and 3.4. FindPython3Libs.cmake lists hardcoded versions of python3 to look for, which include up to python 3.2. Added python 3.3 and 3.4 to this list so that building on these versions works. A better solution would be ideal in future, so as to avoid having to add python versions to this list as time passes. However, this fixes the issue for now. Change-Id: I9c113f70164c30dc3a94a5c946facbc38901f68e Reviewed-by: John Ehresman --- cmake/Modules/FindPython3Libs.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/FindPython3Libs.cmake b/cmake/Modules/FindPython3Libs.cmake index 8685e9f..20a82ba 100644 --- a/cmake/Modules/FindPython3Libs.cmake +++ b/cmake/Modules/FindPython3Libs.cmake @@ -27,7 +27,7 @@ INCLUDE(CMakeFindFrameworks) # Search for the python framework on Apple. # CMAKE_FIND_FRAMEWORKS(Python) -FOREACH(_CURRENT_VERSION 3.2 3.1 3.0) +FOREACH(_CURRENT_VERSION 3.4 3.3 3.2 3.1 3.0) IF(_CURRENT_VERSION GREATER 3.1) SET(_32FLAGS "m" "u" "mu" "dm" "du" "dmu" "") ELSE() From 35d006a7bf9b33807c1df93f5f9439ff83cd32c0 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Sun, 10 Nov 2013 17:09:31 -0500 Subject: [PATCH 07/66] Fix function rejections (i.e. support overloads) Add an additional check to AbstractMetaBuilder::traverseFunction to also perform a quick-and-dirty construction of the function signature, and to check that against the rejections. Add a unit test for matching full signatures. Before, we were only testing the function name; as a result, a rejection like 'foo()' would never match (because the name does not have ()'s). This is especially helpful for rejecting specific overloads of functions while allowing others to be wrapped normally. (The unit test shows a not-so-far-fetched example why one might want to do this.) The signature building logic isn't very sophisticated and likely requires a very exacting match to the signature as it appears in the wrapped sources, but that's likely not a serious issue, and at any rate this is much better than not being able to match overloads at all. Change-Id: Ic686377477aacf54f79c7bd2013e9aea8521a4ea Reviewed-by: John Ehresman --- ApiExtractor/abstractmetabuilder.cpp | 12 ++++++++++++ tests/libsample/photon.cpp | 3 +++ tests/libsample/photon.h | 13 +++++++++++++ tests/samplebinding/typesystem_sample.xml | 5 +++++ 4 files changed, 33 insertions(+) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index a5c31bf..564f6c3 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1850,6 +1850,14 @@ void AbstractMetaBuilder::fixArgumentNames(AbstractMetaFunction* func) } } +static QString functionSignature(FunctionModelItem functionItem) +{ + QStringList args; + foreach (ArgumentModelItem arg, functionItem->arguments()) + args << arg->type().toString(); + return QString("%1(%2)").arg(functionItem->name(), args.join(",")); +} + AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(FunctionModelItem functionItem) { QString functionName = functionItem->name(); @@ -1861,6 +1869,10 @@ AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(FunctionModelItem fu m_rejectedFunctions.insert(className + "::" + functionName, GenerationDisabled); return 0; } + else if (TypeDatabase::instance()->isFunctionRejected(className, functionSignature(functionItem))) { + m_rejectedFunctions.insert(className + "::" + functionName, GenerationDisabled); + return 0; + } Q_ASSERT(functionItem->functionType() == CodeModel::Normal || functionItem->functionType() == CodeModel::Signal diff --git a/tests/libsample/photon.cpp b/tests/libsample/photon.cpp index b1b3328..ae2031c 100644 --- a/tests/libsample/photon.cpp +++ b/tests/libsample/photon.cpp @@ -24,6 +24,9 @@ namespace Photon { +const ClassType Base::staticType; +template <> const ClassType TemplateBase::staticType; +template <> const ClassType TemplateBase::staticType; int callCalculateForValueDuplicatorPointer(ValueDuplicator* value) { return value->calculate(); diff --git a/tests/libsample/photon.h b/tests/libsample/photon.h index f6c97b7..18917e2 100644 --- a/tests/libsample/photon.h +++ b/tests/libsample/photon.h @@ -33,6 +33,7 @@ namespace Photon { enum ClassType { + BaseType = 0, IdentityType = 1, DuplicatorType = 2 }; @@ -41,9 +42,17 @@ class LIBSAMPLE_API Base { public: explicit Base(int value) : m_value(value) {} + virtual ~Base() {} inline void setValue(int value) { m_value = value; } inline int value() const { return m_value; } + + template bool isType() { return type() == T::staticType; } + bool isType(ClassType t) { return type() == t; } + protected: + virtual ClassType type() const { return BaseType; }; + static const ClassType staticType = BaseType; + int m_value; }; @@ -68,6 +77,10 @@ class LIBSAMPLE_API TemplateBase : public Base } static inline TemplateBase* passPointerThrough(TemplateBase* obj) { return obj; } + +protected: + virtual ClassType type() const { return CLASS_TYPE; } + static const ClassType staticType = CLASS_TYPE; }; #if defined _WIN32 || defined __CYGWIN__ diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index dee0285..5da6ad1 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -2393,6 +2393,11 @@ + + + From ebf3ba51187b6bb54cf819e5a0101c2f75e11de1 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Wed, 16 Apr 2014 10:02:21 -0400 Subject: [PATCH 08/66] Add parsing of 'noexcept' keyword Teach Shiboken to parse the 'noexcept' keyword. This doesn't add any features (and we only support unconditional 'noexcept' for now), but addresses an internal error that causes shiboken to SEGV trying to parse modern versions of boost::intrusive_ptr. A test case to replicate the crash (without the other changes) is also added. Change-Id: I4713593dfd189c02ef4a2d7447d785b6d378019c Reviewed-by: John Ehresman --- ApiExtractor/parser/lexer.cpp | 13 +++++++++++++ ApiExtractor/parser/parser.cpp | 9 +++++++++ ApiExtractor/parser/parser.h | 1 + ApiExtractor/parser/tokens.cpp | 1 + ApiExtractor/parser/tokens.h | 1 + tests/libsample/photon.h | 32 ++++++++++++++++++++++++++++++++ 6 files changed, 57 insertions(+) diff --git a/ApiExtractor/parser/lexer.cpp b/ApiExtractor/parser/lexer.cpp index 0d1269e..eff54b7 100644 --- a/ApiExtractor/parser/lexer.cpp +++ b/ApiExtractor/parser/lexer.cpp @@ -1387,6 +1387,19 @@ void Lexer::scanKeyword8() } break; + case 'n': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'e' && + *(cursor + 3) == 'x' && + *(cursor + 4) == 'c' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'p' && + *(cursor + 7) == 't') { + token_stream[(int) index++].kind = Token_noexcept; + return; + } + break; + case 'o': if (*(cursor + 1) == 'p' && *(cursor + 2) == 'e' && diff --git a/ApiExtractor/parser/parser.cpp b/ApiExtractor/parser/parser.cpp index c56369c..c49785f 100644 --- a/ApiExtractor/parser/parser.cpp +++ b/ApiExtractor/parser/parser.cpp @@ -1124,6 +1124,7 @@ bool Parser::parseDeclarator(DeclaratorAST *&node) token_stream.nextToken(); // skip ')' parseCvQualify(ast->fun_cv); + parseNoExcept(); parseExceptionSpecification(ast->exception_spec); if (token_stream.lookAhead() == Token___attribute__) @@ -1863,6 +1864,14 @@ bool Parser::parseElaboratedTypeSpecifier(TypeSpecifierAST *&node) return false; } +bool Parser::parseNoExcept() +{ + // right now we only accept 'noexcept' with no conditional + CHECK(Token_noexcept); + + return true; +} + bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node) { std::size_t start = token_stream.cursor(); diff --git a/ApiExtractor/parser/parser.h b/ApiExtractor/parser/parser.h index 8f31c13..af3c221 100644 --- a/ApiExtractor/parser/parser.h +++ b/ApiExtractor/parser/parser.h @@ -119,6 +119,7 @@ class Parser bool parseNewExpression(ExpressionAST *&node); bool parseNewInitializer(NewInitializerAST *&node); bool parseNewTypeId(NewTypeIdAST *&node); + bool parseNoExcept(); bool parseOperator(OperatorAST *&node); bool parseOperatorFunctionId(OperatorFunctionIdAST *&node); bool parseParameterDeclaration(ParameterDeclarationAST *&node); diff --git a/ApiExtractor/parser/tokens.cpp b/ApiExtractor/parser/tokens.cpp index e3008de..34737d1 100644 --- a/ApiExtractor/parser/tokens.cpp +++ b/ApiExtractor/parser/tokens.cpp @@ -86,6 +86,7 @@ static char const * const _S_token_names[] = { "mutable", "namespace", "new", + "noexcept", "not", "not_eq", "number_literal", diff --git a/ApiExtractor/parser/tokens.h b/ApiExtractor/parser/tokens.h index dbe612d..20c17a7 100644 --- a/ApiExtractor/parser/tokens.h +++ b/ApiExtractor/parser/tokens.h @@ -87,6 +87,7 @@ enum TOKEN_KIND { Token_mutable, Token_namespace, Token_new, + Token_noexcept, Token_not, Token_not_eq, Token_number_literal, diff --git a/tests/libsample/photon.h b/tests/libsample/photon.h index 18917e2..1f8483e 100644 --- a/tests/libsample/photon.h +++ b/tests/libsample/photon.h @@ -96,6 +96,38 @@ LIBSAMPLE_API int callCalculateForValueDuplicatorReference(ValueDuplicator& valu LIBSAMPLE_API int countValueIdentities(const std::list& values); LIBSAMPLE_API int countValueDuplicators(const std::list >& values); +// This simulates an internal error (SEGV) caused by 'noexcept' in +// boost::intrusive_ptr before support for 'noexcept' was added. The ENTIRE +// code below is needed to trigger the exception; it isn't seen with just a +// 'noexcept' following a declaration. +// +// NOTE: For reasons that should be fairly obvious, this test unfortunately can +// only be "run" when building in C++11 mode. +#if __cplusplus < 201103L +#define noexcept +#endif +class Pointer +{ +public: + Pointer() noexcept : px(0) {} + Pointer(int* p) : px(p) {} + + void reset() noexcept { Pointer().swap(*this); } + + int* get() const noexcept { return px; } + int& operator*() const { return *px; } + + void swap(Pointer& rhs) noexcept + { + int* tmp = px; + px = rhs.px; + rhs.px = tmp; + } + +private: + int* px; +}; + } // namespace Photon #endif // PHOTON_H From bca7c117e141ed78b4666c7a8b868a180bd18173 Mon Sep 17 00:00:00 2001 From: John Ehresman Date: Wed, 16 Apr 2014 12:08:20 -0700 Subject: [PATCH 09/66] Remove protected from samblebinding test The protected sections triggered a generation bug when avoiding the protected hack Change-Id: I6346cdb74a25f1ddf49263d9f74670a3b105b07a Reviewed-by: Matthew Woehlke Reviewed-by: Roman Lacko --- tests/libsample/photon.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/libsample/photon.h b/tests/libsample/photon.h index 1f8483e..4662f36 100644 --- a/tests/libsample/photon.h +++ b/tests/libsample/photon.h @@ -49,10 +49,10 @@ class LIBSAMPLE_API Base template bool isType() { return type() == T::staticType; } bool isType(ClassType t) { return type() == t; } -protected: virtual ClassType type() const { return BaseType; }; static const ClassType staticType = BaseType; +protected: int m_value; }; @@ -78,7 +78,6 @@ class LIBSAMPLE_API TemplateBase : public Base static inline TemplateBase* passPointerThrough(TemplateBase* obj) { return obj; } -protected: virtual ClassType type() const { return CLASS_TYPE; } static const ClassType staticType = CLASS_TYPE; }; From e2897e156f697ce4d89e8df50f7083fff7909372 Mon Sep 17 00:00:00 2001 From: John Cummings Date: Thu, 17 Apr 2014 13:43:19 -0500 Subject: [PATCH 10/66] Remove rejection lines that cause the sample_list test to fail These functions (except createComplexList) are are needed by the test. Prior to 5b39f7fd9e21, the rejections were not being recognized; removing them returns the wrappings to their previous state and allows the test to pass again. Change-Id: I3efb08383b2d59f9917a4e4a0200e0516db9c83e Reviewed-by: Matthew Woehlke Reviewed-by: John Ehresman --- tests/samplebinding/typesystem_sample.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 5da6ad1..49de903 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -2387,12 +2387,6 @@ - - - - - - From 4e0031258b9098c5dc02b34e5eb570e54307e6b5 Mon Sep 17 00:00:00 2001 From: John Ehresman Date: Tue, 22 Apr 2014 08:05:08 -0700 Subject: [PATCH 11/66] Version bump Change-Id: I4da6558dfa2dd2aaae6343d2363b7fcfc7786f45 Reviewed-by: John Cummings --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 00b352a..cac90d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ add_definitions(${QT_DEFINITIONS}) set(shiboken_MAJOR_VERSION "1") set(shiboken_MINOR_VERSION "2") -set(shiboken_MICRO_VERSION "1") +set(shiboken_MICRO_VERSION "2") set(shiboken_VERSION "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}.${shiboken_MICRO_VERSION}") option(BUILD_TESTS "Build tests." TRUE) From 4978122812f82f351351767087d7fb9b8915c8c4 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 17 Feb 2015 13:40:46 -0500 Subject: [PATCH 12/66] Return enums in declaration order (order added) Modify _ScopeModelItem to return enums (from the enums() method) in the order that they were added (which presumably is the order in which they were declared). We must do this because we must process enumerations in the same order in order to resolve values, as later declared enums may refer to values from earlier declared enums (and in fact, this is exactly the case in the 'testenum' test), and the order we get just from QHash may not match declaration order. Change-Id: I15a05df98a2cee7ecccb6c82d3f9017735281245 Reviewed-by: John Cummings --- ApiExtractor/parser/codemodel.cpp | 11 +++++++++-- ApiExtractor/parser/codemodel.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ApiExtractor/parser/codemodel.cpp b/ApiExtractor/parser/codemodel.cpp index 43a8c7e..7e3468a 100644 --- a/ApiExtractor/parser/codemodel.cpp +++ b/ApiExtractor/parser/codemodel.cpp @@ -406,7 +406,10 @@ FunctionDefinitionList _ScopeModelItem::functionDefinitions() const EnumList _ScopeModelItem::enums() const { - return _M_enums.values(); + EnumList result; + foreach (const QString& name, _M_enumNames) + result.append(_M_enums.value(name)); + return result; } void _ScopeModelItem::addClass(ClassModelItem item) @@ -440,7 +443,9 @@ void _ScopeModelItem::addTypeAlias(TypeAliasModelItem item) void _ScopeModelItem::addEnum(EnumModelItem item) { + _M_enumNames.removeOne(item->name()); _M_enums.insert(item->name(), item); + _M_enumNames.append(item->name()); } void _ScopeModelItem::removeClass(ClassModelItem item) @@ -499,8 +504,10 @@ void _ScopeModelItem::removeEnum(EnumModelItem item) { QHash::Iterator it = _M_enums.find(item->name()); - if (it != _M_enums.end() && it.value() == item) + if (it != _M_enums.end() && it.value() == item) { + _M_enumNames.removeOne(item->name()); _M_enums.erase(it); + } } ClassModelItem _ScopeModelItem::findClass(const QString &name) const diff --git a/ApiExtractor/parser/codemodel.h b/ApiExtractor/parser/codemodel.h index 3b3571f..82de75b 100644 --- a/ApiExtractor/parser/codemodel.h +++ b/ApiExtractor/parser/codemodel.h @@ -401,6 +401,7 @@ class _ScopeModelItem: public _CodeModelItem _ScopeModelItem(const _ScopeModelItem &other); void operator = (const _ScopeModelItem &other); + QStringList _M_enumNames; QStringList _M_enumsDeclarations; }; From 0fd6bc31ee9f2b9fe7d1bff40542ef8e51d1adac Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 17 Feb 2015 13:45:22 -0500 Subject: [PATCH 13/66] Process global enums in declaration order In the same vein as the previous commit, process global enums in order added (which presumably is declaration order). For what we're doing at this point, this may not be as critical, but again is needed to avoid a spurious test failure. Change-Id: If32a07fee2e7e9b7699e01eda3408ed57855e947 Reviewed-by: John Cummings --- ApiExtractor/abstractmetabuilder.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 564f6c3..ebb3134 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -414,9 +414,8 @@ bool AbstractMetaBuilder::build(QIODevice* input) ReportHandler::flush(); // We need to know all global enums - QHash enumMap = m_dom->enumMap(); - ReportHandler::setProgressReference(enumMap); - foreach (EnumModelItem item, enumMap) { + ReportHandler::setProgressReference(m_dom->enumMap()); + foreach (EnumModelItem item, m_dom->enums()) { ReportHandler::progress("Generating enum model..."); AbstractMetaEnum *metaEnum = traverseEnum(item, 0, QSet()); if (metaEnum) { From aa39374b419c535dd56145ffebcef97c8c20eb39 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Fri, 20 Feb 2015 16:31:23 -0500 Subject: [PATCH 14/66] Don't ignore classes in topology When building the class topology, don't skip classes, even if we are not going to generate code for them. This is necessary to get the topology order correct in a case such as C derived from B derived from A, where B is not generated, but initializing C depends on A being initialized first. Without this change, there is no guaranteed ordering between A and C in such a case. (In particular, this comes up in the Photon test; Photon::ValueIdentity derives from Photon::TemplateBase, which derives from Photon::Base. However, this was not being reflected in the topology, and as a result, it was just luck that the initialization order was correct anyway.) Change-Id: I4b99a50acef3b06e77100a70f2db8236d06af2be Reviewed-by: John Cummings --- ApiExtractor/abstractmetabuilder.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index ebb3134..f956d7c 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -2952,9 +2952,6 @@ AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted(const Abstra QRegExp regex1("\\(.*\\)"); QRegExp regex2("::.*"); foreach (AbstractMetaClass* clazz, classList) { - if (clazz->isInterface() || !clazz->typeEntry()->generateCode()) - continue; - if (clazz->enclosingClass() && map.contains(clazz->enclosingClass()->qualifiedCppName())) graph.addEdge(map[clazz->enclosingClass()->qualifiedCppName()], map[clazz->qualifiedCppName()]); From 64b024f49251d3cf73068ac6d951343c9d9dc246 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 6 Aug 2013 15:51:01 -0400 Subject: [PATCH 15/66] Start implementing template class support Add 'type-template' tag (and 'arg' child tag) to declare a definition of a template struct/class. Modify 'object-type' and 'value-type' to allow creating these as template instantiations referencing a 'type-template', as an alternative to the usual non-template support. There is also a 'redirect' attribute on 'arg' that will be used to create "redirection" methods on the wrapped class to allow calling methods of a template argument class as if they belonged to the instantiation, which is sort of like having an operator->(). The eventual goal is to support wrapping of e.g. QSharedPointer. This is sufficient to parse a typesystem XML (updates to 'sample' included) using the new tags, but not to do anything useful yet, as neither type resolution is working, nor do we generate code for the instantiations. Change-Id: I37960727c4dd69c39e84a414ae08752e3fd0dbf3 --- ApiExtractor/typedatabase.h | 11 +++ ApiExtractor/typesystem.cpp | 96 +++++++++++++++++++++-- ApiExtractor/typesystem.h | 94 ++++++++++++++++++++-- ApiExtractor/typesystem_p.h | 2 + tests/libsample/CMakeLists.txt | 1 + tests/libsample/pointer.cpp | 48 ++++++++++++ tests/libsample/pointer.h | 92 ++++++++++++++++++++++ tests/samplebinding/CMakeLists.txt | 1 + tests/samplebinding/global.h | 1 + tests/samplebinding/typesystem_sample.xml | 6 ++ 10 files changed, 339 insertions(+), 13 deletions(-) create mode 100644 tests/libsample/pointer.cpp create mode 100644 tests/libsample/pointer.h diff --git a/ApiExtractor/typedatabase.h b/ApiExtractor/typedatabase.h index 116e0ed..ffa1c62 100644 --- a/ApiExtractor/typedatabase.h +++ b/ApiExtractor/typedatabase.h @@ -113,6 +113,16 @@ class TypeDatabase m_flagsEntries[fte->originalName()] = fte; } + TypeTemplateEntry* findTypeTemplate(const QString& name) const + { + return m_typeTemplates[name]; + } + + void addTypeTemplate(TypeTemplateEntry* t) + { + m_typeTemplates[t->name()] = t; + } + TemplateEntry* findTemplate(const QString& name) const { return m_templates[name]; @@ -206,6 +216,7 @@ class TypeDatabase bool m_suppressWarnings; TypeEntryHash m_entries; SingleTypeEntryHash m_flagsEntries; + TypeTemplateEntryHash m_typeTemplates; TemplateEntryHash m_templates; QStringList m_suppressedWarnings; diff --git a/ApiExtractor/typesystem.cpp b/ApiExtractor/typesystem.cpp index 9925a39..48843a2 100644 --- a/ApiExtractor/typesystem.cpp +++ b/ApiExtractor/typesystem.cpp @@ -45,6 +45,8 @@ Handler::Handler(TypeDatabase* database, bool generate) m_ignoreDepth = 0; tagNames["rejection"] = StackElement::Rejection; + tagNames["type-template"] = StackElement::TypeTemplate; + tagNames["arg"] = StackElement::Argument; tagNames["custom-type"] = StackElement::CustomTypeEntry; tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry; tagNames["container-type"] = StackElement::ContainerTypeEntry; @@ -167,6 +169,9 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin } } break; + case StackElement::TypeTemplate: + m_database->addTypeTemplate(static_cast(m_current->entry)); + // fall through case StackElement::ObjectTypeEntry: case StackElement::ValueTypeEntry: case StackElement::InterfaceTypeEntry: @@ -532,6 +537,8 @@ bool Handler::startElement(const QString &, const QString &n, attributes["deprecated"] = QString("no"); attributes["hash-function"] = QString(""); attributes["stream"] = QString("no"); + attributes["template"] = QString(); + attributes["args"] = QString(); // fall throooough case StackElement::InterfaceTypeEntry: attributes["default-superclass"] = m_defaultSuperclass; @@ -623,10 +630,59 @@ bool Handler::startElement(const QString &, const QString &n, name = element->parent->entry->name() + "::" + name; } + TypeTemplateEntry *typeTemplate = 0; + QStringList typeTemplateArgNames; - if (name.isEmpty()) { - m_error = "no 'name' attribute specified"; - return false; + if (element->type == StackElement::ObjectTypeEntry || element->type == StackElement::ValueTypeEntry) { + QString typeTemplateName = attributes["template"]; + + if (!name.isEmpty() && !typeTemplateName.isEmpty()) { + m_error = "can't specify both 'name' and 'template' attributes"; + return false; + } + + if (typeTemplateName.isEmpty()) { + if (name.isEmpty()) { + m_error = "no 'name' attribute specified"; + return false; + } + + if (!attributes["args"].isEmpty()) { + m_error = "'args' attribute may only be specified for template instantiation types"; + return false; + } + } else { + typeTemplate = m_database->findTypeTemplate(typeTemplateName); + if (!typeTemplate) { + m_error = "there is no type-template named " + typeTemplateName; + return false; + } + + if (attributes["args"].isEmpty()) { + m_error = "no 'args' attribute specified for template instantiation type"; + return false; + } + + typeTemplateArgNames = attributes["args"].split(QRegExp(",\\s*"), QString::SkipEmptyParts); + if (typeTemplateArgNames.isEmpty()) { + m_error = "invalid 'args' attribute"; + return false; + } + + int xc = typeTemplate->args().count(); + int ac = typeTemplateArgNames.count(); + if (ac != xc) { + m_error = QString("wrong number of args for template instantiation: expected %1, got %2").arg(xc).arg(ac); + return false; + } + + name = QString("%1< %2 >").arg(typeTemplateName, typeTemplateArgNames.join(",")); + } + } else { + if (name.isEmpty()) { + m_error = "no 'name' attribute specified"; + return false; + } } switch (element->type) { @@ -753,7 +809,7 @@ bool Handler::startElement(const QString &, const QString &n, // fall through case StackElement::ValueTypeEntry: { if (!element->entry) { - ValueTypeEntry* typeEntry = new ValueTypeEntry(name, since); + ValueTypeEntry* typeEntry = new ValueTypeEntry(name, since, typeTemplate, typeTemplateArgNames); QString defaultConstructor = attributes["default-constructor"]; if (!defaultConstructor.isEmpty()) typeEntry->setDefaultConstructor(defaultConstructor); @@ -768,7 +824,7 @@ bool Handler::startElement(const QString &, const QString &n, // fall through case StackElement::ObjectTypeEntry: if (!element->entry) - element->entry = new ObjectTypeEntry(name, since); + element->entry = new ObjectTypeEntry(name, since, typeTemplate, typeTemplateArgNames); element->entry->setStream(attributes["stream"] == QString("yes")); @@ -946,7 +1002,8 @@ bool Handler::startElement(const QString &, const QString &n, || element->type == StackElement::ExtraIncludes || element->type == StackElement::ConversionRule || element->type == StackElement::AddFunction - || element->type == StackElement::Template; + || element->type == StackElement::Template + || element->type == StackElement::TypeTemplate; if (!topLevel && m_current->type == StackElement::Root) { m_error = QString("Tag requires parent: '%1'").arg(tagName); @@ -1071,6 +1128,12 @@ bool Handler::startElement(const QString &, const QString &n, attributes["from"] = QString(); attributes["to"] = QString(); break; + case StackElement::TypeTemplate: + attributes["name"] = QString(); + break; + case StackElement::Argument: + attributes["redirect"] = QString(); + break; case StackElement::ReferenceCount: attributes["action"] = QString(); attributes["variable-name"] = QString(); @@ -1787,8 +1850,10 @@ bool Handler::startElement(const QString &, const QString &n, element->entry->setInclude(inc); } else if (topElement.type == StackElement::ExtraIncludes) { element->entry->addExtraInclude(inc); + } else if (topElement.type == StackElement::TypeTemplate) { + element->entry->setInclude(inc); } else { - m_error = "Only supported parent tags are primitive-type, complex types or extra-includes"; + m_error = "Only supported parent tags are primitive-type, type-template, complex types or extra-includes"; return false; } @@ -1814,6 +1879,23 @@ bool Handler::startElement(const QString &, const QString &n, m_database->addRejection(cls, function, field, enum_); } break; + case StackElement::TypeTemplate: { + QString name = attributes["name"]; + if (name.isEmpty()) { + m_error = "no 'name' attribute specified"; + return false; + } + element->entry = new TypeTemplateEntry(name, since); + } + break; + case StackElement::Argument: { + if (topElement.type != StackElement::TypeTemplate) { + m_error = "Can only specify arguments for type-template tag."; + return false; + } + TypeTemplateEntry *tentry = static_cast(topElement.entry); + tentry->addArg(attributes["redirect"]); + } case StackElement::Template: element->value.templateEntry = new TemplateEntry(attributes["name"], since); break; diff --git a/ApiExtractor/typesystem.h b/ApiExtractor/typesystem.h index 0549672..769757f 100644 --- a/ApiExtractor/typesystem.h +++ b/ApiExtractor/typesystem.h @@ -642,7 +642,8 @@ class TypeEntry TypeSystemType, CustomType, TargetLangType, - FunctionType + FunctionType, + TemplateType }; enum CodeGeneration { @@ -707,6 +708,10 @@ class TypeEntry { return m_type == ContainerType; } + bool isTypeTemplate() const + { + return m_type == TemplateType; + } bool isVariant() const { return m_type == VariantType; @@ -1403,6 +1408,8 @@ class FlagsTypeEntry : public TypeEntry }; +class TypeTemplateEntry; + class ComplexTypeEntry : public TypeEntry { public: @@ -1419,7 +1426,8 @@ class ComplexTypeEntry : public TypeEntry Unknown }; - ComplexTypeEntry(const QString &name, Type t, double vr) + ComplexTypeEntry(const QString &name, Type t, double vr, const TypeTemplateEntry *typeTemplate = 0, + const QStringList &typeTemplateArgNames = QStringList()) : TypeEntry(QString(name).replace(".*::", ""), t, vr), m_qualifiedCppName(name), m_qobject(false), @@ -1428,7 +1436,9 @@ class ComplexTypeEntry : public TypeEntry m_typeFlags(0), m_copyableFlag(Unknown), m_hashFunction(""), - m_baseContainerType(0) + m_baseContainerType(0), + m_templateArgNames(typeTemplateArgNames), + m_templateType(typeTemplate) { } @@ -1641,6 +1651,29 @@ class ComplexTypeEntry : public TypeEntry return m_baseContainerType; } + bool isTemplateInstantiation() const + { + return m_templateType; + } + + QStringList templateArgNames() const + { + return m_templateArgNames; + } + const TypeTemplateEntry* templateType() const + { + return m_templateType; + } + + void setTemplateArgTypes(QList templateArgs) + { + m_templateArgTypes = templateArgs; + } + QList templateArgTypes() const + { + return m_templateArgTypes; + } + QString defaultConstructor() const; void setDefaultConstructor(const QString& defaultConstructor); bool hasDefaultConstructor() const; @@ -1668,6 +1701,11 @@ class ComplexTypeEntry : public TypeEntry QString m_hashFunction; const ComplexTypeEntry* m_baseContainerType; + + QStringList m_templateArgNames; + + const TypeTemplateEntry *m_templateType; + QList m_templateArgTypes; }; class ContainerTypeEntry : public ComplexTypeEntry @@ -1731,6 +1769,47 @@ class ContainerTypeEntry : public ComplexTypeEntry typedef QList ContainerTypeEntryList; + +class TypeTemplateEntry : public ComplexTypeEntry +{ +public: + class Argument + { + public: + Argument(const QString &redirect) : m_redirect(redirect) { } + + QString redirect() const + { + return m_redirect; + } + + private: + QString m_redirect; + }; + + TypeTemplateEntry(const QString &name, double vr) + : ComplexTypeEntry(name, TemplateType, vr) + { + setCodeGeneration(GenerateNothing); + } + + QList args() const // FIXME array of ?? + { + return m_args; + } + + void addArg(const QString &redirect) + { + m_args << Argument(redirect); + } + +private: + QList m_args; +}; + +typedef QHash TypeTemplateEntryHash; + + class NamespaceTypeEntry : public ComplexTypeEntry { public: @@ -1741,7 +1820,9 @@ class NamespaceTypeEntry : public ComplexTypeEntry class ValueTypeEntry : public ComplexTypeEntry { public: - ValueTypeEntry(const QString &name, double vr) : ComplexTypeEntry(name, BasicValueType, vr) { } + ValueTypeEntry(const QString &name, double vr, const TypeTemplateEntry *typeTemplate = 0, + const QStringList &typeTemplateArgNames = QStringList()) + : ComplexTypeEntry(name, BasicValueType, vr, typeTemplate, typeTemplateArgNames) { } bool isValue() const { @@ -1877,8 +1958,9 @@ class FunctionTypeEntry : public TypeEntry class ObjectTypeEntry : public ComplexTypeEntry { public: - ObjectTypeEntry(const QString &name, double vr) - : ComplexTypeEntry(name, ObjectType, vr), m_interface(0) {} + ObjectTypeEntry(const QString &name, double vr, const TypeTemplateEntry *typeTemplate = 0, + const QStringList &typeTemplateArgNames = QStringList()) + : ComplexTypeEntry(name, ObjectType, vr, typeTemplate, typeTemplateArgNames), m_interface(0) {} InterfaceTypeEntry *designatedInterface() const { diff --git a/ApiExtractor/typesystem_p.h b/ApiExtractor/typesystem_p.h index 801e71e..23d0ee1 100644 --- a/ApiExtractor/typesystem_p.h +++ b/ApiExtractor/typesystem_p.h @@ -74,6 +74,8 @@ class StackElement NativeToTarget = 0x1100, TargetToNative = 0x1200, AddConversion = 0x1300, + TypeTemplate = 0x1400, + Argument = 0x1500, SimpleMask = 0x3f00, // Code snip tags (0x1000, 0x2000, ... , 0xf000) diff --git a/tests/libsample/CMakeLists.txt b/tests/libsample/CMakeLists.txt index 30205ed..2788f82 100644 --- a/tests/libsample/CMakeLists.txt +++ b/tests/libsample/CMakeLists.txt @@ -31,6 +31,7 @@ pairuser.cpp pen.cpp photon.cpp point.cpp +pointer.cpp pointf.cpp polygon.cpp protected.cpp diff --git a/tests/libsample/pointer.cpp b/tests/libsample/pointer.cpp new file mode 100644 index 0000000..9c6d6fa --- /dev/null +++ b/tests/libsample/pointer.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2013 Kitware, Inc. + * + * This file is part of the Shiboken Python Binding Generator project. + * + * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "pointer.h" + +static int nextId = 0; +static int counter = 0; + +SimpleObject::SimpleObject(int id) : m_id(id) +{ + ++counter; +} + +SimpleObject::~SimpleObject() +{ + --counter; +} + +Pointer SimpleObject::create() +{ + return Pointer(new SimpleObject(++nextId)); +} + +int SimpleObject::count() +{ + return counter; +} diff --git a/tests/libsample/pointer.h b/tests/libsample/pointer.h new file mode 100644 index 0000000..b7084f7 --- /dev/null +++ b/tests/libsample/pointer.h @@ -0,0 +1,92 @@ +/* + * Copyright 2013 Kitware, Inc. + * + * This file is part of the Shiboken Python Binding Generator project. + * + * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef POINTER_H +#define POINTER_H + +#include "libsamplemacros.h" + +template +class Pointer +{ +public: + Pointer() : m_obj(0), m_ref(0) {} + + explicit Pointer(T *obj) : m_obj(obj), m_ref(new int) + { + *m_ref = 1; + } + + Pointer(const Pointer &other) : m_obj(other.m_obj), m_ref(other.m_ref) + { + ++(*m_ref); + } + + Pointer& operator=(const Pointer &other) + { + release(); + m_obj = other.m_obj; + m_ref = other.m_ref; + ++(*m_ref); + return *this; + } + + virtual ~Pointer() + { + release(); + } + + inline T* get() const { return m_obj; } + +private: + void release() + { + if (m_ref && --(*m_ref) <= 0) { + delete m_obj; + delete m_ref; + } + } + + T *m_obj; + int *m_ref; +}; + +class LIBSAMPLE_API SimpleObject +{ +public: + ~SimpleObject(); + + inline int id() const { return m_id; } + + static Pointer create(); + static int count(); + +private: + SimpleObject(int); + + int m_id; +}; + +#endif // POINTER_H + diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index ce13b91..f2f5b54 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -99,6 +99,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someotherinnerclass ${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_derivedfromnamespace_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/simplefile_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/simpleobject_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/size_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/sizef_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/sonofmderived1_wrapper.cpp diff --git a/tests/samplebinding/global.h b/tests/samplebinding/global.h index 007a5e3..5e204e9 100644 --- a/tests/samplebinding/global.h +++ b/tests/samplebinding/global.h @@ -39,6 +39,7 @@ #include "photon.h" #include "point.h" #include "pointf.h" +#include "pointer.h" #include "pointerholder.h" #include "polygon.h" #include "privatector.h" diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 49de903..6db431f 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -2396,6 +2396,12 @@ + + + + + + From 228a918e13f48a955477e6df90a4aa4f92a2c2ba Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 6 Aug 2013 15:51:53 -0400 Subject: [PATCH 16/66] (Partly) implement wrappers for instantiations Teach AbstractMetaBuilder to create wrappers for template instantiation types. Teach generators to generate valid code for the same. This is quite half-baked, as type resolution for instantiations is not yet working (which tends to defeat the purpose). However, a typesystem defining template instantiation types now generates code which also compiles (and 'sample' is updated accordingly). To facilitate code generation, fixedCppTypeName(QString) is now a public static member of ShibokenGenerator, and is used in quite a few places that previously only replaced '::'. This is needed as instantiation wrappers have <>'s in their names that also need to be replaced, and since the additional substitutions that fixedCppTypeName performs should be harmless, this way we are using a helper function that already existed rather than creating a new one for the purpose. Change-Id: I7d077e89d9c3190e6850c1e04aac23a1f179c33b --- ApiExtractor/abstractmetabuilder.cpp | 49 ++++++++++++++++++++++++ ApiExtractor/abstractmetabuilder.h | 1 + generator/shiboken/cppgenerator.cpp | 28 +++++++------- generator/shiboken/headergenerator.cpp | 4 +- generator/shiboken/shibokengenerator.cpp | 16 ++++---- generator/shiboken/shibokengenerator.h | 1 + tests/samplebinding/CMakeLists.txt | 1 + 7 files changed, 76 insertions(+), 24 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index f956d7c..91367c6 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -413,6 +413,23 @@ bool AbstractMetaBuilder::build(QIODevice* input) } ReportHandler::flush(); + ReportHandler::progress("Generating template instantiations model..."); + foreach (QList entries, types->allEntries()) { + foreach (TypeEntry* entry, entries) { + if (entry->isComplex()) { + ComplexTypeEntry *centry = static_cast(entry); + if (centry->isTemplateInstantiation()) { + AbstractMetaClass *cls = createInstantiationMetaClass(centry); + if (!cls) + continue; + + addAbstractMetaClass(cls); + } + } + } + } + ReportHandler::flush(); + // We need to know all global enums ReportHandler::setProgressReference(m_dom->enumMap()); foreach (EnumModelItem item, m_dom->enums()) { @@ -1350,6 +1367,38 @@ void AbstractMetaBuilder::traverseFields(ScopeModelItem scope_item, AbstractMeta } } +AbstractMetaClass* AbstractMetaBuilder::createInstantiationMetaClass(ComplexTypeEntry *entry) +{ + QString fullClassName = entry->name(); + + // Determine base classes + // TODO + + AbstractMetaClass* metaClass = createMetaClass(); + metaClass->setTypeEntry(entry); + *metaClass += AbstractMetaAttributes::Public; + if (entry->stream()) + metaClass->setStream(true); + + ReportHandler::debugSparse(QString("instantiation: '%1'").arg(metaClass->fullName())); + + QStringList template_parameters = entry->templateArgNames(); + QList template_args; + template_args.clear(); + for (int i = 0; i < template_parameters.size(); ++i) { + TemplateArgumentEntry *param_type = new TemplateArgumentEntry(template_parameters.at(i), entry->version()); + param_type->setOrdinal(i); + template_args.append(param_type); + } + metaClass->setTemplateArguments(template_args); + + // Set the default include file name + if (!entry->include().isValid()) + setInclude(entry, entry->include().name()); + + return metaClass; +} + void AbstractMetaBuilder::setupFunctionDefaults(AbstractMetaFunction* metaFunction, AbstractMetaClass *metaClass) { // Set the default value of the declaring class. This may be changed diff --git a/ApiExtractor/abstractmetabuilder.h b/ApiExtractor/abstractmetabuilder.h index 94f5a75..8ee549b 100644 --- a/ApiExtractor/abstractmetabuilder.h +++ b/ApiExtractor/abstractmetabuilder.h @@ -102,6 +102,7 @@ class AbstractMetaBuilder void figureOutDefaultEnumArguments(); void addAbstractMetaClass(AbstractMetaClass *cls); + AbstractMetaClass *createInstantiationMetaClass(ComplexTypeEntry *entry); AbstractMetaClass *traverseTypeAlias(TypeAliasModelItem item); AbstractMetaClass *traverseClass(ClassModelItem item); AbstractMetaClass* currentTraversedClass(ScopeModelItem item); diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index 4fbc134..ff6457f 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -108,7 +108,7 @@ CppGenerator::CppGenerator() QString CppGenerator::fileNameForClass(const AbstractMetaClass *metaClass) const { - return metaClass->qualifiedCppName().toLower().replace("::", "_") + QLatin1String("_wrapper.cpp"); + return fixedCppTypeName(metaClass->qualifiedCppName()).toLower() + QLatin1String("_wrapper.cpp"); } QList CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass, @@ -961,8 +961,8 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla // Returns the C++ pointer of the Python wrapper. s << "// Python to C++ pointer conversion - returns the C++ object of the Python wrapper (keeps object identity)." << endl; - QString sourceTypeName = metaClass->name(); - QString targetTypeName = QString("%1_PTR").arg(metaClass->name()); + QString sourceTypeName = fixedCppTypeName(metaClass->name()); + QString targetTypeName = QString("%1_PTR").arg(sourceTypeName); QString code; QTextStream c(&code); c << INDENT << "Shiboken::Conversions::pythonToCppPointer(&" << cpythonType << ", pyIn, cppOut);"; @@ -1003,8 +1003,8 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla // Always copies C++ value (not pointer, and not reference) to a new Python wrapper. s << endl << "// C++ to Python copy conversion." << endl; - sourceTypeName = QString("%1_COPY").arg(metaClass->name()); - targetTypeName = metaClass->name(); + sourceTypeName = QString("%1_COPY").arg(fixedCppTypeName(metaClass->name())); + targetTypeName = fixedCppTypeName(metaClass->name()); code.clear(); c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << wrapperName(metaClass); c << "(*((" << typeName << "*)cppIn)), true, true);"; @@ -1013,7 +1013,7 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla // Python to C++ copy conversion. s << "// Python to C++ copy conversion." << endl; - sourceTypeName = metaClass->name(); + sourceTypeName = fixedCppTypeName(metaClass->name()); targetTypeName = QString("%1_COPY").arg(sourceTypeName); code.clear(); c << INDENT << "*((" << typeName << "*)cppOut) = *" << cpythonWrapperCPtr(metaClass->typeEntry(), "pyIn") << ';'; @@ -1128,15 +1128,15 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas s << cpythonTypeName(metaClass) << ',' << endl; { Indentation indent(INDENT); - QString sourceTypeName = metaClass->name(); - QString targetTypeName = QString("%1_PTR").arg(metaClass->name()); + QString sourceTypeName = fixedCppTypeName(metaClass->name()); + QString targetTypeName = QString("%1_PTR").arg(sourceTypeName); s << INDENT << pythonToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl; s << INDENT << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl; std::swap(targetTypeName, sourceTypeName); s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName); if (metaClass->typeEntry()->isValue()) { s << ',' << endl; - sourceTypeName = QString("%1_COPY").arg(metaClass->name()); + sourceTypeName = QString("%1_COPY").arg(fixedCppTypeName(metaClass->name())); s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName); } } @@ -1167,8 +1167,8 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas // Python to C++ copy (value, not pointer neither reference) conversion. s << INDENT << "// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter." << endl; - QString sourceTypeName = metaClass->name(); - QString targetTypeName = QString("%1_COPY").arg(metaClass->name()); + QString sourceTypeName = fixedCppTypeName(metaClass->name()); + QString targetTypeName = QString("%1_COPY").arg(sourceTypeName); QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName); QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName); writeAddPythonToCppConversion(s, "converter", toCpp, isConv); @@ -4256,7 +4256,7 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m QString enclosingObjectVariable = hasEnclosingClass ? "enclosingClass" : "module"; QString pyTypeName = cpythonTypeName(metaClass); - s << "void init_" << metaClass->qualifiedCppName().replace("::", "_"); + s << "void init_" << fixedCppTypeName(metaClass->qualifiedCppName()); s << "(PyObject* " << enclosingObjectVariable << ")" << endl; s << '{' << endl; @@ -4623,9 +4623,9 @@ void CppGenerator::finishGeneration() if (!shouldGenerate(cls)) continue; - s_classInitDecl << "void init_" << cls->qualifiedCppName().replace("::", "_") << "(PyObject* module);" << endl; + s_classInitDecl << "void init_" << fixedCppTypeName(cls->qualifiedCppName()) << "(PyObject* module);" << endl; - QString defineStr = "init_" + cls->qualifiedCppName().replace("::", "_"); + QString defineStr = "init_" + fixedCppTypeName(cls->qualifiedCppName()); if (cls->enclosingClass() && (cls->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)) defineStr += "(" + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) +"->tp_dict);"; diff --git a/generator/shiboken/headergenerator.cpp b/generator/shiboken/headergenerator.cpp index b5fa606..76a4615 100644 --- a/generator/shiboken/headergenerator.cpp +++ b/generator/shiboken/headergenerator.cpp @@ -34,7 +34,7 @@ QString HeaderGenerator::fileNameForClass(const AbstractMetaClass* metaClass) const { - return metaClass->qualifiedCppName().toLower().replace("::", "_") + QLatin1String("_wrapper.h"); + return fixedCppTypeName(metaClass->qualifiedCppName()).toLower() + QLatin1String("_wrapper.h"); } void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const @@ -80,7 +80,7 @@ void HeaderGenerator::generateClass(QTextStream& s, const AbstractMetaClass* met s << licenseComment(); QString wrapperName = HeaderGenerator::wrapperName(metaClass); - QString headerGuard = wrapperName.replace("::", "_").toUpper(); + QString headerGuard = fixedCppTypeName(wrapperName).toUpper(); // Header s << "#ifndef SBK_" << headerGuard << "_H" << endl; diff --git a/generator/shiboken/shibokengenerator.cpp b/generator/shiboken/shibokengenerator.cpp index ab3f594..3d9cce7 100644 --- a/generator/shiboken/shibokengenerator.cpp +++ b/generator/shiboken/shibokengenerator.cpp @@ -286,7 +286,7 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const if (shouldGenerateCppWrapper(metaClass)) { QString result = metaClass->name(); if (metaClass->enclosingClass()) // is a inner class - result.replace("::", "_"); + result = fixedCppTypeName(result); result +="Wrapper"; return result; @@ -677,7 +677,7 @@ QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type) } else { baseName = "PyObject"; } - return baseName.replace("::", "_"); + return fixedCppTypeName(baseName); } QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass* metaClass) @@ -748,7 +748,7 @@ QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType* type) return fixedCppTypeName(type->typeEntry(), type->cppSignature()); } -static QString _fixedCppTypeName(QString typeName) +QString ShibokenGenerator::fixedCppTypeName(QString typeName) { return typeName.replace(" ", "") .replace(".", "_") @@ -765,7 +765,7 @@ QString ShibokenGenerator::fixedCppTypeName(const TypeEntry* type, QString typeN typeName = type->qualifiedCppName(); if (!(type->codeGeneration() & TypeEntry::GenerateTargetLang)) typeName.prepend(QString("%1_").arg(type->targetLangPackage())); - return _fixedCppTypeName(typeName); + return fixedCppTypeName(typeName); } QString ShibokenGenerator::pythonPrimitiveTypeName(const QString& cppTypeName) @@ -2341,11 +2341,11 @@ QString ShibokenGenerator::convertersVariableName(const QString& moduleName) con static QString processInstantiationsVariableName(const AbstractMetaType* type) { - QString res = QString("_%1").arg(_fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper()); + QString res = QString("_%1").arg(ShibokenGenerator::fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper()); foreach (const AbstractMetaType* instantiation, type->instantiations()) { res += instantiation->isContainer() ? processInstantiationsVariableName(instantiation) - : QString("_%1").arg(_fixedCppTypeName(instantiation->cppSignature()).toUpper()); + : QString("_%1").arg(ShibokenGenerator::fixedCppTypeName(instantiation->cppSignature()).toUpper()); } return res; } @@ -2355,7 +2355,7 @@ QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass* met const AbstractMetaClass* templateBaseClass = metaClass->templateBaseClass(); if (!templateBaseClass) return QString(); - QString base = _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper(); + QString base = fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper(); QString instantiations; foreach (const AbstractMetaType* instantiation, metaClass->templateBaseClassInstantiations()) instantiations += processInstantiationsVariableName(instantiation); @@ -2370,7 +2370,7 @@ QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type) if (trueType->basicAliasedTypeEntry()) type = trueType->basicAliasedTypeEntry(); } - return QString("SBK_%1_IDX").arg(_fixedCppTypeName(type->qualifiedCppName()).toUpper()); + return QString("SBK_%1_IDX").arg(fixedCppTypeName(type->qualifiedCppName()).toUpper()); } QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type) { diff --git a/generator/shiboken/shibokengenerator.h b/generator/shiboken/shibokengenerator.h index adeb734..6ff8da5 100644 --- a/generator/shiboken/shibokengenerator.h +++ b/generator/shiboken/shibokengenerator.h @@ -284,6 +284,7 @@ class ShibokenGenerator : public Generator static QString fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative); static QString fixedCppTypeName(const AbstractMetaType* type); static QString fixedCppTypeName(const TypeEntry* type, QString typeName = QString()); + static QString fixedCppTypeName(QString typeName); static bool isNumber(QString cpythonApiName); static bool isNumber(const TypeEntry* type); diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index f2f5b54..40b4a93 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -71,6 +71,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/photon_base_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueidentity_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueduplicator_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/point_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointer_simpleobject__wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointerholder_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointf_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointvaluelist_wrapper.cpp From 87c6001c231fca460fda754a87de0cddebc873a0 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 6 Aug 2013 16:12:33 -0400 Subject: [PATCH 17/66] Implement type look-up for template instantiatons Teach translateType() to find and translate template instantiation types. Teach buildAbstractMetaTypeFromString() how to create AbstractMetaType's for the same. This suffices to recognize and translate template instantiation types. However, since redirection is not yet implemented, and adding methods directly to the instantiation is not currently working, the wrapped objects aren't of much use except as opaque handles. However, this is enough to have at least the start of a meaningful unit test, and one is accordingly added to 'sample'. Change-Id: I3aee6ece8ad769a07127ff5fdd67a7af2d05200d --- ApiExtractor/abstractmetabuilder.cpp | 59 +++++++++++++----------- ApiExtractor/typesystem.h | 5 ++ generator/shiboken/shibokengenerator.cpp | 25 ++++++++-- tests/samplebinding/pointer_test.py | 55 ++++++++++++++++++++++ 4 files changed, 115 insertions(+), 29 deletions(-) create mode 100644 tests/samplebinding/pointer_test.py diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 91367c6..8ce3882 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -416,15 +416,13 @@ bool AbstractMetaBuilder::build(QIODevice* input) ReportHandler::progress("Generating template instantiations model..."); foreach (QList entries, types->allEntries()) { foreach (TypeEntry* entry, entries) { - if (entry->isComplex()) { + if (entry->isTemplateInstantiation()) { ComplexTypeEntry *centry = static_cast(entry); - if (centry->isTemplateInstantiation()) { - AbstractMetaClass *cls = createInstantiationMetaClass(centry); - if (!cls) - continue; + AbstractMetaClass *cls = createInstantiationMetaClass(centry); + if (!cls) + continue; - addAbstractMetaClass(cls); - } + addAbstractMetaClass(cls); } } } @@ -2290,15 +2288,22 @@ AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, boo if (!type) type = TypeDatabase::instance()->findType(qualifiedName); - // 6. No? Try looking it up as a flags type + // 6. No? Try looking it up as a template type + if (!type) { + type = TypeDatabase::instance()->findTypeTemplate(qualifiedName); + if (type) + type = TypeDatabase::instance()->findType(typeInfo.instantiationName()); + } + + // 7. No? Try looking it up as a flags type if (!type) type = TypeDatabase::instance()->findFlagsType(qualifiedName); - // 7. No? Try looking it up as a container type + // 8. No? Try looking it up as a container type if (!type) type = TypeDatabase::instance()->findContainerType(name); - // 8. No? Check if the current class is a template and this type is one + // 9. No? Check if the current class is a template and this type is one // of the parameters. if (!type && m_currentClass) { QList template_args = m_currentClass->templateArguments(); @@ -2308,8 +2313,8 @@ AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, boo } } - // 9. Try finding the type by prefixing it with the current - // context and all baseclasses of the current context + // 10. Try finding the type by prefixing it with the current + // context and all baseclasses of the current context if (!type && !TypeDatabase::instance()->isClassRejected(qualifiedName) && m_currentClass && resolveScope) { QStringList contexts; contexts.append(m_currentClass->qualifiedCppName()); @@ -2322,7 +2327,7 @@ AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, boo type = TypeDatabase::instance()->findType(contexts.at(0) + "::" + qualifiedName); contexts.pop_front(); - // 10. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so + // 11. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so // enum types from there may be addressed without any scope resolution in properties. if (!contexts.size() && !subclassesDone) { contexts << "Qt"; @@ -2350,22 +2355,24 @@ AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, boo metaType->setConstant(typeInfo.is_constant); metaType->setOriginalTypeDescription(_typei.toString()); - foreach (const TypeParser::Info &ta, typeInfo.template_instantiations) { - TypeInfo info; - info.setConstant(ta.is_constant); - info.setReference(ta.is_reference); - info.setIndirections(ta.indirections); + if (!type->isTemplateInstantiation()) { + foreach (const TypeParser::Info &ta, typeInfo.template_instantiations) { + TypeInfo info; + info.setConstant(ta.is_constant); + info.setReference(ta.is_reference); + info.setIndirections(ta.indirections); - info.setFunctionPointer(false); - info.setQualifiedName(ta.instantiationName().split("::")); + info.setFunctionPointer(false); + info.setQualifiedName(ta.instantiationName().split("::")); - AbstractMetaType* targType = translateType(info, ok); - if (!(*ok)) { - delete metaType; - return 0; - } + AbstractMetaType* targType = translateType(info, ok); + if (!(*ok)) { + delete metaType; + return 0; + } - metaType->addInstantiation(targType, true); + metaType->addInstantiation(targType, true); + } } // The usage pattern *must* be decided *after* the possible template diff --git a/ApiExtractor/typesystem.h b/ApiExtractor/typesystem.h index 769757f..6377a42 100644 --- a/ApiExtractor/typesystem.h +++ b/ApiExtractor/typesystem.h @@ -883,6 +883,11 @@ class TypeEntry return false; } + virtual bool isTemplateInstantiation() const + { + return false; + } + virtual bool isNativeIdBased() const { return false; diff --git a/generator/shiboken/shibokengenerator.cpp b/generator/shiboken/shibokengenerator.cpp index 3d9cce7..c633a24 100644 --- a/generator/shiboken/shibokengenerator.cpp +++ b/generator/shiboken/shibokengenerator.cpp @@ -2075,6 +2075,7 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ if (typeString.startsWith("::")) typeString.remove(0, 2); + // Try regular types first QString adjustedTypeName = typeString; QStringList instantiatedTypes; int lpos = typeString.indexOf('<'); @@ -2101,9 +2102,8 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ TypeEntry* typeEntry = TypeDatabase::instance()->findType(adjustedTypeName); - AbstractMetaType* metaType = 0; if (typeEntry) { - metaType = new AbstractMetaType(); + AbstractMetaType* metaType = new AbstractMetaType(); metaType->setTypeEntry(typeEntry); metaType->setIndirections(indirections); metaType->setReference(isReference); @@ -2115,8 +2115,27 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ } metaType->decideUsagePattern(); m_metaTypeFromStringCache.insert(typeSignature, metaType); + return metaType; + } + + // If that fails, and the type is a template instantiation, try the unmodified + // type name, which will match template instantiation types + if (typeString != adjustedTypeName) { + if ((typeEntry = TypeDatabase::instance()->findType(typeString))) { + AbstractMetaType* metaType = new AbstractMetaType(); + metaType->setTypeEntry(typeEntry); + metaType->setIndirections(indirections); + metaType->setReference(isReference); + metaType->setConstant(isConst); + metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern); + metaType->decideUsagePattern(); + m_metaTypeFromStringCache.insert(typeSignature, metaType); + return metaType; + } } - return metaType; + + // Type was not found + return 0; } AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry) diff --git a/tests/samplebinding/pointer_test.py b/tests/samplebinding/pointer_test.py new file mode 100644 index 0000000..2d79426 --- /dev/null +++ b/tests/samplebinding/pointer_test.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2013 Kitware, Inc. +# +# This file is part of the Shiboken Python Bindings Generator project. +# +# Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +# +# Contact: PySide team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# version 2.1 as published by the Free Software Foundation. Please +# review the following information to ensure the GNU Lesser General +# Public License version 2.1 requirements will be met: +# http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +# # +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser 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 + +'''Test cases for a template pointer class.''' + +import sys +import unittest + +from sample import SimpleObject + +class TestPointer(unittest.TestCase): + '''Test cases for a template pointer class.''' + + def testRedirection(self): + # Not implemented yet + pass + + def testReferenceCounting(self): + '''Test basic wrapping of template pointer class.''' + o1 = SimpleObject.create() + o2 = SimpleObject.create() + self.assertEqual(SimpleObject.count(), 2) + del o1 + self.assertEqual(SimpleObject.count(), 1) + del o2 + self.assertEqual(SimpleObject.count(), 0) + +if __name__ == '__main__': + unittest.main() + From 8d1dfc29a718ca575c5227f23727fa6894c3b013 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 6 Aug 2013 16:57:33 -0400 Subject: [PATCH 18/66] Implement instantiation resolutions Tweak how we iterate over instantiations to have proper argument reporting, and to be cleaner and (for the second pass anyway) more efficient. Implement resolution of template arguments on instantiations. Implement redirections on template instantiations. Add unit test for redirections. Change-Id: I51ac71154cd2e8c2c82e4e1dd6305d90661ceced --- ApiExtractor/abstractmetabuilder.cpp | 117 ++++++++++++++++++++++++--- ApiExtractor/abstractmetabuilder.h | 1 + tests/samplebinding/pointer_test.py | 6 +- 3 files changed, 113 insertions(+), 11 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 8ce3882..5644daf 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -104,6 +104,15 @@ static QStringList parseTemplateType(const QString& name) { return result; } +static bool entryHasFunction(const ComplexTypeEntry *entry, const QString &signature) +{ + foreach (const FunctionModification &mod, entry->functionModifications()) { + if (mod.signature == signature) + return true; + } + return false; +} + AbstractMetaBuilder::AbstractMetaBuilder() : m_currentClass(0), m_logDirectory(QString('.')+QDir::separator()) { } @@ -413,19 +422,23 @@ bool AbstractMetaBuilder::build(QIODevice* input) } ReportHandler::flush(); - ReportHandler::progress("Generating template instantiations model..."); + QList instantiationTypes; foreach (QList entries, types->allEntries()) { foreach (TypeEntry* entry, entries) { - if (entry->isTemplateInstantiation()) { - ComplexTypeEntry *centry = static_cast(entry); - AbstractMetaClass *cls = createInstantiationMetaClass(centry); - if (!cls) - continue; - - addAbstractMetaClass(cls); - } + if (entry->isTemplateInstantiation()) + instantiationTypes << static_cast(entry); } } + + ReportHandler::setProgressReference(instantiationTypes); + foreach (ComplexTypeEntry *entry, instantiationTypes) { + ReportHandler::progress("Generating template instantiations model..."); + AbstractMetaClass *cls = createInstantiationMetaClass(entry); + if (!cls) + continue; + + addAbstractMetaClass(cls); + } ReportHandler::flush(); // We need to know all global enums @@ -474,6 +487,15 @@ bool AbstractMetaBuilder::build(QIODevice* input) foreach (NamespaceModelItem item, namespaceTypeValues) traverseNamespaceMembers(item); + // Resolve template instantiation argument types and create redirections + ReportHandler::setProgressReference(instantiationTypes); + foreach (ComplexTypeEntry *entry, instantiationTypes) { + ReportHandler::progress("Fixing template instantiations..."); + AbstractMetaClass* cls = m_metaClasses.findClass(entry->qualifiedCppName()); + traverseInstantiation(entry, cls); + } + ReportHandler::flush(); + // Global functions foreach (FunctionModelItem func, m_dom->functions()) { if (func->accessPolicy() != CodeModel::Public || func->name().startsWith("operator")) @@ -1397,6 +1419,83 @@ AbstractMetaClass* AbstractMetaBuilder::createInstantiationMetaClass(ComplexType return metaClass; } +void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, AbstractMetaClass *metaClass) +{ + // Resolve type entries of template instantiation types + QList argTypeEntries; + QHash argTypes; + int ordinal = 0; + foreach (QString argName, entry->templateArgNames()) { + TypeInfo argInfo; + argInfo.setQualifiedName(argName.split("::")); + + bool ok = false; + AbstractMetaType *argType = translateType(argInfo, &ok); + if (ok) { + argTypes.insert(ordinal, argType); + argTypeEntries << argType->typeEntry(); + } else { + ReportHandler::warning(QString("template parameter '%1' of '%2' is not known") + .arg(argName) + .arg(metaClass->name())); + } + ++ordinal; + } + entry->setTemplateArgTypes(argTypeEntries); + + QList args = entry->templateType()->args(); + Q_ASSERT(args.count() == ordinal); + + // Set up redirections + foreach (ordinal, argTypes.keys()) { + const AbstractMetaType *argType = argTypes[ordinal]; + QString accessor = args[ordinal].redirect(); + if (!accessor.isEmpty()) { + AbstractMetaClass *argClass = m_metaClasses.findClass(argType->typeEntry()->qualifiedCppName()); + if (argClass) { + foreach (AbstractMetaFunction *function, argClass->functions()) { + if (!function->isStatic() && !function->isConstructor() && !function->isPrivate()) { + QString signature = function->minimalSignature(); + if (signature.endsWith("const")) + signature = signature.left((signature.length() - 5)); + + // Generate meta function and add to meta class + QString returnType = (function->type() ? function->type()->cppSignature() : QString("void")); + bool isPublic = function->isPublic(); + AddedFunction addedFunction(signature, returnType, 0.0); + addedFunction.setAccess(isPublic ? AddedFunction::Public : AddedFunction::Protected); + addedFunction.setStatic(false); + + traverseFunction(addedFunction, metaClass); + entry->addNewFunction(addedFunction); + + // If there is not a user-defined modification of this redirection, generate a default one + if (!entryHasFunction(entry, signature)) { + FunctionModification redirect(0.0); + redirect.signature = signature; + redirect.modifiers = (isPublic ? Modification::Public : Modification::Protected); + redirect.modifiers |= Modification::CodeInjection; + + CodeSnip snip(0.0); + if (function->type()) { + snip.addCode("%RETURN_TYPE %0 = " + accessor + "%FUNCTION_NAME(%ARGUMENT_NAMES);\n"); + snip.addCode("%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);\n"); + } else { + snip.addCode(accessor + "%FUNCTION_NAME(%ARGUMENT_NAMES);\n"); + } + snip.position = CodeSnip::Beginning; + snip.language = TypeSystem::TargetLangCode; + redirect.snips.append(snip); + + entry->addFunctionModification(redirect); + } + } + } + } + } + } +} + void AbstractMetaBuilder::setupFunctionDefaults(AbstractMetaFunction* metaFunction, AbstractMetaClass *metaClass) { // Set the default value of the declaring class. This may be changed diff --git a/ApiExtractor/abstractmetabuilder.h b/ApiExtractor/abstractmetabuilder.h index 8ee549b..9a2588d 100644 --- a/ApiExtractor/abstractmetabuilder.h +++ b/ApiExtractor/abstractmetabuilder.h @@ -103,6 +103,7 @@ class AbstractMetaBuilder void addAbstractMetaClass(AbstractMetaClass *cls); AbstractMetaClass *createInstantiationMetaClass(ComplexTypeEntry *entry); + void traverseInstantiation(ComplexTypeEntry *entry, AbstractMetaClass *metaClass); AbstractMetaClass *traverseTypeAlias(TypeAliasModelItem item); AbstractMetaClass *traverseClass(ClassModelItem item); AbstractMetaClass* currentTraversedClass(ScopeModelItem item); diff --git a/tests/samplebinding/pointer_test.py b/tests/samplebinding/pointer_test.py index 2d79426..44bf765 100644 --- a/tests/samplebinding/pointer_test.py +++ b/tests/samplebinding/pointer_test.py @@ -37,8 +37,10 @@ class TestPointer(unittest.TestCase): '''Test cases for a template pointer class.''' def testRedirection(self): - # Not implemented yet - pass + '''Test method redirection on template pointer class.''' + o1 = SimpleObject.create() + o2 = SimpleObject.create() + self.assertGreater(o2.id(), o1.id()) def testReferenceCounting(self): '''Test basic wrapping of template pointer class.''' From e04cb8290b462ba3820edab168dc1e56595f3be1 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 6 Aug 2013 17:09:35 -0400 Subject: [PATCH 19/66] Fix adding functions to instantiations Add the little tiny missing piece of code that broke adding new methods to a template instantiation type. Add unit test for this. Change-Id: I4e03805d83669af3b036451845394ca7a5a95276 --- ApiExtractor/abstractmetabuilder.cpp | 2 ++ tests/samplebinding/pointer_test.py | 5 +++++ tests/samplebinding/typesystem_sample.xml | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 5644daf..a446f87 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1416,6 +1416,8 @@ AbstractMetaClass* AbstractMetaBuilder::createInstantiationMetaClass(ComplexType if (!entry->include().isValid()) setInclude(entry, entry->include().name()); + fillAddedFunctions(metaClass); + return metaClass; } diff --git a/tests/samplebinding/pointer_test.py b/tests/samplebinding/pointer_test.py index 44bf765..9754e28 100644 --- a/tests/samplebinding/pointer_test.py +++ b/tests/samplebinding/pointer_test.py @@ -42,6 +42,11 @@ def testRedirection(self): o2 = SimpleObject.create() self.assertGreater(o2.id(), o1.id()) + def testAddedMethod(self): + '''Test method redirection on template pointer class.''' + o = SimpleObject.create() + self.assertEqual(type(o.get()), SimpleObject) + def testReferenceCounting(self): '''Test basic wrapping of template pointer class.''' o1 = SimpleObject.create() diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 6db431f..983a110 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -2400,7 +2400,14 @@ - + + + + %RETURN_TYPE %0 = %CPPSELF->get(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + From faaffc5b44aeb0c5aa2b89008bd37a618fdfaedd Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Wed, 28 Aug 2013 18:39:36 -0400 Subject: [PATCH 20/66] Test resolution of typedefs of type-templates Improve type-template test case to test that Shiboken recognizes and correctly resolves typedefs of type-template instantiations. Change-Id: I613c3f1938561e8dabb25438616316e314163e7d --- tests/libsample/pointer.h | 4 ++++ tests/samplebinding/pointer_test.py | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/tests/libsample/pointer.h b/tests/libsample/pointer.h index b7084f7..e44bead 100644 --- a/tests/libsample/pointer.h +++ b/tests/libsample/pointer.h @@ -72,6 +72,9 @@ class Pointer int *m_ref; }; +class SimpleObject; +typedef Pointer SimpleObjectPointer; + class LIBSAMPLE_API SimpleObject { public: @@ -80,6 +83,7 @@ class LIBSAMPLE_API SimpleObject inline int id() const { return m_id; } static Pointer create(); + static SimpleObjectPointer createAliased() { return create(); } static int count(); private: diff --git a/tests/samplebinding/pointer_test.py b/tests/samplebinding/pointer_test.py index 9754e28..dc40948 100644 --- a/tests/samplebinding/pointer_test.py +++ b/tests/samplebinding/pointer_test.py @@ -57,6 +57,12 @@ def testReferenceCounting(self): del o2 self.assertEqual(SimpleObject.count(), 0) + def testTypeAlias(self): + '''Test that typedef of type template instantiation is recognized.''' + o1 = SimpleObject.create() + o2 = SimpleObject.createAliased() + self.assertEqual(type(o1), type(o2)) + if __name__ == '__main__': unittest.main() From 31662910ad9a7970348743f710bceb17825dff33 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 29 Aug 2013 12:42:28 -0400 Subject: [PATCH 21/66] Fix container argument resolution corner case Fix a corner case where type resolution for a container type breaks due to failing to add the template arguments, due to trailing whitespace causing resolution of the same to fail. As best I can tell, this only happens for redirector functions of type-template instantiations inside of namespaces for which the type-template is also inside of a namespace. Change-Id: Ie5934bcc03ada92c42df49e255ef6df743f9fac6 --- tests/libsample/pointer.cpp | 13 +++++++++++ tests/libsample/pointer.h | 28 +++++++++++++++++++++++ tests/samplebinding/CMakeLists.txt | 3 +++ tests/samplebinding/typesystem_sample.xml | 8 +++++++ 4 files changed, 52 insertions(+) diff --git a/tests/libsample/pointer.cpp b/tests/libsample/pointer.cpp index 9c6d6fa..ab984c5 100644 --- a/tests/libsample/pointer.cpp +++ b/tests/libsample/pointer.cpp @@ -46,3 +46,16 @@ int SimpleObject::count() { return counter; } + +std::list PointerNamespace::NamespaceObject::numbers(int first, int count) const +{ + std::list result; + while (count--) + result.push_back(first++); + return result; +} + +PointerNamespace::NamespaceObjectPointer PointerNamespace::createNamespaceObject() +{ + return NamespaceObjectPointer(new NamespaceObject); +} diff --git a/tests/libsample/pointer.h b/tests/libsample/pointer.h index e44bead..8234aa6 100644 --- a/tests/libsample/pointer.h +++ b/tests/libsample/pointer.h @@ -25,6 +25,8 @@ #ifndef POINTER_H #define POINTER_H +#include + #include "libsamplemacros.h" template @@ -92,5 +94,31 @@ class LIBSAMPLE_API SimpleObject int m_id; }; +namespace PointerNamespace +{ + +template class Pointer +{ +public: + Pointer() {} + Pointer(T* obj) : m_ptr(obj) {} + inline T* get() const { return m_ptr.get(); } + +private: + ::Pointer m_ptr; +}; + +class LIBSAMPLE_API NamespaceObject +{ +public: + ::std::list numbers(int first, int count) const; +}; + +typedef Pointer NamespaceObjectPointer; + +NamespaceObjectPointer createNamespaceObject(); + +} + #endif // POINTER_H diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index 40b4a93..86c602f 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -72,6 +72,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueidentity_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueduplicator_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/point_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointer_simpleobject__wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_namespaceobject_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_pointer_pointernamespace_namespaceobject__wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointerholder_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointf_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointvaluelist_wrapper.cpp diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 983a110..03fbd2f 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -2409,6 +2409,14 @@ + + + + + + + + From 8b8163e38a46042dde8140c72a7db27012ead307 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 29 Aug 2013 16:07:07 -0400 Subject: [PATCH 22/66] Fix scoped resolution of instantiations Modify AbstractMetaBuilder::translateType, and in particular the associated helper function findTypeEntryUsingContext, to also find type-template instantiations within a namespace scope. Change-Id: Id4408fefcb3f3badfe940f15d0f6adab9edc52a3 --- ApiExtractor/abstractmetabuilder.cpp | 13 +++++++++---- tests/libsample/pointer.h | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index a446f87..6466800 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -2254,12 +2254,16 @@ AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunct return metaType; } -static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName) +static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName, const QString& instantiationName) { const TypeEntry* type = 0; QStringList context = metaClass->qualifiedCppName().split("::"); while(!type && (context.size() > 0) ) { - type = TypeDatabase::instance()->findType(context.join("::") + "::" + qualifiedName); + const QString guess = context.join("::") + "::" + qualifiedName; + if ((type = TypeDatabase::instance()->findTypeTemplate(guess))) + type = TypeDatabase::instance()->findType(context.join("::") + "::" + instantiationName); + else + type = TypeDatabase::instance()->findType(guess); context.removeLast(); } return type; @@ -2373,12 +2377,13 @@ AbstractMetaType* AbstractMetaBuilder::translateType(const TypeInfo& _typei, boo // 5.1 - Try first using the current scope if (m_currentClass) { - type = findTypeEntryUsingContext(m_currentClass, qualifiedName); + const QString& instantiationName = typeInfo.instantiationName(); + type = findTypeEntryUsingContext(m_currentClass, qualifiedName, instantiationName); // 5.1.1 - Try using the class parents' scopes if (!type && !m_currentClass->baseClassNames().isEmpty()) { foreach (const AbstractMetaClass* cls, getBaseClasses(m_currentClass)) { - type = findTypeEntryUsingContext(cls, qualifiedName); + type = findTypeEntryUsingContext(cls, qualifiedName, instantiationName); if (type) break; } diff --git a/tests/libsample/pointer.h b/tests/libsample/pointer.h index 8234aa6..7edc0c9 100644 --- a/tests/libsample/pointer.h +++ b/tests/libsample/pointer.h @@ -116,7 +116,7 @@ class LIBSAMPLE_API NamespaceObject typedef Pointer NamespaceObjectPointer; -NamespaceObjectPointer createNamespaceObject(); +LIBSAMPLE_API NamespaceObjectPointer createNamespaceObject(); } From ea8820bd09171bc82d386b6f3e2e5b7bbfb0ca9b Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 29 Aug 2013 19:14:02 -0400 Subject: [PATCH 23/66] Fix type alias creation for instantiations Modify Binder to correctly qualify type aliases for template instantiations. This seems to mainly be a problem for type-template instantiations, but may affect regular instantiations as well. Also convert the set of qualified types to a QSet (which should be slightly less expensive than an unused QString value on a QHash). Modify the tests to exercise the newly-working resolution. This is in some ways closely related to the previous two commits, and the test updates are at least partly relevant to those also. Change-Id: I45ae5ea9573d0c9ba26dd60c3b70056d13e9868c --- ApiExtractor/parser/binder.cpp | 65 ++++++++++++++++++----- ApiExtractor/parser/binder.h | 6 ++- ApiExtractor/tests/testtemplates.cpp | 2 +- tests/libsample/pointer.cpp | 10 ++++ tests/libsample/pointer.h | 8 +++ tests/samplebinding/CMakeLists.txt | 1 + tests/samplebinding/pointer_test.py | 9 +++- tests/samplebinding/typesystem_sample.xml | 13 ++++- 8 files changed, 97 insertions(+), 17 deletions(-) diff --git a/ApiExtractor/parser/binder.cpp b/ApiExtractor/parser/binder.cpp index 64289c5..93d236f 100644 --- a/ApiExtractor/parser/binder.cpp +++ b/ApiExtractor/parser/binder.cpp @@ -33,7 +33,6 @@ #include "dumptree.h" #include -#include Binder::Binder(CodeModel *__model, LocationManager &__location, Control *__control) : _M_model(__model), @@ -45,13 +44,13 @@ Binder::Binder(CodeModel *__model, LocationManager &__location, Control *__contr name_cc(this), decl_cc(this) { - _M_qualified_types["char"] = QString(); - _M_qualified_types["double"] = QString(); - _M_qualified_types["float"] = QString(); - _M_qualified_types["int"] = QString(); - _M_qualified_types["long"] = QString(); - _M_qualified_types["short"] = QString(); - _M_qualified_types["void"] = QString(); + _M_qualified_types.insert("char"); + _M_qualified_types.insert("double"); + _M_qualified_types.insert("float"); + _M_qualified_types.insert("int"); + _M_qualified_types.insert("long"); + _M_qualified_types.insert("short"); + _M_qualified_types.insert("void"); } Binder::~Binder() @@ -521,7 +520,7 @@ void Binder::visitTypedef(TypedefAST *node) typeAlias->setName(alias_name); typeAlias->setType(qualifyType(typeInfo, currentScope()->qualifiedName())); typeAlias->setScope(typedefScope->qualifiedName()); - _M_qualified_types[typeAlias->qualifiedName().join(".")] = QString(); + addQualifiedType(typeAlias->qualifiedName()); currentScope()->addTypeAlias(typeAlias); } while (it != end); } @@ -574,7 +573,7 @@ void Binder::visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *no return; ScopeModelItem scope = currentScope(); - _M_qualified_types[(scope->qualifiedName() + name_cc.qualifiedName()).join(".")] = QString(); + addQualifiedType((scope->qualifiedName() + name_cc.qualifiedName())); } void Binder::visitClassSpecifier(ClassSpecifierAST *node) @@ -624,7 +623,7 @@ void Binder::visitClassSpecifier(ClassSpecifierAST *node) CodeModel::FunctionType oldFunctionType = changeCurrentFunctionType(CodeModel::Normal); _M_current_class->setScope(scope->qualifiedName()); - _M_qualified_types[_M_current_class->qualifiedName().join(".")] = QString(); + addQualifiedType(_M_current_class->qualifiedName()); scope->addClass(_M_current_class); @@ -673,7 +672,7 @@ void Binder::visitEnumSpecifier(EnumSpecifierAST *node) _M_current_enum->setAnonymous(isAnonymous); _M_current_enum->setScope(enumScope->qualifiedName()); - _M_qualified_types[_M_current_enum->qualifiedName().join(".")] = QString(); + addQualifiedType(_M_current_enum->qualifiedName()); enumScope->addEnum(_M_current_enum); @@ -806,6 +805,33 @@ void Binder::applyFunctionSpecifiers(const ListNode *it, FunctionMo } while (it != end); } +static QString normalizeInstantiationName(const QString &name) +{ + const int n = name.indexOf('<'); + if (n < 0) + return name; + + // Convert template arguments into a 'standard' placeholder. This isn't perfect + // because it can't hope to understand '<' / '>' used as an operator in an + // argument (assuming we don't already fall apart on those elsewhere), but should + // suffice to handle most cases. + QString result = name; + + // First remove any nested instantiation names + QRegExp nested("<([^<>]+)>"); + int i; + while ((i = nested.lastIndexIn(result)) != n) { + result.replace(i, nested.matchedLength(), "_"); + } + + // Now rebuild the name with the template arguments replaced with placeholders + QStringList args = result.split(','); + result = args[0].left(n + 1) + "_1"; + for (int a = 1; a < args.count(); ++a) + result += QString(", _%1").arg(a + 1); + return result + ">"; +} + TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) const { // ### Potentially improve to use string list in the name table to @@ -817,7 +843,9 @@ TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) c } else { QStringList expanded = context; expanded << type.qualifiedName(); - if (_M_qualified_types.contains(expanded.join("."))) { + QStringList normalized = expanded; + normalized.last() = normalizeInstantiationName(normalized.last()); + if (_M_qualified_types.contains(normalized.join("."))) { TypeInfo modified_type = type; modified_type.setQualifiedName(expanded); return modified_type; @@ -843,6 +871,17 @@ TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) c } } +void Binder::addQualifiedType(const QStringList &name) +{ + _M_qualified_types.insert(name.join(".")); + + if (name.last().contains('<')) { + QStringList normalized = name; + normalized.last() = normalizeInstantiationName(normalized.last()); + _M_qualified_types.insert(normalized.join(".")); + } +} + void Binder::updateItemPosition(CodeModelItem item, AST *node) { QString filename; diff --git a/ApiExtractor/parser/binder.h b/ApiExtractor/parser/binder.h index da1b77c..35f0f1b 100644 --- a/ApiExtractor/parser/binder.h +++ b/ApiExtractor/parser/binder.h @@ -32,6 +32,8 @@ #include "name_compiler.h" #include "declarator_compiler.h" +#include + class TokenStream; class LocationManager; class Control; @@ -98,6 +100,8 @@ class Binder: protected DefaultVisitor void updateItemPosition(CodeModelItem item, AST *node); + void addQualifiedType(const QStringList &name); + private: CodeModel *_M_model; LocationManager &_M_location; @@ -113,7 +117,7 @@ class Binder: protected DefaultVisitor EnumModelItem _M_current_enum; QStringList _M_context; TemplateParameterList _M_current_template_parameters; // ### check me - QHash _M_qualified_types; + QSet _M_qualified_types; QHash _M_anonymous_enums; protected: diff --git a/ApiExtractor/tests/testtemplates.cpp b/ApiExtractor/tests/testtemplates.cpp index 2ae4ce9..e9af7a8 100644 --- a/ApiExtractor/tests/testtemplates.cpp +++ b/ApiExtractor/tests/testtemplates.cpp @@ -324,7 +324,7 @@ void TestTemplates::testTypedefOfInstantiationOfTemplateClass() const ComplexTypeEntry* oneType = one->typeEntry(); const ComplexTypeEntry* baseType = base->typeEntry(); QCOMPARE(oneType->baseContainerType(), baseType); - QCOMPARE(one->baseClassNames(), QStringList("BaseTemplateClass")); + QCOMPARE(one->baseClassNames(), QStringList("NSpace::BaseTemplateClass")); QVERIFY(one->hasTemplateBaseClassInstantiations()); AbstractMetaTypeList instantiations = one->templateBaseClassInstantiations(); diff --git a/tests/libsample/pointer.cpp b/tests/libsample/pointer.cpp index ab984c5..642f46f 100644 --- a/tests/libsample/pointer.cpp +++ b/tests/libsample/pointer.cpp @@ -59,3 +59,13 @@ PointerNamespace::NamespaceObjectPointer PointerNamespace::createNamespaceObject { return NamespaceObjectPointer(new NamespaceObject); } + +std::list PointerHelper::numbers(const PointerNamespace::NamespaceObjectPointer& ptr, int first, int count) +{ + return ptr.get()->numbers(first, count); +} + +std::list PointerHelper::numbers(const PointerNamespace::PointerNamespaceObjectAlias& obj, int first, int count) +{ + return obj.numbers(first, count); +} diff --git a/tests/libsample/pointer.h b/tests/libsample/pointer.h index 7edc0c9..84026ac 100644 --- a/tests/libsample/pointer.h +++ b/tests/libsample/pointer.h @@ -115,10 +115,18 @@ class LIBSAMPLE_API NamespaceObject }; typedef Pointer NamespaceObjectPointer; +typedef NamespaceObject PointerNamespaceObjectAlias; LIBSAMPLE_API NamespaceObjectPointer createNamespaceObject(); } +class LIBSAMPLE_API PointerHelper +{ +public: + static ::std::list numbers(const PointerNamespace::NamespaceObjectPointer& ptr, int first, int count); + static ::std::list numbers(const PointerNamespace::PointerNamespaceObjectAlias& obj, int first, int count); +}; + #endif // POINTER_H diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index 86c602f..c385953 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -75,6 +75,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/pointer_simpleobject__wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_namespaceobject_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_pointer_pointernamespace_namespaceobject__wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointerhelper_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointerholder_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointf_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointvaluelist_wrapper.cpp diff --git a/tests/samplebinding/pointer_test.py b/tests/samplebinding/pointer_test.py index dc40948..a4db598 100644 --- a/tests/samplebinding/pointer_test.py +++ b/tests/samplebinding/pointer_test.py @@ -31,7 +31,7 @@ import sys import unittest -from sample import SimpleObject +from sample import SimpleObject, PointerNamespace, PointerHelper class TestPointer(unittest.TestCase): '''Test cases for a template pointer class.''' @@ -63,6 +63,13 @@ def testTypeAlias(self): o2 = SimpleObject.createAliased() self.assertEqual(type(o1), type(o2)) + def testTypeAlias(self): + '''Test type resolution for some namespace corner cases.''' + o = PointerNamespace.createNamespaceObject() + o.numbers + PointerHelper.numbers(o, 1, 3) + PointerHelper.numbers(o.get(), 4, 2) + if __name__ == '__main__': unittest.main() diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 03fbd2f..167c148 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -600,6 +600,8 @@ + + @@ -2415,7 +2417,16 @@ - + + + + %RETURN_TYPE %0 = %CPPSELF->get(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + From b794b3d2bb418bc21ec0aeeddb0c4758db99de6b Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Wed, 4 Sep 2013 15:11:34 -0400 Subject: [PATCH 24/66] Fix resolution of instantiation arguments Modify translateType to also try a canonicalized form of the type name. This is necessary to resolve function arguments to type-template instantiations, as the canonical instantiation name has spaces inside the <>'s, but the function argument has these stripped due to minimal signature normalization. (Return types are not normalized and so do not have this problem.) Change-Id: Ide191042c709f995a04ff7b77855c0e6f80a7d9c --- ApiExtractor/abstractmetabuilder.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 6466800..a5c959d 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -54,6 +54,11 @@ static QString stripTemplateArgs(const QString &name) int pos = name.indexOf('<'); return pos < 0 ? name : name.left(pos); } +static QString canonicalizeInstantiationName(QString name) { + name.replace(QRegExp("<([^ ])"), "< \\1"); + name.replace(QRegExp("([^ ])>"), "\\1 >"); + return name; +} static QStringList parseTemplateType(const QString& name) { int n = name.indexOf('<'); @@ -2202,6 +2207,10 @@ AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunct return 0; type = typeDb->findType(typeName); + if (!type) + type = typeDb->findType(canonicalizeInstantiationName(typeName)); + if (!type) + type = TypeDatabase::instance()->findTypeTemplate(typeName); // test if the type is a template, like a container bool isTemplate = false; From 0212dde936804d178e7d2d5b7472c2666f3f8ba9 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Wed, 4 Sep 2013 15:12:26 -0400 Subject: [PATCH 25/66] Fix instantiation naming Fix ::name of AbstractMeta{Type,Class} for type-template instantiations. These were giving odd results because namespace splitting could split on a template argument and throw out the actual type name and resulting in names like 'Object >'. This doesn't seem to obviously affect code generation (probably it works because the names are still unique for the cases we've tested so far, but would have collisions in case of more than one instantiation with the same template argument(s)), but helps with debugging when inspecting the name()s. Change-Id: I7de115b31496bf605b9f660d106ba1d6082bfe7f --- ApiExtractor/abstractmetalang.cpp | 10 +++++++++- ApiExtractor/abstractmetalang.h | 13 +++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/ApiExtractor/abstractmetalang.cpp b/ApiExtractor/abstractmetalang.cpp index 21e7793..b7432b7 100644 --- a/ApiExtractor/abstractmetalang.cpp +++ b/ApiExtractor/abstractmetalang.cpp @@ -1472,7 +1472,15 @@ bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const QString AbstractMetaClass::name() const { - return QString(m_typeEntry->targetLangName()).split("::").last(); + const QString& tlName = m_typeEntry->targetLangName(); + QStringList templateParts = tlName.split('<'); + if (templateParts.count() > 1) { + QString& templateBaseName = templateParts[0]; + templateBaseName = templateBaseName.split("::").last(); + return templateParts.join("<"); + } else { + return QString(tlName).split("::").last(); + } } void AbstractMetaClass::setBaseClass(AbstractMetaClass *baseClass) diff --git a/ApiExtractor/abstractmetalang.h b/ApiExtractor/abstractmetalang.h index 6d2366e..0736ccf 100644 --- a/ApiExtractor/abstractmetalang.h +++ b/ApiExtractor/abstractmetalang.h @@ -325,8 +325,17 @@ class AbstractMetaType } QString name() const { - if (m_name.isNull()) - m_name = m_typeEntry->targetLangName().split("::").last(); + if (m_name.isNull()) { + const QString& tlName = m_typeEntry->targetLangName(); + QStringList templateParts = tlName.split('<'); + if (templateParts.count() > 1) { + QString& templateBaseName = templateParts[0]; + templateBaseName = templateBaseName.split("::").last(); + m_name = templateParts.join("<"); + } else { + m_name = QString(tlName).split("::").last(); + } + } return m_name; } QString fullName() const From 888df1ee66b4894a6c8ee73a9637c1b8bc6c265c Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Wed, 4 Sep 2013 18:22:48 -0400 Subject: [PATCH 26/66] Omit redirections for protected members Don't generate redirections to internal class's protected members. This isn't working right, because it requires a static cast of the inner class to its wrapper to bypass the access protection, but right now the generated code is doing the cast on the outer class instead (which is otherwise the right thing to do). Since 1) it's questionable if protected methods should be exposed anyway, and 2) likely significant work to get it working, just disable it for now. Change-Id: Ia7e3aee3ffd4f670fc74735cec3248dcf8f0d2ef --- ApiExtractor/abstractmetabuilder.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index a5c959d..df96705 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1461,7 +1461,7 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac AbstractMetaClass *argClass = m_metaClasses.findClass(argType->typeEntry()->qualifiedCppName()); if (argClass) { foreach (AbstractMetaFunction *function, argClass->functions()) { - if (!function->isStatic() && !function->isConstructor() && !function->isPrivate()) { + if (!function->isStatic() && !function->isConstructor() && function->isPublic()) { QString signature = function->minimalSignature(); if (signature.endsWith("const")) signature = signature.left((signature.length() - 5)); @@ -1470,7 +1470,7 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac QString returnType = (function->type() ? function->type()->cppSignature() : QString("void")); bool isPublic = function->isPublic(); AddedFunction addedFunction(signature, returnType, 0.0); - addedFunction.setAccess(isPublic ? AddedFunction::Public : AddedFunction::Protected); + addedFunction.setAccess(AddedFunction::Public); addedFunction.setStatic(false); traverseFunction(addedFunction, metaClass); @@ -1480,7 +1480,7 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac if (!entryHasFunction(entry, signature)) { FunctionModification redirect(0.0); redirect.signature = signature; - redirect.modifiers = (isPublic ? Modification::Public : Modification::Protected); + redirect.modifiers = Modification::Public; redirect.modifiers |= Modification::CodeInjection; CodeSnip snip(0.0); From 8a920a379a3a3ee93065ea80d0aefff5192f9264 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Wed, 4 Sep 2013 18:25:20 -0400 Subject: [PATCH 27/66] Always sanitize name of wrapper classes It isn't obvious why only "inner classes" would need their names sanitized; at least within our tests, no classes that trip this flag have names that need to be sanitized. However, names of type template instantiations must always be sanitized, and there is no ready check for these at the moment, so just sanitize everything. (It may have just been for performance reasons that we weren't doing this anyway, but this shouldn't be in the critical path for that we need to be overly worried about performance here.) Change-Id: Ic13089efde9793fc5da8acd049e9d54363f5efa7 --- generator/shiboken/shibokengenerator.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/generator/shiboken/shibokengenerator.cpp b/generator/shiboken/shibokengenerator.cpp index c633a24..3b01620 100644 --- a/generator/shiboken/shibokengenerator.cpp +++ b/generator/shiboken/shibokengenerator.cpp @@ -283,16 +283,10 @@ const AbstractMetaClass* ShibokenGenerator::getProperEnclosingClassForEnum(const QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const { - if (shouldGenerateCppWrapper(metaClass)) { - QString result = metaClass->name(); - if (metaClass->enclosingClass()) // is a inner class - result = fixedCppTypeName(result); - - result +="Wrapper"; - return result; - } else { + if (shouldGenerateCppWrapper(metaClass)) + return fixedCppTypeName(metaClass->name()) + "Wrapper"; + else return metaClass->qualifiedCppName(); - } } QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func) From 5f9ac1aee1eed5cf55bb82f2a5e891fdaf429fdf Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 5 Sep 2013 15:00:15 -0400 Subject: [PATCH 28/66] Use qualified name for wrapper class name When generating wrapper classes, use the mangled qualified name instead of just the base name. This is required to avoid symbol collisions in the case of wrapping two classes with the same name in different namespaces. This doesn't "really" belong on this branch, as it applies to Shiboken in general, however it effectively depends on the mangling that was added here, and especially the previous commit, where we changed to always mangle the wrapper name. Change-Id: I276a97b4eac4385307a94159437ee4757d88a196 --- generator/shiboken/shibokengenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generator/shiboken/shibokengenerator.cpp b/generator/shiboken/shibokengenerator.cpp index 3b01620..bc0df25 100644 --- a/generator/shiboken/shibokengenerator.cpp +++ b/generator/shiboken/shibokengenerator.cpp @@ -284,7 +284,7 @@ const AbstractMetaClass* ShibokenGenerator::getProperEnclosingClassForEnum(const QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const { if (shouldGenerateCppWrapper(metaClass)) - return fixedCppTypeName(metaClass->name()) + "Wrapper"; + return fixedCppTypeName(metaClass->qualifiedCppName()) + "Wrapper"; else return metaClass->qualifiedCppName(); } From e7ee10a47267a61084db4e110014f616157ee2b0 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Mon, 16 Sep 2013 16:15:59 -0400 Subject: [PATCH 29/66] Support type-template function modifications Modify typesystem parser to (partly) set the correct context for function additions/modifications to type-template. Modify AbstractMetaBuilder::createInstantiationMetaClass to add functions from the type template to the instantiation. This is only partly complete; template argument types are not yet supported as types in the function. Change-Id: Ie6369d2facf3bcd642e9a2a51cbb107046e9094d --- ApiExtractor/abstractmetabuilder.cpp | 2 ++ ApiExtractor/typesystem.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index df96705..5751500 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1422,6 +1422,8 @@ AbstractMetaClass* AbstractMetaBuilder::createInstantiationMetaClass(ComplexType setInclude(entry, entry->include().name()); fillAddedFunctions(metaClass); + foreach (AddedFunction addedFunc, metaClass->typeEntry()->templateType()->addedFunctions()) + traverseFunction(addedFunc, metaClass); return metaClass; } diff --git a/ApiExtractor/typesystem.cpp b/ApiExtractor/typesystem.cpp index 48843a2..03a2275 100644 --- a/ApiExtractor/typesystem.cpp +++ b/ApiExtractor/typesystem.cpp @@ -264,6 +264,7 @@ bool Handler::endElement(const QString &, const QString &localName, const QStrin } if (m_current->type == StackElement::Root + || m_current->type == StackElement::TypeTemplate || m_current->type == StackElement::NamespaceTypeEntry || m_current->type == StackElement::InterfaceTypeEntry || m_current->type == StackElement::ObjectTypeEntry @@ -495,6 +496,7 @@ bool Handler::startElement(const QString &, const QString &n, customConversionsForReview.clear(); if (element->type == StackElement::Root + || element->type == StackElement::TypeTemplate || element->type == StackElement::NamespaceTypeEntry || element->type == StackElement::InterfaceTypeEntry || element->type == StackElement::ObjectTypeEntry From 5cac414801ddda9177a49ffca2cc5bcf5f14c226 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 17 Sep 2013 12:13:32 -0400 Subject: [PATCH 30/66] Remove unneeded code Don't bother adding redirection functions to the instantiation type entry; they are only needed for adding the functions to the abstract meta objects, which we are doing anyway, and are not needed by the generate phase, so adding them to the type entry also is superfluous. Change-Id: I81adc0a3e4d460e98c4a9849da6bbafe65f1ad61 --- ApiExtractor/abstractmetabuilder.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 5751500..861787a 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1476,7 +1476,6 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac addedFunction.setStatic(false); traverseFunction(addedFunction, metaClass); - entry->addNewFunction(addedFunction); // If there is not a user-defined modification of this redirection, generate a default one if (!entryHasFunction(entry, signature)) { From fadb8c8c36b91e8ee7e19a04f97471fef9c2a4ae Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 17 Sep 2013 13:26:50 -0400 Subject: [PATCH 31/66] Fix type resolution for type-template functions Modify type resolution of function modifications to accept a mapping of template arguments, in order to support e.g. '%INTYPE_0' as return and/or argument types to functions. This is relevant to function modifications declared on type templates. An example of such is added to the sample binding, however there is no test yet, as functions added to instantiations via type templates are not being added correctly at the moment. (This will be fixed in the next commit.) Change-Id: I8875354547aae2d56d66b5697f1672287717c7b0 --- ApiExtractor/abstractmetabuilder.cpp | 47 ++++++++++++++++++----- ApiExtractor/abstractmetabuilder.h | 5 ++- ApiExtractor/typesystem.cpp | 2 +- tests/samplebinding/typesystem_sample.xml | 13 +++++++ 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 861787a..11e3de6 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1422,8 +1422,6 @@ AbstractMetaClass* AbstractMetaBuilder::createInstantiationMetaClass(ComplexType setInclude(entry, entry->include().name()); fillAddedFunctions(metaClass); - foreach (AddedFunction addedFunc, metaClass->typeEntry()->templateType()->addedFunctions()) - traverseFunction(addedFunc, metaClass); return metaClass; } @@ -1455,6 +1453,10 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac QList args = entry->templateType()->args(); Q_ASSERT(args.count() == ordinal); + // Add functions from the type template + foreach (AddedFunction addedFunc, metaClass->typeEntry()->templateType()->addedFunctions()) + traverseFunction(addedFunc, metaClass, argTypes); + // Set up redirections foreach (ordinal, argTypes.keys()) { const AbstractMetaType *argType = argTypes[ordinal]; @@ -1881,12 +1883,8 @@ void AbstractMetaBuilder::traverseEnums(ScopeModelItem scopeItem, AbstractMetaCl } } -AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& addedFunc) -{ - return traverseFunction(addedFunc, 0); -} - -AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& addedFunc, AbstractMetaClass* metaClass) +AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& addedFunc, AbstractMetaClass* metaClass, + const QHash &templateArgs) { AbstractMetaFunction* metaFunction = createMetaFunction(); metaFunction->setConstant(addedFunc.isConstant()); @@ -1897,7 +1895,7 @@ AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& metaFunction->setUserAdded(true); AbstractMetaAttributes::Attribute isStatic = addedFunc.isStatic() ? AbstractMetaFunction::Static : AbstractMetaFunction::None; metaFunction->setAttributes(metaFunction->attributes() | AbstractMetaAttributes::Final | isStatic); - metaFunction->setType(translateType(addedFunc.version(), addedFunc.returnType())); + metaFunction->setType(translateType(addedFunc.version(), addedFunc.returnType(), templateArgs)); QList args = addedFunc.arguments(); @@ -1906,7 +1904,7 @@ AbstractMetaFunction* AbstractMetaBuilder::traverseFunction(const AddedFunction& for (int i = 0; i < args.count(); ++i) { AddedFunction::TypeInfo& typeInfo = args[i]; AbstractMetaArgument* metaArg = createMetaArgument(); - AbstractMetaType* type = translateType(addedFunc.version(), typeInfo); + AbstractMetaType* type = translateType(addedFunc.version(), typeInfo, templateArgs); decideUsagePattern(type); metaArg->setType(type); metaArg->setArgumentIndex(i); @@ -2264,6 +2262,35 @@ AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunct return metaType; } +AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunction::TypeInfo& typeInfo, const QHash< int, AbstractMetaType* >& templateArgs) +{ + if (!templateArgs.isEmpty()) { + // Resolve references to template argument types + QHash::const_iterator iter, end = templateArgs.constEnd(); + for (iter = templateArgs.begin(); iter != end; ++iter) { + if (typeInfo.name == QString("%INTYPE_%1").arg(iter.key())) { + if (iter.value()) { + // Make a copy of the template argument type, and set appropriate indirections + AbstractMetaType* metaType = createMetaType(); + metaType->setTypeEntry(iter.value()->typeEntry()); + metaType->setIndirections(typeInfo.indirections); + metaType->setReference(typeInfo.isReference); + metaType->setConstant(typeInfo.isConstant); + foreach (AbstractMetaType* instantation, iter.value()->instantiations()) { + AbstractMetaType* metaArgType = createMetaType(); + metaArgType->setTypeEntry(instantation->typeEntry()); + metaType->addInstantiation(metaArgType); + } + metaType->setTypeUsagePattern(iter.value()->typeUsagePattern()); + return metaType; + } + return 0; // type is 'void' + } + } + } + return translateType(vr, typeInfo); +} + static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName, const QString& instantiationName) { const TypeEntry* type = 0; diff --git a/ApiExtractor/abstractmetabuilder.h b/ApiExtractor/abstractmetabuilder.h index 9a2588d..0a75d5e 100644 --- a/ApiExtractor/abstractmetabuilder.h +++ b/ApiExtractor/abstractmetabuilder.h @@ -119,8 +119,8 @@ class AbstractMetaBuilder void traverseFields(ScopeModelItem item, AbstractMetaClass *parent); void traverseStreamOperator(FunctionModelItem functionItem); void traverseOperatorFunction(FunctionModelItem item); - AbstractMetaFunction* traverseFunction(const AddedFunction& addedFunc); - AbstractMetaFunction* traverseFunction(const AddedFunction& addedFunc, AbstractMetaClass* metaClass); + AbstractMetaFunction* traverseFunction(const AddedFunction& addedFunc, AbstractMetaClass* metaClass = 0, + const QHash &templateArgs = QHash()); AbstractMetaFunction *traverseFunction(FunctionModelItem function); AbstractMetaField *traverseField(VariableModelItem field, const AbstractMetaClass *cls); void checkFunctionModifications(); @@ -150,6 +150,7 @@ class AbstractMetaBuilder AbstractMetaFunction *fnc, AbstractMetaClass *, int argumentIndex); AbstractMetaType* translateType(double vr, const AddedFunction::TypeInfo& typeInfo); + AbstractMetaType* translateType(double vr, const AddedFunction::TypeInfo& typeInfo, const QHash &templateArgs); AbstractMetaType *translateType(const TypeInfo &type, bool *ok, bool resolveType = true, bool resolveScope = true); int findOutValueFromString(const QString& stringValue, bool& ok); diff --git a/ApiExtractor/typesystem.cpp b/ApiExtractor/typesystem.cpp index 03a2275..67b946b 100644 --- a/ApiExtractor/typesystem.cpp +++ b/ApiExtractor/typesystem.cpp @@ -2197,7 +2197,7 @@ bool FunctionModification::operator==(const FunctionModification& other) const static AddedFunction::TypeInfo parseType(const QString& signature, int startPos = 0, int* endPos = 0) { AddedFunction::TypeInfo result; - QRegExp regex("\\w"); + QRegExp regex("%?\\w"); int length = signature.length(); int start = signature.indexOf(regex, startPos); if (start == -1) { diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 167c148..48e02c9 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -2400,6 +2400,19 @@ + + + %RETURN_TYPE %0 = %CPPSELF->get(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + + + %INTYPE_0* ptr = %CPPSELF->get(); + %RETURN_TYPE %0 = !!ptr; + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + From a3a2adad6c922eced350cf181418bce081048876 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Tue, 17 Sep 2013 13:34:55 -0400 Subject: [PATCH 32/66] Fix type template function additions Fix the code to add functions from type templates to instantiations to also copy the code modifications. This fixes the functions being generated with 'empty' bodies as explained in the previous commit. Update the unit test to call these, now that they are useful. Change-Id: I29527973e87cfe7aaf8b5769eb0aa7e7c36ba61f --- ApiExtractor/abstractmetabuilder.cpp | 28 +++++++++++++++++++++++++--- tests/samplebinding/pointer_test.py | 4 +++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 11e3de6..ab0e1a5 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1453,9 +1453,31 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac QList args = entry->templateType()->args(); Q_ASSERT(args.count() == ordinal); - // Add functions from the type template - foreach (AddedFunction addedFunc, metaClass->typeEntry()->templateType()->addedFunctions()) - traverseFunction(addedFunc, metaClass, argTypes); + // Add functions and modifications from the type template + foreach (AddedFunction addedFunction, metaClass->typeEntry()->templateType()->addedFunctions()) + traverseFunction(addedFunction, metaClass, argTypes); + + foreach (FunctionModification modification, metaClass->typeEntry()->templateType()->functionModifications()) { + FunctionModification resolvedModification(modification); + resolvedModification.snips.clear(); + + // Resolve template types in code snips + foreach (const CodeSnip &snip, modification.snips) { + CodeSnip resolvedSnip(snip); + resolvedSnip.codeList.clear(); + + QString code = snip.code(); + QHash::const_iterator iter, end = argTypes.constEnd(); + for (iter = argTypes.begin(); iter != end; ++iter) { + code.replace(QRegExp(QString("%INTYPE_%1\\b").arg(iter.key())), + iter.value()->typeEntry()->qualifiedCppName()); + } + + resolvedSnip.addCode(code); + resolvedModification.snips.append(resolvedSnip); + } + entry->addFunctionModification(resolvedModification); + } // Set up redirections foreach (ordinal, argTypes.keys()) { diff --git a/tests/samplebinding/pointer_test.py b/tests/samplebinding/pointer_test.py index a4db598..c11202f 100644 --- a/tests/samplebinding/pointer_test.py +++ b/tests/samplebinding/pointer_test.py @@ -42,10 +42,12 @@ def testRedirection(self): o2 = SimpleObject.create() self.assertGreater(o2.id(), o1.id()) - def testAddedMethod(self): + def testAddedMethods(self): '''Test method redirection on template pointer class.''' o = SimpleObject.create() self.assertEqual(type(o.get()), SimpleObject) + self.assertEqual(type(o.template_get()), SimpleObject) + self.assertTrue(o.valid()) def testReferenceCounting(self): '''Test basic wrapping of template pointer class.''' From 60673f5e62ee807dda8416f0a88951fb940893d5 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 19 Sep 2013 16:25:24 -0400 Subject: [PATCH 33/66] Fix late resolution of instantiation arguments Modify ShibokenGenerator::buildAbstractMetaTypeFromString to canonicalize type names before trying to look up instantiations. Move canonicalization function to AbstractMetaClass, and use when returning the name of template instantiation classes. This should ensure that everyone is looking at the same form of the type name. This fixes a crash or assertion (depending on whether the type appears by itself, or as a template type in a container-type) due to failure to look up the type when it is used in code snippets. Change-Id: Ic090138a9db9a3acbbd93a9015e07a9504080fd4 --- ApiExtractor/abstractmetabuilder.cpp | 7 +------ ApiExtractor/abstractmetalang.cpp | 9 ++++++++- ApiExtractor/abstractmetalang.h | 2 ++ generator/shiboken/shibokengenerator.cpp | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index ab0e1a5..acd9bb2 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -54,11 +54,6 @@ static QString stripTemplateArgs(const QString &name) int pos = name.indexOf('<'); return pos < 0 ? name : name.left(pos); } -static QString canonicalizeInstantiationName(QString name) { - name.replace(QRegExp("<([^ ])"), "< \\1"); - name.replace(QRegExp("([^ ])>"), "\\1 >"); - return name; -} static QStringList parseTemplateType(const QString& name) { int n = name.indexOf('<'); @@ -2229,7 +2224,7 @@ AbstractMetaType* AbstractMetaBuilder::translateType(double vr, const AddedFunct type = typeDb->findType(typeName); if (!type) - type = typeDb->findType(canonicalizeInstantiationName(typeName)); + type = typeDb->findType(AbstractMetaClass::canonicalizeInstantiationName(typeName)); if (!type) type = TypeDatabase::instance()->findTypeTemplate(typeName); diff --git a/ApiExtractor/abstractmetalang.cpp b/ApiExtractor/abstractmetalang.cpp index b7432b7..47a6fe1 100644 --- a/ApiExtractor/abstractmetalang.cpp +++ b/ApiExtractor/abstractmetalang.cpp @@ -1469,6 +1469,13 @@ bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const return false; } +QString AbstractMetaClass::canonicalizeInstantiationName(QString name) +{ + name.replace(QRegExp("\\s+"), " "); + name.replace(QRegExp("<([^ ])"), "< \\1"); + name.replace(QRegExp("([^ ])>"), "\\1 >"); + return name; +} QString AbstractMetaClass::name() const { @@ -1477,7 +1484,7 @@ QString AbstractMetaClass::name() const if (templateParts.count() > 1) { QString& templateBaseName = templateParts[0]; templateBaseName = templateBaseName.split("::").last(); - return templateParts.join("<"); + return canonicalizeInstantiationName(templateParts.join("<")); } else { return QString(tlName).split("::").last(); } diff --git a/ApiExtractor/abstractmetalang.h b/ApiExtractor/abstractmetalang.h index 0736ccf..329ef57 100644 --- a/ApiExtractor/abstractmetalang.h +++ b/ApiExtractor/abstractmetalang.h @@ -1574,6 +1574,8 @@ class AbstractMetaClass : public AbstractMetaAttributes return package() + "." + name(); } + static QString canonicalizeInstantiationName(QString); + /** * Retrieves the class name without any namespace/scope information. * /return the class name without scope information diff --git a/generator/shiboken/shibokengenerator.cpp b/generator/shiboken/shibokengenerator.cpp index bc0df25..11928e8 100644 --- a/generator/shiboken/shibokengenerator.cpp +++ b/generator/shiboken/shibokengenerator.cpp @@ -2115,7 +2115,7 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ // If that fails, and the type is a template instantiation, try the unmodified // type name, which will match template instantiation types if (typeString != adjustedTypeName) { - if ((typeEntry = TypeDatabase::instance()->findType(typeString))) { + if ((typeEntry = TypeDatabase::instance()->findType(AbstractMetaClass::canonicalizeInstantiationName(typeString)))) { AbstractMetaType* metaType = new AbstractMetaType(); metaType->setTypeEntry(typeEntry); metaType->setIndirections(indirections); From 40d167ccdc735ea365eaf131d79aaa815b39e232 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 19 Sep 2013 16:30:20 -0400 Subject: [PATCH 34/66] Reject container types with unknown arguments Modify ShibokenGenerator::buildAbstractMetaTypeFromString to explicitly reject container types if resolution of a template argument type fails. This prevents us crashing later due to the type having an instantiation type that is null. (We still exit abnormally, but at least now there is a useful error message as to why.) Change-Id: Ief704a7f9d1f50867fc904a5c397435136af9017 --- generator/shiboken/shibokengenerator.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/generator/shiboken/shibokengenerator.cpp b/generator/shiboken/shibokengenerator.cpp index 11928e8..c57b3e0 100644 --- a/generator/shiboken/shibokengenerator.cpp +++ b/generator/shiboken/shibokengenerator.cpp @@ -2105,6 +2105,11 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern); foreach (const QString& instantiation, instantiatedTypes) { AbstractMetaType* tmplArgType = buildAbstractMetaTypeFromString(instantiation); + if (!tmplArgType) { + qFatal(qPrintable(QString("Could not find template argument type '%1' in type '%2'. " + "Make sure to use the full C++ name, e.g. 'Namespace::Class'.") + .arg(instantiation).arg(typeSignature)), NULL); + } metaType->addInstantiation(tmplArgType); } metaType->decideUsagePattern(); From 48462f92be02f070a36c26f12a367f4d997e43e4 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 19 Sep 2013 17:58:51 -0400 Subject: [PATCH 35/66] Fix redirections of base class methods Move parsing of instantiation types to after base classes have been otherwise resolved. Remove resolves argument types from TypeEntry (nothing outside of AbstractMetaBuilder::traverseInstantiation was using them, and they're first determined in traverseInstantiation and so don't need to be stored). Move setting up redirections to its own helper method so that it can be called recursively to also set up redirections for the base class and other interface classes (and do so). The sample binding is accordingly updated to test generation of redirections of base class members. Change-Id: Ifb89e0e1c14b7788d1839ec4cf30476012cf832b --- ApiExtractor/abstractmetabuilder.cpp | 117 +++++++++++++--------- ApiExtractor/abstractmetabuilder.h | 1 + ApiExtractor/typesystem.h | 10 -- tests/libsample/pointer.h | 11 +- tests/samplebinding/CMakeLists.txt | 1 + tests/samplebinding/pointer_test.py | 1 + tests/samplebinding/typesystem_sample.xml | 1 + 7 files changed, 82 insertions(+), 60 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index acd9bb2..048d9b1 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -487,15 +487,6 @@ bool AbstractMetaBuilder::build(QIODevice* input) foreach (NamespaceModelItem item, namespaceTypeValues) traverseNamespaceMembers(item); - // Resolve template instantiation argument types and create redirections - ReportHandler::setProgressReference(instantiationTypes); - foreach (ComplexTypeEntry *entry, instantiationTypes) { - ReportHandler::progress("Fixing template instantiations..."); - AbstractMetaClass* cls = m_metaClasses.findClass(entry->qualifiedCppName()); - traverseInstantiation(entry, cls); - } - ReportHandler::flush(); - // Global functions foreach (FunctionModelItem func, m_dom->functions()) { if (func->accessPolicy() != CodeModel::Public || func->name().startsWith("operator")) @@ -532,6 +523,17 @@ bool AbstractMetaBuilder::build(QIODevice* input) } ReportHandler::flush(); + // Resolve template instantiation argument types and set up functions on + // the same, including redirections and function modifications from the + // type-template. + ReportHandler::setProgressReference(instantiationTypes); + foreach (ComplexTypeEntry *entry, instantiationTypes) { + ReportHandler::progress("Fixing template instantiations..."); + AbstractMetaClass* cls = m_metaClasses.findClass(entry->qualifiedCppName()); + traverseInstantiation(entry, cls); + } + ReportHandler::flush(); + ReportHandler::setProgressReference(m_metaClasses); foreach (AbstractMetaClass* cls, m_metaClasses) { ReportHandler::progress("Detecting inconsistencies in class model..."); @@ -1443,10 +1445,9 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac } ++ordinal; } - entry->setTemplateArgTypes(argTypeEntries); QList args = entry->templateType()->args(); - Q_ASSERT(args.count() == ordinal); + Q_ASSERT(args.count() == argTypes.count()); // Add functions and modifications from the type template foreach (AddedFunction addedFunction, metaClass->typeEntry()->templateType()->addedFunctions()) @@ -1463,7 +1464,7 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac QString code = snip.code(); QHash::const_iterator iter, end = argTypes.constEnd(); - for (iter = argTypes.begin(); iter != end; ++iter) { + for (iter = argTypes.constBegin(); iter != end; ++iter) { code.replace(QRegExp(QString("%INTYPE_%1\\b").arg(iter.key())), iter.value()->typeEntry()->qualifiedCppName()); } @@ -1475,49 +1476,67 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac } // Set up redirections - foreach (ordinal, argTypes.keys()) { + foreach (int ordinal, argTypes.keys()) { const AbstractMetaType *argType = argTypes[ordinal]; QString accessor = args[ordinal].redirect(); if (!accessor.isEmpty()) { AbstractMetaClass *argClass = m_metaClasses.findClass(argType->typeEntry()->qualifiedCppName()); - if (argClass) { - foreach (AbstractMetaFunction *function, argClass->functions()) { - if (!function->isStatic() && !function->isConstructor() && function->isPublic()) { - QString signature = function->minimalSignature(); - if (signature.endsWith("const")) - signature = signature.left((signature.length() - 5)); - - // Generate meta function and add to meta class - QString returnType = (function->type() ? function->type()->cppSignature() : QString("void")); - bool isPublic = function->isPublic(); - AddedFunction addedFunction(signature, returnType, 0.0); - addedFunction.setAccess(AddedFunction::Public); - addedFunction.setStatic(false); - - traverseFunction(addedFunction, metaClass); - - // If there is not a user-defined modification of this redirection, generate a default one - if (!entryHasFunction(entry, signature)) { - FunctionModification redirect(0.0); - redirect.signature = signature; - redirect.modifiers = Modification::Public; - redirect.modifiers |= Modification::CodeInjection; - - CodeSnip snip(0.0); - if (function->type()) { - snip.addCode("%RETURN_TYPE %0 = " + accessor + "%FUNCTION_NAME(%ARGUMENT_NAMES);\n"); - snip.addCode("%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);\n"); - } else { - snip.addCode(accessor + "%FUNCTION_NAME(%ARGUMENT_NAMES);\n"); - } - snip.position = CodeSnip::Beginning; - snip.language = TypeSystem::TargetLangCode; - redirect.snips.append(snip); + if (!argClass) { + ReportHandler::warning(QString("template argument '%1' of '%2' is not known; not adding redirections") + .arg(argType->typeEntry()->qualifiedCppName()) + .arg(metaClass->name())); + continue; + } - entry->addFunctionModification(redirect); - } - } + addRedirections(entry, metaClass, argClass, accessor); + } + } +} + +void AbstractMetaBuilder::addRedirections(ComplexTypeEntry *entry, AbstractMetaClass* metaClass, AbstractMetaClass* fromClass, const QString &accessor) +{ + // Add redirections from the class's primary base class + if (fromClass->baseClass()) + addRedirections(entry, metaClass, fromClass->baseClass(), accessor); + + // Add redirections from the class's interfaces + foreach (AbstractMetaClass *iface, fromClass->interfaces()) + addRedirections(entry, metaClass, iface, accessor); + + // Add redirections from the class itself + foreach (AbstractMetaFunction *function, fromClass->functions()) { + if (!function->isStatic() && !function->isConstructor() && function->isPublic()) { + QString signature = function->minimalSignature(); + if (signature.endsWith("const")) + signature = signature.left((signature.length() - 5)); + + // Generate meta function and add to meta class + QString returnType = (function->type() ? function->type()->cppSignature() : QString("void")); + AddedFunction addedFunction(signature, returnType, 0.0); + addedFunction.setAccess(AddedFunction::Public); + addedFunction.setStatic(false); + + traverseFunction(addedFunction, metaClass); + + // If there is not a user-defined modification of this redirection, generate a default one + if (!entryHasFunction(entry, signature)) { + FunctionModification redirect(0.0); + redirect.signature = signature; + redirect.modifiers = Modification::Public; + redirect.modifiers |= Modification::CodeInjection; + + CodeSnip snip(0.0); + if (function->type()) { + snip.addCode("%RETURN_TYPE %0 = " + accessor + "%FUNCTION_NAME(%ARGUMENT_NAMES);\n"); + snip.addCode("%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0);\n"); + } else { + snip.addCode(accessor + "%FUNCTION_NAME(%ARGUMENT_NAMES);\n"); } + snip.position = CodeSnip::Beginning; + snip.language = TypeSystem::TargetLangCode; + redirect.snips.append(snip); + + entry->addFunctionModification(redirect); } } } diff --git a/ApiExtractor/abstractmetabuilder.h b/ApiExtractor/abstractmetabuilder.h index 0a75d5e..acec69a 100644 --- a/ApiExtractor/abstractmetabuilder.h +++ b/ApiExtractor/abstractmetabuilder.h @@ -104,6 +104,7 @@ class AbstractMetaBuilder void addAbstractMetaClass(AbstractMetaClass *cls); AbstractMetaClass *createInstantiationMetaClass(ComplexTypeEntry *entry); void traverseInstantiation(ComplexTypeEntry *entry, AbstractMetaClass *metaClass); + void addRedirections(ComplexTypeEntry *entry, AbstractMetaClass* metaClass, AbstractMetaClass* fromClass, const QString &accessor); AbstractMetaClass *traverseTypeAlias(TypeAliasModelItem item); AbstractMetaClass *traverseClass(ClassModelItem item); AbstractMetaClass* currentTraversedClass(ScopeModelItem item); diff --git a/ApiExtractor/typesystem.h b/ApiExtractor/typesystem.h index 6377a42..cb72d3f 100644 --- a/ApiExtractor/typesystem.h +++ b/ApiExtractor/typesystem.h @@ -1670,15 +1670,6 @@ class ComplexTypeEntry : public TypeEntry return m_templateType; } - void setTemplateArgTypes(QList templateArgs) - { - m_templateArgTypes = templateArgs; - } - QList templateArgTypes() const - { - return m_templateArgTypes; - } - QString defaultConstructor() const; void setDefaultConstructor(const QString& defaultConstructor); bool hasDefaultConstructor() const; @@ -1710,7 +1701,6 @@ class ComplexTypeEntry : public TypeEntry QStringList m_templateArgNames; const TypeTemplateEntry *m_templateType; - QList m_templateArgTypes; }; class ContainerTypeEntry : public ComplexTypeEntry diff --git a/tests/libsample/pointer.h b/tests/libsample/pointer.h index 84026ac..9c232d6 100644 --- a/tests/libsample/pointer.h +++ b/tests/libsample/pointer.h @@ -74,10 +74,19 @@ class Pointer int *m_ref; }; +class SimpleObjectBase +{ +public: + inline int square(int value) { return value * value; } + +protected: + SimpleObjectBase() {} +}; + class SimpleObject; typedef Pointer SimpleObjectPointer; -class LIBSAMPLE_API SimpleObject +class LIBSAMPLE_API SimpleObject : public SimpleObjectBase { public: ~SimpleObject(); diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index c385953..d83ed7e 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -105,6 +105,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_derivedfromnamespace_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/simplefile_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/simpleobject_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/simpleobjectbase_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/size_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/sizef_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/sonofmderived1_wrapper.cpp diff --git a/tests/samplebinding/pointer_test.py b/tests/samplebinding/pointer_test.py index c11202f..ff111e5 100644 --- a/tests/samplebinding/pointer_test.py +++ b/tests/samplebinding/pointer_test.py @@ -41,6 +41,7 @@ def testRedirection(self): o1 = SimpleObject.create() o2 = SimpleObject.create() self.assertGreater(o2.id(), o1.id()) + self.assertEqual(o1.square(2), 4) def testAddedMethods(self): '''Test method redirection on template pointer class.''' diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 48e02c9..fe45229 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -2414,6 +2414,7 @@ + From 6db96dbfacbc199ed6e4ccb698ee2910166db5e8 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Fri, 20 Sep 2013 12:14:35 -0400 Subject: [PATCH 36/66] Fix creation of duplicate redirections Change processing of redirections to bind redirections starting with the most derived class, rather than the other way around, and to ignore method signatures that have already been bound. This prevents us adding the same signature more than once, which confuses the overload resolution and produces generated code with build errors. Note that this isn't quite right as it doesn't account for the usual shadowing rules. While this in and of itself would not be hard to implement, it would possibly cause more harm than good given that we don't appear to parse 'using' declarations, and so would tend to drop more methods than we should in real life code. Change-Id: Ic19776f283153d30b2f1bd56d7969fd535750b26 --- ApiExtractor/abstractmetabuilder.cpp | 29 ++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 048d9b1..3e7f935 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -113,6 +113,15 @@ static bool entryHasFunction(const ComplexTypeEntry *entry, const QString &signa return false; } +static bool classHasFunction(const AbstractMetaClass *metaClass, const QString &minimalSignature) +{ + foreach (const AbstractMetaFunction *function, metaClass->functions()) { + if (function->minimalSignature() == minimalSignature) + return true; + } + return false; +} + AbstractMetaBuilder::AbstractMetaBuilder() : m_currentClass(0), m_logDirectory(QString('.')+QDir::separator()) { } @@ -1495,14 +1504,6 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac void AbstractMetaBuilder::addRedirections(ComplexTypeEntry *entry, AbstractMetaClass* metaClass, AbstractMetaClass* fromClass, const QString &accessor) { - // Add redirections from the class's primary base class - if (fromClass->baseClass()) - addRedirections(entry, metaClass, fromClass->baseClass(), accessor); - - // Add redirections from the class's interfaces - foreach (AbstractMetaClass *iface, fromClass->interfaces()) - addRedirections(entry, metaClass, iface, accessor); - // Add redirections from the class itself foreach (AbstractMetaFunction *function, fromClass->functions()) { if (!function->isStatic() && !function->isConstructor() && function->isPublic()) { @@ -1510,6 +1511,10 @@ void AbstractMetaBuilder::addRedirections(ComplexTypeEntry *entry, AbstractMetaC if (signature.endsWith("const")) signature = signature.left((signature.length() - 5)); + // Skip function if it already exists (e.g. overloaded virtuals or shadowed methods) + if (classHasFunction(metaClass, signature)) + continue; + // Generate meta function and add to meta class QString returnType = (function->type() ? function->type()->cppSignature() : QString("void")); AddedFunction addedFunction(signature, returnType, 0.0); @@ -1540,6 +1545,14 @@ void AbstractMetaBuilder::addRedirections(ComplexTypeEntry *entry, AbstractMetaC } } } + + // Add redirections from the class's primary base class + if (fromClass->baseClass()) + addRedirections(entry, metaClass, fromClass->baseClass(), accessor); + + // Add redirections from the class's interfaces + foreach (AbstractMetaClass *iface, fromClass->interfaces()) + addRedirections(entry, metaClass, iface, accessor); } void AbstractMetaBuilder::setupFunctionDefaults(AbstractMetaFunction* metaFunction, AbstractMetaClass *metaClass) From 76854eedb6a6db6cfe1118b715cc42d68b237de4 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 16 Sep 2013 17:00:28 -0400 Subject: [PATCH 37/66] Improve pointer-like template wrapping Using "wrap-pointer-as" informs the wrapping code that the type-template wraps another type as a pointer and can be retrieved via the code in the attribute's value. This implies "redirect" if it is not set and also adds implicit conversion to Python's None if the pointer is null. --- ApiExtractor/typesystem.cpp | 14 +++++++++++++- ApiExtractor/typesystem.h | 11 +++++++++++ generator/shiboken/cppgenerator.cpp | 10 ++++++++++ tests/samplebinding/typesystem_sample.xml | 2 +- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/ApiExtractor/typesystem.cpp b/ApiExtractor/typesystem.cpp index 67b946b..fce56d8 100644 --- a/ApiExtractor/typesystem.cpp +++ b/ApiExtractor/typesystem.cpp @@ -1135,6 +1135,7 @@ bool Handler::startElement(const QString &, const QString &n, break; case StackElement::Argument: attributes["redirect"] = QString(); + attributes["wraps-pointer-as"] = QString(); break; case StackElement::ReferenceCount: attributes["action"] = QString(); @@ -1896,7 +1897,18 @@ bool Handler::startElement(const QString &, const QString &n, return false; } TypeTemplateEntry *tentry = static_cast(topElement.entry); - tentry->addArg(attributes["redirect"]); + const QString &wrapsPointerAs = attributes["wraps-pointer-as"]; + QString redirect = attributes["redirect"]; + if (!wrapsPointerAs.isEmpty()) { + if (!tentry->wrapsPointerAs().isEmpty()) { + m_error = "Template types can only wrap a single type argument as a pointer."; + return false; + } + tentry->setWrapsPointerAs(wrapsPointerAs); + if (redirect.isEmpty()) + redirect = wrapsPointerAs + "->"; + } + tentry->addArg(redirect); } case StackElement::Template: element->value.templateEntry = new TemplateEntry(attributes["name"], since); diff --git a/ApiExtractor/typesystem.h b/ApiExtractor/typesystem.h index cb72d3f..7e1c110 100644 --- a/ApiExtractor/typesystem.h +++ b/ApiExtractor/typesystem.h @@ -1793,6 +1793,16 @@ class TypeTemplateEntry : public ComplexTypeEntry return m_args; } + QString wrapsPointerAs() const + { + return m_wrapsPointerAs; + } + + void setWrapsPointerAs(const QString &wrapsPointerAs) + { + m_wrapsPointerAs = wrapsPointerAs; + } + void addArg(const QString &redirect) { m_args << Argument(redirect); @@ -1800,6 +1810,7 @@ class TypeTemplateEntry : public ComplexTypeEntry private: QList m_args; + QString m_wrapsPointerAs; }; typedef QHash TypeTemplateEntryHash; diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index ff6457f..a9c9399 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -989,6 +989,16 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla } c << INDENT << '}' << endl; c << INDENT << "const char* typeName = typeid(*((" << typeName << "*)cppIn)).name();" << endl; + const TypeTemplateEntry *typeTemplate = metaClass->typeEntry()->templateType(); + if (typeTemplate && !typeTemplate->wrapsPointerAs().isEmpty()) + { + c << INDENT << "if (*reinterpret_cast< " << typeName << "* >(cppIn)) {" << endl; + { + Indentation indent(INDENT); + c << INDENT << "Py_RETURN_NONE;" << endl; + } + c << INDENT << "}" << endl; + } c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType; c << ", const_cast(cppIn), false, false, typeName);"; } diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index fe45229..c2ec5d3 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -2429,7 +2429,7 @@ - + From a6fdc410174fa91655d898fecdac9ba23f0d2f43 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 18 Sep 2013 12:35:12 -0400 Subject: [PATCH 38/66] Add a 'const' in the reinterpret_cast --- generator/shiboken/cppgenerator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index a9c9399..79d579d 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -992,7 +992,8 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla const TypeTemplateEntry *typeTemplate = metaClass->typeEntry()->templateType(); if (typeTemplate && !typeTemplate->wrapsPointerAs().isEmpty()) { - c << INDENT << "if (*reinterpret_cast< " << typeName << "* >(cppIn)) {" << endl; + const QString &cppSelfCode = QString("(reinterpret_cast< const %1 * >(cppIn))").arg(typeName); + c << INDENT << "if (" << typeTemplate->wrapsPointerAs().replace("%CPPSELF", cppSelfCode) << ") {" << endl; { Indentation indent(INDENT); c << INDENT << "Py_RETURN_NONE;" << endl; From ad050f90a0fc1ab7fe2506433191cd9d116277a5 Mon Sep 17 00:00:00 2001 From: John Tourtellott Date: Mon, 23 Sep 2013 18:08:56 -0400 Subject: [PATCH 39/66] Add conversion to python None in the C++ to Python copy conversion function --- generator/shiboken/cppgenerator.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index 79d579d..ba38e97 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -993,7 +993,7 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla if (typeTemplate && !typeTemplate->wrapsPointerAs().isEmpty()) { const QString &cppSelfCode = QString("(reinterpret_cast< const %1 * >(cppIn))").arg(typeName); - c << INDENT << "if (" << typeTemplate->wrapsPointerAs().replace("%CPPSELF", cppSelfCode) << ") {" << endl; + c << INDENT << "if (!" << typeTemplate->wrapsPointerAs().replace("%CPPSELF", cppSelfCode) << ") {" << endl; { Indentation indent(INDENT); c << INDENT << "Py_RETURN_NONE;" << endl; @@ -1017,6 +1017,20 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla sourceTypeName = QString("%1_COPY").arg(fixedCppTypeName(metaClass->name())); targetTypeName = fixedCppTypeName(metaClass->name()); code.clear(); + + // For wrapped pointers, checks internal pointer and returns None if not instantiated + const TypeTemplateEntry *typeTemplate = metaClass->typeEntry()->templateType(); + if (typeTemplate && !typeTemplate->wrapsPointerAs().isEmpty()) + { + const QString &cppSelfCode = QString("(reinterpret_cast< const %1 * >(cppIn))").arg(typeName); + c << INDENT << "if (!" << typeTemplate->wrapsPointerAs().replace("%CPPSELF", cppSelfCode) << ") {" << endl; + { + Indentation indent(INDENT); + c << INDENT << "Py_RETURN_NONE;" << endl; + } + c << INDENT << "}" << endl; + } + c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << wrapperName(metaClass); c << "(*((" << typeName << "*)cppIn)), true, true);"; writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); From 9f68e949868b9764b3d970aaea64be170569dc7e Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 1 Oct 2013 16:41:26 -0400 Subject: [PATCH 40/66] Add test for wraps-pointer-as inheritance --- tests/libsample/pointer.cpp | 5 +++++ tests/libsample/pointer.h | 7 +++++++ tests/samplebinding/CMakeLists.txt | 2 ++ tests/samplebinding/pointer_test.py | 10 ++++++++++ tests/samplebinding/typesystem_sample.xml | 9 +++++++++ 5 files changed, 33 insertions(+) diff --git a/tests/libsample/pointer.cpp b/tests/libsample/pointer.cpp index 642f46f..646d539 100644 --- a/tests/libsample/pointer.cpp +++ b/tests/libsample/pointer.cpp @@ -60,6 +60,11 @@ PointerNamespace::NamespaceObjectPointer PointerNamespace::createNamespaceObject return NamespaceObjectPointer(new NamespaceObject); } +PointerNamespace::InheritNamespaceObjectPointer PointerNamespace::createInheritNamespaceObject() +{ + return InheritNamespaceObjectPointer(new InheritNamespaceObject); +} + std::list PointerHelper::numbers(const PointerNamespace::NamespaceObjectPointer& ptr, int first, int count) { return ptr.get()->numbers(first, count); diff --git a/tests/libsample/pointer.h b/tests/libsample/pointer.h index 9c232d6..59c5a45 100644 --- a/tests/libsample/pointer.h +++ b/tests/libsample/pointer.h @@ -123,10 +123,17 @@ class LIBSAMPLE_API NamespaceObject ::std::list numbers(int first, int count) const; }; +class LIBSAMPLE_API InheritNamespaceObject : public NamespaceObject +{ +}; + typedef Pointer NamespaceObjectPointer; +typedef Pointer InheritNamespaceObjectPointer; typedef NamespaceObject PointerNamespaceObjectAlias; +typedef InheritNamespaceObject PointerInheritNamespaceObjectAlias; LIBSAMPLE_API NamespaceObjectPointer createNamespaceObject(); +LIBSAMPLE_API InheritNamespaceObjectPointer createInheritNamespaceObject(); } diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index d83ed7e..673fd56 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -75,6 +75,8 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/pointer_simpleobject__wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_namespaceobject_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_pointer_pointernamespace_namespaceobject__wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_inheritnamespaceobject_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointernamespace_pointer_pointernamespace_inheritnamespaceobject__wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointerhelper_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointerholder_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/pointf_wrapper.cpp diff --git a/tests/samplebinding/pointer_test.py b/tests/samplebinding/pointer_test.py index ff111e5..6c46db5 100644 --- a/tests/samplebinding/pointer_test.py +++ b/tests/samplebinding/pointer_test.py @@ -73,6 +73,16 @@ def testTypeAlias(self): PointerHelper.numbers(o, 1, 3) PointerHelper.numbers(o.get(), 4, 2) + def testInheritMethods(self): + '''Test method redirection on template pointer class to inherited methods.''' + o = PointerNamespace.createInheritNamespaceObject() + # Test that base class members are available. + o.numbers(1, 2) + # Test that the raw pointer downcast is implicit. + PointerHelper.numbers(o.get(), 4, 2) + # Test that the wrapping pointer downcast is implicit as well. + PointerHelper.numbers(o, 1, 3) + if __name__ == '__main__': unittest.main() diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index c2ec5d3..eb3768f 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -2427,6 +2427,7 @@ + @@ -2439,6 +2440,14 @@ + + + + %RETURN_TYPE %0 = %CPPSELF->get(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + + + From 5912b32529811f00ebb8c627ba0228c0b005e8d6 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 2 Oct 2013 15:00:59 -0400 Subject: [PATCH 41/66] Support adding a base class to a metaclass --- ApiExtractor/abstractmetalang.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ApiExtractor/abstractmetalang.h b/ApiExtractor/abstractmetalang.h index 329ef57..164e951 100644 --- a/ApiExtractor/abstractmetalang.h +++ b/ApiExtractor/abstractmetalang.h @@ -1719,6 +1719,11 @@ class AbstractMetaClass : public AbstractMetaAttributes return m_baseClassNames; } + void addBaseClassName(const QString &name) + { + m_baseClassNames.append(name); + } + void setBaseClassNames(const QStringList &names) { m_baseClassNames = names; From 77b0af47eacf780398e3fb70c2d7d88424fcbf17 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 2 Oct 2013 15:01:17 -0400 Subject: [PATCH 42/66] Store the pointer argument index --- ApiExtractor/typesystem.cpp | 2 +- ApiExtractor/typesystem.h | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ApiExtractor/typesystem.cpp b/ApiExtractor/typesystem.cpp index fce56d8..81de5f9 100644 --- a/ApiExtractor/typesystem.cpp +++ b/ApiExtractor/typesystem.cpp @@ -1904,7 +1904,7 @@ bool Handler::startElement(const QString &, const QString &n, m_error = "Template types can only wrap a single type argument as a pointer."; return false; } - tentry->setWrapsPointerAs(wrapsPointerAs); + tentry->setWrapsPointerAs(wrapsPointerAs, tentry->args().size()); if (redirect.isEmpty()) redirect = wrapsPointerAs + "->"; } diff --git a/ApiExtractor/typesystem.h b/ApiExtractor/typesystem.h index 7e1c110..753113c 100644 --- a/ApiExtractor/typesystem.h +++ b/ApiExtractor/typesystem.h @@ -1798,9 +1798,15 @@ class TypeTemplateEntry : public ComplexTypeEntry return m_wrapsPointerAs; } - void setWrapsPointerAs(const QString &wrapsPointerAs) + int wrapsPointerArg() const + { + return m_wrapsPointerArg; + } + + void setWrapsPointerAs(const QString &wrapsPointerAs, int arg) { m_wrapsPointerAs = wrapsPointerAs; + m_wrapsPointerArg = arg; } void addArg(const QString &redirect) @@ -1811,6 +1817,7 @@ class TypeTemplateEntry : public ComplexTypeEntry private: QList m_args; QString m_wrapsPointerAs; + int m_wrapsPointerArg; }; typedef QHash TypeTemplateEntryHash; From 59481390e28f99849c13efa72d39bed6f9095bad Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 2 Oct 2013 15:01:30 -0400 Subject: [PATCH 43/66] Output base class information piecemeal --- generator/shiboken/cppgenerator.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index ba38e97..265ebc1 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -4341,23 +4341,23 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m if ((avoidProtectedHack() && metaClass->hasProtectedDestructor()) || classTypeEntry->isValue()) dtorClassName = wrapperName(metaClass); s << ", &Shiboken::callCppDestructor< ::" << dtorClassName << " >"; - } else if (metaClass->baseClass() || hasEnclosingClass) { + } else s << ", 0"; - } // Base type - if (metaClass->baseClass()) { + if (metaClass->baseClass()) s << ", (SbkObjectType*)" << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()); - // The other base types - if (metaClass->baseClassNames().size() > 1) - s << ", " << pyTypeBasesVariable; - else if (hasEnclosingClass) - s << ", 0"; - } else if (hasEnclosingClass) { - s << ", 0, 0"; - } + else + s << ", 0"; + // The other base types + if (metaClass->baseClassNames().size() > 1) + s << ", " << pyTypeBasesVariable; + else + s << ", 0"; if (hasEnclosingClass) s << ", true"; + else + s << ", false"; s << ")) {" << endl; s << INDENT << "return;" << endl; } From 24daa8862750b6e27b65d3d328d8a20a37c8c997 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 26 Sep 2013 17:20:00 -0400 Subject: [PATCH 44/66] Make wraps-pointer-as inherit over the wrapped type This marks ptr as inheriting from ptr if B inherits from A and ptr is marked as wraps-pointer-as for T. --- ApiExtractor/abstractmetabuilder.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 3e7f935..99d11a0 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1455,6 +1455,7 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac ++ordinal; } + bool wrapsPointer = !entry->templateType()->wrapsPointerAs().isEmpty(); QList args = entry->templateType()->args(); Q_ASSERT(args.count() == argTypes.count()); @@ -1498,6 +1499,28 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac } addRedirections(entry, metaClass, argClass, accessor); + + if (wrapsPointer + && entry->templateType()->wrapsPointerArg() == ordinal + && !argClass->baseClassName().isEmpty()) { + QStringList argList = parseTemplateType(metaClass->name()); + QString templateClass = argList.takeFirst(); + argList[ordinal] = argClass->baseClass()->qualifiedCppName(); + QString baseTemplateClass = QString("%1< %2 >").arg(templateClass).arg(argList.join(", ")); + + AbstractMetaClass* baseMetaClass = m_metaClasses.findClass(baseTemplateClass); + + if (baseMetaClass) { + if (metaClass->baseClass()) + metaClass->addBaseClassName(baseTemplateClass); + else + metaClass->setBaseClass(baseMetaClass); + } else { + QString warn = QString("want to inherit %1 from same class with arg %2 replaced with %3, but it is an unknown type.") + .arg(metaClass->name()).arg(ordinal).arg(argClass->baseClass()->qualifiedCppName()); + ReportHandler::warning(warn); + } + } } } } From 1f52db3fef7129f13148ac1728311ef27a7cad4b Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 2 Oct 2013 16:10:12 -0400 Subject: [PATCH 45/66] Check the baseClasses variable for its size Checking the baseClassNames for its size is pointless since everything is run off of the size of baseClasses anyways. --- generator/shiboken/cppgenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index 265ebc1..6d172f1 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -4313,7 +4313,7 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m // Multiple inheritance QString pyTypeBasesVariable = QString("%1_bases").arg(pyTypeName); const AbstractMetaClassList baseClasses = getBaseClasses(metaClass); - if (metaClass->baseClassNames().size() > 1) { + if (!baseClasses.isEmpty()) { s << INDENT << "PyObject* " << pyTypeBasesVariable << " = PyTuple_Pack(" << baseClasses.size() << ',' << endl; QStringList bases; foreach (const AbstractMetaClass* base, baseClasses) @@ -4350,7 +4350,7 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m else s << ", 0"; // The other base types - if (metaClass->baseClassNames().size() > 1) + if (!baseClasses.isEmpty()) s << ", " << pyTypeBasesVariable; else s << ", 0"; From 2a3990634c0a33b4c79d3f7fb63e9b52048c7e60 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 8 Oct 2013 13:59:53 -0400 Subject: [PATCH 46/66] Set the base class if it is not already set --- ApiExtractor/abstractmetabuilder.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 99d11a0..3f56fb5 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1511,10 +1511,9 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac AbstractMetaClass* baseMetaClass = m_metaClasses.findClass(baseTemplateClass); if (baseMetaClass) { - if (metaClass->baseClass()) - metaClass->addBaseClassName(baseTemplateClass); - else + if (!metaClass->baseClass()) metaClass->setBaseClass(baseMetaClass); + metaClass->addBaseClassName(baseTemplateClass); } else { QString warn = QString("want to inherit %1 from same class with arg %2 replaced with %3, but it is an unknown type.") .arg(metaClass->name()).arg(ordinal).arg(argClass->baseClass()->qualifiedCppName()); From 34440203a4108139ed3f02c4b11601982533384b Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 8 Oct 2013 14:00:06 -0400 Subject: [PATCH 47/66] Use the qualified name of the base class --- ApiExtractor/abstractmetabuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 3f56fb5..521d827 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1503,7 +1503,7 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac if (wrapsPointer && entry->templateType()->wrapsPointerArg() == ordinal && !argClass->baseClassName().isEmpty()) { - QStringList argList = parseTemplateType(metaClass->name()); + QStringList argList = parseTemplateType(metaClass->qualifiedCppName()); QString templateClass = argList.takeFirst(); argList[ordinal] = argClass->baseClass()->qualifiedCppName(); QString baseTemplateClass = QString("%1< %2 >").arg(templateClass).arg(argList.join(", ")); From b3cd80614c565ba76b7f7016ca1b559ea4c5232a Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 8 Oct 2013 14:00:37 -0400 Subject: [PATCH 48/66] Mark a metaclass which has injected dependencies --- ApiExtractor/abstractmetabuilder.cpp | 2 ++ ApiExtractor/abstractmetalang.h | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 521d827..6fad04d 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -1511,6 +1511,8 @@ void AbstractMetaBuilder::traverseInstantiation(ComplexTypeEntry *entry, Abstrac AbstractMetaClass* baseMetaClass = m_metaClasses.findClass(baseTemplateClass); if (baseMetaClass) { + metaClass->setHasInjectedDependencies(); + baseMetaClass->setHasInjectedDependencies(); if (!metaClass->baseClass()) metaClass->setBaseClass(baseMetaClass); metaClass->addBaseClassName(baseTemplateClass); diff --git a/ApiExtractor/abstractmetalang.h b/ApiExtractor/abstractmetalang.h index 164e951..3a63bfb 100644 --- a/ApiExtractor/abstractmetalang.h +++ b/ApiExtractor/abstractmetalang.h @@ -1428,7 +1428,8 @@ class AbstractMetaClass : public AbstractMetaAttributes m_extractedInterface(0), m_primaryInterfaceImplementor(0), m_typeEntry(0), - m_stream(false) + m_stream(false), + m_hasInjectedDependencies(false) { } @@ -1700,6 +1701,21 @@ class AbstractMetaClass : public AbstractMetaAttributes */ bool hasProtectedMembers() const; + /** + * Tells if this class has dependencies injected by the metabuilder. + * \return true if the class has injected dependencies. + */ + bool hasInjectedDependencies() const + { + return m_hasInjectedDependencies; + } + /** + * Tell the metaclass that it has injected dependencies. + */ + void setHasInjectedDependencies() + { + m_hasInjectedDependencies = true; + } QList templateArguments() const { @@ -1971,6 +1987,7 @@ class AbstractMetaClass : public AbstractMetaAttributes // FunctionModelItem m_qDebugStreamFunction; bool m_stream; + bool m_hasInjectedDependencies; static int m_count; }; From 5315776ca18150931dbcf01a02502f9c597b39c3 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 8 Oct 2013 14:00:54 -0400 Subject: [PATCH 49/66] Sort classes with injected dependencies --- ApiExtractor/abstractmetabuilder.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 6fad04d..97dac62 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -3224,6 +3224,10 @@ AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted(const Abstra QRegExp regex1("\\(.*\\)"); QRegExp regex2("::.*"); foreach (AbstractMetaClass* clazz, classList) { + if (!clazz->hasInjectedDependencies() && + (clazz->isInterface() || !clazz->typeEntry()->generateCode())) + continue; + if (clazz->enclosingClass() && map.contains(clazz->enclosingClass()->qualifiedCppName())) graph.addEdge(map[clazz->enclosingClass()->qualifiedCppName()], map[clazz->qualifiedCppName()]); From eac1bab8e5e9a8b16f433dcf9b6cbb25dec27afb Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 8 Oct 2013 14:01:21 -0400 Subject: [PATCH 50/66] Look up full names when sorting --- ApiExtractor/abstractmetabuilder.cpp | 6 +++--- ApiExtractor/abstractmetabuilder.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 97dac62..5f22acd 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -2802,12 +2802,12 @@ AbstractMetaClass* AbstractMetaBuilder::findTemplateClass(const QString& name, c return 0; } -AbstractMetaClassList AbstractMetaBuilder::getBaseClasses(const AbstractMetaClass* metaClass) const +AbstractMetaClassList AbstractMetaBuilder::getBaseClasses(const AbstractMetaClass* metaClass, bool useTemplate) const { AbstractMetaClassList baseClasses; foreach (const QString& parent, metaClass->baseClassNames()) { AbstractMetaClass* cls = 0; - if (parent.contains('<')) + if (useTemplate && parent.contains('<')) cls = findTemplateClass(parent, metaClass); else cls = m_metaClasses.findClass(parent); @@ -3231,7 +3231,7 @@ AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted(const Abstra if (clazz->enclosingClass() && map.contains(clazz->enclosingClass()->qualifiedCppName())) graph.addEdge(map[clazz->enclosingClass()->qualifiedCppName()], map[clazz->qualifiedCppName()]); - AbstractMetaClassList bases = getBaseClasses(clazz); + AbstractMetaClassList bases = getBaseClasses(clazz, false); foreach(AbstractMetaClass* baseClass, bases) { // Fix polymorphic expression if (clazz->baseClass() == baseClass) diff --git a/ApiExtractor/abstractmetabuilder.h b/ApiExtractor/abstractmetabuilder.h index acec69a..fcd4da4 100644 --- a/ApiExtractor/abstractmetabuilder.h +++ b/ApiExtractor/abstractmetabuilder.h @@ -170,7 +170,7 @@ class AbstractMetaBuilder AbstractMetaClass *findTemplateClass(const QString& name, const AbstractMetaClass *context, TypeParser::Info *info = 0, ComplexTypeEntry **baseContainerType = 0) const; - AbstractMetaClassList getBaseClasses(const AbstractMetaClass* metaClass) const; + AbstractMetaClassList getBaseClasses(const AbstractMetaClass* metaClass, bool useTemplate = true) const; bool ancestorHasPrivateCopyConstructor(const AbstractMetaClass* metaClass) const; bool inheritTemplate(AbstractMetaClass *subclass, From 86477e53393fd5c7c627268e55842cd31b117b6a Mon Sep 17 00:00:00 2001 From: Jacob Becker Date: Wed, 25 Sep 2013 14:18:46 -0400 Subject: [PATCH 51/66] fix a compilation error in mac This is actually a work around for a known gcc bug --- ApiExtractor/abstractmetabuilder.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ApiExtractor/abstractmetabuilder.h b/ApiExtractor/abstractmetabuilder.h index fcd4da4..ef1abb7 100644 --- a/ApiExtractor/abstractmetabuilder.h +++ b/ApiExtractor/abstractmetabuilder.h @@ -37,6 +37,7 @@ class TypeDatabase; class AbstractMetaBuilder { public: + typedef QHash IntAbstractMetaHash; enum RejectReason { NotInTypeSystem, GenerationDisabled, @@ -121,7 +122,7 @@ class AbstractMetaBuilder void traverseStreamOperator(FunctionModelItem functionItem); void traverseOperatorFunction(FunctionModelItem item); AbstractMetaFunction* traverseFunction(const AddedFunction& addedFunc, AbstractMetaClass* metaClass = 0, - const QHash &templateArgs = QHash()); + const IntAbstractMetaHash &templateArgs = IntAbstractMetaHash()); AbstractMetaFunction *traverseFunction(FunctionModelItem function); AbstractMetaField *traverseField(VariableModelItem field, const AbstractMetaClass *cls); void checkFunctionModifications(); From bc7152b86630a3e4097d74e54a0f805116051037 Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Thu, 29 Aug 2013 11:26:02 -0400 Subject: [PATCH 52/66] Remove output to cerr that looks to be left over debugging code. --- ApiExtractor/parser/rpp/pp-engine-bits.h | 1 - 1 file changed, 1 deletion(-) diff --git a/ApiExtractor/parser/rpp/pp-engine-bits.h b/ApiExtractor/parser/rpp/pp-engine-bits.h index a15059e..9a6f184 100644 --- a/ApiExtractor/parser/rpp/pp-engine-bits.h +++ b/ApiExtractor/parser/rpp/pp-engine-bits.h @@ -290,7 +290,6 @@ inline FILE *pp::find_include_file(std::string const &__input_filename, std::str __filepath->append(__input_filename.substr(0, slashPos)); __filepath->append(".framework/Headers/"); __filepath->append(__input_filename.substr(slashPos + 1, std::string::npos)); - std::cerr << *__filepath << "\n"; if (file_exists(*__filepath) && !file_isdir(*__filepath)) return fopen(__filepath->c_str(), "r"); From 9348940e1bc522da027afbd6c23b29a16512c860 Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Thu, 15 Aug 2013 09:42:16 -0400 Subject: [PATCH 53/66] Correctly assign m_handle to ptr. --- tests/libsample/handle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libsample/handle.h b/tests/libsample/handle.h index 403fc54..d010d01 100644 --- a/tests/libsample/handle.h +++ b/tests/libsample/handle.h @@ -42,7 +42,7 @@ class LIBSAMPLE_API HandleHolder explicit HandleHolder(HANDLE ptr = 0) : m_handle(ptr) {} explicit HandleHolder(Foo::HANDLE val): m_handle2(val) {} - inline void set(HANDLE ptr) { m_handle = m_handle; } + inline void set(HANDLE ptr) { m_handle = ptr; } inline void set(const Foo::HANDLE& val) { m_handle2 = val; } inline HANDLE handle() { return m_handle; } inline Foo::HANDLE handle2() { return m_handle2; } From c4c321988a5b11c0dc9a790f82e7ba6dbc9674fd Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Thu, 15 Aug 2013 09:42:39 -0400 Subject: [PATCH 54/66] Correct forward declare of SbkObject to be of type struct. sbkObject is a struct, but was forward declared as a class. --- libshiboken/autodecref.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libshiboken/autodecref.h b/libshiboken/autodecref.h index 5de614c..bc60bd0 100644 --- a/libshiboken/autodecref.h +++ b/libshiboken/autodecref.h @@ -26,7 +26,7 @@ #include "sbkpython.h" #include "shibokenmacros.h" -class SbkObject; +struct SbkObject; namespace Shiboken { From 32b682c1951160261a7db21872a30837111f69cf Mon Sep 17 00:00:00 2001 From: Jacob Becker Date: Thu, 17 Oct 2013 18:18:38 -0400 Subject: [PATCH 55/66] add setting install_name_dir property --- libshiboken/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/libshiboken/CMakeLists.txt b/libshiboken/CMakeLists.txt index c8575e7..20d8909 100644 --- a/libshiboken/CMakeLists.txt +++ b/libshiboken/CMakeLists.txt @@ -48,6 +48,7 @@ target_link_libraries(libshiboken ${SBK_PYTHON_LIBRARIES}) set_target_properties(libshiboken PROPERTIES OUTPUT_NAME "shiboken${shiboken_SUFFIX}${PYTHON_SUFFIX}" VERSION ${libshiboken_VERSION} SOVERSION ${libshiboken_SOVERSION} + INSTALL_NAME_DIR "${LIB_INSTALL_DIR}" DEFINE_SYMBOL LIBSHIBOKEN_EXPORTS) install(FILES From 549528f268b00b84692d0acd15ea11a86dfd21c5 Mon Sep 17 00:00:00 2001 From: Jacob Becker Date: Wed, 23 Oct 2013 21:26:14 -0400 Subject: [PATCH 56/66] add rpath so libshiboken can be found when in same dir --- shibokenmodule/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shibokenmodule/CMakeLists.txt b/shibokenmodule/CMakeLists.txt index 41b20cd..be37871 100644 --- a/shibokenmodule/CMakeLists.txt +++ b/shibokenmodule/CMakeLists.txt @@ -22,6 +22,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} add_library(shibokenmodule MODULE ${sample_SRC}) set_property(TARGET shibokenmodule PROPERTY PREFIX "") set_property(TARGET shibokenmodule PROPERTY OUTPUT_NAME "shiboken") +set_property(TARGET shibokenmodule PROPERTY INSTALL_RPATH "\$ORIGIN") if(WIN32) set_property(TARGET shibokenmodule PROPERTY SUFFIX ".pyd") endif() @@ -31,4 +32,4 @@ target_link_libraries(shibokenmodule add_dependencies(shibokenmodule shiboken) -install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}) \ No newline at end of file +install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}) From 2bb65242ec808ae51d5f3eb2aa205fc68649e900 Mon Sep 17 00:00:00 2001 From: Jacob Becker Date: Thu, 24 Oct 2013 15:39:21 -0400 Subject: [PATCH 57/66] add control and protection --- shibokenmodule/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/shibokenmodule/CMakeLists.txt b/shibokenmodule/CMakeLists.txt index be37871..acdf071 100644 --- a/shibokenmodule/CMakeLists.txt +++ b/shibokenmodule/CMakeLists.txt @@ -22,7 +22,11 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} add_library(shibokenmodule MODULE ${sample_SRC}) set_property(TARGET shibokenmodule PROPERTY PREFIX "") set_property(TARGET shibokenmodule PROPERTY OUTPUT_NAME "shiboken") -set_property(TARGET shibokenmodule PROPERTY INSTALL_RPATH "\$ORIGIN") + +option(SET_RPATH "Set the rvalue to be the origin (used in UNIX)." FALSE) +if(UNIX AND NOT APPLE AND SET_RPATH) + set_property(TARGET shibokenmodule PROPERTY INSTALL_RPATH "\$ORIGIN") +endif() if(WIN32) set_property(TARGET shibokenmodule PROPERTY SUFFIX ".pyd") endif() From a997bb032a0a416b25844adfac08c0e205c0608e Mon Sep 17 00:00:00 2001 From: David Thompson Date: Mon, 11 Nov 2013 15:24:37 -0500 Subject: [PATCH 58/66] Fix for Mavericks (and other systems using libc++). On Mavericks and other systems using libc++, only C++11 support is provided. Some things, including the hash class, are moved from the tr1 namespace to std. This patch is adapted from [homebrew pull 23867](https://github.com/mxcl/homebrew/pull/23867). --- ext/sparsehash/google/sparsehash/sparseconfig.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ext/sparsehash/google/sparsehash/sparseconfig.h b/ext/sparsehash/google/sparsehash/sparseconfig.h index 5073639..792cc34 100644 --- a/ext/sparsehash/google/sparsehash/sparseconfig.h +++ b/ext/sparsehash/google/sparsehash/sparseconfig.h @@ -13,9 +13,11 @@ #define HASH_NAMESPACE stdext /* The system-provided hash function including the namespace. */ #define SPARSEHASH_HASH HASH_NAMESPACE::hash_compare -/* libc++ does not implement the tr1 namespce, instead the - * equivalient functionality is placed in namespace std, - * so use when it targeting such systems (OS X 10.7 onwards) */ + +/* libc++ does not implement the tr1 namespace as it provides + * only C++11 support; instead of tr1, the equivalent functionality + * is placed in namespace std, so use when it targeting such + * systems (OS X 10.7 onwards, various Linux distributions) */ #elif defined(_LIBCPP_VERSION) /* the location of the header defining hash functions */ #define HASH_FUN_H From abc5a7b29b6fe534242780a599e9bf53fd2efab2 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Sat, 7 Dec 2013 11:24:00 -0500 Subject: [PATCH 59/66] Eliminate warnings in headers and generated code. These changes allow shiboken-generated code to be compiled with more aggressive warning-reporting enabled (e.g., "-Wall -Wextra"). There are still a few initialization warnings but this patch eliminates the majority of warnings on Darwin+clang. --- generator/shiboken/cppgenerator.cpp | 13 +++++++++---- libshiboken/conversions.h | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index 6d172f1..b85bf95 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -325,8 +325,8 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl s << "static PyMethodDef " << className << "_methods[] = {" << endl; s << methodsDefinitions << endl; if (metaClass->typeEntry()->isValue()) - s << INDENT << "{\"__copy__\", (PyCFunction)" << className << "___copy__" << ", METH_NOARGS}," << endl; - s << INDENT << "{0} // Sentinel" << endl; + s << INDENT << "{\"__copy__\", (PyCFunction)" << className << "___copy__" << ", METH_NOARGS, NULL}," << endl; + s << INDENT << "{NULL, NULL, 0, NULL} // Sentinel" << endl; s << "};" << endl << endl; // Write tp_getattro function @@ -409,9 +409,11 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl s << INDENT << "{const_cast(\"" << metaField->name() << "\"), "; s << cpythonGetterFunctionName(metaField); s << ", " << (hasSetter ? cpythonSetterFunctionName(metaField) : "0"); + s << ", NULL"; // TODO: documentation string goes here + s << ", NULL"; // TODO: closure goes here s << "}," << endl; } - s << INDENT << "{0} // Sentinel" << endl; + s << INDENT << "{NULL, NULL, NULL, NULL, NULL} // Sentinel" << endl; s << "};" << endl << endl; } @@ -1273,6 +1275,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream& s, OverloadData& over bool initPythonArguments; bool usesNamedArguments; + s << "(void)" << PYTHON_SELF_VAR << ";\n"; // Avoid warnings when self is unused. // If method is a constructor... if (rfunc->isConstructor()) { // Check if the right constructor was called. @@ -1335,6 +1338,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun s << "static int" << endl; s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* args, PyObject* kwds)" << endl; s << '{' << endl; + s << "(void)kwds;" << endl; // Avoid warnings when kwd is unused. QSet argNamesSet; if (usePySideExtensions() && metaClass->isQObject()) { @@ -3969,6 +3973,7 @@ void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMeta } if (func->ownerClass() && overloadData.hasStaticFunction()) s << "|METH_STATIC"; + s << ", NULL"; } void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads) @@ -4748,7 +4753,7 @@ void CppGenerator::finishGeneration() s << "static PyMethodDef " << moduleName() << "_methods[] = {" << endl; s << globalFunctionDecl; - s << INDENT << "{0} // Sentinel" << endl << "};" << endl << endl; + s << INDENT << "{NULL, NULL, 0, NULL} // Sentinel" << endl << "};" << endl << endl; s << "// Classes initialization functions "; s << "------------------------------------------------------------" << endl; diff --git a/libshiboken/conversions.h b/libshiboken/conversions.h index 8b58886..f4fd4a7 100644 --- a/libshiboken/conversions.h +++ b/libshiboken/conversions.h @@ -141,8 +141,8 @@ struct Converter template<> struct Converter { - static inline bool checkType(PyObject* pyObj) { return false; } - static inline bool isConvertible(PyObject* pyobj) { return true; } + static inline bool checkType(PyObject*) { return false; } + static inline bool isConvertible(PyObject*) { return true; } static PyObject* toPython(void* cppobj) { if (!cppobj) @@ -291,7 +291,7 @@ struct OverFlowChecker template<> struct OverFlowChecker { - static bool check(const PY_LONG_LONG& value) + static bool check(const PY_LONG_LONG&) { return false; } @@ -300,7 +300,7 @@ struct OverFlowChecker template<> struct OverFlowChecker { - static bool check(const double& value) + static bool check(const double&) { return false; } From 32fdeee1200ceea0276595cd727c3dd06298680a Mon Sep 17 00:00:00 2001 From: David Thompson Date: Tue, 17 Dec 2013 18:32:23 -0500 Subject: [PATCH 60/66] Generate code that generates fewer warnings. --- generator/shiboken/cppgenerator.cpp | 51 ++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/generator/shiboken/cppgenerator.cpp b/generator/shiboken/cppgenerator.cpp index b85bf95..3a8c619 100644 --- a/generator/shiboken/cppgenerator.cpp +++ b/generator/shiboken/cppgenerator.cpp @@ -1150,8 +1150,9 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas { if (metaClass->isNamespace()) return; + QString cvtname = QString("converter%1").arg(INDENT.indent); s << INDENT << "// Register Converter" << endl; - s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(&"; + s << INDENT << "SbkConverter* " << cvtname << " = Shiboken::Conversions::createConverter(&"; s << cpythonTypeName(metaClass) << ',' << endl; { Indentation indent(INDENT); @@ -1174,16 +1175,16 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas QStringList cppSignature = metaClass->qualifiedCppName().split("::", QString::SkipEmptyParts); while (!cppSignature.isEmpty()) { QString signature = cppSignature.join("::"); - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "\");" << endl; - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "*\");" << endl; - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "&\");" << endl; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtname << ", \"" << signature << "\");" << endl; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtname << ", \"" << signature << "*\");" << endl; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtname << ", \"" << signature << "&\");" << endl; cppSignature.removeFirst(); } - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::"; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtname << ", typeid(::"; s << metaClass->qualifiedCppName() << ").name());" << endl; if (shouldGenerateCppWrapper(metaClass)) { - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::"; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtname << ", typeid(::"; s << wrapperName(metaClass) << ").name());" << endl; } @@ -1198,7 +1199,7 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas QString targetTypeName = QString("%1_COPY").arg(sourceTypeName); QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName); QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); + writeAddPythonToCppConversion(s, cvtname, toCpp, isConv); // User provided implicit conversions. CustomConversion* customConversion = metaClass->typeEntry()->customConversion(); @@ -1230,10 +1231,10 @@ void CppGenerator::writeConverterRegister(QTextStream& s, const AbstractMetaClas } QString toCpp = pythonToCppFunctionName(sourceType, targetType); QString isConv = convertibleToCppFunctionName(sourceType, targetType); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); + writeAddPythonToCppConversion(s, cvtname, toCpp, isConv); } - writeCustomConverterRegister(s, customConversion, "converter"); + writeCustomConverterRegister(s, customConversion, cvtname); } void CppGenerator::writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar) @@ -1338,6 +1339,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun s << "static int" << endl; s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* args, PyObject* kwds)" << endl; s << '{' << endl; + s << "(void)args;" << endl; // Avoid warnings when args is unused. s << "(void)kwds;" << endl; // Avoid warnings when kwd is unused. QSet argNamesSet; @@ -1489,6 +1491,18 @@ void CppGenerator::writeMethodWrapper(QTextStream& s, const AbstractMetaFunction s << ", PyObject* kwds"; } s << ')' << endl << '{' << endl; + // Avoid unused variable warnings + if (maxArgs > 0) + { + if (pythonFunctionWrapperUsesListOfArguments(overloadData)) + { + s << "(void)args;" << endl; + } + else + { + s << "(void)" << PYTHON_ARG << ";" << endl; + } + } writeMethodWrapperPreamble(s, overloadData); @@ -2487,6 +2501,7 @@ void CppGenerator::writeIsPythonConvertibleToCppFunction(QTextStream& s, s << "static PythonToCppFunc " << convertibleToCppFunctionName(sourceTypeName, targetTypeName); s << "(PyObject* pyIn) {" << endl; + s << "(void)pyIn;" << endl; // Avoid unused-variable warnings. if (acceptNoneAsCppNull) { s << INDENT << "if (pyIn == Py_None)" << endl; Indentation indent(INDENT); @@ -3212,7 +3227,8 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn { Indentation indent(INDENT); QString typeName = fixedCppTypeName(enumType); - s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(" << enumPythonType << ',' << endl; + QString cvtName = QString("converter%1").arg(INDENT.indent); + s << INDENT << "SbkConverter* " << cvtName << " = Shiboken::Conversions::createConverter(" << enumPythonType << ',' << endl; { Indentation indent(INDENT); s << INDENT << cppToPythonFunctionName(typeName, typeName) << ");" << endl; @@ -3222,25 +3238,25 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn QString enumTypeName = fixedCppTypeName(flags->originator()); QString toCpp = pythonToCppFunctionName(enumTypeName, typeName); QString isConv = convertibleToCppFunctionName(enumTypeName, typeName); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); + writeAddPythonToCppConversion(s, cvtName, toCpp, isConv); } QString toCpp = pythonToCppFunctionName(typeName, typeName); QString isConv = convertibleToCppFunctionName(typeName, typeName); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); + writeAddPythonToCppConversion(s, cvtName, toCpp, isConv); if (flags) { QString toCpp = pythonToCppFunctionName("number", typeName); QString isConv = convertibleToCppFunctionName("number", typeName); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); + writeAddPythonToCppConversion(s, cvtName, toCpp, isConv); } - s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl; - s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl; + s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", " << cvtName << ");" << endl; + s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", " << cvtName << ");" << endl; QStringList cppSignature = enumType->qualifiedCppName().split("::", QString::SkipEmptyParts); while (!cppSignature.isEmpty()) { QString signature = cppSignature.join("::"); - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \""; + s << INDENT << "Shiboken::Conversions::registerConverterName(" << cvtName << ", \""; if (flags) s << "QFlags<"; s << signature << "\");" << endl; @@ -4493,6 +4509,9 @@ void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMeta QString polymorphicExpr = metaClass->typeEntry()->polymorphicIdValue(); s << "static void* " << cpythonBaseName(metaClass) << "_typeDiscovery(void* cptr, SbkObjectType* instanceType)\n{" << endl; + // Avoid warnings: + s << "(void)cptr;" << endl; + s << "(void)instanceType;" << endl; if (!polymorphicExpr.isEmpty()) { polymorphicExpr = polymorphicExpr.replace("%1", " reinterpret_cast< ::" + metaClass->qualifiedCppName() + "*>(cptr)"); From 9469d27c99c1b967735ca467f9309296430ff521 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Thu, 20 Feb 2014 15:05:26 -0500 Subject: [PATCH 61/66] Fix broken file-existence tests. These still don't test for whether the given filename points to a file that actually exists (other errors might keep us from opening the file). But close enough. --- tests/libsample/simplefile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/libsample/simplefile.cpp b/tests/libsample/simplefile.cpp index deac166..3eda2ad 100644 --- a/tests/libsample/simplefile.cpp +++ b/tests/libsample/simplefile.cpp @@ -90,13 +90,13 @@ bool SimpleFile::exists() const { std::ifstream ifile(p->m_filename); - return ifile; + return ifile.is_open(); } bool SimpleFile::exists(const char* filename) { std::ifstream ifile(filename); - return ifile; + return ifile.is_open(); } From db11f040b9ba57e8b03503b3b27bad159e848d80 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Tue, 9 Sep 2014 13:54:28 -0400 Subject: [PATCH 62/66] Provide a way to skip parsing statements. Shiboken cannot parse many boost headers. Shiboken will *never* be able to parse many boost headers. When shiboken is preprocessing files, it should define a macro so that it is possible to handle projects that include boost without crashing. This commit adds the macro SHIBOKEN_SKIP. When it is defined, your source is being parsed by Shiboken. --- ApiExtractor/parser/rpp/pp-qt-configuration | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ApiExtractor/parser/rpp/pp-qt-configuration b/ApiExtractor/parser/rpp/pp-qt-configuration index 206c3d6..6a3dcfa 100644 --- a/ApiExtractor/parser/rpp/pp-qt-configuration +++ b/ApiExtractor/parser/rpp/pp-qt-configuration @@ -1,5 +1,9 @@ #define __cplusplus 1 +// Provide SHIBOKEN_SKIP macro so projects can eliminate +// code shiboken cannot parse. +#define SHIBOKEN_SKIP + #define __STDC__ // Qt From ea007f98771b1b230e4d82acc0d043bec738b807 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 15 Apr 2015 15:03:55 -0400 Subject: [PATCH 63/66] shiboken: support response files --- generator/main.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/generator/main.cpp b/generator/main.cpp index 88fe3a9..85d17d5 100644 --- a/generator/main.cpp +++ b/generator/main.cpp @@ -215,13 +215,8 @@ static QMap getInitializedArguments() return args; } -static QMap getCommandLineArgs() +static void parseCommandLine(QMap& args, QStringList arguments, int& argNum) { - QMap args = getInitializedArguments(); - QStringList arguments = QCoreApplication::arguments(); - arguments.removeFirst(); - - int argNum = 0; foreach (QString arg, arguments) { arg = arg.trimmed(); if (arg.startsWith("--")) { @@ -232,11 +227,31 @@ static QMap getCommandLineArgs() args[arg.mid(2)] = QString(); } else if (arg.startsWith("-")) { args[arg.mid(1)] = QString(); + } else if (arg.startsWith("@")) { + QFile responseFile(arg.mid(1)); + if (responseFile.open(QIODevice::ReadOnly)) { + QTextStream stream(&responseFile); + QStringList responseArgs; + while (!stream.atEnd()) { + responseArgs << stream.readLine(); + } + parseCommandLine(args, responseArgs, argNum); + } } else { argNum++; args[QString("arg-%1").arg(argNum)] = arg; } } +} + +static QMap getCommandLineArgs() +{ + QMap args = getInitializedArguments(); + QStringList arguments = QCoreApplication::arguments(); + arguments.removeFirst(); + + int argNum = 0; + parseCommandLine(args, arguments, argNum); return args; } From d2d421c728a74816cff206504cd02375bb15b241 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 23 Apr 2015 16:47:42 -0400 Subject: [PATCH 64/66] cmake: provide PYTHONPATH component needed to use the module --- data/ShibokenConfig-spec.cmake.in | 1 + 1 file changed, 1 insertion(+) diff --git a/data/ShibokenConfig-spec.cmake.in b/data/ShibokenConfig-spec.cmake.in index e1358b6..95c870d 100644 --- a/data/ShibokenConfig-spec.cmake.in +++ b/data/ShibokenConfig-spec.cmake.in @@ -15,6 +15,7 @@ elseif(WIN32) else() SET(SHIBOKEN_LIBRARY "@LIB_INSTALL_DIR@/@CMAKE_SHARED_LIBRARY_PREFIX@shiboken@shiboken_SUFFIX@@PYTHON_SUFFIX@@LIBRARY_OUTPUT_SUFFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@") endif() +SET(SHIBOKEN_PYTHONPATH "@PYTHON_SITE_PACKAGES@") SET(SHIBOKEN_PYTHON_INCLUDE_DIR "@SBK_PYTHON_INCLUDE_DIR@") SET(SHIBOKEN_PYTHON_INCLUDE_DIR "@SBK_PYTHON_INCLUDE_DIR@") SET(SHIBOKEN_PYTHON_INTERPRETER "@PYTHON_EXECUTABLE@") From acd0c977cf4d169f31b8973fe976d31531d184f8 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 27 Apr 2015 10:26:00 -0400 Subject: [PATCH 65/66] cmake: ensure forward slashes in the python path --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index cac90d3..f9e7d69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ if (NOT PYTHON_SITE_PACKAGES) elseif (APPLE) message(STATUS "!!! The generated bindings will be installed on ${PYTHON_SITE_PACKAGES}, is it right!?") endif() + file(TO_CMAKE_PATH "${PYTHON_SITE_PACKAGES}" PYTHON_SITE_PACKAGES) endif() if(MSVC) From c09e3f862b756117769f8778b5fec2068c11f131 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 1 Jun 2016 18:44:20 -0400 Subject: [PATCH 66/66] operators: skip nullary operators The function assumes at least unary operators. --- ApiExtractor/abstractmetabuilder.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ApiExtractor/abstractmetabuilder.cpp b/ApiExtractor/abstractmetabuilder.cpp index 5f22acd..06c0afe 100644 --- a/ApiExtractor/abstractmetabuilder.cpp +++ b/ApiExtractor/abstractmetabuilder.cpp @@ -652,8 +652,12 @@ bool AbstractMetaBuilder::build(QIODevice* input) + m_dom->findFunctions("operator~") + m_dom->findFunctions("operator>"); - foreach (FunctionModelItem item, binaryOperators) + foreach (FunctionModelItem item, binaryOperators) { + if (item->arguments().empty()) { + continue; + } traverseOperatorFunction(item); + } } {